@brightbeamai/chap-coordinator-mcp 0.3.3 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +162 -19
- package/dist/cli.cjs +338 -41
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +341 -39
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +485 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +92 -8
- package/dist/index.d.ts +92 -8
- package/dist/index.js +486 -21
- package/dist/index.js.map +1 -1
- package/dist/schemas.cjs +40 -3
- package/dist/schemas.cjs.map +1 -1
- package/dist/schemas.d.cts +1 -1
- package/dist/schemas.d.ts +1 -1
- package/dist/schemas.js +40 -3
- package/dist/schemas.js.map +1 -1
- package/dist/tools.cjs +27 -6
- package/dist/tools.cjs.map +1 -1
- package/dist/tools.d.cts +17 -1
- package/dist/tools.d.ts +17 -1
- package/dist/tools.js +26 -6
- package/dist/tools.js.map +1 -1
- package/package.json +3 -3
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/index.ts","../src/schemas.ts","../src/tools.ts","../src/envelope.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * CHAP MCP server (stdio).\n *\n * Runs a CHAP Coordinator and exposes every CHAP method as an MCP tool, so\n * any MCP client can drive a CHAP workspace.\n *\n * npx @brightbeamai/chap-coordinator-mcp\n *\n * Client configuration (Claude Desktop, Claude Code, Cursor, and similar):\n *\n * { \"mcpServers\": { \"chap\": {\n * \"command\": \"npx\",\n * \"args\": [\"-y\", \"@brightbeamai/chap-coordinator-mcp\"],\n * \"env\": { \"CHAP_DB_PATH\": \"~/chap.db\" } } } }\n *\n * Environment\n *\n * CHAP_DB_PATH Path to a SQLite file. Without it the coordinator runs in\n * memory and everything is lost when the client restarts,\n * which is fine for a trial and wrong for real decisions.\n * CHAP_PROFILES Comma-separated profile list for new workspaces.\n * Defaults to the set below.\n *\n * To embed the server in your own process instead, import makeChapMcpServer\n * from this package and pass it a Coordinator you built yourself.\n *\n * Spec target: MCP 2026-07-28, serving 2025-11-25 clients as well.\n */\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { Coordinator } from \"@brightbeamai/chap-coordinator\";\nimport type { Store } from \"@brightbeamai/chap-coordinator\";\nimport { makeChapMcpServer } from \"./index.js\";\n\nconst VERSION = \"0.3.3\";\n\n/**\n * Chaining is on by default because it costs almost nothing and the\n * alternative is worse: a workspace that adds audit-scitt/1.0 later can\n * never chain-verify the entries written before it, so verify_chain reports\n * not_evaluated for the rest of that workspace's life. Starting chained\n * avoids the gap entirely.\n */\nconst DEFAULT_PROFILES = [\n \"core/1.0\",\n \"review/1.0\",\n \"whisper/1.0\",\n \"deliberation/1.0\",\n \"handoff/1.0\",\n \"control/1.0\",\n \"routing/1.0\",\n \"modes/1.0\",\n \"audit-scitt/1.0\",\n];\n\nconst profiles = process.env.CHAP_PROFILES\n ? process.env.CHAP_PROFILES.split(\",\").map(p => p.trim()).filter(Boolean)\n : DEFAULT_PROFILES;\n\nif (profiles.length === 0) {\n process.stderr.write(\"CHAP_PROFILES was set but empty. Unset it to use the defaults.\\n\");\n process.exit(1);\n}\n\n/**\n * SqliteStore is loaded only when asked for. better-sqlite3 is a native\n * optional dependency, so it may be absent on a machine where the build did\n * not run. Failing loudly here beats starting in memory and silently\n * discarding the decisions the operator asked to persist.\n */\nasync function openStore(dbPath: string): Promise<Store> {\n try {\n const { SqliteStore } = await import(\"@brightbeamai/chap-coordinator/storage/sqlite\");\n return new SqliteStore(dbPath) as Store;\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n process.stderr.write(\n `CHAP_DB_PATH is set to ${dbPath} but the SQLite store could not be opened.\\n` +\n `${detail}\\n` +\n \"better-sqlite3 is an optional native dependency; reinstall with build tools\\n\" +\n \"available, or unset CHAP_DB_PATH to run in memory without persistence.\\n\",\n );\n process.exit(1);\n }\n}\n\n/**\n * Wrapped in a function rather than run at the top level: tsup emits both\n * ESM and CJS, and top-level await cannot compile to CJS.\n */\nasync function main(): Promise<void> {\n const dbPath = process.env.CHAP_DB_PATH?.trim();\n const store = dbPath ? await openStore(dbPath) : undefined;\n\n const coord = new Coordinator({ defaultProfiles: profiles, ...(store ? { store } : {}) });\n // Loads any persisted workspaces before the first request is served.\n await coord.start();\n\n const server = makeChapMcpServer(coord, { name: \"chap\", version: VERSION });\n\n // stdout carries the MCP protocol stream; anything written there corrupts it.\n process.stderr.write(`CHAP MCP server ${VERSION} on stdio.\\n`);\n process.stderr.write(`Profiles: ${profiles.join(\", \")}\\n`);\n process.stderr.write(\n dbPath\n ? `Persisting to ${dbPath}\\n`\n : \"In memory. Set CHAP_DB_PATH to keep workspaces across restarts.\\n\",\n );\n\n await server.connect(new StdioServerTransport());\n}\n\nmain().catch((err: unknown) => {\n process.stderr.write(`CHAP MCP server failed to start: ${\n err instanceof Error ? (err.stack ?? err.message) : String(err)}\\n`);\n process.exit(1);\n});\n","/**\n * @brightbeamai/chap-coordinator-mcp\n *\n * MCP server adapter for a CHAP Coordinator. Wraps a Coordinator\n * instance and exposes every CHAP method as an MCP tool.\n *\n * Spec target: MCP 2026-07-28 (current), serving MCP 2025-11-25\n * clients as well. CHAP 0.3.\n *\n * Usage (stdio):\n *\n * import { Coordinator } from \"@brightbeamai/chap-coordinator\";\n * import { makeChapMcpServer } from \"@brightbeamai/chap-coordinator-mcp\";\n * import { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\n *\n * const coord = new Coordinator({ ... });\n * const server = makeChapMcpServer(coord, { name: \"chap\", version: \"0.3.3\" });\n * await server.connect(new StdioServerTransport());\n *\n * Usage (Streamable HTTP): see reference/mcp-server-ts/server.ts.\n *\n * Architecture notes:\n *\n * - One Coordinator -> one MCP server. Multi-workspace is handled\n * inside the Coordinator (workspaces are addressable by id).\n *\n * - The adapter holds no state. Every tool call translates to a\n * JSON-RPC envelope and dispatches through coord.dispatch().\n *\n * - Tool naming follows \"chap.<method>\" so the prefix avoids\n * collisions with other MCP servers a client might load.\n *\n * - Tool inputs are described by JSON Schemas (not Zod) and are\n * passed through to the Coordinator without re-validating at the\n * MCP layer. The Coordinator's own dispatch validates params and\n * returns spec-correct JSON-RPC error codes, which we surface as\n * MCP tool errors. This keeps the schema definitions single-sourced.\n *\n * - Authentication is intentionally out of scope at this layer.\n * Apply OAuth 2.1 / Streamable HTTP auth at the transport layer\n * per MCP's auth model.\n */\n\nimport { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n ErrorCode,\n type CallToolResult,\n type Tool,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { z } from \"zod\";\nimport type { Coordinator, Envelope } from \"@brightbeamai/chap-coordinator\";\n\nimport { SCHEMAS, TOOL_NAMES, methodForTool, coerceToolArgs } from \"./schemas.js\";\nimport { TOOL_DESCRIPTIONS, TOOL_ANNOTATIONS } from \"./tools.js\";\nimport { classifyEnvelope, ProtocolError, SUPPORTED_PROTOCOL_VERSIONS, type ProtocolEra } from \"./envelope.js\";\n\nexport { SCHEMAS, TOOL_NAMES, schemaFor, methodForTool, coerceToolArgs } from \"./schemas.js\";\nexport { TOOL_DESCRIPTIONS, TOOL_ANNOTATIONS } from \"./tools.js\";\nexport type { ToolAnnotations } from \"./tools.js\";\nexport type { JsonSchema } from \"./schemas.js\";\n\nexport {\n ProtocolError,\n MODERN_PROTOCOL_VERSIONS,\n SUPPORTED_PROTOCOL_VERSIONS,\n UNSUPPORTED_PROTOCOL_VERSION,\n META_PROTOCOL_VERSION,\n META_CLIENT_INFO,\n META_CLIENT_CAPABILITIES,\n classifyEnvelope,\n} from \"./envelope.js\";\nexport type { ProtocolEra } from \"./envelope.js\";\n\n/** `_meta` key carrying server identity (MCP 2026-07-28, SEP-2575). */\nexport const META_SERVER_INFO = \"io.modelcontextprotocol/serverInfo\";\n\n/** Freshness hint for cacheable list results. The CHAP tool surface is\n * fixed at construction, so a long TTL is safe. */\nconst LIST_TTL_MS = 3_600_000;\n\n/**\n * Request schema for `server/discover` (MCP 2026-07-28, SEP-2575).\n *\n * Hand-written because the pinned SDK major predates the 2026 era. The\n * shape is permissive on `params` so a probe carrying `_meta`\n * (protocolVersion, clientInfo, clientCapabilities) validates, and a\n * bare probe with no params validates too.\n */\nexport const ServerDiscoverRequestSchema = z.object({\n method: z.literal(\"server/discover\"),\n params: z.optional(z.object({ _meta: z.optional(z.record(z.string(), z.unknown())) }).loose()),\n});\n\nexport interface ChapMcpOptions {\n /** Server name advertised to MCP clients. Default: \"chap\". */\n name?: string;\n /** Server version. Default: \"0.3.3\". */\n version?: string;\n /** Override the list of CHAP methods to expose. Default: all 39. */\n toolFilter?: (toolName: string) => boolean;\n /** Optional id generator for the envelopes emitted by tool calls. */\n envelopeIdFactory?: () => string | number;\n}\n\n/**\n * Wrap a CHAP Coordinator as an MCP server. The returned ``Server``\n * has ``tools/list`` and ``tools/call`` handlers registered for every\n * CHAP method; pass it to a transport (stdio, Streamable HTTP) to\n * start serving.\n */\nexport function makeChapMcpServer(coord: Coordinator, options: ChapMcpOptions = {}): Server {\n const serverInfo = {\n name: options.name ?? \"chap\",\n version: options.version ?? \"0.3.3\",\n };\n\n const server = new Server(\n serverInfo,\n {\n capabilities: {\n tools: {},\n },\n },\n );\n\n let counter = 0;\n const nextId = options.envelopeIdFactory ?? (() => `mcp-${++counter}`);\n const filter = options.toolFilter ?? (() => true);\n\n const enabledTools: Tool[] = TOOL_NAMES\n .filter((name) => filter(name) && methodForTool(name) !== null)\n .map((name) => {\n const ann = TOOL_ANNOTATIONS[name];\n return {\n name,\n // The title was the tool name, which told a reader nothing they could\n // not already see. The annotation carries a readable one.\n title: ann?.title ?? name,\n description: TOOL_DESCRIPTIONS[name] ?? `CHAP method ${methodForTool(name)}.`,\n inputSchema: SCHEMAS[name] as Tool[\"inputSchema\"],\n // Behavioural hints. Without these a client has only the prose to go\n // on when deciding whether a call is safe to make or to retry.\n ...(ann ? { annotations: ann } : {}),\n };\n });\n\n server.setRequestHandler(ListToolsRequestSchema, async (request) => {\n // Rejects a malformed or unsupported envelope before any work is done.\n const era = classifyEnvelope(request.params);\n if (era === \"legacy\") return { tools: enabledTools };\n\n // 2026-07-28 requires every result to be typed, and makes list results\n // cacheable. These fields are 2026 vocabulary, so they are emitted only\n // to a caller that asked in 2026 terms; a handshake-era session gets the\n // result shape its own revision defines.\n return {\n tools: enabledTools,\n resultType: \"complete\",\n ttlMs: LIST_TTL_MS,\n cacheScope: \"public\",\n _meta: { [META_SERVER_INFO]: serverInfo },\n };\n });\n\n // server/discover (MCP 2026-07-28, SEP-2575). Servers MUST implement it;\n // clients MAY call it for up-front version selection, and on stdio a\n // client that supports both eras SHOULD probe with it first. Answering\n // the probe is what keeps this server usable by 2026-era clients: a\n // server that stays silent is only reachable through timeout-based\n // fallback to the legacy initialize handshake.\n //\n // Registered against a hand-written schema because the pinned SDK\n // (1.x) predates the 2026 era and does not export one yet. When the\n // SDK ships its own ServerDiscover types this can be swapped for them\n // without changing the wire behaviour.\n server.setRequestHandler(ServerDiscoverRequestSchema, async (request) => {\n // `server/discover` is 2026 vocabulary. A request that carries no\n // per-request envelope belongs to the handshake era, where the method\n // does not exist; answering it anyway would tell a dual-era client that\n // a legacy connection can speak 2026. Mirrors the Python SDK, which\n // returns MethodNotFound in the same situation.\n if (classifyEnvelope(request.params) === \"legacy\") {\n // `data` carries the method name, matching what the Python SDK emits,\n // so a client sees the same error either side.\n throw new ProtocolError(ErrorCode.MethodNotFound, \"Method not found\", \"server/discover\");\n }\n return {\n resultType: \"complete\",\n supportedVersions: SUPPORTED_PROTOCOL_VERSIONS,\n capabilities: { tools: {} },\n instructions:\n \"CHAP Coordinator exposed as MCP tools. Every accepted call that \" +\n \"changes state is recorded on the CHAP audit log, as is a member's \" +\n \"refused attempt at a governed action. Governed methods enforce \" +\n \"membership and review rules server-side.\",\n ttlMs: LIST_TTL_MS,\n cacheScope: \"public\",\n _meta: { [META_SERVER_INFO]: serverInfo },\n };\n });\n\n server.setRequestHandler(CallToolRequestSchema, async (request): Promise<CallToolResult> => {\n const era = classifyEnvelope(request.params);\n // `resultType` is 2026 vocabulary: emitted to a modern caller, withheld\n // from a handshake-era one whose revision does not define the field.\n const terminal = <T extends object>(result: T): T =>\n (era === \"modern\" ? { resultType: \"complete\", ...result } : result) as T;\n\n const toolName = request.params.name;\n const rawArgs = (request.params.arguments ?? {}) as Record<string, unknown>;\n const method = methodForTool(toolName);\n\n if (!method) {\n return terminal({\n isError: true,\n content: [{ type: \"text\", text: `Unknown CHAP tool: ${toolName}` }],\n });\n }\n\n // Normalise stringified-JSON arguments (a common MCP-client\n // behaviour) before they reach the protocol core. See coerceToolArgs.\n const args = coerceToolArgs(toolName, rawArgs);\n\n const envelope: Envelope = {\n jsonrpc: \"2.0\",\n id: nextId(),\n method,\n params: args,\n };\n\n let response: Envelope;\n try {\n response = coord.dispatch(envelope);\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n return terminal({\n isError: true,\n content: [{ type: \"text\", text: `CHAP dispatch threw: ${msg}` }],\n });\n }\n\n if (response.error) {\n return terminal({\n isError: true,\n content: [{\n type: \"text\",\n text: JSON.stringify({\n chap_error: response.error.code,\n message: response.error.message,\n ...(response.error.data !== undefined ? { data: response.error.data } : {}),\n }, null, 2),\n }],\n });\n }\n\n return terminal({\n content: [{\n type: \"text\",\n text: JSON.stringify(response.result, null, 2),\n }],\n });\n });\n\n return server;\n}\n\n/**\n * Lower-level helper: translate a tool call to a CHAP envelope and\n * back. Useful for tests and for embedding the adapter inside a\n * larger MCP server that registers its own additional tools.\n */\nexport function dispatchToolCall(\n coord: Coordinator,\n toolName: string,\n args: Record<string, unknown>,\n envelopeId: string | number = \"mcp-call\",\n): Envelope {\n const method = methodForTool(toolName);\n if (!method) {\n return {\n jsonrpc: \"2.0\",\n id: envelopeId,\n error: { code: -32601, message: `Unknown CHAP tool: ${toolName}` },\n };\n }\n return coord.dispatch({\n jsonrpc: \"2.0\",\n id: envelopeId,\n method,\n params: coerceToolArgs(toolName, args ?? {}),\n });\n}\n","/**\n * @brightbeamai/chap-coordinator-mcp/schemas\n *\n * JSON Schema definitions for each CHAP method, used as the\n * inputSchema for the corresponding MCP tool. Each schema describes\n * the params object that the CHAP envelope would carry; the tool\n * handler wraps the params in a JSON-RPC 2.0 envelope before dispatch.\n *\n * A description here is what an MCP client reads before deciding\n * whether and how to call the tool, so each one states what the\n * coordinator does with the parameter, and names the error code where\n * a constraint is enforced. A parameter that is recorded but not acted\n * on says so; describing an intention the code does not implement is\n * worse than saying nothing.\n *\n * Aligned with CHAP 0.3 (see profiles/*.md) and MCP 2025-11-25.\n */\n\nexport interface JsonSchema {\n type?: string;\n description?: string;\n properties?: Record<string, JsonSchema>;\n required?: string[];\n enum?: string[];\n items?: JsonSchema;\n additionalProperties?: boolean | JsonSchema;\n oneOf?: JsonSchema[];\n default?: unknown;\n /** JSON Schema `pattern`, used where a string has a fixed wire shape. */\n pattern?: string;\n}\n\n// Common reusable fragments.\nconst PARTICIPANT_URI: JsonSchema = {\n type: \"string\",\n description: \"Participant URI, e.g. 'human:alice@example.org' or 'agent:bot@local'.\",\n};\n\nconst WORKSPACE_ID: JsonSchema = {\n type: \"string\",\n description: \"Workspace identifier, e.g. 'wsp_techcorp_support'.\",\n};\n\nconst TASK_ID: JsonSchema = {\n type: \"string\",\n description: \"Task identifier returned by chap.task.create.\",\n};\n\n/**\n * SPECIFICATION.md S7: a number in a CHAP envelope must be an integer.\n * Fractional values travel as decimal strings, so that canonicalisation and\n * therefore the audit hash are identical across implementations. A JSON number\n * with a fractional part is refused at ingress with -32602, so any parameter\n * that is conceptually fractional is declared here as a string.\n */\nconst decimalStringNote = (example: string) =>\n `Written as a decimal string, e.g. \"${example}\". CHAP canonicalisation accepts integers only, so a JSON number with a fractional part is refused with -32602.`;\n\nconst ROUTING_HINTS: JsonSchema = {\n type: \"object\",\n description: \"Signals recorded on the task and read by the routing/1.0 methods: task.route, review.depth and escalate.auto. Recording a hint has no effect on its own; it is consulted only when one of those methods is called.\",\n properties: {\n criticality: {\n type: \"string\",\n enum: [\"low\", \"medium\", \"high\", \"critical\"],\n description: \"How costly a wrong answer would be. The default review-depth policy reads it: 'critical' gives a full review, and 'high' with confidence below 0.7 does the same. The default assignee policy does not read it.\",\n },\n deadline: { type: \"string\", description: \"When the work is needed by, as an ISO 8601 timestamp. Recorded on the task; the coordinator does not act on it.\" },\n risk_tier: { type: \"string\", description: \"Operator-defined risk band, e.g. 'regulated' or 'internal'. No built-in policy reads it; it is available to an operator-supplied routing policy.\" },\n max_cost_usd: { type: \"string\", description: `Budget ceiling for this task in US dollars. ${decimalStringNote(\"12.50\")} No built-in policy reads it.` },\n },\n additionalProperties: true,\n};\n\n/** Free-text justification attached to a decision and kept in the audit log. */\nconst COMMENT: JsonSchema = {\n type: \"string\",\n description: \"The reviewer's note on this decision. Recorded in the audit entry for the decision.\",\n};\n\n/** Workspace-defined labels carried on a decision. */\nconst TAGS: JsonSchema = {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Workspace-defined labels for this decision, e.g. ['tone', 'unsupported-claim']. Recorded in the audit entry. chap.audit.read does not filter on tags, so grouping by tag is done by the reader.\",\n};\n\n/** Binds a decision to the exact artefact the reviewer saw. */\nconst ARTEFACT_DIGEST: JsonSchema = {\n type: \"string\",\n pattern: \"^sha256:[0-9a-f]{64}$\",\n description: \"Optional. SHA-256 over the JCS canonicalisation of the artefact under review, in the form `sha256:<hex>`. When present it binds the decision to the exact content reviewed, and a mismatch is refused with -32074.\",\n};\n\n/** Applies to `output` and `artefact`, which are opaque JSON payloads. */\nconst STRUCTURED_PAYLOAD_NOTE =\n \"Pass a JSON object or array. A JSON-encoded string is parsed back to the structured value before dispatch, so patches in chap.decide.override apply against a real object.\";\n\n// ============================================================\n// Core\n// ============================================================\n\nexport const SCHEMAS: Record<string, JsonSchema> = {\n \"chap.workspace.create\": {\n type: \"object\",\n properties: {\n workspace: { ...WORKSPACE_ID, description: \"Workspace id to create. If omitted, one is generated.\" },\n profiles: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Profile identifiers to enable, e.g. ['core/1.0', 'review/1.0']. Recorded on the workspace. Two profiles change behaviour by being present: modes/1.0, under which a trial-mode task requires review, and audit-scitt/1.0, which turns on the hash-linked chain.\",\n },\n mode: {\n type: \"string\",\n enum: [\"shadow\", \"trial\", \"production\"],\n default: \"trial\",\n description: \"Default mode for tasks created here. Under modes/1.0 a trial-mode task has review_required set to true whatever the caller passes. 'shadow' and 'production' are recorded on the task and carry no further behaviour in this implementation.\",\n },\n mode_ceiling: {\n type: \"string\",\n enum: [\"shadow\", \"trial\", \"production\"],\n default: \"production\",\n description: \"Highest mode a task in this workspace may request. A task.create above the ceiling is refused with -32040. The ceiling can be changed afterwards with chap.control.set_mode_ceiling.\",\n },\n },\n additionalProperties: false,\n },\n\n \"chap.workspace.describe\": {\n type: \"object\",\n properties: { workspace: WORKSPACE_ID },\n required: [\"workspace\"],\n },\n\n \"chap.workspace.set_profiles\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID,\n profiles: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"The complete profile set to enable, replacing the current one. Adding audit-scitt/1.0 to a workspace that already has entries leaves those entries unchained and outside chain verification.\",\n },\n },\n required: [\"workspace\", \"profiles\"],\n },\n\n \"chap.participant.join\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID,\n from: PARTICIPANT_URI,\n type: {\n type: \"string\",\n enum: [\"human\", \"agent\", \"service\", \"group\", \"workspace\"],\n description: \"The kind of participant. Only members of type 'human' are eligible for the review that chap.task.complete opens on a task marked review_required, and a completion with no eligible human is refused with -32011.\",\n },\n role: { type: \"string\", description: \"Operator-defined role, e.g. 'reviewer' or 'drafter'. One value is read by the coordinator: 'admin' permits revoking another member's key.\" },\n display_name: { type: \"string\", description: \"Human-readable name for interfaces. Not used in authorisation.\" },\n },\n required: [\"workspace\", \"from\", \"type\"],\n },\n\n \"chap.participant.leave\": {\n type: \"object\",\n properties: { workspace: WORKSPACE_ID, from: PARTICIPANT_URI },\n required: [\"workspace\", \"from\"],\n },\n\n \"chap.task.create\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID,\n from: { ...PARTICIPANT_URI, description: \"The delegator. Must be a workspace member.\" },\n kind: { type: \"string\", description: \"Task kind, e.g. 'draft_response' or 'review'. Free text; the coordinator records it without interpreting it.\" },\n assignee: { ...PARTICIPANT_URI, description: \"Who the task is assigned to. Must be a workspace member, and must not be paused: assigning to a paused member is refused with -32063.\" },\n input: { type: \"object\", description: \"Task-specific input payload.\", additionalProperties: true },\n routing_hints: ROUTING_HINTS,\n mode: {\n type: \"string\",\n enum: [\"shadow\", \"trial\", \"production\"],\n description: \"Mode for this task, defaulting to the workspace mode. A mode above the workspace ceiling is refused with -32040.\",\n },\n review_required: {\n type: \"boolean\",\n description: \"When true, chap.task.complete opens a review instead of completing: the output becomes the artefact under review, and the task reaches 'completed' only on a reviewer decision. chap.task.update cannot complete such a task. Under modes/1.0 a trial-mode task has this set to true whatever is passed here.\",\n },\n deadline: { type: \"string\", description: \"When the task is due, as an ISO 8601 timestamp. Recorded on the task; the coordinator does not act on it.\" },\n idempotency_key: {\n type: \"string\",\n description: \"Caller-chosen key for safe retries. A second create carrying a key already seen in this workspace returns the original task and records nothing further. The workspace retains the 10,000 most recent keys.\",\n },\n },\n required: [\"workspace\", \"from\", \"kind\", \"assignee\", \"input\"],\n },\n\n \"chap.task.update\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID,\n from: PARTICIPANT_URI,\n task_id: TASK_ID,\n state: {\n type: \"string\",\n enum: [\"in_progress\", \"declined\", \"cancelled\", \"completed\"],\n description: \"The state to move the task to. Only the transitions in SPECIFICATION.md 8.1 are legal from the task's current state; others are refused with -32602. A review opens with chap.review.request, or with chap.task.complete on a task that requires one, so 'review_requested' is not a target here. A task marked review_required cannot be moved to 'completed' here: submit the output with chap.task.complete, which opens the review.\",\n },\n progress_note: { type: \"string\", description: \"Short note on what changed, kept in the task's history.\" },\n },\n required: [\"workspace\", \"from\", \"task_id\", \"state\"],\n },\n\n \"chap.task.complete\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID,\n from: PARTICIPANT_URI,\n task_id: TASK_ID,\n output: { description: `The task's output artefact. ${STRUCTURED_PAYLOAD_NOTE}` },\n confidence: { type: \"string\", description: `Self-reported confidence in the output, between 0 and 1. ${decimalStringNote(\"0.86\")}` },\n routing_hints: ROUTING_HINTS,\n },\n required: [\"workspace\", \"from\", \"task_id\"],\n },\n\n \"chap.audit.read\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID,\n range: {\n type: \"object\",\n description: \"Sequence window to return. Omit for the whole log.\",\n properties: {\n from_seq: { type: \"integer\", description: \"Start sequence number, inclusive.\" },\n to_seq: { type: \"integer\", description: \"End sequence number, exclusive.\" },\n },\n },\n filter: {\n type: \"object\",\n description: \"Narrows the entries returned. Conditions combine with AND, and are applied within the sequence window rather than before it.\",\n properties: {\n method: { type: \"string\", description: \"Return only entries for this CHAP method, e.g. 'decide.override'. Matched in full, without the 'chap.' tool-name prefix.\" },\n from: { type: \"string\", description: \"Return only entries whose actor is this participant URI.\" },\n task_id: { type: \"string\", description: \"Return only entries about this task.\" },\n outcome: {\n type: \"string\",\n enum: [\"accepted\", \"refused\"],\n description: \"Return only accepted calls, or only the refused attempts the coordinator recorded. Omit for both.\",\n },\n },\n },\n },\n required: [\"workspace\"],\n },\n\n // ============================================================\n // review/1.0\n // ============================================================\n\n \"chap.review.request\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID,\n from: PARTICIPANT_URI,\n task_id: TASK_ID,\n to: {\n oneOf: [PARTICIPANT_URI, { type: \"array\", items: PARTICIPANT_URI }],\n description: \"One or more reviewers, as a single URI string or an array of URI strings. Only a workspace member can go on to decide, so a review addressed elsewhere cannot be closed by its recipient.\",\n },\n rule: {\n type: \"string\",\n enum: [\"any_one_approves\", \"all_approve\", \"quorum:2\", \"quorum:3\"],\n default: \"any_one_approves\",\n description: \"How many of the addressed reviewers must approve before the task completes. quorum:N is accepted for any N of 1 or more. The rule is fixed once the review is open: a later request naming a different one is refused with -32014. Omitting it on a later request leaves the rule alone, which is how reviewers are added to an open review.\",\n },\n artefact: { description: `The draft being submitted for review. ${STRUCTURED_PAYLOAD_NOTE} Re-requesting with the same artefact widens the reviewer set; a different artefact on an open review is refused with -32014.` },\n deadline: { type: \"string\", description: \"When the review is needed by, as an ISO 8601 timestamp. Recorded on the review; the coordinator does not act on it.\" },\n },\n required: [\"workspace\", \"from\", \"task_id\", \"to\", \"artefact\"],\n },\n\n \"chap.decide.approve\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI, task_id: TASK_ID,\n approved_artefact_digest: ARTEFACT_DIGEST,\n comment: COMMENT,\n tags: TAGS,\n },\n required: [\"workspace\", \"from\", \"task_id\"],\n },\n\n \"chap.decide.reject\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI, task_id: TASK_ID,\n approved_artefact_digest: ARTEFACT_DIGEST,\n comment: COMMENT,\n tags: TAGS,\n request_revision: { type: \"boolean\", description: \"When true the task returns to 'in_progress' rather than 'declined', so the assignee can revise and resubmit.\" },\n },\n required: [\"workspace\", \"from\", \"task_id\"],\n },\n\n \"chap.decide.override\": {\n type: \"object\",\n properties: {\n approved_artefact_digest: ARTEFACT_DIGEST,\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI, task_id: TASK_ID,\n diff: {\n type: \"array\",\n description: \"RFC 6902 JSON Patch operations applied to the artefact under review. The patched artefact becomes the task output; a patch that does not apply is refused with -32012.\",\n items: {\n type: \"object\",\n properties: {\n op: { type: \"string\", enum: [\"add\", \"replace\", \"remove\", \"copy\", \"move\", \"test\"], description: \"The patch operation to apply.\" },\n path: { type: \"string\", description: \"JSON Pointer into the artefact, e.g. '/body' or '/items/0/severity'.\" },\n value: { description: \"The new value, for add, replace and test.\" },\n from: { type: \"string\", description: \"Source JSON Pointer, for copy and move.\" },\n },\n required: [\"op\", \"path\"],\n },\n },\n rationale: { type: \"string\", description: \"Why the correction was made. Required on every override and recorded in the audit entry, since the diff shows what changed but not why.\" },\n tags: TAGS,\n policy_refs: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Identifiers of the policies or guidelines this correction applies, e.g. ['policy:no-delivery-promises']. Recorded in the audit entry.\",\n },\n logical_id: {\n type: \"string\",\n description: \"Caller-chosen identifier for the item being decided, stable across revisions and overrides of the same underlying content. Recorded in the audit entry.\",\n },\n intent_preserved: {\n type: \"boolean\",\n description: \"True when the edit refines the decision the draft was making, false when it substitutes a different one. Recorded in the audit entry.\",\n },\n },\n required: [\"workspace\", \"from\", \"task_id\", \"diff\", \"rationale\"],\n },\n\n \"chap.abstain.declare\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI, task_id: TASK_ID,\n reason: { type: \"string\", description: \"Why this reviewer is standing aside. Recorded in the audit entry.\" },\n category: {\n type: \"string\",\n enum: [\"conflict_of_interest\", \"insufficient_context\", \"out_of_scope\", \"other\"],\n description: \"The kind of abstention. Recorded in the audit entry.\",\n },\n },\n required: [\"workspace\", \"from\", \"task_id\", \"reason\"],\n },\n\n \"chap.escalate.raise\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n original_task_id: { ...TASK_ID, description: \"The task being escalated. It moves to 'escalated' and is linked to the successor. A completed, cancelled or superseded task cannot be escalated.\" },\n new_task: {\n type: \"object\",\n description: \"The successor task to open for the escalation target.\",\n properties: {\n kind: { type: \"string\", description: \"Task kind for the successor. Defaults to the original's kind.\" },\n assignee: { ...PARTICIPANT_URI, description: \"Who the escalation goes to. Must be a workspace member who is not paused: a paused assignee is refused with -32063.\" },\n input: { type: \"object\", additionalProperties: true, description: \"Input payload for the successor. It defaults to an empty object rather than the original's input, so anything the new assignee needs has to be restated here.\" },\n mode: { type: \"string\", enum: [\"shadow\", \"trial\", \"production\"], description: \"Mode for the successor, defaulting to the original's. A mode above the workspace's current ceiling is refused with -32040, so after the ceiling is lowered a task is escalated by naming a mode within it.\" },\n },\n required: [\"assignee\"],\n },\n },\n required: [\"workspace\", \"from\", \"original_task_id\", \"new_task\"],\n },\n\n // ============================================================\n // whisper/1.0\n // ============================================================\n\n \"chap.whisper.ask\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI, task_id: TASK_ID,\n to: { type: \"array\", items: PARTICIPANT_URI, description: \"Who is being asked.\" },\n question: { type: \"string\", description: \"The question being put. A whisper is answered on its own, without the recipient opening the task.\" },\n options: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n id: { type: \"string\", description: \"Stable identifier that an answer refers to.\" },\n label: { type: \"string\", description: \"What the option says to the person answering.\" },\n },\n required: [\"id\"],\n },\n description: \"Multiple-choice options. When present, an answer must name one of these ids in answer_option; any other id is refused with -32022.\",\n },\n deadline_ms: { type: \"integer\", description: \"How long the whisper stays open, in milliseconds from now. Once it passes, the whisper lapses and default_if_lapsed is applied.\" },\n default_if_lapsed: { description: \"The value applied if the deadline passes with no answer. Required, so that a lapsed whisper still has a defined outcome.\" },\n urgency: {\n type: \"string\",\n enum: [\"low\", \"medium\", \"high\"],\n default: \"low\",\n description: \"How urgent the question is. Recorded and passed on to the client; it does not change the deadline or the lapse behaviour.\",\n },\n },\n required: [\"workspace\", \"from\", \"task_id\", \"to\", \"question\", \"deadline_ms\", \"default_if_lapsed\"],\n },\n\n \"chap.whisper.answer\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n whisper_id: { type: \"string\", description: \"Identifier returned by chap.whisper.ask. A whisper that has already been answered is refused with -32020, and one past its deadline with -32021.\" },\n answer_option: { type: \"string\", description: \"The id of the chosen option. Required when the whisper carried options.\" },\n answer: { type: \"string\", description: \"Free-text answer, for a whisper with no options.\" },\n comment: { type: \"string\", description: \"Anything else the answerer wants recorded alongside the answer.\" },\n },\n required: [\"workspace\", \"from\", \"whisper_id\"],\n },\n\n // ============================================================\n // deliberation/1.0\n // ============================================================\n\n \"chap.deliberate.open\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n to: { type: \"array\", items: PARTICIPANT_URI, description: \"The participants entitled to vote. A vote from anyone else is refused with -32030.\" },\n task_id: TASK_ID,\n rule: {\n type: \"string\",\n description: \"How the outcome is decided when the deliberation closes: any_one_approves, all_approve, quorum:N, weighted_vote:T or weighted_vote_with_veto:T. An unrecognised rule is refused at open with -32033.\",\n },\n question: { type: \"string\", description: \"What the group is deciding. State it so that a yea or a nay is unambiguous.\" },\n weights: { type: \"object\", additionalProperties: { type: \"integer\" }, description: \"Voter to weight map, read by the weighted rules. A voter with no entry counts as 1. Weights must be integers: a JSON number with a fractional part is refused with -32602.\" },\n veto: { type: \"object\", additionalProperties: { type: \"boolean\" }, description: \"Voter to can-veto map. A veto is honoured only under weighted_vote_with_veto, and only from a voter listed true here.\" },\n deadline: { type: \"string\", description: \"When voting is intended to close, as an ISO 8601 timestamp. Recorded on the deliberation; closing is done by chap.deliberate.close and the coordinator does not close on the deadline.\" },\n },\n required: [\"workspace\", \"from\", \"to\", \"rule\"],\n },\n\n \"chap.deliberate.comment\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n deliberation_id: { type: \"string\", description: \"Identifier returned by chap.deliberate.open. A closed deliberation is refused with -32032.\" },\n comment: { type: \"string\", description: \"The contribution to record. Comments are kept with the deliberation and in the audit log, so the reasoning survives the vote.\" },\n },\n required: [\"workspace\", \"from\", \"deliberation_id\", \"comment\"],\n },\n\n \"chap.deliberate.vote\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n deliberation_id: { type: \"string\", description: \"Identifier returned by chap.deliberate.open. A closed deliberation is refused with -32032, and a second vote from the same voter with -32031.\" },\n vote: { type: \"string\", enum: [\"yea\", \"nay\", \"abstain\"], description: \"This voter's position. An abstention is recorded but counts as neither a yea nor a nay, so under all_approve or quorum:N it withholds the approval those rules need.\" },\n weight: { type: \"integer\", description: \"Recorded with the vote. The tally uses the weights map given at chap.deliberate.open, not this value.\" },\n comment: { type: \"string\", description: \"Why the vote went this way. Recorded with it.\" },\n veto_invoked: { type: \"boolean\", description: \"Blocks the outcome regardless of the tally. Honoured only under weighted_vote_with_veto, and only when the voter is listed true in the veto map given at open.\" },\n },\n required: [\"workspace\", \"from\", \"deliberation_id\", \"vote\"],\n },\n\n \"chap.deliberate.close\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n deliberation_id: { type: \"string\", description: \"Identifier returned by chap.deliberate.open. Closing computes the outcome from the votes cast; closing an already closed deliberation returns the outcome unchanged.\" },\n },\n required: [\"workspace\", \"from\", \"deliberation_id\"],\n },\n\n // ============================================================\n // handoff/1.0\n // ============================================================\n\n \"chap.handoff.propose\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n to: { type: \"string\", description: \"Recipient, as a participant URI or a group URI such as 'group:support-team'. A recipient who is not a workspace member is refused with -32052.\" },\n tasks: {\n type: \"array\",\n description: \"The work being handed over, one entry per task. Every task must currently be assigned to the proposer; otherwise the proposal is refused with -32050.\",\n items: {\n type: \"object\",\n properties: {\n task_id: TASK_ID,\n title: { type: \"string\", description: \"Short label for the task.\" },\n status_summary: { type: \"string\", description: \"Where the work has reached, and what has already been tried.\" },\n next_action: { type: \"string\", description: \"What the recipient should do first.\" },\n blockers: { type: \"array\", items: { type: \"string\" }, description: \"What is preventing progress, if anything.\" },\n },\n required: [\"task_id\"],\n },\n },\n summary: { type: \"string\", description: \"Covering note for the handover as a whole, above the per-task detail.\" },\n context_links: { type: \"array\", items: { type: \"string\" }, description: \"URLs to threads, tickets or documents the recipient will need.\" },\n },\n required: [\"workspace\", \"from\", \"to\", \"tasks\"],\n },\n\n \"chap.handoff.accept\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n handoff_id: { type: \"string\", description: \"Identifier returned by chap.handoff.propose. A handoff already accepted or declined is refused with -32051.\" },\n accepted_task_ids: { type: \"array\", items: TASK_ID, description: \"Which of the proposed tasks are being accepted. If omitted, all of them are.\" },\n comment: { type: \"string\", description: \"Anything the recipient wants recorded when taking the work on.\" },\n },\n required: [\"workspace\", \"from\", \"handoff_id\"],\n },\n\n \"chap.handoff.decline\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n handoff_id: { type: \"string\", description: \"Identifier returned by chap.handoff.propose. A handoff already accepted or declined is refused with -32051.\" },\n reason: { type: \"string\", description: \"Why the handover is refused. Recorded so the proposer can route it elsewhere.\" },\n suggested_target: { ...PARTICIPANT_URI, description: \"Who should take it instead, if the decliner knows.\" },\n },\n required: [\"workspace\", \"from\", \"handoff_id\"],\n },\n\n // ============================================================\n // control/1.0\n // ============================================================\n\n \"chap.control.pause\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n scope: {\n type: \"string\",\n enum: [\"task\", \"participant\", \"workspace\"],\n default: \"task\",\n description: \"What the pause applies to. 'task' moves one task to 'paused'; a task that is completed, declined, cancelled or superseded is refused with -32061. 'participant' stops new tasks being assigned to that member and leaves their existing work running. 'workspace' refuses every method except workspace.create, workspace.describe, control.resume, audit.read, participant.join and participant.leave.\",\n },\n task_id: TASK_ID,\n participant_uri: { ...PARTICIPANT_URI, description: \"Whose work to pause, when scope is 'participant'. Must be a workspace member.\" },\n in_flight_policy: {\n type: \"string\",\n enum: [\"allow_to_complete\", \"interrupt\"],\n description: \"Recorded with the request, and echoed back when scope is 'participant'. The coordinator does not act on it: under either value, work already under way is left alone.\",\n },\n reason: { type: \"string\", description: \"Why the pause was applied. Recorded in the audit entry.\" },\n },\n required: [\"workspace\", \"from\"],\n },\n\n \"chap.control.resume\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n scope: {\n type: \"string\",\n enum: [\"task\", \"participant\", \"workspace\"],\n default: \"task\",\n description: \"What the resume applies to. 'task' returns a paused task to the state it held at the pause; a task that is not paused is refused with -32061. 'participant' allows that member to be assigned tasks again. 'workspace' returns the workspace to active.\",\n },\n task_id: TASK_ID,\n participant_uri: { ...PARTICIPANT_URI, description: \"Whose work to resume, when scope is 'participant'. Must be a workspace member.\" },\n },\n required: [\"workspace\", \"from\"],\n },\n\n \"chap.control.cancel\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n task_id: { ...TASK_ID, description: \"The task to cancel. A task that is completed, declined, cancelled or superseded is refused with -32061.\" },\n reason: { type: \"string\", description: \"Why the task was cancelled. Recorded in the audit entry.\" },\n },\n required: [\"workspace\", \"from\", \"task_id\"],\n },\n\n \"chap.control.snapshot\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n label: { type: \"string\", description: \"Name for this snapshot, recorded on the artefact. chap.control.rollback identifies a snapshot by its artefact id, not by label.\" },\n include: { type: \"array\", items: { type: \"string\" }, description: \"Which aspects of the workspace to capture. Recognised values are 'members', 'open_tasks', 'mode_ceiling', 'policy' and 'audit'. Defaults to members, open_tasks and mode_ceiling.\" },\n },\n required: [\"workspace\", \"from\"],\n },\n\n \"chap.control.rollback\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n to_snapshot_artefact_id: { type: \"string\", description: \"Artefact id returned by chap.control.snapshot. An id with no matching snapshot is refused with -32062.\" },\n what_to_restore: { type: \"array\", items: { type: \"string\" }, description: \"Which captured aspects to apply. Only 'mode_ceiling' and 'members' are restored; the others are held in the snapshot and not reapplied. Restoring members resets role and scopes on members still present, and does not re-add members who have left. Defaults to the snapshot's include list.\" },\n reason: { type: \"string\", description: \"Why the rollback was performed. The rollback is itself an audit entry; earlier entries are not rewritten.\" },\n },\n required: [\"workspace\", \"from\", \"to_snapshot_artefact_id\"],\n },\n\n \"chap.control.supersede\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n task_id: { ...TASK_ID, description: \"The task being replaced. It moves to 'superseded' and is linked to the successor rather than deleted.\" },\n successor_task: {\n type: \"object\",\n description: \"The replacement task.\",\n properties: {\n kind: { type: \"string\", description: \"Task kind for the successor. Required.\" },\n assignee: { ...PARTICIPANT_URI, description: \"Who takes the replacement on. Defaults to the superseded task's assignee, and must be a workspace member who is not paused.\" },\n input: { type: \"object\", additionalProperties: true, description: \"Input payload for the successor. Defaults to an empty object.\" },\n mode: { type: \"string\", enum: [\"shadow\", \"trial\", \"production\"], description: \"Mode for the successor, defaulting to the superseded task's. A mode above the workspace's current ceiling is refused with -32040.\" },\n review_required: { type: \"boolean\", description: \"Whether completing the successor needs a reviewer decision. A successor of a task that requires review requires it whatever is passed here, and under modes/1.0 so does a trial-mode successor.\" },\n },\n required: [\"kind\"],\n },\n reason: { type: \"string\", description: \"Why the original is being replaced. Recorded in the audit entry.\" },\n },\n required: [\"workspace\", \"from\", \"task_id\", \"successor_task\"],\n },\n\n \"chap.control.set_mode_ceiling\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n new_ceiling: {\n type: \"string\",\n enum: [\"shadow\", \"trial\", \"production\"],\n description: \"The highest mode tasks in this workspace may request from now on. Existing tasks keep the mode they were created with. Where the coordinator is configured to enforce step-up authentication this method is one of the privileged ones and a call without step-up is refused with -32402.\",\n },\n reason: { type: \"string\", description: \"Why the ceiling is being changed. Recorded in the audit entry.\" },\n },\n required: [\"workspace\", \"from\", \"new_ceiling\"],\n },\n\n // ============================================================\n // routing/1.0\n // ============================================================\n\n \"chap.task.route\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n task_id: TASK_ID,\n candidates: { type: \"array\", items: PARTICIPANT_URI, description: \"Candidate assignees. An empty list is refused with -32513. The default policy takes the first candidate that is a workspace member and is not paused, and refuses the call with -32510 when there is none. An operator-supplied routing policy may select on any basis; a choice that is not a member is refused with -32510, and one who is paused with -32063.\" },\n },\n required: [\"workspace\", \"from\", \"task_id\", \"candidates\"],\n },\n\n \"chap.review.depth\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n task_id: TASK_ID,\n artefact_routing_hints: {\n type: \"object\",\n description: \"Per-artefact signals such as confidence, model_id and cost_consumed_usd, merged over the task's routing_hints for this call. The default policy reads criticality and confidence. If the merged set is empty the call is refused with -32514. Fractional values are written as decimal strings, e.g. \\\"confidence\\\": \\\"0.86\\\".\",\n additionalProperties: true,\n },\n },\n required: [\"workspace\", \"from\", \"task_id\"],\n },\n\n \"chap.escalate.auto\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n task_id: TASK_ID,\n default_escalation_target: { ...PARTICIPANT_URI, description: \"Who to escalate to when the policy decides to escalate and names no target of its own. It must be a workspace member or a group URI; if the policy escalates with no usable target the call is refused with -32516.\" },\n },\n required: [\"workspace\", \"from\", \"task_id\"],\n },\n\n // ============================================================\n // security-signed/1.0\n // ============================================================\n\n \"chap.participant.rotate_key\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n old_kid: { type: \"string\", description: \"Key id being retired. It is given a valid_until timestamp and stays in the member's key history, so signatures made before the rotation still verify. A key id that is unknown is refused with -32071, and one already revoked with -32072.\" },\n new_jwk: { type: \"object\", additionalProperties: true, description: \"The replacement public key as a JWK. It must carry a 'kid'. Whether the request itself has to be signed with the old key is decided at dispatch, and only where the coordinator is configured to require signatures.\" },\n },\n required: [\"workspace\", \"from\", \"old_kid\", \"new_jwk\"],\n },\n\n \"chap.participant.revoke_key\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n target_uri: { ...PARTICIPANT_URI, description: \"Whose key is being revoked. Revoking another member's key requires the caller to hold the role 'admin'; otherwise the call is refused with -32011.\" },\n kid: { type: \"string\", description: \"Key id to revoke. It is marked revoked with a timestamp and a reason, and signatures presented with it are refused from then on. A key id that is unknown is refused with -32071.\" },\n reason: { type: \"string\", description: \"Why the key was revoked, e.g. 'laptop lost'. Recorded on the key and in the audit entry.\" },\n },\n required: [\"workspace\", \"from\", \"target_uri\", \"kid\"],\n },\n\n // ============================================================\n // audit-scitt/1.0\n // ============================================================\n\n \"chap.audit.submit_to_scitt\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n range: {\n type: \"object\",\n description: \"Sequence window to anchor. Omit to submit the whole chain.\",\n properties: {\n from_seq: { type: \"integer\", description: \"Start sequence number, inclusive.\" },\n to_seq: { type: \"integer\", description: \"End sequence number, exclusive.\" },\n },\n },\n issuer: { type: \"string\", description: \"Issuer identifier placed on each SCITT signed statement, naming who vouches for the chain. Defaults to 'service:coordinator'. Where no submitter is configured the statements are returned unsigned for the deployment to submit out of band.\" },\n },\n required: [\"workspace\"],\n },\n\n \"chap.audit.verify_receipt\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n receipt: { type: \"object\", additionalProperties: true, description: \"The SCITT receipt to check, as returned by the transparency service. Verification is delegated to a hook supplied by the deployment, and fails closed with -32082 where no hook is configured.\" },\n },\n required: [\"workspace\", \"receipt\"],\n },\n\n \"chap.audit.verify_chain\": {\n type: \"object\",\n properties: { workspace: WORKSPACE_ID, from: PARTICIPANT_URI },\n required: [\"workspace\"],\n },\n};\n\n/** Methods that map to MCP tools. Currently: all 39 CHAP methods. */\nexport const TOOL_NAMES = Object.keys(SCHEMAS);\n\n/** Get the JSON Schema for a tool, or null if not a known CHAP method. */\nexport function schemaFor(toolName: string): JsonSchema | null {\n return SCHEMAS[toolName] ?? null;\n}\n\n/** Map an MCP tool name back to its CHAP method name. */\nexport function methodForTool(toolName: string): string | null {\n if (!toolName.startsWith(\"chap.\")) return null;\n return toolName.slice(\"chap.\".length);\n}\n\n// ============================================================\n// Stringified-JSON coercion\n// ============================================================\n//\n// LLM MCP clients (Claude Desktop, Cursor, and others) frequently\n// serialise structured tool arguments as JSON-encoded *strings* rather\n// than as native JSON objects/arrays. For example, an `artefact` that\n// should arrive as { \"draft\": \"...\" } arrives as the string\n// \"{\\\"draft\\\": \\\"...\\\"}\", and a `to` that should be [\"human:me@local\"]\n// arrives as \"[\\\"human:me@local\\\"]\".\n//\n// The CHAP protocol core is deliberately strict: it stores artefacts\n// and applies JSON Patches against whatever it receives. A stringified\n// object therefore (a) pollutes the audit log with the wrong type and\n// (b) makes object-path patches in decide.override impossible, because\n// there is no object to traverse.\n//\n// We fix this at the adapter boundary, leaving the protocol core\n// untouched. Before an argument is wrapped in a CHAP envelope, any\n// string value whose schema admits a non-string type is JSON-parsed\n// when (and only when) it parses cleanly to a type the schema allows.\n// Plain strings that the schema accepts as strings (participant URIs,\n// task ids, rationales) are never touched, so a bare \"human:me@local\"\n// passed to a string|array `to` field is preserved as-is.\n\n/** True if the schema admits `object` as a value type. */\nfunction admitsType(schema: JsonSchema | undefined, t: \"object\" | \"array\"): boolean {\n if (!schema) return false;\n if (schema.type === t) return true;\n if (schema.oneOf) return schema.oneOf.some((s) => admitsType(s, t));\n // A field declared with neither `type` nor `oneOf` (e.g. `output`,\n // `artefact`) is an opaque payload: it admits any JSON value, so we\n // allow coercion to both object and array for it.\n if (schema.type === undefined && !schema.oneOf && !schema.enum) return true;\n return false;\n}\n\n/**\n * Coerce a single argument value against its parameter schema. Returns\n * the parsed value when the string is stringified JSON the schema\n * accepts; otherwise returns the value unchanged.\n */\nfunction coerceValue(value: unknown, schema: JsonSchema | undefined): unknown {\n if (typeof value !== \"string\") return value;\n const trimmed = value.trim();\n if (trimmed.length === 0) return value;\n const looksLikeObject = trimmed.startsWith(\"{\");\n const looksLikeArray = trimmed.startsWith(\"[\");\n if (!looksLikeObject && !looksLikeArray) return value;\n\n const wantObject = looksLikeObject && admitsType(schema, \"object\");\n const wantArray = looksLikeArray && admitsType(schema, \"array\");\n if (!wantObject && !wantArray) return value;\n\n try {\n const parsed = JSON.parse(value);\n // Only accept the parse if its type is one the schema admits. This\n // guards against, say, a string that happens to start with \"[\" but\n // is meant to be a literal string in a string-only field.\n if (Array.isArray(parsed) && admitsType(schema, \"array\")) return parsed;\n if (parsed !== null && typeof parsed === \"object\" && !Array.isArray(parsed)\n && admitsType(schema, \"object\")) return parsed;\n return value;\n } catch {\n // Not valid JSON: leave it for the coordinator to validate/reject.\n return value;\n }\n}\n\n/**\n * Normalise the arguments object for a tool call, coercing any\n * stringified-JSON values whose parameter schema admits a structured\n * type. Unknown keys (not in the schema) are passed through untouched.\n *\n * This is a pure function: it returns a new object and does not mutate\n * its input. Coordinator dispatch sees correctly-typed params, so the\n * audit log records the right shapes and decide.override patches apply\n * against real objects.\n */\nexport function coerceToolArgs(\n toolName: string,\n args: Record<string, unknown>,\n): Record<string, unknown> {\n const schema = schemaFor(toolName);\n const props = schema?.properties;\n if (!props) return args;\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(args)) {\n out[key] = coerceValue(value, props[key]);\n }\n return out;\n}\n","/**\n * @brightbeamai/chap-coordinator-mcp/tools\n *\n * Tool-level descriptions and behavioural annotations for each CHAP\n * method exposed over MCP. A client shows these in its UI and reads\n * them when choosing a tool.\n *\n * A description says what the method does, how it differs from its\n * nearest sibling, and the consequence a caller most needs to know\n * before calling. It does not restate the parameter schema: every\n * parameter is already described in schemas.ts, and repeating that\n * here costs length and adds no meaning.\n *\n * The annotations carry what prose states poorly.\n *\n * `readOnlyHint` is not a judgement. It is exactly the coordinator's\n * own READ_ONLY_METHODS set, the list that decides whether an envelope\n * is recorded on the audit chain, and a test holds the two together.\n * Anything absent from that set appends an entry, which is a change of\n * state whatever else it does.\n *\n * `idempotentHint` was derived by calling each method twice with\n * identical arguments and comparing workspace state, and is claimed\n * only where the second call both succeeds and leaves that state\n * untouched. Where a repeat is refused rather than absorbed, the hint\n * is absent: an agent must not read an error as a safe retry. It is\n * also absent from `task.create`, which is idempotent only when the\n * caller supplies `idempotency_key` and creates a second task when\n * they do not.\n *\n * `destructiveHint` marks the methods that overwrite or remove state\n * that was there before, or settle it somewhere it cannot come back\n * from. Most of CHAP is additive and carries `false`.\n */\n\nexport const TOOL_DESCRIPTIONS: Record<string, string> = {\n // Core\n \"chap.workspace.create\":\n \"Create a workspace: the container for the participants, tasks and audit log of one piece of \" +\n \"collaborative work. Returns the workspace id, which every later call carries.\",\n\n \"chap.workspace.describe\":\n \"Report the current state of a workspace: its members, enabled profiles, audit length, and task and \" +\n \"override counts.\",\n\n \"chap.workspace.set_profiles\":\n \"Replace the whole set of profiles enabled on a workspace. The list is not merged: any profile absent \" +\n \"from it is dropped, so send the complete set you want. Enabling audit-scitt/1.0 on a workspace that \" +\n \"already has entries starts the chain from that point and leaves the earlier entries permanently outside \" +\n \"it, which chap.audit.verify_chain then reports as not_evaluated. Prefer setting profiles at \" +\n \"chap.workspace.create, where no entries exist yet to strand.\",\n\n \"chap.participant.join\":\n \"Add a participant to a workspace. The type given, human, agent, service, group or workspace, decides \" +\n \"whether they are eligible to review work that requires it.\",\n\n \"chap.participant.leave\":\n \"Remove a participant from a workspace. Entries they have already written stay in the audit log and their \" +\n \"past signatures still verify, so leaving is not a way to withdraw a decision. They can no longer be \" +\n \"assigned tasks or act as a reviewer, and returning means a fresh chap.participant.join.\",\n\n \"chap.task.create\":\n \"Create a task: a unit of work assigned to one participant. Set review_required to make completion depend \" +\n \"on a reviewer decision rather than on the assignee. Returns a task_id that the rest of the lifecycle \" +\n \"takes. Supplying idempotency_key is what makes a retry safe: a repeat carrying a key already seen \" +\n \"returns the original task, while a repeat without one creates a second task. Assigning to a paused \" +\n \"member is refused.\",\n\n \"chap.task.update\":\n \"Move a task to a new state. Only the transitions in the specification's lifecycle table are accepted, \" +\n \"and a task that requires review cannot be completed here.\",\n\n \"chap.task.complete\":\n \"Submit a task's output. A task that requires review does not complete: the output is held as the \" +\n \"artefact under review, the task moves to review_requested, and a reviewer decision completes it. Any \" +\n \"other task completes immediately.\",\n\n \"chap.audit.read\":\n \"Read entries from a workspace's audit log, optionally within a sequence range and filtered by method, \" +\n \"sender, task or outcome. This is the query surface for everything the workspace has recorded, decisions \" +\n \"and overrides included. An accepted call is under 'envelope'. A refused attempt the coordinator recorded, \" +\n \"such as a decision by someone the review was not addressed to, is under 'request' with an 'outcome' \" +\n \"giving the error code, and it did not take effect. Reads only: it records nothing, so it never appears in \" +\n \"its own output. Entries come back as recorded, without aggregation, so grouping them, by tag for \" +\n \"instance, is the reader's job.\",\n\n // review/1.0\n \"chap.review.request\":\n \"Open a review on a task and address it to one or more reviewers. They then call chap.decide.approve, \" +\n \"chap.decide.reject, chap.decide.override or chap.abstain.declare. Repeating the request with the same \" +\n \"artefact adds reviewers to the open review.\",\n\n \"chap.decide.approve\":\n \"Approve the artefact under review as it stands. Only a reviewer the review was addressed to may decide, \" +\n \"and anyone else is refused with -32011. The task completes once the review's rule is satisfied, so under \" +\n \"all_approve or quorum:N an approval may leave the review open awaiting others. Use chap.decide.override \" +\n \"instead to accept a corrected version.\",\n\n \"chap.decide.reject\":\n \"Reject the artefact under review. The task is declined, or returns to in_progress when request_revision \" +\n \"is set, which is the choice between ending the work and sending it back. Only a reviewer the review was \" +\n \"addressed to may decide. Use chap.decide.override instead to correct the artefact and accept it rather \" +\n \"than refuse it.\",\n\n \"chap.decide.override\":\n \"Correct the artefact under review with an RFC 6902 JSON Patch and accept the result. The patch, the \" +\n \"rationale and any tags are recorded together, so the audit log holds what was changed and why, rather \" +\n \"than only that the work was not accepted as written.\",\n\n \"chap.abstain.declare\":\n \"Stand aside from a review this participant cannot decide, for example on a conflict of interest or for \" +\n \"want of context. Use it in place of chap.decide.reject, which judges the work; abstaining judges nothing \" +\n \"and leaves the artefact intact. It requires an open review addressed to the caller and answers -32010 \" +\n \"otherwise. The task moves to abstained, which is not terminal: chap.escalate.raise or a fresh \" +\n \"chap.review.request can still carry it forward.\",\n\n \"chap.escalate.raise\":\n \"Hand a task upwards, where the current holder can act but should not decide alone. The original moves to \" +\n \"escalated and is linked to a new task for whoever takes it on. Use chap.handoff.propose to pass work \" +\n \"sideways without that link, and chap.control.supersede to replace a task outright. The successor starts \" +\n \"with an empty input unless one is supplied, so restate whatever the new assignee needs. A completed, \" +\n \"cancelled or superseded task cannot be escalated. The successor takes the mode new_task.mode names, or \" +\n \"else the original's, and requires review when the original did, or when it is a trial task under \" +\n \"modes/1.0. A paused assignee is refused with -32063, and a mode above the workspace's current ceiling \" +\n \"with -32040; after the ceiling is lowered, name a mode within it.\",\n\n // whisper/1.0\n \"chap.whisper.ask\":\n \"Put one question to one or more participants, with a deadline and a default. If the deadline passes \" +\n \"unanswered the default applies, so a task is never blocked waiting on a reply.\",\n\n \"chap.whisper.answer\":\n \"Answer an open whisper. Where the question carried options, the answer must name one of their ids and \" +\n \"any other value is refused with -32022. A whisper already answered is refused with -32020 and one past \" +\n \"its deadline with -32021, in which case the default supplied at chap.whisper.ask has already been \" +\n \"applied.\",\n\n // deliberation/1.0\n \"chap.deliberate.open\":\n \"Open a group decision among several participants under a stated voting rule: any_one_approves, \" +\n \"all_approve, quorum:N, weighted_vote:T or weighted_vote_with_veto:T. Use it where several people must \" +\n \"weigh in on one question; chap.review.request is the tool for judging one participant's output. Returns \" +\n \"a deliberation_id that the comment, vote and close tools all take. The participant list, rule, weights \" +\n \"and veto map are fixed at open, so the terms are settled before anyone votes. No outcome exists until \" +\n \"chap.deliberate.close computes one.\",\n\n \"chap.deliberate.comment\":\n \"Record a comment on an open deliberation, so the reasoning behind a vote survives alongside the tally. \" +\n \"Comments carry no weight in the outcome and may be added by any participant at any point before \" +\n \"chap.deliberate.close.\",\n\n \"chap.deliberate.vote\":\n \"Cast a yea, nay or abstain in an open deliberation. Each participant votes once and a second attempt \" +\n \"answers -32031, so a vote cannot be revised. An abstention is recorded but counts as neither side, which \" +\n \"under all_approve or quorum:N withholds the approval those rules need. The tally is computed later, by \" +\n \"chap.deliberate.close.\",\n\n \"chap.deliberate.close\":\n \"Close a deliberation and compute its outcome from the votes cast under its rule. Closing is final: \" +\n \"further comments and votes are refused with -32032. Calling it again on a closed deliberation returns \" +\n \"the same outcome and changes nothing, so a retry is safe. Votes never cast are simply absent from the \" +\n \"tally rather than counted as abstentions.\",\n\n // handoff/1.0\n \"chap.handoff.propose\":\n \"Propose handing one or more tasks to another participant or a group, with the context needed to pick \" +\n \"them up. Every task must currently be assigned to the proposer.\",\n\n \"chap.handoff.accept\":\n \"Accept a proposed handoff. The accepted tasks are reassigned to the accepting participant, which is the \" +\n \"point at which responsibility actually moves. Omitting accepted_task_ids accepts all of them. Accepting \" +\n \"resolves the proposal for good: a later accept or decline on the same handoff answers -32051. A paused \" +\n \"participant cannot accept and is refused with -32063.\",\n\n \"chap.handoff.decline\":\n \"Decline a proposed handoff. The tasks stay with the proposer and nothing is reassigned, which is the \" +\n \"difference from chap.handoff.accept. Declining resolves the proposal for good: a later accept or decline \" +\n \"on the same handoff answers -32051, and trying again means a fresh proposal. The reason is recorded so \" +\n \"the proposer can route the work elsewhere.\",\n\n // control/1.0\n \"chap.control.pause\":\n \"Pause work. Scoped to a task it moves that task to paused; to a participant it stops new tasks being \" +\n \"assigned to them; to the workspace it refuses every method except describing, reading the audit log, \" +\n \"joining, leaving and resuming.\",\n\n \"chap.control.resume\":\n \"Resume work paused at the same scope: a task returns to the state it held at the pause, a participant \" +\n \"can be assigned tasks again, a workspace returns to active.\",\n\n \"chap.control.cancel\":\n \"Cancel a task. Cancelled is terminal, and a task that has already settled cannot be cancelled.\",\n\n \"chap.control.snapshot\":\n \"Capture the workspace state as an artefact before a change you may want to undo. Returns a snapshot \" +\n \"artefact id, which is the only thing chap.control.rollback accepts as a target; the label is for a human \" +\n \"reading the log and cannot be used to select it. Taking a snapshot changes nothing. Note that a rollback \" +\n \"restores only the mode ceiling and member roles, so a snapshot is a narrow safety net rather than a \" +\n \"general undo.\",\n\n \"chap.control.rollback\":\n \"Restore workspace state from a snapshot. The mode ceiling and member roles are restored; the rollback is \" +\n \"appended to the audit log rather than rewriting it.\",\n\n \"chap.control.supersede\":\n \"Replace a task with a successor in one call. The original moves to superseded and stays linked to its \" +\n \"replacement. The successor requires review when the original did, whatever its own review_required \" +\n \"says, and a paused assignee is refused with -32063.\",\n\n \"chap.control.set_mode_ceiling\":\n \"Set the highest operating mode tasks in this workspace may request. A task above the ceiling is refused.\",\n\n // routing/1.0\n \"chap.task.route\":\n \"Choose an assignee for a task from a list of candidates and reassign the task to the one selected. Use \" +\n \"it where the choice itself belongs on the record: it writes a route_decision artefact naming the policy, \" +\n \"the candidate chosen and the alternatives passed over, none of which is captured by setting assignee \" +\n \"directly on chap.task.create. The default policy takes the first candidate that is a workspace member \" +\n \"and is not paused. An operator-supplied policy may choose on any basis, and the call is refused with \" +\n \"-32510 when its choice is not a member, or with -32063 when its choice is paused.\",\n\n \"chap.review.depth\":\n \"Decide how much review a task warrants, skip, spot_check or full, from its routing hints. Records a \" +\n \"route_decision artefact giving the rule that produced the answer.\",\n\n \"chap.escalate.auto\":\n \"Evaluate a task's routing hints against the escalation policy and report whether it should be escalated, \" +\n \"and to whom. It decides only: a route_decision artefact is recorded but the task does not move, so act \" +\n \"on the answer with chap.escalate.raise. The default policy escalates on criticality critical, or high \" +\n \"with confidence below 0.6.\",\n\n // security-signed/1.0\n \"chap.participant.rotate_key\":\n \"Retire a participant's signing key and register its replacement. The old key stays in the key history \" +\n \"with a valid_until timestamp, so envelopes it signed still verify.\",\n\n \"chap.participant.revoke_key\":\n \"Revoke a signing key, for example after a device is lost. Signatures presented with it are refused from \" +\n \"then on. Revoking another participant's key requires the admin role.\",\n\n // audit-scitt/1.0\n \"chap.audit.submit_to_scitt\":\n \"Build COSE_Sign1-shaped statements for a range of audit entries and submit them to the configured SCITT \" +\n \"transparency service. Where none is configured the statements are returned for submission out of band.\",\n\n \"chap.audit.verify_receipt\":\n \"Check a receipt returned by an external SCITT transparency service, confirming that service logged the \" +\n \"statement. This is the external half of verification; chap.audit.verify_chain checks the local prev-hash \" +\n \"chain instead, and the two answer different questions. Verification is delegated to a hook the \" +\n \"deployment supplies and fails closed with -32082 when none is configured, so a missing verifier can \" +\n \"never read as a pass. Reads only: nothing is recorded.\",\n\n \"chap.audit.verify_chain\":\n \"Replay a workspace's prev-hash chain. Only status verified with ok true means the log was checked and is \" +\n \"intact. Status not_evaluated with ok false means part of the log was never checked, so its integrity is \" +\n \"unknown and must not be reported as verified; entries_unchecked says how much. An error means the chain \" +\n \"is broken or absent.\",\n};\n\n/** MCP tool annotations (2025-03-26 onwards). Every field is a hint. */\nexport interface ToolAnnotations {\n /** Human-readable title, shown by a client instead of the raw tool name. */\n title: string;\n /** Does not modify state. Mirrors the coordinator's own read-only set. */\n readOnlyHint: boolean;\n /** May overwrite or remove existing state, or settle it irreversibly. */\n destructiveHint: boolean;\n /** A repeat with identical arguments succeeds and changes nothing further. */\n idempotentHint: boolean;\n /** Reaches a system outside this coordinator. */\n openWorldHint: boolean;\n}\n\n/**\n * Read-only, and so never recorded on the chain. This is the coordinator's own\n * READ_ONLY_METHODS set, the list that decides whether an envelope is\n * recorded. It is repeated here rather than imported so the adapter does not\n * depend on a coordinator export at runtime, and annotations.test.ts reads\n * that source and fails if the two ever diverge.\n */\nconst READ_ONLY = new Set([\n \"chap.workspace.describe\", \"chap.audit.read\", \"chap.audit.verify_chain\", \"chap.audit.verify_receipt\",\n // Submitting reads the chain and sends it onward. It changes nothing here,\n // which is what readOnlyHint claims; openWorldHint carries the fact that it\n // reaches a service outside this coordinator.\n \"chap.audit.submit_to_scitt\",\n]);\n\n/** Overwrites, removes, or settles state irreversibly. */\nconst DESTRUCTIVE = new Set([\n \"chap.workspace.set_profiles\", // replaces the profile set; can strand entries outside the chain\n \"chap.participant.leave\", // removes a member\n \"chap.participant.revoke_key\", // invalidates a key from then on\n \"chap.control.cancel\", // cancelled is terminal\n \"chap.control.supersede\", // superseded is terminal\n \"chap.control.rollback\", // overwrites the mode ceiling and member roles\n]);\n\n/** Verified by calling twice with identical arguments and diffing workspace state. */\nconst IDEMPOTENT = new Set([\n \"chap.workspace.describe\", \"chap.audit.read\", \"chap.audit.verify_chain\", \"chap.audit.verify_receipt\",\n \"chap.participant.join\", // a re-join is additive and adds no duplicate member\n \"chap.participant.leave\", // leaving twice leaves the same absence\n \"chap.control.pause\", // pausing an already paused target changes nothing\n \"chap.control.set_mode_ceiling\", // setting the ceiling it already has changes nothing\n \"chap.deliberate.close\", // returns the same outcome, recomputing nothing\n]);\n\n/** Reaches a transparency service outside this coordinator. */\nconst OPEN_WORLD = new Set([\n \"chap.audit.submit_to_scitt\", \"chap.audit.verify_receipt\",\n]);\n\n/**\n * Human-readable titles. A client that shows a title instead of the tool\n * name should still show something a person can read at a glance.\n */\nconst TITLES: Record<string, string> = {\n \"chap.workspace.create\": \"Create workspace\",\n \"chap.workspace.describe\": \"Describe workspace\",\n \"chap.workspace.set_profiles\": \"Replace workspace profiles\",\n \"chap.participant.join\": \"Add participant\",\n \"chap.participant.leave\": \"Remove participant\",\n \"chap.task.create\": \"Create task\",\n \"chap.task.update\": \"Change task state\",\n \"chap.task.complete\": \"Submit task output\",\n \"chap.audit.read\": \"Read audit log\",\n \"chap.review.request\": \"Request review\",\n \"chap.decide.approve\": \"Approve\",\n \"chap.decide.reject\": \"Reject\",\n \"chap.decide.override\": \"Override with a correction\",\n \"chap.abstain.declare\": \"Abstain from review\",\n \"chap.escalate.raise\": \"Escalate task\",\n \"chap.whisper.ask\": \"Ask a whisper\",\n \"chap.whisper.answer\": \"Answer a whisper\",\n \"chap.deliberate.open\": \"Open deliberation\",\n \"chap.deliberate.comment\": \"Comment on deliberation\",\n \"chap.deliberate.vote\": \"Vote in deliberation\",\n \"chap.deliberate.close\": \"Close deliberation\",\n \"chap.handoff.propose\": \"Propose handoff\",\n \"chap.handoff.accept\": \"Accept handoff\",\n \"chap.handoff.decline\": \"Decline handoff\",\n \"chap.control.pause\": \"Pause work\",\n \"chap.control.resume\": \"Resume work\",\n \"chap.control.cancel\": \"Cancel task\",\n \"chap.control.snapshot\": \"Snapshot workspace\",\n \"chap.control.rollback\": \"Roll back to snapshot\",\n \"chap.control.supersede\": \"Supersede task\",\n \"chap.control.set_mode_ceiling\": \"Set mode ceiling\",\n \"chap.task.route\": \"Route task to an assignee\",\n \"chap.review.depth\": \"Decide review depth\",\n \"chap.escalate.auto\": \"Evaluate auto-escalation\",\n \"chap.participant.rotate_key\": \"Rotate signing key\",\n \"chap.participant.revoke_key\": \"Revoke signing key\",\n \"chap.audit.submit_to_scitt\": \"Anchor audit log in SCITT\",\n \"chap.audit.verify_receipt\": \"Verify SCITT receipt\",\n \"chap.audit.verify_chain\": \"Verify audit chain\",\n};\n\n/** Annotations for every tool, derived from the sets above. */\nexport const TOOL_ANNOTATIONS: Record<string, ToolAnnotations> = Object.fromEntries(\n Object.keys(TOOL_DESCRIPTIONS).map((name) => [name, {\n title: TITLES[name] ?? name,\n readOnlyHint: READ_ONLY.has(name),\n // Meaningful only when readOnlyHint is false, per the specification.\n destructiveHint: DESTRUCTIVE.has(name),\n idempotentHint: IDEMPOTENT.has(name),\n openWorldHint: OPEN_WORLD.has(name),\n }]),\n);\n","/**\n * Per-request protocol envelope (MCP 2026-07-28).\n *\n * The 2026 revision is stateless: instead of negotiating once through an\n * `initialize` handshake, every request declares its protocol version and\n * client capabilities in `_meta`, and the server accepts or rejects each\n * request on its own. This module implements that classification so the\n * TypeScript adapter behaves the same way the Python `mcp` 2.x SDK does,\n * which enforces the same rules natively.\n *\n * Two version sets, deliberately different:\n *\n * - `MODERN_PROTOCOL_VERSIONS` is what may be declared per request. Only\n * revisions that use per-request metadata qualify, so `2025-11-25` is\n * not a legal per-request declaration: it is negotiated by handshake.\n * This is the set named in an `UnsupportedProtocolVersionError`, so a\n * client retrying from that list always retries with something usable.\n *\n * - `SUPPORTED_PROTOCOL_VERSIONS` is what `server/discover` advertises. It\n * spans both eras because CHAP serves both: a modern client uses\n * `2026-07-28` per request, a handshake-era client negotiates\n * `2025-11-25` through `initialize`.\n */\n\nimport { ErrorCode } from \"@modelcontextprotocol/sdk/types.js\";\n\n/**\n * A JSON-RPC error carrying a spec-exact `message`.\n *\n * The SDK's own `McpError` rewrites the message to `MCP error <code>: <text>`\n * and the protocol layer puts that rewritten string on the wire, which would\n * make CHAP answer `MCP error -32022: Unsupported protocol version` where the\n * specification, and the Python implementation, both say `Unsupported\n * protocol version`. The protocol layer reads `code`, `message` and `data`\n * off whatever is thrown, so a plain `Error` carrying those fields\n * serialises exactly as written.\n */\nexport class ProtocolError extends Error {\n readonly code: number;\n readonly data?: unknown;\n\n constructor(code: number, message: string, data?: unknown) {\n super(message);\n this.name = \"ProtocolError\";\n this.code = code;\n if (data !== undefined) this.data = data;\n }\n}\n\n/** `_meta` key carrying the protocol version of a single request. */\nexport const META_PROTOCOL_VERSION = \"io.modelcontextprotocol/protocolVersion\";\n/** `_meta` key carrying client identity. Optional per the specification. */\nexport const META_CLIENT_INFO = \"io.modelcontextprotocol/clientInfo\";\n/** `_meta` key carrying client capabilities. Required on a modern request. */\nexport const META_CLIENT_CAPABILITIES = \"io.modelcontextprotocol/clientCapabilities\";\n\n/**\n * `UnsupportedProtocolVersionError`. The specification reserves -32020 to\n * -32099 for its own codes; -32022 is the one it assigns to a version the\n * server does not implement.\n */\nexport const UNSUPPORTED_PROTOCOL_VERSION = -32022;\n\n/** Revisions that may be declared in a per-request `_meta` envelope. */\nexport const MODERN_PROTOCOL_VERSIONS = [\"2026-07-28\"] as const;\n\n/**\n * Revisions advertised by `server/discover`, newest first. The tool surface\n * is identical across both: CHAP exposes plain tools with JSON Schema\n * inputs, which the 2026-07-28 stateless core carries unchanged.\n */\nexport const SUPPORTED_PROTOCOL_VERSIONS = [\"2026-07-28\", \"2025-11-25\"] as const;\n\n/**\n * Which era a single request belongs to. `modern` means it carried a valid\n * per-request envelope; `legacy` means it carried no protocol version at\n * all and therefore belongs to a handshake-negotiated session.\n */\nexport type ProtocolEra = \"modern\" | \"legacy\";\n\n/**\n * Classify one request by its `_meta` envelope, rejecting a malformed or\n * unsupported one.\n *\n * The rejection ladder matches the Python SDK's, rung for rung, so the two\n * implementations answer an identical probe identically:\n *\n * 1. no `_meta`, or no protocol version in it, is a handshake-era request\n * 2. a declared version with no `clientCapabilities` is malformed: -32602\n * 3. a non-string version is malformed: -32602\n * 4. a version outside `MODERN_PROTOCOL_VERSIONS`: -32022\n *\n * @throws ProtocolError on a malformed or unsupported envelope.\n */\nexport function classifyEnvelope(params: unknown): ProtocolEra {\n const meta = readMeta(params);\n if (meta === null) return \"legacy\";\n\n if (!(META_PROTOCOL_VERSION in meta)) return \"legacy\";\n const declared = meta[META_PROTOCOL_VERSION];\n if (declared === undefined || declared === null) return \"legacy\";\n\n // A declared version makes this a modern request, so the rest of the\n // required envelope must be present. The specification marks\n // clientCapabilities required and clientInfo optional, and requires a\n // missing required field to be rejected as invalid params.\n if (!(META_CLIENT_CAPABILITIES in meta)) {\n throw new ProtocolError(\n ErrorCode.InvalidParams,\n `params._meta is missing the required envelope key(s): ${META_CLIENT_CAPABILITIES}`,\n );\n }\n\n if (typeof declared !== \"string\") {\n throw new ProtocolError(\n ErrorCode.InvalidParams,\n \"the protocol-version envelope value must be a string\",\n );\n }\n\n if (!(MODERN_PROTOCOL_VERSIONS as readonly string[]).includes(declared)) {\n throw new ProtocolError(UNSUPPORTED_PROTOCOL_VERSION, \"Unsupported protocol version\", {\n supported: [...MODERN_PROTOCOL_VERSIONS],\n requested: declared,\n });\n }\n\n return \"modern\";\n}\n\n/** Read `params._meta` as a plain object, or null when it is absent. */\nfunction readMeta(params: unknown): Record<string, unknown> | null {\n if (typeof params !== \"object\" || params === null) return null;\n const meta = (params as Record<string, unknown>)._meta;\n if (typeof meta !== \"object\" || meta === null || Array.isArray(meta)) return null;\n return meta as Record<string, unknown>;\n}\n"],"mappings":"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","names":["ErrorCode","ErrorCode"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/index.ts","../src/schemas.ts","../src/tools.ts","../src/envelope.ts","../src/remote.ts","../src/http.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * CHAP MCP server (stdio).\n *\n * Serves CHAP to one MCP client as one participant: every call is made as\n * that member, by default the agent `agent:assistant`, as the mcp-gate\n * template names its agent, with the tools an agent's own work needs. A\n * person decides in a desk, so this server never acts as a `human:`\n * participant.\n *\n * npx @brightbeamai/chap-coordinator-mcp --url http://127.0.0.1:8792/chap --as agent:assistant\n *\n * With --url it forwards every call to a running CHAP server's JSON-RPC\n * endpoint, such as a desk server's POST /chap, so the assistant's work\n * waits for the person at that desk. Without it, it runs its own\n * coordinator, in memory or on a SQLite file.\n *\n * Client configuration (Claude Desktop, Claude Code, Cursor, and similar):\n *\n * { \"mcpServers\": { \"chap\": {\n * \"command\": \"npx\",\n * \"args\": [\"-y\", \"@brightbeamai/chap-coordinator-mcp\",\n * \"--url\", \"http://127.0.0.1:8792/chap\", \"--as\", \"agent:assistant\"] } } }\n *\n * The options are in USAGE below. CHAP_PARTICIPANT, CHAP_DB_PATH and\n * CHAP_PROFILES stand in for --as, --db and --profiles; an empty one counts\n * as unset.\n *\n * To embed the server in your own process instead, import makeChapMcpServer\n * from this package and pass it a Coordinator you built yourself.\n *\n * Spec target: MCP 2026-07-28, serving 2025-11-25 clients as well.\n */\nimport { mkdirSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, resolve } from \"node:path\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { Coordinator } from \"@brightbeamai/chap-coordinator\";\nimport type { Store } from \"@brightbeamai/chap-coordinator\";\nimport { makeChapMcpServer, AGENT_MCP_TOOLS, type ChapDispatcher } from \"./index.js\";\nimport { remoteDispatcher } from \"./remote.js\";\n\nconst VERSION = \"0.3.5\";\n\n/**\n * Chaining is on by default because it costs almost nothing and the\n * alternative is worse: a workspace that adds audit-scitt/1.0 later can\n * never chain-verify the entries written before it, so verify_chain reports\n * not_evaluated for the rest of that workspace's life. Starting chained\n * avoids the gap entirely.\n */\nconst DEFAULT_PROFILES = [\n \"core/1.0\",\n \"review/1.0\",\n \"whisper/1.0\",\n \"deliberation/1.0\",\n \"handoff/1.0\",\n \"control/1.0\",\n \"routing/1.0\",\n \"modes/1.0\",\n \"audit-scitt/1.0\",\n];\n\nconst DEFAULT_PARTICIPANT = \"agent:assistant\";\n\nconst USAGE = `Usage: chap-mcp-server [options]\n\nServes CHAP to one MCP client on stdio, making every call as one participant.\n\nOptions:\n --as <uri> the participant every call is made as (CHAP_PARTICIPANT,\n default ${DEFAULT_PARTICIPANT}). A human: URI is refused:\n a person decides in a desk, never through the assistant\n --tools agent|all agent, the default: the tools an agent's own work needs,\n listed below; all: every CHAP method\n --url <endpoint> forward every call to a running CHAP server's JSON-RPC\n endpoint, such as http://127.0.0.1:8792/chap, which\n keeps the workspaces\n --db <path> keep the workspaces in this SQLite file (CHAP_DB_PATH);\n a leading ~ is the home directory. Without --db or\n --url, state is in memory only\n --profiles <list> comma-separated profiles for new workspaces\n (CHAP_PROFILES, default those listed below)\n --help print this and exit\n\nThe agent tools:\n${[...AGENT_MCP_TOOLS].sort().map((name) => ` ${name}`).join(\"\\n\")}\n\nThe default profiles:\n${DEFAULT_PROFILES.map((profile) => ` ${profile}`).join(\"\\n\")}\n`;\n\n/** A participant URI: a scheme, a colon, then printable characters with no quote, backslash or space. */\nconst URI_RE = /^[a-z][a-z0-9+.-]*:[\\x21\\x23-\\x5b\\x5d-\\x7e]+$/;\n\nclass UsageError extends Error {}\n\ninterface Options {\n help: boolean;\n participant: string;\n tools: \"agent\" | \"all\";\n url?: string;\n db?: string;\n profiles: string[];\n}\n\n/** An environment variable's value, or undefined when it is unset or blank. */\nfunction fromEnv(name: string): string | undefined {\n const value = process.env[name]?.trim();\n return value ? value : undefined;\n}\n\n/** `~` or `~/...` at the start of a path is the home directory, as a shell would read it. */\nfunction expandHome(path: string): string {\n return /^~(?=$|[\\\\/])/.test(path) ? homedir() + path.slice(1) : path;\n}\n\nfunction parseArgs(argv: string[]): Options {\n const given: Record<string, string> = {};\n let help = false;\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n if (arg === \"--help\" || arg === \"-h\") { help = true; continue; }\n const m = /^(--as|--tools|--url|--db|--profiles)(?:=(.*))?$/.exec(arg);\n if (!m) throw new UsageError(arg.startsWith(\"-\") ? `Unknown option ${arg}` : `Unexpected argument ${arg}`);\n const value = m[2] ?? argv[++i];\n if (value === undefined || value === \"\") throw new UsageError(`${m[1]} needs a value`);\n given[m[1]] = value;\n }\n\n const [participant, participantFrom] = given[\"--as\"] !== undefined\n ? [given[\"--as\"], \"--as\"]\n : fromEnv(\"CHAP_PARTICIPANT\") !== undefined ? [fromEnv(\"CHAP_PARTICIPANT\")!, \"CHAP_PARTICIPANT\"] : [DEFAULT_PARTICIPANT, \"--as\"];\n if (!URI_RE.test(participant)) {\n throw new UsageError(`${participantFrom} ${participant} is not a participant URI. Use the form agent:name@example.org.`);\n }\n if (participant.startsWith(\"human:\")) {\n throw new UsageError(\n `${participantFrom} ${participant} names a person. This server acts for an assistant, and a person ` +\n \"decides in a desk; give the assistant's own URI, such as agent:assistant.\",\n );\n }\n\n const tools = given[\"--tools\"] ?? \"agent\";\n if (tools !== \"agent\" && tools !== \"all\") throw new UsageError(`--tools takes agent or all; ${tools} is neither`);\n\n let url: string | undefined;\n if (given[\"--url\"] !== undefined) {\n let parsed: URL | undefined;\n try { parsed = new URL(given[\"--url\"]); } catch { parsed = undefined; }\n if (!parsed || (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\")) {\n throw new UsageError(`--url takes the http or https address of a CHAP JSON-RPC endpoint, such as http://127.0.0.1:8792/chap; ${given[\"--url\"]} is not one`);\n }\n url = parsed.href;\n }\n\n const [rawDb, dbFrom] = given[\"--db\"] !== undefined ? [given[\"--db\"], \"--db\"] : [fromEnv(\"CHAP_DB_PATH\"), \"CHAP_DB_PATH\"];\n const [rawProfiles, profilesFrom] = given[\"--profiles\"] !== undefined\n ? [given[\"--profiles\"], \"--profiles\"] : [fromEnv(\"CHAP_PROFILES\"), \"CHAP_PROFILES\"];\n if (url && rawDb !== undefined) {\n throw new UsageError(`--url forwards to a server that keeps its own store, so ${dbFrom} does not apply. Set one or the other.`);\n }\n if (url && rawProfiles !== undefined) {\n throw new UsageError(`--url forwards to a server that sets its own profiles, so ${profilesFrom} does not apply. Set one or the other.`);\n }\n\n let profiles = DEFAULT_PROFILES;\n if (rawProfiles !== undefined) {\n profiles = rawProfiles.split(\",\").map((p) => p.trim()).filter(Boolean);\n if (profiles.length === 0) throw new UsageError(`${profilesFrom} names no profiles. Leave it unset for the defaults.`);\n }\n\n return {\n help, participant, tools, url, profiles,\n ...(rawDb !== undefined ? { db: resolve(expandHome(rawDb)) } : {}),\n };\n}\n\n/**\n * SqliteStore is loaded only when asked for. better-sqlite3 is a native\n * optional dependency, so it may be absent on a machine where the build did\n * not run. Failing loudly here beats starting in memory and silently\n * discarding the decisions the operator asked to persist.\n */\nasync function openStore(dbPath: string): Promise<Store> {\n try {\n // SQLite creates the file, and the directory it goes in is made here.\n mkdirSync(dirname(dbPath), { recursive: true });\n const { SqliteStore } = await import(\"@brightbeamai/chap-coordinator/storage/sqlite\");\n return new SqliteStore(dbPath) as Store;\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n process.stderr.write(\n `The SQLite store at ${dbPath} could not be opened.\\n` +\n `${detail}\\n` +\n \"better-sqlite3 is an optional native dependency; reinstall with build tools\\n\" +\n \"available, or leave --db and CHAP_DB_PATH unset to run in memory without persistence.\\n\",\n );\n process.exit(1);\n }\n}\n\n/**\n * Wrapped in a function, since tsup emits both ESM and CJS, and top-level\n * await cannot compile to CJS.\n */\nasync function main(): Promise<void> {\n let options: Options;\n try {\n options = parseArgs(process.argv.slice(2));\n } catch (err) {\n if (!(err instanceof UsageError)) throw err;\n process.stderr.write(`${err.message}\\nRun chap-mcp-server --help for the options.\\n`);\n process.exit(2);\n }\n if (options.help) {\n process.stdout.write(USAGE);\n return;\n }\n\n // stdout carries the MCP protocol stream; anything written there corrupts it.\n const toolSet = options.tools === \"agent\" ? \"the agent tools\" : \"every CHAP tool\";\n process.stderr.write(`CHAP MCP server ${VERSION} on stdio, acting as ${options.participant} with ${toolSet}.\\n`);\n\n let dispatcher: ChapDispatcher;\n if (options.url) {\n dispatcher = remoteDispatcher(options.url);\n process.stderr.write(`Forwarding every call to ${options.url}, whose coordinator keeps the workspaces.\\n`);\n } else {\n const store = options.db ? await openStore(options.db) : undefined;\n const coord = new Coordinator({ defaultProfiles: options.profiles, ...(store ? { store } : {}) });\n // Loads any persisted workspaces before the first request is served.\n await coord.start();\n dispatcher = coord;\n process.stderr.write(`Profiles: ${options.profiles.join(\", \")}\\n`);\n process.stderr.write(\n options.db\n ? `Persisting to ${options.db}\\n`\n : \"State is in memory only: the workspaces are lost when this process exits. Set --db or CHAP_DB_PATH to keep them.\\n\",\n );\n if (options.tools === \"agent\" && coord.workspaces.size === 0) {\n process.stderr.write(\n \"No workspace exists yet, and the agent tools cannot create one: run once with --tools all, \" +\n \"or use --url to reach a server that has one.\\n\",\n );\n }\n }\n\n const server = makeChapMcpServer(dispatcher, {\n name: \"chap\",\n version: VERSION,\n participant: options.participant,\n ...(options.tools === \"agent\" ? { toolFilter: (name: string) => AGENT_MCP_TOOLS.has(name) } : {}),\n });\n await server.connect(new StdioServerTransport());\n}\n\nmain().catch((err: unknown) => {\n process.stderr.write(`CHAP MCP server failed to start: ${\n err instanceof Error ? (err.stack ?? err.message) : String(err)}\\n`);\n process.exit(1);\n});\n","/**\n * @brightbeamai/chap-coordinator-mcp\n *\n * MCP server adapter for a CHAP Coordinator. Wraps a Coordinator\n * instance and exposes every CHAP method as an MCP tool.\n *\n * Spec target: MCP 2026-07-28 (current), serving MCP 2025-11-25\n * clients as well. CHAP 0.3.\n *\n * Usage (stdio):\n *\n * import { Coordinator } from \"@brightbeamai/chap-coordinator\";\n * import { makeChapMcpServer } from \"@brightbeamai/chap-coordinator-mcp\";\n * import { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\n *\n * const coord = new Coordinator({ ... });\n * const server = makeChapMcpServer(coord, { name: \"chap\", version: \"0.3.5\" });\n * await server.connect(new StdioServerTransport());\n *\n * Usage (HTTP): chapMcpHttpHandler(coord, options) answers a Node `http`\n * request on an MCP endpoint, in both protocol eras, and refuses a request\n * under a foreign Host or from a foreign Origin.\n *\n * Architecture notes:\n *\n * - One Coordinator -> one MCP server. Multi-workspace is handled\n * inside the Coordinator (workspaces are addressable by id).\n *\n * - The adapter holds no state. Every tool call translates to a\n * JSON-RPC envelope and dispatches through coord.dispatch().\n *\n * - Tool naming follows \"chap.<method>\" so the prefix avoids\n * collisions with other MCP servers a client might load.\n *\n * - A server that is one participant's connection, such as an\n * agent's, takes `participant`: every call is made as that member,\n * and a call naming another `from` is refused. AGENT_MCP_TOOLS is\n * the tool set such a connection offers an agent.\n *\n * - Tool inputs are described by JSON Schemas (not Zod) and are\n * passed through to the Coordinator without re-validating at the\n * MCP layer. The Coordinator's own dispatch validates params and\n * returns spec-correct JSON-RPC error codes, which we surface as\n * MCP tool errors. This keeps the schema definitions single-sourced.\n *\n * - Authentication is intentionally out of scope at this layer.\n * Apply OAuth 2.1 / Streamable HTTP auth at the transport layer\n * per MCP's auth model.\n */\n\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n ErrorCode,\n type CallToolResult,\n type Tool,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { z } from \"zod\";\nimport type { Coordinator, Envelope } from \"@brightbeamai/chap-coordinator\";\n\nimport { SCHEMAS, TOOL_NAMES, methodForTool, coerceToolArgs, type JsonSchema } from \"./schemas.js\";\nimport { TOOL_DESCRIPTIONS, TOOL_ANNOTATIONS } from \"./tools.js\";\nimport { classifyEnvelope, ProtocolError, SUPPORTED_PROTOCOL_VERSIONS, type ProtocolEra } from \"./envelope.js\";\nimport { ChapEndpointError } from \"./remote.js\";\nimport { DEFAULT_MAX_BODY_BYTES, DEFAULT_TIMEOUT_MS, mcpHttpHandler } from \"./http.js\";\n\nexport { SCHEMAS, TOOL_NAMES, schemaFor, methodForTool, coerceToolArgs } from \"./schemas.js\";\nexport { TOOL_DESCRIPTIONS, TOOL_ANNOTATIONS, AGENT_MCP_TOOLS } from \"./tools.js\";\nexport type { ToolAnnotations } from \"./tools.js\";\nexport type { JsonSchema } from \"./schemas.js\";\n\nexport {\n ProtocolError,\n MODERN_PROTOCOL_VERSIONS,\n SUPPORTED_PROTOCOL_VERSIONS,\n UNSUPPORTED_PROTOCOL_VERSION,\n META_PROTOCOL_VERSION,\n META_CLIENT_INFO,\n META_CLIENT_CAPABILITIES,\n classifyEnvelope,\n} from \"./envelope.js\";\nexport type { ProtocolEra } from \"./envelope.js\";\n\n/** `_meta` key carrying server identity (MCP 2026-07-28, SEP-2575). */\nexport const META_SERVER_INFO = \"io.modelcontextprotocol/serverInfo\";\n\n/** Freshness hint for cacheable list results. The CHAP tool surface is\n * fixed at construction, so a long TTL is safe. */\nconst LIST_TTL_MS = 3_600_000;\n\n/**\n * Request schema for `server/discover` (MCP 2026-07-28, SEP-2575).\n *\n * Hand-written because the pinned SDK major predates the 2026 era. The\n * shape is permissive on `params` so a probe carrying `_meta`\n * (protocolVersion, clientInfo, clientCapabilities) validates, and a\n * bare probe with no params validates too.\n */\nexport const ServerDiscoverRequestSchema = z.object({\n method: z.literal(\"server/discover\"),\n // `.passthrough()` keeps unknown keys under zod 3 and zod 4 alike, and the\n // package accepts both majors. The zod 4 name for the same thing does not\n // exist in zod 3, where it stopped the package at import.\n params: z.optional(z.object({ _meta: z.optional(z.record(z.string(), z.unknown())) }).passthrough()),\n});\n\n/** JSON-RPC's internal error: a fault inside the coordinator, which refused nothing. */\nconst INTERNAL_ERROR = -32603;\n\n/** What a client is told of a fault inside the server; the detail is in the server's log. */\nconst FAILED_INSIDE = { chap_error: INTERNAL_ERROR, message: \"The CHAP call failed inside the server; its log has the detail.\" };\n\n/**\n * What the server dispatches each call through: a Coordinator, or anything\n * with the same `dispatch`, such as a client that forwards the envelope to a\n * running server. The answer may be returned or promised.\n */\nexport interface ChapDispatcher {\n dispatch(envelope: Envelope): Envelope | Promise<Envelope>;\n}\n\nexport interface ChapMcpOptions {\n /** Server name advertised to MCP clients. Default: \"chap\". */\n name?: string;\n /** Server version. Default: \"0.3.5\". */\n version?: string;\n /**\n * Restrict the CHAP methods this server offers. Default: all of them. A\n * tool the filter excludes is left out of the list and refused when called.\n */\n toolFilter?: (toolName: string) => boolean;\n /**\n * Make every call as this participant. `from` is filled in on each call,\n * and a call that names another `from` is refused. Use it where the server\n * is one participant's connection, such as an agent's, so the connection\n * cannot act in anyone else's name. The tools then list `from` as optional,\n * with this URI in its description. A `human:` URI is refused: a person\n * decides in a desk, never through a connection made for an agent.\n * Default: each call names its own `from`.\n */\n participant?: string;\n /** Optional id generator for the envelopes emitted by tool calls. */\n envelopeIdFactory?: () => string | number;\n}\n\n/**\n * Refuse a `human:` participant, as the commands refuse one: a server that\n * makes every call as one member is a connection for an agent, and a\n * person decides in a desk.\n */\nfunction refusePerson(participant: string | undefined): void {\n if (participant?.startsWith(\"human:\")) {\n throw new Error(`participant ${participant} names a person. This server acts for an agent, and a person ` +\n \"decides in a desk; give the agent's own URI, such as agent:assistant.\");\n }\n}\n\n/**\n * A tool's input schema as a server that acts as `participant` advertises\n * it. `from` is filled in, so a client need not send it, and the schema says\n * whose name the calls carry.\n */\nfunction pinnedSchema(schema: JsonSchema, participant: string): JsonSchema {\n if (!schema.properties?.from) return schema;\n return {\n ...schema,\n properties: {\n ...schema.properties,\n from: {\n type: \"string\",\n description: `This server acts as ${participant}: it fills this in, and refuses a call that names anyone else.`,\n },\n },\n required: (schema.required ?? []).filter((key) => key !== \"from\"),\n };\n}\n\n/**\n * Wrap a CHAP Coordinator as an MCP server. The returned ``Server``\n * has ``tools/list`` and ``tools/call`` handlers registered for every\n * CHAP method; pass it to a transport (stdio, Streamable HTTP) to\n * start serving.\n */\nexport function makeChapMcpServer(coord: ChapDispatcher, options: ChapMcpOptions = {}): Server {\n refusePerson(options.participant);\n const serverInfo = {\n name: options.name ?? \"chap\",\n version: options.version ?? \"0.3.5\",\n };\n\n const server = new Server(\n serverInfo,\n {\n capabilities: {\n tools: {},\n },\n },\n );\n\n let counter = 0;\n const nextId = options.envelopeIdFactory ?? (() => `mcp-${++counter}`);\n const filter = options.toolFilter ?? (() => true);\n\n const enabledTools: Tool[] = TOOL_NAMES\n .filter((name) => filter(name) && methodForTool(name) !== null)\n .map((name) => {\n const ann = TOOL_ANNOTATIONS[name];\n return {\n name,\n // The title was the tool name, which told a reader nothing they could\n // not already see. The annotation carries a readable one.\n title: ann?.title ?? name,\n description: TOOL_DESCRIPTIONS[name] ?? `CHAP method ${methodForTool(name)}.`,\n inputSchema: (options.participant === undefined\n ? SCHEMAS[name]\n : pinnedSchema(SCHEMAS[name], options.participant)) as Tool[\"inputSchema\"],\n // Behavioural hints. Without these a client has only the prose to go\n // on when deciding whether a call is safe to make or to retry.\n ...(ann ? { annotations: ann } : {}),\n };\n });\n\n server.setRequestHandler(ListToolsRequestSchema, async (request) => {\n // Rejects a malformed or unsupported envelope before any work is done.\n const era = classifyEnvelope(request.params);\n if (era === \"legacy\") return { tools: enabledTools };\n\n // 2026-07-28 requires every result to be typed, and makes list results\n // cacheable. These fields are 2026 vocabulary, so they are emitted only\n // to a caller that asked in 2026 terms; a handshake-era session gets the\n // result shape its own revision defines.\n return {\n tools: enabledTools,\n resultType: \"complete\",\n ttlMs: LIST_TTL_MS,\n cacheScope: \"public\",\n _meta: { [META_SERVER_INFO]: serverInfo },\n };\n });\n\n // server/discover (MCP 2026-07-28, SEP-2575). Servers MUST implement it;\n // clients MAY call it for up-front version selection, and on stdio a\n // client that supports both eras SHOULD probe with it first. Answering\n // the probe is what keeps this server usable by 2026-era clients: a\n // server that stays silent is only reachable through timeout-based\n // fallback to the legacy initialize handshake.\n //\n // Registered against a hand-written schema because the pinned SDK\n // (1.x) predates the 2026 era and does not export one yet. When the\n // SDK ships its own ServerDiscover types this can be swapped for them\n // without changing the wire behaviour.\n server.setRequestHandler(ServerDiscoverRequestSchema, async (request) => {\n // `server/discover` is 2026 vocabulary. A request that carries no\n // per-request envelope belongs to the handshake era, where the method\n // does not exist; answering it anyway would tell a dual-era client that\n // a legacy connection can speak 2026. Mirrors the Python SDK, which\n // returns MethodNotFound in the same situation.\n if (classifyEnvelope(request.params) === \"legacy\") {\n // `data` carries the method name, matching what the Python SDK emits,\n // so a client sees the same error either side.\n throw new ProtocolError(ErrorCode.MethodNotFound, \"Method not found\", \"server/discover\");\n }\n return {\n resultType: \"complete\",\n supportedVersions: SUPPORTED_PROTOCOL_VERSIONS,\n capabilities: { tools: {} },\n instructions:\n \"CHAP Coordinator exposed as MCP tools. Every accepted call that \" +\n \"changes state is recorded on the CHAP audit log, as is a member's \" +\n \"refused attempt at a governed action. Governed methods enforce \" +\n \"membership and review rules server-side.\",\n ttlMs: LIST_TTL_MS,\n cacheScope: \"public\",\n _meta: { [META_SERVER_INFO]: serverInfo },\n };\n });\n\n server.setRequestHandler(CallToolRequestSchema, async (request): Promise<CallToolResult> => {\n const era = classifyEnvelope(request.params);\n // `resultType` is 2026 vocabulary: emitted to a modern caller, withheld\n // from a handshake-era one whose revision does not define the field.\n const terminal = <T extends object>(result: T): T =>\n (era === \"modern\" ? { resultType: \"complete\", ...result } : result) as T;\n\n const toolName = request.params.name;\n const rawArgs = (request.params.arguments ?? {}) as Record<string, unknown>;\n\n // A name that is no CHAP tool is a protocol error, -32602, as the tools\n // page of both revisions has it. A tool this server leaves out is\n // refused below as a tool result, as any refusal is.\n if (!Object.hasOwn(SCHEMAS, toolName)) {\n throw new ProtocolError(ErrorCode.InvalidParams, `Unknown tool: ${toolName}`);\n }\n const method = methodForTool(toolName)!;\n // The filter decides what this server offers, so a tool it excludes is\n // refused here as well as left out of the list. Hidden alone, it still ran\n // for any client that called it by name.\n if (!filter(toolName)) {\n return terminal({\n isError: true,\n content: [{ type: \"text\", text: `CHAP tool not offered by this server: ${toolName}` }],\n });\n }\n\n // Normalise stringified-JSON arguments (a common MCP-client\n // behaviour) before they reach the protocol core. See coerceToolArgs.\n const args = { ...coerceToolArgs(toolName, rawArgs) };\n if (options.participant !== undefined) {\n if (args.from !== undefined && args.from !== options.participant) {\n return terminal({\n isError: true,\n content: [{\n type: \"text\",\n text: `This server acts as ${options.participant}; a call cannot name another from (${JSON.stringify(args.from)}).`,\n }],\n });\n }\n args.from = options.participant;\n }\n\n const envelope: Envelope = {\n jsonrpc: \"2.0\",\n id: nextId(),\n method,\n params: args,\n };\n\n let response: Envelope;\n try {\n response = await coord.dispatch(envelope);\n } catch (e) {\n // A forwarding dispatcher's own failures are written for the client:\n // the server could not be reached, or did not answer in JSON-RPC.\n if (e instanceof ChapEndpointError) {\n return terminal({ isError: true, content: [{ type: \"text\", text: e.message }] });\n }\n // Anything else is a fault in the server. Its message can carry a path\n // or a stack line, so it goes to the server's log, which the client never sees.\n console.error(\"CHAP dispatch failed:\", e);\n return terminal({\n isError: true,\n content: [{ type: \"text\", text: FAILED_INSIDE.message }],\n });\n }\n\n if (response.error) {\n // -32603 is a fault inside the coordinator, and its data can carry the\n // exception's text. It goes to the server's log, and the client is\n // told only that the call failed. A refusal is passed on as it came.\n const internal = response.error.code === INTERNAL_ERROR;\n if (internal) console.error(\"CHAP call failed:\", response.error);\n return terminal({\n isError: true,\n content: [{\n type: \"text\",\n text: JSON.stringify(internal ? FAILED_INSIDE : {\n chap_error: response.error.code,\n message: response.error.message,\n ...(response.error.data !== undefined ? { data: response.error.data } : {}),\n }, null, 2),\n }],\n });\n }\n\n return terminal({\n content: [{\n type: \"text\",\n text: JSON.stringify(response.result, null, 2),\n }],\n });\n });\n\n return server;\n}\n\n/**\n * Lower-level helper: translate a tool call to a CHAP envelope and\n * back. Useful for tests and for embedding the adapter inside a\n * larger MCP server that registers its own additional tools.\n */\nexport function dispatchToolCall(\n coord: Coordinator,\n toolName: string,\n args: Record<string, unknown>,\n envelopeId: string | number = \"mcp-call\",\n): Envelope {\n const method = methodForTool(toolName);\n if (!method) {\n return {\n jsonrpc: \"2.0\",\n id: envelopeId,\n error: { code: -32601, message: `Unknown CHAP tool: ${toolName}` },\n };\n }\n return coord.dispatch({\n jsonrpc: \"2.0\",\n id: envelopeId,\n method,\n params: coerceToolArgs(toolName, args ?? {}),\n });\n}\n\nexport interface ChapMcpHttpOptions extends ChapMcpOptions {\n /**\n * The largest request body read, when the caller has not read it. Default\n * 1,114,112 bytes: the coordinator's default envelope limit of 1 MiB, and\n * 64 KiB for the MCP request around it.\n */\n maxBodyBytes?: number;\n /**\n * Names the server also answers to, each as a Host header carries it:\n * `mcp.internal:8792`, or a bare name behind a proxy on the default port.\n * Its loopback names on the port it was reached on, 127.0.0.1, localhost\n * and [::1], are always allowed. A request under any other name is refused\n * with 421, so a page that rebinds its own name to the server's address\n * gets nothing.\n */\n allowedHosts?: string[];\n /**\n * Origins a browser page may call from, each as an Origin header carries\n * it, such as `http://localhost:6274`. A page served under one of the\n * server's own names is always allowed, and a client that is not a\n * browser sends no Origin. A request from any other origin is refused with\n * 403. The handler sends no CORS headers: a page on another origin needs\n * them from the server the handler is mounted in, as Express's cors\n * middleware sends them.\n */\n allowedOrigins?: string[];\n /**\n * How long a request waits for the server's answer, in milliseconds. One\n * with no answer by then is answered with an internal error, -32603: with\n * HTTP 500, or on the event stream where a handshake-era answer has begun.\n * Default 45,000.\n */\n timeoutMs?: number;\n}\n\n/** Answers one HTTP request on the MCP endpoint. Pass `parsedBody` when the server has read and parsed the body already. */\nexport type ChapMcpHttpHandler = (req: IncomingMessage, res: ServerResponse, parsedBody?: unknown) => Promise<void>;\n\n/**\n * Serve MCP over HTTP: a handler for a Node `http` request and response,\n * for an endpoint such as `/mcp`, with the version handling of the stdio\n * server. A request with no MCP-Protocol-Version header, or a handshake-era\n * one, is answered by the SDK's Streamable HTTP transport, statelessly; a\n * 2026-07-28 request is answered as that revision's single exchange, one\n * JSON-RPC request and one JSON answer. `options` are those of\n * makeChapMcpServer, so `participant` and `toolFilter` hold over HTTP as on\n * stdio.\n *\n * It answers only under the server's own names, refuses a browser request\n * from another origin, and takes POST only; `allowedHosts` and\n * `allowedOrigins` add names and origins. A request with no answer within\n * `timeoutMs` is answered with an internal error.\n *\n * const mcp = chapMcpHttpHandler(coord, { participant: \"agent:assistant\", toolFilter: (n) => AGENT_MCP_TOOLS.has(n) });\n * createServer((req, res) => (req.url === \"/mcp\" ? mcp(req, res) : notFound(res)));\n */\nexport function chapMcpHttpHandler(coord: ChapDispatcher, options: ChapMcpHttpOptions = {}): ChapMcpHttpHandler {\n const {\n maxBodyBytes = DEFAULT_MAX_BODY_BYTES,\n timeoutMs = DEFAULT_TIMEOUT_MS,\n allowedHosts = [],\n allowedOrigins = [],\n ...serverOptions\n } = options;\n refusePerson(serverOptions.participant);\n return mcpHttpHandler({\n makeServer: () => makeChapMcpServer(coord, serverOptions),\n maxBodyBytes,\n timeoutMs,\n allowedHosts: allowedHosts.map((host) => host.toLowerCase()),\n allowedOrigins: allowedOrigins.map((origin) => {\n let parsed: string | undefined;\n try { parsed = new URL(origin).origin; } catch { parsed = undefined; }\n // A URL with no host, such as \"localhost:6274\", has the opaque origin \"null\".\n if (parsed === undefined || parsed === \"null\") {\n throw new TypeError(`allowedOrigins takes origins such as http://localhost:6274; ${JSON.stringify(origin)} is not one`);\n }\n return parsed;\n }),\n });\n}\n","/**\n * @brightbeamai/chap-coordinator-mcp/schemas\n *\n * JSON Schema definitions for each CHAP method, used as the\n * inputSchema for the corresponding MCP tool. Each schema describes\n * the params object that the CHAP envelope would carry; the tool\n * handler wraps the params in a JSON-RPC 2.0 envelope before dispatch.\n *\n * A description here is what an MCP client reads before deciding\n * whether and how to call the tool, so each one states what the\n * coordinator does with the parameter, and names the error code where\n * a constraint is enforced. A parameter that is recorded but not acted\n * on says so; describing an intention the code does not implement is\n * worse than saying nothing.\n *\n * Aligned with CHAP 0.3 (see profiles/*.md) and MCP 2025-11-25.\n */\n\nexport interface JsonSchema {\n type?: string;\n description?: string;\n properties?: Record<string, JsonSchema>;\n required?: string[];\n enum?: string[];\n items?: JsonSchema;\n additionalProperties?: boolean | JsonSchema;\n oneOf?: JsonSchema[];\n default?: unknown;\n /** JSON Schema `pattern`, used where a string has a fixed wire shape. */\n pattern?: string;\n}\n\n// Common reusable fragments.\nconst PARTICIPANT_URI: JsonSchema = {\n type: \"string\",\n description: \"Participant URI, e.g. 'human:alice@example.org' or 'agent:bot@local'.\",\n};\n\nconst WORKSPACE_ID: JsonSchema = {\n type: \"string\",\n description: \"Workspace identifier, e.g. 'wsp_techcorp_support'.\",\n};\n\nconst TASK_ID: JsonSchema = {\n type: \"string\",\n description: \"Task identifier returned by chap.task.create.\",\n};\n\n/**\n * SPECIFICATION.md S7: a number in a CHAP envelope must be an integer.\n * Fractional values travel as decimal strings, so that canonicalisation and\n * therefore the audit hash are identical across implementations. A JSON number\n * with a fractional part is refused at ingress with -32602, so any parameter\n * that is conceptually fractional is declared here as a string.\n */\nconst decimalStringNote = (example: string) =>\n `Written as a decimal string, e.g. \"${example}\". CHAP canonicalisation accepts integers only, so a JSON number with a fractional part is refused with -32602.`;\n\nconst ROUTING_HINTS: JsonSchema = {\n type: \"object\",\n description: \"Signals recorded on the task and read by the routing/1.0 methods: task.route, review.depth and escalate.auto. Recording a hint has no effect on its own; it is consulted only when one of those methods is called.\",\n properties: {\n criticality: {\n type: \"string\",\n enum: [\"low\", \"medium\", \"high\", \"critical\"],\n description: \"How costly a wrong answer would be. The default review-depth policy reads it: 'critical' gives a full review, and 'high' with confidence below 0.7 does the same. The default assignee policy does not read it.\",\n },\n deadline: { type: \"string\", description: \"When the work is needed by, as an ISO 8601 timestamp. Recorded on the task; the coordinator does not act on it.\" },\n risk_tier: { type: \"string\", description: \"Operator-defined risk band, e.g. 'regulated' or 'internal'. No built-in policy reads it; it is available to an operator-supplied routing policy.\" },\n max_cost_usd: { type: \"string\", description: `Budget ceiling for this task in US dollars. ${decimalStringNote(\"12.50\")} No built-in policy reads it.` },\n },\n additionalProperties: true,\n};\n\n/** Free-text justification attached to a decision and kept in the audit log. */\nconst COMMENT: JsonSchema = {\n type: \"string\",\n description: \"The reviewer's note on this decision. Recorded in the audit entry for the decision.\",\n};\n\n/** Workspace-defined labels carried on a decision. */\nconst TAGS: JsonSchema = {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Workspace-defined labels for this decision, e.g. ['tone', 'unsupported-claim']. Recorded in the audit entry. chap.audit.read does not filter on tags, so grouping by tag is done by the reader.\",\n};\n\n/** Binds a decision to the exact artefact the reviewer saw. */\nconst ARTEFACT_DIGEST: JsonSchema = {\n type: \"string\",\n pattern: \"^sha256:[0-9a-f]{64}$\",\n description: \"Optional. SHA-256 over the JCS canonicalisation of the artefact under review, in the form `sha256:<hex>`. When present it binds the decision to the exact content reviewed, and a mismatch is refused with -32074.\",\n};\n\n/** Applies to `output` and `artefact`, which are opaque JSON payloads. */\nconst STRUCTURED_PAYLOAD_NOTE =\n \"Pass a JSON object or array. A JSON-encoded string is parsed back to the structured value before dispatch, so patches in chap.decide.override apply against a real object.\";\n\n// ============================================================\n// Core\n// ============================================================\n\nexport const SCHEMAS: Record<string, JsonSchema> = {\n \"chap.workspace.create\": {\n type: \"object\",\n properties: {\n workspace: { ...WORKSPACE_ID, description: \"Workspace id to create. If omitted, one is generated.\" },\n profiles: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Profile identifiers to enable, e.g. ['core/1.0', 'review/1.0']. Recorded on the workspace. Two profiles change behaviour by being present: modes/1.0, under which a trial-mode task requires review, and audit-scitt/1.0, which turns on the hash-linked chain.\",\n },\n mode: {\n type: \"string\",\n enum: [\"shadow\", \"trial\", \"production\"],\n default: \"trial\",\n description: \"Default mode for tasks created here. Under modes/1.0 a trial-mode task has review_required set to true whatever the caller passes. 'shadow' and 'production' are recorded on the task and carry no further behaviour in this implementation.\",\n },\n mode_ceiling: {\n type: \"string\",\n enum: [\"shadow\", \"trial\", \"production\"],\n default: \"production\",\n description: \"Highest mode a task in this workspace may request. A task.create above the ceiling is refused with -32040. The ceiling can be changed afterwards with chap.control.set_mode_ceiling.\",\n },\n join_policy: {\n type: \"string\",\n enum: [\"open\", \"invite\"],\n default: \"open\",\n description: \"Who may join. 'open' admits anyone. 'invite' admits only a participant an admin invited with chap.workspace.invite, and the workspace's first member, which becomes its admin; any other join is refused with -32011. It cannot be changed afterwards.\",\n },\n review_rule: {\n type: \"string\",\n pattern: \"^(any_one_approves|all_approve|quorum:[1-9][0-9]*)$\",\n default: \"any_one_approves\",\n description: \"The rule of every review that task.complete opens here: any_one_approves, all_approve or quorum:<n>. An author cannot open a review of their own review-required task, so this is how a workspace asks for more than one approval. It cannot be changed afterwards.\",\n },\n },\n additionalProperties: false,\n },\n\n \"chap.workspace.describe\": {\n type: \"object\",\n properties: { workspace: WORKSPACE_ID },\n required: [\"workspace\"],\n },\n\n \"chap.workspace.set_profiles\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID,\n profiles: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"The complete profile set to enable, replacing the current one. Adding audit-scitt/1.0 to a workspace that already has entries leaves those entries unchained and outside chain verification.\",\n },\n },\n required: [\"workspace\", \"profiles\"],\n },\n\n \"chap.workspace.invite\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID,\n from: { ...PARTICIPANT_URI, description: \"The admin who invites. Any other sender is refused with -32011.\" },\n uri: { ...PARTICIPANT_URI, description: \"The participant invited. Its scheme must name type, as at a join.\" },\n type: {\n type: \"string\",\n enum: [\"human\", \"agent\", \"service\"],\n description: \"The kind of participant invited, which the scheme of uri must name. The member takes this type. group: and workspace: URIs name address scopes, which cannot join, and are refused with -32602.\",\n },\n role: { type: \"string\", description: \"The role the member takes when it joins, whatever role the join names. Only an invitation grants 'admin' after the first member, and only to a human or a service.\" },\n jwks: {\n type: \"object\",\n description: \"Keys to pin, as {keys: [JWK, ...]}, each with a kid. The join's keys must be among them, and the member holds them. For a member that holds no key in force, the call registers these keys at once: the way back for a member whose keys were all revoked.\",\n },\n oidc_sub: { type: \"string\", description: \"The OIDC subject whose token admits the invitee: the join must carry an oidc_token for it. Needs a token verifier on the coordinator.\" },\n },\n required: [\"workspace\", \"from\", \"uri\", \"type\"],\n },\n\n \"chap.participant.join\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID,\n from: PARTICIPANT_URI,\n type: {\n type: \"string\",\n enum: [\"human\", \"agent\", \"service\"],\n description: \"The kind of participant, which the scheme of from must name: 'agent:' for an agent, and so on. Any other join is refused with -32602, and so is a join of a group: or workspace: URI, which names an address scope. Only members of type 'human' are eligible for the review that chap.task.complete opens on a task marked review_required, and a completion with no eligible human is refused with -32011. In a workspace that requires signatures, a participant that signs joins with a key.\",\n },\n role: { type: \"string\", description: \"Operator-defined role, e.g. 'reviewer' or 'drafter'. One value is read by the coordinator: 'admin', which changes the profiles, invites, and revokes another member's key. It is granted, never claimed: only the workspace's first member, or a participant an admin's invitation names as admin, may name it at a join, and any other join naming it is refused with -32011. Only a human or a service holds it. An invitation's role replaces the one named here.\" },\n display_name: { type: \"string\", description: \"Human-readable name for interfaces. Not used in authorisation.\" },\n },\n required: [\"workspace\", \"from\", \"type\"],\n },\n\n \"chap.participant.leave\": {\n type: \"object\",\n properties: { workspace: WORKSPACE_ID, from: PARTICIPANT_URI },\n required: [\"workspace\", \"from\"],\n },\n\n \"chap.task.create\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID,\n from: { ...PARTICIPANT_URI, description: \"The delegator. Must be a workspace member.\" },\n kind: { type: \"string\", description: \"Task kind, e.g. 'draft_response' or 'review'. Free text; the coordinator records it without interpreting it.\" },\n assignee: { ...PARTICIPANT_URI, description: \"Who the task is assigned to. Must be a workspace member, and must not be paused: assigning to a paused member is refused with -32063.\" },\n input: { type: \"object\", description: \"Task-specific input payload.\", additionalProperties: true },\n routing_hints: ROUTING_HINTS,\n mode: {\n type: \"string\",\n enum: [\"shadow\", \"trial\", \"production\"],\n description: \"Mode for this task, defaulting to the workspace mode. A mode above the workspace ceiling is refused with -32040.\",\n },\n review_required: {\n type: \"boolean\",\n description: \"When true, chap.task.complete opens a review instead of completing: the output becomes the artefact under review, and the task reaches 'completed' only on a reviewer decision. chap.task.update cannot complete such a task. Under modes/1.0 a trial-mode task has this set to true whatever is passed here.\",\n },\n deadline: { type: \"string\", description: \"When the task is due, as an ISO 8601 timestamp. Recorded on the task; the coordinator does not act on it.\" },\n idempotency_key: {\n type: \"string\",\n description: \"Caller-chosen key for safe retries. A second create carrying a key already seen in this workspace returns the original task and records nothing further. The workspace retains the 10,000 most recent keys.\",\n },\n },\n required: [\"workspace\", \"from\", \"kind\", \"assignee\", \"input\"],\n },\n\n \"chap.task.update\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID,\n from: PARTICIPANT_URI,\n task_id: TASK_ID,\n state: {\n type: \"string\",\n enum: [\"in_progress\", \"declined\", \"cancelled\", \"completed\"],\n description: \"The state to move the task to. Only the transitions in SPECIFICATION.md 8.1 are legal from the task's current state; others are refused with -32602. A review opens with chap.review.request, or with chap.task.complete on a task that requires one, so 'review_requested' is not a target here. A task marked review_required cannot be moved to 'completed' here: submit the output with chap.task.complete, which opens the review.\",\n },\n progress_note: { type: \"string\", description: \"Short note on what changed, kept in the task's history.\" },\n },\n required: [\"workspace\", \"from\", \"task_id\", \"state\"],\n },\n\n \"chap.task.complete\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID,\n from: PARTICIPANT_URI,\n task_id: TASK_ID,\n output: { description: `The task's output artefact. ${STRUCTURED_PAYLOAD_NOTE}` },\n confidence: { type: \"string\", description: `Self-reported confidence in the output, between 0 and 1. ${decimalStringNote(\"0.86\")}` },\n routing_hints: ROUTING_HINTS,\n },\n required: [\"workspace\", \"from\", \"task_id\"],\n },\n\n \"chap.audit.read\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID,\n range: {\n type: \"object\",\n description: \"Sequence window to return. Omit for the whole log.\",\n properties: {\n from_seq: { type: \"integer\", description: \"Start sequence number, inclusive.\" },\n to_seq: { type: \"integer\", description: \"End sequence number, exclusive.\" },\n },\n },\n filter: {\n type: \"object\",\n description: \"Narrows the entries returned. Conditions combine with AND, and are applied within the sequence window rather than before it.\",\n properties: {\n method: { type: \"string\", description: \"Return only entries for this CHAP method, e.g. 'decide.override'. Matched in full, without the 'chap.' tool-name prefix.\" },\n from: { type: \"string\", description: \"Return only entries whose actor is this participant URI.\" },\n task_id: { type: \"string\", description: \"Return only entries about this task.\" },\n outcome: {\n type: \"string\",\n enum: [\"accepted\", \"refused\"],\n description: \"Return only accepted calls, or only the refused attempts the coordinator recorded. Omit for both.\",\n },\n },\n },\n },\n required: [\"workspace\"],\n },\n\n // ============================================================\n // review/1.0\n // ============================================================\n\n \"chap.review.request\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID,\n from: PARTICIPANT_URI,\n task_id: TASK_ID,\n to: {\n oneOf: [PARTICIPANT_URI, { type: \"array\", items: PARTICIPANT_URI }],\n description: \"One or more reviewers, as a single URI string or an array of URI strings. Only a workspace member can go on to decide, so a review addressed elsewhere cannot be closed by its recipient.\",\n },\n rule: {\n type: \"string\",\n enum: [\"any_one_approves\", \"all_approve\", \"quorum:2\", \"quorum:3\"],\n default: \"any_one_approves\",\n description: \"How many of the addressed reviewers must approve before the task completes. quorum:N is accepted for any N of 1 or more. The rule is fixed once the review is open: a later request naming a different one is refused with -32014. Omitting it on a later request leaves the rule alone, which is how reviewers are added to an open review.\",\n },\n artefact: { description: `The draft being submitted for review. ${STRUCTURED_PAYLOAD_NOTE} Re-requesting with the same artefact widens the reviewer set; a different artefact on an open review is refused with -32014.` },\n deadline: { type: \"string\", description: \"When the review is needed by, as an ISO 8601 timestamp. Recorded on the review; the coordinator does not act on it.\" },\n },\n required: [\"workspace\", \"from\", \"task_id\", \"to\", \"artefact\"],\n },\n\n \"chap.review.acknowledge\": {\n type: \"object\",\n properties: { workspace: WORKSPACE_ID, from: PARTICIPANT_URI, task_id: TASK_ID },\n required: [\"workspace\", \"from\", \"task_id\"],\n },\n\n \"chap.decide.approve\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI, task_id: TASK_ID,\n approved_artefact_digest: ARTEFACT_DIGEST,\n comment: COMMENT,\n tags: TAGS,\n },\n required: [\"workspace\", \"from\", \"task_id\"],\n },\n\n \"chap.decide.reject\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI, task_id: TASK_ID,\n approved_artefact_digest: ARTEFACT_DIGEST,\n comment: COMMENT,\n tags: TAGS,\n request_revision: { type: \"boolean\", description: \"When true the task returns to 'in_progress' rather than 'declined', so the assignee can revise and resubmit.\" },\n },\n required: [\"workspace\", \"from\", \"task_id\"],\n },\n\n \"chap.decide.override\": {\n type: \"object\",\n properties: {\n approved_artefact_digest: ARTEFACT_DIGEST,\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI, task_id: TASK_ID,\n diff: {\n type: \"array\",\n description: \"RFC 6902 JSON Patch operations applied to the artefact under review. The patched artefact becomes the task output; a patch that does not apply is refused with -32012.\",\n items: {\n type: \"object\",\n properties: {\n op: { type: \"string\", enum: [\"add\", \"replace\", \"remove\", \"copy\", \"move\", \"test\"], description: \"The patch operation to apply.\" },\n path: { type: \"string\", description: \"JSON Pointer into the artefact, e.g. '/body' or '/items/0/severity'.\" },\n value: { description: \"The new value, for add, replace and test.\" },\n from: { type: \"string\", description: \"Source JSON Pointer, for copy and move.\" },\n },\n required: [\"op\", \"path\"],\n },\n },\n rationale: { type: \"string\", description: \"Why the correction was made. Required on every override and recorded in the audit entry, since the diff shows what changed but not why.\" },\n tags: TAGS,\n policy_refs: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Identifiers of the policies or guidelines this correction applies, e.g. ['policy:no-delivery-promises']. Recorded in the audit entry.\",\n },\n logical_id: {\n type: \"string\",\n description: \"Caller-chosen identifier for the item being decided, stable across revisions and overrides of the same underlying content. Recorded in the audit entry.\",\n },\n intent_preserved: {\n type: \"boolean\",\n description: \"True when the edit refines the decision the draft was making, false when it substitutes a different one. Recorded in the audit entry.\",\n },\n },\n required: [\"workspace\", \"from\", \"task_id\", \"diff\", \"rationale\"],\n },\n\n \"chap.abstain.declare\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI, task_id: TASK_ID,\n reason: { type: \"string\", description: \"Why this reviewer is standing aside. Recorded in the audit entry.\" },\n category: {\n type: \"string\",\n enum: [\"conflict_of_interest\", \"insufficient_context\", \"out_of_scope\", \"other\"],\n description: \"The kind of abstention. Recorded in the audit entry.\",\n },\n },\n required: [\"workspace\", \"from\", \"task_id\", \"reason\"],\n },\n\n \"chap.escalate.raise\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n original_task_id: { ...TASK_ID, description: \"The task being escalated. It moves to 'escalated' and is linked to the successor. A completed, cancelled or superseded task cannot be escalated.\" },\n new_task: {\n type: \"object\",\n description: \"The successor task to open for the escalation target.\",\n properties: {\n kind: { type: \"string\", description: \"Task kind for the successor. Defaults to the original's kind.\" },\n assignee: { ...PARTICIPANT_URI, description: \"Who the escalation goes to. Must be a workspace member who is not paused: a paused assignee is refused with -32063.\" },\n input: { type: \"object\", additionalProperties: true, description: \"Input payload for the successor. It defaults to an empty object rather than the original's input, so anything the new assignee needs has to be restated here.\" },\n mode: { type: \"string\", enum: [\"shadow\", \"trial\", \"production\"], description: \"Mode for the successor, defaulting to the original's. A mode above the workspace's current ceiling is refused with -32040, so after the ceiling is lowered a task is escalated by naming a mode within it.\" },\n },\n required: [\"assignee\"],\n },\n },\n required: [\"workspace\", \"from\", \"original_task_id\", \"new_task\"],\n },\n\n // ============================================================\n // whisper/1.0\n // ============================================================\n\n \"chap.whisper.ask\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI, task_id: TASK_ID,\n to: { type: \"array\", items: PARTICIPANT_URI, description: \"Who is being asked.\" },\n question: { type: \"string\", description: \"The question being put. A whisper is answered on its own, without the recipient opening the task.\" },\n options: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n id: { type: \"string\", description: \"Stable identifier that an answer refers to.\" },\n label: { type: \"string\", description: \"What the option says to the person answering.\" },\n },\n required: [\"id\"],\n },\n description: \"Multiple-choice options. When present, an answer must name one of these ids in answer_option; any other id is refused with -32022.\",\n },\n deadline_ms: { type: \"integer\", description: \"How long the whisper stays open, in milliseconds from now. Once it passes, the whisper lapses and default_if_lapsed is applied.\" },\n default_if_lapsed: { description: \"The value applied if the deadline passes with no answer. Required, so that a lapsed whisper still has a defined outcome.\" },\n urgency: {\n type: \"string\",\n enum: [\"low\", \"medium\", \"high\"],\n default: \"low\",\n description: \"How urgent the question is. Recorded and passed on to the client; it does not change the deadline or the lapse behaviour.\",\n },\n },\n required: [\"workspace\", \"from\", \"task_id\", \"to\", \"question\", \"deadline_ms\", \"default_if_lapsed\"],\n },\n\n \"chap.whisper.answer\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n whisper_id: { type: \"string\", description: \"Identifier returned by chap.whisper.ask. A whisper that has already been answered is refused with -32020, and one past its deadline with -32021.\" },\n answer_option: { type: \"string\", description: \"The id of the chosen option. Required when the whisper carried options.\" },\n answer: { type: \"string\", description: \"Free-text answer, for a whisper with no options.\" },\n comment: { type: \"string\", description: \"Anything else the answerer wants recorded alongside the answer.\" },\n },\n required: [\"workspace\", \"from\", \"whisper_id\"],\n },\n\n // ============================================================\n // deliberation/1.0\n // ============================================================\n\n \"chap.deliberate.open\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n to: { type: \"array\", items: PARTICIPANT_URI, description: \"The participants entitled to vote. A vote from anyone else is refused with -32030.\" },\n task_id: TASK_ID,\n rule: {\n type: \"string\",\n description: \"How the outcome is decided when the deliberation closes: any_one_approves, all_approve, quorum:N, weighted_vote:T or weighted_vote_with_veto:T. An unrecognised rule is refused at open with -32033.\",\n },\n question: { type: \"string\", description: \"What the group is deciding. State it so that a yea or a nay is unambiguous.\" },\n weights: { type: \"object\", additionalProperties: { type: \"integer\" }, description: \"Voter to weight map, read by the weighted rules. A voter with no entry counts as 1. Weights must be integers: a JSON number with a fractional part is refused with -32602.\" },\n veto: { type: \"object\", additionalProperties: { type: \"boolean\" }, description: \"Voter to can-veto map. A veto is honoured only under weighted_vote_with_veto, and only from a voter listed true here.\" },\n deadline: { type: \"string\", description: \"When voting is intended to close, as an ISO 8601 timestamp. Recorded on the deliberation; closing is done by chap.deliberate.close and the coordinator does not close on the deadline.\" },\n },\n required: [\"workspace\", \"from\", \"to\", \"rule\"],\n },\n\n \"chap.deliberate.comment\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n deliberation_id: { type: \"string\", description: \"Identifier returned by chap.deliberate.open. A closed deliberation is refused with -32032.\" },\n comment: { type: \"string\", description: \"The contribution to record. Comments are kept with the deliberation and in the audit log, so the reasoning survives the vote.\" },\n },\n required: [\"workspace\", \"from\", \"deliberation_id\", \"comment\"],\n },\n\n \"chap.deliberate.vote\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n deliberation_id: { type: \"string\", description: \"Identifier returned by chap.deliberate.open. A closed deliberation is refused with -32032, and a second vote from the same voter with -32031.\" },\n vote: { type: \"string\", enum: [\"yea\", \"nay\", \"abstain\"], description: \"This voter's position. An abstention is recorded but counts as neither a yea nor a nay, so under all_approve or quorum:N it withholds the approval those rules need.\" },\n weight: { type: \"integer\", description: \"Recorded with the vote. The tally uses the weights map given at chap.deliberate.open, not this value.\" },\n comment: { type: \"string\", description: \"Why the vote went this way. Recorded with it.\" },\n veto_invoked: { type: \"boolean\", description: \"Blocks the outcome regardless of the tally. Honoured only under weighted_vote_with_veto, and only when the voter is listed true in the veto map given at open.\" },\n },\n required: [\"workspace\", \"from\", \"deliberation_id\", \"vote\"],\n },\n\n \"chap.deliberate.close\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n deliberation_id: { type: \"string\", description: \"Identifier returned by chap.deliberate.open. Closing computes the outcome from the votes cast; closing an already closed deliberation returns the outcome unchanged.\" },\n },\n required: [\"workspace\", \"from\", \"deliberation_id\"],\n },\n\n // ============================================================\n // handoff/1.0\n // ============================================================\n\n \"chap.handoff.propose\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n to: { type: \"string\", description: \"Recipient, as a participant URI or a group URI such as 'group:support-team'. A recipient who is not a workspace member is refused with -32052.\" },\n tasks: {\n type: \"array\",\n description: \"The work being handed over, one entry per task. Every task must currently be assigned to the proposer; otherwise the proposal is refused with -32050.\",\n items: {\n type: \"object\",\n properties: {\n task_id: TASK_ID,\n title: { type: \"string\", description: \"Short label for the task.\" },\n status_summary: { type: \"string\", description: \"Where the work has reached, and what has already been tried.\" },\n next_action: { type: \"string\", description: \"What the recipient should do first.\" },\n blockers: { type: \"array\", items: { type: \"string\" }, description: \"What is preventing progress, if anything.\" },\n },\n required: [\"task_id\"],\n },\n },\n summary: { type: \"string\", description: \"Covering note for the handover as a whole, above the per-task detail.\" },\n context_links: { type: \"array\", items: { type: \"string\" }, description: \"URLs to threads, tickets or documents the recipient will need.\" },\n },\n required: [\"workspace\", \"from\", \"to\", \"tasks\"],\n },\n\n \"chap.handoff.accept\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n handoff_id: { type: \"string\", description: \"Identifier returned by chap.handoff.propose. A handoff already accepted or declined is refused with -32051.\" },\n accepted_task_ids: { type: \"array\", items: TASK_ID, description: \"Which of the proposed tasks are being accepted. If omitted, all of them are.\" },\n comment: { type: \"string\", description: \"Anything the recipient wants recorded when taking the work on.\" },\n },\n required: [\"workspace\", \"from\", \"handoff_id\"],\n },\n\n \"chap.handoff.decline\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n handoff_id: { type: \"string\", description: \"Identifier returned by chap.handoff.propose. A handoff already accepted or declined is refused with -32051.\" },\n reason: { type: \"string\", description: \"Why the handover is refused. Recorded so the proposer can route it elsewhere.\" },\n suggested_target: { ...PARTICIPANT_URI, description: \"Who should take it instead, if the decliner knows.\" },\n },\n required: [\"workspace\", \"from\", \"handoff_id\"],\n },\n\n // ============================================================\n // control/1.0\n // ============================================================\n\n \"chap.control.pause\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n scope: {\n type: \"string\",\n enum: [\"task\", \"participant\", \"workspace\"],\n default: \"task\",\n description: \"What the pause applies to. 'task' moves one task to 'paused'; a task that is completed, declined, cancelled or superseded is refused with -32061. 'participant' stops new tasks being assigned to that member and leaves their existing work running. 'workspace' refuses every method except workspace.create, workspace.describe, control.resume, audit.read, participant.join and participant.leave.\",\n },\n task_id: TASK_ID,\n participant_uri: { ...PARTICIPANT_URI, description: \"Whose work to pause, when scope is 'participant'. Must be a workspace member.\" },\n in_flight_policy: {\n type: \"string\",\n enum: [\"allow_to_complete\", \"interrupt\"],\n description: \"Recorded with the request, and echoed back when scope is 'participant'. The coordinator does not act on it: under either value, work already under way is left alone.\",\n },\n reason: { type: \"string\", description: \"Why the pause was applied. Recorded in the audit entry.\" },\n },\n required: [\"workspace\", \"from\"],\n },\n\n \"chap.control.resume\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n scope: {\n type: \"string\",\n enum: [\"task\", \"participant\", \"workspace\"],\n default: \"task\",\n description: \"What the resume applies to. 'task' returns a paused task to the state it held at the pause; a task that is not paused is refused with -32061. 'participant' allows that member to be assigned tasks again. 'workspace' returns the workspace to active.\",\n },\n task_id: TASK_ID,\n participant_uri: { ...PARTICIPANT_URI, description: \"Whose work to resume, when scope is 'participant'. Must be a workspace member.\" },\n },\n required: [\"workspace\", \"from\"],\n },\n\n \"chap.control.cancel\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n task_id: { ...TASK_ID, description: \"The task to cancel. A task that is completed, declined, cancelled or superseded is refused with -32061.\" },\n reason: { type: \"string\", description: \"Why the task was cancelled. Recorded in the audit entry.\" },\n },\n required: [\"workspace\", \"from\", \"task_id\"],\n },\n\n \"chap.control.snapshot\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n label: { type: \"string\", description: \"Name for this snapshot, recorded on the artefact. chap.control.rollback identifies a snapshot by its artefact id, not by label.\" },\n include: { type: \"array\", items: { type: \"string\" }, description: \"Which aspects of the workspace to capture. Recognised values are 'members', 'open_tasks', 'mode_ceiling', 'policy' and 'audit'. Defaults to members, open_tasks and mode_ceiling.\" },\n },\n required: [\"workspace\", \"from\"],\n },\n\n \"chap.control.rollback\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n to_snapshot_artefact_id: { type: \"string\", description: \"Artefact id returned by chap.control.snapshot. An id with no matching snapshot is refused with -32062.\" },\n what_to_restore: { type: \"array\", items: { type: \"string\" }, description: \"Which captured aspects to apply. Only 'mode_ceiling' and 'members' are restored; the others are held in the snapshot and not reapplied. Restoring members resets role and scopes on members still present, and does not re-add members who have left. Defaults to the snapshot's include list.\" },\n reason: { type: \"string\", description: \"Why the rollback was performed. The rollback is itself an audit entry; earlier entries are not rewritten.\" },\n },\n required: [\"workspace\", \"from\", \"to_snapshot_artefact_id\"],\n },\n\n \"chap.control.supersede\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n task_id: { ...TASK_ID, description: \"The task being replaced. It moves to 'superseded' and is linked to the successor rather than deleted.\" },\n successor_task: {\n type: \"object\",\n description: \"The replacement task.\",\n properties: {\n kind: { type: \"string\", description: \"Task kind for the successor. Required.\" },\n assignee: { ...PARTICIPANT_URI, description: \"Who takes the replacement on. Defaults to the superseded task's assignee, and must be a workspace member who is not paused.\" },\n input: { type: \"object\", additionalProperties: true, description: \"Input payload for the successor. Defaults to an empty object.\" },\n mode: { type: \"string\", enum: [\"shadow\", \"trial\", \"production\"], description: \"Mode for the successor, defaulting to the superseded task's. A mode above the workspace's current ceiling is refused with -32040.\" },\n review_required: { type: \"boolean\", description: \"Whether completing the successor needs a reviewer decision. A successor of a task that requires review requires it whatever is passed here, and under modes/1.0 so does a trial-mode successor.\" },\n },\n required: [\"kind\"],\n },\n reason: { type: \"string\", description: \"Why the original is being replaced. Recorded in the audit entry.\" },\n },\n required: [\"workspace\", \"from\", \"task_id\", \"successor_task\"],\n },\n\n \"chap.control.set_mode_ceiling\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n new_ceiling: {\n type: \"string\",\n enum: [\"shadow\", \"trial\", \"production\"],\n description: \"The highest mode tasks in this workspace may request from now on. Existing tasks keep the mode they were created with. Where the coordinator is configured to enforce step-up authentication this method is one of the privileged ones and a call without step-up is refused with -32402.\",\n },\n reason: { type: \"string\", description: \"Why the ceiling is being changed. Recorded in the audit entry.\" },\n },\n required: [\"workspace\", \"from\", \"new_ceiling\"],\n },\n\n // ============================================================\n // routing/1.0\n // ============================================================\n\n \"chap.task.route\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n task_id: TASK_ID,\n candidates: { type: \"array\", items: PARTICIPANT_URI, description: \"Candidate assignees. An empty list is refused with -32513. The default policy takes the first candidate that is a workspace member and is not paused, and refuses the call with -32510 when there is none. An operator-supplied routing policy may select on any basis; a choice that is not a member is refused with -32510, and one who is paused with -32063.\" },\n },\n required: [\"workspace\", \"from\", \"task_id\", \"candidates\"],\n },\n\n \"chap.review.depth\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n task_id: TASK_ID,\n artefact_routing_hints: {\n type: \"object\",\n description: \"Per-artefact signals such as confidence, model_id and cost_consumed_usd, merged over the task's routing_hints for this call. The default policy reads criticality and confidence. If the merged set is empty the call is refused with -32514. Fractional values are written as decimal strings, e.g. \\\"confidence\\\": \\\"0.86\\\".\",\n additionalProperties: true,\n },\n },\n required: [\"workspace\", \"from\", \"task_id\"],\n },\n\n \"chap.escalate.auto\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n task_id: TASK_ID,\n default_escalation_target: { ...PARTICIPANT_URI, description: \"Who to escalate to when the policy decides to escalate and names no target of its own. It must be a workspace member or a group URI; if the policy escalates with no usable target the call is refused with -32516.\" },\n },\n required: [\"workspace\", \"from\", \"task_id\"],\n },\n\n // ============================================================\n // security-signed/1.0\n // ============================================================\n\n \"chap.participant.rotate_key\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n old_kid: { type: \"string\", description: \"Key id being retired. It is given a valid_until timestamp and stays in the member's key history, so signatures made before the rotation still verify. A key id that is unknown is refused with -32071, and one already revoked with -32072.\" },\n new_jwk: { type: \"object\", additionalProperties: true, description: \"The replacement public key as a JWK. It must carry a 'kid'. Whether the request itself has to be signed with the old key is decided at dispatch, and only where the coordinator is configured to require signatures.\" },\n },\n required: [\"workspace\", \"from\", \"old_kid\", \"new_jwk\"],\n },\n\n \"chap.participant.revoke_key\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n target_uri: { ...PARTICIPANT_URI, description: \"Whose key is being revoked. Revoking another member's key requires the caller to hold the role 'admin'; otherwise the call is refused with -32011.\" },\n kid: { type: \"string\", description: \"Key id to revoke. It is marked revoked with a timestamp and a reason, and signatures presented with it are refused from then on. A key id that is unknown is refused with -32071.\" },\n reason: { type: \"string\", description: \"Why the key was revoked, e.g. 'laptop lost'. Recorded on the key and in the audit entry.\" },\n },\n required: [\"workspace\", \"from\", \"target_uri\", \"kid\"],\n },\n\n // ============================================================\n // audit-scitt/1.0\n // ============================================================\n\n \"chap.audit.submit_to_scitt\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n range: {\n type: \"object\",\n description: \"Sequence window to anchor. Omit to submit the whole chain.\",\n properties: {\n from_seq: { type: \"integer\", description: \"Start sequence number, inclusive.\" },\n to_seq: { type: \"integer\", description: \"End sequence number, exclusive.\" },\n },\n },\n issuer: { type: \"string\", description: \"Issuer identifier placed on each SCITT signed statement, naming who vouches for the chain. Defaults to 'service:coordinator'. Where no submitter is configured the statements are returned unsigned for the deployment to submit out of band.\" },\n },\n required: [\"workspace\"],\n },\n\n \"chap.audit.verify_receipt\": {\n type: \"object\",\n properties: {\n workspace: WORKSPACE_ID, from: PARTICIPANT_URI,\n receipt: { type: \"object\", additionalProperties: true, description: \"The SCITT receipt to check, as returned by the transparency service. Verification is delegated to a hook supplied by the deployment, and fails closed with -32082 where no hook is configured.\" },\n },\n required: [\"workspace\", \"receipt\"],\n },\n\n \"chap.audit.verify_chain\": {\n type: \"object\",\n properties: { workspace: WORKSPACE_ID, from: PARTICIPANT_URI },\n required: [\"workspace\"],\n },\n};\n\n/** Methods that map to MCP tools: every CHAP method the coordinators implement. */\nexport const TOOL_NAMES = Object.keys(SCHEMAS);\n\n/** Get the JSON Schema for a tool, or null if not a known CHAP method. */\nexport function schemaFor(toolName: string): JsonSchema | null {\n return SCHEMAS[toolName] ?? null;\n}\n\n/** Map an MCP tool name back to its CHAP method name. */\nexport function methodForTool(toolName: string): string | null {\n if (!toolName.startsWith(\"chap.\")) return null;\n return toolName.slice(\"chap.\".length);\n}\n\n// ============================================================\n// Stringified-JSON coercion\n// ============================================================\n//\n// LLM MCP clients (Claude Desktop, Cursor, and others) frequently\n// serialise structured tool arguments as JSON-encoded *strings* rather\n// than as native JSON objects/arrays. For example, an `artefact` that\n// should arrive as { \"draft\": \"...\" } arrives as the string\n// \"{\\\"draft\\\": \\\"...\\\"}\", and a `to` that should be [\"human:me@local\"]\n// arrives as \"[\\\"human:me@local\\\"]\".\n//\n// The CHAP protocol core is deliberately strict: it stores artefacts\n// and applies JSON Patches against whatever it receives. A stringified\n// object therefore (a) pollutes the audit log with the wrong type and\n// (b) makes object-path patches in decide.override impossible, because\n// there is no object to traverse.\n//\n// We fix this at the adapter boundary, leaving the protocol core\n// untouched. Before an argument is wrapped in a CHAP envelope, any\n// string value whose schema admits a non-string type is JSON-parsed\n// when (and only when) it parses cleanly to a type the schema allows.\n// Plain strings that the schema accepts as strings (participant URIs,\n// task ids, rationales) are never touched, so a bare \"human:me@local\"\n// passed to a string|array `to` field is preserved as-is.\n\n/** True if the schema admits `object` as a value type. */\nfunction admitsType(schema: JsonSchema | undefined, t: \"object\" | \"array\"): boolean {\n if (!schema) return false;\n if (schema.type === t) return true;\n if (schema.oneOf) return schema.oneOf.some((s) => admitsType(s, t));\n // A field declared with neither `type` nor `oneOf` (e.g. `output`,\n // `artefact`) is an opaque payload: it admits any JSON value, so we\n // allow coercion to both object and array for it.\n if (schema.type === undefined && !schema.oneOf && !schema.enum) return true;\n return false;\n}\n\n/**\n * Coerce a single argument value against its parameter schema. Returns\n * the parsed value when the string is stringified JSON the schema\n * accepts; otherwise returns the value unchanged.\n */\nfunction coerceValue(value: unknown, schema: JsonSchema | undefined): unknown {\n if (typeof value !== \"string\") return value;\n const trimmed = value.trim();\n if (trimmed.length === 0) return value;\n const looksLikeObject = trimmed.startsWith(\"{\");\n const looksLikeArray = trimmed.startsWith(\"[\");\n if (!looksLikeObject && !looksLikeArray) return value;\n\n const wantObject = looksLikeObject && admitsType(schema, \"object\");\n const wantArray = looksLikeArray && admitsType(schema, \"array\");\n if (!wantObject && !wantArray) return value;\n\n try {\n const parsed = JSON.parse(value);\n // Only accept the parse if its type is one the schema admits. This\n // guards against, say, a string that happens to start with \"[\" but\n // is meant to be a literal string in a string-only field.\n if (Array.isArray(parsed) && admitsType(schema, \"array\")) return parsed;\n if (parsed !== null && typeof parsed === \"object\" && !Array.isArray(parsed)\n && admitsType(schema, \"object\")) return parsed;\n return value;\n } catch {\n // Not valid JSON: leave it for the coordinator to validate/reject.\n return value;\n }\n}\n\n/**\n * Normalise the arguments object for a tool call, coercing any\n * stringified-JSON values whose parameter schema admits a structured\n * type. Unknown keys (not in the schema) are passed through untouched.\n *\n * This is a pure function: it returns a new object and does not mutate\n * its input. Coordinator dispatch sees correctly-typed params, so the\n * audit log records the right shapes and decide.override patches apply\n * against real objects.\n */\nexport function coerceToolArgs(\n toolName: string,\n args: Record<string, unknown>,\n): Record<string, unknown> {\n const schema = schemaFor(toolName);\n const props = schema?.properties;\n if (!props) return args;\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(args)) {\n out[key] = coerceValue(value, props[key]);\n }\n return out;\n}\n","/**\n * @brightbeamai/chap-coordinator-mcp/tools\n *\n * Tool-level descriptions and behavioural annotations for each CHAP\n * method exposed over MCP. A client shows these in its UI and reads\n * them when choosing a tool.\n *\n * A description says what the method does, how it differs from its\n * nearest sibling, and the consequence a caller most needs to know\n * before calling. It does not restate the parameter schema: every\n * parameter is already described in schemas.ts, and repeating that\n * here costs length and adds no meaning.\n *\n * The annotations carry what prose states poorly.\n *\n * `readOnlyHint` is not a judgement. It is exactly the coordinator's\n * own READ_ONLY_METHODS set, the list that decides whether an envelope\n * is recorded on the audit chain, and a test holds the two together.\n * Anything absent from that set appends an entry, which is a change of\n * state whatever else it does.\n *\n * `idempotentHint` was derived by calling each method twice with\n * identical arguments and comparing workspace state, and is claimed\n * only where the second call both succeeds and leaves that state\n * untouched. Where a repeat is refused rather than absorbed, the hint\n * is absent: an agent must not read an error as a safe retry. It is\n * also absent from `task.create`, which is idempotent only when the\n * caller supplies `idempotency_key` and creates a second task when\n * they do not.\n *\n * `destructiveHint` marks the methods that overwrite or remove state\n * that was there before, or settle it somewhere it cannot come back\n * from. Most of CHAP is additive and carries `false`.\n */\n\nexport const TOOL_DESCRIPTIONS: Record<string, string> = {\n // Core\n \"chap.workspace.create\":\n \"Create a workspace: the container for the participants, tasks and audit log of one piece of \" +\n \"collaborative work. Returns the workspace id, which every later call carries.\",\n\n \"chap.workspace.describe\":\n \"Report the current state of a workspace: its members, enabled profiles, audit length, and task and \" +\n \"override counts.\",\n\n \"chap.workspace.set_profiles\":\n \"Replace the whole set of profiles enabled on a workspace. The list is not merged: any profile absent \" +\n \"from it is dropped, so send the complete set you want. Enabling audit-scitt/1.0 on a workspace that \" +\n \"already has entries starts the chain from that point and leaves the earlier entries permanently outside \" +\n \"it, which chap.audit.verify_chain then reports as not_evaluated. Prefer setting profiles at \" +\n \"chap.workspace.create, where no entries exist yet to strand.\",\n\n \"chap.workspace.invite\":\n \"Invite a participant to a workspace, as its admin. The invitation names the type and role the member \" +\n \"takes when it joins, and may pin its keys and its OIDC subject. A workspace whose join policy is \" +\n \"'invite' admits nobody else. For a member that holds no key in force, the call registers the keys it \" +\n \"names at once, so a member whose keys were all revoked can sign again. Where a token or credential \" +\n \"verifier is configured, an invitation names no keys for a person: their keys arrive with the token they \" +\n \"join with (-32602).\",\n\n \"chap.participant.join\":\n \"Add a participant to a workspace. The type given, human, agent, service, group or workspace, decides \" +\n \"whether they are eligible to review work that requires it.\",\n\n \"chap.participant.leave\":\n \"Remove a participant from a workspace. Entries they have already written stay in the audit log and their \" +\n \"past signatures still verify, so leaving is not a way to withdraw a decision. They can no longer be \" +\n \"assigned tasks or act as a reviewer, and returning means a fresh chap.participant.join.\",\n\n \"chap.task.create\":\n \"Create a task: a unit of work assigned to one participant. Set review_required to make completion depend \" +\n \"on a reviewer decision rather than on the assignee. Returns a task_id that the rest of the lifecycle \" +\n \"takes. Supplying idempotency_key is what makes a retry safe: a repeat carrying a key already seen \" +\n \"returns the original task, while a repeat without one creates a second task. Assigning to a paused \" +\n \"member is refused.\",\n\n \"chap.task.update\":\n \"Move a task to a new state. Only the transitions in the specification's lifecycle table are accepted, \" +\n \"and a task that requires review cannot be completed here. A task whose review no decision has closed, or \" +\n \"a successor that carries one on, is not declined (-32602).\",\n\n \"chap.task.complete\":\n \"Submit a task's output. A task that requires review does not complete: the output is held as the \" +\n \"artefact under review, the task moves to review_requested, and a reviewer decision completes it. Any \" +\n \"other task completes immediately.\",\n\n \"chap.audit.read\":\n \"Read entries from a workspace's audit log, optionally within a sequence range and filtered by method, \" +\n \"sender, task or outcome. This is the query surface for everything the workspace has recorded, decisions \" +\n \"and overrides included. An accepted call is under 'envelope'. A refused attempt the coordinator recorded, \" +\n \"such as a decision by someone the review was not addressed to, is under 'request' with an 'outcome' \" +\n \"giving the error code, and it did not take effect. Reads only: it records nothing, so it never appears in \" +\n \"its own output. Entries come back as recorded, without aggregation, so grouping them, by tag for \" +\n \"instance, is the reader's job.\",\n\n // review/1.0\n \"chap.review.request\":\n \"Open a review on a task and address it to one or more reviewers. They then call chap.decide.approve, \" +\n \"chap.decide.reject, chap.decide.override or chap.abstain.declare, and may first say they have begun with \" +\n \"chap.review.acknowledge. Repeating the request with the same artefact adds reviewers to the open review. \" +\n \"A task marked review_required is reviewed through chap.task.complete, which opens its review under the \" +\n \"workspace's rule; on such a task this tool only adds people to a review already open, and before it \" +\n \"opens is refused with -32011.\",\n\n \"chap.review.acknowledge\":\n \"Say that this reviewer has begun the open review on a task, before deciding it. The call is recorded, so \" +\n \"the audit log shows when each reviewer took the review up as well as when they decided. It decides \" +\n \"nothing: the review stays open and the acknowledgement counts towards no rule. Only someone who may \" +\n \"decide the review may send it, and anyone else is refused with -32011. A task with no open review is \" +\n \"refused with -32010, and a second acknowledgement from the same reviewer in the same round with -32602. \" +\n \"Returns requested_at, the time the round opened, which names it.\",\n\n \"chap.decide.approve\":\n \"Approve the artefact under review as it stands. Only a reviewer the review was addressed to may decide, \" +\n \"and anyone else is refused with -32011. The task completes once the review's rule is satisfied, so under \" +\n \"all_approve or quorum:N an approval may leave the review open awaiting others. Use chap.decide.override \" +\n \"instead to accept a corrected version.\",\n\n \"chap.decide.reject\":\n \"Reject the artefact under review. The task is declined, or returns to in_progress when request_revision \" +\n \"is set, which is the choice between ending the work and sending it back. Only a reviewer the review was \" +\n \"addressed to may decide. Use chap.decide.override instead to correct the artefact and accept it rather \" +\n \"than refuse it.\",\n\n \"chap.decide.override\":\n \"Correct the artefact under review with an RFC 6902 JSON Patch and accept the result. The patch, the \" +\n \"rationale and any tags are recorded together, so the audit log holds what was changed and why, rather \" +\n \"than only that the work was not accepted as written.\",\n\n \"chap.abstain.declare\":\n \"Stand aside from a review this participant cannot decide, for example on a conflict of interest or for \" +\n \"want of context. Use it in place of chap.decide.reject, which judges the work; abstaining judges nothing \" +\n \"and leaves the artefact intact. It requires an open review addressed to the caller and answers -32010 \" +\n \"otherwise. The task moves to abstained, which is not terminal: chap.escalate.raise or a fresh \" +\n \"chap.review.request can still carry it forward.\",\n\n \"chap.escalate.raise\":\n \"Hand a task upwards, where the current holder can act but should not decide alone. The original moves to \" +\n \"escalated and is linked to a new task for whoever takes it on. Use chap.handoff.propose to pass work \" +\n \"sideways without that link, and chap.control.supersede to replace a task outright. The successor starts \" +\n \"with an empty input unless one is supplied, so restate whatever the new assignee needs. A completed, \" +\n \"cancelled or superseded task cannot be escalated. The successor takes the mode new_task.mode names, or \" +\n \"else the original's, and requires review when the original did or held a review, or when it is a trial \" +\n \"task under modes/1.0. Whoever made the original's work counts as an author of the successor's review. A \" +\n \"paused assignee is refused with -32063, and a mode above the workspace's current ceiling with -32040; \" +\n \"after the ceiling is lowered, name a mode within it.\",\n\n // whisper/1.0\n \"chap.whisper.ask\":\n \"Put one question to one or more participants, with a deadline and a default. If the deadline passes \" +\n \"unanswered the default applies, so a task is never blocked waiting on a reply.\",\n\n \"chap.whisper.answer\":\n \"Answer an open whisper. Where the question carried options, the answer must name one of their ids and \" +\n \"any other value is refused with -32022. A whisper already answered is refused with -32020 and one past \" +\n \"its deadline with -32021, in which case the default supplied at chap.whisper.ask has already been \" +\n \"applied.\",\n\n // deliberation/1.0\n \"chap.deliberate.open\":\n \"Open a group decision among several participants under a stated voting rule: any_one_approves, \" +\n \"all_approve, quorum:N, weighted_vote:T or weighted_vote_with_veto:T. Use it where several people must \" +\n \"weigh in on one question; chap.review.request is the tool for judging one participant's output. Returns \" +\n \"a deliberation_id that the comment, vote and close tools all take. The participant list, rule, weights \" +\n \"and veto map are fixed at open, so the terms are settled before anyone votes. No outcome exists until \" +\n \"chap.deliberate.close computes one.\",\n\n \"chap.deliberate.comment\":\n \"Record a comment on an open deliberation, so the reasoning behind a vote survives alongside the tally. \" +\n \"Comments carry no weight in the outcome and may be added by any participant at any point before \" +\n \"chap.deliberate.close.\",\n\n \"chap.deliberate.vote\":\n \"Cast a yea, nay or abstain in an open deliberation. Each participant votes once and a second attempt \" +\n \"answers -32031, so a vote cannot be revised. An abstention is recorded but counts as neither side, which \" +\n \"under all_approve or quorum:N withholds the approval those rules need. The tally is computed later, by \" +\n \"chap.deliberate.close.\",\n\n \"chap.deliberate.close\":\n \"Close a deliberation and compute its outcome from the votes cast under its rule. Closing is final: \" +\n \"further comments and votes are refused with -32032. Calling it again on a closed deliberation returns \" +\n \"the same outcome and changes nothing, so a retry is safe. Votes never cast are simply absent from the \" +\n \"tally rather than counted as abstentions.\",\n\n // handoff/1.0\n \"chap.handoff.propose\":\n \"Propose handing one or more tasks to another participant or a group, with the context needed to pick \" +\n \"them up. Every task must currently be assigned to the proposer.\",\n\n \"chap.handoff.accept\":\n \"Accept a proposed handoff. The accepted tasks are reassigned to the accepting participant, which is the \" +\n \"point at which responsibility actually moves. Omitting accepted_task_ids accepts all of them. Accepting \" +\n \"resolves the proposal for good: a later accept or decline on the same handoff answers -32051. A paused \" +\n \"participant cannot accept and is refused with -32063.\",\n\n \"chap.handoff.decline\":\n \"Decline a proposed handoff. The tasks stay with the proposer and nothing is reassigned, which is the \" +\n \"difference from chap.handoff.accept. Declining resolves the proposal for good: a later accept or decline \" +\n \"on the same handoff answers -32051, and trying again means a fresh proposal. The reason is recorded so \" +\n \"the proposer can route the work elsewhere.\",\n\n // control/1.0\n \"chap.control.pause\":\n \"Pause work. Scoped to a task it moves that task to paused; to a participant it stops new tasks being \" +\n \"assigned to them; to the workspace it refuses every method except describing, reading the audit log, \" +\n \"joining, leaving and resuming.\",\n\n \"chap.control.resume\":\n \"Resume work paused at the same scope: a task returns to the state it held at the pause, a participant \" +\n \"can be assigned tasks again, a workspace returns to active.\",\n\n \"chap.control.cancel\":\n \"Cancel a task. Cancelled is terminal, and a task that has already settled cannot be cancelled. From the \" +\n \"moment a review the task requires opens until a reviewer rejects the work, the authors of the work cannot \" +\n \"cancel it, even once they take the work back, nor a successor that carries its review (-32011).\",\n\n \"chap.control.snapshot\":\n \"Capture the workspace state as an artefact before a change you may want to undo. Returns a snapshot \" +\n \"artefact id, which is the only thing chap.control.rollback accepts as a target; the label is for a human \" +\n \"reading the log and cannot be used to select it. Taking a snapshot changes nothing. Note that a rollback \" +\n \"restores only the mode ceiling and member roles, so a snapshot is a narrow safety net rather than a \" +\n \"general undo.\",\n\n \"chap.control.rollback\":\n \"Restore workspace state from a snapshot. The mode ceiling and member roles are restored; the rollback is \" +\n \"appended to the audit log rather than rewriting it.\",\n\n \"chap.control.supersede\":\n \"Replace a task with a successor in one call. The original moves to superseded and stays linked to its \" +\n \"replacement. The successor requires review when the original did, whatever its own review_required \" +\n \"says, and whoever made the original's work counts as an author of the successor's review. A paused \" +\n \"assignee is refused with -32063, and from the moment a review the original requires opens until a \" +\n \"reviewer rejects the work, the authors of the work cannot supersede it, nor a successor that carries its \" +\n \"review (-32011).\",\n\n \"chap.control.set_mode_ceiling\":\n \"Set the highest operating mode tasks in this workspace may request. A task above the ceiling is refused.\",\n\n // routing/1.0\n \"chap.task.route\":\n \"Choose an assignee for a task from a list of candidates and reassign the task to the one selected. Use \" +\n \"it where the choice itself belongs on the record: it writes a route_decision artefact naming the policy, \" +\n \"the candidate chosen and the alternatives passed over, none of which is captured by setting assignee \" +\n \"directly on chap.task.create. The default policy takes the first candidate that is a workspace member \" +\n \"and is not paused. An operator-supplied policy may choose on any basis, and the call is refused with \" +\n \"-32510 when its choice is not a member, or with -32063 when its choice is paused.\",\n\n \"chap.review.depth\":\n \"Decide how much review a task warrants, skip, spot_check or full, from its routing hints. Records a \" +\n \"route_decision artefact giving the rule that produced the answer.\",\n\n \"chap.escalate.auto\":\n \"Evaluate a task's routing hints against the escalation policy and report whether it should be escalated, \" +\n \"and to whom. It decides only: a route_decision artefact is recorded but the task does not move, so act \" +\n \"on the answer with chap.escalate.raise. The default policy escalates on criticality critical, or high \" +\n \"with confidence below 0.6.\",\n\n // security-signed/1.0\n \"chap.participant.rotate_key\":\n \"Retire a participant's signing key and register its replacement. The old key stays in the key history \" +\n \"with a valid_until timestamp, so envelopes it signed still verify.\",\n\n \"chap.participant.revoke_key\":\n \"Revoke a signing key, for example after a device is lost. Signatures presented with it are refused from \" +\n \"then on. Revoking another participant's key requires the admin role.\",\n\n // audit-scitt/1.0\n \"chap.audit.submit_to_scitt\":\n \"Build COSE_Sign1-shaped statements for a range of audit entries and submit them to the configured SCITT \" +\n \"transparency service. Where none is configured the statements are returned for submission out of band.\",\n\n \"chap.audit.verify_receipt\":\n \"Check a receipt returned by an external SCITT transparency service, confirming that service logged the \" +\n \"statement. This is the external half of verification; chap.audit.verify_chain checks the local prev-hash \" +\n \"chain instead, and the two answer different questions. Verification is delegated to a hook the \" +\n \"deployment supplies and fails closed with -32082 when none is configured, so a missing verifier can \" +\n \"never read as a pass. Reads only: nothing is recorded.\",\n\n \"chap.audit.verify_chain\":\n \"Replay a workspace's prev-hash chain. Only status verified with ok true means the log was checked and is \" +\n \"intact. Status not_evaluated with ok false means part of the log was never checked, so its integrity is \" +\n \"unknown and must not be reported as verified; entries_unchecked says how much. An error means the chain \" +\n \"is broken or absent.\",\n};\n\n/** MCP tool annotations (2025-03-26 onwards). Every field is a hint. */\nexport interface ToolAnnotations {\n /** Human-readable title, shown by a client instead of the raw tool name. */\n title: string;\n /** Does not modify state. Mirrors the coordinator's own read-only set. */\n readOnlyHint: boolean;\n /** May overwrite or remove existing state, or settle it irreversibly. */\n destructiveHint: boolean;\n /** A repeat with identical arguments succeeds and changes nothing further. */\n idempotentHint: boolean;\n /** Reaches a system outside this coordinator. */\n openWorldHint: boolean;\n}\n\n/**\n * Read-only, and so never recorded on the chain. This is the coordinator's own\n * READ_ONLY_METHODS set, the list that decides whether an envelope is\n * recorded. It is repeated here rather than imported so the adapter does not\n * depend on a coordinator export at runtime, and annotations.test.ts reads\n * that source and fails if the two ever diverge.\n */\nconst READ_ONLY = new Set([\n \"chap.workspace.describe\", \"chap.audit.read\", \"chap.audit.verify_chain\", \"chap.audit.verify_receipt\",\n // Submitting reads the chain and sends it onward. It changes nothing here,\n // which is what readOnlyHint claims; openWorldHint carries the fact that it\n // reaches a service outside this coordinator.\n \"chap.audit.submit_to_scitt\",\n]);\n\n/** Overwrites, removes, or settles state irreversibly. */\nconst DESTRUCTIVE = new Set([\n \"chap.workspace.set_profiles\", // replaces the profile set; can strand entries outside the chain\n \"chap.participant.leave\", // removes a member\n \"chap.participant.revoke_key\", // invalidates a key from then on\n \"chap.control.cancel\", // cancelled is terminal\n \"chap.control.supersede\", // superseded is terminal\n \"chap.control.rollback\", // overwrites the mode ceiling and member roles\n]);\n\n/** Verified by calling twice with identical arguments and diffing workspace state. */\nconst IDEMPOTENT = new Set([\n \"chap.workspace.describe\", \"chap.audit.read\", \"chap.audit.verify_chain\", \"chap.audit.verify_receipt\",\n \"chap.participant.join\", // a re-join is additive and adds no duplicate member\n \"chap.participant.leave\", // leaving twice leaves the same absence\n \"chap.control.pause\", // pausing an already paused target changes nothing\n \"chap.control.set_mode_ceiling\", // setting the ceiling it already has changes nothing\n \"chap.deliberate.close\", // returns the same outcome, recomputing nothing\n \"chap.review.acknowledge\", // a second acknowledgement in the round is refused and records nothing\n]);\n\n/** Reaches a transparency service outside this coordinator. */\nconst OPEN_WORLD = new Set([\n \"chap.audit.submit_to_scitt\", \"chap.audit.verify_receipt\",\n]);\n\n/**\n * Human-readable titles. A client that shows a title instead of the tool\n * name should still show something a person can read at a glance.\n */\nconst TITLES: Record<string, string> = {\n \"chap.workspace.create\": \"Create workspace\",\n \"chap.workspace.describe\": \"Describe workspace\",\n \"chap.workspace.set_profiles\": \"Replace workspace profiles\",\n \"chap.workspace.invite\": \"Invite participant\",\n \"chap.participant.join\": \"Add participant\",\n \"chap.participant.leave\": \"Remove participant\",\n \"chap.task.create\": \"Create task\",\n \"chap.task.update\": \"Change task state\",\n \"chap.task.complete\": \"Submit task output\",\n \"chap.audit.read\": \"Read audit log\",\n \"chap.review.request\": \"Request review\",\n \"chap.review.acknowledge\": \"Acknowledge review\",\n \"chap.decide.approve\": \"Approve\",\n \"chap.decide.reject\": \"Reject\",\n \"chap.decide.override\": \"Override with a correction\",\n \"chap.abstain.declare\": \"Abstain from review\",\n \"chap.escalate.raise\": \"Escalate task\",\n \"chap.whisper.ask\": \"Ask a whisper\",\n \"chap.whisper.answer\": \"Answer a whisper\",\n \"chap.deliberate.open\": \"Open deliberation\",\n \"chap.deliberate.comment\": \"Comment on deliberation\",\n \"chap.deliberate.vote\": \"Vote in deliberation\",\n \"chap.deliberate.close\": \"Close deliberation\",\n \"chap.handoff.propose\": \"Propose handoff\",\n \"chap.handoff.accept\": \"Accept handoff\",\n \"chap.handoff.decline\": \"Decline handoff\",\n \"chap.control.pause\": \"Pause work\",\n \"chap.control.resume\": \"Resume work\",\n \"chap.control.cancel\": \"Cancel task\",\n \"chap.control.snapshot\": \"Snapshot workspace\",\n \"chap.control.rollback\": \"Roll back to snapshot\",\n \"chap.control.supersede\": \"Supersede task\",\n \"chap.control.set_mode_ceiling\": \"Set mode ceiling\",\n \"chap.task.route\": \"Route task to an assignee\",\n \"chap.review.depth\": \"Decide review depth\",\n \"chap.escalate.auto\": \"Evaluate auto-escalation\",\n \"chap.participant.rotate_key\": \"Rotate signing key\",\n \"chap.participant.revoke_key\": \"Revoke signing key\",\n \"chap.audit.submit_to_scitt\": \"Anchor audit log in SCITT\",\n \"chap.audit.verify_receipt\": \"Verify SCITT receipt\",\n \"chap.audit.verify_chain\": \"Verify audit chain\",\n};\n\n/** Annotations for every tool, derived from the sets above. */\nexport const TOOL_ANNOTATIONS: Record<string, ToolAnnotations> = Object.fromEntries(\n Object.keys(TOOL_DESCRIPTIONS).map((name) => [name, {\n title: TITLES[name] ?? name,\n readOnlyHint: READ_ONLY.has(name),\n // Meaningful only when readOnlyHint is false, per the specification.\n destructiveHint: DESTRUCTIVE.has(name),\n idempotentHint: IDEMPOTENT.has(name),\n openWorldHint: OPEN_WORLD.has(name),\n }]),\n);\n\n/**\n * The tools an agent's own connection offers: what its work needs, and\n * nothing that chooses who reviews that work or passes its review on. The\n * decision tools and review.acknowledge stay for work the agent is asked to\n * review; on its own work the coordinator refuses them and records the\n * attempt. Left out are workspace and membership changes, review.request\n * (an explicit review may name its own author), escalate.raise (it passes\n * the open review on to a successor task), and every other tool.\n * task.update stays, and can take a task under review back to in_progress,\n * which withdraws the draft; the next completion opens the review again, so\n * a task that holds a review completes only through a decision.\n *\n * The stdio server offers this set by default. A server that gives an agent\n * its own MCP connection, as the templates' /mcp does, imports it from here.\n */\nexport const AGENT_MCP_TOOLS: ReadonlySet<string> = new Set([\n \"chap.task.create\", \"chap.task.update\", \"chap.task.complete\", \"chap.whisper.ask\",\n \"chap.decide.approve\", \"chap.decide.reject\", \"chap.decide.override\", \"chap.review.acknowledge\",\n \"chap.workspace.describe\", \"chap.audit.read\", \"chap.audit.verify_chain\",\n]);\n","/**\n * Per-request protocol envelope (MCP 2026-07-28).\n *\n * The 2026 revision is stateless: instead of negotiating once through an\n * `initialize` handshake, every request declares its protocol version and\n * client capabilities in `_meta`, and the server accepts or rejects each\n * request on its own. This module implements that classification so the\n * TypeScript adapter behaves the same way the Python `mcp` 2.x SDK does,\n * which enforces the same rules natively.\n *\n * Two version sets, deliberately different:\n *\n * - `MODERN_PROTOCOL_VERSIONS` is what may be declared per request. Only\n * revisions that use per-request metadata qualify, so `2025-11-25` is\n * not a legal per-request declaration: it is negotiated by handshake.\n * This is the set named in an `UnsupportedProtocolVersionError`, so a\n * client retrying from that list always retries with something usable.\n *\n * - `SUPPORTED_PROTOCOL_VERSIONS` is what `server/discover` advertises. It\n * spans both eras because CHAP serves both: a modern client uses\n * `2026-07-28` per request, a handshake-era client negotiates\n * `2025-11-25` through `initialize`.\n */\n\nimport { ErrorCode } from \"@modelcontextprotocol/sdk/types.js\";\n\n/**\n * A JSON-RPC error carrying a spec-exact `message`.\n *\n * The SDK's own `McpError` rewrites the message to `MCP error <code>: <text>`\n * and the protocol layer puts that rewritten string on the wire, which would\n * make CHAP answer `MCP error -32022: Unsupported protocol version` where the\n * specification, and the Python implementation, both say `Unsupported\n * protocol version`. The protocol layer reads `code`, `message` and `data`\n * off whatever is thrown, so a plain `Error` carrying those fields\n * serialises exactly as written.\n */\nexport class ProtocolError extends Error {\n readonly code: number;\n readonly data?: unknown;\n\n constructor(code: number, message: string, data?: unknown) {\n super(message);\n this.name = \"ProtocolError\";\n this.code = code;\n if (data !== undefined) this.data = data;\n }\n}\n\n/** `_meta` key carrying the protocol version of a single request. */\nexport const META_PROTOCOL_VERSION = \"io.modelcontextprotocol/protocolVersion\";\n/** `_meta` key carrying client identity. Optional per the specification. */\nexport const META_CLIENT_INFO = \"io.modelcontextprotocol/clientInfo\";\n/** `_meta` key carrying client capabilities. Required on a modern request. */\nexport const META_CLIENT_CAPABILITIES = \"io.modelcontextprotocol/clientCapabilities\";\n\n/**\n * `UnsupportedProtocolVersionError`. The specification reserves -32020 to\n * -32099 for its own codes; -32022 is the one it assigns to a version the\n * server does not implement.\n */\nexport const UNSUPPORTED_PROTOCOL_VERSION = -32022;\n\n/** Revisions that may be declared in a per-request `_meta` envelope. */\nexport const MODERN_PROTOCOL_VERSIONS = [\"2026-07-28\"] as const;\n\n/**\n * Revisions advertised by `server/discover`, newest first. The tool surface\n * is identical across both: CHAP exposes plain tools with JSON Schema\n * inputs, which the 2026-07-28 stateless core carries unchanged.\n */\nexport const SUPPORTED_PROTOCOL_VERSIONS = [\"2026-07-28\", \"2025-11-25\"] as const;\n\n/**\n * Which era a single request belongs to. `modern` means it carried a valid\n * per-request envelope; `legacy` means it carried no protocol version at\n * all and therefore belongs to a handshake-negotiated session.\n */\nexport type ProtocolEra = \"modern\" | \"legacy\";\n\n/**\n * Classify one request by its `_meta` envelope, rejecting a malformed or\n * unsupported one.\n *\n * The rejection ladder matches the Python SDK's, rung for rung, so the two\n * implementations answer an identical probe identically:\n *\n * 1. no `_meta`, or no protocol version in it, is a handshake-era request\n * 2. a declared version with no `clientCapabilities` is malformed: -32602\n * 3. a non-string version is malformed: -32602\n * 4. a version outside `MODERN_PROTOCOL_VERSIONS`: -32022\n *\n * @throws ProtocolError on a malformed or unsupported envelope.\n */\nexport function classifyEnvelope(params: unknown): ProtocolEra {\n const meta = readMeta(params);\n if (meta === null) return \"legacy\";\n\n if (!(META_PROTOCOL_VERSION in meta)) return \"legacy\";\n const declared = meta[META_PROTOCOL_VERSION];\n if (declared === undefined || declared === null) return \"legacy\";\n\n // A declared version makes this a modern request, so the rest of the\n // required envelope must be present. The specification marks\n // clientCapabilities required and clientInfo optional, and requires a\n // missing required field to be rejected as invalid params.\n if (!(META_CLIENT_CAPABILITIES in meta)) {\n throw new ProtocolError(\n ErrorCode.InvalidParams,\n `params._meta is missing the required envelope key(s): ${META_CLIENT_CAPABILITIES}`,\n );\n }\n\n if (typeof declared !== \"string\") {\n throw new ProtocolError(\n ErrorCode.InvalidParams,\n \"the protocol-version envelope value must be a string\",\n );\n }\n\n if (!(MODERN_PROTOCOL_VERSIONS as readonly string[]).includes(declared)) {\n throw new ProtocolError(UNSUPPORTED_PROTOCOL_VERSION, \"Unsupported protocol version\", {\n supported: [...MODERN_PROTOCOL_VERSIONS],\n requested: declared,\n });\n }\n\n return \"modern\";\n}\n\n/** Read `params._meta` as a plain object, or null when it is absent. */\nfunction readMeta(params: unknown): Record<string, unknown> | null {\n if (typeof params !== \"object\" || params === null) return null;\n const meta = (params as Record<string, unknown>)._meta;\n if (typeof meta !== \"object\" || meta === null || Array.isArray(meta)) return null;\n return meta as Record<string, unknown>;\n}\n","/**\n * Forwarding to a running CHAP server.\n *\n * `chap-mcp-server --url <endpoint>` serves MCP on stdio and sends each call\n * on to the JSON-RPC endpoint of a server that already runs a coordinator,\n * such as a desk server's `POST /chap`. The workspace, its store and the\n * people deciding in the desk all stay with that server.\n */\n\nimport type { Envelope } from \"@brightbeamai/chap-coordinator\";\n\n/** How long a call waits for the server's answer: 30 seconds, as the Python client waits. */\nexport const REMOTE_TIMEOUT_MS = 30_000;\n\n/**\n * The endpoint could not be reached, or did not answer in JSON-RPC. The\n * message is written for the MCP client, which shows it to the assistant.\n */\nexport class ChapEndpointError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ChapEndpointError\";\n }\n}\n\n/**\n * A dispatcher that POSTs each envelope to `endpoint` and returns the JSON-RPC\n * response. A refusal comes back as the server's own error envelope; only a\n * failure to get a JSON-RPC answer at all throws, and so does a server that\n * has not answered within `timeoutMs`.\n */\nexport function remoteDispatcher(\n endpoint: string,\n timeoutMs: number = REMOTE_TIMEOUT_MS,\n): { dispatch(envelope: Envelope): Promise<Envelope> } {\n return {\n async dispatch(envelope: Envelope): Promise<Envelope> {\n let response: Response;\n let text: string;\n try {\n response = await fetch(endpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", accept: \"application/json\" },\n body: JSON.stringify(envelope),\n signal: AbortSignal.timeout(timeoutMs),\n });\n text = await response.text();\n } catch (err) {\n throw new ChapEndpointError(`The CHAP server at ${endpoint} could not be reached (${reason(err)}). Start it, or check --url.`);\n }\n let body: unknown;\n try {\n body = JSON.parse(text);\n } catch {\n throw new ChapEndpointError(`The CHAP server at ${endpoint} answered HTTP ${response.status} with a body that is not JSON.`);\n }\n if (isResponseEnvelope(body)) return body;\n const said = typeof (body as { error?: unknown })?.error === \"string\" ? `: ${(body as { error: string }).error}` : \"\";\n throw new ChapEndpointError(`The CHAP server at ${endpoint} refused the call with HTTP ${response.status}${said}`);\n },\n };\n}\n\n/**\n * Why a request got no answer, in the words the Python client uses: \"timed\n * out\", or the network's own reason, such as ECONNREFUSED. fetch wraps that\n * reason as the cause of its \"fetch failed\", by code where it has one.\n */\nfunction reason(err: unknown): string {\n if (err instanceof Error && err.name === \"TimeoutError\") return \"timed out\";\n const cause = (err as { cause?: { code?: unknown; message?: unknown } }).cause;\n if (typeof cause?.code === \"string\") return cause.code;\n if (typeof cause?.message === \"string\" && cause.message) return cause.message;\n return err instanceof Error ? err.message : String(err);\n}\n\nfunction isResponseEnvelope(body: unknown): body is Envelope {\n if (typeof body !== \"object\" || body === null || Array.isArray(body)) return false;\n const b = body as Record<string, unknown>;\n return b.jsonrpc === \"2.0\" && (\"result\" in b || (typeof b.error === \"object\" && b.error !== null));\n}\n","/**\n * MCP over HTTP, for one Node `http` request and its response.\n *\n * The stdio server answers both protocol eras on one connection. Over HTTP\n * the SDK's Streamable HTTP transport answers the handshake era only: a\n * request naming MCP-Protocol-Version 2026-07-28 is refused with 400 before\n * any handler sees it. This serves both eras on one endpoint:\n *\n * - Every request is checked first. A Host that is not one of the server's\n * names is refused with 421, so a page that rebinds its own name to this\n * address gets nothing; an Origin naming another site is refused with 403;\n * and any method but POST with 405, since neither era has a use for GET or\n * DELETE on a server that keeps no session.\n * - A request with no MCP-Protocol-Version header, or one naming a\n * handshake-era revision, goes to the SDK's transport, stateless: a\n * server and a transport for each request. A batch is refused before it,\n * as every revision since 2025-06-18 refuses one, and so is a body whose\n * envelope declares a version the header does not name.\n * - A request naming any other version takes the 2026-07-28 binding: one\n * POST carrying one JSON-RPC message, answered with one JSON object, with\n * no session. The message must be one the SDK's own schema accepts, the\n * headers that mirror the body are checked against it, the envelope is\n * classified, and the request runs through the same handlers as on stdio.\n * An error carries the HTTP status that binding gives its code.\n *\n * No request waits for ever. One the server has not answered within the\n * timeout is answered with an internal error, and one whose client has gone\n * stops waiting at once.\n */\n\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport type { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport type { Transport } from \"@modelcontextprotocol/sdk/shared/transport.js\";\nimport {\n ErrorCode,\n SUPPORTED_PROTOCOL_VERSIONS as SDK_PROTOCOL_VERSIONS,\n isJSONRPCNotification,\n isJSONRPCRequest,\n type JSONRPCMessage,\n type JSONRPCRequest,\n type RequestId,\n} from \"@modelcontextprotocol/sdk/types.js\";\n\nimport {\n META_CLIENT_CAPABILITIES,\n META_PROTOCOL_VERSION,\n MODERN_PROTOCOL_VERSIONS,\n UNSUPPORTED_PROTOCOL_VERSION,\n} from \"./envelope.js\";\n\n/** The 2026-07-28 binding's error for headers that disagree with the body, or are missing. */\nconst HEADER_MISMATCH = -32020;\n\n/** The largest body read when the caller has not read it: the coordinator's 1 MiB envelope limit, and room for the MCP wrapping. */\nexport const DEFAULT_MAX_BODY_BYTES = 1_048_576 + 65_536;\n\n/**\n * How long a request waits for its answer by default: longer than the 30\n * seconds a forwarding dispatcher waits for its CHAP server, so that\n * server's own error arrives first, and shorter than the 60 seconds the\n * TypeScript SDK's client waits, so the client hears why.\n */\nexport const DEFAULT_TIMEOUT_MS = 45_000;\n\n/** Revisions reached through `initialize`, which the SDK's transport serves. */\nconst HANDSHAKE_VERSIONS: readonly string[] = SDK_PROTOCOL_VERSIONS.filter(\n (v) => !(MODERN_PROTOCOL_VERSIONS as readonly string[]).includes(v),\n);\n\n/** The methods the 2026-07-28 binding reaches here; any other is not found. */\nconst MODERN_METHODS = new Set([\"server/discover\", \"tools/list\", \"tools/call\"]);\n\n/** The headers a 2026-07-28 request mirrors from its body; each may appear once. */\nconst ROUTING_HEADERS = new Set([\"mcp-protocol-version\", \"mcp-method\", \"mcp-name\"]);\n\n/** HTTP status for a JSON-RPC error code on the 2026-07-28 binding. Any other code is 200. */\nconst STATUS_FOR_CODE = new Map<number, number>([\n [ErrorCode.ParseError, 400],\n [ErrorCode.InvalidRequest, 400],\n [ErrorCode.InvalidParams, 400],\n [HEADER_MISMATCH, 400],\n [UNSUPPORTED_PROTOCOL_VERSION, 400],\n [ErrorCode.MethodNotFound, 404],\n]);\n\nconst NOT_ONE_MESSAGE = \"Body must be a single JSON-RPC request or notification object\";\nconst INTERNAL = { code: ErrorCode.InternalError, message: \"Internal error\" };\n\ninterface RpcError { code: number; message: string; data?: unknown }\n\n/** What the handler is built with. */\nexport interface HttpSettings {\n /** The MCP server a request is answered by, one for each request. */\n makeServer: () => Server;\n maxBodyBytes: number;\n timeoutMs: number;\n /** Host header values served besides the loopback names on the port a request came in on, in lower case. */\n allowedHosts: readonly string[];\n /** Origins served besides those on a served host, each as `new URL(origin).origin` gives it. */\n allowedOrigins: readonly string[];\n}\n\n/**\n * The handler for one endpoint. `parsedBody`, when the caller has read the\n * body already, is used as it stands.\n */\nexport function mcpHttpHandler(settings: HttpSettings) {\n return async function handle(req: IncomingMessage, res: ServerResponse, parsedBody?: unknown): Promise<void> {\n try {\n const hosts = servedHosts(req, settings.allowedHosts);\n if (!hosts.has((req.headers.host ?? \"\").toLowerCase())) {\n answer(res, 421, { code: ErrorCode.InvalidRequest, message: \"Unknown host: add it to allowedHosts to serve under that name\" });\n return;\n }\n if (foreignOrigin(req.headers.origin, hosts, settings.allowedOrigins)) {\n answer(res, 403, { code: ErrorCode.InvalidRequest, message: \"Cross-origin requests are refused: add the origin to allowedOrigins to serve it\" });\n return;\n }\n if (req.method !== \"POST\") {\n res.writeHead(405, { allow: \"POST\" }).end();\n return;\n }\n const declared = req.headers[\"mcp-protocol-version\"];\n if (declared === undefined || (typeof declared === \"string\" && HANDSHAKE_VERSIONS.includes(declared))) {\n await handshake(settings, req, res, parsedBody);\n return;\n }\n await singleExchange(settings, req, res, parsedBody);\n } catch (err) {\n // The handler's promise settles whatever happens, so a server that\n // mounts it without a catch of its own keeps running. The detail goes\n // to the log, and the client gets a short answer if it can still take\n // one.\n console.error(\"MCP request failed:\", err);\n if (!res.headersSent) answer(res, 500, INTERNAL);\n else res.destroy();\n }\n };\n}\n\n/**\n * A handshake-era request: the SDK's transport answers it, once the body is\n * known to be one message whose envelope, if it declares a version, declares\n * the one the header names.\n */\nasync function handshake(settings: HttpSettings, req: IncomingMessage, res: ServerResponse, parsedBody: unknown): Promise<void> {\n let body = parsedBody;\n // A body of another type is left unread, for the transport to refuse with 415.\n if (body === undefined && isJsonType(req.headers[\"content-type\"])) {\n const read = await readJson(req, res, settings.maxBodyBytes);\n if (!read) return;\n body = read.value;\n }\n if (Array.isArray(body)) {\n answer(res, 400, { code: ErrorCode.InvalidRequest, message: \"A batch is not accepted: send each JSON-RPC message in a POST of its own\" });\n return;\n }\n const header = req.headers[\"mcp-protocol-version\"];\n const version = envelopeVersion(body);\n if (version !== undefined && version !== header) {\n answer(res, 400, {\n code: HEADER_MISMATCH,\n message: header === undefined\n ? \"mcp-protocol-version header is missing, and the request envelope declares a protocol version\"\n : \"mcp-protocol-version header does not match the request envelope's protocol version\",\n }, idOf(body));\n return;\n }\n\n const id = isJSONRPCRequest(body) ? body.id : undefined;\n const server = settings.makeServer();\n const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined, maxRequestBodySize: settings.maxBodyBytes });\n const timer = setTimeout(() => {\n console.error(`MCP request ${JSON.stringify(id ?? null)} had no answer within ${settings.timeoutMs} ms`);\n if (!res.headersSent) answer(res, 500, INTERNAL, id);\n // The transport has begun its event stream: the error is the answer on\n // it, and ends it.\n else if (id !== undefined) transport.send({ jsonrpc: \"2.0\", id, error: INTERNAL }).catch(() => res.destroy());\n else res.destroy();\n }, settings.timeoutMs);\n res.on(\"close\", () => { clearTimeout(timer); void transport.close(); void server.close(); });\n await server.connect(transport);\n await transport.handleRequest(req, res, body);\n}\n\n/** One 2026-07-28 request: checked, run, and answered with one JSON object. */\nasync function singleExchange(settings: HttpSettings, req: IncomingMessage, res: ServerResponse, parsedBody: unknown): Promise<void> {\n if (!acceptsJson(req.headers.accept)) {\n res.writeHead(406).end();\n return;\n }\n if (!isJsonType(req.headers[\"content-type\"])) {\n answer(res, 415, { code: ErrorCode.InvalidRequest, message: \"Unsupported Media Type: Content-Type must be application/json\" });\n return;\n }\n\n let body = parsedBody;\n if (body === undefined) {\n const read = await readJson(req, res, settings.maxBodyBytes);\n if (!read) return;\n body = read.value;\n }\n\n // A notification: accepted and dropped. This binding defines none that a\n // client sends, and a single exchange has nothing for one to act on.\n if (isObject(body) && !(\"id\" in body)) {\n if (!isJSONRPCNotification(body)) {\n answer(res, 400, { code: ErrorCode.InvalidRequest, message: NOT_ONE_MESSAGE });\n return;\n }\n const version = String(req.headers[\"mcp-protocol-version\"]);\n if (!(MODERN_PROTOCOL_VERSIONS as readonly string[]).includes(version)) {\n answer(res, 400, unsupported(version));\n return;\n }\n res.writeHead(202).end();\n return;\n }\n // The SDK's server acts only on a message its schema accepts, and never\n // answers one it cannot class, so the same schema decides here.\n if (!isJSONRPCRequest(body)) {\n answer(res, 400, { code: ErrorCode.InvalidRequest, message: NOT_ONE_MESSAGE }, idOf(body));\n return;\n }\n\n const refusal = duplicatedHeader(req.rawHeaders) ?? classify(body, req.headers);\n if (refusal) {\n answer(res, STATUS_FOR_CODE.get(refusal.code) ?? 200, refusal, body.id);\n return;\n }\n if (!MODERN_METHODS.has(body.method)) {\n answer(res, 404, { code: ErrorCode.MethodNotFound, message: \"Method not found\", data: body.method }, body.id);\n return;\n }\n if (!validParams(body)) {\n answer(res, 400, { code: ErrorCode.InvalidParams, message: \"Invalid request parameters\" }, body.id);\n return;\n }\n\n const outcome = await exchange(settings, res, body);\n switch (outcome.kind) {\n case \"reply\": {\n const error = (outcome.message as { error?: RpcError }).error;\n const status = error ? STATUS_FOR_CODE.get(error.code) ?? 200 : 200;\n res.writeHead(status, { \"content-type\": \"application/json\" }).end(JSON.stringify(outcome.message));\n return;\n }\n case \"gone\":\n return;\n case \"timeout\":\n console.error(`MCP request ${JSON.stringify(body.id)} had no answer within ${settings.timeoutMs} ms`);\n answer(res, 500, INTERNAL, body.id);\n return;\n case \"error\":\n console.error(\"MCP request failed:\", outcome.error);\n answer(res, 500, INTERNAL, body.id);\n }\n}\n\ntype Outcome =\n | { kind: \"reply\"; message: JSONRPCMessage }\n | { kind: \"error\"; error: Error }\n | { kind: \"timeout\" }\n | { kind: \"gone\" };\n\n/**\n * Run one request through a server of its own, and wait for the first of:\n * its answer, an error the server reports with no answer to follow, the\n * timeout, or the client closing the connection.\n */\nasync function exchange(settings: HttpSettings, res: ServerResponse, request: JSONRPCRequest): Promise<Outcome> {\n let settle!: (outcome: Outcome) => void;\n const outcome = new Promise<Outcome>((resolve) => { settle = resolve; });\n const timer = setTimeout(() => settle({ kind: \"timeout\" }), settings.timeoutMs);\n const gone = () => settle({ kind: \"gone\" });\n res.once(\"close\", gone);\n\n const server = settings.makeServer();\n server.onerror = (error) => settle({ kind: \"error\", error });\n const transport = new SingleExchangeTransport((message) => settle({ kind: \"reply\", message }));\n try {\n await server.connect(transport);\n transport.onmessage?.(request);\n return await outcome;\n } finally {\n clearTimeout(timer);\n res.off(\"close\", gone);\n await server.close();\n }\n}\n\n/**\n * The 2026-07-28 ladder for a request that reached this path, first failure\n * first: the envelope is present, the mirrored headers match the body, and\n * the version is one this server implements.\n */\nfunction classify(body: JSONRPCRequest, headers: IncomingMessage[\"headers\"]): RpcError | null {\n const meta = isObject(body.params) ? body.params._meta : undefined;\n if (!isObject(meta)) {\n return {\n code: ErrorCode.InvalidParams,\n message: `params._meta must be an object carrying the required '${META_PROTOCOL_VERSION}' and '${META_CLIENT_CAPABILITIES}' envelope keys`,\n };\n }\n const missing = [META_PROTOCOL_VERSION, META_CLIENT_CAPABILITIES].filter((key) => !(key in meta));\n if (missing.length) {\n return { code: ErrorCode.InvalidParams, message: `params._meta is missing the required envelope key(s): ${missing.join(\", \")}` };\n }\n const version = meta[META_PROTOCOL_VERSION];\n if (headers[\"mcp-protocol-version\"] !== version) {\n return { code: HEADER_MISMATCH, message: \"mcp-protocol-version header does not match the request envelope's protocol version\" };\n }\n if (headers[\"mcp-method\"] !== body.method) {\n return { code: HEADER_MISMATCH, message: \"mcp-method header does not match the request body's method\" };\n }\n // tools/call is the one method served here that names what Mcp-Name mirrors.\n const named = body.method === \"tools/call\" && isObject(body.params) ? body.params.name : undefined;\n if (named !== undefined && named !== null && decodeHeaderValue(headers[\"mcp-name\"]) !== named) {\n return { code: HEADER_MISMATCH, message: \"mcp-name header does not match the request body's 'name' parameter\" };\n }\n if (!(MODERN_PROTOCOL_VERSIONS as readonly string[]).includes(version as string)) return unsupported(String(version));\n return null;\n}\n\n/**\n * The params of a method served here have the shape it takes: a tool call\n * names its tool and passes an object of arguments, and a list takes a\n * string cursor. The SDK would refuse others with its own validation text.\n */\nfunction validParams(body: JSONRPCRequest): boolean {\n const params = body.params ?? {};\n if (body.method === \"tools/call\") {\n return typeof params.name === \"string\" && (params.arguments === undefined || isObject(params.arguments));\n }\n if (body.method === \"tools/list\") return params.cursor === undefined || typeof params.cursor === \"string\";\n return true;\n}\n\nfunction unsupported(requested: string): RpcError {\n return { code: UNSUPPORTED_PROTOCOL_VERSION, message: \"Unsupported protocol version\", data: { supported: [...MODERN_PROTOCOL_VERSIONS], requested } };\n}\n\n/** A routing header sent more than once: readers taking the first and the last copy would disagree. */\nfunction duplicatedHeader(rawHeaders: string[]): RpcError | null {\n const seen = new Set<string>();\n for (let i = 0; i < rawHeaders.length; i += 2) {\n const name = rawHeaders[i].toLowerCase();\n if (!ROUTING_HEADERS.has(name)) continue;\n if (seen.has(name)) return { code: HEADER_MISMATCH, message: `${name} header appears more than once` };\n seen.add(name);\n }\n return null;\n}\n\n/**\n * A header value as the client meant it. A value that would not survive as\n * plain ASCII travels as `=?base64?<UTF-8 in base64>?=`; one that does not\n * decode, or is not in canonical form, reads as absent, so it matches nothing.\n */\nfunction decodeHeaderValue(value: string | string[] | undefined): string | undefined {\n if (typeof value !== \"string\") return undefined;\n const m = /^=\\?base64\\?(.*)\\?=$/.exec(value);\n if (!m) return value;\n const bytes = Buffer.from(m[1], \"base64\");\n if (bytes.toString(\"base64\") !== m[1]) return undefined;\n const text = new TextDecoder(\"utf-8\", { fatal: true });\n try { return text.decode(bytes); } catch { return undefined; }\n}\n\n/** The protocol version a body's envelope declares, if it declares one, as classifyEnvelope reads it. */\nfunction envelopeVersion(body: unknown): unknown {\n const meta = isObject(body) && isObject(body.params) ? body.params._meta : undefined;\n const version = isObject(meta) ? meta[META_PROTOCOL_VERSION] : undefined;\n return version === null ? undefined : version;\n}\n\n/** The names a request may reach the server by: its loopback names on the port the request came in on, and those it was given. */\nfunction servedHosts(req: IncomingMessage, extra: readonly string[]): Set<string> {\n const port = req.socket.localPort;\n return new Set([`127.0.0.1:${port}`, `localhost:${port}`, `[::1]:${port}`, ...extra]);\n}\n\n/**\n * An Origin naming a site other than the server's own names and the origins\n * it was given; none at all is a client that is not a browser.\n */\nfunction foreignOrigin(origin: string | undefined, hosts: Set<string>, origins: readonly string[]): boolean {\n if (origin === undefined) return false;\n let url: URL;\n try { url = new URL(origin); } catch { return true; }\n return !(hosts.has(url.host.toLowerCase()) || origins.includes(url.origin));\n}\n\n/** Accept names JSON, directly or by a wildcard. */\nfunction acceptsJson(accept: string | undefined): boolean {\n return (accept ?? \"\").split(\",\").some((part) => {\n const type = part.split(\";\")[0].trim().toLowerCase();\n return type === \"application/json\" || type === \"application/*\" || type === \"*/*\";\n });\n}\n\nfunction isJsonType(contentType: string | undefined): boolean {\n return (contentType ?? \"\").toLowerCase().startsWith(\"application/json\");\n}\n\n/**\n * A JSON-RPC error. `id` is left out where the request's could not be read,\n * as the 2026-07-28 schema has it: an id is a string or a number, never null.\n */\nfunction answer(res: ServerResponse, status: number, error: RpcError, id?: RequestId): void {\n res.writeHead(status, { \"content-type\": \"application/json\" })\n .end(JSON.stringify({ jsonrpc: \"2.0\", ...(id !== undefined ? { id } : {}), error }));\n}\n\n/** The body's id, where it has one a response can carry. */\nfunction idOf(body: unknown): RequestId | undefined {\n if (!isObject(body)) return undefined;\n const id = body.id;\n return typeof id === \"string\" || (typeof id === \"number\" && Number.isInteger(id)) ? id : undefined;\n}\n\nclass BodyTooLarge extends Error {}\n\n/**\n * The body, read up to `limit` bytes and parsed. Undefined when it has been\n * answered here: 413 over the limit, 400 when it is not JSON, and nothing\n * at all when the client went away before its body arrived, so a call cut\n * short never runs.\n */\nasync function readJson(req: IncomingMessage, res: ServerResponse, limit: number): Promise<{ value: unknown } | undefined> {\n let text: string;\n try {\n text = await readBody(req, limit);\n } catch (err) {\n if (err instanceof BodyTooLarge) {\n answer(res, 413, { code: ErrorCode.InvalidRequest, message: `Payload Too Large: Request body must not exceed ${limit} bytes` });\n } else {\n res.destroy();\n }\n return undefined;\n }\n try {\n return { value: JSON.parse(text) };\n } catch {\n answer(res, 400, { code: ErrorCode.ParseError, message: \"Parse error\" });\n return undefined;\n }\n}\n\nasync function readBody(req: IncomingMessage, limit: number): Promise<string> {\n if (Number(req.headers[\"content-length\"]) > limit) throw new BodyTooLarge();\n const chunks: Buffer[] = [];\n let size = 0;\n for await (const chunk of req) {\n size += (chunk as Buffer).length;\n if (size > limit) throw new BodyTooLarge();\n chunks.push(chunk as Buffer);\n }\n return Buffer.concat(chunks).toString(\"utf8\");\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * A transport for one request: the server's handlers receive it, and the\n * first response they send is the answer. A notification the server sends\n * on the way is dropped, since the answer is one JSON object.\n */\nclass SingleExchangeTransport implements Transport {\n onclose?: () => void;\n onerror?: (error: Error) => void;\n onmessage?: (message: JSONRPCMessage) => void;\n\n constructor(private readonly onreply: (message: JSONRPCMessage) => void) {}\n\n async start(): Promise<void> {}\n\n async send(message: JSONRPCMessage): Promise<void> {\n if (\"id\" in message && (\"result\" in message || \"error\" in message)) this.onreply(message);\n }\n\n async close(): Promise<void> {\n this.onclose?.();\n }\n}\n"],"mappings":"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","names":["ErrorCode","ErrorCode","ErrorCode","ErrorCode","ErrorCode"]}
|