From be0f9f8087c94eff9d05038fab198666143d19b0 Mon Sep 17 00:00:00 2001 From: Ario Barin Ostovary Date: Mon, 27 Jul 2026 14:14:14 -0400 Subject: [PATCH] defer compass mcp context loading --- apps/compass-mcp/README.md | 12 ++++++---- apps/compass-mcp/src/server.ts | 33 ++++++++++----------------- apps/compass-mcp/test/smoke.ts | 11 +++++---- apps/compass-mcp/test/worker-smoke.ts | 5 +++- 4 files changed, 29 insertions(+), 32 deletions(-) diff --git a/apps/compass-mcp/README.md b/apps/compass-mcp/README.md index a0d6f0f..5419789 100644 --- a/apps/compass-mcp/README.md +++ b/apps/compass-mcp/README.md @@ -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 diff --git a/apps/compass-mcp/src/server.ts b/apps/compass-mcp/src/server.ts index 94e2aac..2c2e36e 100644 --- a/apps/compass-mcp/src/server.ts +++ b/apps/compass-mcp/src/server.ts @@ -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"); } @@ -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 } }, @@ -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 } }, @@ -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 } }, diff --git a/apps/compass-mcp/test/smoke.ts b/apps/compass-mcp/test/smoke.ts index d0d685d..ef5e676 100644 --- a/apps/compass-mcp/test/smoke.ts +++ b/apps/compass-mcp/test/smoke.ts @@ -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( @@ -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: {} }); diff --git a/apps/compass-mcp/test/worker-smoke.ts b/apps/compass-mcp/test/worker-smoke.ts index 40e78be..5ff5672 100644 --- a/apps/compass-mcp/test/worker-smoke.ts +++ b/apps/compass-mcp/test/worker-smoke.ts @@ -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(