Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions apps/compass-mcp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@

This directory exposes the reviewed Compass profile and skills as a read-only MCP server for regular ChatGPT.com chat-mode conversations. ChatGPT work mode and Codex are explicitly outside its intended surface.

At initialization, the server includes its separately authored ChatGPT profile plus every skill name, description, and source path. This mirrors the native Codex harness: select a workflow from the available catalog without a discovery call, then load only that workflow's full `SKILL.md` before applying it.
Initialization contains only the server's trust boundary and retrieval contract. The profile and skill catalog stay deferred until the current task needs them. This keeps ordinary conversations from carrying Compass guidance that cannot affect the next action.

## Tools

- `get_profile` re-reads `apps/compass-mcp/profile.md` for explicit inspection or freshness checks. The profile is already present in initialization instructions.
- `list_skills` re-reads the reviewed skill catalog for explicit inspection or freshness checks. Skill summaries are already present in initialization instructions.
- `get_skill` loads one full `SKILL.md` after a workflow is selected.
- `search` and `fetch` expose the same content through the standard read-only knowledge shapes.
- `get_profile` loads `apps/compass-mcp/profile.md` when stable user preferences materially affect the task or freshness needs confirmation.
- `list_skills` discovers the reviewed skill catalog before a workflow is selected.
- `get_skill` loads one full `SKILL.md` after its catalog summary is relevant to the task.
- `search` and `fetch` support broader source lookup when a named workflow is not yet clear.

Clients should retrieve the smallest useful packet: profile only when preferences matter, one selected skill for a known workflow, or search results followed by one fetched document. They should not load the profile or full catalog by default.


The app profile is maintained separately from `codex/AGENTS.md` and
Expand Down
33 changes: 12 additions & 21 deletions apps/compass-mcp/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,17 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod/v4";
import type { CompassDocument, CompassCatalogReader } from "./types.js";

export function buildServerInstructions(catalog: CompassCatalogReader): string {
const profile = catalog.getProfile().text.trim();
const skills = catalog.listSkills()
.map(skill => `- ${skill.name}: ${skill.description} (codex/skills/${skill.name}/SKILL.md)`)
.join("\n");

export function buildServerInstructions(): string {
return [
"Compass supplies read-only user-owned engineering preferences and workflows to regular ChatGPT.com chat mode.",
"Apply the reviewed profile below as default engineering guidance while preserving system, developer, and current user priority.",
"Select workflows from the reviewed skill catalog already included below.",
"Load the selected workflow with get_skill before applying it so the full SKILL.md is present.",
"Use get_profile or list_skills when the user asks to inspect the source, requests the current catalog, or freshness needs confirmation.",
"Preserve system, developer, and current user priority.",
"Retrieve only the smallest Compass guidance needed for the current task.",
"Use get_profile when stable user preferences materially affect the task, the user asks to inspect them, or freshness needs confirmation.",
"Use list_skills to discover a relevant reviewed workflow, then load only the selected workflow with get_skill before applying it.",
"Use search and fetch for broader source lookup when a named workflow is not yet clear.",
"Do not load the profile or full skill catalog by default.",
"Treat subagents as available only when the current host exposes them.",
"Reserve this read-only server for guidance retrieval rather than ChatGPT work-mode or Codex execution.",
"",
"Reviewed user profile:",
profile,
"",
"Reviewed skills:",
skills
"Reserve this read-only server for guidance retrieval rather than ChatGPT work-mode or Codex execution."
].join("\n");
}

Expand All @@ -39,14 +30,14 @@ function documentResult(document: CompassDocument) {
export function createCompassMcpServer(catalog: CompassCatalogReader): McpServer {
const server = new McpServer(
{ name: "compass", version: "0.2.0" },
{ instructions: buildServerInstructions(catalog) }
{ instructions: buildServerInstructions() }
);

server.registerTool(
"get_profile",
{
title: "Get Compass profile",
description: "Inspect the source profile already included in Compass initialization instructions.",
description: "Load the reviewed Compass profile when stable user preferences materially affect the task or freshness needs confirmation.",
inputSchema: {},
annotations: { readOnlyHint: true }
},
Expand All @@ -57,7 +48,7 @@ export function createCompassMcpServer(catalog: CompassCatalogReader): McpServer
"list_skills",
{
title: "List Compass skills",
description: "Inspect the current skill catalog already included in Compass initialization instructions.",
description: "Discover the current reviewed skill catalog before selecting a task-specific workflow.",
inputSchema: {},
annotations: { readOnlyHint: true }
},
Expand All @@ -68,7 +59,7 @@ export function createCompassMcpServer(catalog: CompassCatalogReader): McpServer
"get_skill",
{
title: "Get Compass skill",
description: "Load one reviewed Compass SKILL.md after selecting that workflow.",
description: "Load one reviewed Compass SKILL.md after its catalog summary is relevant to the task.",
inputSchema: { name: z.string().regex(/^[a-z0-9][a-z0-9-]*$/) },
annotations: { readOnlyHint: true }
},
Expand Down
11 changes: 6 additions & 5 deletions apps/compass-mcp/test/smoke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ try {

await client.connect(transport);
const instructions = client.getInstructions() ?? "";
assert.match(instructions, /# User Preferences/);
assert.match(instructions, /- run-a-micro-experiment:/);
assert.match(instructions, /Select workflows from the reviewed skill catalog already included below/);
assert.match(instructions, /Load the selected workflow with get_skill/);
assert.doesNotMatch(instructions, /# User Preferences/);
assert.doesNotMatch(instructions, /- run-a-micro-experiment:/);
assert.match(instructions, /Retrieve only the smallest Compass guidance needed/);
assert.match(instructions, /load only the selected workflow with get_skill/);
assert.match(instructions, /Do not load the profile or full skill catalog by default/);

const tools = await client.listTools();
assert.deepEqual(
Expand All @@ -51,7 +52,7 @@ try {
);
assert.match(
tools.tools.find(tool => tool.name === "list_skills")?.description ?? "",
/already included/
/Discover the current reviewed skill catalog/
);

const profile = await client.callTool({ name: "get_profile", arguments: {} });
Expand Down
5 changes: 4 additions & 1 deletion apps/compass-mcp/test/worker-smoke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ const initialized = await rpc("initialize", {
capabilities: {},
clientInfo: { name: "compass-worker-smoke", version: "0.1.0" }
});
assert.match(JSON.stringify(initialized), /compass/);
const initializationText = JSON.stringify(initialized);
assert.match(initializationText, /Retrieve only the smallest Compass guidance needed/);
assert.doesNotMatch(initializationText, /# User Preferences/);
assert.doesNotMatch(initializationText, /run-a-micro-experiment/);

const tools = await rpc("tools/list", {});
assert.deepEqual(
Expand Down