Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@copass/mcp

Package Overview
Dependencies
Maintainers
1
Versions
32
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@copass/mcp - npm Package Compare versions

Comparing version
0.3.5
to
0.3.6
+7
-3
dist/bin.cjs

@@ -400,6 +400,9 @@ #!/usr/bin/env node

project_id: import_zod3.z.string().optional().describe("Override the server default project_id."),
storage_only: import_zod3.z.boolean().optional().describe("If true, chunk and store but skip ontology ingestion.")
storage_only: import_zod3.z.boolean().optional().describe("If true, chunk and store but skip ontology ingestion."),
occurred_at: import_zod3.z.string().optional().describe(
"Optional ISO 8601 timestamp anchoring the content to a real-world moment (e.g. when this decision was made, when the user said it). Used as the default occurred_at for any composed event whose own timestamp is null, so temporal queries can find it."
)
}
},
async ({ content, source_type, data_source_id, project_id, storage_only }) => {
async ({ content, source_type, data_source_id, project_id, storage_only, occurred_at }) => {
try {

@@ -416,3 +419,4 @@ const sourceId = data_source_id ?? config.ingest_data_source_id;

project_id: project_id ?? config.project_id,
storage_only
storage_only,
occurred_at
});

@@ -419,0 +423,0 @@ return mcpResult3({

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/bin.ts","../src/config.ts","../src/server.ts","../src/windows.ts","../src/tools/retrieval.ts","../src/tools/context-window.ts","../src/tools/ingest.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { CopassClient } from '@copass/core';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { loadConfig } from './config.js';\nimport { buildServer } from './server.js';\nimport { WindowRegistry } from './windows.js';\n\nasync function main(): Promise<void> {\n const config = loadConfig();\n // loadConfig() enforces api_key at runtime; the static type marks it\n // optional so embedded callers (buildServer({ client })) don't have\n // to pass one. The bin path always has it.\n const apiKey = config.api_key!;\n\n const client = new CopassClient({\n apiUrl: config.api_url,\n auth: apiKey.startsWith('olk_')\n ? { type: 'api-key', key: apiKey }\n : { type: 'bearer', token: apiKey },\n });\n\n const windows = new WindowRegistry();\n\n // Pre-attach to a Context Window if the caller passed one via env var.\n // Lets a parent process (e.g. an HTTP server) own window lifecycle and share\n // it across multiple MCP subprocess spawns.\n if (config.context_window_id) {\n try {\n const window = await client.contextWindow.attach({\n sandbox_id: config.sandbox_id,\n data_source_id: config.context_window_id,\n initialTurns: config.context_window_initial_turns,\n });\n windows.set(window);\n const turnCount = config.context_window_initial_turns?.length ?? 0;\n process.stderr.write(\n `copass-mcp: attached to context window ${config.context_window_id}` +\n (turnCount > 0 ? ` (${turnCount} initial turn${turnCount === 1 ? '' : 's'})` : '') +\n '\\n',\n );\n } catch (err) {\n process.stderr.write(\n `copass-mcp: failed to attach to COPASS_CONTEXT_WINDOW_ID=${config.context_window_id}: ${\n err instanceof Error ? err.message : String(err)\n }\\n`,\n );\n throw err;\n }\n }\n\n const server = buildServer({ client, config, windows });\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n process.stderr.write(\n `copass-mcp: started (sandbox=${config.sandbox_id}, preset=${config.preset})\\n`,\n );\n}\n\nmain().catch((err) => {\n process.stderr.write(`copass-mcp: fatal: ${err instanceof Error ? err.message : String(err)}\\n`);\n process.exit(1);\n});\n","import type { ChatMessage, SearchPreset } from '@copass/core';\n\nexport interface ServerConfig {\n api_url: string;\n /**\n * Required when the standalone `copass-mcp` bin builds its own\n * `CopassClient` from this config (`bin.ts`). Optional for embedded\n * use — when a host process (e.g. another MCP server) constructs the\n * `CopassClient` itself and passes it into `buildServer({ client })`,\n * the tool handlers never read this field.\n */\n api_key?: string;\n sandbox_id: string;\n project_id?: string;\n preset: SearchPreset;\n /** Default data_source_id for `ingest` when the caller doesn't pass one. */\n ingest_data_source_id?: string;\n /**\n * If set, the server attaches to this Context Window on startup and makes\n * it the active window. Use when another process (e.g. a Hono server)\n * already created the window and you're launching the MCP server as a\n * subprocess that should share it.\n */\n context_window_id?: string;\n /**\n * Optional pre-existing turns to seed the Context Window's buffer on\n * startup. Makes retrieval immediately window-aware on the first tool\n * call — without these, the first `discover` / `interpret` / `search`\n * after a subprocess spawn sees an empty history.\n *\n * Required when `context_window_id` refers to a thread that has prior\n * turns and the server should dedupe retrieval against them.\n */\n context_window_initial_turns?: ChatMessage[];\n}\n\nconst VALID_PRESETS: readonly SearchPreset[] = [\n 'fast',\n 'auto',\n 'discover',\n 'sql',\n 'max',\n // `-decompose` variants are /search-only. Setting one of these as the\n // MCP subprocess default makes `interpret` fail (decomposition isn't\n // valid on /interpret) — fine when the subprocess is only used for\n // `search`, otherwise override per-call via the `preset` tool arg.\n 'fast-decompose',\n 'auto-decompose',\n 'discover-decompose',\n 'sql-decompose',\n] as const;\n\n/**\n * Read config from `process.env`.\n *\n * - `COPASS_API_KEY` (required)\n * - `COPASS_SANDBOX_ID` (required)\n * - `COPASS_API_URL` (default: https://ai.copass.id)\n * - `COPASS_PROJECT_ID` (optional — default for retrieval/ingest)\n * - `COPASS_PRESET` (default: `auto`). Accepts any `SearchPreset`, but\n * `auto` is the only value whose providers consume the\n * `semantic_alignment_scopes` that `/interpret`'s scope adapter\n * produces — so non-`auto` defaults (and any `-decompose` default)\n * break `interpret`. Leave at `auto` unless the subprocess is\n * search-only, and override per-call via the `preset` tool arg.\n *\n * Throws a descriptive error for missing/invalid values so the MCP client\n * sees an immediate startup failure with actionable text.\n */\nexport function loadConfig(env: NodeJS.ProcessEnv = process.env): ServerConfig {\n const missing: string[] = [];\n const api_key = env.COPASS_API_KEY ?? '';\n const sandbox_id = env.COPASS_SANDBOX_ID ?? '';\n\n if (!api_key) missing.push('COPASS_API_KEY');\n if (!sandbox_id) missing.push('COPASS_SANDBOX_ID');\n\n if (missing.length > 0) {\n throw new Error(\n `@copass/mcp: missing required env var(s): ${missing.join(', ')}. ` +\n `Set them before launching the server.`,\n );\n }\n\n const api_url = env.COPASS_API_URL?.trim() || 'https://ai.copass.id';\n const project_id = env.COPASS_PROJECT_ID?.trim() || undefined;\n const rawPreset = env.COPASS_PRESET?.trim() || 'auto';\n\n if (!VALID_PRESETS.includes(rawPreset as SearchPreset)) {\n throw new Error(\n `@copass/mcp: COPASS_PRESET must be one of ${VALID_PRESETS.join(', ')}; got \"${rawPreset}\"`,\n );\n }\n\n const ingest_data_source_id = env.COPASS_INGEST_DATA_SOURCE_ID?.trim() || undefined;\n const context_window_id = env.COPASS_CONTEXT_WINDOW_ID?.trim() || undefined;\n const context_window_initial_turns = parseInitialTurns(\n env.COPASS_CONTEXT_WINDOW_INITIAL_TURNS,\n );\n\n return {\n api_url,\n api_key,\n sandbox_id,\n project_id,\n preset: rawPreset as SearchPreset,\n ingest_data_source_id,\n context_window_id,\n context_window_initial_turns,\n };\n}\n\nfunction parseInitialTurns(raw: string | undefined): ChatMessage[] | undefined {\n if (!raw || !raw.trim()) return undefined;\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n throw new Error(\n `@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS is not valid JSON: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n if (!Array.isArray(parsed)) {\n throw new Error(\n '@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS must be a JSON array of {role, content} objects',\n );\n }\n const turns: ChatMessage[] = [];\n for (const [i, entry] of parsed.entries()) {\n if (\n !entry ||\n typeof entry !== 'object' ||\n typeof (entry as { role?: unknown }).role !== 'string' ||\n typeof (entry as { content?: unknown }).content !== 'string'\n ) {\n throw new Error(\n `@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS[${i}] must be {role: string, content: string}`,\n );\n }\n const { role, content } = entry as { role: string; content: string };\n if (role !== 'user' && role !== 'assistant' && role !== 'system') {\n throw new Error(\n `@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS[${i}].role must be \"user\" | \"assistant\" | \"system\"; got \"${role}\"`,\n );\n }\n turns.push({ role, content });\n }\n return turns;\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CopassClient } from '@copass/core';\nimport type { ServerConfig } from './config.js';\nimport { WindowRegistry } from './windows.js';\nimport { registerRetrievalTools } from './tools/retrieval.js';\nimport { registerContextWindowTools } from './tools/context-window.js';\nimport { registerIngestTool } from './tools/ingest.js';\n\nexport interface BuildServerOptions {\n client: CopassClient;\n config: ServerConfig;\n /**\n * Optional pre-populated window registry. Useful when a parent process has\n * already created or attached to a Context Window and wants the server to\n * start with it as the active window.\n */\n windows?: WindowRegistry;\n}\n\n/**\n * Assemble the Copass MCP server with every tool registered. Doesn't connect\n * a transport — see `startStdioServer` in `./bin.ts` for the default path,\n * or wire your own transport if embedding.\n */\nexport function buildServer({ client, config, windows }: BuildServerOptions): McpServer {\n const server = new McpServer(\n {\n name: 'copass',\n version: '0.3.0',\n },\n {\n capabilities: { tools: {} },\n },\n );\n\n const registry = windows ?? new WindowRegistry();\n const deps = { client, config, windows: registry };\n\n registerRetrievalTools(server, deps);\n registerContextWindowTools(server, deps);\n registerIngestTool(server, { client, config });\n\n return server;\n}\n","import type { ContextWindow } from '@copass/core';\n\n/**\n * In-memory registry of open Context Windows.\n *\n * Tracks a map of `data_source_id → ContextWindow` plus a single \"active\"\n * window id. Retrieval and add-turn tools use the active window implicitly\n * so the LLM doesn't have to thread an id on every call.\n *\n * For multi-window use cases, callers pass `data_source_id` explicitly and\n * the active id is ignored.\n */\nexport class WindowRegistry {\n private readonly windows = new Map<string, ContextWindow>();\n private activeId: string | null = null;\n\n /** Register a new window and make it active. */\n set(window: ContextWindow): void {\n this.windows.set(window.dataSourceId, window);\n this.activeId = window.dataSourceId;\n }\n\n /** Look up a window by id, or fall back to the active one. */\n resolve(dataSourceId?: string): ContextWindow | undefined {\n const id = dataSourceId ?? this.activeId;\n return id ? this.windows.get(id) : undefined;\n }\n\n /** Make an existing window the active one. Throws if unknown. */\n activate(dataSourceId: string): ContextWindow {\n const window = this.windows.get(dataSourceId);\n if (!window) {\n throw new Error(\n `No window registered for data_source_id=\"${dataSourceId}\" — call context_window_create or context_window_attach first.`,\n );\n }\n this.activeId = dataSourceId;\n return window;\n }\n\n /** Drop a window from the registry. Clears active if it matched. */\n drop(dataSourceId: string): void {\n this.windows.delete(dataSourceId);\n if (this.activeId === dataSourceId) this.activeId = null;\n }\n\n get activeDataSourceId(): string | null {\n return this.activeId;\n }\n}\n","import { z } from 'zod';\nimport {\n DISCOVER_QUERY_PARAM,\n INTERPRET_DESCRIPTION,\n INTERPRET_ITEMS_PARAM,\n INTERPRET_QUERY_PARAM,\n MCP_DISCOVER_DESCRIPTION,\n PRESET_PARAM,\n PROJECT_ID_PARAM,\n SEARCH_DESCRIPTION,\n SEARCH_QUERY_PARAM,\n} from '@copass/config';\nimport type { CopassClient } from '@copass/core';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ServerConfig } from '../config.js';\nimport type { WindowRegistry } from '../windows.js';\n\ninterface RetrievalDeps {\n client: CopassClient;\n config: ServerConfig;\n windows: WindowRegistry;\n}\n\nfunction mcpResult(payload: unknown) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(payload, null, 2) }],\n };\n}\n\nfunction mcpError(error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Error: ${message}` }],\n isError: true,\n };\n}\n\nexport function registerRetrievalTools(server: McpServer, deps: RetrievalDeps): void {\n const { client, config, windows } = deps;\n\n server.registerTool(\n 'discover',\n {\n description: MCP_DISCOVER_DESCRIPTION,\n inputSchema: {\n query: z.string().describe(DISCOVER_QUERY_PARAM),\n project_id: z.string().optional().describe(PROJECT_ID_PARAM),\n },\n },\n async ({ query, project_id }) => {\n try {\n const response = await client.retrieval.discover(config.sandbox_id, {\n query,\n project_id: project_id ?? config.project_id,\n window: windows.resolve(),\n });\n return mcpResult({\n header: response.header,\n items: response.items.map((item) => ({\n score: item.score,\n summary: item.summary,\n canonical_ids: item.canonical_ids,\n })),\n next_steps: response.next_steps,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'interpret',\n {\n description: INTERPRET_DESCRIPTION,\n inputSchema: {\n query: z.string().describe(INTERPRET_QUERY_PARAM),\n items: z.array(z.array(z.string()).min(1)).min(1).describe(INTERPRET_ITEMS_PARAM),\n preset: z.enum(['fast', 'auto', 'max']).optional().describe(PRESET_PARAM),\n project_id: z.string().optional().describe(PROJECT_ID_PARAM),\n },\n },\n async ({ query, items, preset, project_id }) => {\n try {\n const response = await client.retrieval.interpret(config.sandbox_id, {\n query,\n items,\n project_id: project_id ?? config.project_id,\n window: windows.resolve(),\n preset: preset ?? config.preset,\n });\n return mcpResult({ brief: response.brief });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'search',\n {\n description: SEARCH_DESCRIPTION,\n inputSchema: {\n query: z.string().describe(SEARCH_QUERY_PARAM),\n // `max` is omitted — the server returns 403 for public callers,\n // so exposing it would only yield confusing tool-use errors.\n // `-decompose` variants split the question into sub-questions and\n // run the base preset on each before a combined synthesis.\n preset: z\n .enum([\n 'fast',\n 'auto',\n 'discover',\n 'sql',\n 'fast-decompose',\n 'auto-decompose',\n 'discover-decompose',\n 'sql-decompose',\n ])\n .optional()\n .describe(PRESET_PARAM),\n project_id: z.string().optional().describe(PROJECT_ID_PARAM),\n },\n },\n async ({ query, preset, project_id }) => {\n try {\n const response = await client.retrieval.search(config.sandbox_id, {\n query,\n project_id: project_id ?? config.project_id,\n window: windows.resolve(),\n preset: preset ?? config.preset,\n });\n return mcpResult({ answer: response.answer });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n}\n","import { z } from 'zod';\nimport type { CopassClient } from '@copass/core';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ServerConfig } from '../config.js';\nimport type { WindowRegistry } from '../windows.js';\n\ninterface ContextWindowDeps {\n client: CopassClient;\n config: ServerConfig;\n windows: WindowRegistry;\n}\n\nfunction mcpResult(payload: unknown) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(payload, null, 2) }],\n };\n}\n\nfunction mcpError(error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Error: ${message}` }],\n isError: true,\n };\n}\n\nexport function registerContextWindowTools(server: McpServer, deps: ContextWindowDeps): void {\n const { client, config, windows } = deps;\n\n server.registerTool(\n 'context_window_create',\n {\n description:\n 'Open a new Context Window — an ephemeral data source tracking this conversation. ' +\n 'Subsequent retrieval calls become automatically window-aware, and every turn you ' +\n 'record via `context_window_add_turn` is ingested into the graph so past turns ' +\n 'become retrievable. Returns a `data_source_id`; persist it on your side if you ' +\n 'may want to resume this conversation later via `context_window_attach`.',\n inputSchema: {\n project_id: z.string().optional().describe('Override the server default project_id.'),\n name: z.string().optional().describe('Optional stable name for the underlying data source.'),\n },\n },\n async ({ project_id, name }) => {\n try {\n const window = await client.contextWindow.create({\n sandbox_id: config.sandbox_id,\n project_id: project_id ?? config.project_id,\n name,\n });\n windows.set(window);\n return mcpResult({\n data_source_id: window.dataSourceId,\n active: true,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'context_window_add_turn',\n {\n description:\n 'Append a turn to the active Context Window and push it into the graph. Call on ' +\n 'every user message AND every assistant message so the thread itself becomes ' +\n 'retrievable. If you omit `data_source_id`, the active window is used.',\n inputSchema: {\n role: z\n .enum(['user', 'assistant', 'system'])\n .describe('Role of the speaker for this turn.'),\n content: z.string().describe('The turn content.'),\n data_source_id: z\n .string()\n .optional()\n .describe('Override the active window id (for multi-window use cases).'),\n },\n },\n async ({ role, content, data_source_id }) => {\n try {\n const window = windows.resolve(data_source_id);\n if (!window) {\n throw new Error(\n 'No active Context Window — call context_window_create or context_window_attach first.',\n );\n }\n await window.addTurn({ role, content });\n return mcpResult({\n data_source_id: window.dataSourceId,\n turn_count: window.getTurns().length,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'context_window_attach',\n {\n description:\n 'Resume an existing Context Window by `data_source_id` (one you previously persisted ' +\n 'on your side after `context_window_create`). Makes the resumed window the active ' +\n 'window. Pass `initial_turns` to seed the local buffer for immediate window-aware ' +\n 'retrieval, otherwise the buffer starts empty and fills as you call add_turn.',\n inputSchema: {\n data_source_id: z.string().describe('Id of the Context Window data source to resume.'),\n initial_turns: z\n .array(\n z.object({\n role: z.enum(['user', 'assistant', 'system']),\n content: z.string(),\n }),\n )\n .optional()\n .describe('Optional pre-existing turns to seed the local buffer.'),\n },\n },\n async ({ data_source_id, initial_turns }) => {\n try {\n const window = await client.contextWindow.attach({\n sandbox_id: config.sandbox_id,\n data_source_id,\n initialTurns: initial_turns,\n });\n windows.set(window);\n return mcpResult({\n data_source_id: window.dataSourceId,\n turn_count: window.getTurns().length,\n active: true,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'context_window_close',\n {\n description:\n 'Close a Context Window — flips the underlying data source to `disconnected` ' +\n 'immediately instead of waiting for TTL. Best-effort; idempotent. If you omit ' +\n '`data_source_id`, the active window is closed.',\n inputSchema: {\n data_source_id: z\n .string()\n .optional()\n .describe('Override the active window id.'),\n },\n },\n async ({ data_source_id }) => {\n try {\n const window = windows.resolve(data_source_id);\n if (!window) {\n throw new Error('No active Context Window to close.');\n }\n await window.close();\n windows.drop(window.dataSourceId);\n return mcpResult({\n data_source_id: window.dataSourceId,\n closed: true,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n}\n","import { z } from 'zod';\nimport type { CopassClient } from '@copass/core';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ServerConfig } from '../config.js';\n\ninterface IngestDeps {\n client: CopassClient;\n config: ServerConfig;\n}\n\nfunction mcpResult(payload: unknown) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(payload, null, 2) }],\n };\n}\n\nfunction mcpError(error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Error: ${message}` }],\n isError: true,\n };\n}\n\nexport function registerIngestTool(server: McpServer, deps: IngestDeps): void {\n const { client, config } = deps;\n\n server.registerTool(\n 'ingest',\n {\n description:\n 'Push content into the knowledge graph via a data source. Use for: architecture ' +\n 'decisions (source_type: \"decision\"), user-shared context (\"user_input\"), ' +\n 'corrections (\"correction\"), durable notes, any significant new concept. Do NOT ' +\n 'ingest trivial changes or ephemeral debug context — those belong in the Context ' +\n 'Window (via context_window_add_turn). Pass `data_source_id` explicitly or set ' +\n '`COPASS_INGEST_DATA_SOURCE_ID` in the server env for an implicit target.',\n inputSchema: {\n content: z.string().min(1).describe('The content to ingest.'),\n source_type: z\n .string()\n .optional()\n .describe(\n 'Type tag: code, markdown, json, text, conversation, decision, correction, ' +\n 'user_input. Defaults to \"text\" when omitted.',\n ),\n data_source_id: z\n .string()\n .optional()\n .describe(\n 'Target data source. Falls back to COPASS_INGEST_DATA_SOURCE_ID env var.',\n ),\n project_id: z.string().optional().describe('Override the server default project_id.'),\n storage_only: z\n .boolean()\n .optional()\n .describe('If true, chunk and store but skip ontology ingestion.'),\n },\n },\n async ({ content, source_type, data_source_id, project_id, storage_only }) => {\n try {\n const sourceId = data_source_id ?? config.ingest_data_source_id;\n if (!sourceId) {\n throw new Error(\n 'ingest requires a `data_source_id` argument or COPASS_INGEST_DATA_SOURCE_ID env var. ' +\n 'Register a data source via the REST API or CLI, then pass its id here.',\n );\n }\n\n const response = await client.sources.ingest(config.sandbox_id, sourceId, {\n text: content,\n source_type: source_type ?? 'text',\n project_id: project_id ?? config.project_id,\n storage_only,\n });\n\n return mcpResult({\n job_id: response.job_id,\n status: response.status,\n data_source_id: sourceId,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n}\n"],"mappings":"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","names":["import_zod","mcpResult","mcpError","import_zod","mcpResult","mcpError"]}
{"version":3,"sources":["../src/bin.ts","../src/config.ts","../src/server.ts","../src/windows.ts","../src/tools/retrieval.ts","../src/tools/context-window.ts","../src/tools/ingest.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { CopassClient } from '@copass/core';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { loadConfig } from './config.js';\nimport { buildServer } from './server.js';\nimport { WindowRegistry } from './windows.js';\n\nasync function main(): Promise<void> {\n const config = loadConfig();\n // loadConfig() enforces api_key at runtime; the static type marks it\n // optional so embedded callers (buildServer({ client })) don't have\n // to pass one. The bin path always has it.\n const apiKey = config.api_key!;\n\n const client = new CopassClient({\n apiUrl: config.api_url,\n auth: apiKey.startsWith('olk_')\n ? { type: 'api-key', key: apiKey }\n : { type: 'bearer', token: apiKey },\n });\n\n const windows = new WindowRegistry();\n\n // Pre-attach to a Context Window if the caller passed one via env var.\n // Lets a parent process (e.g. an HTTP server) own window lifecycle and share\n // it across multiple MCP subprocess spawns.\n if (config.context_window_id) {\n try {\n const window = await client.contextWindow.attach({\n sandbox_id: config.sandbox_id,\n data_source_id: config.context_window_id,\n initialTurns: config.context_window_initial_turns,\n });\n windows.set(window);\n const turnCount = config.context_window_initial_turns?.length ?? 0;\n process.stderr.write(\n `copass-mcp: attached to context window ${config.context_window_id}` +\n (turnCount > 0 ? ` (${turnCount} initial turn${turnCount === 1 ? '' : 's'})` : '') +\n '\\n',\n );\n } catch (err) {\n process.stderr.write(\n `copass-mcp: failed to attach to COPASS_CONTEXT_WINDOW_ID=${config.context_window_id}: ${\n err instanceof Error ? err.message : String(err)\n }\\n`,\n );\n throw err;\n }\n }\n\n const server = buildServer({ client, config, windows });\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n process.stderr.write(\n `copass-mcp: started (sandbox=${config.sandbox_id}, preset=${config.preset})\\n`,\n );\n}\n\nmain().catch((err) => {\n process.stderr.write(`copass-mcp: fatal: ${err instanceof Error ? err.message : String(err)}\\n`);\n process.exit(1);\n});\n","import type { ChatMessage, SearchPreset } from '@copass/core';\n\nexport interface ServerConfig {\n api_url: string;\n /**\n * Required when the standalone `copass-mcp` bin builds its own\n * `CopassClient` from this config (`bin.ts`). Optional for embedded\n * use — when a host process (e.g. another MCP server) constructs the\n * `CopassClient` itself and passes it into `buildServer({ client })`,\n * the tool handlers never read this field.\n */\n api_key?: string;\n sandbox_id: string;\n project_id?: string;\n preset: SearchPreset;\n /** Default data_source_id for `ingest` when the caller doesn't pass one. */\n ingest_data_source_id?: string;\n /**\n * If set, the server attaches to this Context Window on startup and makes\n * it the active window. Use when another process (e.g. a Hono server)\n * already created the window and you're launching the MCP server as a\n * subprocess that should share it.\n */\n context_window_id?: string;\n /**\n * Optional pre-existing turns to seed the Context Window's buffer on\n * startup. Makes retrieval immediately window-aware on the first tool\n * call — without these, the first `discover` / `interpret` / `search`\n * after a subprocess spawn sees an empty history.\n *\n * Required when `context_window_id` refers to a thread that has prior\n * turns and the server should dedupe retrieval against them.\n */\n context_window_initial_turns?: ChatMessage[];\n}\n\nconst VALID_PRESETS: readonly SearchPreset[] = [\n 'fast',\n 'auto',\n 'discover',\n 'sql',\n 'max',\n // `-decompose` variants are /search-only. Setting one of these as the\n // MCP subprocess default makes `interpret` fail (decomposition isn't\n // valid on /interpret) — fine when the subprocess is only used for\n // `search`, otherwise override per-call via the `preset` tool arg.\n 'fast-decompose',\n 'auto-decompose',\n 'discover-decompose',\n 'sql-decompose',\n] as const;\n\n/**\n * Read config from `process.env`.\n *\n * - `COPASS_API_KEY` (required)\n * - `COPASS_SANDBOX_ID` (required)\n * - `COPASS_API_URL` (default: https://ai.copass.id)\n * - `COPASS_PROJECT_ID` (optional — default for retrieval/ingest)\n * - `COPASS_PRESET` (default: `auto`). Accepts any `SearchPreset`, but\n * `auto` is the only value whose providers consume the\n * `semantic_alignment_scopes` that `/interpret`'s scope adapter\n * produces — so non-`auto` defaults (and any `-decompose` default)\n * break `interpret`. Leave at `auto` unless the subprocess is\n * search-only, and override per-call via the `preset` tool arg.\n *\n * Throws a descriptive error for missing/invalid values so the MCP client\n * sees an immediate startup failure with actionable text.\n */\nexport function loadConfig(env: NodeJS.ProcessEnv = process.env): ServerConfig {\n const missing: string[] = [];\n const api_key = env.COPASS_API_KEY ?? '';\n const sandbox_id = env.COPASS_SANDBOX_ID ?? '';\n\n if (!api_key) missing.push('COPASS_API_KEY');\n if (!sandbox_id) missing.push('COPASS_SANDBOX_ID');\n\n if (missing.length > 0) {\n throw new Error(\n `@copass/mcp: missing required env var(s): ${missing.join(', ')}. ` +\n `Set them before launching the server.`,\n );\n }\n\n const api_url = env.COPASS_API_URL?.trim() || 'https://ai.copass.id';\n const project_id = env.COPASS_PROJECT_ID?.trim() || undefined;\n const rawPreset = env.COPASS_PRESET?.trim() || 'auto';\n\n if (!VALID_PRESETS.includes(rawPreset as SearchPreset)) {\n throw new Error(\n `@copass/mcp: COPASS_PRESET must be one of ${VALID_PRESETS.join(', ')}; got \"${rawPreset}\"`,\n );\n }\n\n const ingest_data_source_id = env.COPASS_INGEST_DATA_SOURCE_ID?.trim() || undefined;\n const context_window_id = env.COPASS_CONTEXT_WINDOW_ID?.trim() || undefined;\n const context_window_initial_turns = parseInitialTurns(\n env.COPASS_CONTEXT_WINDOW_INITIAL_TURNS,\n );\n\n return {\n api_url,\n api_key,\n sandbox_id,\n project_id,\n preset: rawPreset as SearchPreset,\n ingest_data_source_id,\n context_window_id,\n context_window_initial_turns,\n };\n}\n\nfunction parseInitialTurns(raw: string | undefined): ChatMessage[] | undefined {\n if (!raw || !raw.trim()) return undefined;\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n throw new Error(\n `@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS is not valid JSON: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n if (!Array.isArray(parsed)) {\n throw new Error(\n '@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS must be a JSON array of {role, content} objects',\n );\n }\n const turns: ChatMessage[] = [];\n for (const [i, entry] of parsed.entries()) {\n if (\n !entry ||\n typeof entry !== 'object' ||\n typeof (entry as { role?: unknown }).role !== 'string' ||\n typeof (entry as { content?: unknown }).content !== 'string'\n ) {\n throw new Error(\n `@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS[${i}] must be {role: string, content: string}`,\n );\n }\n const { role, content } = entry as { role: string; content: string };\n if (role !== 'user' && role !== 'assistant' && role !== 'system') {\n throw new Error(\n `@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS[${i}].role must be \"user\" | \"assistant\" | \"system\"; got \"${role}\"`,\n );\n }\n turns.push({ role, content });\n }\n return turns;\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CopassClient } from '@copass/core';\nimport type { ServerConfig } from './config.js';\nimport { WindowRegistry } from './windows.js';\nimport { registerRetrievalTools } from './tools/retrieval.js';\nimport { registerContextWindowTools } from './tools/context-window.js';\nimport { registerIngestTool } from './tools/ingest.js';\n\nexport interface BuildServerOptions {\n client: CopassClient;\n config: ServerConfig;\n /**\n * Optional pre-populated window registry. Useful when a parent process has\n * already created or attached to a Context Window and wants the server to\n * start with it as the active window.\n */\n windows?: WindowRegistry;\n}\n\n/**\n * Assemble the Copass MCP server with every tool registered. Doesn't connect\n * a transport — see `startStdioServer` in `./bin.ts` for the default path,\n * or wire your own transport if embedding.\n */\nexport function buildServer({ client, config, windows }: BuildServerOptions): McpServer {\n const server = new McpServer(\n {\n name: 'copass',\n version: '0.3.0',\n },\n {\n capabilities: { tools: {} },\n },\n );\n\n const registry = windows ?? new WindowRegistry();\n const deps = { client, config, windows: registry };\n\n registerRetrievalTools(server, deps);\n registerContextWindowTools(server, deps);\n registerIngestTool(server, { client, config });\n\n return server;\n}\n","import type { ContextWindow } from '@copass/core';\n\n/**\n * In-memory registry of open Context Windows.\n *\n * Tracks a map of `data_source_id → ContextWindow` plus a single \"active\"\n * window id. Retrieval and add-turn tools use the active window implicitly\n * so the LLM doesn't have to thread an id on every call.\n *\n * For multi-window use cases, callers pass `data_source_id` explicitly and\n * the active id is ignored.\n */\nexport class WindowRegistry {\n private readonly windows = new Map<string, ContextWindow>();\n private activeId: string | null = null;\n\n /** Register a new window and make it active. */\n set(window: ContextWindow): void {\n this.windows.set(window.dataSourceId, window);\n this.activeId = window.dataSourceId;\n }\n\n /** Look up a window by id, or fall back to the active one. */\n resolve(dataSourceId?: string): ContextWindow | undefined {\n const id = dataSourceId ?? this.activeId;\n return id ? this.windows.get(id) : undefined;\n }\n\n /** Make an existing window the active one. Throws if unknown. */\n activate(dataSourceId: string): ContextWindow {\n const window = this.windows.get(dataSourceId);\n if (!window) {\n throw new Error(\n `No window registered for data_source_id=\"${dataSourceId}\" — call context_window_create or context_window_attach first.`,\n );\n }\n this.activeId = dataSourceId;\n return window;\n }\n\n /** Drop a window from the registry. Clears active if it matched. */\n drop(dataSourceId: string): void {\n this.windows.delete(dataSourceId);\n if (this.activeId === dataSourceId) this.activeId = null;\n }\n\n get activeDataSourceId(): string | null {\n return this.activeId;\n }\n}\n","import { z } from 'zod';\nimport {\n DISCOVER_QUERY_PARAM,\n INTERPRET_DESCRIPTION,\n INTERPRET_ITEMS_PARAM,\n INTERPRET_QUERY_PARAM,\n MCP_DISCOVER_DESCRIPTION,\n PRESET_PARAM,\n PROJECT_ID_PARAM,\n SEARCH_DESCRIPTION,\n SEARCH_QUERY_PARAM,\n} from '@copass/config';\nimport type { CopassClient } from '@copass/core';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ServerConfig } from '../config.js';\nimport type { WindowRegistry } from '../windows.js';\n\ninterface RetrievalDeps {\n client: CopassClient;\n config: ServerConfig;\n windows: WindowRegistry;\n}\n\nfunction mcpResult(payload: unknown) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(payload, null, 2) }],\n };\n}\n\nfunction mcpError(error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Error: ${message}` }],\n isError: true,\n };\n}\n\nexport function registerRetrievalTools(server: McpServer, deps: RetrievalDeps): void {\n const { client, config, windows } = deps;\n\n server.registerTool(\n 'discover',\n {\n description: MCP_DISCOVER_DESCRIPTION,\n inputSchema: {\n query: z.string().describe(DISCOVER_QUERY_PARAM),\n project_id: z.string().optional().describe(PROJECT_ID_PARAM),\n },\n },\n async ({ query, project_id }) => {\n try {\n const response = await client.retrieval.discover(config.sandbox_id, {\n query,\n project_id: project_id ?? config.project_id,\n window: windows.resolve(),\n });\n return mcpResult({\n header: response.header,\n items: response.items.map((item) => ({\n score: item.score,\n summary: item.summary,\n canonical_ids: item.canonical_ids,\n })),\n next_steps: response.next_steps,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'interpret',\n {\n description: INTERPRET_DESCRIPTION,\n inputSchema: {\n query: z.string().describe(INTERPRET_QUERY_PARAM),\n items: z.array(z.array(z.string()).min(1)).min(1).describe(INTERPRET_ITEMS_PARAM),\n preset: z.enum(['fast', 'auto', 'max']).optional().describe(PRESET_PARAM),\n project_id: z.string().optional().describe(PROJECT_ID_PARAM),\n },\n },\n async ({ query, items, preset, project_id }) => {\n try {\n const response = await client.retrieval.interpret(config.sandbox_id, {\n query,\n items,\n project_id: project_id ?? config.project_id,\n window: windows.resolve(),\n preset: preset ?? config.preset,\n });\n return mcpResult({ brief: response.brief });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'search',\n {\n description: SEARCH_DESCRIPTION,\n inputSchema: {\n query: z.string().describe(SEARCH_QUERY_PARAM),\n // `max` is omitted — the server returns 403 for public callers,\n // so exposing it would only yield confusing tool-use errors.\n // `-decompose` variants split the question into sub-questions and\n // run the base preset on each before a combined synthesis.\n preset: z\n .enum([\n 'fast',\n 'auto',\n 'discover',\n 'sql',\n 'fast-decompose',\n 'auto-decompose',\n 'discover-decompose',\n 'sql-decompose',\n ])\n .optional()\n .describe(PRESET_PARAM),\n project_id: z.string().optional().describe(PROJECT_ID_PARAM),\n },\n },\n async ({ query, preset, project_id }) => {\n try {\n const response = await client.retrieval.search(config.sandbox_id, {\n query,\n project_id: project_id ?? config.project_id,\n window: windows.resolve(),\n preset: preset ?? config.preset,\n });\n return mcpResult({ answer: response.answer });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n}\n","import { z } from 'zod';\nimport type { CopassClient } from '@copass/core';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ServerConfig } from '../config.js';\nimport type { WindowRegistry } from '../windows.js';\n\ninterface ContextWindowDeps {\n client: CopassClient;\n config: ServerConfig;\n windows: WindowRegistry;\n}\n\nfunction mcpResult(payload: unknown) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(payload, null, 2) }],\n };\n}\n\nfunction mcpError(error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Error: ${message}` }],\n isError: true,\n };\n}\n\nexport function registerContextWindowTools(server: McpServer, deps: ContextWindowDeps): void {\n const { client, config, windows } = deps;\n\n server.registerTool(\n 'context_window_create',\n {\n description:\n 'Open a new Context Window — an ephemeral data source tracking this conversation. ' +\n 'Subsequent retrieval calls become automatically window-aware, and every turn you ' +\n 'record via `context_window_add_turn` is ingested into the graph so past turns ' +\n 'become retrievable. Returns a `data_source_id`; persist it on your side if you ' +\n 'may want to resume this conversation later via `context_window_attach`.',\n inputSchema: {\n project_id: z.string().optional().describe('Override the server default project_id.'),\n name: z.string().optional().describe('Optional stable name for the underlying data source.'),\n },\n },\n async ({ project_id, name }) => {\n try {\n const window = await client.contextWindow.create({\n sandbox_id: config.sandbox_id,\n project_id: project_id ?? config.project_id,\n name,\n });\n windows.set(window);\n return mcpResult({\n data_source_id: window.dataSourceId,\n active: true,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'context_window_add_turn',\n {\n description:\n 'Append a turn to the active Context Window and push it into the graph. Call on ' +\n 'every user message AND every assistant message so the thread itself becomes ' +\n 'retrievable. If you omit `data_source_id`, the active window is used.',\n inputSchema: {\n role: z\n .enum(['user', 'assistant', 'system'])\n .describe('Role of the speaker for this turn.'),\n content: z.string().describe('The turn content.'),\n data_source_id: z\n .string()\n .optional()\n .describe('Override the active window id (for multi-window use cases).'),\n },\n },\n async ({ role, content, data_source_id }) => {\n try {\n const window = windows.resolve(data_source_id);\n if (!window) {\n throw new Error(\n 'No active Context Window — call context_window_create or context_window_attach first.',\n );\n }\n await window.addTurn({ role, content });\n return mcpResult({\n data_source_id: window.dataSourceId,\n turn_count: window.getTurns().length,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'context_window_attach',\n {\n description:\n 'Resume an existing Context Window by `data_source_id` (one you previously persisted ' +\n 'on your side after `context_window_create`). Makes the resumed window the active ' +\n 'window. Pass `initial_turns` to seed the local buffer for immediate window-aware ' +\n 'retrieval, otherwise the buffer starts empty and fills as you call add_turn.',\n inputSchema: {\n data_source_id: z.string().describe('Id of the Context Window data source to resume.'),\n initial_turns: z\n .array(\n z.object({\n role: z.enum(['user', 'assistant', 'system']),\n content: z.string(),\n }),\n )\n .optional()\n .describe('Optional pre-existing turns to seed the local buffer.'),\n },\n },\n async ({ data_source_id, initial_turns }) => {\n try {\n const window = await client.contextWindow.attach({\n sandbox_id: config.sandbox_id,\n data_source_id,\n initialTurns: initial_turns,\n });\n windows.set(window);\n return mcpResult({\n data_source_id: window.dataSourceId,\n turn_count: window.getTurns().length,\n active: true,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'context_window_close',\n {\n description:\n 'Close a Context Window — flips the underlying data source to `disconnected` ' +\n 'immediately instead of waiting for TTL. Best-effort; idempotent. If you omit ' +\n '`data_source_id`, the active window is closed.',\n inputSchema: {\n data_source_id: z\n .string()\n .optional()\n .describe('Override the active window id.'),\n },\n },\n async ({ data_source_id }) => {\n try {\n const window = windows.resolve(data_source_id);\n if (!window) {\n throw new Error('No active Context Window to close.');\n }\n await window.close();\n windows.drop(window.dataSourceId);\n return mcpResult({\n data_source_id: window.dataSourceId,\n closed: true,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n}\n","import { z } from 'zod';\nimport type { CopassClient } from '@copass/core';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ServerConfig } from '../config.js';\n\ninterface IngestDeps {\n client: CopassClient;\n config: ServerConfig;\n}\n\nfunction mcpResult(payload: unknown) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(payload, null, 2) }],\n };\n}\n\nfunction mcpError(error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Error: ${message}` }],\n isError: true,\n };\n}\n\nexport function registerIngestTool(server: McpServer, deps: IngestDeps): void {\n const { client, config } = deps;\n\n server.registerTool(\n 'ingest',\n {\n description:\n 'Push content into the knowledge graph via a data source. Use for: architecture ' +\n 'decisions (source_type: \"decision\"), user-shared context (\"user_input\"), ' +\n 'corrections (\"correction\"), durable notes, any significant new concept. Do NOT ' +\n 'ingest trivial changes or ephemeral debug context — those belong in the Context ' +\n 'Window (via context_window_add_turn). Pass `data_source_id` explicitly or set ' +\n '`COPASS_INGEST_DATA_SOURCE_ID` in the server env for an implicit target.',\n inputSchema: {\n content: z.string().min(1).describe('The content to ingest.'),\n source_type: z\n .string()\n .optional()\n .describe(\n 'Type tag: code, markdown, json, text, conversation, decision, correction, ' +\n 'user_input. Defaults to \"text\" when omitted.',\n ),\n data_source_id: z\n .string()\n .optional()\n .describe(\n 'Target data source. Falls back to COPASS_INGEST_DATA_SOURCE_ID env var.',\n ),\n project_id: z.string().optional().describe('Override the server default project_id.'),\n storage_only: z\n .boolean()\n .optional()\n .describe('If true, chunk and store but skip ontology ingestion.'),\n occurred_at: z\n .string()\n .optional()\n .describe(\n 'Optional ISO 8601 timestamp anchoring the content to a real-world moment ' +\n '(e.g. when this decision was made, when the user said it). Used as the ' +\n 'default occurred_at for any composed event whose own timestamp is null, ' +\n 'so temporal queries can find it.',\n ),\n },\n },\n async ({ content, source_type, data_source_id, project_id, storage_only, occurred_at }) => {\n try {\n const sourceId = data_source_id ?? config.ingest_data_source_id;\n if (!sourceId) {\n throw new Error(\n 'ingest requires a `data_source_id` argument or COPASS_INGEST_DATA_SOURCE_ID env var. ' +\n 'Register a data source via the REST API or CLI, then pass its id here.',\n );\n }\n\n const response = await client.sources.ingest(config.sandbox_id, sourceId, {\n text: content,\n source_type: source_type ?? 'text',\n project_id: project_id ?? config.project_id,\n storage_only,\n occurred_at,\n });\n\n return mcpResult({\n job_id: response.job_id,\n status: response.status,\n data_source_id: sourceId,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n}\n"],"mappings":"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","names":["import_zod","mcpResult","mcpError","import_zod","mcpResult","mcpError"]}

@@ -409,6 +409,9 @@ #!/usr/bin/env node

project_id: z3.string().optional().describe("Override the server default project_id."),
storage_only: z3.boolean().optional().describe("If true, chunk and store but skip ontology ingestion.")
storage_only: z3.boolean().optional().describe("If true, chunk and store but skip ontology ingestion."),
occurred_at: z3.string().optional().describe(
"Optional ISO 8601 timestamp anchoring the content to a real-world moment (e.g. when this decision was made, when the user said it). Used as the default occurred_at for any composed event whose own timestamp is null, so temporal queries can find it."
)
}
},
async ({ content, source_type, data_source_id, project_id, storage_only }) => {
async ({ content, source_type, data_source_id, project_id, storage_only, occurred_at }) => {
try {

@@ -425,3 +428,4 @@ const sourceId = data_source_id ?? config.ingest_data_source_id;

project_id: project_id ?? config.project_id,
storage_only
storage_only,
occurred_at
});

@@ -428,0 +432,0 @@ return mcpResult3({

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/bin.ts","../src/config.ts","../src/server.ts","../src/windows.ts","../src/tools/retrieval.ts","../src/tools/context-window.ts","../src/tools/ingest.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { CopassClient } from '@copass/core';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { loadConfig } from './config.js';\nimport { buildServer } from './server.js';\nimport { WindowRegistry } from './windows.js';\n\nasync function main(): Promise<void> {\n const config = loadConfig();\n // loadConfig() enforces api_key at runtime; the static type marks it\n // optional so embedded callers (buildServer({ client })) don't have\n // to pass one. The bin path always has it.\n const apiKey = config.api_key!;\n\n const client = new CopassClient({\n apiUrl: config.api_url,\n auth: apiKey.startsWith('olk_')\n ? { type: 'api-key', key: apiKey }\n : { type: 'bearer', token: apiKey },\n });\n\n const windows = new WindowRegistry();\n\n // Pre-attach to a Context Window if the caller passed one via env var.\n // Lets a parent process (e.g. an HTTP server) own window lifecycle and share\n // it across multiple MCP subprocess spawns.\n if (config.context_window_id) {\n try {\n const window = await client.contextWindow.attach({\n sandbox_id: config.sandbox_id,\n data_source_id: config.context_window_id,\n initialTurns: config.context_window_initial_turns,\n });\n windows.set(window);\n const turnCount = config.context_window_initial_turns?.length ?? 0;\n process.stderr.write(\n `copass-mcp: attached to context window ${config.context_window_id}` +\n (turnCount > 0 ? ` (${turnCount} initial turn${turnCount === 1 ? '' : 's'})` : '') +\n '\\n',\n );\n } catch (err) {\n process.stderr.write(\n `copass-mcp: failed to attach to COPASS_CONTEXT_WINDOW_ID=${config.context_window_id}: ${\n err instanceof Error ? err.message : String(err)\n }\\n`,\n );\n throw err;\n }\n }\n\n const server = buildServer({ client, config, windows });\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n process.stderr.write(\n `copass-mcp: started (sandbox=${config.sandbox_id}, preset=${config.preset})\\n`,\n );\n}\n\nmain().catch((err) => {\n process.stderr.write(`copass-mcp: fatal: ${err instanceof Error ? err.message : String(err)}\\n`);\n process.exit(1);\n});\n","import type { ChatMessage, SearchPreset } from '@copass/core';\n\nexport interface ServerConfig {\n api_url: string;\n /**\n * Required when the standalone `copass-mcp` bin builds its own\n * `CopassClient` from this config (`bin.ts`). Optional for embedded\n * use — when a host process (e.g. another MCP server) constructs the\n * `CopassClient` itself and passes it into `buildServer({ client })`,\n * the tool handlers never read this field.\n */\n api_key?: string;\n sandbox_id: string;\n project_id?: string;\n preset: SearchPreset;\n /** Default data_source_id for `ingest` when the caller doesn't pass one. */\n ingest_data_source_id?: string;\n /**\n * If set, the server attaches to this Context Window on startup and makes\n * it the active window. Use when another process (e.g. a Hono server)\n * already created the window and you're launching the MCP server as a\n * subprocess that should share it.\n */\n context_window_id?: string;\n /**\n * Optional pre-existing turns to seed the Context Window's buffer on\n * startup. Makes retrieval immediately window-aware on the first tool\n * call — without these, the first `discover` / `interpret` / `search`\n * after a subprocess spawn sees an empty history.\n *\n * Required when `context_window_id` refers to a thread that has prior\n * turns and the server should dedupe retrieval against them.\n */\n context_window_initial_turns?: ChatMessage[];\n}\n\nconst VALID_PRESETS: readonly SearchPreset[] = [\n 'fast',\n 'auto',\n 'discover',\n 'sql',\n 'max',\n // `-decompose` variants are /search-only. Setting one of these as the\n // MCP subprocess default makes `interpret` fail (decomposition isn't\n // valid on /interpret) — fine when the subprocess is only used for\n // `search`, otherwise override per-call via the `preset` tool arg.\n 'fast-decompose',\n 'auto-decompose',\n 'discover-decompose',\n 'sql-decompose',\n] as const;\n\n/**\n * Read config from `process.env`.\n *\n * - `COPASS_API_KEY` (required)\n * - `COPASS_SANDBOX_ID` (required)\n * - `COPASS_API_URL` (default: https://ai.copass.id)\n * - `COPASS_PROJECT_ID` (optional — default for retrieval/ingest)\n * - `COPASS_PRESET` (default: `auto`). Accepts any `SearchPreset`, but\n * `auto` is the only value whose providers consume the\n * `semantic_alignment_scopes` that `/interpret`'s scope adapter\n * produces — so non-`auto` defaults (and any `-decompose` default)\n * break `interpret`. Leave at `auto` unless the subprocess is\n * search-only, and override per-call via the `preset` tool arg.\n *\n * Throws a descriptive error for missing/invalid values so the MCP client\n * sees an immediate startup failure with actionable text.\n */\nexport function loadConfig(env: NodeJS.ProcessEnv = process.env): ServerConfig {\n const missing: string[] = [];\n const api_key = env.COPASS_API_KEY ?? '';\n const sandbox_id = env.COPASS_SANDBOX_ID ?? '';\n\n if (!api_key) missing.push('COPASS_API_KEY');\n if (!sandbox_id) missing.push('COPASS_SANDBOX_ID');\n\n if (missing.length > 0) {\n throw new Error(\n `@copass/mcp: missing required env var(s): ${missing.join(', ')}. ` +\n `Set them before launching the server.`,\n );\n }\n\n const api_url = env.COPASS_API_URL?.trim() || 'https://ai.copass.id';\n const project_id = env.COPASS_PROJECT_ID?.trim() || undefined;\n const rawPreset = env.COPASS_PRESET?.trim() || 'auto';\n\n if (!VALID_PRESETS.includes(rawPreset as SearchPreset)) {\n throw new Error(\n `@copass/mcp: COPASS_PRESET must be one of ${VALID_PRESETS.join(', ')}; got \"${rawPreset}\"`,\n );\n }\n\n const ingest_data_source_id = env.COPASS_INGEST_DATA_SOURCE_ID?.trim() || undefined;\n const context_window_id = env.COPASS_CONTEXT_WINDOW_ID?.trim() || undefined;\n const context_window_initial_turns = parseInitialTurns(\n env.COPASS_CONTEXT_WINDOW_INITIAL_TURNS,\n );\n\n return {\n api_url,\n api_key,\n sandbox_id,\n project_id,\n preset: rawPreset as SearchPreset,\n ingest_data_source_id,\n context_window_id,\n context_window_initial_turns,\n };\n}\n\nfunction parseInitialTurns(raw: string | undefined): ChatMessage[] | undefined {\n if (!raw || !raw.trim()) return undefined;\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n throw new Error(\n `@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS is not valid JSON: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n if (!Array.isArray(parsed)) {\n throw new Error(\n '@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS must be a JSON array of {role, content} objects',\n );\n }\n const turns: ChatMessage[] = [];\n for (const [i, entry] of parsed.entries()) {\n if (\n !entry ||\n typeof entry !== 'object' ||\n typeof (entry as { role?: unknown }).role !== 'string' ||\n typeof (entry as { content?: unknown }).content !== 'string'\n ) {\n throw new Error(\n `@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS[${i}] must be {role: string, content: string}`,\n );\n }\n const { role, content } = entry as { role: string; content: string };\n if (role !== 'user' && role !== 'assistant' && role !== 'system') {\n throw new Error(\n `@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS[${i}].role must be \"user\" | \"assistant\" | \"system\"; got \"${role}\"`,\n );\n }\n turns.push({ role, content });\n }\n return turns;\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CopassClient } from '@copass/core';\nimport type { ServerConfig } from './config.js';\nimport { WindowRegistry } from './windows.js';\nimport { registerRetrievalTools } from './tools/retrieval.js';\nimport { registerContextWindowTools } from './tools/context-window.js';\nimport { registerIngestTool } from './tools/ingest.js';\n\nexport interface BuildServerOptions {\n client: CopassClient;\n config: ServerConfig;\n /**\n * Optional pre-populated window registry. Useful when a parent process has\n * already created or attached to a Context Window and wants the server to\n * start with it as the active window.\n */\n windows?: WindowRegistry;\n}\n\n/**\n * Assemble the Copass MCP server with every tool registered. Doesn't connect\n * a transport — see `startStdioServer` in `./bin.ts` for the default path,\n * or wire your own transport if embedding.\n */\nexport function buildServer({ client, config, windows }: BuildServerOptions): McpServer {\n const server = new McpServer(\n {\n name: 'copass',\n version: '0.3.0',\n },\n {\n capabilities: { tools: {} },\n },\n );\n\n const registry = windows ?? new WindowRegistry();\n const deps = { client, config, windows: registry };\n\n registerRetrievalTools(server, deps);\n registerContextWindowTools(server, deps);\n registerIngestTool(server, { client, config });\n\n return server;\n}\n","import type { ContextWindow } from '@copass/core';\n\n/**\n * In-memory registry of open Context Windows.\n *\n * Tracks a map of `data_source_id → ContextWindow` plus a single \"active\"\n * window id. Retrieval and add-turn tools use the active window implicitly\n * so the LLM doesn't have to thread an id on every call.\n *\n * For multi-window use cases, callers pass `data_source_id` explicitly and\n * the active id is ignored.\n */\nexport class WindowRegistry {\n private readonly windows = new Map<string, ContextWindow>();\n private activeId: string | null = null;\n\n /** Register a new window and make it active. */\n set(window: ContextWindow): void {\n this.windows.set(window.dataSourceId, window);\n this.activeId = window.dataSourceId;\n }\n\n /** Look up a window by id, or fall back to the active one. */\n resolve(dataSourceId?: string): ContextWindow | undefined {\n const id = dataSourceId ?? this.activeId;\n return id ? this.windows.get(id) : undefined;\n }\n\n /** Make an existing window the active one. Throws if unknown. */\n activate(dataSourceId: string): ContextWindow {\n const window = this.windows.get(dataSourceId);\n if (!window) {\n throw new Error(\n `No window registered for data_source_id=\"${dataSourceId}\" — call context_window_create or context_window_attach first.`,\n );\n }\n this.activeId = dataSourceId;\n return window;\n }\n\n /** Drop a window from the registry. Clears active if it matched. */\n drop(dataSourceId: string): void {\n this.windows.delete(dataSourceId);\n if (this.activeId === dataSourceId) this.activeId = null;\n }\n\n get activeDataSourceId(): string | null {\n return this.activeId;\n }\n}\n","import { z } from 'zod';\nimport {\n DISCOVER_QUERY_PARAM,\n INTERPRET_DESCRIPTION,\n INTERPRET_ITEMS_PARAM,\n INTERPRET_QUERY_PARAM,\n MCP_DISCOVER_DESCRIPTION,\n PRESET_PARAM,\n PROJECT_ID_PARAM,\n SEARCH_DESCRIPTION,\n SEARCH_QUERY_PARAM,\n} from '@copass/config';\nimport type { CopassClient } from '@copass/core';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ServerConfig } from '../config.js';\nimport type { WindowRegistry } from '../windows.js';\n\ninterface RetrievalDeps {\n client: CopassClient;\n config: ServerConfig;\n windows: WindowRegistry;\n}\n\nfunction mcpResult(payload: unknown) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(payload, null, 2) }],\n };\n}\n\nfunction mcpError(error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Error: ${message}` }],\n isError: true,\n };\n}\n\nexport function registerRetrievalTools(server: McpServer, deps: RetrievalDeps): void {\n const { client, config, windows } = deps;\n\n server.registerTool(\n 'discover',\n {\n description: MCP_DISCOVER_DESCRIPTION,\n inputSchema: {\n query: z.string().describe(DISCOVER_QUERY_PARAM),\n project_id: z.string().optional().describe(PROJECT_ID_PARAM),\n },\n },\n async ({ query, project_id }) => {\n try {\n const response = await client.retrieval.discover(config.sandbox_id, {\n query,\n project_id: project_id ?? config.project_id,\n window: windows.resolve(),\n });\n return mcpResult({\n header: response.header,\n items: response.items.map((item) => ({\n score: item.score,\n summary: item.summary,\n canonical_ids: item.canonical_ids,\n })),\n next_steps: response.next_steps,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'interpret',\n {\n description: INTERPRET_DESCRIPTION,\n inputSchema: {\n query: z.string().describe(INTERPRET_QUERY_PARAM),\n items: z.array(z.array(z.string()).min(1)).min(1).describe(INTERPRET_ITEMS_PARAM),\n preset: z.enum(['fast', 'auto', 'max']).optional().describe(PRESET_PARAM),\n project_id: z.string().optional().describe(PROJECT_ID_PARAM),\n },\n },\n async ({ query, items, preset, project_id }) => {\n try {\n const response = await client.retrieval.interpret(config.sandbox_id, {\n query,\n items,\n project_id: project_id ?? config.project_id,\n window: windows.resolve(),\n preset: preset ?? config.preset,\n });\n return mcpResult({ brief: response.brief });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'search',\n {\n description: SEARCH_DESCRIPTION,\n inputSchema: {\n query: z.string().describe(SEARCH_QUERY_PARAM),\n // `max` is omitted — the server returns 403 for public callers,\n // so exposing it would only yield confusing tool-use errors.\n // `-decompose` variants split the question into sub-questions and\n // run the base preset on each before a combined synthesis.\n preset: z\n .enum([\n 'fast',\n 'auto',\n 'discover',\n 'sql',\n 'fast-decompose',\n 'auto-decompose',\n 'discover-decompose',\n 'sql-decompose',\n ])\n .optional()\n .describe(PRESET_PARAM),\n project_id: z.string().optional().describe(PROJECT_ID_PARAM),\n },\n },\n async ({ query, preset, project_id }) => {\n try {\n const response = await client.retrieval.search(config.sandbox_id, {\n query,\n project_id: project_id ?? config.project_id,\n window: windows.resolve(),\n preset: preset ?? config.preset,\n });\n return mcpResult({ answer: response.answer });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n}\n","import { z } from 'zod';\nimport type { CopassClient } from '@copass/core';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ServerConfig } from '../config.js';\nimport type { WindowRegistry } from '../windows.js';\n\ninterface ContextWindowDeps {\n client: CopassClient;\n config: ServerConfig;\n windows: WindowRegistry;\n}\n\nfunction mcpResult(payload: unknown) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(payload, null, 2) }],\n };\n}\n\nfunction mcpError(error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Error: ${message}` }],\n isError: true,\n };\n}\n\nexport function registerContextWindowTools(server: McpServer, deps: ContextWindowDeps): void {\n const { client, config, windows } = deps;\n\n server.registerTool(\n 'context_window_create',\n {\n description:\n 'Open a new Context Window — an ephemeral data source tracking this conversation. ' +\n 'Subsequent retrieval calls become automatically window-aware, and every turn you ' +\n 'record via `context_window_add_turn` is ingested into the graph so past turns ' +\n 'become retrievable. Returns a `data_source_id`; persist it on your side if you ' +\n 'may want to resume this conversation later via `context_window_attach`.',\n inputSchema: {\n project_id: z.string().optional().describe('Override the server default project_id.'),\n name: z.string().optional().describe('Optional stable name for the underlying data source.'),\n },\n },\n async ({ project_id, name }) => {\n try {\n const window = await client.contextWindow.create({\n sandbox_id: config.sandbox_id,\n project_id: project_id ?? config.project_id,\n name,\n });\n windows.set(window);\n return mcpResult({\n data_source_id: window.dataSourceId,\n active: true,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'context_window_add_turn',\n {\n description:\n 'Append a turn to the active Context Window and push it into the graph. Call on ' +\n 'every user message AND every assistant message so the thread itself becomes ' +\n 'retrievable. If you omit `data_source_id`, the active window is used.',\n inputSchema: {\n role: z\n .enum(['user', 'assistant', 'system'])\n .describe('Role of the speaker for this turn.'),\n content: z.string().describe('The turn content.'),\n data_source_id: z\n .string()\n .optional()\n .describe('Override the active window id (for multi-window use cases).'),\n },\n },\n async ({ role, content, data_source_id }) => {\n try {\n const window = windows.resolve(data_source_id);\n if (!window) {\n throw new Error(\n 'No active Context Window — call context_window_create or context_window_attach first.',\n );\n }\n await window.addTurn({ role, content });\n return mcpResult({\n data_source_id: window.dataSourceId,\n turn_count: window.getTurns().length,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'context_window_attach',\n {\n description:\n 'Resume an existing Context Window by `data_source_id` (one you previously persisted ' +\n 'on your side after `context_window_create`). Makes the resumed window the active ' +\n 'window. Pass `initial_turns` to seed the local buffer for immediate window-aware ' +\n 'retrieval, otherwise the buffer starts empty and fills as you call add_turn.',\n inputSchema: {\n data_source_id: z.string().describe('Id of the Context Window data source to resume.'),\n initial_turns: z\n .array(\n z.object({\n role: z.enum(['user', 'assistant', 'system']),\n content: z.string(),\n }),\n )\n .optional()\n .describe('Optional pre-existing turns to seed the local buffer.'),\n },\n },\n async ({ data_source_id, initial_turns }) => {\n try {\n const window = await client.contextWindow.attach({\n sandbox_id: config.sandbox_id,\n data_source_id,\n initialTurns: initial_turns,\n });\n windows.set(window);\n return mcpResult({\n data_source_id: window.dataSourceId,\n turn_count: window.getTurns().length,\n active: true,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'context_window_close',\n {\n description:\n 'Close a Context Window — flips the underlying data source to `disconnected` ' +\n 'immediately instead of waiting for TTL. Best-effort; idempotent. If you omit ' +\n '`data_source_id`, the active window is closed.',\n inputSchema: {\n data_source_id: z\n .string()\n .optional()\n .describe('Override the active window id.'),\n },\n },\n async ({ data_source_id }) => {\n try {\n const window = windows.resolve(data_source_id);\n if (!window) {\n throw new Error('No active Context Window to close.');\n }\n await window.close();\n windows.drop(window.dataSourceId);\n return mcpResult({\n data_source_id: window.dataSourceId,\n closed: true,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n}\n","import { z } from 'zod';\nimport type { CopassClient } from '@copass/core';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ServerConfig } from '../config.js';\n\ninterface IngestDeps {\n client: CopassClient;\n config: ServerConfig;\n}\n\nfunction mcpResult(payload: unknown) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(payload, null, 2) }],\n };\n}\n\nfunction mcpError(error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Error: ${message}` }],\n isError: true,\n };\n}\n\nexport function registerIngestTool(server: McpServer, deps: IngestDeps): void {\n const { client, config } = deps;\n\n server.registerTool(\n 'ingest',\n {\n description:\n 'Push content into the knowledge graph via a data source. Use for: architecture ' +\n 'decisions (source_type: \"decision\"), user-shared context (\"user_input\"), ' +\n 'corrections (\"correction\"), durable notes, any significant new concept. Do NOT ' +\n 'ingest trivial changes or ephemeral debug context — those belong in the Context ' +\n 'Window (via context_window_add_turn). Pass `data_source_id` explicitly or set ' +\n '`COPASS_INGEST_DATA_SOURCE_ID` in the server env for an implicit target.',\n inputSchema: {\n content: z.string().min(1).describe('The content to ingest.'),\n source_type: z\n .string()\n .optional()\n .describe(\n 'Type tag: code, markdown, json, text, conversation, decision, correction, ' +\n 'user_input. Defaults to \"text\" when omitted.',\n ),\n data_source_id: z\n .string()\n .optional()\n .describe(\n 'Target data source. Falls back to COPASS_INGEST_DATA_SOURCE_ID env var.',\n ),\n project_id: z.string().optional().describe('Override the server default project_id.'),\n storage_only: z\n .boolean()\n .optional()\n .describe('If true, chunk and store but skip ontology ingestion.'),\n },\n },\n async ({ content, source_type, data_source_id, project_id, storage_only }) => {\n try {\n const sourceId = data_source_id ?? config.ingest_data_source_id;\n if (!sourceId) {\n throw new Error(\n 'ingest requires a `data_source_id` argument or COPASS_INGEST_DATA_SOURCE_ID env var. ' +\n 'Register a data source via the REST API or CLI, then pass its id here.',\n );\n }\n\n const response = await client.sources.ingest(config.sandbox_id, sourceId, {\n text: content,\n source_type: source_type ?? 'text',\n project_id: project_id ?? config.project_id,\n storage_only,\n });\n\n return mcpResult({\n job_id: response.job_id,\n status: response.status,\n data_source_id: sourceId,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n}\n"],"mappings":"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","names":["z","mcpResult","mcpError","z","mcpResult","mcpError"]}
{"version":3,"sources":["../src/bin.ts","../src/config.ts","../src/server.ts","../src/windows.ts","../src/tools/retrieval.ts","../src/tools/context-window.ts","../src/tools/ingest.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { CopassClient } from '@copass/core';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { loadConfig } from './config.js';\nimport { buildServer } from './server.js';\nimport { WindowRegistry } from './windows.js';\n\nasync function main(): Promise<void> {\n const config = loadConfig();\n // loadConfig() enforces api_key at runtime; the static type marks it\n // optional so embedded callers (buildServer({ client })) don't have\n // to pass one. The bin path always has it.\n const apiKey = config.api_key!;\n\n const client = new CopassClient({\n apiUrl: config.api_url,\n auth: apiKey.startsWith('olk_')\n ? { type: 'api-key', key: apiKey }\n : { type: 'bearer', token: apiKey },\n });\n\n const windows = new WindowRegistry();\n\n // Pre-attach to a Context Window if the caller passed one via env var.\n // Lets a parent process (e.g. an HTTP server) own window lifecycle and share\n // it across multiple MCP subprocess spawns.\n if (config.context_window_id) {\n try {\n const window = await client.contextWindow.attach({\n sandbox_id: config.sandbox_id,\n data_source_id: config.context_window_id,\n initialTurns: config.context_window_initial_turns,\n });\n windows.set(window);\n const turnCount = config.context_window_initial_turns?.length ?? 0;\n process.stderr.write(\n `copass-mcp: attached to context window ${config.context_window_id}` +\n (turnCount > 0 ? ` (${turnCount} initial turn${turnCount === 1 ? '' : 's'})` : '') +\n '\\n',\n );\n } catch (err) {\n process.stderr.write(\n `copass-mcp: failed to attach to COPASS_CONTEXT_WINDOW_ID=${config.context_window_id}: ${\n err instanceof Error ? err.message : String(err)\n }\\n`,\n );\n throw err;\n }\n }\n\n const server = buildServer({ client, config, windows });\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n process.stderr.write(\n `copass-mcp: started (sandbox=${config.sandbox_id}, preset=${config.preset})\\n`,\n );\n}\n\nmain().catch((err) => {\n process.stderr.write(`copass-mcp: fatal: ${err instanceof Error ? err.message : String(err)}\\n`);\n process.exit(1);\n});\n","import type { ChatMessage, SearchPreset } from '@copass/core';\n\nexport interface ServerConfig {\n api_url: string;\n /**\n * Required when the standalone `copass-mcp` bin builds its own\n * `CopassClient` from this config (`bin.ts`). Optional for embedded\n * use — when a host process (e.g. another MCP server) constructs the\n * `CopassClient` itself and passes it into `buildServer({ client })`,\n * the tool handlers never read this field.\n */\n api_key?: string;\n sandbox_id: string;\n project_id?: string;\n preset: SearchPreset;\n /** Default data_source_id for `ingest` when the caller doesn't pass one. */\n ingest_data_source_id?: string;\n /**\n * If set, the server attaches to this Context Window on startup and makes\n * it the active window. Use when another process (e.g. a Hono server)\n * already created the window and you're launching the MCP server as a\n * subprocess that should share it.\n */\n context_window_id?: string;\n /**\n * Optional pre-existing turns to seed the Context Window's buffer on\n * startup. Makes retrieval immediately window-aware on the first tool\n * call — without these, the first `discover` / `interpret` / `search`\n * after a subprocess spawn sees an empty history.\n *\n * Required when `context_window_id` refers to a thread that has prior\n * turns and the server should dedupe retrieval against them.\n */\n context_window_initial_turns?: ChatMessage[];\n}\n\nconst VALID_PRESETS: readonly SearchPreset[] = [\n 'fast',\n 'auto',\n 'discover',\n 'sql',\n 'max',\n // `-decompose` variants are /search-only. Setting one of these as the\n // MCP subprocess default makes `interpret` fail (decomposition isn't\n // valid on /interpret) — fine when the subprocess is only used for\n // `search`, otherwise override per-call via the `preset` tool arg.\n 'fast-decompose',\n 'auto-decompose',\n 'discover-decompose',\n 'sql-decompose',\n] as const;\n\n/**\n * Read config from `process.env`.\n *\n * - `COPASS_API_KEY` (required)\n * - `COPASS_SANDBOX_ID` (required)\n * - `COPASS_API_URL` (default: https://ai.copass.id)\n * - `COPASS_PROJECT_ID` (optional — default for retrieval/ingest)\n * - `COPASS_PRESET` (default: `auto`). Accepts any `SearchPreset`, but\n * `auto` is the only value whose providers consume the\n * `semantic_alignment_scopes` that `/interpret`'s scope adapter\n * produces — so non-`auto` defaults (and any `-decompose` default)\n * break `interpret`. Leave at `auto` unless the subprocess is\n * search-only, and override per-call via the `preset` tool arg.\n *\n * Throws a descriptive error for missing/invalid values so the MCP client\n * sees an immediate startup failure with actionable text.\n */\nexport function loadConfig(env: NodeJS.ProcessEnv = process.env): ServerConfig {\n const missing: string[] = [];\n const api_key = env.COPASS_API_KEY ?? '';\n const sandbox_id = env.COPASS_SANDBOX_ID ?? '';\n\n if (!api_key) missing.push('COPASS_API_KEY');\n if (!sandbox_id) missing.push('COPASS_SANDBOX_ID');\n\n if (missing.length > 0) {\n throw new Error(\n `@copass/mcp: missing required env var(s): ${missing.join(', ')}. ` +\n `Set them before launching the server.`,\n );\n }\n\n const api_url = env.COPASS_API_URL?.trim() || 'https://ai.copass.id';\n const project_id = env.COPASS_PROJECT_ID?.trim() || undefined;\n const rawPreset = env.COPASS_PRESET?.trim() || 'auto';\n\n if (!VALID_PRESETS.includes(rawPreset as SearchPreset)) {\n throw new Error(\n `@copass/mcp: COPASS_PRESET must be one of ${VALID_PRESETS.join(', ')}; got \"${rawPreset}\"`,\n );\n }\n\n const ingest_data_source_id = env.COPASS_INGEST_DATA_SOURCE_ID?.trim() || undefined;\n const context_window_id = env.COPASS_CONTEXT_WINDOW_ID?.trim() || undefined;\n const context_window_initial_turns = parseInitialTurns(\n env.COPASS_CONTEXT_WINDOW_INITIAL_TURNS,\n );\n\n return {\n api_url,\n api_key,\n sandbox_id,\n project_id,\n preset: rawPreset as SearchPreset,\n ingest_data_source_id,\n context_window_id,\n context_window_initial_turns,\n };\n}\n\nfunction parseInitialTurns(raw: string | undefined): ChatMessage[] | undefined {\n if (!raw || !raw.trim()) return undefined;\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n throw new Error(\n `@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS is not valid JSON: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n if (!Array.isArray(parsed)) {\n throw new Error(\n '@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS must be a JSON array of {role, content} objects',\n );\n }\n const turns: ChatMessage[] = [];\n for (const [i, entry] of parsed.entries()) {\n if (\n !entry ||\n typeof entry !== 'object' ||\n typeof (entry as { role?: unknown }).role !== 'string' ||\n typeof (entry as { content?: unknown }).content !== 'string'\n ) {\n throw new Error(\n `@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS[${i}] must be {role: string, content: string}`,\n );\n }\n const { role, content } = entry as { role: string; content: string };\n if (role !== 'user' && role !== 'assistant' && role !== 'system') {\n throw new Error(\n `@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS[${i}].role must be \"user\" | \"assistant\" | \"system\"; got \"${role}\"`,\n );\n }\n turns.push({ role, content });\n }\n return turns;\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CopassClient } from '@copass/core';\nimport type { ServerConfig } from './config.js';\nimport { WindowRegistry } from './windows.js';\nimport { registerRetrievalTools } from './tools/retrieval.js';\nimport { registerContextWindowTools } from './tools/context-window.js';\nimport { registerIngestTool } from './tools/ingest.js';\n\nexport interface BuildServerOptions {\n client: CopassClient;\n config: ServerConfig;\n /**\n * Optional pre-populated window registry. Useful when a parent process has\n * already created or attached to a Context Window and wants the server to\n * start with it as the active window.\n */\n windows?: WindowRegistry;\n}\n\n/**\n * Assemble the Copass MCP server with every tool registered. Doesn't connect\n * a transport — see `startStdioServer` in `./bin.ts` for the default path,\n * or wire your own transport if embedding.\n */\nexport function buildServer({ client, config, windows }: BuildServerOptions): McpServer {\n const server = new McpServer(\n {\n name: 'copass',\n version: '0.3.0',\n },\n {\n capabilities: { tools: {} },\n },\n );\n\n const registry = windows ?? new WindowRegistry();\n const deps = { client, config, windows: registry };\n\n registerRetrievalTools(server, deps);\n registerContextWindowTools(server, deps);\n registerIngestTool(server, { client, config });\n\n return server;\n}\n","import type { ContextWindow } from '@copass/core';\n\n/**\n * In-memory registry of open Context Windows.\n *\n * Tracks a map of `data_source_id → ContextWindow` plus a single \"active\"\n * window id. Retrieval and add-turn tools use the active window implicitly\n * so the LLM doesn't have to thread an id on every call.\n *\n * For multi-window use cases, callers pass `data_source_id` explicitly and\n * the active id is ignored.\n */\nexport class WindowRegistry {\n private readonly windows = new Map<string, ContextWindow>();\n private activeId: string | null = null;\n\n /** Register a new window and make it active. */\n set(window: ContextWindow): void {\n this.windows.set(window.dataSourceId, window);\n this.activeId = window.dataSourceId;\n }\n\n /** Look up a window by id, or fall back to the active one. */\n resolve(dataSourceId?: string): ContextWindow | undefined {\n const id = dataSourceId ?? this.activeId;\n return id ? this.windows.get(id) : undefined;\n }\n\n /** Make an existing window the active one. Throws if unknown. */\n activate(dataSourceId: string): ContextWindow {\n const window = this.windows.get(dataSourceId);\n if (!window) {\n throw new Error(\n `No window registered for data_source_id=\"${dataSourceId}\" — call context_window_create or context_window_attach first.`,\n );\n }\n this.activeId = dataSourceId;\n return window;\n }\n\n /** Drop a window from the registry. Clears active if it matched. */\n drop(dataSourceId: string): void {\n this.windows.delete(dataSourceId);\n if (this.activeId === dataSourceId) this.activeId = null;\n }\n\n get activeDataSourceId(): string | null {\n return this.activeId;\n }\n}\n","import { z } from 'zod';\nimport {\n DISCOVER_QUERY_PARAM,\n INTERPRET_DESCRIPTION,\n INTERPRET_ITEMS_PARAM,\n INTERPRET_QUERY_PARAM,\n MCP_DISCOVER_DESCRIPTION,\n PRESET_PARAM,\n PROJECT_ID_PARAM,\n SEARCH_DESCRIPTION,\n SEARCH_QUERY_PARAM,\n} from '@copass/config';\nimport type { CopassClient } from '@copass/core';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ServerConfig } from '../config.js';\nimport type { WindowRegistry } from '../windows.js';\n\ninterface RetrievalDeps {\n client: CopassClient;\n config: ServerConfig;\n windows: WindowRegistry;\n}\n\nfunction mcpResult(payload: unknown) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(payload, null, 2) }],\n };\n}\n\nfunction mcpError(error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Error: ${message}` }],\n isError: true,\n };\n}\n\nexport function registerRetrievalTools(server: McpServer, deps: RetrievalDeps): void {\n const { client, config, windows } = deps;\n\n server.registerTool(\n 'discover',\n {\n description: MCP_DISCOVER_DESCRIPTION,\n inputSchema: {\n query: z.string().describe(DISCOVER_QUERY_PARAM),\n project_id: z.string().optional().describe(PROJECT_ID_PARAM),\n },\n },\n async ({ query, project_id }) => {\n try {\n const response = await client.retrieval.discover(config.sandbox_id, {\n query,\n project_id: project_id ?? config.project_id,\n window: windows.resolve(),\n });\n return mcpResult({\n header: response.header,\n items: response.items.map((item) => ({\n score: item.score,\n summary: item.summary,\n canonical_ids: item.canonical_ids,\n })),\n next_steps: response.next_steps,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'interpret',\n {\n description: INTERPRET_DESCRIPTION,\n inputSchema: {\n query: z.string().describe(INTERPRET_QUERY_PARAM),\n items: z.array(z.array(z.string()).min(1)).min(1).describe(INTERPRET_ITEMS_PARAM),\n preset: z.enum(['fast', 'auto', 'max']).optional().describe(PRESET_PARAM),\n project_id: z.string().optional().describe(PROJECT_ID_PARAM),\n },\n },\n async ({ query, items, preset, project_id }) => {\n try {\n const response = await client.retrieval.interpret(config.sandbox_id, {\n query,\n items,\n project_id: project_id ?? config.project_id,\n window: windows.resolve(),\n preset: preset ?? config.preset,\n });\n return mcpResult({ brief: response.brief });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'search',\n {\n description: SEARCH_DESCRIPTION,\n inputSchema: {\n query: z.string().describe(SEARCH_QUERY_PARAM),\n // `max` is omitted — the server returns 403 for public callers,\n // so exposing it would only yield confusing tool-use errors.\n // `-decompose` variants split the question into sub-questions and\n // run the base preset on each before a combined synthesis.\n preset: z\n .enum([\n 'fast',\n 'auto',\n 'discover',\n 'sql',\n 'fast-decompose',\n 'auto-decompose',\n 'discover-decompose',\n 'sql-decompose',\n ])\n .optional()\n .describe(PRESET_PARAM),\n project_id: z.string().optional().describe(PROJECT_ID_PARAM),\n },\n },\n async ({ query, preset, project_id }) => {\n try {\n const response = await client.retrieval.search(config.sandbox_id, {\n query,\n project_id: project_id ?? config.project_id,\n window: windows.resolve(),\n preset: preset ?? config.preset,\n });\n return mcpResult({ answer: response.answer });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n}\n","import { z } from 'zod';\nimport type { CopassClient } from '@copass/core';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ServerConfig } from '../config.js';\nimport type { WindowRegistry } from '../windows.js';\n\ninterface ContextWindowDeps {\n client: CopassClient;\n config: ServerConfig;\n windows: WindowRegistry;\n}\n\nfunction mcpResult(payload: unknown) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(payload, null, 2) }],\n };\n}\n\nfunction mcpError(error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Error: ${message}` }],\n isError: true,\n };\n}\n\nexport function registerContextWindowTools(server: McpServer, deps: ContextWindowDeps): void {\n const { client, config, windows } = deps;\n\n server.registerTool(\n 'context_window_create',\n {\n description:\n 'Open a new Context Window — an ephemeral data source tracking this conversation. ' +\n 'Subsequent retrieval calls become automatically window-aware, and every turn you ' +\n 'record via `context_window_add_turn` is ingested into the graph so past turns ' +\n 'become retrievable. Returns a `data_source_id`; persist it on your side if you ' +\n 'may want to resume this conversation later via `context_window_attach`.',\n inputSchema: {\n project_id: z.string().optional().describe('Override the server default project_id.'),\n name: z.string().optional().describe('Optional stable name for the underlying data source.'),\n },\n },\n async ({ project_id, name }) => {\n try {\n const window = await client.contextWindow.create({\n sandbox_id: config.sandbox_id,\n project_id: project_id ?? config.project_id,\n name,\n });\n windows.set(window);\n return mcpResult({\n data_source_id: window.dataSourceId,\n active: true,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'context_window_add_turn',\n {\n description:\n 'Append a turn to the active Context Window and push it into the graph. Call on ' +\n 'every user message AND every assistant message so the thread itself becomes ' +\n 'retrievable. If you omit `data_source_id`, the active window is used.',\n inputSchema: {\n role: z\n .enum(['user', 'assistant', 'system'])\n .describe('Role of the speaker for this turn.'),\n content: z.string().describe('The turn content.'),\n data_source_id: z\n .string()\n .optional()\n .describe('Override the active window id (for multi-window use cases).'),\n },\n },\n async ({ role, content, data_source_id }) => {\n try {\n const window = windows.resolve(data_source_id);\n if (!window) {\n throw new Error(\n 'No active Context Window — call context_window_create or context_window_attach first.',\n );\n }\n await window.addTurn({ role, content });\n return mcpResult({\n data_source_id: window.dataSourceId,\n turn_count: window.getTurns().length,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'context_window_attach',\n {\n description:\n 'Resume an existing Context Window by `data_source_id` (one you previously persisted ' +\n 'on your side after `context_window_create`). Makes the resumed window the active ' +\n 'window. Pass `initial_turns` to seed the local buffer for immediate window-aware ' +\n 'retrieval, otherwise the buffer starts empty and fills as you call add_turn.',\n inputSchema: {\n data_source_id: z.string().describe('Id of the Context Window data source to resume.'),\n initial_turns: z\n .array(\n z.object({\n role: z.enum(['user', 'assistant', 'system']),\n content: z.string(),\n }),\n )\n .optional()\n .describe('Optional pre-existing turns to seed the local buffer.'),\n },\n },\n async ({ data_source_id, initial_turns }) => {\n try {\n const window = await client.contextWindow.attach({\n sandbox_id: config.sandbox_id,\n data_source_id,\n initialTurns: initial_turns,\n });\n windows.set(window);\n return mcpResult({\n data_source_id: window.dataSourceId,\n turn_count: window.getTurns().length,\n active: true,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'context_window_close',\n {\n description:\n 'Close a Context Window — flips the underlying data source to `disconnected` ' +\n 'immediately instead of waiting for TTL. Best-effort; idempotent. If you omit ' +\n '`data_source_id`, the active window is closed.',\n inputSchema: {\n data_source_id: z\n .string()\n .optional()\n .describe('Override the active window id.'),\n },\n },\n async ({ data_source_id }) => {\n try {\n const window = windows.resolve(data_source_id);\n if (!window) {\n throw new Error('No active Context Window to close.');\n }\n await window.close();\n windows.drop(window.dataSourceId);\n return mcpResult({\n data_source_id: window.dataSourceId,\n closed: true,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n}\n","import { z } from 'zod';\nimport type { CopassClient } from '@copass/core';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ServerConfig } from '../config.js';\n\ninterface IngestDeps {\n client: CopassClient;\n config: ServerConfig;\n}\n\nfunction mcpResult(payload: unknown) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(payload, null, 2) }],\n };\n}\n\nfunction mcpError(error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Error: ${message}` }],\n isError: true,\n };\n}\n\nexport function registerIngestTool(server: McpServer, deps: IngestDeps): void {\n const { client, config } = deps;\n\n server.registerTool(\n 'ingest',\n {\n description:\n 'Push content into the knowledge graph via a data source. Use for: architecture ' +\n 'decisions (source_type: \"decision\"), user-shared context (\"user_input\"), ' +\n 'corrections (\"correction\"), durable notes, any significant new concept. Do NOT ' +\n 'ingest trivial changes or ephemeral debug context — those belong in the Context ' +\n 'Window (via context_window_add_turn). Pass `data_source_id` explicitly or set ' +\n '`COPASS_INGEST_DATA_SOURCE_ID` in the server env for an implicit target.',\n inputSchema: {\n content: z.string().min(1).describe('The content to ingest.'),\n source_type: z\n .string()\n .optional()\n .describe(\n 'Type tag: code, markdown, json, text, conversation, decision, correction, ' +\n 'user_input. Defaults to \"text\" when omitted.',\n ),\n data_source_id: z\n .string()\n .optional()\n .describe(\n 'Target data source. Falls back to COPASS_INGEST_DATA_SOURCE_ID env var.',\n ),\n project_id: z.string().optional().describe('Override the server default project_id.'),\n storage_only: z\n .boolean()\n .optional()\n .describe('If true, chunk and store but skip ontology ingestion.'),\n occurred_at: z\n .string()\n .optional()\n .describe(\n 'Optional ISO 8601 timestamp anchoring the content to a real-world moment ' +\n '(e.g. when this decision was made, when the user said it). Used as the ' +\n 'default occurred_at for any composed event whose own timestamp is null, ' +\n 'so temporal queries can find it.',\n ),\n },\n },\n async ({ content, source_type, data_source_id, project_id, storage_only, occurred_at }) => {\n try {\n const sourceId = data_source_id ?? config.ingest_data_source_id;\n if (!sourceId) {\n throw new Error(\n 'ingest requires a `data_source_id` argument or COPASS_INGEST_DATA_SOURCE_ID env var. ' +\n 'Register a data source via the REST API or CLI, then pass its id here.',\n );\n }\n\n const response = await client.sources.ingest(config.sandbox_id, sourceId, {\n text: content,\n source_type: source_type ?? 'text',\n project_id: project_id ?? config.project_id,\n storage_only,\n occurred_at,\n });\n\n return mcpResult({\n job_id: response.job_id,\n status: response.status,\n data_source_id: sourceId,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n}\n"],"mappings":"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","names":["z","mcpResult","mcpError","z","mcpResult","mcpError"]}

@@ -340,6 +340,9 @@ "use strict";

project_id: import_zod3.z.string().optional().describe("Override the server default project_id."),
storage_only: import_zod3.z.boolean().optional().describe("If true, chunk and store but skip ontology ingestion.")
storage_only: import_zod3.z.boolean().optional().describe("If true, chunk and store but skip ontology ingestion."),
occurred_at: import_zod3.z.string().optional().describe(
"Optional ISO 8601 timestamp anchoring the content to a real-world moment (e.g. when this decision was made, when the user said it). Used as the default occurred_at for any composed event whose own timestamp is null, so temporal queries can find it."
)
}
},
async ({ content, source_type, data_source_id, project_id, storage_only }) => {
async ({ content, source_type, data_source_id, project_id, storage_only, occurred_at }) => {
try {

@@ -356,3 +359,4 @@ const sourceId = data_source_id ?? config.ingest_data_source_id;

project_id: project_id ?? config.project_id,
storage_only
storage_only,
occurred_at
});

@@ -359,0 +363,0 @@ return mcpResult3({

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/index.ts","../src/server.ts","../src/windows.ts","../src/tools/retrieval.ts","../src/tools/context-window.ts","../src/tools/ingest.ts","../src/config.ts"],"sourcesContent":["export { buildServer } from './server.js';\nexport type { BuildServerOptions } from './server.js';\nexport { loadConfig } from './config.js';\nexport type { ServerConfig } from './config.js';\nexport { WindowRegistry } from './windows.js';\n\n// Sub-registrars — for callers that want to compose tools onto an\n// existing `McpServer` rather than spinning up a whole `buildServer()`.\n// Pick the tool groups you want and skip the rest (e.g. embed\n// `discover` / `interpret` / `search` without the SDK ingest when the\n// host process owns its own ingest tool).\nexport { registerRetrievalTools } from './tools/retrieval.js';\nexport { registerContextWindowTools } from './tools/context-window.js';\nexport { registerIngestTool } from './tools/ingest.js';\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CopassClient } from '@copass/core';\nimport type { ServerConfig } from './config.js';\nimport { WindowRegistry } from './windows.js';\nimport { registerRetrievalTools } from './tools/retrieval.js';\nimport { registerContextWindowTools } from './tools/context-window.js';\nimport { registerIngestTool } from './tools/ingest.js';\n\nexport interface BuildServerOptions {\n client: CopassClient;\n config: ServerConfig;\n /**\n * Optional pre-populated window registry. Useful when a parent process has\n * already created or attached to a Context Window and wants the server to\n * start with it as the active window.\n */\n windows?: WindowRegistry;\n}\n\n/**\n * Assemble the Copass MCP server with every tool registered. Doesn't connect\n * a transport — see `startStdioServer` in `./bin.ts` for the default path,\n * or wire your own transport if embedding.\n */\nexport function buildServer({ client, config, windows }: BuildServerOptions): McpServer {\n const server = new McpServer(\n {\n name: 'copass',\n version: '0.3.0',\n },\n {\n capabilities: { tools: {} },\n },\n );\n\n const registry = windows ?? new WindowRegistry();\n const deps = { client, config, windows: registry };\n\n registerRetrievalTools(server, deps);\n registerContextWindowTools(server, deps);\n registerIngestTool(server, { client, config });\n\n return server;\n}\n","import type { ContextWindow } from '@copass/core';\n\n/**\n * In-memory registry of open Context Windows.\n *\n * Tracks a map of `data_source_id → ContextWindow` plus a single \"active\"\n * window id. Retrieval and add-turn tools use the active window implicitly\n * so the LLM doesn't have to thread an id on every call.\n *\n * For multi-window use cases, callers pass `data_source_id` explicitly and\n * the active id is ignored.\n */\nexport class WindowRegistry {\n private readonly windows = new Map<string, ContextWindow>();\n private activeId: string | null = null;\n\n /** Register a new window and make it active. */\n set(window: ContextWindow): void {\n this.windows.set(window.dataSourceId, window);\n this.activeId = window.dataSourceId;\n }\n\n /** Look up a window by id, or fall back to the active one. */\n resolve(dataSourceId?: string): ContextWindow | undefined {\n const id = dataSourceId ?? this.activeId;\n return id ? this.windows.get(id) : undefined;\n }\n\n /** Make an existing window the active one. Throws if unknown. */\n activate(dataSourceId: string): ContextWindow {\n const window = this.windows.get(dataSourceId);\n if (!window) {\n throw new Error(\n `No window registered for data_source_id=\"${dataSourceId}\" — call context_window_create or context_window_attach first.`,\n );\n }\n this.activeId = dataSourceId;\n return window;\n }\n\n /** Drop a window from the registry. Clears active if it matched. */\n drop(dataSourceId: string): void {\n this.windows.delete(dataSourceId);\n if (this.activeId === dataSourceId) this.activeId = null;\n }\n\n get activeDataSourceId(): string | null {\n return this.activeId;\n }\n}\n","import { z } from 'zod';\nimport {\n DISCOVER_QUERY_PARAM,\n INTERPRET_DESCRIPTION,\n INTERPRET_ITEMS_PARAM,\n INTERPRET_QUERY_PARAM,\n MCP_DISCOVER_DESCRIPTION,\n PRESET_PARAM,\n PROJECT_ID_PARAM,\n SEARCH_DESCRIPTION,\n SEARCH_QUERY_PARAM,\n} from '@copass/config';\nimport type { CopassClient } from '@copass/core';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ServerConfig } from '../config.js';\nimport type { WindowRegistry } from '../windows.js';\n\ninterface RetrievalDeps {\n client: CopassClient;\n config: ServerConfig;\n windows: WindowRegistry;\n}\n\nfunction mcpResult(payload: unknown) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(payload, null, 2) }],\n };\n}\n\nfunction mcpError(error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Error: ${message}` }],\n isError: true,\n };\n}\n\nexport function registerRetrievalTools(server: McpServer, deps: RetrievalDeps): void {\n const { client, config, windows } = deps;\n\n server.registerTool(\n 'discover',\n {\n description: MCP_DISCOVER_DESCRIPTION,\n inputSchema: {\n query: z.string().describe(DISCOVER_QUERY_PARAM),\n project_id: z.string().optional().describe(PROJECT_ID_PARAM),\n },\n },\n async ({ query, project_id }) => {\n try {\n const response = await client.retrieval.discover(config.sandbox_id, {\n query,\n project_id: project_id ?? config.project_id,\n window: windows.resolve(),\n });\n return mcpResult({\n header: response.header,\n items: response.items.map((item) => ({\n score: item.score,\n summary: item.summary,\n canonical_ids: item.canonical_ids,\n })),\n next_steps: response.next_steps,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'interpret',\n {\n description: INTERPRET_DESCRIPTION,\n inputSchema: {\n query: z.string().describe(INTERPRET_QUERY_PARAM),\n items: z.array(z.array(z.string()).min(1)).min(1).describe(INTERPRET_ITEMS_PARAM),\n preset: z.enum(['fast', 'auto', 'max']).optional().describe(PRESET_PARAM),\n project_id: z.string().optional().describe(PROJECT_ID_PARAM),\n },\n },\n async ({ query, items, preset, project_id }) => {\n try {\n const response = await client.retrieval.interpret(config.sandbox_id, {\n query,\n items,\n project_id: project_id ?? config.project_id,\n window: windows.resolve(),\n preset: preset ?? config.preset,\n });\n return mcpResult({ brief: response.brief });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'search',\n {\n description: SEARCH_DESCRIPTION,\n inputSchema: {\n query: z.string().describe(SEARCH_QUERY_PARAM),\n // `max` is omitted — the server returns 403 for public callers,\n // so exposing it would only yield confusing tool-use errors.\n // `-decompose` variants split the question into sub-questions and\n // run the base preset on each before a combined synthesis.\n preset: z\n .enum([\n 'fast',\n 'auto',\n 'discover',\n 'sql',\n 'fast-decompose',\n 'auto-decompose',\n 'discover-decompose',\n 'sql-decompose',\n ])\n .optional()\n .describe(PRESET_PARAM),\n project_id: z.string().optional().describe(PROJECT_ID_PARAM),\n },\n },\n async ({ query, preset, project_id }) => {\n try {\n const response = await client.retrieval.search(config.sandbox_id, {\n query,\n project_id: project_id ?? config.project_id,\n window: windows.resolve(),\n preset: preset ?? config.preset,\n });\n return mcpResult({ answer: response.answer });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n}\n","import { z } from 'zod';\nimport type { CopassClient } from '@copass/core';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ServerConfig } from '../config.js';\nimport type { WindowRegistry } from '../windows.js';\n\ninterface ContextWindowDeps {\n client: CopassClient;\n config: ServerConfig;\n windows: WindowRegistry;\n}\n\nfunction mcpResult(payload: unknown) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(payload, null, 2) }],\n };\n}\n\nfunction mcpError(error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Error: ${message}` }],\n isError: true,\n };\n}\n\nexport function registerContextWindowTools(server: McpServer, deps: ContextWindowDeps): void {\n const { client, config, windows } = deps;\n\n server.registerTool(\n 'context_window_create',\n {\n description:\n 'Open a new Context Window — an ephemeral data source tracking this conversation. ' +\n 'Subsequent retrieval calls become automatically window-aware, and every turn you ' +\n 'record via `context_window_add_turn` is ingested into the graph so past turns ' +\n 'become retrievable. Returns a `data_source_id`; persist it on your side if you ' +\n 'may want to resume this conversation later via `context_window_attach`.',\n inputSchema: {\n project_id: z.string().optional().describe('Override the server default project_id.'),\n name: z.string().optional().describe('Optional stable name for the underlying data source.'),\n },\n },\n async ({ project_id, name }) => {\n try {\n const window = await client.contextWindow.create({\n sandbox_id: config.sandbox_id,\n project_id: project_id ?? config.project_id,\n name,\n });\n windows.set(window);\n return mcpResult({\n data_source_id: window.dataSourceId,\n active: true,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'context_window_add_turn',\n {\n description:\n 'Append a turn to the active Context Window and push it into the graph. Call on ' +\n 'every user message AND every assistant message so the thread itself becomes ' +\n 'retrievable. If you omit `data_source_id`, the active window is used.',\n inputSchema: {\n role: z\n .enum(['user', 'assistant', 'system'])\n .describe('Role of the speaker for this turn.'),\n content: z.string().describe('The turn content.'),\n data_source_id: z\n .string()\n .optional()\n .describe('Override the active window id (for multi-window use cases).'),\n },\n },\n async ({ role, content, data_source_id }) => {\n try {\n const window = windows.resolve(data_source_id);\n if (!window) {\n throw new Error(\n 'No active Context Window — call context_window_create or context_window_attach first.',\n );\n }\n await window.addTurn({ role, content });\n return mcpResult({\n data_source_id: window.dataSourceId,\n turn_count: window.getTurns().length,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'context_window_attach',\n {\n description:\n 'Resume an existing Context Window by `data_source_id` (one you previously persisted ' +\n 'on your side after `context_window_create`). Makes the resumed window the active ' +\n 'window. Pass `initial_turns` to seed the local buffer for immediate window-aware ' +\n 'retrieval, otherwise the buffer starts empty and fills as you call add_turn.',\n inputSchema: {\n data_source_id: z.string().describe('Id of the Context Window data source to resume.'),\n initial_turns: z\n .array(\n z.object({\n role: z.enum(['user', 'assistant', 'system']),\n content: z.string(),\n }),\n )\n .optional()\n .describe('Optional pre-existing turns to seed the local buffer.'),\n },\n },\n async ({ data_source_id, initial_turns }) => {\n try {\n const window = await client.contextWindow.attach({\n sandbox_id: config.sandbox_id,\n data_source_id,\n initialTurns: initial_turns,\n });\n windows.set(window);\n return mcpResult({\n data_source_id: window.dataSourceId,\n turn_count: window.getTurns().length,\n active: true,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'context_window_close',\n {\n description:\n 'Close a Context Window — flips the underlying data source to `disconnected` ' +\n 'immediately instead of waiting for TTL. Best-effort; idempotent. If you omit ' +\n '`data_source_id`, the active window is closed.',\n inputSchema: {\n data_source_id: z\n .string()\n .optional()\n .describe('Override the active window id.'),\n },\n },\n async ({ data_source_id }) => {\n try {\n const window = windows.resolve(data_source_id);\n if (!window) {\n throw new Error('No active Context Window to close.');\n }\n await window.close();\n windows.drop(window.dataSourceId);\n return mcpResult({\n data_source_id: window.dataSourceId,\n closed: true,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n}\n","import { z } from 'zod';\nimport type { CopassClient } from '@copass/core';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ServerConfig } from '../config.js';\n\ninterface IngestDeps {\n client: CopassClient;\n config: ServerConfig;\n}\n\nfunction mcpResult(payload: unknown) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(payload, null, 2) }],\n };\n}\n\nfunction mcpError(error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Error: ${message}` }],\n isError: true,\n };\n}\n\nexport function registerIngestTool(server: McpServer, deps: IngestDeps): void {\n const { client, config } = deps;\n\n server.registerTool(\n 'ingest',\n {\n description:\n 'Push content into the knowledge graph via a data source. Use for: architecture ' +\n 'decisions (source_type: \"decision\"), user-shared context (\"user_input\"), ' +\n 'corrections (\"correction\"), durable notes, any significant new concept. Do NOT ' +\n 'ingest trivial changes or ephemeral debug context — those belong in the Context ' +\n 'Window (via context_window_add_turn). Pass `data_source_id` explicitly or set ' +\n '`COPASS_INGEST_DATA_SOURCE_ID` in the server env for an implicit target.',\n inputSchema: {\n content: z.string().min(1).describe('The content to ingest.'),\n source_type: z\n .string()\n .optional()\n .describe(\n 'Type tag: code, markdown, json, text, conversation, decision, correction, ' +\n 'user_input. Defaults to \"text\" when omitted.',\n ),\n data_source_id: z\n .string()\n .optional()\n .describe(\n 'Target data source. Falls back to COPASS_INGEST_DATA_SOURCE_ID env var.',\n ),\n project_id: z.string().optional().describe('Override the server default project_id.'),\n storage_only: z\n .boolean()\n .optional()\n .describe('If true, chunk and store but skip ontology ingestion.'),\n },\n },\n async ({ content, source_type, data_source_id, project_id, storage_only }) => {\n try {\n const sourceId = data_source_id ?? config.ingest_data_source_id;\n if (!sourceId) {\n throw new Error(\n 'ingest requires a `data_source_id` argument or COPASS_INGEST_DATA_SOURCE_ID env var. ' +\n 'Register a data source via the REST API or CLI, then pass its id here.',\n );\n }\n\n const response = await client.sources.ingest(config.sandbox_id, sourceId, {\n text: content,\n source_type: source_type ?? 'text',\n project_id: project_id ?? config.project_id,\n storage_only,\n });\n\n return mcpResult({\n job_id: response.job_id,\n status: response.status,\n data_source_id: sourceId,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n}\n","import type { ChatMessage, SearchPreset } from '@copass/core';\n\nexport interface ServerConfig {\n api_url: string;\n /**\n * Required when the standalone `copass-mcp` bin builds its own\n * `CopassClient` from this config (`bin.ts`). Optional for embedded\n * use — when a host process (e.g. another MCP server) constructs the\n * `CopassClient` itself and passes it into `buildServer({ client })`,\n * the tool handlers never read this field.\n */\n api_key?: string;\n sandbox_id: string;\n project_id?: string;\n preset: SearchPreset;\n /** Default data_source_id for `ingest` when the caller doesn't pass one. */\n ingest_data_source_id?: string;\n /**\n * If set, the server attaches to this Context Window on startup and makes\n * it the active window. Use when another process (e.g. a Hono server)\n * already created the window and you're launching the MCP server as a\n * subprocess that should share it.\n */\n context_window_id?: string;\n /**\n * Optional pre-existing turns to seed the Context Window's buffer on\n * startup. Makes retrieval immediately window-aware on the first tool\n * call — without these, the first `discover` / `interpret` / `search`\n * after a subprocess spawn sees an empty history.\n *\n * Required when `context_window_id` refers to a thread that has prior\n * turns and the server should dedupe retrieval against them.\n */\n context_window_initial_turns?: ChatMessage[];\n}\n\nconst VALID_PRESETS: readonly SearchPreset[] = [\n 'fast',\n 'auto',\n 'discover',\n 'sql',\n 'max',\n // `-decompose` variants are /search-only. Setting one of these as the\n // MCP subprocess default makes `interpret` fail (decomposition isn't\n // valid on /interpret) — fine when the subprocess is only used for\n // `search`, otherwise override per-call via the `preset` tool arg.\n 'fast-decompose',\n 'auto-decompose',\n 'discover-decompose',\n 'sql-decompose',\n] as const;\n\n/**\n * Read config from `process.env`.\n *\n * - `COPASS_API_KEY` (required)\n * - `COPASS_SANDBOX_ID` (required)\n * - `COPASS_API_URL` (default: https://ai.copass.id)\n * - `COPASS_PROJECT_ID` (optional — default for retrieval/ingest)\n * - `COPASS_PRESET` (default: `auto`). Accepts any `SearchPreset`, but\n * `auto` is the only value whose providers consume the\n * `semantic_alignment_scopes` that `/interpret`'s scope adapter\n * produces — so non-`auto` defaults (and any `-decompose` default)\n * break `interpret`. Leave at `auto` unless the subprocess is\n * search-only, and override per-call via the `preset` tool arg.\n *\n * Throws a descriptive error for missing/invalid values so the MCP client\n * sees an immediate startup failure with actionable text.\n */\nexport function loadConfig(env: NodeJS.ProcessEnv = process.env): ServerConfig {\n const missing: string[] = [];\n const api_key = env.COPASS_API_KEY ?? '';\n const sandbox_id = env.COPASS_SANDBOX_ID ?? '';\n\n if (!api_key) missing.push('COPASS_API_KEY');\n if (!sandbox_id) missing.push('COPASS_SANDBOX_ID');\n\n if (missing.length > 0) {\n throw new Error(\n `@copass/mcp: missing required env var(s): ${missing.join(', ')}. ` +\n `Set them before launching the server.`,\n );\n }\n\n const api_url = env.COPASS_API_URL?.trim() || 'https://ai.copass.id';\n const project_id = env.COPASS_PROJECT_ID?.trim() || undefined;\n const rawPreset = env.COPASS_PRESET?.trim() || 'auto';\n\n if (!VALID_PRESETS.includes(rawPreset as SearchPreset)) {\n throw new Error(\n `@copass/mcp: COPASS_PRESET must be one of ${VALID_PRESETS.join(', ')}; got \"${rawPreset}\"`,\n );\n }\n\n const ingest_data_source_id = env.COPASS_INGEST_DATA_SOURCE_ID?.trim() || undefined;\n const context_window_id = env.COPASS_CONTEXT_WINDOW_ID?.trim() || undefined;\n const context_window_initial_turns = parseInitialTurns(\n env.COPASS_CONTEXT_WINDOW_INITIAL_TURNS,\n );\n\n return {\n api_url,\n api_key,\n sandbox_id,\n project_id,\n preset: rawPreset as SearchPreset,\n ingest_data_source_id,\n context_window_id,\n context_window_initial_turns,\n };\n}\n\nfunction parseInitialTurns(raw: string | undefined): ChatMessage[] | undefined {\n if (!raw || !raw.trim()) return undefined;\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n throw new Error(\n `@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS is not valid JSON: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n if (!Array.isArray(parsed)) {\n throw new Error(\n '@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS must be a JSON array of {role, content} objects',\n );\n }\n const turns: ChatMessage[] = [];\n for (const [i, entry] of parsed.entries()) {\n if (\n !entry ||\n typeof entry !== 'object' ||\n typeof (entry as { role?: unknown }).role !== 'string' ||\n typeof (entry as { content?: unknown }).content !== 'string'\n ) {\n throw new Error(\n `@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS[${i}] must be {role: string, content: string}`,\n );\n }\n const { role, content } = entry as { role: string; content: string };\n if (role !== 'user' && role !== 'assistant' && role !== 'system') {\n throw new Error(\n `@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS[${i}].role must be \"user\" | \"assistant\" | \"system\"; got \"${role}\"`,\n );\n }\n turns.push({ role, content });\n }\n return turns;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,iBAA0B;;;ACYnB,IAAM,iBAAN,MAAqB;AAAA,EACT,UAAU,oBAAI,IAA2B;AAAA,EAClD,WAA0B;AAAA;AAAA,EAGlC,IAAI,QAA6B;AAC/B,SAAK,QAAQ,IAAI,OAAO,cAAc,MAAM;AAC5C,SAAK,WAAW,OAAO;AAAA,EACzB;AAAA;AAAA,EAGA,QAAQ,cAAkD;AACxD,UAAM,KAAK,gBAAgB,KAAK;AAChC,WAAO,KAAK,KAAK,QAAQ,IAAI,EAAE,IAAI;AAAA,EACrC;AAAA;AAAA,EAGA,SAAS,cAAqC;AAC5C,UAAM,SAAS,KAAK,QAAQ,IAAI,YAAY;AAC5C,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI;AAAA,QACR,4CAA4C,YAAY;AAAA,MAC1D;AAAA,IACF;AACA,SAAK,WAAW;AAChB,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,KAAK,cAA4B;AAC/B,SAAK,QAAQ,OAAO,YAAY;AAChC,QAAI,KAAK,aAAa,aAAc,MAAK,WAAW;AAAA,EACtD;AAAA,EAEA,IAAI,qBAAoC;AACtC,WAAO,KAAK;AAAA,EACd;AACF;;;ACjDA,iBAAkB;AAClB,oBAUO;AAYP,SAAS,UAAU,SAAkB;AACnC,SAAO;AAAA,IACL,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,KAAK,UAAU,SAAS,MAAM,CAAC,EAAE,CAAC;AAAA,EAC7E;AACF;AAEA,SAAS,SAAS,OAAgB;AAChC,QAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,SAAO;AAAA,IACL,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,UAAU,OAAO,GAAG,CAAC;AAAA,IAC9D,SAAS;AAAA,EACX;AACF;AAEO,SAAS,uBAAuB,QAAmB,MAA2B;AACnF,QAAM,EAAE,QAAQ,QAAQ,QAAQ,IAAI;AAEpC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,aAAa;AAAA,QACX,OAAO,aAAE,OAAO,EAAE,SAAS,kCAAoB;AAAA,QAC/C,YAAY,aAAE,OAAO,EAAE,SAAS,EAAE,SAAS,8BAAgB;AAAA,MAC7D;AAAA,IACF;AAAA,IACA,OAAO,EAAE,OAAO,WAAW,MAAM;AAC/B,UAAI;AACF,cAAM,WAAW,MAAM,OAAO,UAAU,SAAS,OAAO,YAAY;AAAA,UAClE;AAAA,UACA,YAAY,cAAc,OAAO;AAAA,UACjC,QAAQ,QAAQ,QAAQ;AAAA,QAC1B,CAAC;AACD,eAAO,UAAU;AAAA,UACf,QAAQ,SAAS;AAAA,UACjB,OAAO,SAAS,MAAM,IAAI,CAAC,UAAU;AAAA,YACnC,OAAO,KAAK;AAAA,YACZ,SAAS,KAAK;AAAA,YACd,eAAe,KAAK;AAAA,UACtB,EAAE;AAAA,UACF,YAAY,SAAS;AAAA,QACvB,CAAC;AAAA,MACH,SAAS,GAAG;AACV,eAAO,SAAS,CAAC;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,aAAa;AAAA,QACX,OAAO,aAAE,OAAO,EAAE,SAAS,mCAAqB;AAAA,QAChD,OAAO,aAAE,MAAM,aAAE,MAAM,aAAE,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS,mCAAqB;AAAA,QAChF,QAAQ,aAAE,KAAK,CAAC,QAAQ,QAAQ,KAAK,CAAC,EAAE,SAAS,EAAE,SAAS,0BAAY;AAAA,QACxE,YAAY,aAAE,OAAO,EAAE,SAAS,EAAE,SAAS,8BAAgB;AAAA,MAC7D;AAAA,IACF;AAAA,IACA,OAAO,EAAE,OAAO,OAAO,QAAQ,WAAW,MAAM;AAC9C,UAAI;AACF,cAAM,WAAW,MAAM,OAAO,UAAU,UAAU,OAAO,YAAY;AAAA,UACnE;AAAA,UACA;AAAA,UACA,YAAY,cAAc,OAAO;AAAA,UACjC,QAAQ,QAAQ,QAAQ;AAAA,UACxB,QAAQ,UAAU,OAAO;AAAA,QAC3B,CAAC;AACD,eAAO,UAAU,EAAE,OAAO,SAAS,MAAM,CAAC;AAAA,MAC5C,SAAS,GAAG;AACV,eAAO,SAAS,CAAC;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,aAAa;AAAA,QACX,OAAO,aAAE,OAAO,EAAE,SAAS,gCAAkB;AAAA;AAAA;AAAA;AAAA;AAAA,QAK7C,QAAQ,aACL,KAAK;AAAA,UACJ;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,CAAC,EACA,SAAS,EACT,SAAS,0BAAY;AAAA,QACxB,YAAY,aAAE,OAAO,EAAE,SAAS,EAAE,SAAS,8BAAgB;AAAA,MAC7D;AAAA,IACF;AAAA,IACA,OAAO,EAAE,OAAO,QAAQ,WAAW,MAAM;AACvC,UAAI;AACF,cAAM,WAAW,MAAM,OAAO,UAAU,OAAO,OAAO,YAAY;AAAA,UAChE;AAAA,UACA,YAAY,cAAc,OAAO;AAAA,UACjC,QAAQ,QAAQ,QAAQ;AAAA,UACxB,QAAQ,UAAU,OAAO;AAAA,QAC3B,CAAC;AACD,eAAO,UAAU,EAAE,QAAQ,SAAS,OAAO,CAAC;AAAA,MAC9C,SAAS,GAAG;AACV,eAAO,SAAS,CAAC;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AACF;;;AC1IA,IAAAA,cAAkB;AAYlB,SAASC,WAAU,SAAkB;AACnC,SAAO;AAAA,IACL,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,KAAK,UAAU,SAAS,MAAM,CAAC,EAAE,CAAC;AAAA,EAC7E;AACF;AAEA,SAASC,UAAS,OAAgB;AAChC,QAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,SAAO;AAAA,IACL,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,UAAU,OAAO,GAAG,CAAC;AAAA,IAC9D,SAAS;AAAA,EACX;AACF;AAEO,SAAS,2BAA2B,QAAmB,MAA+B;AAC3F,QAAM,EAAE,QAAQ,QAAQ,QAAQ,IAAI;AAEpC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aACE;AAAA,MAKF,aAAa;AAAA,QACX,YAAY,cAAE,OAAO,EAAE,SAAS,EAAE,SAAS,yCAAyC;AAAA,QACpF,MAAM,cAAE,OAAO,EAAE,SAAS,EAAE,SAAS,sDAAsD;AAAA,MAC7F;AAAA,IACF;AAAA,IACA,OAAO,EAAE,YAAY,KAAK,MAAM;AAC9B,UAAI;AACF,cAAM,SAAS,MAAM,OAAO,cAAc,OAAO;AAAA,UAC/C,YAAY,OAAO;AAAA,UACnB,YAAY,cAAc,OAAO;AAAA,UACjC;AAAA,QACF,CAAC;AACD,gBAAQ,IAAI,MAAM;AAClB,eAAOD,WAAU;AAAA,UACf,gBAAgB,OAAO;AAAA,UACvB,QAAQ;AAAA,QACV,CAAC;AAAA,MACH,SAAS,GAAG;AACV,eAAOC,UAAS,CAAC;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aACE;AAAA,MAGF,aAAa;AAAA,QACX,MAAM,cACH,KAAK,CAAC,QAAQ,aAAa,QAAQ,CAAC,EACpC,SAAS,oCAAoC;AAAA,QAChD,SAAS,cAAE,OAAO,EAAE,SAAS,mBAAmB;AAAA,QAChD,gBAAgB,cACb,OAAO,EACP,SAAS,EACT,SAAS,6DAA6D;AAAA,MAC3E;AAAA,IACF;AAAA,IACA,OAAO,EAAE,MAAM,SAAS,eAAe,MAAM;AAC3C,UAAI;AACF,cAAM,SAAS,QAAQ,QAAQ,cAAc;AAC7C,YAAI,CAAC,QAAQ;AACX,gBAAM,IAAI;AAAA,YACR;AAAA,UACF;AAAA,QACF;AACA,cAAM,OAAO,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACtC,eAAOD,WAAU;AAAA,UACf,gBAAgB,OAAO;AAAA,UACvB,YAAY,OAAO,SAAS,EAAE;AAAA,QAChC,CAAC;AAAA,MACH,SAAS,GAAG;AACV,eAAOC,UAAS,CAAC;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aACE;AAAA,MAIF,aAAa;AAAA,QACX,gBAAgB,cAAE,OAAO,EAAE,SAAS,iDAAiD;AAAA,QACrF,eAAe,cACZ;AAAA,UACC,cAAE,OAAO;AAAA,YACP,MAAM,cAAE,KAAK,CAAC,QAAQ,aAAa,QAAQ,CAAC;AAAA,YAC5C,SAAS,cAAE,OAAO;AAAA,UACpB,CAAC;AAAA,QACH,EACC,SAAS,EACT,SAAS,uDAAuD;AAAA,MACrE;AAAA,IACF;AAAA,IACA,OAAO,EAAE,gBAAgB,cAAc,MAAM;AAC3C,UAAI;AACF,cAAM,SAAS,MAAM,OAAO,cAAc,OAAO;AAAA,UAC/C,YAAY,OAAO;AAAA,UACnB;AAAA,UACA,cAAc;AAAA,QAChB,CAAC;AACD,gBAAQ,IAAI,MAAM;AAClB,eAAOD,WAAU;AAAA,UACf,gBAAgB,OAAO;AAAA,UACvB,YAAY,OAAO,SAAS,EAAE;AAAA,UAC9B,QAAQ;AAAA,QACV,CAAC;AAAA,MACH,SAAS,GAAG;AACV,eAAOC,UAAS,CAAC;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aACE;AAAA,MAGF,aAAa;AAAA,QACX,gBAAgB,cACb,OAAO,EACP,SAAS,EACT,SAAS,gCAAgC;AAAA,MAC9C;AAAA,IACF;AAAA,IACA,OAAO,EAAE,eAAe,MAAM;AAC5B,UAAI;AACF,cAAM,SAAS,QAAQ,QAAQ,cAAc;AAC7C,YAAI,CAAC,QAAQ;AACX,gBAAM,IAAI,MAAM,oCAAoC;AAAA,QACtD;AACA,cAAM,OAAO,MAAM;AACnB,gBAAQ,KAAK,OAAO,YAAY;AAChC,eAAOD,WAAU;AAAA,UACf,gBAAgB,OAAO;AAAA,UACvB,QAAQ;AAAA,QACV,CAAC;AAAA,MACH,SAAS,GAAG;AACV,eAAOC,UAAS,CAAC;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AACF;;;ACzKA,IAAAC,cAAkB;AAUlB,SAASC,WAAU,SAAkB;AACnC,SAAO;AAAA,IACL,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,KAAK,UAAU,SAAS,MAAM,CAAC,EAAE,CAAC;AAAA,EAC7E;AACF;AAEA,SAASC,UAAS,OAAgB;AAChC,QAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,SAAO;AAAA,IACL,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,UAAU,OAAO,GAAG,CAAC;AAAA,IAC9D,SAAS;AAAA,EACX;AACF;AAEO,SAAS,mBAAmB,QAAmB,MAAwB;AAC5E,QAAM,EAAE,QAAQ,OAAO,IAAI;AAE3B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aACE;AAAA,MAMF,aAAa;AAAA,QACX,SAAS,cAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,wBAAwB;AAAA,QAC5D,aAAa,cACV,OAAO,EACP,SAAS,EACT;AAAA,UACC;AAAA,QAEF;AAAA,QACF,gBAAgB,cACb,OAAO,EACP,SAAS,EACT;AAAA,UACC;AAAA,QACF;AAAA,QACF,YAAY,cAAE,OAAO,EAAE,SAAS,EAAE,SAAS,yCAAyC;AAAA,QACpF,cAAc,cACX,QAAQ,EACR,SAAS,EACT,SAAS,uDAAuD;AAAA,MACrE;AAAA,IACF;AAAA,IACA,OAAO,EAAE,SAAS,aAAa,gBAAgB,YAAY,aAAa,MAAM;AAC5E,UAAI;AACF,cAAM,WAAW,kBAAkB,OAAO;AAC1C,YAAI,CAAC,UAAU;AACb,gBAAM,IAAI;AAAA,YACR;AAAA,UAEF;AAAA,QACF;AAEA,cAAM,WAAW,MAAM,OAAO,QAAQ,OAAO,OAAO,YAAY,UAAU;AAAA,UACxE,MAAM;AAAA,UACN,aAAa,eAAe;AAAA,UAC5B,YAAY,cAAc,OAAO;AAAA,UACjC;AAAA,QACF,CAAC;AAED,eAAOD,WAAU;AAAA,UACf,QAAQ,SAAS;AAAA,UACjB,QAAQ,SAAS;AAAA,UACjB,gBAAgB;AAAA,QAClB,CAAC;AAAA,MACH,SAAS,GAAG;AACV,eAAOC,UAAS,CAAC;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AACF;;;AJ9DO,SAAS,YAAY,EAAE,QAAQ,QAAQ,QAAQ,GAAkC;AACtF,QAAM,SAAS,IAAI;AAAA,IACjB;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,cAAc,EAAE,OAAO,CAAC,EAAE;AAAA,IAC5B;AAAA,EACF;AAEA,QAAM,WAAW,WAAW,IAAI,eAAe;AAC/C,QAAM,OAAO,EAAE,QAAQ,QAAQ,SAAS,SAAS;AAEjD,yBAAuB,QAAQ,IAAI;AACnC,6BAA2B,QAAQ,IAAI;AACvC,qBAAmB,QAAQ,EAAE,QAAQ,OAAO,CAAC;AAE7C,SAAO;AACT;;;AKPA,IAAM,gBAAyC;AAAA,EAC7C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAmBO,SAAS,WAAW,MAAyB,QAAQ,KAAmB;AAC7E,QAAM,UAAoB,CAAC;AAC3B,QAAM,UAAU,IAAI,kBAAkB;AACtC,QAAM,aAAa,IAAI,qBAAqB;AAE5C,MAAI,CAAC,QAAS,SAAQ,KAAK,gBAAgB;AAC3C,MAAI,CAAC,WAAY,SAAQ,KAAK,mBAAmB;AAEjD,MAAI,QAAQ,SAAS,GAAG;AACtB,UAAM,IAAI;AAAA,MACR,6CAA6C,QAAQ,KAAK,IAAI,CAAC;AAAA,IAEjE;AAAA,EACF;AAEA,QAAM,UAAU,IAAI,gBAAgB,KAAK,KAAK;AAC9C,QAAM,aAAa,IAAI,mBAAmB,KAAK,KAAK;AACpD,QAAM,YAAY,IAAI,eAAe,KAAK,KAAK;AAE/C,MAAI,CAAC,cAAc,SAAS,SAAyB,GAAG;AACtD,UAAM,IAAI;AAAA,MACR,6CAA6C,cAAc,KAAK,IAAI,CAAC,UAAU,SAAS;AAAA,IAC1F;AAAA,EACF;AAEA,QAAM,wBAAwB,IAAI,8BAA8B,KAAK,KAAK;AAC1E,QAAM,oBAAoB,IAAI,0BAA0B,KAAK,KAAK;AAClE,QAAM,+BAA+B;AAAA,IACnC,IAAI;AAAA,EACN;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,kBAAkB,KAAoD;AAC7E,MAAI,CAAC,OAAO,CAAC,IAAI,KAAK,EAAG,QAAO;AAChC,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,GAAG;AAAA,EACzB,SAAS,KAAK;AACZ,UAAM,IAAI;AAAA,MACR,uEACE,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CACjD;AAAA,IACF;AAAA,EACF;AACA,MAAI,CAAC,MAAM,QAAQ,MAAM,GAAG;AAC1B,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,QAAM,QAAuB,CAAC;AAC9B,aAAW,CAAC,GAAG,KAAK,KAAK,OAAO,QAAQ,GAAG;AACzC,QACE,CAAC,SACD,OAAO,UAAU,YACjB,OAAQ,MAA6B,SAAS,YAC9C,OAAQ,MAAgC,YAAY,UACpD;AACA,YAAM,IAAI;AAAA,QACR,oDAAoD,CAAC;AAAA,MACvD;AAAA,IACF;AACA,UAAM,EAAE,MAAM,QAAQ,IAAI;AAC1B,QAAI,SAAS,UAAU,SAAS,eAAe,SAAS,UAAU;AAChE,YAAM,IAAI;AAAA,QACR,oDAAoD,CAAC,wDAAwD,IAAI;AAAA,MACnH;AAAA,IACF;AACA,UAAM,KAAK,EAAE,MAAM,QAAQ,CAAC;AAAA,EAC9B;AACA,SAAO;AACT;","names":["import_zod","mcpResult","mcpError","import_zod","mcpResult","mcpError"]}
{"version":3,"sources":["../src/index.ts","../src/server.ts","../src/windows.ts","../src/tools/retrieval.ts","../src/tools/context-window.ts","../src/tools/ingest.ts","../src/config.ts"],"sourcesContent":["export { buildServer } from './server.js';\nexport type { BuildServerOptions } from './server.js';\nexport { loadConfig } from './config.js';\nexport type { ServerConfig } from './config.js';\nexport { WindowRegistry } from './windows.js';\n\n// Sub-registrars — for callers that want to compose tools onto an\n// existing `McpServer` rather than spinning up a whole `buildServer()`.\n// Pick the tool groups you want and skip the rest (e.g. embed\n// `discover` / `interpret` / `search` without the SDK ingest when the\n// host process owns its own ingest tool).\nexport { registerRetrievalTools } from './tools/retrieval.js';\nexport { registerContextWindowTools } from './tools/context-window.js';\nexport { registerIngestTool } from './tools/ingest.js';\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CopassClient } from '@copass/core';\nimport type { ServerConfig } from './config.js';\nimport { WindowRegistry } from './windows.js';\nimport { registerRetrievalTools } from './tools/retrieval.js';\nimport { registerContextWindowTools } from './tools/context-window.js';\nimport { registerIngestTool } from './tools/ingest.js';\n\nexport interface BuildServerOptions {\n client: CopassClient;\n config: ServerConfig;\n /**\n * Optional pre-populated window registry. Useful when a parent process has\n * already created or attached to a Context Window and wants the server to\n * start with it as the active window.\n */\n windows?: WindowRegistry;\n}\n\n/**\n * Assemble the Copass MCP server with every tool registered. Doesn't connect\n * a transport — see `startStdioServer` in `./bin.ts` for the default path,\n * or wire your own transport if embedding.\n */\nexport function buildServer({ client, config, windows }: BuildServerOptions): McpServer {\n const server = new McpServer(\n {\n name: 'copass',\n version: '0.3.0',\n },\n {\n capabilities: { tools: {} },\n },\n );\n\n const registry = windows ?? new WindowRegistry();\n const deps = { client, config, windows: registry };\n\n registerRetrievalTools(server, deps);\n registerContextWindowTools(server, deps);\n registerIngestTool(server, { client, config });\n\n return server;\n}\n","import type { ContextWindow } from '@copass/core';\n\n/**\n * In-memory registry of open Context Windows.\n *\n * Tracks a map of `data_source_id → ContextWindow` plus a single \"active\"\n * window id. Retrieval and add-turn tools use the active window implicitly\n * so the LLM doesn't have to thread an id on every call.\n *\n * For multi-window use cases, callers pass `data_source_id` explicitly and\n * the active id is ignored.\n */\nexport class WindowRegistry {\n private readonly windows = new Map<string, ContextWindow>();\n private activeId: string | null = null;\n\n /** Register a new window and make it active. */\n set(window: ContextWindow): void {\n this.windows.set(window.dataSourceId, window);\n this.activeId = window.dataSourceId;\n }\n\n /** Look up a window by id, or fall back to the active one. */\n resolve(dataSourceId?: string): ContextWindow | undefined {\n const id = dataSourceId ?? this.activeId;\n return id ? this.windows.get(id) : undefined;\n }\n\n /** Make an existing window the active one. Throws if unknown. */\n activate(dataSourceId: string): ContextWindow {\n const window = this.windows.get(dataSourceId);\n if (!window) {\n throw new Error(\n `No window registered for data_source_id=\"${dataSourceId}\" — call context_window_create or context_window_attach first.`,\n );\n }\n this.activeId = dataSourceId;\n return window;\n }\n\n /** Drop a window from the registry. Clears active if it matched. */\n drop(dataSourceId: string): void {\n this.windows.delete(dataSourceId);\n if (this.activeId === dataSourceId) this.activeId = null;\n }\n\n get activeDataSourceId(): string | null {\n return this.activeId;\n }\n}\n","import { z } from 'zod';\nimport {\n DISCOVER_QUERY_PARAM,\n INTERPRET_DESCRIPTION,\n INTERPRET_ITEMS_PARAM,\n INTERPRET_QUERY_PARAM,\n MCP_DISCOVER_DESCRIPTION,\n PRESET_PARAM,\n PROJECT_ID_PARAM,\n SEARCH_DESCRIPTION,\n SEARCH_QUERY_PARAM,\n} from '@copass/config';\nimport type { CopassClient } from '@copass/core';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ServerConfig } from '../config.js';\nimport type { WindowRegistry } from '../windows.js';\n\ninterface RetrievalDeps {\n client: CopassClient;\n config: ServerConfig;\n windows: WindowRegistry;\n}\n\nfunction mcpResult(payload: unknown) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(payload, null, 2) }],\n };\n}\n\nfunction mcpError(error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Error: ${message}` }],\n isError: true,\n };\n}\n\nexport function registerRetrievalTools(server: McpServer, deps: RetrievalDeps): void {\n const { client, config, windows } = deps;\n\n server.registerTool(\n 'discover',\n {\n description: MCP_DISCOVER_DESCRIPTION,\n inputSchema: {\n query: z.string().describe(DISCOVER_QUERY_PARAM),\n project_id: z.string().optional().describe(PROJECT_ID_PARAM),\n },\n },\n async ({ query, project_id }) => {\n try {\n const response = await client.retrieval.discover(config.sandbox_id, {\n query,\n project_id: project_id ?? config.project_id,\n window: windows.resolve(),\n });\n return mcpResult({\n header: response.header,\n items: response.items.map((item) => ({\n score: item.score,\n summary: item.summary,\n canonical_ids: item.canonical_ids,\n })),\n next_steps: response.next_steps,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'interpret',\n {\n description: INTERPRET_DESCRIPTION,\n inputSchema: {\n query: z.string().describe(INTERPRET_QUERY_PARAM),\n items: z.array(z.array(z.string()).min(1)).min(1).describe(INTERPRET_ITEMS_PARAM),\n preset: z.enum(['fast', 'auto', 'max']).optional().describe(PRESET_PARAM),\n project_id: z.string().optional().describe(PROJECT_ID_PARAM),\n },\n },\n async ({ query, items, preset, project_id }) => {\n try {\n const response = await client.retrieval.interpret(config.sandbox_id, {\n query,\n items,\n project_id: project_id ?? config.project_id,\n window: windows.resolve(),\n preset: preset ?? config.preset,\n });\n return mcpResult({ brief: response.brief });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'search',\n {\n description: SEARCH_DESCRIPTION,\n inputSchema: {\n query: z.string().describe(SEARCH_QUERY_PARAM),\n // `max` is omitted — the server returns 403 for public callers,\n // so exposing it would only yield confusing tool-use errors.\n // `-decompose` variants split the question into sub-questions and\n // run the base preset on each before a combined synthesis.\n preset: z\n .enum([\n 'fast',\n 'auto',\n 'discover',\n 'sql',\n 'fast-decompose',\n 'auto-decompose',\n 'discover-decompose',\n 'sql-decompose',\n ])\n .optional()\n .describe(PRESET_PARAM),\n project_id: z.string().optional().describe(PROJECT_ID_PARAM),\n },\n },\n async ({ query, preset, project_id }) => {\n try {\n const response = await client.retrieval.search(config.sandbox_id, {\n query,\n project_id: project_id ?? config.project_id,\n window: windows.resolve(),\n preset: preset ?? config.preset,\n });\n return mcpResult({ answer: response.answer });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n}\n","import { z } from 'zod';\nimport type { CopassClient } from '@copass/core';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ServerConfig } from '../config.js';\nimport type { WindowRegistry } from '../windows.js';\n\ninterface ContextWindowDeps {\n client: CopassClient;\n config: ServerConfig;\n windows: WindowRegistry;\n}\n\nfunction mcpResult(payload: unknown) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(payload, null, 2) }],\n };\n}\n\nfunction mcpError(error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Error: ${message}` }],\n isError: true,\n };\n}\n\nexport function registerContextWindowTools(server: McpServer, deps: ContextWindowDeps): void {\n const { client, config, windows } = deps;\n\n server.registerTool(\n 'context_window_create',\n {\n description:\n 'Open a new Context Window — an ephemeral data source tracking this conversation. ' +\n 'Subsequent retrieval calls become automatically window-aware, and every turn you ' +\n 'record via `context_window_add_turn` is ingested into the graph so past turns ' +\n 'become retrievable. Returns a `data_source_id`; persist it on your side if you ' +\n 'may want to resume this conversation later via `context_window_attach`.',\n inputSchema: {\n project_id: z.string().optional().describe('Override the server default project_id.'),\n name: z.string().optional().describe('Optional stable name for the underlying data source.'),\n },\n },\n async ({ project_id, name }) => {\n try {\n const window = await client.contextWindow.create({\n sandbox_id: config.sandbox_id,\n project_id: project_id ?? config.project_id,\n name,\n });\n windows.set(window);\n return mcpResult({\n data_source_id: window.dataSourceId,\n active: true,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'context_window_add_turn',\n {\n description:\n 'Append a turn to the active Context Window and push it into the graph. Call on ' +\n 'every user message AND every assistant message so the thread itself becomes ' +\n 'retrievable. If you omit `data_source_id`, the active window is used.',\n inputSchema: {\n role: z\n .enum(['user', 'assistant', 'system'])\n .describe('Role of the speaker for this turn.'),\n content: z.string().describe('The turn content.'),\n data_source_id: z\n .string()\n .optional()\n .describe('Override the active window id (for multi-window use cases).'),\n },\n },\n async ({ role, content, data_source_id }) => {\n try {\n const window = windows.resolve(data_source_id);\n if (!window) {\n throw new Error(\n 'No active Context Window — call context_window_create or context_window_attach first.',\n );\n }\n await window.addTurn({ role, content });\n return mcpResult({\n data_source_id: window.dataSourceId,\n turn_count: window.getTurns().length,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'context_window_attach',\n {\n description:\n 'Resume an existing Context Window by `data_source_id` (one you previously persisted ' +\n 'on your side after `context_window_create`). Makes the resumed window the active ' +\n 'window. Pass `initial_turns` to seed the local buffer for immediate window-aware ' +\n 'retrieval, otherwise the buffer starts empty and fills as you call add_turn.',\n inputSchema: {\n data_source_id: z.string().describe('Id of the Context Window data source to resume.'),\n initial_turns: z\n .array(\n z.object({\n role: z.enum(['user', 'assistant', 'system']),\n content: z.string(),\n }),\n )\n .optional()\n .describe('Optional pre-existing turns to seed the local buffer.'),\n },\n },\n async ({ data_source_id, initial_turns }) => {\n try {\n const window = await client.contextWindow.attach({\n sandbox_id: config.sandbox_id,\n data_source_id,\n initialTurns: initial_turns,\n });\n windows.set(window);\n return mcpResult({\n data_source_id: window.dataSourceId,\n turn_count: window.getTurns().length,\n active: true,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'context_window_close',\n {\n description:\n 'Close a Context Window — flips the underlying data source to `disconnected` ' +\n 'immediately instead of waiting for TTL. Best-effort; idempotent. If you omit ' +\n '`data_source_id`, the active window is closed.',\n inputSchema: {\n data_source_id: z\n .string()\n .optional()\n .describe('Override the active window id.'),\n },\n },\n async ({ data_source_id }) => {\n try {\n const window = windows.resolve(data_source_id);\n if (!window) {\n throw new Error('No active Context Window to close.');\n }\n await window.close();\n windows.drop(window.dataSourceId);\n return mcpResult({\n data_source_id: window.dataSourceId,\n closed: true,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n}\n","import { z } from 'zod';\nimport type { CopassClient } from '@copass/core';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ServerConfig } from '../config.js';\n\ninterface IngestDeps {\n client: CopassClient;\n config: ServerConfig;\n}\n\nfunction mcpResult(payload: unknown) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(payload, null, 2) }],\n };\n}\n\nfunction mcpError(error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Error: ${message}` }],\n isError: true,\n };\n}\n\nexport function registerIngestTool(server: McpServer, deps: IngestDeps): void {\n const { client, config } = deps;\n\n server.registerTool(\n 'ingest',\n {\n description:\n 'Push content into the knowledge graph via a data source. Use for: architecture ' +\n 'decisions (source_type: \"decision\"), user-shared context (\"user_input\"), ' +\n 'corrections (\"correction\"), durable notes, any significant new concept. Do NOT ' +\n 'ingest trivial changes or ephemeral debug context — those belong in the Context ' +\n 'Window (via context_window_add_turn). Pass `data_source_id` explicitly or set ' +\n '`COPASS_INGEST_DATA_SOURCE_ID` in the server env for an implicit target.',\n inputSchema: {\n content: z.string().min(1).describe('The content to ingest.'),\n source_type: z\n .string()\n .optional()\n .describe(\n 'Type tag: code, markdown, json, text, conversation, decision, correction, ' +\n 'user_input. Defaults to \"text\" when omitted.',\n ),\n data_source_id: z\n .string()\n .optional()\n .describe(\n 'Target data source. Falls back to COPASS_INGEST_DATA_SOURCE_ID env var.',\n ),\n project_id: z.string().optional().describe('Override the server default project_id.'),\n storage_only: z\n .boolean()\n .optional()\n .describe('If true, chunk and store but skip ontology ingestion.'),\n occurred_at: z\n .string()\n .optional()\n .describe(\n 'Optional ISO 8601 timestamp anchoring the content to a real-world moment ' +\n '(e.g. when this decision was made, when the user said it). Used as the ' +\n 'default occurred_at for any composed event whose own timestamp is null, ' +\n 'so temporal queries can find it.',\n ),\n },\n },\n async ({ content, source_type, data_source_id, project_id, storage_only, occurred_at }) => {\n try {\n const sourceId = data_source_id ?? config.ingest_data_source_id;\n if (!sourceId) {\n throw new Error(\n 'ingest requires a `data_source_id` argument or COPASS_INGEST_DATA_SOURCE_ID env var. ' +\n 'Register a data source via the REST API or CLI, then pass its id here.',\n );\n }\n\n const response = await client.sources.ingest(config.sandbox_id, sourceId, {\n text: content,\n source_type: source_type ?? 'text',\n project_id: project_id ?? config.project_id,\n storage_only,\n occurred_at,\n });\n\n return mcpResult({\n job_id: response.job_id,\n status: response.status,\n data_source_id: sourceId,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n}\n","import type { ChatMessage, SearchPreset } from '@copass/core';\n\nexport interface ServerConfig {\n api_url: string;\n /**\n * Required when the standalone `copass-mcp` bin builds its own\n * `CopassClient` from this config (`bin.ts`). Optional for embedded\n * use — when a host process (e.g. another MCP server) constructs the\n * `CopassClient` itself and passes it into `buildServer({ client })`,\n * the tool handlers never read this field.\n */\n api_key?: string;\n sandbox_id: string;\n project_id?: string;\n preset: SearchPreset;\n /** Default data_source_id for `ingest` when the caller doesn't pass one. */\n ingest_data_source_id?: string;\n /**\n * If set, the server attaches to this Context Window on startup and makes\n * it the active window. Use when another process (e.g. a Hono server)\n * already created the window and you're launching the MCP server as a\n * subprocess that should share it.\n */\n context_window_id?: string;\n /**\n * Optional pre-existing turns to seed the Context Window's buffer on\n * startup. Makes retrieval immediately window-aware on the first tool\n * call — without these, the first `discover` / `interpret` / `search`\n * after a subprocess spawn sees an empty history.\n *\n * Required when `context_window_id` refers to a thread that has prior\n * turns and the server should dedupe retrieval against them.\n */\n context_window_initial_turns?: ChatMessage[];\n}\n\nconst VALID_PRESETS: readonly SearchPreset[] = [\n 'fast',\n 'auto',\n 'discover',\n 'sql',\n 'max',\n // `-decompose` variants are /search-only. Setting one of these as the\n // MCP subprocess default makes `interpret` fail (decomposition isn't\n // valid on /interpret) — fine when the subprocess is only used for\n // `search`, otherwise override per-call via the `preset` tool arg.\n 'fast-decompose',\n 'auto-decompose',\n 'discover-decompose',\n 'sql-decompose',\n] as const;\n\n/**\n * Read config from `process.env`.\n *\n * - `COPASS_API_KEY` (required)\n * - `COPASS_SANDBOX_ID` (required)\n * - `COPASS_API_URL` (default: https://ai.copass.id)\n * - `COPASS_PROJECT_ID` (optional — default for retrieval/ingest)\n * - `COPASS_PRESET` (default: `auto`). Accepts any `SearchPreset`, but\n * `auto` is the only value whose providers consume the\n * `semantic_alignment_scopes` that `/interpret`'s scope adapter\n * produces — so non-`auto` defaults (and any `-decompose` default)\n * break `interpret`. Leave at `auto` unless the subprocess is\n * search-only, and override per-call via the `preset` tool arg.\n *\n * Throws a descriptive error for missing/invalid values so the MCP client\n * sees an immediate startup failure with actionable text.\n */\nexport function loadConfig(env: NodeJS.ProcessEnv = process.env): ServerConfig {\n const missing: string[] = [];\n const api_key = env.COPASS_API_KEY ?? '';\n const sandbox_id = env.COPASS_SANDBOX_ID ?? '';\n\n if (!api_key) missing.push('COPASS_API_KEY');\n if (!sandbox_id) missing.push('COPASS_SANDBOX_ID');\n\n if (missing.length > 0) {\n throw new Error(\n `@copass/mcp: missing required env var(s): ${missing.join(', ')}. ` +\n `Set them before launching the server.`,\n );\n }\n\n const api_url = env.COPASS_API_URL?.trim() || 'https://ai.copass.id';\n const project_id = env.COPASS_PROJECT_ID?.trim() || undefined;\n const rawPreset = env.COPASS_PRESET?.trim() || 'auto';\n\n if (!VALID_PRESETS.includes(rawPreset as SearchPreset)) {\n throw new Error(\n `@copass/mcp: COPASS_PRESET must be one of ${VALID_PRESETS.join(', ')}; got \"${rawPreset}\"`,\n );\n }\n\n const ingest_data_source_id = env.COPASS_INGEST_DATA_SOURCE_ID?.trim() || undefined;\n const context_window_id = env.COPASS_CONTEXT_WINDOW_ID?.trim() || undefined;\n const context_window_initial_turns = parseInitialTurns(\n env.COPASS_CONTEXT_WINDOW_INITIAL_TURNS,\n );\n\n return {\n api_url,\n api_key,\n sandbox_id,\n project_id,\n preset: rawPreset as SearchPreset,\n ingest_data_source_id,\n context_window_id,\n context_window_initial_turns,\n };\n}\n\nfunction parseInitialTurns(raw: string | undefined): ChatMessage[] | undefined {\n if (!raw || !raw.trim()) return undefined;\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n throw new Error(\n `@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS is not valid JSON: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n if (!Array.isArray(parsed)) {\n throw new Error(\n '@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS must be a JSON array of {role, content} objects',\n );\n }\n const turns: ChatMessage[] = [];\n for (const [i, entry] of parsed.entries()) {\n if (\n !entry ||\n typeof entry !== 'object' ||\n typeof (entry as { role?: unknown }).role !== 'string' ||\n typeof (entry as { content?: unknown }).content !== 'string'\n ) {\n throw new Error(\n `@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS[${i}] must be {role: string, content: string}`,\n );\n }\n const { role, content } = entry as { role: string; content: string };\n if (role !== 'user' && role !== 'assistant' && role !== 'system') {\n throw new Error(\n `@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS[${i}].role must be \"user\" | \"assistant\" | \"system\"; got \"${role}\"`,\n );\n }\n turns.push({ role, content });\n }\n return turns;\n}\n"],"mappings":"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","names":["import_zod","mcpResult","mcpError","import_zod","mcpResult","mcpError"]}

@@ -319,6 +319,9 @@ // src/server.ts

project_id: z3.string().optional().describe("Override the server default project_id."),
storage_only: z3.boolean().optional().describe("If true, chunk and store but skip ontology ingestion.")
storage_only: z3.boolean().optional().describe("If true, chunk and store but skip ontology ingestion."),
occurred_at: z3.string().optional().describe(
"Optional ISO 8601 timestamp anchoring the content to a real-world moment (e.g. when this decision was made, when the user said it). Used as the default occurred_at for any composed event whose own timestamp is null, so temporal queries can find it."
)
}
},
async ({ content, source_type, data_source_id, project_id, storage_only }) => {
async ({ content, source_type, data_source_id, project_id, storage_only, occurred_at }) => {
try {

@@ -335,3 +338,4 @@ const sourceId = data_source_id ?? config.ingest_data_source_id;

project_id: project_id ?? config.project_id,
storage_only
storage_only,
occurred_at
});

@@ -338,0 +342,0 @@ return mcpResult3({

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/server.ts","../src/windows.ts","../src/tools/retrieval.ts","../src/tools/context-window.ts","../src/tools/ingest.ts","../src/config.ts"],"sourcesContent":["import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CopassClient } from '@copass/core';\nimport type { ServerConfig } from './config.js';\nimport { WindowRegistry } from './windows.js';\nimport { registerRetrievalTools } from './tools/retrieval.js';\nimport { registerContextWindowTools } from './tools/context-window.js';\nimport { registerIngestTool } from './tools/ingest.js';\n\nexport interface BuildServerOptions {\n client: CopassClient;\n config: ServerConfig;\n /**\n * Optional pre-populated window registry. Useful when a parent process has\n * already created or attached to a Context Window and wants the server to\n * start with it as the active window.\n */\n windows?: WindowRegistry;\n}\n\n/**\n * Assemble the Copass MCP server with every tool registered. Doesn't connect\n * a transport — see `startStdioServer` in `./bin.ts` for the default path,\n * or wire your own transport if embedding.\n */\nexport function buildServer({ client, config, windows }: BuildServerOptions): McpServer {\n const server = new McpServer(\n {\n name: 'copass',\n version: '0.3.0',\n },\n {\n capabilities: { tools: {} },\n },\n );\n\n const registry = windows ?? new WindowRegistry();\n const deps = { client, config, windows: registry };\n\n registerRetrievalTools(server, deps);\n registerContextWindowTools(server, deps);\n registerIngestTool(server, { client, config });\n\n return server;\n}\n","import type { ContextWindow } from '@copass/core';\n\n/**\n * In-memory registry of open Context Windows.\n *\n * Tracks a map of `data_source_id → ContextWindow` plus a single \"active\"\n * window id. Retrieval and add-turn tools use the active window implicitly\n * so the LLM doesn't have to thread an id on every call.\n *\n * For multi-window use cases, callers pass `data_source_id` explicitly and\n * the active id is ignored.\n */\nexport class WindowRegistry {\n private readonly windows = new Map<string, ContextWindow>();\n private activeId: string | null = null;\n\n /** Register a new window and make it active. */\n set(window: ContextWindow): void {\n this.windows.set(window.dataSourceId, window);\n this.activeId = window.dataSourceId;\n }\n\n /** Look up a window by id, or fall back to the active one. */\n resolve(dataSourceId?: string): ContextWindow | undefined {\n const id = dataSourceId ?? this.activeId;\n return id ? this.windows.get(id) : undefined;\n }\n\n /** Make an existing window the active one. Throws if unknown. */\n activate(dataSourceId: string): ContextWindow {\n const window = this.windows.get(dataSourceId);\n if (!window) {\n throw new Error(\n `No window registered for data_source_id=\"${dataSourceId}\" — call context_window_create or context_window_attach first.`,\n );\n }\n this.activeId = dataSourceId;\n return window;\n }\n\n /** Drop a window from the registry. Clears active if it matched. */\n drop(dataSourceId: string): void {\n this.windows.delete(dataSourceId);\n if (this.activeId === dataSourceId) this.activeId = null;\n }\n\n get activeDataSourceId(): string | null {\n return this.activeId;\n }\n}\n","import { z } from 'zod';\nimport {\n DISCOVER_QUERY_PARAM,\n INTERPRET_DESCRIPTION,\n INTERPRET_ITEMS_PARAM,\n INTERPRET_QUERY_PARAM,\n MCP_DISCOVER_DESCRIPTION,\n PRESET_PARAM,\n PROJECT_ID_PARAM,\n SEARCH_DESCRIPTION,\n SEARCH_QUERY_PARAM,\n} from '@copass/config';\nimport type { CopassClient } from '@copass/core';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ServerConfig } from '../config.js';\nimport type { WindowRegistry } from '../windows.js';\n\ninterface RetrievalDeps {\n client: CopassClient;\n config: ServerConfig;\n windows: WindowRegistry;\n}\n\nfunction mcpResult(payload: unknown) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(payload, null, 2) }],\n };\n}\n\nfunction mcpError(error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Error: ${message}` }],\n isError: true,\n };\n}\n\nexport function registerRetrievalTools(server: McpServer, deps: RetrievalDeps): void {\n const { client, config, windows } = deps;\n\n server.registerTool(\n 'discover',\n {\n description: MCP_DISCOVER_DESCRIPTION,\n inputSchema: {\n query: z.string().describe(DISCOVER_QUERY_PARAM),\n project_id: z.string().optional().describe(PROJECT_ID_PARAM),\n },\n },\n async ({ query, project_id }) => {\n try {\n const response = await client.retrieval.discover(config.sandbox_id, {\n query,\n project_id: project_id ?? config.project_id,\n window: windows.resolve(),\n });\n return mcpResult({\n header: response.header,\n items: response.items.map((item) => ({\n score: item.score,\n summary: item.summary,\n canonical_ids: item.canonical_ids,\n })),\n next_steps: response.next_steps,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'interpret',\n {\n description: INTERPRET_DESCRIPTION,\n inputSchema: {\n query: z.string().describe(INTERPRET_QUERY_PARAM),\n items: z.array(z.array(z.string()).min(1)).min(1).describe(INTERPRET_ITEMS_PARAM),\n preset: z.enum(['fast', 'auto', 'max']).optional().describe(PRESET_PARAM),\n project_id: z.string().optional().describe(PROJECT_ID_PARAM),\n },\n },\n async ({ query, items, preset, project_id }) => {\n try {\n const response = await client.retrieval.interpret(config.sandbox_id, {\n query,\n items,\n project_id: project_id ?? config.project_id,\n window: windows.resolve(),\n preset: preset ?? config.preset,\n });\n return mcpResult({ brief: response.brief });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'search',\n {\n description: SEARCH_DESCRIPTION,\n inputSchema: {\n query: z.string().describe(SEARCH_QUERY_PARAM),\n // `max` is omitted — the server returns 403 for public callers,\n // so exposing it would only yield confusing tool-use errors.\n // `-decompose` variants split the question into sub-questions and\n // run the base preset on each before a combined synthesis.\n preset: z\n .enum([\n 'fast',\n 'auto',\n 'discover',\n 'sql',\n 'fast-decompose',\n 'auto-decompose',\n 'discover-decompose',\n 'sql-decompose',\n ])\n .optional()\n .describe(PRESET_PARAM),\n project_id: z.string().optional().describe(PROJECT_ID_PARAM),\n },\n },\n async ({ query, preset, project_id }) => {\n try {\n const response = await client.retrieval.search(config.sandbox_id, {\n query,\n project_id: project_id ?? config.project_id,\n window: windows.resolve(),\n preset: preset ?? config.preset,\n });\n return mcpResult({ answer: response.answer });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n}\n","import { z } from 'zod';\nimport type { CopassClient } from '@copass/core';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ServerConfig } from '../config.js';\nimport type { WindowRegistry } from '../windows.js';\n\ninterface ContextWindowDeps {\n client: CopassClient;\n config: ServerConfig;\n windows: WindowRegistry;\n}\n\nfunction mcpResult(payload: unknown) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(payload, null, 2) }],\n };\n}\n\nfunction mcpError(error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Error: ${message}` }],\n isError: true,\n };\n}\n\nexport function registerContextWindowTools(server: McpServer, deps: ContextWindowDeps): void {\n const { client, config, windows } = deps;\n\n server.registerTool(\n 'context_window_create',\n {\n description:\n 'Open a new Context Window — an ephemeral data source tracking this conversation. ' +\n 'Subsequent retrieval calls become automatically window-aware, and every turn you ' +\n 'record via `context_window_add_turn` is ingested into the graph so past turns ' +\n 'become retrievable. Returns a `data_source_id`; persist it on your side if you ' +\n 'may want to resume this conversation later via `context_window_attach`.',\n inputSchema: {\n project_id: z.string().optional().describe('Override the server default project_id.'),\n name: z.string().optional().describe('Optional stable name for the underlying data source.'),\n },\n },\n async ({ project_id, name }) => {\n try {\n const window = await client.contextWindow.create({\n sandbox_id: config.sandbox_id,\n project_id: project_id ?? config.project_id,\n name,\n });\n windows.set(window);\n return mcpResult({\n data_source_id: window.dataSourceId,\n active: true,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'context_window_add_turn',\n {\n description:\n 'Append a turn to the active Context Window and push it into the graph. Call on ' +\n 'every user message AND every assistant message so the thread itself becomes ' +\n 'retrievable. If you omit `data_source_id`, the active window is used.',\n inputSchema: {\n role: z\n .enum(['user', 'assistant', 'system'])\n .describe('Role of the speaker for this turn.'),\n content: z.string().describe('The turn content.'),\n data_source_id: z\n .string()\n .optional()\n .describe('Override the active window id (for multi-window use cases).'),\n },\n },\n async ({ role, content, data_source_id }) => {\n try {\n const window = windows.resolve(data_source_id);\n if (!window) {\n throw new Error(\n 'No active Context Window — call context_window_create or context_window_attach first.',\n );\n }\n await window.addTurn({ role, content });\n return mcpResult({\n data_source_id: window.dataSourceId,\n turn_count: window.getTurns().length,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'context_window_attach',\n {\n description:\n 'Resume an existing Context Window by `data_source_id` (one you previously persisted ' +\n 'on your side after `context_window_create`). Makes the resumed window the active ' +\n 'window. Pass `initial_turns` to seed the local buffer for immediate window-aware ' +\n 'retrieval, otherwise the buffer starts empty and fills as you call add_turn.',\n inputSchema: {\n data_source_id: z.string().describe('Id of the Context Window data source to resume.'),\n initial_turns: z\n .array(\n z.object({\n role: z.enum(['user', 'assistant', 'system']),\n content: z.string(),\n }),\n )\n .optional()\n .describe('Optional pre-existing turns to seed the local buffer.'),\n },\n },\n async ({ data_source_id, initial_turns }) => {\n try {\n const window = await client.contextWindow.attach({\n sandbox_id: config.sandbox_id,\n data_source_id,\n initialTurns: initial_turns,\n });\n windows.set(window);\n return mcpResult({\n data_source_id: window.dataSourceId,\n turn_count: window.getTurns().length,\n active: true,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'context_window_close',\n {\n description:\n 'Close a Context Window — flips the underlying data source to `disconnected` ' +\n 'immediately instead of waiting for TTL. Best-effort; idempotent. If you omit ' +\n '`data_source_id`, the active window is closed.',\n inputSchema: {\n data_source_id: z\n .string()\n .optional()\n .describe('Override the active window id.'),\n },\n },\n async ({ data_source_id }) => {\n try {\n const window = windows.resolve(data_source_id);\n if (!window) {\n throw new Error('No active Context Window to close.');\n }\n await window.close();\n windows.drop(window.dataSourceId);\n return mcpResult({\n data_source_id: window.dataSourceId,\n closed: true,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n}\n","import { z } from 'zod';\nimport type { CopassClient } from '@copass/core';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ServerConfig } from '../config.js';\n\ninterface IngestDeps {\n client: CopassClient;\n config: ServerConfig;\n}\n\nfunction mcpResult(payload: unknown) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(payload, null, 2) }],\n };\n}\n\nfunction mcpError(error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Error: ${message}` }],\n isError: true,\n };\n}\n\nexport function registerIngestTool(server: McpServer, deps: IngestDeps): void {\n const { client, config } = deps;\n\n server.registerTool(\n 'ingest',\n {\n description:\n 'Push content into the knowledge graph via a data source. Use for: architecture ' +\n 'decisions (source_type: \"decision\"), user-shared context (\"user_input\"), ' +\n 'corrections (\"correction\"), durable notes, any significant new concept. Do NOT ' +\n 'ingest trivial changes or ephemeral debug context — those belong in the Context ' +\n 'Window (via context_window_add_turn). Pass `data_source_id` explicitly or set ' +\n '`COPASS_INGEST_DATA_SOURCE_ID` in the server env for an implicit target.',\n inputSchema: {\n content: z.string().min(1).describe('The content to ingest.'),\n source_type: z\n .string()\n .optional()\n .describe(\n 'Type tag: code, markdown, json, text, conversation, decision, correction, ' +\n 'user_input. Defaults to \"text\" when omitted.',\n ),\n data_source_id: z\n .string()\n .optional()\n .describe(\n 'Target data source. Falls back to COPASS_INGEST_DATA_SOURCE_ID env var.',\n ),\n project_id: z.string().optional().describe('Override the server default project_id.'),\n storage_only: z\n .boolean()\n .optional()\n .describe('If true, chunk and store but skip ontology ingestion.'),\n },\n },\n async ({ content, source_type, data_source_id, project_id, storage_only }) => {\n try {\n const sourceId = data_source_id ?? config.ingest_data_source_id;\n if (!sourceId) {\n throw new Error(\n 'ingest requires a `data_source_id` argument or COPASS_INGEST_DATA_SOURCE_ID env var. ' +\n 'Register a data source via the REST API or CLI, then pass its id here.',\n );\n }\n\n const response = await client.sources.ingest(config.sandbox_id, sourceId, {\n text: content,\n source_type: source_type ?? 'text',\n project_id: project_id ?? config.project_id,\n storage_only,\n });\n\n return mcpResult({\n job_id: response.job_id,\n status: response.status,\n data_source_id: sourceId,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n}\n","import type { ChatMessage, SearchPreset } from '@copass/core';\n\nexport interface ServerConfig {\n api_url: string;\n /**\n * Required when the standalone `copass-mcp` bin builds its own\n * `CopassClient` from this config (`bin.ts`). Optional for embedded\n * use — when a host process (e.g. another MCP server) constructs the\n * `CopassClient` itself and passes it into `buildServer({ client })`,\n * the tool handlers never read this field.\n */\n api_key?: string;\n sandbox_id: string;\n project_id?: string;\n preset: SearchPreset;\n /** Default data_source_id for `ingest` when the caller doesn't pass one. */\n ingest_data_source_id?: string;\n /**\n * If set, the server attaches to this Context Window on startup and makes\n * it the active window. Use when another process (e.g. a Hono server)\n * already created the window and you're launching the MCP server as a\n * subprocess that should share it.\n */\n context_window_id?: string;\n /**\n * Optional pre-existing turns to seed the Context Window's buffer on\n * startup. Makes retrieval immediately window-aware on the first tool\n * call — without these, the first `discover` / `interpret` / `search`\n * after a subprocess spawn sees an empty history.\n *\n * Required when `context_window_id` refers to a thread that has prior\n * turns and the server should dedupe retrieval against them.\n */\n context_window_initial_turns?: ChatMessage[];\n}\n\nconst VALID_PRESETS: readonly SearchPreset[] = [\n 'fast',\n 'auto',\n 'discover',\n 'sql',\n 'max',\n // `-decompose` variants are /search-only. Setting one of these as the\n // MCP subprocess default makes `interpret` fail (decomposition isn't\n // valid on /interpret) — fine when the subprocess is only used for\n // `search`, otherwise override per-call via the `preset` tool arg.\n 'fast-decompose',\n 'auto-decompose',\n 'discover-decompose',\n 'sql-decompose',\n] as const;\n\n/**\n * Read config from `process.env`.\n *\n * - `COPASS_API_KEY` (required)\n * - `COPASS_SANDBOX_ID` (required)\n * - `COPASS_API_URL` (default: https://ai.copass.id)\n * - `COPASS_PROJECT_ID` (optional — default for retrieval/ingest)\n * - `COPASS_PRESET` (default: `auto`). Accepts any `SearchPreset`, but\n * `auto` is the only value whose providers consume the\n * `semantic_alignment_scopes` that `/interpret`'s scope adapter\n * produces — so non-`auto` defaults (and any `-decompose` default)\n * break `interpret`. Leave at `auto` unless the subprocess is\n * search-only, and override per-call via the `preset` tool arg.\n *\n * Throws a descriptive error for missing/invalid values so the MCP client\n * sees an immediate startup failure with actionable text.\n */\nexport function loadConfig(env: NodeJS.ProcessEnv = process.env): ServerConfig {\n const missing: string[] = [];\n const api_key = env.COPASS_API_KEY ?? '';\n const sandbox_id = env.COPASS_SANDBOX_ID ?? '';\n\n if (!api_key) missing.push('COPASS_API_KEY');\n if (!sandbox_id) missing.push('COPASS_SANDBOX_ID');\n\n if (missing.length > 0) {\n throw new Error(\n `@copass/mcp: missing required env var(s): ${missing.join(', ')}. ` +\n `Set them before launching the server.`,\n );\n }\n\n const api_url = env.COPASS_API_URL?.trim() || 'https://ai.copass.id';\n const project_id = env.COPASS_PROJECT_ID?.trim() || undefined;\n const rawPreset = env.COPASS_PRESET?.trim() || 'auto';\n\n if (!VALID_PRESETS.includes(rawPreset as SearchPreset)) {\n throw new Error(\n `@copass/mcp: COPASS_PRESET must be one of ${VALID_PRESETS.join(', ')}; got \"${rawPreset}\"`,\n );\n }\n\n const ingest_data_source_id = env.COPASS_INGEST_DATA_SOURCE_ID?.trim() || undefined;\n const context_window_id = env.COPASS_CONTEXT_WINDOW_ID?.trim() || undefined;\n const context_window_initial_turns = parseInitialTurns(\n env.COPASS_CONTEXT_WINDOW_INITIAL_TURNS,\n );\n\n return {\n api_url,\n api_key,\n sandbox_id,\n project_id,\n preset: rawPreset as SearchPreset,\n ingest_data_source_id,\n context_window_id,\n context_window_initial_turns,\n };\n}\n\nfunction parseInitialTurns(raw: string | undefined): ChatMessage[] | undefined {\n if (!raw || !raw.trim()) return undefined;\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n throw new Error(\n `@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS is not valid JSON: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n if (!Array.isArray(parsed)) {\n throw new Error(\n '@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS must be a JSON array of {role, content} objects',\n );\n }\n const turns: ChatMessage[] = [];\n for (const [i, entry] of parsed.entries()) {\n if (\n !entry ||\n typeof entry !== 'object' ||\n typeof (entry as { role?: unknown }).role !== 'string' ||\n typeof (entry as { content?: unknown }).content !== 'string'\n ) {\n throw new Error(\n `@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS[${i}] must be {role: string, content: string}`,\n );\n }\n const { role, content } = entry as { role: string; content: string };\n if (role !== 'user' && role !== 'assistant' && role !== 'system') {\n throw new Error(\n `@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS[${i}].role must be \"user\" | \"assistant\" | \"system\"; got \"${role}\"`,\n );\n }\n turns.push({ role, content });\n }\n return turns;\n}\n"],"mappings":"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","names":["z","mcpResult","mcpError","z","mcpResult","mcpError"]}
{"version":3,"sources":["../src/server.ts","../src/windows.ts","../src/tools/retrieval.ts","../src/tools/context-window.ts","../src/tools/ingest.ts","../src/config.ts"],"sourcesContent":["import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { CopassClient } from '@copass/core';\nimport type { ServerConfig } from './config.js';\nimport { WindowRegistry } from './windows.js';\nimport { registerRetrievalTools } from './tools/retrieval.js';\nimport { registerContextWindowTools } from './tools/context-window.js';\nimport { registerIngestTool } from './tools/ingest.js';\n\nexport interface BuildServerOptions {\n client: CopassClient;\n config: ServerConfig;\n /**\n * Optional pre-populated window registry. Useful when a parent process has\n * already created or attached to a Context Window and wants the server to\n * start with it as the active window.\n */\n windows?: WindowRegistry;\n}\n\n/**\n * Assemble the Copass MCP server with every tool registered. Doesn't connect\n * a transport — see `startStdioServer` in `./bin.ts` for the default path,\n * or wire your own transport if embedding.\n */\nexport function buildServer({ client, config, windows }: BuildServerOptions): McpServer {\n const server = new McpServer(\n {\n name: 'copass',\n version: '0.3.0',\n },\n {\n capabilities: { tools: {} },\n },\n );\n\n const registry = windows ?? new WindowRegistry();\n const deps = { client, config, windows: registry };\n\n registerRetrievalTools(server, deps);\n registerContextWindowTools(server, deps);\n registerIngestTool(server, { client, config });\n\n return server;\n}\n","import type { ContextWindow } from '@copass/core';\n\n/**\n * In-memory registry of open Context Windows.\n *\n * Tracks a map of `data_source_id → ContextWindow` plus a single \"active\"\n * window id. Retrieval and add-turn tools use the active window implicitly\n * so the LLM doesn't have to thread an id on every call.\n *\n * For multi-window use cases, callers pass `data_source_id` explicitly and\n * the active id is ignored.\n */\nexport class WindowRegistry {\n private readonly windows = new Map<string, ContextWindow>();\n private activeId: string | null = null;\n\n /** Register a new window and make it active. */\n set(window: ContextWindow): void {\n this.windows.set(window.dataSourceId, window);\n this.activeId = window.dataSourceId;\n }\n\n /** Look up a window by id, or fall back to the active one. */\n resolve(dataSourceId?: string): ContextWindow | undefined {\n const id = dataSourceId ?? this.activeId;\n return id ? this.windows.get(id) : undefined;\n }\n\n /** Make an existing window the active one. Throws if unknown. */\n activate(dataSourceId: string): ContextWindow {\n const window = this.windows.get(dataSourceId);\n if (!window) {\n throw new Error(\n `No window registered for data_source_id=\"${dataSourceId}\" — call context_window_create or context_window_attach first.`,\n );\n }\n this.activeId = dataSourceId;\n return window;\n }\n\n /** Drop a window from the registry. Clears active if it matched. */\n drop(dataSourceId: string): void {\n this.windows.delete(dataSourceId);\n if (this.activeId === dataSourceId) this.activeId = null;\n }\n\n get activeDataSourceId(): string | null {\n return this.activeId;\n }\n}\n","import { z } from 'zod';\nimport {\n DISCOVER_QUERY_PARAM,\n INTERPRET_DESCRIPTION,\n INTERPRET_ITEMS_PARAM,\n INTERPRET_QUERY_PARAM,\n MCP_DISCOVER_DESCRIPTION,\n PRESET_PARAM,\n PROJECT_ID_PARAM,\n SEARCH_DESCRIPTION,\n SEARCH_QUERY_PARAM,\n} from '@copass/config';\nimport type { CopassClient } from '@copass/core';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ServerConfig } from '../config.js';\nimport type { WindowRegistry } from '../windows.js';\n\ninterface RetrievalDeps {\n client: CopassClient;\n config: ServerConfig;\n windows: WindowRegistry;\n}\n\nfunction mcpResult(payload: unknown) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(payload, null, 2) }],\n };\n}\n\nfunction mcpError(error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Error: ${message}` }],\n isError: true,\n };\n}\n\nexport function registerRetrievalTools(server: McpServer, deps: RetrievalDeps): void {\n const { client, config, windows } = deps;\n\n server.registerTool(\n 'discover',\n {\n description: MCP_DISCOVER_DESCRIPTION,\n inputSchema: {\n query: z.string().describe(DISCOVER_QUERY_PARAM),\n project_id: z.string().optional().describe(PROJECT_ID_PARAM),\n },\n },\n async ({ query, project_id }) => {\n try {\n const response = await client.retrieval.discover(config.sandbox_id, {\n query,\n project_id: project_id ?? config.project_id,\n window: windows.resolve(),\n });\n return mcpResult({\n header: response.header,\n items: response.items.map((item) => ({\n score: item.score,\n summary: item.summary,\n canonical_ids: item.canonical_ids,\n })),\n next_steps: response.next_steps,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'interpret',\n {\n description: INTERPRET_DESCRIPTION,\n inputSchema: {\n query: z.string().describe(INTERPRET_QUERY_PARAM),\n items: z.array(z.array(z.string()).min(1)).min(1).describe(INTERPRET_ITEMS_PARAM),\n preset: z.enum(['fast', 'auto', 'max']).optional().describe(PRESET_PARAM),\n project_id: z.string().optional().describe(PROJECT_ID_PARAM),\n },\n },\n async ({ query, items, preset, project_id }) => {\n try {\n const response = await client.retrieval.interpret(config.sandbox_id, {\n query,\n items,\n project_id: project_id ?? config.project_id,\n window: windows.resolve(),\n preset: preset ?? config.preset,\n });\n return mcpResult({ brief: response.brief });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'search',\n {\n description: SEARCH_DESCRIPTION,\n inputSchema: {\n query: z.string().describe(SEARCH_QUERY_PARAM),\n // `max` is omitted — the server returns 403 for public callers,\n // so exposing it would only yield confusing tool-use errors.\n // `-decompose` variants split the question into sub-questions and\n // run the base preset on each before a combined synthesis.\n preset: z\n .enum([\n 'fast',\n 'auto',\n 'discover',\n 'sql',\n 'fast-decompose',\n 'auto-decompose',\n 'discover-decompose',\n 'sql-decompose',\n ])\n .optional()\n .describe(PRESET_PARAM),\n project_id: z.string().optional().describe(PROJECT_ID_PARAM),\n },\n },\n async ({ query, preset, project_id }) => {\n try {\n const response = await client.retrieval.search(config.sandbox_id, {\n query,\n project_id: project_id ?? config.project_id,\n window: windows.resolve(),\n preset: preset ?? config.preset,\n });\n return mcpResult({ answer: response.answer });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n}\n","import { z } from 'zod';\nimport type { CopassClient } from '@copass/core';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ServerConfig } from '../config.js';\nimport type { WindowRegistry } from '../windows.js';\n\ninterface ContextWindowDeps {\n client: CopassClient;\n config: ServerConfig;\n windows: WindowRegistry;\n}\n\nfunction mcpResult(payload: unknown) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(payload, null, 2) }],\n };\n}\n\nfunction mcpError(error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Error: ${message}` }],\n isError: true,\n };\n}\n\nexport function registerContextWindowTools(server: McpServer, deps: ContextWindowDeps): void {\n const { client, config, windows } = deps;\n\n server.registerTool(\n 'context_window_create',\n {\n description:\n 'Open a new Context Window — an ephemeral data source tracking this conversation. ' +\n 'Subsequent retrieval calls become automatically window-aware, and every turn you ' +\n 'record via `context_window_add_turn` is ingested into the graph so past turns ' +\n 'become retrievable. Returns a `data_source_id`; persist it on your side if you ' +\n 'may want to resume this conversation later via `context_window_attach`.',\n inputSchema: {\n project_id: z.string().optional().describe('Override the server default project_id.'),\n name: z.string().optional().describe('Optional stable name for the underlying data source.'),\n },\n },\n async ({ project_id, name }) => {\n try {\n const window = await client.contextWindow.create({\n sandbox_id: config.sandbox_id,\n project_id: project_id ?? config.project_id,\n name,\n });\n windows.set(window);\n return mcpResult({\n data_source_id: window.dataSourceId,\n active: true,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'context_window_add_turn',\n {\n description:\n 'Append a turn to the active Context Window and push it into the graph. Call on ' +\n 'every user message AND every assistant message so the thread itself becomes ' +\n 'retrievable. If you omit `data_source_id`, the active window is used.',\n inputSchema: {\n role: z\n .enum(['user', 'assistant', 'system'])\n .describe('Role of the speaker for this turn.'),\n content: z.string().describe('The turn content.'),\n data_source_id: z\n .string()\n .optional()\n .describe('Override the active window id (for multi-window use cases).'),\n },\n },\n async ({ role, content, data_source_id }) => {\n try {\n const window = windows.resolve(data_source_id);\n if (!window) {\n throw new Error(\n 'No active Context Window — call context_window_create or context_window_attach first.',\n );\n }\n await window.addTurn({ role, content });\n return mcpResult({\n data_source_id: window.dataSourceId,\n turn_count: window.getTurns().length,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'context_window_attach',\n {\n description:\n 'Resume an existing Context Window by `data_source_id` (one you previously persisted ' +\n 'on your side after `context_window_create`). Makes the resumed window the active ' +\n 'window. Pass `initial_turns` to seed the local buffer for immediate window-aware ' +\n 'retrieval, otherwise the buffer starts empty and fills as you call add_turn.',\n inputSchema: {\n data_source_id: z.string().describe('Id of the Context Window data source to resume.'),\n initial_turns: z\n .array(\n z.object({\n role: z.enum(['user', 'assistant', 'system']),\n content: z.string(),\n }),\n )\n .optional()\n .describe('Optional pre-existing turns to seed the local buffer.'),\n },\n },\n async ({ data_source_id, initial_turns }) => {\n try {\n const window = await client.contextWindow.attach({\n sandbox_id: config.sandbox_id,\n data_source_id,\n initialTurns: initial_turns,\n });\n windows.set(window);\n return mcpResult({\n data_source_id: window.dataSourceId,\n turn_count: window.getTurns().length,\n active: true,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n\n server.registerTool(\n 'context_window_close',\n {\n description:\n 'Close a Context Window — flips the underlying data source to `disconnected` ' +\n 'immediately instead of waiting for TTL. Best-effort; idempotent. If you omit ' +\n '`data_source_id`, the active window is closed.',\n inputSchema: {\n data_source_id: z\n .string()\n .optional()\n .describe('Override the active window id.'),\n },\n },\n async ({ data_source_id }) => {\n try {\n const window = windows.resolve(data_source_id);\n if (!window) {\n throw new Error('No active Context Window to close.');\n }\n await window.close();\n windows.drop(window.dataSourceId);\n return mcpResult({\n data_source_id: window.dataSourceId,\n closed: true,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n}\n","import { z } from 'zod';\nimport type { CopassClient } from '@copass/core';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ServerConfig } from '../config.js';\n\ninterface IngestDeps {\n client: CopassClient;\n config: ServerConfig;\n}\n\nfunction mcpResult(payload: unknown) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(payload, null, 2) }],\n };\n}\n\nfunction mcpError(error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Error: ${message}` }],\n isError: true,\n };\n}\n\nexport function registerIngestTool(server: McpServer, deps: IngestDeps): void {\n const { client, config } = deps;\n\n server.registerTool(\n 'ingest',\n {\n description:\n 'Push content into the knowledge graph via a data source. Use for: architecture ' +\n 'decisions (source_type: \"decision\"), user-shared context (\"user_input\"), ' +\n 'corrections (\"correction\"), durable notes, any significant new concept. Do NOT ' +\n 'ingest trivial changes or ephemeral debug context — those belong in the Context ' +\n 'Window (via context_window_add_turn). Pass `data_source_id` explicitly or set ' +\n '`COPASS_INGEST_DATA_SOURCE_ID` in the server env for an implicit target.',\n inputSchema: {\n content: z.string().min(1).describe('The content to ingest.'),\n source_type: z\n .string()\n .optional()\n .describe(\n 'Type tag: code, markdown, json, text, conversation, decision, correction, ' +\n 'user_input. Defaults to \"text\" when omitted.',\n ),\n data_source_id: z\n .string()\n .optional()\n .describe(\n 'Target data source. Falls back to COPASS_INGEST_DATA_SOURCE_ID env var.',\n ),\n project_id: z.string().optional().describe('Override the server default project_id.'),\n storage_only: z\n .boolean()\n .optional()\n .describe('If true, chunk and store but skip ontology ingestion.'),\n occurred_at: z\n .string()\n .optional()\n .describe(\n 'Optional ISO 8601 timestamp anchoring the content to a real-world moment ' +\n '(e.g. when this decision was made, when the user said it). Used as the ' +\n 'default occurred_at for any composed event whose own timestamp is null, ' +\n 'so temporal queries can find it.',\n ),\n },\n },\n async ({ content, source_type, data_source_id, project_id, storage_only, occurred_at }) => {\n try {\n const sourceId = data_source_id ?? config.ingest_data_source_id;\n if (!sourceId) {\n throw new Error(\n 'ingest requires a `data_source_id` argument or COPASS_INGEST_DATA_SOURCE_ID env var. ' +\n 'Register a data source via the REST API or CLI, then pass its id here.',\n );\n }\n\n const response = await client.sources.ingest(config.sandbox_id, sourceId, {\n text: content,\n source_type: source_type ?? 'text',\n project_id: project_id ?? config.project_id,\n storage_only,\n occurred_at,\n });\n\n return mcpResult({\n job_id: response.job_id,\n status: response.status,\n data_source_id: sourceId,\n });\n } catch (e) {\n return mcpError(e);\n }\n },\n );\n}\n","import type { ChatMessage, SearchPreset } from '@copass/core';\n\nexport interface ServerConfig {\n api_url: string;\n /**\n * Required when the standalone `copass-mcp` bin builds its own\n * `CopassClient` from this config (`bin.ts`). Optional for embedded\n * use — when a host process (e.g. another MCP server) constructs the\n * `CopassClient` itself and passes it into `buildServer({ client })`,\n * the tool handlers never read this field.\n */\n api_key?: string;\n sandbox_id: string;\n project_id?: string;\n preset: SearchPreset;\n /** Default data_source_id for `ingest` when the caller doesn't pass one. */\n ingest_data_source_id?: string;\n /**\n * If set, the server attaches to this Context Window on startup and makes\n * it the active window. Use when another process (e.g. a Hono server)\n * already created the window and you're launching the MCP server as a\n * subprocess that should share it.\n */\n context_window_id?: string;\n /**\n * Optional pre-existing turns to seed the Context Window's buffer on\n * startup. Makes retrieval immediately window-aware on the first tool\n * call — without these, the first `discover` / `interpret` / `search`\n * after a subprocess spawn sees an empty history.\n *\n * Required when `context_window_id` refers to a thread that has prior\n * turns and the server should dedupe retrieval against them.\n */\n context_window_initial_turns?: ChatMessage[];\n}\n\nconst VALID_PRESETS: readonly SearchPreset[] = [\n 'fast',\n 'auto',\n 'discover',\n 'sql',\n 'max',\n // `-decompose` variants are /search-only. Setting one of these as the\n // MCP subprocess default makes `interpret` fail (decomposition isn't\n // valid on /interpret) — fine when the subprocess is only used for\n // `search`, otherwise override per-call via the `preset` tool arg.\n 'fast-decompose',\n 'auto-decompose',\n 'discover-decompose',\n 'sql-decompose',\n] as const;\n\n/**\n * Read config from `process.env`.\n *\n * - `COPASS_API_KEY` (required)\n * - `COPASS_SANDBOX_ID` (required)\n * - `COPASS_API_URL` (default: https://ai.copass.id)\n * - `COPASS_PROJECT_ID` (optional — default for retrieval/ingest)\n * - `COPASS_PRESET` (default: `auto`). Accepts any `SearchPreset`, but\n * `auto` is the only value whose providers consume the\n * `semantic_alignment_scopes` that `/interpret`'s scope adapter\n * produces — so non-`auto` defaults (and any `-decompose` default)\n * break `interpret`. Leave at `auto` unless the subprocess is\n * search-only, and override per-call via the `preset` tool arg.\n *\n * Throws a descriptive error for missing/invalid values so the MCP client\n * sees an immediate startup failure with actionable text.\n */\nexport function loadConfig(env: NodeJS.ProcessEnv = process.env): ServerConfig {\n const missing: string[] = [];\n const api_key = env.COPASS_API_KEY ?? '';\n const sandbox_id = env.COPASS_SANDBOX_ID ?? '';\n\n if (!api_key) missing.push('COPASS_API_KEY');\n if (!sandbox_id) missing.push('COPASS_SANDBOX_ID');\n\n if (missing.length > 0) {\n throw new Error(\n `@copass/mcp: missing required env var(s): ${missing.join(', ')}. ` +\n `Set them before launching the server.`,\n );\n }\n\n const api_url = env.COPASS_API_URL?.trim() || 'https://ai.copass.id';\n const project_id = env.COPASS_PROJECT_ID?.trim() || undefined;\n const rawPreset = env.COPASS_PRESET?.trim() || 'auto';\n\n if (!VALID_PRESETS.includes(rawPreset as SearchPreset)) {\n throw new Error(\n `@copass/mcp: COPASS_PRESET must be one of ${VALID_PRESETS.join(', ')}; got \"${rawPreset}\"`,\n );\n }\n\n const ingest_data_source_id = env.COPASS_INGEST_DATA_SOURCE_ID?.trim() || undefined;\n const context_window_id = env.COPASS_CONTEXT_WINDOW_ID?.trim() || undefined;\n const context_window_initial_turns = parseInitialTurns(\n env.COPASS_CONTEXT_WINDOW_INITIAL_TURNS,\n );\n\n return {\n api_url,\n api_key,\n sandbox_id,\n project_id,\n preset: rawPreset as SearchPreset,\n ingest_data_source_id,\n context_window_id,\n context_window_initial_turns,\n };\n}\n\nfunction parseInitialTurns(raw: string | undefined): ChatMessage[] | undefined {\n if (!raw || !raw.trim()) return undefined;\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (err) {\n throw new Error(\n `@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS is not valid JSON: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n if (!Array.isArray(parsed)) {\n throw new Error(\n '@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS must be a JSON array of {role, content} objects',\n );\n }\n const turns: ChatMessage[] = [];\n for (const [i, entry] of parsed.entries()) {\n if (\n !entry ||\n typeof entry !== 'object' ||\n typeof (entry as { role?: unknown }).role !== 'string' ||\n typeof (entry as { content?: unknown }).content !== 'string'\n ) {\n throw new Error(\n `@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS[${i}] must be {role: string, content: string}`,\n );\n }\n const { role, content } = entry as { role: string; content: string };\n if (role !== 'user' && role !== 'assistant' && role !== 'system') {\n throw new Error(\n `@copass/mcp: COPASS_CONTEXT_WINDOW_INITIAL_TURNS[${i}].role must be \"user\" | \"assistant\" | \"system\"; got \"${role}\"`,\n );\n }\n turns.push({ role, content });\n }\n return turns;\n}\n"],"mappings":"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","names":["z","mcpResult","mcpError","z","mcpResult","mcpError"]}
{
"name": "@copass/mcp",
"version": "0.3.5",
"version": "0.3.6",
"description": "Standalone MCP server for Copass — drop-in discover/interpret/search + Context Window tools for any MCP client (Claude Agent SDK, Claude Code, Claude Desktop, Cursor)",

@@ -71,3 +71,3 @@ "publishConfig": {

"devDependencies": {
"@copass/core": "^0.3.5",
"@copass/core": "^0.3.6",
"@types/node": "^25.0.0",

@@ -77,3 +77,3 @@ "tsup": "^8.5.0",

},
"gitHead": "f2abb022e54daabdaf7e3ccd27a974c54e3a202e"
"gitHead": "8ade3ea8b8d9f19b84b618dce5e96565eeaef0f7"
}