@orkestrel/mcp 0.0.7 → 0.0.9

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["#emitter","#name","#version","#tools","#call","#emitter","#transport","#name","#version","#timeout","#pending","#receive","#connected","#protocol","#request","#settle","#tool","#text","#nextId","#timeoutRequest"],"sources":["../../../src/core/constants.ts","../../../src/core/errors.ts","../../../src/core/validators.ts","../../../src/core/parsers.ts","../../../src/core/helpers.ts","../../../src/core/MCPServer.ts","../../../src/core/MCPClient.ts","../../../src/core/factories.ts"],"sourcesContent":["// MCP protocol revisions + the reserved JSON-RPC 2.0 error codes. The negotiated\n// protocol version is the current rev unless the client requests a supported\n// one (see `initializeResult` in ./helpers.js). Transport-level header names\n// (session / version headers) belong to the HTTP transport sub-chunk, NOT here.\n\n/** The MCP protocol revision this server implements (the default negotiated version). */\nexport const MCP_PROTOCOL_VERSION = '2025-06-18'\n\n/**\n * The MCP protocol revisions this server can negotiate.\n *\n * @remarks\n * `initialize` echoes the client's requested `protocolVersion` when it appears in\n * this list, else falls back to {@link MCP_PROTOCOL_VERSION}. Frozen so the list is\n * an immutable contract. The package does not advertise `2025-03-26` because that\n * revision mandates JSON-RPC batching, while this package accepts only individual\n * JSON-RPC messages.\n */\nexport const SUPPORTED_PROTOCOL_VERSIONS: readonly string[] = Object.freeze(['2025-06-18'])\n\n/** JSON-RPC 2.0 reserved error: invalid JSON was received (the message did not parse). */\nexport const JSONRPC_PARSE_ERROR = -32700\n\n/** JSON-RPC 2.0 reserved error: the payload was not a valid Request object. */\nexport const JSONRPC_INVALID_REQUEST = -32600\n\n/** JSON-RPC 2.0 reserved error: the requested method does not exist. */\nexport const JSONRPC_METHOD_NOT_FOUND = -32601\n\n/** JSON-RPC 2.0 reserved error: the method's parameters were invalid. */\nexport const JSONRPC_INVALID_PARAMS = -32602\n\n/** JSON-RPC 2.0 implementation-defined server error (the `-32000` to `-32099` range). */\nexport const JSONRPC_SERVER_ERROR = -32000\n\n// MCP CLIENT defaults — the identity an `MCPClient` reports in the `initialize`\n// handshake (`clientInfo`) and the per-request deadline, when the caller supplies\n// none. The egress mirror of the server's protocol-version constants above.\n\n/** The default client name reported in the MCP `initialize` handshake (`clientInfo.name`). */\nexport const DEFAULT_MCP_CLIENT_NAME = 'taverna'\n\n/** The default client version reported in the MCP `initialize` handshake (`clientInfo.version`). */\nexport const DEFAULT_MCP_CLIENT_VERSION = '1.0.0'\n\n/**\n * The default per-request deadline (ms) an `MCPClient` applies when `options.timeout`\n * is unset — a request the remote server does not answer within it rejects.\n */\nexport const DEFAULT_MCP_REQUEST_TIMEOUT = 30_000\n","/**\n * A remote Model Context Protocol JSON-RPC error, preserving its machine-readable\n * numeric code and optional structured context.\n *\n * @remarks\n * {@link MCPClient} throws this error only for a remote JSON-RPC `error` response.\n * Local lifecycle and transport conditions such as disconnects and request timeouts\n * remain plain `Error`s. `context` carries the response's optional `error.data`\n * unchanged and is `undefined` when the peer omitted it.\n *\n * @example\n * ```ts\n * const error = new MCPError('Method not found', -32601, { method: 'missing' })\n * error.code // -32601\n * error.context // { method: 'missing' }\n * ```\n */\nexport class MCPError extends Error {\n\toverride readonly name = 'MCPError'\n\treadonly code: number\n\treadonly context: unknown\n\n\t/**\n\t * Create a remote MCP protocol error.\n\t *\n\t * @param message - The human-readable JSON-RPC error message\n\t * @param code - The machine-readable numeric JSON-RPC error code\n\t * @param context - The optional JSON-RPC `error.data` payload\n\t */\n\tconstructor(message: string, code: number, context?: unknown) {\n\t\tsuper(message)\n\t\tthis.code = code\n\t\tthis.context = context\n\t}\n}\n\n/**\n * Determine whether an unknown value is an {@link MCPError}.\n *\n * @param value - The unknown value to inspect\n * @returns `true` only when the value is an `MCPError`\n *\n * @example\n * ```ts\n * isMCPError(new MCPError('Method not found', -32601)) // true\n * isMCPError(new Error('Method not found')) // false\n * ```\n */\nexport function isMCPError(value: unknown): value is MCPError {\n\ttry {\n\t\t// A revoked Proxy or a hostile prototype can make `instanceof` throw — this guard\n\t\t// must stay total, so the check is wrapped rather than left to escape.\n\t\treturn value instanceof MCPError\n\t} catch {\n\t\treturn false\n\t}\n}\n","import type { JSONRPCMessage, JSONRPCRequest, JSONRPCResponse } from './types.js'\nimport { isNumber, isRecord, isString, isUndefined } from '@orkestrel/contract'\n\n// AGENTS §14: every guard here is a TOTAL function over the already-`JSON.parse`d\n// value — adversarial input returns `false`, never throws. The raw-string\n// `JSON.parse` (which CAN throw) happens in `MCPServer.handle` inside a try/catch;\n// these guards only ever see a parsed `unknown`. Each is a flat structural test on\n// `isRecord` + field checks (no user callbacks), so totality is immediate.\n\n/**\n * Determine whether a value is a valid JSON-RPC REQUEST `id` — a string, a number,\n * or absent.\n *\n * @remarks\n * A request id is a string, a number, or `undefined` (its ABSENCE marks a\n * NOTIFICATION). `null` is NOT a valid request id — it is valid only on a RESPONSE.\n * Total (§14): any other input returns `false`.\n *\n * @param value - The already-parsed value to test\n * @returns `true` when `value` is a string, a number, or `undefined`\n *\n * @example\n * ```ts\n * isRequestId(1) // true\n * isRequestId('abc') // true\n * isRequestId(undefined) // true — a notification\n * isRequestId(null) // false — valid only on a response\n * ```\n */\nexport function isRequestId(value: unknown): value is string | number | undefined {\n\treturn isUndefined(value) || isString(value) || isNumber(value)\n}\n\n/**\n * Determine whether a parsed value is a {@link JSONRPCRequest}.\n *\n * @remarks\n * A request is a record with `jsonrpc === '2.0'` and a string `method`. `id`, when\n * present, must be a string or number; its ABSENCE is valid — that marks a\n * NOTIFICATION (a fire-and-forget request that yields no response). `params`, when\n * present, must be a record. Total (§14): any other input returns `false`.\n *\n * @param value - The already-parsed value to test\n * @returns `true` when `value` is a valid JSON-RPC request\n *\n * @example\n * ```ts\n * isJSONRPCRequest({ jsonrpc: '2.0', method: 'ping', id: 1 }) // true\n * isJSONRPCRequest({ jsonrpc: '2.0', method: 'notifications/initialized' }) // true — a notification\n * isJSONRPCRequest({ jsonrpc: '1.0', method: 'ping' }) // false\n * ```\n */\nexport function isJSONRPCRequest(value: unknown): value is JSONRPCRequest {\n\tif (!isRecord(value)) {\n\t\treturn false\n\t}\n\tif (value['jsonrpc'] !== '2.0' || !isString(value['method'])) {\n\t\treturn false\n\t}\n\tif (!isRequestId(value['id'])) {\n\t\treturn false\n\t}\n\tconst params = value['params']\n\treturn isUndefined(params) || isRecord(params)\n}\n\n/**\n * Determine whether a parsed value is a {@link JSONRPCResponse}.\n *\n * @remarks\n * A response is a record with `jsonrpc === '2.0'`, an `id` that is a string,\n * number, or `null`, and EXACTLY ONE of a `result` (any value, including\n * `undefined`'s absence) or an `error` (a record with a numeric `code` and string\n * `message`). Total (§14).\n *\n * @param value - The already-parsed value to test\n * @returns `true` when `value` is a valid JSON-RPC response\n */\nexport function isJSONRPCResponse(value: unknown): value is JSONRPCResponse {\n\tif (!isRecord(value)) {\n\t\treturn false\n\t}\n\tif (value['jsonrpc'] !== '2.0') {\n\t\treturn false\n\t}\n\tconst id = value['id']\n\tif (id !== null && !isString(id) && !isNumber(id)) {\n\t\treturn false\n\t}\n\tconst hasResult = Object.hasOwn(value, 'result')\n\tconst error = value['error']\n\tconst hasError = !isUndefined(error)\n\t// Exactly one of result / error — never both, never neither.\n\tif (hasResult === hasError) {\n\t\treturn false\n\t}\n\tif (hasError) {\n\t\treturn isRecord(error) && isNumber(error['code']) && isString(error['message'])\n\t}\n\treturn true\n}\n\n/**\n * Determine whether a parsed value is a {@link JSONRPCMessage} — a request or a\n * response.\n *\n * @remarks\n * The union of {@link isJSONRPCRequest} and {@link isJSONRPCResponse}. Total (§14).\n *\n * @param value - The already-parsed value to test\n * @returns `true` when `value` is a valid JSON-RPC request or response\n */\nexport function isJSONRPCMessage(value: unknown): value is JSONRPCMessage {\n\treturn isJSONRPCRequest(value) || isJSONRPCResponse(value)\n}\n\n/**\n * Determine whether a parsed value is an MCP `initialize` request — a\n * {@link JSONRPCRequest} whose `method` is `'initialize'`.\n *\n * @param value - The already-parsed value to test\n * @returns `true` when `value` is a valid `initialize` request\n *\n * @example\n * ```ts\n * isInitializeRequest({ jsonrpc: '2.0', method: 'initialize', id: 1 }) // true\n * isInitializeRequest({ jsonrpc: '2.0', method: 'ping', id: 1 }) // false\n * ```\n */\nexport function isInitializeRequest(value: unknown): value is JSONRPCRequest {\n\treturn isJSONRPCRequest(value) && value.method === 'initialize'\n}\n","import type { JSONRPCMessage } from './types.js'\nimport { isJSONRPCMessage } from './validators.js'\n\n/**\n * Narrow an already-parsed value to a {@link JSONRPCMessage}, or `undefined` when\n * it is not one.\n *\n * @remarks\n * Total (§14) — a non-message returns `undefined`, never throws. The input must\n * ALREADY be `JSON.parse`d: the raw-string parse (which can throw on malformed\n * JSON) happens in `MCPServer.handle` inside a try/catch that maps a parse failure\n * to a `-32700` response. Sound with {@link isJSONRPCMessage}: a guard-valid input\n * is returned unchanged, and every non-`undefined` output satisfies the guard.\n *\n * @param value - The already-parsed value to narrow\n * @returns The value as a {@link JSONRPCMessage}, or `undefined`\n *\n * @example\n * ```ts\n * parseJSONRPCMessage({ jsonrpc: '2.0', method: 'ping', id: 1 }) // the request\n * parseJSONRPCMessage({ method: 'ping' }) // undefined — missing jsonrpc\n * ```\n */\nexport function parseJSONRPCMessage(value: unknown): JSONRPCMessage | undefined {\n\treturn isJSONRPCMessage(value) ? value : undefined\n}\n","import type { ToolManagerInterface, ToolResult } from '@orkestrel/agent'\nimport type {\n\tJSONRPCResponse,\n\tMCPClientInterface,\n\tMCPServerInterface,\n\tMCPToolDescriptor,\n\tMCPToolResult,\n\tMCPTransportInterface,\n} from './types.js'\nimport { MCP_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS } from './constants.js'\nimport { parseJSONRPCMessage } from './parsers.js'\n\n// Pure dispatch builders (AGENTS §5: the dispatch branches stay exported helpers,\n// not hidden privates). Each turns a piece of MCP state into the JSON-RPC `result`\n// payload (or a response envelope) the server returns — independently testable.\n\n/**\n * Build a JSON-RPC success {@link JSONRPCResponse} — the `id` echoed, the method's\n * value as `result`.\n *\n * @param id - The request's id (`null` only for a parse / invalid-request error)\n * @param result - The method's return value\n * @returns The success response envelope\n */\nexport function jsonRPCResult(id: string | number | null, result: unknown): JSONRPCResponse {\n\treturn { jsonrpc: '2.0', id, result }\n}\n\n/**\n * Build a JSON-RPC error {@link JSONRPCResponse} — the `id` echoed, the failure as\n * an `error` object.\n *\n * @param id - The request's id (`null` for a parse / invalid-request error)\n * @param code - One of the reserved JSON-RPC codes (see `./constants.js`)\n * @param message - A short human description of the failure\n * @param data - An OPTIONAL machine-readable payload (omitted from the envelope when absent)\n * @returns The error response envelope\n */\nexport function jsonRPCError(\n\tid: string | number | null,\n\tcode: number,\n\tmessage: string,\n\tdata?: unknown,\n): JSONRPCResponse {\n\treturn {\n\t\tjsonrpc: '2.0',\n\t\tid,\n\t\terror: data === undefined ? { code, message } : { code, message, data },\n\t}\n}\n\n/**\n * Map a {@link ToolManagerInterface}'s definitions to MCP `tools/list` descriptors\n * — renaming `parameters` to the wire's `inputSchema`.\n *\n * @remarks\n * Each {@link import('@orkestrel/agent').ToolDefinition} carries through its\n * `name` and (when present) `description`; its open JSON-Schema `parameters`\n * becomes `inputSchema`, defaulting to an empty object schema (`{ type: 'object' }`)\n * when a tool declares none (MCP requires an `inputSchema`).\n *\n * @param manager - The tool registry to describe\n * @returns One {@link MCPToolDescriptor} per registered tool, in registry order\n */\nexport function buildToolDescriptors(manager: ToolManagerInterface): readonly MCPToolDescriptor[] {\n\treturn manager.definitions().map((definition) => {\n\t\tconst descriptor: {\n\t\t\tname: string\n\t\t\tdescription?: string\n\t\t\tinputSchema: Readonly<Record<string, unknown>>\n\t\t} = {\n\t\t\tname: definition.name,\n\t\t\tinputSchema: definition.parameters ?? { type: 'object' },\n\t\t}\n\t\tif (definition.description !== undefined) descriptor.description = definition.description\n\t\treturn descriptor\n\t})\n}\n\n/**\n * Map an executed tool's {@link ToolResult} to an MCP {@link MCPToolResult} — the\n * value (or error) as a `text` content block.\n *\n * @remarks\n * The {@link ToolManagerInterface} already isolates a thrown tool into\n * `result.error` (so the server adds NO try/catch around `execute`): when `error`\n * is present, this builds an `isError: true` result carrying the error text, so the\n * model sees the failure as a tool result it can react to rather than a protocol\n * error; otherwise it serializes `result.value` (via `JSON.stringify`) into one\n * `text` block.\n *\n * @param result - The tool's execution outcome\n * @returns The MCP tool-call result\n */\nexport function buildToolResult(result: ToolResult): MCPToolResult {\n\tif (result.error !== undefined) {\n\t\treturn { content: [{ type: 'text', text: result.error }], isError: true }\n\t}\n\t// A content block must carry a string `text`; `JSON.stringify(undefined)` is the value\n\t// `undefined` (which serializes away), so a value-less result becomes an empty text block.\n\tconst text = result.value === undefined ? '' : JSON.stringify(result.value)\n\treturn { content: [{ type: 'text', text }] }\n}\n\n/**\n * Build the MCP `initialize` result — the negotiated protocol version, the\n * advertised capabilities, and the server identity.\n *\n * @remarks\n * Version negotiation echoes the client's `requested` version when it is one of the\n * {@link SUPPORTED_PROTOCOL_VERSIONS}, else falls back to {@link MCP_PROTOCOL_VERSION}.\n * `capabilities.tools` is an empty object — this server advertises the tools\n * capability with no sub-options (no list-changed notification yet).\n *\n * @param name - The server name (echoed in `serverInfo`)\n * @param version - The server version (echoed in `serverInfo`)\n * @param requested - The client's requested protocol version (negotiated when supported)\n * @returns The `initialize` result payload\n */\nexport function initializeResult(\n\tname: string,\n\tversion: string,\n\trequested?: string,\n): Readonly<Record<string, unknown>> {\n\tconst protocolVersion =\n\t\trequested !== undefined && SUPPORTED_PROTOCOL_VERSIONS.includes(requested)\n\t\t\t? requested\n\t\t\t: MCP_PROTOCOL_VERSION\n\treturn {\n\t\tprotocolVersion,\n\t\tcapabilities: { tools: {} },\n\t\tserverInfo: { name, version },\n\t}\n}\n\n// The environment-agnostic PORT binders — the keystone that lets an\n// {@link MCPServerInterface} / {@link MCPClientInterface} run over ANY\n// {@link MCPTransportInterface} (a Node stdio pair, a browser MessagePort, a Web\n// Worker `self`) with no per-environment dispatch/correlation wiring duplicated at\n// each face. Both are TOTAL: a `send` throw or rejection is caught and never\n// escapes as an unhandled rejection.\n\n/**\n * Pipe an {@link MCPTransportInterface} into an {@link MCPServerInterface} — every\n * inbound message runs through `server.handle`, and a defined reply is written back\n * via `transport.send`.\n *\n * @remarks\n * `server.handle` already turns a malformed message into a serialized `-32700` /\n * `-32600` reply and a notification into `undefined` (no reply), so this binder adds\n * no parsing of its own. A `transport.send` throw or rejection is caught and routed\n * to `server.emitter`'s `error` event (never rethrown, never an unhandled rejection);\n * a listener on that event that itself throws is swallowed (the end of the line —\n * the caller's own bug, never this binder's). The returned unbind DETACHES this\n * binder (further inbound messages and the transport's `closed` signal are ignored)\n * WITHOUT closing the transport — closing is the caller's decision.\n *\n * `listen`/`closed` are REPLACE semantics (§ port contract): the returned unbind\n * DETACHES by replacing this binder's own handlers with no-ops, so a subsequent\n * `bindServer` call on the SAME transport is never double-dispatched by a stale\n * subscription left behind — an unbind→rebind cycle yields exactly one reply per\n * request.\n *\n * @param server - The transport-agnostic server to dispatch inbound messages over\n * @param transport - The duplex channel to pipe the server over\n * @returns Detach this binder from the transport (does not close it)\n *\n * @example\n * ```ts\n * const unbind = bindServer(server, transport)\n * // ... later, detach without closing:\n * unbind()\n * ```\n */\nexport function bindServer(\n\tserver: MCPServerInterface,\n\ttransport: MCPTransportInterface,\n): () => void {\n\tlet active = true\n\ttransport.listen(async (message) => {\n\t\tif (!active) return\n\t\ttry {\n\t\t\tconst response = await server.handle(message)\n\t\t\tif (response !== undefined) await transport.send(response)\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tserver.emitter.emit('error', error)\n\t\t\t} catch {\n\t\t\t\t// A throwing `error` listener is the caller's own bug — the end of the line.\n\t\t\t}\n\t\t}\n\t})\n\ttransport.closed(() => {\n\t\tactive = false\n\t})\n\treturn () => {\n\t\tactive = false\n\t\ttransport.listen(() => {})\n\t\ttransport.closed(() => {})\n\t}\n}\n\n/**\n * Pipe an {@link MCPTransportInterface} into an {@link MCPClientInterface} — every\n * inbound message is decoded and delivered onto the client's OWN transport\n * (`client.transport.emitter`'s `message` / `close` events), resolving/rejecting the\n * client's correlated pending requests exactly as a direct reply would.\n *\n * @remarks\n * The client's outbound writes flow through `client.transport.send` — its existing,\n * unmodified request/response correlation — so `client` must have been constructed\n * with a {@link import('./types.js').ClientTransportInterface} that itself carries\n * the SAME `transport` (see {@link import('./factories.js').createDuplexClientTransport},\n * the additive factory that adapts an {@link MCPTransportInterface} into that shape);\n * this binder then completes the inbound half by decoding each message and pushing it\n * onto `client.transport.emitter` (an {@link import('@orkestrel/emitter').EmitterInterface}\n * exposes `emit`, so no client modification is needed). A malformed / non-JSON-RPC\n * inbound message is DROPPED (§14, total — never throws); a delivery fault is routed to\n * `client.transport.emitter`'s `error` event (never rethrown). The returned unbind\n * DETACHES this binder (further inbound messages and the transport's `closed` signal are\n * ignored) WITHOUT closing the transport.\n *\n * `listen`/`closed` are REPLACE semantics (§ port contract): the returned unbind\n * DETACHES by replacing this binder's own handlers with no-ops, so a subsequent\n * `bindClient` call on the SAME transport is never double-dispatched by a stale\n * subscription left behind — an unbind→rebind cycle delivers exactly one `message`\n * emit per inbound reply.\n *\n * @param client - The transport-agnostic client whose transport to deliver messages onto\n * @param transport - The duplex channel to pipe the client over\n * @returns Detach this binder from the transport (does not close it)\n *\n * @example\n * ```ts\n * const client = createMCPClient({ transport: createDuplexClientTransport(transport) })\n * const unbind = bindClient(client, transport)\n * await client.connect()\n * // ... later, detach without closing:\n * unbind()\n * ```\n */\nexport function bindClient(\n\tclient: MCPClientInterface,\n\ttransport: MCPTransportInterface,\n): () => void {\n\tlet active = true\n\ttransport.listen((message) => {\n\t\tif (!active) return\n\t\tlet parsed: unknown\n\t\ttry {\n\t\t\tparsed = JSON.parse(message)\n\t\t} catch {\n\t\t\treturn\n\t\t}\n\t\tconst decoded = parseJSONRPCMessage(parsed)\n\t\tif (decoded === undefined) return\n\t\ttry {\n\t\t\tclient.transport.emitter.emit('message', decoded)\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tclient.transport.emitter.emit('error', error)\n\t\t\t} catch {\n\t\t\t\t// A throwing `error` listener is the caller's own bug — the end of the line.\n\t\t\t}\n\t\t}\n\t})\n\ttransport.closed(() => {\n\t\tif (!active) return\n\t\tactive = false\n\t\ttry {\n\t\t\tclient.transport.emitter.emit('close')\n\t\t} catch {\n\t\t\t// A throwing `close` listener is the caller's own bug — the end of the line.\n\t\t}\n\t})\n\treturn () => {\n\t\tactive = false\n\t\ttransport.listen(() => {})\n\t\ttransport.closed(() => {})\n\t}\n}\n","import type { EmitterInterface } from '@orkestrel/emitter'\nimport type { ToolManagerInterface } from '@orkestrel/agent'\nimport type {\n\tJSONRPCRequest,\n\tJSONRPCResponse,\n\tMCPServerEventMap,\n\tMCPServerInterface,\n\tMCPServerOptions,\n} from './types.js'\nimport { Emitter } from '@orkestrel/emitter'\nimport { isRecord, isString } from '@orkestrel/contract'\nimport {\n\tJSONRPC_INVALID_PARAMS,\n\tJSONRPC_INVALID_REQUEST,\n\tJSONRPC_METHOD_NOT_FOUND,\n\tJSONRPC_PARSE_ERROR,\n} from './constants.js'\nimport {\n\tbuildToolDescriptors,\n\tbuildToolResult,\n\tinitializeResult,\n\tjsonRPCError,\n\tjsonRPCResult,\n} from './helpers.js'\nimport { parseJSONRPCMessage } from './parsers.js'\n\n/**\n * A transport-agnostic Model Context Protocol server — dispatches JSON-RPC 2.0\n * requests over a live {@link ToolManagerInterface}, with NO transport coupling.\n *\n * @remarks\n * - **Two entry points.** `dispatch(request)` runs an already-parsed request and\n * resolves a {@link JSONRPCResponse} — or `undefined` for a NOTIFICATION (a\n * request with no `id`). `handle(message)` is the string boundary: it\n * `JSON.parse`s the raw message (a failure → a `-32700` response), narrows it to\n * a request (a non-request → a `-32600` response), dispatches, and serializes the\n * response back to a string (`undefined` for a notification).\n * - **The method switch.** `initialize` negotiates the protocol version + advertises\n * the tools capability; `notifications/initialized` is a notification (no\n * response); `ping` returns `{}`; `tools/list` lists the registry's tools (its\n * `parameters` renamed to `inputSchema`); `tools/call` runs a tool by name (the\n * {@link ToolManagerInterface} isolates a tool throw into the result `error`, which\n * maps to an `isError: true` tool result — so the server adds NO try/catch). An\n * unknown method → `-32601`; a `tools/call` with a missing / non-string `name` →\n * `-32602`.\n * - **Provider-agnostic.** Imports only core siblings — JSON-RPC + the tool registry,\n * no HTTP, no model. Wire fields are narrowed via the contracts guards (no `as`).\n * - **Observable (§13).** The owned `emitter` fires `request` at the top of every\n * dispatch; the emitter isolates a listener throw and routes it to its `error` handler\n * (the `error` option), so a listener throw can never escape the dispatch.\n *\n * @example\n * ```ts\n * const tools = createToolManager()\n * tools.add(createTool({ name: 'add', execute: (a) => Number(a.x) + Number(a.y) }))\n * const server = new MCPServer({ name: 'demo', version: '1.0.0', tools })\n * await server.handle('{\"jsonrpc\":\"2.0\",\"method\":\"ping\",\"id\":1}') // '{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{}}'\n * ```\n */\nexport class MCPServer implements MCPServerInterface {\n\treadonly #emitter: Emitter<MCPServerEventMap>\n\treadonly #name: string\n\treadonly #version: string\n\treadonly #tools: ToolManagerInterface\n\n\tconstructor(options: MCPServerOptions) {\n\t\tthis.#emitter = new Emitter<MCPServerEventMap>({\n\t\t\t...(options.on !== undefined ? { on: options.on } : {}),\n\t\t\t...(options.error !== undefined ? { error: options.error } : {}),\n\t\t})\n\t\tthis.#name = options.name\n\t\tthis.#version = options.version\n\t\tthis.#tools = options.tools\n\t}\n\n\tget emitter(): EmitterInterface<MCPServerEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tget name(): string {\n\t\treturn this.#name\n\t}\n\n\tget version(): string {\n\t\treturn this.#version\n\t}\n\n\tasync dispatch(request: JSONRPCRequest): Promise<JSONRPCResponse | undefined> {\n\t\tconst id = request.id ?? null\n\t\tthis.#emitter.emit('request', request.method, id)\n\t\t// JSON-RPC: a request with NO `id` is a NOTIFICATION — it is handled (the\n\t\t// `request` event already fired) but NEVER produces a response, whatever its\n\t\t// method (`notifications/initialized`, a fire-and-forget `ping`, an unknown\n\t\t// method — all silent). So short-circuit here, and the switch below only ever\n\t\t// runs for an id-bearing request that expects a reply.\n\t\tif (request.id === undefined) {\n\t\t\treturn undefined\n\t\t}\n\t\tswitch (request.method) {\n\t\t\tcase 'initialize': {\n\t\t\t\tconst requested = request.params?.['protocolVersion']\n\t\t\t\treturn jsonRPCResult(\n\t\t\t\t\tid,\n\t\t\t\t\tinitializeResult(this.#name, this.#version, isString(requested) ? requested : undefined),\n\t\t\t\t)\n\t\t\t}\n\t\t\tcase 'ping':\n\t\t\t\treturn jsonRPCResult(id, {})\n\t\t\tcase 'tools/list':\n\t\t\t\treturn jsonRPCResult(id, { tools: buildToolDescriptors(this.#tools) })\n\t\t\tcase 'tools/call':\n\t\t\t\treturn this.#call(request, id)\n\t\t\tdefault:\n\t\t\t\treturn jsonRPCError(id, JSONRPC_METHOD_NOT_FOUND, `Method not found: ${request.method}`)\n\t\t}\n\t}\n\n\tasync handle(message: string): Promise<string | undefined> {\n\t\tlet parsed: unknown\n\t\ttry {\n\t\t\tparsed = JSON.parse(message)\n\t\t} catch {\n\t\t\treturn JSON.stringify(jsonRPCError(null, JSONRPC_PARSE_ERROR, 'Parse error'))\n\t\t}\n\t\tconst decoded = parseJSONRPCMessage(parsed)\n\t\t// Only a REQUEST is dispatchable — a response (or any non-message) is invalid input.\n\t\tif (decoded === undefined || !('method' in decoded)) {\n\t\t\treturn JSON.stringify(jsonRPCError(null, JSONRPC_INVALID_REQUEST, 'Invalid Request'))\n\t\t}\n\t\tconst response = await this.dispatch(decoded)\n\t\treturn response === undefined ? undefined : JSON.stringify(response)\n\t}\n\n\t// Run a `tools/call`: narrow `params.name` (string) + `params.arguments` (record,\n\t// default `{}`) with no `as`, execute the tool (the manager isolates a throw into\n\t// `result.error`), and map the result to an MCP tool-call result.\n\tasync #call(request: JSONRPCRequest, id: string | number | null): Promise<JSONRPCResponse> {\n\t\tconst params = request.params\n\t\tconst name = params?.['name']\n\t\tif (!isString(name)) {\n\t\t\treturn jsonRPCError(id, JSONRPC_INVALID_PARAMS, 'Invalid params: a string `name` is required')\n\t\t}\n\t\tconst rawArguments = params?.['arguments']\n\t\tconst args = isRecord(rawArguments) ? rawArguments : {}\n\t\tconst callId = request.id === undefined ? crypto.randomUUID() : String(request.id)\n\t\tconst result = await this.#tools.execute({ id: callId, name, arguments: args })\n\t\treturn jsonRPCResult(id, buildToolResult(result))\n\t}\n}\n","import type { EmitterInterface } from '@orkestrel/emitter'\nimport type { ToolInterface } from '@orkestrel/agent'\nimport type {\n\tClientTransportInterface,\n\tJSONRPCMessage,\n\tJSONRPCRequest,\n\tMCPClientEventMap,\n\tMCPClientInterface,\n\tMCPClientOptions,\n} from './types.js'\nimport { Emitter } from '@orkestrel/emitter'\nimport { Tool } from '@orkestrel/agent'\nimport { isArray, isRecord, isString } from '@orkestrel/contract'\nimport {\n\tDEFAULT_MCP_CLIENT_NAME,\n\tDEFAULT_MCP_CLIENT_VERSION,\n\tDEFAULT_MCP_REQUEST_TIMEOUT,\n\tMCP_PROTOCOL_VERSION,\n\tSUPPORTED_PROTOCOL_VERSIONS,\n} from './constants.js'\nimport { MCPError } from './errors.js'\nimport { isJSONRPCResponse, isRequestId } from './validators.js'\n\n/**\n * A transport-agnostic Model Context Protocol CLIENT — connects to a REMOTE MCP server\n * over an injected {@link ClientTransportInterface}, runs the `initialize` handshake,\n * and exposes the server's tools as local {@link ToolInterface}s an agent can run.\n *\n * @remarks\n * - **The mirror of `MCPServer`.** The server DISPATCHES requests over a tool registry;\n * this client ISSUES them over a transport. `connect` runs `initialize`, validates and\n * exposes the negotiated `protocol`, then sends `notifications/initialized`; `tools()`\n * lists the remote tools and wraps each as a\n * local {@link ToolInterface} whose `execute` calls back through `call`; `call` runs a\n * remote `tools/call` and returns the tool's value (a remote `isError: true` throws\n * locally, so an agent's {@link import('@orkestrel/agent').ToolManagerInterface}\n * isolates it into a result `error` just like a local throw).\n * - **Request↔response correlation.** Each request is tagged with a monotonic numeric\n * `id` ({@link #nextId}); a single transport `message` subscription resolves / rejects\n * the matching {@link #pending} entry by `id`. A message that is NOT a response to a\n * pending request is a server NOTIFICATION — re-surfaced on the `notification` event.\n * - **Per-request deadline.** `#request` races `AbortSignal.timeout(this.#timeout)` (the\n * taverna idiom — never a raw `setTimeout`): a server that never replies REJECTS the\n * pending request once the deadline fires, never hanging.\n * - **Transport-agnostic.** Imports only core siblings (JSON-RPC + the tool vocabulary);\n * the concrete transport is injected. Wire fields are narrowed via the contracts\n * guards (no `as`).\n * - **Observable (§13).** The owned `emitter` fires `connect` / `disconnect` /\n * `notification` / `error`; the emitter isolates a listener throw and routes it to its\n * `error` handler (the `error` option), so a listener throw can never escape.\n *\n * @example\n * ```ts\n * const client = new MCPClient({ transport, name: 'agent', version: '1.0.0' })\n * await client.connect()\n * const tools = await client.tools()\n * agent.context.tools.add(tools) // the remote tools are now the agent's\n * const value = await client.call('search', { query: 'mcp' })\n * ```\n */\nexport class MCPClient implements MCPClientInterface {\n\treadonly #emitter: Emitter<MCPClientEventMap>\n\treadonly #transport: ClientTransportInterface\n\treadonly #name: string\n\treadonly #version: string\n\treadonly #timeout: number\n\t// The in-flight requests, keyed by JSON-RPC id, each holding its promise settlers —\n\t// resolved on the matching response, rejected on an error response, the deadline, or\n\t// `disconnect`. Genuinely private glue (§5): the settler shape lives inline here.\n\treadonly #pending = new Map<\n\t\tstring | number,\n\t\t{\n\t\t\treadonly resolve: (value: unknown) => void\n\t\t\treadonly reject: (reason?: unknown) => void\n\t\t\treadonly deadline: AbortSignal\n\t\t\treadonly timeout: () => void\n\t\t}\n\t>()\n\t#nextId = 0\n\t#connected = false\n\t#protocol: string | undefined = undefined\n\n\tconstructor(options: MCPClientOptions) {\n\t\tthis.#emitter = new Emitter<MCPClientEventMap>({\n\t\t\t...(options.on !== undefined ? { on: options.on } : {}),\n\t\t\t...(options.error !== undefined ? { error: options.error } : {}),\n\t\t})\n\t\tthis.#transport = options.transport\n\t\tthis.#name = options.name ?? DEFAULT_MCP_CLIENT_NAME\n\t\tthis.#version = options.version ?? DEFAULT_MCP_CLIENT_VERSION\n\t\tthis.#timeout = options.timeout ?? DEFAULT_MCP_REQUEST_TIMEOUT\n\t\t// One message subscription for the client's whole life: a response settles its\n\t\t// pending request by id; anything else is a server notification.\n\t\tthis.#transport.emitter.on('message', (message) => this.#receive(message))\n\t}\n\n\tget emitter(): EmitterInterface<MCPClientEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tget connected(): boolean {\n\t\treturn this.#connected\n\t}\n\n\tget protocol(): string | undefined {\n\t\treturn this.#protocol\n\t}\n\n\tget transport(): ClientTransportInterface {\n\t\treturn this.#transport\n\t}\n\n\ton<K extends keyof MCPClientEventMap>(\n\t\tevent: K,\n\t\thandler: (...args: MCPClientEventMap[K]) => void,\n\t): void {\n\t\tthis.#emitter.on(event, handler)\n\t}\n\n\tasync connect(): Promise<void> {\n\t\tif (this.#connected) return\n\t\tawait this.#transport.start()\n\t\t// The MCP handshake: negotiate the protocol version + advertise (empty) client\n\t\t// capabilities + identify ourselves, then mark connected and fire the no-args\n\t\t// `notifications/initialized` (a notification — no id, no response).\n\t\tconst result = await this.#request('initialize', {\n\t\t\tprotocolVersion: MCP_PROTOCOL_VERSION,\n\t\t\tcapabilities: {},\n\t\t\tclientInfo: { name: this.#name, version: this.#version },\n\t\t})\n\t\tconst protocol = isRecord(result) ? result['protocolVersion'] : undefined\n\t\tif (!isString(protocol) || !SUPPORTED_PROTOCOL_VERSIONS.includes(protocol)) {\n\t\t\tawait this.#transport.close()\n\t\t\tif (isString(protocol)) {\n\t\t\t\tthrow new Error(`MCP server negotiated unsupported protocol version '${protocol}'`)\n\t\t\t}\n\t\t\tthrow new Error('MCP server returned a non-string protocol version')\n\t\t}\n\t\tthis.#protocol = protocol\n\t\tthis.#connected = true\n\t\tawait this.#transport.send({ jsonrpc: '2.0', method: 'notifications/initialized' })\n\t\tthis.#emitter.emit('connect')\n\t}\n\n\tasync disconnect(): Promise<void> {\n\t\tif (!this.#connected) return\n\t\tthis.#connected = false\n\t\tthis.#protocol = undefined\n\t\t// Reject every still-pending request so no caller hangs past a disconnect, then\n\t\t// clear the map and tear the transport down.\n\t\tfor (const id of this.#pending.keys()) {\n\t\t\tthis.#settle(id, new Error('MCP client disconnected'), true)\n\t\t}\n\t\tawait this.#transport.close()\n\t\tthis.#emitter.emit('disconnect')\n\t}\n\n\tasync tools(): Promise<readonly ToolInterface[]> {\n\t\tconst result = await this.#request('tools/list')\n\t\t// The wire shape is `{ tools: MCPToolDescriptor[] }` — narrow it (§14): a\n\t\t// non-record / non-array `tools` yields no tools rather than throwing.\n\t\tif (!isRecord(result) || !isArray(result['tools'])) return []\n\t\tconst tools: ToolInterface[] = []\n\t\tfor (const descriptor of result['tools']) {\n\t\t\tif (!isRecord(descriptor) || !isString(descriptor['name'])) continue\n\t\t\tconst name = descriptor['name']\n\t\t\ttools.push(this.#tool(name, descriptor))\n\t\t}\n\t\treturn tools\n\t}\n\n\tasync call(name: string, args: Readonly<Record<string, unknown>>): Promise<unknown> {\n\t\tconst result = await this.#request('tools/call', { name, arguments: args })\n\t\t// The inverse of the server's `buildToolResult`: concat the result's text blocks,\n\t\t// then either throw (a remote `isError`) or parse the JSON value.\n\t\tconst text = this.#text(result)\n\t\tif (isRecord(result) && result['isError'] === true) {\n\t\t\tthrow new Error(text.length > 0 ? text : `MCP tool '${name}' failed`)\n\t\t}\n\t\t// A success carries the value JSON-serialized into the text block(s); parse it,\n\t\t// falling back to the raw string when it is not JSON (the inverse of the server's\n\t\t// `JSON.stringify`, whose value-less result is an empty text block).\n\t\tif (text.length === 0) return undefined\n\t\ttry {\n\t\t\treturn JSON.parse(text)\n\t\t} catch {\n\t\t\treturn text\n\t\t}\n\t}\n\n\t// Issue a request and await its correlated response, bounded by the per-request\n\t// deadline. A monotonic numeric id keys the pending settlers; `AbortSignal.timeout`\n\t// (the taverna idiom — never a raw setTimeout) rejects the pending request if the\n\t// server never answers. The transport `send` is awaited so a write failure rejects\n\t// here rather than leaving a pending request to time out.\n\t#request(method: string, params?: Readonly<Record<string, unknown>>): Promise<unknown> {\n\t\tthis.#nextId += 1\n\t\tconst id = this.#nextId\n\t\tconst request: JSONRPCRequest = {\n\t\t\tjsonrpc: '2.0',\n\t\t\tid,\n\t\t\tmethod,\n\t\t\t...(params === undefined ? {} : { params }),\n\t\t}\n\t\treturn new Promise<unknown>((resolve, reject) => {\n\t\t\tconst deadline = AbortSignal.timeout(this.#timeout)\n\t\t\tconst timeout = this.#timeoutRequest.bind(this, id, method)\n\t\t\tdeadline.addEventListener('abort', timeout, { once: true })\n\t\t\tthis.#pending.set(id, { resolve, reject, deadline, timeout })\n\t\t\tthis.#transport.send(request).catch((error: unknown) => {\n\t\t\t\tthis.#settle(id, error instanceof Error ? error : new Error(String(error)), true)\n\t\t\t})\n\t\t})\n\t}\n\n\t// Handle one inbound transport message: a response settles its pending request by\n\t// id (an error response rejects, a result resolves); anything else (a message with\n\t// no matching pending id) is a server-initiated notification, re-surfaced on the\n\t// `notification` event.\n\t#receive(message: JSONRPCMessage): void {\n\t\tif (isJSONRPCResponse(message) && isRequestId(message.id)) {\n\t\t\tif (this.#pending.has(message.id)) {\n\t\t\t\tif (message.error !== undefined) {\n\t\t\t\t\tthis.#settle(\n\t\t\t\t\t\tmessage.id,\n\t\t\t\t\t\tnew MCPError(message.error.message, message.error.code, message.error.data),\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t)\n\t\t\t\t} else {\n\t\t\t\t\tthis.#settle(message.id, message.result, false)\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\t// Not a correlated response — a server notification (or an unsolicited response).\n\t\tthis.#emitter.emit('notification', message)\n\t}\n\n\t// Wrap one remote tool descriptor as a local tool: map `inputSchema` → `parameters`\n\t// (the inverse of the server's rename, no `as`), carry `description` when present,\n\t// and bind `execute` to a remote `tools/call` via `call`.\n\t#tool(name: string, descriptor: Readonly<Record<string, unknown>>): ToolInterface {\n\t\tconst inputSchema = descriptor['inputSchema']\n\t\tconst description = descriptor['description']\n\t\tconst options: {\n\t\t\tname: string\n\t\t\tdescription?: string\n\t\t\tparameters?: Readonly<Record<string, unknown>>\n\t\t\texecute: (args: Readonly<Record<string, unknown>>) => Promise<unknown>\n\t\t} = {\n\t\t\tname,\n\t\t\texecute: this.call.bind(this, name),\n\t\t}\n\t\tif (isString(description)) options.description = description\n\t\tif (isRecord(inputSchema)) options.parameters = inputSchema\n\t\treturn new Tool(options)\n\t}\n\n\t// Concatenate an MCP tool-call result's text content blocks into one string — the\n\t// inverse of the server splitting a value into text block(s). Total (§14): a\n\t// non-record result, a non-array `content`, or a non-string `text` contributes\n\t// nothing rather than throwing.\n\t#text(result: unknown): string {\n\t\tif (!isRecord(result) || !isArray(result['content'])) return ''\n\t\tconst parts: string[] = []\n\t\tfor (const block of result['content']) {\n\t\t\tif (isRecord(block) && isString(block['text'])) parts.push(block['text'])\n\t\t}\n\t\treturn parts.join('\\n')\n\t}\n\n\t#timeoutRequest(id: string | number, method: string): void {\n\t\tthis.#settle(id, new Error(`MCP request '${method}' timed out after ${this.#timeout}ms`), true)\n\t}\n\n\t#settle(id: string | number, value: unknown, failed: boolean): void {\n\t\tconst pending = this.#pending.get(id)\n\t\tif (pending === undefined) return\n\t\tthis.#pending.delete(id)\n\t\tpending.deadline.removeEventListener('abort', pending.timeout)\n\t\tif (failed) pending.reject(value)\n\t\telse pending.resolve(value)\n\t}\n}\n","import type {\n\tClientTransportEventMap,\n\tClientTransportInterface,\n\tJSONRPCMessage,\n\tMCPClientInterface,\n\tMCPClientOptions,\n\tMCPServerInterface,\n\tMCPServerOptions,\n\tMCPTransportInterface,\n} from './types.js'\nimport { Emitter } from '@orkestrel/emitter'\nimport { MCPClient } from './MCPClient.js'\nimport { MCPServer } from './MCPServer.js'\n\n/**\n * Create a transport-agnostic Model Context Protocol server — exposes a live\n * {@link import('@orkestrel/agent').ToolManagerInterface} over JSON-RPC 2.0\n * (`initialize` / `ping` / `tools/list` / `tools/call`).\n *\n * @remarks\n * Pump raw message strings through `handle` (parse → dispatch → serialize) from a\n * transport, or call the typed `dispatch` directly with an already-parsed request.\n * The server is provider-agnostic — JSON-RPC plus the tool registry, with no HTTP\n * and no model. The {@link import('@orkestrel/agent').ToolManagerInterface} already\n * isolates a thrown tool into a result error (surfaced as an MCP `isError: true`\n * tool result), so a misbehaving tool never crashes a dispatch. Subscribe to the\n * `request` event via `server.emitter.on('request', …)` for tracing.\n *\n * @param options - `name` / `version` (the server identity), `tools` (the live\n * registry to expose), an optional `description`, and the reserved `on`\n * {@link import('@orkestrel/emitter').EmitterHooks} (see {@link MCPServerOptions})\n * @returns A working {@link MCPServerInterface}\n *\n * @example\n * ```ts\n * import { createMCPServer, createTool, createToolManager } from '@src/core'\n *\n * const tools = createToolManager()\n * tools.add(createTool({ name: 'add', execute: (a) => Number(a.x) + Number(a.y) }))\n *\n * const server = createMCPServer({ name: 'calculator', version: '1.0.0', tools })\n * server.emitter.on('request', (method, id) => log(method, id))\n *\n * // A transport pumps message strings through `handle`:\n * const reply = await server.handle('{\"jsonrpc\":\"2.0\",\"method\":\"tools/list\",\"id\":1}')\n * // reply → '{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"tools\":[{\"name\":\"add\",\"inputSchema\":{\"type\":\"object\"}}]}}'\n * ```\n */\nexport function createMCPServer(options: MCPServerOptions): MCPServerInterface {\n\treturn new MCPServer(options)\n}\n\n/**\n * Create a transport-agnostic Model Context Protocol CLIENT — connects to a REMOTE\n * MCP server over an injected {@link import('./types.js').ClientTransportInterface},\n * runs the `initialize` handshake, and exposes the server's tools as local\n * {@link import('@orkestrel/agent').ToolInterface}s an agent can run.\n *\n * @remarks\n * The egress mirror of {@link createMCPServer}: where the server exposes a local tool\n * registry over MCP, the client USES a remote server's tools. `connect()` handshakes,\n * validates and exposes the negotiated protocol, `tools()` lists + wraps the remote\n * tools (each `execute` calls back over the wire),\n * and `call(name, args)` runs a remote `tools/call` (a remote tool failure throws\n * locally, so an agent's {@link import('@orkestrel/agent').ToolManagerInterface}\n * isolates it). The transport is injected — a concrete one (the HTTP transport over\n * `fetch`) lives in `@src/server`; the client itself is provider-agnostic. Subscribe\n * to `connect` / `disconnect` / `notification` via `client.on(...)` (or\n * `client.emitter.on(...)`).\n *\n * @param options - `transport` (the carrier; REQUIRED), `name` / `version` (the client\n * identity), `timeout` (the per-request deadline), and the reserved `on`\n * {@link import('@orkestrel/emitter').EmitterHooks} (see {@link MCPClientOptions})\n * @returns A working {@link MCPClientInterface}\n *\n * @example\n * ```ts\n * import { createMCPClient } from '@src/core'\n * import { createHTTPClientTransport } from '@src/server'\n *\n * const client = createMCPClient({\n * \ttransport: createHTTPClientTransport({ url: 'http://localhost:3000/mcp' }),\n * })\n * await client.connect()\n * agent.context.tools.add(await client.tools()) // give the agent the remote tools\n * const value = await client.call('search', { query: 'mcp' })\n * ```\n */\nexport function createMCPClient(options: MCPClientOptions): MCPClientInterface {\n\treturn new MCPClient(options)\n}\n\n/**\n * Adapt an {@link MCPTransportInterface} (the environment-agnostic duplex message\n * channel) into a {@link ClientTransportInterface} — the additive bridge that lets\n * `createMCPClient` run over the new port without any change to `MCPClient`'s\n * existing shape.\n *\n * @remarks\n * Hand the RESULT to `createMCPClient({ transport })`, then pass the SAME\n * `transport` to {@link import('./helpers.js').bindClient} to complete the inbound\n * wiring: `send` serializes each outbound {@link JSONRPCMessage} and writes it via\n * `transport.send`; `close` closes the underlying\n * `transport`; `start` is a no-op (the duplex channel is already open by the time\n * it is handed in — there is no separate connect step at this layer); `session` is\n * always `undefined` (session correlation is a higher-level concern the duplex port\n * does not carry). Inbound delivery (`emitter`'s `message` / `close` events) is\n * `bindClient`'s job, not this factory's — the returned object exposes a `message`-\n * capable emitter for `bindClient` to push onto.\n *\n * @param transport - The duplex channel to adapt\n * @returns A {@link ClientTransportInterface} `createMCPClient` can drive\n *\n * @example\n * ```ts\n * const client = createMCPClient({ transport: createDuplexClientTransport(transport) })\n * const unbind = bindClient(client, transport)\n * await client.connect()\n * ```\n */\nexport function createDuplexClientTransport(\n\ttransport: MCPTransportInterface,\n): ClientTransportInterface {\n\tconst emitter = new Emitter<ClientTransportEventMap>()\n\treturn {\n\t\temitter,\n\t\tsession: undefined,\n\t\tasync start(): Promise<void> {\n\t\t\t// The duplex channel is already open by the time it is handed in — no separate\n\t\t\t// connect step at this layer.\n\t\t},\n\t\tasync send(message: JSONRPCMessage): Promise<void> {\n\t\t\tawait transport.send(JSON.stringify(message))\n\t\t},\n\t\tasync close(): Promise<void> {\n\t\t\tawait transport.close()\n\t\t},\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["#handlers","#emitter","#options","#methods","#limits","#register","#modern","#legacy","#runTool","#discover","#list","#call","#subscribe","#input","#required","#subscription","#subscriptions","#emitter","#transport","#identity","#capabilities","#pin","#timeout","#probe","#pending","#offer","#receive","#connected","#version","#era","#initialize","#request","#settle","#tool","#text","#nextId","#timeoutRequest"],"sources":["../../../src/core/constants.ts","../../../src/core/errors.ts","../../../src/core/validators.ts","../../../src/core/parsers.ts","../../../src/core/inferers.ts","../../../src/core/helpers.ts","../../../src/core/MCPMethodManager.ts","../../../src/core/MCPServer.ts","../../../src/core/MCPClient.ts","../../../src/core/factories.ts"],"sourcesContent":["import type { MCPVersion } from './types.js'\n\n// MCP protocol revisions, reserved modern `_meta` keys, and protocol error codes.\n// Transport-level header names (session / version headers) belong to the HTTP\n// transport, not core.\n\n/**\n * The revision offered and defaulted to in the legacy `initialize` handshake.\n *\n * @remarks\n * This is deliberately a legacy revision, and the newest one supported. 2026-07-28 is stateless\n * and defines no `initialize`, so it can never be the handshake's version — a client that offers\n * it is asking to negotiate a revision with no negotiation.\n */\nexport const MCP_PROTOCOL_VERSION: MCPVersion = '2025-11-25'\n\n/** The legacy fallback anchor used when an initialize request cannot be accepted as modern. */\nexport const MCP_LEGACY_VERSION: MCPVersion = '2025-06-18'\n\n/** The modern revision offered by an unpinned client during discovery. */\nexport const MCP_MODERN_VERSION: MCPVersion = '2026-07-28'\n\n/**\n * The MCP protocol revisions this server can negotiate.\n *\n * @remarks\n * `initialize` echoes the client's requested `protocolVersion` when it appears in\n * this list. Frozen in client-preference and discovery-advertisement order. The\n * package does not advertise `2025-03-26` because that revision mandates JSON-RPC\n * batching, while this package accepts only individual JSON-RPC messages.\n */\nexport const SUPPORTED_PROTOCOL_VERSIONS: readonly MCPVersion[] = Object.freeze([\n\t'2026-07-28',\n\t'2025-11-25',\n\t'2025-06-18',\n])\n\n/** Reserved modern `_meta` key carrying the request's protocol revision. */\nexport const MCP_META_VERSION = 'io.modelcontextprotocol/protocolVersion'\n\n/** Reserved modern `_meta` key carrying the client's open capability record. */\nexport const MCP_META_CAPABILITIES = 'io.modelcontextprotocol/clientCapabilities'\n\n/** Reserved modern `_meta` key carrying the optional client identity. */\nexport const MCP_META_CLIENT = 'io.modelcontextprotocol/clientInfo'\n\n/** Reserved modern `_meta` key carrying the server identity on results. */\nexport const MCP_META_SERVER = 'io.modelcontextprotocol/serverInfo'\n\n/** Reserved modern `_meta` key carrying a `subscriptions/listen` request id. */\nexport const MCP_META_SUBSCRIPTION = 'io.modelcontextprotocol/subscriptionId'\n\n/** MCP reserved error: required HTTP metadata does not match the request body. */\nexport const MCP_HEADER_MISMATCH = -32020\n\n/** MCP reserved error: an operation needs a client capability that was not declared. */\nexport const MCP_MISSING_CAPABILITY = -32021\n\n/** MCP reserved error: a request names an unsupported protocol revision. */\nexport const MCP_UNSUPPORTED_VERSION = -32022\n\n/**\n * Default modern result freshness lifetime in milliseconds.\n *\n * @remarks\n * `ttlMs` is required on cacheable results, while zero means immediately stale\n * rather than uncached, so the neutral usable default is one minute.\n */\nexport const DEFAULT_MCP_CACHE_TTL = 60_000\n\n/**\n * Secure server bounds used when the matching `limit` option leaf is absent or malformed.\n *\n * @remarks\n * One MiB admits ordinary JSON-RPC requests and substantial tool arguments; 16 KiB admits\n * extension-rich modern metadata and signed multi-round state; four MiB admits substantial\n * JSON tool output without allowing an unconfigured service to serialize arbitrary process\n * memory; 64 metadata keys admits the reserved keys plus many extensions; 128 concurrent\n * streams admits a busy service while bounding retained producers; depth 32 admits ordinary\n * JSON documents while rejecting stack-hostile nesting. Frozen so callers cannot alter the\n * defaults observed by later servers.\n */\nexport const DEFAULT_MCP_LIMITS = Object.freeze({\n\tmessage: 1_048_576,\n\tmetadata: 16_384,\n\tkeys: 64,\n\tstate: 16_384,\n\tcontent: 4_194_304,\n\tsubscriptions: 128,\n\tdepth: 32,\n})\n\n/** JSON-RPC 2.0 reserved error: invalid JSON was received (the message did not parse). */\nexport const JSONRPC_PARSE_ERROR = -32700\n\n/** JSON-RPC 2.0 reserved error: the payload was not a valid Request object. */\nexport const JSONRPC_INVALID_REQUEST = -32600\n\n/** JSON-RPC 2.0 reserved error: the requested method does not exist. */\nexport const JSONRPC_METHOD_NOT_FOUND = -32601\n\n/** JSON-RPC 2.0 reserved error: the method's parameters were invalid. */\nexport const JSONRPC_INVALID_PARAMS = -32602\n\n/** JSON-RPC 2.0 implementation-defined server error (the `-32000` to `-32099` range). */\nexport const JSONRPC_SERVER_ERROR = -32000\n\n// MCP CLIENT defaults — the identity an `MCPClient` reports in the `initialize`\n// handshake (`clientInfo`) and the per-request deadline, when the caller supplies\n// none. The egress mirror of the server's protocol-version constants above.\n\n/** The default client name reported in the MCP `initialize` handshake (`clientInfo.name`). */\nexport const DEFAULT_MCP_CLIENT_NAME = 'taverna'\n\n/** The default client version reported in the MCP `initialize` handshake (`clientInfo.version`). */\nexport const DEFAULT_MCP_CLIENT_VERSION = '1.0.0'\n\n/**\n * The default per-request deadline (ms) an `MCPClient` applies when `options.timeout`\n * is unset — a request the remote server does not answer within it rejects.\n */\nexport const DEFAULT_MCP_REQUEST_TIMEOUT = 30_000\n\n/** The maximum discovery-probe deadline used when a client deadline is configured. */\nexport const DEFAULT_MCP_PROBE_TIMEOUT = 50\n","/**\n * A remote Model Context Protocol JSON-RPC error, preserving its machine-readable\n * numeric code and optional structured context.\n *\n * @remarks\n * {@link MCPClient} throws this error only for a remote JSON-RPC `error` response.\n * Local lifecycle and transport conditions such as disconnects and request timeouts\n * remain plain `Error`s. `context` carries the response's optional `error.data`\n * unchanged and is `undefined` when the peer omitted it. This includes the modern\n * reserved paths: `-32020` carries no context, `-32021` may carry\n * `requiredCapabilities`, and `-32022` carries the peer's `supported` revisions and\n * `requested` revision for negotiation recovery.\n *\n * @example\n * ```ts\n * const error = new MCPError('Unsupported protocol version', -32022, {\n * \tsupported: ['2026-07-28'],\n * \trequested: '2024-11-05',\n * })\n * error.code // -32022\n * error.context // { supported: ['2026-07-28'], requested: '2024-11-05' }\n * ```\n */\nexport class MCPError extends Error {\n\toverride readonly name = 'MCPError'\n\treadonly code: number\n\treadonly context: unknown\n\n\t/**\n\t * Create a remote MCP protocol error.\n\t *\n\t * @param message - The human-readable JSON-RPC error message\n\t * @param code - The machine-readable numeric JSON-RPC error code\n\t * @param context - The optional JSON-RPC `error.data` payload\n\t */\n\tconstructor(message: string, code: number, context?: unknown) {\n\t\tsuper(message)\n\t\tthis.code = code\n\t\tthis.context = context\n\t}\n}\n\n/**\n * Determine whether an unknown value is an {@link MCPError}.\n *\n * @param value - The unknown value to inspect\n * @returns `true` only when the value is an `MCPError`\n *\n * @example\n * ```ts\n * isMCPError(new MCPError('Method not found', -32601)) // true\n * isMCPError(new Error('Method not found')) // false\n * ```\n */\nexport function isMCPError(value: unknown): value is MCPError {\n\ttry {\n\t\t// A revoked Proxy or a hostile prototype can make `instanceof` throw — this guard\n\t\t// must stay total, so the check is wrapped rather than left to escape.\n\t\treturn value instanceof MCPError\n\t} catch {\n\t\treturn false\n\t}\n}\n","import type { JSONValue } from '@orkestrel/contract'\nimport type {\n\tElicitRequest,\n\tElicitRequestFormParams,\n\tElicitRequestURLParams,\n\tElicitPrimitiveSchema,\n\tElicitResult,\n\tInputRequest,\n\tInputRequiredResult,\n\tInputRequests,\n\tJSONRPCMessage,\n\tJSONRPCRequest,\n\tJSONRPCResponse,\n\tMCPJSONLimitOptions,\n\tMCPVersion,\n\tSubscriptionFilter,\n} from './types.js'\nimport {\n\tarrayOf,\n\tattempt,\n\tenumerableKeys,\n\tisBoolean,\n\tisNumber,\n\tisRecord,\n\tisString,\n\tisUndefined,\n\tsanitizeBudget,\n} from '@orkestrel/contract'\nimport { MCP_META_VERSION, SUPPORTED_PROTOCOL_VERSIONS } from './constants.js'\n\n// AGENTS §14: every guard here is a TOTAL function over the already-`JSON.parse`d\n// value — adversarial input returns `false`, never throws. The raw-string\n// `JSON.parse` (which CAN throw) happens in `MCPServer.handle` inside a try/catch;\n// these guards only ever see a parsed `unknown`. Recursive structure is walked\n// iteratively with explicit ancestor/depth bounds, and callback-capable boundaries use\n// `attempt`, so totality is preserved without relying on the JavaScript call stack.\n\n/**\n * Determine whether a value is a string within a UTF-8 byte bound.\n *\n * @param value - The unknown value to inspect\n * @param bytes - The maximum accepted encoded bytes\n * @returns `true` only for a string whose UTF-8 representation fits the bound\n *\n * @example\n * ```ts\n * isBoundedString('€', 3) // true\n * isBoundedString('€', 2) // false\n * ```\n */\nexport function isBoundedString(value: unknown, bytes: number): value is string {\n\tif (!isString(value) || !Number.isFinite(bytes) || !Number.isInteger(bytes) || bytes < 0) {\n\t\treturn false\n\t}\n\tlet measured = 0\n\tfor (let index = 0; index < value.length; index += 1) {\n\t\tconst code = value.charCodeAt(index)\n\t\tif (code <= 0x7f) measured += 1\n\t\telse if (code <= 0x7ff) measured += 2\n\t\telse if (code >= 0xd800 && code <= 0xdbff) {\n\t\t\tconst next = value.charCodeAt(index + 1)\n\t\t\tif (next >= 0xdc00 && next <= 0xdfff) {\n\t\t\t\tmeasured += 4\n\t\t\t\tindex += 1\n\t\t\t} else measured += 3\n\t\t} else measured += 3\n\t\tif (measured > bytes) return false\n\t}\n\treturn true\n}\n\n/**\n * Determine whether a value is bounded, cycle-free JSON with safe property names.\n *\n * @remarks\n * Traversal is iterative, ancestor-aware, and contained by {@link attempt}; deep input,\n * cycles, accessors, hostile proxies, `Map`/`Set`, and the prototype-pollution keys\n * `__proto__`, `constructor`, and `prototype` return `false` rather than throwing.\n * The byte count matches `JSON.stringify` without first allocating the serialization.\n *\n * @param value - The unknown value to inspect\n * @param limits - Serialized byte, optional key, and nesting-depth bounds\n * @returns `true` only for safe JSON satisfying every bound\n *\n * @example\n * ```ts\n * isBoundedJSON({ ok: true }, { bytes: 16, keys: 1, depth: 1 }) // true\n * ```\n */\nexport function isBoundedJSON<T>(value: T, limits: MCPJSONLimitOptions): value is T & JSONValue {\n\tconst outcome = attempt(() => {\n\t\tconst limit = sanitizeBudget(limits.bytes, 0)\n\t\tconst depth = sanitizeBudget(limits.depth, 0)\n\t\tconst breadth = limits.keys === undefined ? undefined : sanitizeBudget(limits.keys, 0)\n\t\tlet bytes = 0\n\t\tlet keys = 0\n\t\tconst ancestors = new WeakSet<object>()\n\t\tconst pending: { value: unknown; depth: number; closing: boolean }[] = [\n\t\t\t{ value, depth: 0, closing: false },\n\t\t]\n\t\twhile (pending.length > 0) {\n\t\t\tconst frame = pending.pop()\n\t\t\tif (frame === undefined) return false\n\t\t\tconst entry = frame.value\n\t\t\tif (frame.closing) {\n\t\t\t\tif (typeof entry !== 'object' || entry === null) return false\n\t\t\t\tancestors.delete(entry)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif (frame.depth > depth) return false\n\t\t\tif (entry === null) bytes += 4\n\t\t\telse if (isBoolean(entry)) bytes += entry ? 4 : 5\n\t\t\t// A non-finite number is still serializable: `JSON.stringify` writes `NaN` and\n\t\t\t// ±`Infinity` as `null`, so they cost four bytes rather than being rejected. Only\n\t\t\t// `undefined` is genuinely absent from JSON, and it stays rejected below.\n\t\t\telse if (isNumber(entry)) bytes += Number.isFinite(entry) ? String(entry).length : 4\n\t\t\telse if (isString(entry)) {\n\t\t\t\tbytes += 2\n\t\t\t\tif (bytes > limit) return false\n\t\t\t\tfor (let index = 0; index < entry.length; index += 1) {\n\t\t\t\t\tconst code = entry.charCodeAt(index)\n\t\t\t\t\tif (\n\t\t\t\t\t\tcode === 0x22 ||\n\t\t\t\t\t\tcode === 0x5c ||\n\t\t\t\t\t\tcode === 0x08 ||\n\t\t\t\t\t\tcode === 0x09 ||\n\t\t\t\t\t\tcode === 0x0a ||\n\t\t\t\t\t\tcode === 0x0c ||\n\t\t\t\t\t\tcode === 0x0d\n\t\t\t\t\t) {\n\t\t\t\t\t\tbytes += 2\n\t\t\t\t\t} else if (code <= 0x1f) bytes += 6\n\t\t\t\t\telse if (code <= 0x7f) bytes += 1\n\t\t\t\t\telse if (code <= 0x7ff) bytes += 2\n\t\t\t\t\telse if (code >= 0xd800 && code <= 0xdbff) {\n\t\t\t\t\t\tconst next = entry.charCodeAt(index + 1)\n\t\t\t\t\t\tif (next >= 0xdc00 && next <= 0xdfff) {\n\t\t\t\t\t\t\tbytes += 4\n\t\t\t\t\t\t\tindex += 1\n\t\t\t\t\t\t} else bytes += 6\n\t\t\t\t\t} else if (code >= 0xdc00 && code <= 0xdfff) bytes += 6\n\t\t\t\t\telse bytes += 3\n\t\t\t\t\tif (bytes > limit) return false\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t} else if (typeof entry === 'object') {\n\t\t\t\tif (ancestors.has(entry)) return false\n\t\t\t\tconst names = enumerableKeys(entry)\n\t\t\t\tif (names === undefined) return false\n\t\t\t\tfor (const name of names) {\n\t\t\t\t\tif (name === '__proto__' || name === 'constructor' || name === 'prototype') {\n\t\t\t\t\t\treturn false\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (Array.isArray(entry)) {\n\t\t\t\t\tbytes += 2 + Math.max(0, entry.length - 1)\n\t\t\t\t\tif (bytes > limit || names.length !== entry.length) return false\n\t\t\t\t\tancestors.add(entry)\n\t\t\t\t\tpending.push({ value: entry, depth: frame.depth, closing: true })\n\t\t\t\t\tfor (let index = entry.length - 1; index >= 0; index -= 1) {\n\t\t\t\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(entry, String(index))\n\t\t\t\t\t\tif (descriptor === undefined || !Object.hasOwn(descriptor, 'value')) return false\n\t\t\t\t\t\tpending.push({ value: descriptor.value, depth: frame.depth + 1, closing: false })\n\t\t\t\t\t}\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (!isRecord(entry)) return false\n\t\t\t\tkeys += names.length\n\t\t\t\tif (breadth !== undefined && keys > breadth) return false\n\t\t\t\tbytes += 2 + Math.max(0, names.length - 1) + names.length\n\t\t\t\tif (bytes > limit) return false\n\t\t\t\tancestors.add(entry)\n\t\t\t\tpending.push({ value: entry, depth: frame.depth, closing: true })\n\t\t\t\tfor (let index = names.length - 1; index >= 0; index -= 1) {\n\t\t\t\t\tconst name = names[index]\n\t\t\t\t\tif (name === undefined) return false\n\t\t\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(entry, name)\n\t\t\t\t\tif (descriptor === undefined || !Object.hasOwn(descriptor, 'value')) return false\n\t\t\t\t\tpending.push({ value: descriptor.value, depth: frame.depth + 1, closing: false })\n\t\t\t\t\tpending.push({ value: name, depth: frame.depth, closing: false })\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t} else return false\n\t\t\tif (bytes > limit) return false\n\t\t}\n\t\treturn bytes <= limit\n\t})\n\treturn outcome.success && outcome.value\n}\n\n/**\n * Determine whether a value is a valid JSON-RPC REQUEST `id` — a string, a number,\n * or absent.\n *\n * @remarks\n * A request id is a string, a number, or `undefined` (its ABSENCE marks a\n * NOTIFICATION). `null` is NOT a valid request id — it is valid only on a RESPONSE.\n * Total (§14): any other input returns `false`.\n *\n * @param value - The already-parsed value to test\n * @returns `true` when `value` is a string, a number, or `undefined`\n *\n * @example\n * ```ts\n * isRequestId(1) // true\n * isRequestId('abc') // true\n * isRequestId(undefined) // true — a notification\n * isRequestId(null) // false — valid only on a response\n * ```\n */\nexport function isRequestId(value: unknown): value is string | number | undefined {\n\treturn isUndefined(value) || isString(value) || isNumber(value)\n}\n\n/**\n * Determine whether a value is a supported {@link MCPVersion}.\n *\n * @param value - The unknown value to inspect\n * @returns `true` when the value is one of {@link SUPPORTED_PROTOCOL_VERSIONS}\n */\nexport function isMCPVersion(value: unknown): value is MCPVersion {\n\treturn isString(value) && SUPPORTED_PROTOCOL_VERSIONS.some((version) => version === value)\n}\n\n/**\n * Determine whether a value is an MCP {@link SubscriptionFilter}.\n *\n * @remarks\n * Every filter field is optional. Boolean notification families accept only booleans, and\n * `resourceSubscriptions` accepts only an array of string URIs. Unknown fields remain open\n * for protocol extensions and are ignored by the built-in subscription matcher. Total over\n * hostile input.\n *\n * @param value - The unknown value to inspect\n * @returns `true` when every recognized filter field has its protocol shape\n */\nexport function isSubscriptionFilter(value: unknown): value is SubscriptionFilter {\n\tif (!isRecord(value)) return false\n\tconst tools = value['toolsListChanged']\n\tif (!isUndefined(tools) && !isBoolean(tools)) return false\n\tconst prompts = value['promptsListChanged']\n\tif (!isUndefined(prompts) && !isBoolean(prompts)) return false\n\tconst resources = value['resourcesListChanged']\n\tif (!isUndefined(resources) && !isBoolean(resources)) return false\n\tconst subscriptions = value['resourceSubscriptions']\n\treturn isUndefined(subscriptions) || arrayOf(isString)(subscriptions)\n}\n\n/**\n * Determine whether a client capability record declares form-mode elicitation.\n *\n * @remarks\n * The protocol's empty `elicitation` object is the implicit form-only declaration.\n * A non-empty declaration must carry a record-valued `form` member; URL-only support\n * does not authorize a form request. Total over hostile input.\n *\n * @param value - The client capability record to inspect\n * @returns `true` when form-mode elicitation is declared\n *\n * @example\n * ```ts\n * isFormElicitationSupported({ elicitation: {} }) // true — implicit form mode\n * isFormElicitationSupported({ elicitation: { url: {} } }) // false\n * ```\n */\nexport function isFormElicitationSupported(value: unknown): boolean {\n\ttry {\n\t\tif (!isRecord(value)) return false\n\t\tconst elicitation = value['elicitation']\n\t\tif (!isRecord(elicitation)) return false\n\t\tif (isRecord(elicitation['form'])) return true\n\t\treturn Object.keys(elicitation).length === 0\n\t} catch {\n\t\treturn false\n\t}\n}\n\n/**\n * Determine whether a value is one restricted primitive form-elicitation schema.\n *\n * @param value - The unknown value to inspect\n * @returns `true` for a supported boolean, numeric, string, or string-array schema\n *\n * @example\n * ```ts\n * isElicitPrimitiveSchema({ type: 'boolean', default: true }) // true\n * isElicitPrimitiveSchema({ type: 'object' }) // false\n * ```\n */\nexport function isElicitPrimitiveSchema(value: unknown): value is ElicitPrimitiveSchema {\n\ttry {\n\t\tif (!isRecord(value)) return false\n\t\tconst title = value['title']\n\t\tconst description = value['description']\n\t\tif (!isUndefined(title) && !isString(title)) return false\n\t\tif (!isUndefined(description) && !isString(description)) return false\n\n\t\tconst fallback = value['default']\n\t\tif (value['type'] === 'boolean') return isUndefined(fallback) || isBoolean(fallback)\n\t\tif (value['type'] === 'number' || value['type'] === 'integer') {\n\t\t\tconst minimum = value['minimum']\n\t\t\tconst maximum = value['maximum']\n\t\t\treturn (\n\t\t\t\t(isUndefined(minimum) || isNumber(minimum)) &&\n\t\t\t\t(isUndefined(maximum) || isNumber(maximum)) &&\n\t\t\t\t(isUndefined(fallback) || isNumber(fallback))\n\t\t\t)\n\t\t}\n\t\tif (value['type'] === 'string') {\n\t\t\tconst minimum = value['minLength']\n\t\t\tconst maximum = value['maxLength']\n\t\t\tconst format = value['format']\n\t\t\tconst choices = value['enum']\n\t\t\tconst names = value['enumNames']\n\t\t\tconst titled = value['oneOf']\n\t\t\treturn (\n\t\t\t\t(isUndefined(minimum) || isNumber(minimum)) &&\n\t\t\t\t(isUndefined(maximum) || isNumber(maximum)) &&\n\t\t\t\t(isUndefined(format) ||\n\t\t\t\t\tformat === 'uri' ||\n\t\t\t\t\tformat === 'email' ||\n\t\t\t\t\tformat === 'date' ||\n\t\t\t\t\tformat === 'date-time') &&\n\t\t\t\t(isUndefined(fallback) || isString(fallback)) &&\n\t\t\t\t(isUndefined(choices) || arrayOf(isString)(choices)) &&\n\t\t\t\t(isUndefined(names) || arrayOf(isString)(names)) &&\n\t\t\t\t(isUndefined(titled) ||\n\t\t\t\t\t(arrayOf(isRecord)(titled) &&\n\t\t\t\t\t\ttitled.every((choice) => isString(choice['const']) && isString(choice['title']))))\n\t\t\t)\n\t\t}\n\t\tif (value['type'] !== 'array') return false\n\t\tconst minimum = value['minItems']\n\t\tconst maximum = value['maxItems']\n\t\tconst items = value['items']\n\t\tif (\n\t\t\t(!isUndefined(minimum) && !isNumber(minimum)) ||\n\t\t\t(!isUndefined(maximum) && !isNumber(maximum)) ||\n\t\t\t(!isUndefined(fallback) && !arrayOf(isString)(fallback)) ||\n\t\t\t!isRecord(items)\n\t\t) {\n\t\t\treturn false\n\t\t}\n\t\tif (items['type'] === 'string') return arrayOf(isString)(items['enum'])\n\t\tconst choices = items['anyOf']\n\t\treturn (\n\t\t\tarrayOf(isRecord)(choices) &&\n\t\t\tchoices.every((choice) => isString(choice['const']) && isString(choice['title']))\n\t\t)\n\t} catch {\n\t\treturn false\n\t}\n}\n\n/**\n * Determine whether a value is a form-mode elicitation parameter object.\n *\n * @param value - The unknown value to inspect\n * @returns `true` when `value` has the restricted form elicitation shape\n *\n * @example\n * ```ts\n * isElicitRequestFormParams({\n * message: 'Continue?',\n * requestedSchema: { type: 'object', properties: {} },\n * }) // true\n * ```\n */\nexport function isElicitRequestFormParams(value: unknown): value is ElicitRequestFormParams {\n\ttry {\n\t\tif (!isRecord(value)) return false\n\t\tconst mode = value['mode']\n\t\tif (!isUndefined(mode) && mode !== 'form') return false\n\t\tif (!isString(value['message'])) return false\n\t\tconst schema = value['requestedSchema']\n\t\tif (!isRecord(schema) || schema['type'] !== 'object' || !isRecord(schema['properties'])) {\n\t\t\treturn false\n\t\t}\n\t\tconst dialect = schema['$schema']\n\t\tif (!isUndefined(dialect) && !isString(dialect)) return false\n\t\tconst required = schema['required']\n\t\treturn (\n\t\t\t(isUndefined(required) || arrayOf(isString)(required)) &&\n\t\t\tObject.values(schema['properties']).every((property) => isElicitPrimitiveSchema(property))\n\t\t)\n\t} catch {\n\t\treturn false\n\t}\n}\n\n/**\n * Determine whether a value is a URL-mode elicitation parameter object.\n *\n * @param value - The unknown value to inspect\n * @returns `true` when `value` has the URL elicitation shape\n *\n * @example\n * ```ts\n * isElicitRequestURLParams({ mode: 'url', message: 'Authenticate', url: 'https://example.test' })\n * ```\n */\nexport function isElicitRequestURLParams(value: unknown): value is ElicitRequestURLParams {\n\treturn (\n\t\tisRecord(value) &&\n\t\tvalue['mode'] === 'url' &&\n\t\tisString(value['message']) &&\n\t\tisString(value['url'])\n\t)\n}\n\n/**\n * Determine whether a value is an embedded `elicitation/create` request.\n *\n * @param value - The unknown value to inspect\n * @returns `true` when `value` is a form- or URL-mode elicitation request\n *\n * @example\n * ```ts\n * isElicitRequest({\n * method: 'elicitation/create',\n * params: { message: 'Continue?', requestedSchema: { type: 'object', properties: {} } },\n * }) // true\n * ```\n */\nexport function isElicitRequest(value: unknown): value is ElicitRequest {\n\tif (!isRecord(value) || value['method'] !== 'elicitation/create') return false\n\treturn isElicitRequestFormParams(value['params']) || isElicitRequestURLParams(value['params'])\n}\n\n/**\n * Determine whether a value is one legal embedded multi-round-trip request.\n *\n * @param value - The unknown value to inspect\n * @returns `true` for elicitation, deprecated sampling, or deprecated roots requests\n *\n * @example\n * ```ts\n * isInputRequest({ method: 'roots/list' }) // true — legal but not produced by this package\n * ```\n */\nexport function isInputRequest(value: unknown): value is InputRequest {\n\tif (isElicitRequest(value)) return true\n\tif (!isRecord(value)) return false\n\tconst params = value['params']\n\tif (value['method'] === 'sampling/createMessage') return isRecord(params)\n\treturn value['method'] === 'roots/list' && (isUndefined(params) || isRecord(params))\n}\n\n/**\n * Determine whether a value is a server-keyed map of embedded input requests.\n *\n * @param value - The unknown value to inspect\n * @returns `true` when every own value is a legal {@link InputRequest}\n *\n * @example\n * ```ts\n * isInputRequests({ confirm: { method: 'roots/list' } }) // true; maps, never arrays\n * ```\n */\nexport function isInputRequests(value: unknown): value is InputRequests {\n\ttry {\n\t\treturn isRecord(value) && Object.values(value).every((request) => isInputRequest(request))\n\t} catch {\n\t\treturn false\n\t}\n}\n\n/**\n * Determine whether a value is one elicitation response.\n *\n * @param value - The unknown value to inspect\n * @returns `true` when action/content have the protocol shape\n *\n * @example\n * ```ts\n * isElicitResult({ action: 'accept', content: { approved: true } }) // true\n * ```\n */\nexport function isElicitResult(value: unknown): value is ElicitResult {\n\ttry {\n\t\tif (!isRecord(value)) return false\n\t\tconst action = value['action']\n\t\tif (action !== 'accept' && action !== 'decline' && action !== 'cancel') return false\n\t\tconst content = value['content']\n\t\tif (isUndefined(content)) return true\n\t\tif (!isRecord(content)) return false\n\t\treturn Object.values(content).every(\n\t\t\t(item) => isString(item) || isNumber(item) || isBoolean(item) || arrayOf(isString)(item),\n\t\t)\n\t} catch {\n\t\treturn false\n\t}\n}\n\n/**\n * Determine whether a value is an MCP input-required result.\n *\n * @remarks\n * Enforces the at-least-one-of rule at runtime: `inputRequests`, `requestState`, or\n * both must be present and valid. Total over hostile input.\n *\n * @param value - The unknown value to inspect\n * @returns `true` when `value` is a valid input-required result\n *\n * @example\n * ```ts\n * isInputRequiredResult({ resultType: 'input_required', requestState: 'opaque' }) // true\n * isInputRequiredResult({ resultType: 'input_required' }) // false\n * ```\n */\nexport function isInputRequiredResult(value: unknown): value is InputRequiredResult {\n\ttry {\n\t\tif (!isRecord(value) || value['resultType'] !== 'input_required') return false\n\t\tconst inputRequests = value['inputRequests']\n\t\tconst requestState = value['requestState']\n\t\tif (!isUndefined(inputRequests) && !isInputRequests(inputRequests)) return false\n\t\tif (!isUndefined(requestState) && !isString(requestState)) return false\n\t\treturn !isUndefined(inputRequests) || !isUndefined(requestState)\n\t} catch {\n\t\treturn false\n\t}\n}\n\n/**\n * Determine whether a parsed value is a {@link JSONRPCRequest}.\n *\n * @remarks\n * A request is a record with `jsonrpc === '2.0'` and a string `method`. `id`, when\n * present, must be a string or number; its ABSENCE is valid — that marks a\n * NOTIFICATION (a fire-and-forget request that yields no response). `params`, when\n * present, must be a record. Total (§14): any other input returns `false`.\n *\n * @param value - The already-parsed value to test\n * @returns `true` when `value` is a valid JSON-RPC request\n *\n * @example\n * ```ts\n * isJSONRPCRequest({ jsonrpc: '2.0', method: 'ping', id: 1 }) // true\n * isJSONRPCRequest({ jsonrpc: '2.0', method: 'notifications/initialized' }) // true — a notification\n * isJSONRPCRequest({ jsonrpc: '1.0', method: 'ping' }) // false\n * ```\n */\nexport function isJSONRPCRequest(value: unknown): value is JSONRPCRequest {\n\tif (!isRecord(value)) {\n\t\treturn false\n\t}\n\tif (value['jsonrpc'] !== '2.0' || !isString(value['method'])) {\n\t\treturn false\n\t}\n\tif (!isRequestId(value['id'])) {\n\t\treturn false\n\t}\n\tconst params = value['params']\n\treturn isUndefined(params) || isRecord(params)\n}\n\n/**\n * Determine whether a parsed value is a {@link JSONRPCResponse}.\n *\n * @remarks\n * A response is a record with `jsonrpc === '2.0'`, an `id` that is a string,\n * number, or `null`, and EXACTLY ONE of a `result` (any value, including\n * `undefined`'s absence) or an `error` (a record with a numeric `code` and string\n * `message`). Total (§14).\n *\n * @param value - The already-parsed value to test\n * @returns `true` when `value` is a valid JSON-RPC response\n */\nexport function isJSONRPCResponse(value: unknown): value is JSONRPCResponse {\n\tif (!isRecord(value)) {\n\t\treturn false\n\t}\n\tif (value['jsonrpc'] !== '2.0') {\n\t\treturn false\n\t}\n\tconst id = value['id']\n\tif (id !== null && !isString(id) && !isNumber(id)) {\n\t\treturn false\n\t}\n\tconst hasResult = Object.hasOwn(value, 'result')\n\tconst error = value['error']\n\tconst hasError = !isUndefined(error)\n\t// Exactly one of result / error — never both, never neither.\n\tif (hasResult === hasError) {\n\t\treturn false\n\t}\n\tif (hasError) {\n\t\treturn isRecord(error) && isNumber(error['code']) && isString(error['message'])\n\t}\n\treturn true\n}\n\n/**\n * Determine whether a parsed value is a {@link JSONRPCMessage} — a request or a\n * response.\n *\n * @remarks\n * The union of {@link isJSONRPCRequest} and {@link isJSONRPCResponse}. Total (§14).\n *\n * @param value - The already-parsed value to test\n * @returns `true` when `value` is a valid JSON-RPC request or response\n */\nexport function isJSONRPCMessage(value: unknown): value is JSONRPCMessage {\n\treturn isJSONRPCRequest(value) || isJSONRPCResponse(value)\n}\n\n/**\n * Determine whether a parsed value is an MCP `initialize` request — a\n * {@link JSONRPCRequest} whose `method` is `'initialize'`.\n *\n * @param value - The already-parsed value to test\n * @returns `true` when `value` is a valid `initialize` request\n *\n * @example\n * ```ts\n * isInitializeRequest({ jsonrpc: '2.0', method: 'initialize', id: 1 }) // true\n * isInitializeRequest({ jsonrpc: '2.0', method: 'ping', id: 1 }) // false\n * ```\n */\nexport function isInitializeRequest(value: unknown): value is JSONRPCRequest {\n\treturn isJSONRPCRequest(value) && value.method === 'initialize'\n}\n\n/**\n * Determine whether a JSON-RPC request uses the modern per-request MCP wire shape.\n *\n * @remarks\n * Presence routes and validity answers: this guard checks only that\n * `params._meta` carries the reserved protocol-version key. The key's value is\n * deliberately not narrowed here, so a present non-string version remains modern\n * and is rejected later by `parseRequestContext` rather than falling through to\n * legacy dispatch. Total over hostile and malformed input.\n *\n * @param value - The already-parsed value to inspect\n * @returns `true` when the value is a request carrying the reserved version key\n */\nexport function isModernRequest(value: unknown): value is JSONRPCRequest {\n\ttry {\n\t\tif (!isJSONRPCRequest(value)) return false\n\t\tconst metadata = value.params?.['_meta']\n\t\treturn isRecord(metadata) && Object.hasOwn(metadata, MCP_META_VERSION)\n\t} catch {\n\t\treturn false\n\t}\n}\n","import type { JSONRPCMessage, MCPInputState, MCPRequestContext } from './types.js'\nimport { isNumber, isRecord, isString, isUndefined } from '@orkestrel/contract'\nimport { MCP_META_CAPABILITIES, MCP_META_CLIENT, MCP_META_VERSION } from './constants.js'\nimport { isJSONRPCMessage, isModernRequest } from './validators.js'\n\n/**\n * Narrow an already-parsed value to a {@link JSONRPCMessage}, or `undefined` when\n * it is not one.\n *\n * @remarks\n * Total (§14) — a non-message returns `undefined`, never throws. The input must\n * ALREADY be `JSON.parse`d: the raw-string parse (which can throw on malformed\n * JSON) happens in `MCPServer.handle` inside a try/catch that maps a parse failure\n * to a `-32700` response. Sound with {@link isJSONRPCMessage}: a guard-valid input\n * is returned unchanged, and every non-`undefined` output satisfies the guard.\n *\n * @param value - The already-parsed value to narrow\n * @returns The value as a {@link JSONRPCMessage}, or `undefined`\n *\n * @example\n * ```ts\n * parseJSONRPCMessage({ jsonrpc: '2.0', method: 'ping', id: 1 }) // the request\n * parseJSONRPCMessage({ method: 'ping' }) // undefined — missing jsonrpc\n * ```\n */\nexport function parseJSONRPCMessage(value: unknown): JSONRPCMessage | undefined {\n\treturn isJSONRPCMessage(value) ? value : undefined\n}\n\n/**\n * Parse the reserved modern request metadata into an {@link MCPRequestContext}.\n *\n * @remarks\n * This is the validity step after {@link isModernRequest}: a defined result can\n * only come from a guard-positive request, while a guard-positive request returns\n * `undefined` exactly when its required modern metadata is malformed. The version\n * must be a string but need not be supported; unsupported strings belong to the\n * dedicated protocol-version error path. Client identity is optional, but when\n * present it must carry string `name` and `version` members. Total over hostile and\n * malformed input.\n *\n * @param value - The already-parsed request candidate to coerce\n * @returns The validated modern request context, or `undefined`\n */\nexport function parseRequestContext(value: unknown): MCPRequestContext | undefined {\n\ttry {\n\t\tif (!isModernRequest(value)) return undefined\n\t\tconst metadata = value.params?.['_meta']\n\t\tif (!isRecord(metadata)) return undefined\n\t\tconst version = metadata[MCP_META_VERSION]\n\t\tconst capabilities = metadata[MCP_META_CAPABILITIES]\n\t\tif (!isString(version) || !isRecord(capabilities)) return undefined\n\t\tconst client = metadata[MCP_META_CLIENT]\n\t\tif (client === undefined) return { version, capabilities }\n\t\tif (!isRecord(client)) return undefined\n\t\tconst name = client['name']\n\t\tconst clientVersion = client['version']\n\t\tif (!isString(name) || !isString(clientVersion)) return undefined\n\t\treturn {\n\t\t\tversion,\n\t\t\tcapabilities,\n\t\t\tidentity: { name, version: clientVersion },\n\t\t}\n\t} catch {\n\t\treturn undefined\n\t}\n}\n\n/**\n * Parse the verified value embedded in an opaque signed `requestState` token.\n *\n * @remarks\n * This parser does not verify the HMAC; {@link import('@orkestrel/server').verifyToken}\n * performs that boundary first and returns the JSON string parsed here. The protected\n * payload binds the authenticated principal, token lifetime, originating request id,\n * server-assigned input key, tool name, and optional consumer state. Total over malformed\n * or hostile input.\n *\n * @param value - The HMAC-verified token value to parse\n * @returns The protected input state, or `undefined` when malformed\n *\n * @example\n * ```ts\n * parseMCPInputState('{\"principal\":\"user-1\",\"ttl\":1000,\"origin\":1,\"key\":\"k\",\"name\":\"reply\"}')\n * // { principal: 'user-1', ttl: 1000, origin: 1, key: 'k', name: 'reply' }\n * ```\n */\nexport function parseMCPInputState(value: unknown): MCPInputState | undefined {\n\ttry {\n\t\tif (!isString(value)) return undefined\n\t\tconst parsed: unknown = JSON.parse(value)\n\t\tif (!isRecord(parsed)) return undefined\n\t\tconst principal = parsed['principal']\n\t\tconst ttl = parsed['ttl']\n\t\tconst origin = parsed['origin']\n\t\tconst key = parsed['key']\n\t\tconst name = parsed['name']\n\t\tconst state = parsed['state']\n\t\tif (!isString(principal) || !isNumber(ttl) || !Number.isFinite(ttl)) return undefined\n\t\tif (!isString(origin) && !isNumber(origin)) return undefined\n\t\tif (!isString(key) || !isString(name)) return undefined\n\t\tif (!isUndefined(state) && !isString(state)) return undefined\n\t\treturn {\n\t\t\tprincipal,\n\t\t\tttl,\n\t\t\torigin,\n\t\t\tkey,\n\t\t\tname,\n\t\t\t...(isString(state) ? { state } : {}),\n\t\t}\n\t} catch {\n\t\treturn undefined\n\t}\n}\n","import type { MCPEra, MCPVersion } from './types.js'\nimport { SUPPORTED_PROTOCOL_VERSIONS } from './constants.js'\n\n/**\n * Infer the wire era for an MCP protocol revision.\n *\n * @param version - The protocol revision to classify\n * @returns `'modern'` for `2026-07-28`, `'legacy'` for either supported legacy\n * revision, or `undefined` when the revision is unsupported\n */\nexport function inferEra(version: string): MCPEra | undefined {\n\tswitch (version) {\n\t\tcase '2026-07-28':\n\t\t\treturn 'modern'\n\t\tcase '2025-11-25':\n\t\tcase '2025-06-18':\n\t\t\treturn 'legacy'\n\t\tdefault:\n\t\t\treturn undefined\n\t}\n}\n\n/**\n * Infer the newest supported protocol revision present in a peer's offer.\n *\n * @param offered - The protocol revisions offered by the peer\n * @returns The newest locally supported offered revision, or `undefined`\n */\nexport function inferVersion(offered: readonly string[]): MCPVersion | undefined {\n\tfor (const version of SUPPORTED_PROTOCOL_VERSIONS) {\n\t\tif (offered.includes(version)) return version\n\t}\n\treturn undefined\n}\n","import type { ToolManagerInterface, ToolResult } from '@orkestrel/tool'\nimport type {\n\tJSONRPCRequest,\n\tJSONRPCResponse,\n\tMCPCallResult,\n\tMCPClientInterface,\n\tMCPDiscoverResult,\n\tMCPIdentity,\n\tMCPServerInterface,\n\tMCPServerOptions,\n\tMCPStream,\n\tMCPTextStream,\n\tMCPToolDescriptor,\n\tMCPTransportInterface,\n\tSubscriptionFilter,\n\tSubscriptionsListenResult,\n\tSubscriptionsListenResultMetaObject,\n} from './types.js'\nimport { isRecord } from '@orkestrel/contract'\nimport {\n\tDEFAULT_MCP_CACHE_TTL,\n\tMCP_LEGACY_VERSION,\n\tMCP_META_SERVER,\n\tMCP_META_SUBSCRIPTION,\n\tSUPPORTED_PROTOCOL_VERSIONS,\n} from './constants.js'\nimport { inferEra } from './inferers.js'\nimport { parseJSONRPCMessage } from './parsers.js'\nimport { isMCPVersion } from './validators.js'\n\n// Pure dispatch builders (AGENTS §5: the dispatch branches stay exported helpers,\n// not hidden privates). Each turns a piece of MCP state into the JSON-RPC `result`\n// payload (or a response envelope) the server returns — independently testable.\n\n/**\n * Build a JSON-RPC success {@link JSONRPCResponse} — the `id` echoed, the method's\n * value as `result`.\n *\n * @param id - The request's id (`null` only for a parse / invalid-request error)\n * @param result - The method's return value\n * @returns The success response envelope\n */\nexport function buildJSONRPCResult(id: string | number | null, result: unknown): JSONRPCResponse {\n\treturn { jsonrpc: '2.0', id, result }\n}\n\n/**\n * Build a JSON-RPC error {@link JSONRPCResponse} — the `id` echoed, the failure as\n * an `error` object.\n *\n * @param id - The request's id (`null` for a parse / invalid-request error)\n * @param code - One of the reserved JSON-RPC codes (see `./constants.js`)\n * @param message - A short human description of the failure\n * @param data - An OPTIONAL machine-readable payload (omitted from the envelope when absent)\n * @returns The error response envelope\n */\nexport function buildJSONRPCError(\n\tid: string | number | null,\n\tcode: number,\n\tmessage: string,\n\tdata?: unknown,\n): JSONRPCResponse {\n\treturn {\n\t\tjsonrpc: '2.0',\n\t\tid,\n\t\terror: data === undefined ? { code, message } : { code, message, data },\n\t}\n}\n\n/**\n * Map a {@link ToolManagerInterface}'s definitions to MCP `tools/list` descriptors\n * — renaming `parameters` to the wire's `inputSchema`.\n *\n * @remarks\n * Each {@link import('@orkestrel/tool').ToolDefinition} carries through its\n * `name` and (when present) `description`; its open JSON-Schema `parameters`\n * becomes `inputSchema`, defaulting to an empty object schema (`{ type: 'object' }`)\n * when a tool declares none (MCP requires an `inputSchema`).\n *\n * @param manager - The tool registry to describe\n * @returns One {@link MCPToolDescriptor} per registered tool, in registry order\n */\nexport function buildToolDescriptors(manager: ToolManagerInterface): readonly MCPToolDescriptor[] {\n\treturn manager.definitions().map((definition) => {\n\t\tconst descriptor: {\n\t\t\tname: string\n\t\t\tdescription?: string\n\t\t\tinputSchema: Readonly<Record<string, unknown>>\n\t\t} = {\n\t\t\tname: definition.name,\n\t\t\tinputSchema: definition.parameters ?? { type: 'object' },\n\t\t}\n\t\tif (definition.description !== undefined) descriptor.description = definition.description\n\t\treturn descriptor\n\t})\n}\n\n/**\n * Map an executed tool's {@link ToolResult} to an MCP {@link MCPCallResult} — the\n * value as structured content plus a backwards-compatible `text` block, or the\n * error as a `text` block.\n *\n * @remarks\n * The {@link ToolManagerInterface} already isolates a thrown tool into a\n * `success: false` result (so the server adds NO try/catch around `execute`):\n * that branch builds an `isError: true` result carrying `result.error`, so the\n * model sees the failure as a tool result it can react to rather than a protocol\n * error; a valued `success: true` branch carries `result.value` unchanged as\n * `structuredContent` and serializes it (via `JSON.stringify`) into one `text`\n * block. A value-less success retains the required empty `content` block and\n * omits `structuredContent`.\n *\n * @param result - The tool's execution outcome\n * @returns The MCP tool-call result\n */\nexport function buildCallResult(result: ToolResult): MCPCallResult {\n\tif (!result.success) {\n\t\treturn { content: [{ type: 'text', text: result.error }], isError: true }\n\t}\n\t// A content block must carry a string `text`; `JSON.stringify(undefined)` is the value\n\t// `undefined` (which serializes away), so a value-less result becomes an empty text block.\n\tif (result.value === undefined) return { content: [{ type: 'text', text: '' }] }\n\treturn {\n\t\tcontent: [{ type: 'text', text: JSON.stringify(result.value) }],\n\t\tstructuredContent: result.value,\n\t}\n}\n\n/**\n * Stamp a result with the modern complete-result discriminator and server\n * metadata, plus cache fields when the result is cacheable.\n *\n * @remarks\n * This is the single stamping site shared by modern result builders. Supplying\n * `ttl` adds both schema-coupled fields (`ttlMs` and `cacheScope`); omitting it\n * adds neither, which keeps `tools/call` distinct from cacheable results.\n *\n * @param result - The unstamped result payload\n * @param identity - The server identity carried under the reserved `_meta` key\n * @param ttl - Required freshness lifetime for a cacheable result; omit for a non-cacheable result\n * @param scope - The cache visibility, defaulting to `'private'` when `ttl` is supplied\n * @returns A copy of the payload with its modern stamps\n */\nexport function buildModernResult<T extends object>(\n\tresult: T,\n\tidentity: MCPIdentity,\n\tttl: number,\n\tscope?: 'public' | 'private',\n): T & {\n\treadonly resultType: 'complete'\n\treadonly _meta: Readonly<Record<string, unknown>>\n\treadonly ttlMs: number\n\treadonly cacheScope: 'public' | 'private'\n}\nexport function buildModernResult<T extends object>(\n\tresult: T,\n\tidentity: MCPIdentity,\n): T & {\n\treadonly resultType: 'complete'\n\treadonly _meta: Readonly<Record<string, unknown>>\n}\nexport function buildModernResult<T extends object>(\n\tresult: T,\n\tidentity: MCPIdentity,\n\tttl?: number,\n\tscope?: 'public' | 'private',\n): T & {\n\treadonly resultType: 'complete'\n\treadonly _meta: Readonly<Record<string, unknown>>\n\treadonly ttlMs?: number\n\treadonly cacheScope?: 'public' | 'private'\n} {\n\tconst currentMetadata = isRecord(result) ? result['_meta'] : undefined\n\tconst metadata = {\n\t\t...(isRecord(currentMetadata) ? currentMetadata : {}),\n\t\t[MCP_META_SERVER]: identity,\n\t}\n\tif (ttl === undefined) return { ...result, resultType: 'complete', _meta: metadata }\n\treturn {\n\t\t...result,\n\t\tresultType: 'complete',\n\t\tttlMs: ttl,\n\t\tcacheScope: scope ?? 'private',\n\t\t_meta: metadata,\n\t}\n}\n\n/**\n * Intersect a requested subscription filter with the notification families a server supports.\n *\n * @param requested - The notification families requested by the client\n * @param supported - The notification families the server can actually produce\n * @returns The exact subset the server will honour\n */\nexport function buildSubscriptionFilter(\n\trequested: SubscriptionFilter,\n\tsupported: SubscriptionFilter,\n): SubscriptionFilter {\n\tconst toolsListChanged =\n\t\trequested.toolsListChanged === true && supported.toolsListChanged === true\n\tconst promptsListChanged =\n\t\trequested.promptsListChanged === true && supported.promptsListChanged === true\n\tconst resourcesListChanged =\n\t\trequested.resourcesListChanged === true && supported.resourcesListChanged === true\n\tconst supportedResources = new Set(supported.resourceSubscriptions ?? [])\n\tconst resourceSubscriptions = requested.resourceSubscriptions?.filter((uri) =>\n\t\tsupportedResources.has(uri),\n\t)\n\treturn {\n\t\t...(toolsListChanged ? { toolsListChanged: true } : {}),\n\t\t...(promptsListChanged ? { promptsListChanged: true } : {}),\n\t\t...(resourcesListChanged ? { resourcesListChanged: true } : {}),\n\t\t...(resourceSubscriptions !== undefined && resourceSubscriptions.length > 0\n\t\t\t? { resourceSubscriptions }\n\t\t\t: {}),\n\t}\n}\n\n/**\n * Determine whether a produced notification belongs to an honoured subscription filter.\n *\n * @param notification - The server notification offered by the configured producer\n * @param filter - The filter acknowledged to the client\n * @returns `true` when the notification belongs on this subscription stream\n */\nexport function matchesSubscriptionNotification(\n\tnotification: JSONRPCRequest,\n\tfilter: SubscriptionFilter,\n): boolean {\n\tif (notification.method === 'notifications/tools/list_changed') {\n\t\treturn filter.toolsListChanged === true\n\t}\n\tif (notification.method === 'notifications/prompts/list_changed') {\n\t\treturn filter.promptsListChanged === true\n\t}\n\tif (notification.method === 'notifications/resources/list_changed') {\n\t\treturn filter.resourcesListChanged === true\n\t}\n\tif (notification.method !== 'notifications/resources/updated') return false\n\tconst uri = notification.params?.['uri']\n\treturn typeof uri === 'string' && filter.resourceSubscriptions?.includes(uri) === true\n}\n\n/**\n * Stamp a subscription notification with the request id reserved for its held-open stream.\n *\n * @param notification - The notification to copy and stamp\n * @param id - The `subscriptions/listen` request id\n * @returns The stamped notification, preserving its other params and metadata\n */\nexport function stampSubscriptionNotification(\n\tnotification: JSONRPCRequest,\n\tid: string | number,\n): JSONRPCRequest {\n\tconst metadata = notification.params?.['_meta']\n\treturn {\n\t\tjsonrpc: notification.jsonrpc,\n\t\tmethod: notification.method,\n\t\tparams: {\n\t\t\t...notification.params,\n\t\t\t_meta: {\n\t\t\t\t...(isRecord(metadata) ? metadata : {}),\n\t\t\t\t[MCP_META_SUBSCRIPTION]: id,\n\t\t\t},\n\t\t},\n\t}\n}\n\n/**\n * Build the first notification carrying a subscription id for a listen request.\n *\n * @param notifications - The exact notification filter the server will honour\n * @param id - The `subscriptions/listen` request id\n * @returns The stamped subscription acknowledgement notification\n */\nexport function buildSubscriptionAcknowledgement(\n\tnotifications: SubscriptionFilter,\n\tid: string | number,\n): JSONRPCRequest {\n\treturn stampSubscriptionNotification(\n\t\t{\n\t\t\tjsonrpc: '2.0',\n\t\t\tmethod: 'notifications/subscriptions/acknowledged',\n\t\t\tparams: { notifications },\n\t\t},\n\t\tid,\n\t)\n}\n\n/**\n * Build the terminating response for a subscription source that closes gracefully.\n *\n * @param id - The `subscriptions/listen` request id\n * @param identity - The server identity included by the modern result stamping site\n * @returns The complete modern result carrying the required subscription id metadata\n */\nexport function buildSubscriptionResult(\n\tid: string | number,\n\tidentity: MCPIdentity,\n): JSONRPCResponse {\n\tconst metadata: SubscriptionsListenResultMetaObject = { [MCP_META_SUBSCRIPTION]: id }\n\tconst result: SubscriptionsListenResult = buildModernResult({ _meta: metadata }, identity)\n\treturn buildJSONRPCResult(id, result)\n}\n\n/**\n * Build the mandatory modern `server/discover` result.\n *\n * @param options - The server identity, instructions, and cache configuration\n * @returns The supported revisions, tools capability, and required modern cache stamps\n */\nexport function buildDiscoverResult(options: MCPServerOptions): MCPDiscoverResult {\n\treturn buildModernResult(\n\t\t{\n\t\t\tsupportedVersions: SUPPORTED_PROTOCOL_VERSIONS.filter(isMCPVersion),\n\t\t\tcapabilities: { tools: {} },\n\t\t\t...(options.instructions === undefined ? {} : { instructions: options.instructions }),\n\t\t},\n\t\toptions.identity,\n\t\toptions.cache?.ttl ?? DEFAULT_MCP_CACHE_TTL,\n\t\toptions.cache?.scope,\n\t)\n}\n\n/**\n * Build the MCP `initialize` result — the negotiated protocol version, the\n * advertised capabilities, and the server identity.\n *\n * @remarks\n * Version negotiation echoes the client's `requested` version when it is one of the\n * supported legacy revisions. A modern or unsupported request receives the newest\n * supported legacy revision; the client decides whether to continue.\n * `capabilities.tools` is an empty object — this server advertises the tools\n * capability with no sub-options (no list-changed notification yet).\n *\n * @param name - The server name (echoed in `serverInfo`)\n * @param version - The server version (echoed in `serverInfo`)\n * @param requested - The client's requested protocol version (negotiated when supported)\n * @returns The `initialize` result payload\n */\nexport function buildInitializeResult(\n\tname: string,\n\tversion: string,\n\trequested?: string,\n): Readonly<Record<string, unknown>> {\n\tconst newestLegacy =\n\t\tSUPPORTED_PROTOCOL_VERSIONS.find((candidate) => inferEra(candidate) === 'legacy') ??\n\t\tMCP_LEGACY_VERSION\n\tconst protocolVersion =\n\t\tisMCPVersion(requested) && inferEra(requested) === 'legacy' ? requested : newestLegacy\n\treturn {\n\t\tprotocolVersion,\n\t\tcapabilities: { tools: {} },\n\t\tserverInfo: { name, version },\n\t}\n}\n\n// Held-open stream leaves — the two pure transformations that carry an\n// {@link MCPStream} across the string boundary and onto a transport. Both consume the\n// generator MANUALLY rather than with `for await`, because `for await` discards the\n// `return` value and the terminating response IS that value.\n\n/**\n * Serialize a typed {@link MCPStream} into its string mirror — each yielded\n * notification and the terminating response, already `JSON.stringify`d.\n *\n * @remarks\n * The string-boundary half of the held-open arm: `handle` returns this so a transport\n * writes each message with no second parse, exactly as it writes a unary reply string.\n * The terminating response arrives as the returned generator's OWN `return` value, so a\n * consumer distinguishes \"one more notification\" from \"this is the answer\" without a\n * sentinel.\n *\n * @param stream - The typed held-open result to serialize\n * @returns The same sequence with every message serialized to a string\n *\n * @example\n * ```ts\n * const text = serializeStream(stream)\n * for (let next = await text.next(); ; next = await text.next()) {\n * \tif (next.done === true) return next.value // the terminating response, serialized\n * \tlog(next.value) // one serialized notification\n * }\n * ```\n */\nexport async function* serializeStream(stream: MCPStream): MCPTextStream {\n\tlet next = await stream.next()\n\twhile (!next.done) {\n\t\tyield JSON.stringify(next.value)\n\t\tnext = await stream.next()\n\t}\n\treturn JSON.stringify(next.value)\n}\n\n/**\n * Pump an {@link MCPTextStream} onto a transport — every notification in order, then the\n * terminating response.\n *\n * @remarks\n * The generator's `return` value is a message like any other on the wire: it is sent\n * LAST and closes the exchange. Sends are awaited one at a time so the transport\n * receives the sequence in the order the method produced it.\n *\n * @param stream - The serialized held-open result to write out\n * @param transport - The duplex channel to write each message to\n * @returns Resolves once the terminating response has been sent\n *\n * @example\n * ```ts\n * const answer = await server.handle(message)\n * if (typeof answer !== 'string') await sendStream(answer, transport)\n * ```\n */\nexport async function sendStream(\n\tstream: MCPTextStream,\n\ttransport: MCPTransportInterface,\n): Promise<void> {\n\tlet next = await stream.next()\n\twhile (!next.done) {\n\t\tawait transport.send(next.value)\n\t\tnext = await stream.next()\n\t}\n\tawait transport.send(next.value)\n}\n\n// The environment-agnostic PORT binders — the keystone that lets an\n// {@link MCPServerInterface} / {@link MCPClientInterface} run over ANY\n// {@link MCPTransportInterface} (a Node stdio pair, a browser MessagePort, a Web\n// Worker `self`) with no per-environment dispatch/correlation wiring duplicated at\n// each face. Both are TOTAL: a `send` throw or rejection is caught and never\n// escapes as an unhandled rejection.\n\n/**\n * Pipe an {@link MCPTransportInterface} into an {@link MCPServerInterface} — every\n * inbound message runs through `server.handle`, and a defined reply is written back\n * via `transport.send`.\n *\n * @remarks\n * `server.handle` already turns a malformed message into a serialized `-32700` /\n * `-32600` reply and a notification into `undefined` (no reply), so this binder adds\n * no parsing of its own. A HELD-OPEN reply arrives as an\n * {@link import('./types.js').MCPTextStream} instead of a string: this is the one place\n * that pumps it, writing each notification in order and then the generator's returned\n * terminating response ({@link sendStream}). A `transport.send` throw or rejection —\n * mid-stream included — is caught and routed\n * to `server.emitter`'s `error` event (never rethrown, never an unhandled rejection);\n * a listener on that event that itself throws is swallowed (the end of the line —\n * the caller's own bug, never this binder's). The returned unbind DETACHES this\n * binder (further inbound messages and the transport's `closed` signal are ignored)\n * WITHOUT closing the transport — closing is the caller's decision.\n *\n * `listen`/`closed` are REPLACE semantics (§ port contract): the returned unbind\n * DETACHES by replacing this binder's own handlers with no-ops, so a subsequent\n * `bindServer` call on the SAME transport is never double-dispatched by a stale\n * subscription left behind — an unbind→rebind cycle yields exactly one reply per\n * request.\n *\n * @param server - The transport-agnostic server to dispatch inbound messages over\n * @param transport - The duplex channel to pipe the server over\n * @returns Detach this binder from the transport (does not close it)\n *\n * @example\n * ```ts\n * const unbind = bindServer(server, transport)\n * // ... later, detach without closing:\n * unbind()\n * ```\n */\nexport function bindServer(\n\tserver: MCPServerInterface,\n\ttransport: MCPTransportInterface,\n): () => void {\n\tlet active = true\n\ttransport.listen(async (message) => {\n\t\tif (!active) return\n\t\ttry {\n\t\t\tconst answer = await server.handle(message)\n\t\t\tif (answer === undefined) return\n\t\t\tif (typeof answer === 'string') await transport.send(answer)\n\t\t\telse await sendStream(answer, transport)\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tserver.emitter.emit('error', error)\n\t\t\t} catch {\n\t\t\t\t// A throwing `error` listener is the caller's own bug — the end of the line.\n\t\t\t}\n\t\t}\n\t})\n\ttransport.closed(() => {\n\t\tactive = false\n\t})\n\treturn () => {\n\t\tactive = false\n\t\ttransport.listen(() => {})\n\t\ttransport.closed(() => {})\n\t}\n}\n\n/**\n * Pipe an {@link MCPTransportInterface} into an {@link MCPClientInterface} — every\n * inbound message is decoded and delivered onto the client's OWN transport\n * (`client.transport.emitter`'s `message` / `close` events), resolving/rejecting the\n * client's correlated pending requests exactly as a direct reply would.\n *\n * @remarks\n * The client's outbound writes flow through `client.transport.send` — its existing,\n * unmodified request/response correlation — so `client` must have been constructed\n * with a {@link import('./types.js').ClientTransportInterface} that itself carries\n * the SAME `transport` (see {@link import('./factories.js').createDuplexClientTransport},\n * the additive factory that adapts an {@link MCPTransportInterface} into that shape);\n * this binder then completes the inbound half by decoding each message and pushing it\n * onto `client.transport.emitter` (an {@link import('@orkestrel/emitter').EmitterInterface}\n * exposes `emit`, so no client modification is needed). A malformed / non-JSON-RPC\n * inbound message is DROPPED (§14, total — never throws); a delivery fault is routed to\n * `client.transport.emitter`'s `error` event (never rethrown). The returned unbind\n * DETACHES this binder (further inbound messages and the transport's `closed` signal are\n * ignored) WITHOUT closing the transport.\n *\n * `listen`/`closed` are REPLACE semantics (§ port contract): the returned unbind\n * DETACHES by replacing this binder's own handlers with no-ops, so a subsequent\n * `bindClient` call on the SAME transport is never double-dispatched by a stale\n * subscription left behind — an unbind→rebind cycle delivers exactly one `message`\n * emit per inbound reply.\n *\n * @param client - The transport-agnostic client whose transport to deliver messages onto\n * @param transport - The duplex channel to pipe the client over\n * @returns Detach this binder from the transport (does not close it)\n *\n * @example\n * ```ts\n * const client = createMCPClient({ transport: createDuplexClientTransport(transport) })\n * const unbind = bindClient(client, transport)\n * await client.connect()\n * // ... later, detach without closing:\n * unbind()\n * ```\n */\nexport function bindClient(\n\tclient: MCPClientInterface,\n\ttransport: MCPTransportInterface,\n): () => void {\n\tlet active = true\n\ttransport.listen((message) => {\n\t\tif (!active) return\n\t\tlet parsed: unknown\n\t\ttry {\n\t\t\tparsed = JSON.parse(message)\n\t\t} catch {\n\t\t\treturn\n\t\t}\n\t\tconst decoded = parseJSONRPCMessage(parsed)\n\t\tif (decoded === undefined) return\n\t\ttry {\n\t\t\tclient.transport.emitter.emit('message', decoded)\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tclient.transport.emitter.emit('error', error)\n\t\t\t} catch {\n\t\t\t\t// A throwing `error` listener is the caller's own bug — the end of the line.\n\t\t\t}\n\t\t}\n\t})\n\ttransport.closed(() => {\n\t\tif (!active) return\n\t\tactive = false\n\t\ttry {\n\t\t\tclient.transport.emitter.emit('close')\n\t\t} catch {\n\t\t\t// A throwing `close` listener is the caller's own bug — the end of the line.\n\t\t}\n\t})\n\treturn () => {\n\t\tactive = false\n\t\ttransport.listen(() => {})\n\t\ttransport.closed(() => {})\n\t}\n}\n","import type { MCPMethodHandler, MCPMethodManagerInterface } from './types.js'\n\n/**\n * The modern method registry an {@link import('./types.js').MCPServerInterface}\n * dispatches through — a name-keyed store of {@link MCPMethodHandler}s that owns its\n * map rather than exposing one.\n *\n * @remarks\n * - **One seam.** The server registers its built-in modern methods here at construction\n * and resolves EVERY modern method from here, so a consumer's method and a built-in\n * are the same kind of thing on the same path.\n * - **Registration is a write, not a merge.** `add` under a name already present\n * REPLACES it, which is how a consumer overrides a built-in; there is no precedence\n * rule to remember.\n * - **A narrower contract than a `Map`.** Callers register and resolve; they cannot\n * iterate, clear, or otherwise reach the server's internal state through it.\n *\n * @example\n * ```ts\n * const methods = new MCPMethodManager()\n * methods.add('tools/list', async (request) => buildJSONRPCResult(request.id ?? null, { tools: [] }))\n * methods.method('tools/list') // the handler\n * methods.method('tools/nope') // undefined → the dispatch branch answers -32601\n * ```\n */\nexport class MCPMethodManager implements MCPMethodManagerInterface {\n\treadonly #handlers = new Map<string, MCPMethodHandler>()\n\n\tadd(name: string, handler: MCPMethodHandler): void {\n\t\tthis.#handlers.set(name, handler)\n\t}\n\n\tmethod(name: string): MCPMethodHandler | undefined {\n\t\treturn this.#handlers.get(name)\n\t}\n}\n","import type { EmitterInterface } from '@orkestrel/emitter'\nimport type {\n\tJSONRPCRequest,\n\tJSONRPCResponse,\n\tMCPElicitation,\n\tMCPCallResult,\n\tMCPDispatchOptions,\n\tMCPIdentity,\n\tMCPLimitOptions,\n\tMCPMethodManagerInterface,\n\tMCPServerEventMap,\n\tMCPServerInterface,\n\tMCPServerOptions,\n\tMCPStream,\n\tMCPTextStream,\n\tSubscriptionFilter,\n} from './types.js'\nimport { Emitter } from '@orkestrel/emitter'\nimport { attempt, isRecord, isString, sanitizeBudget } from '@orkestrel/contract'\nimport { signToken, verifyToken } from '@orkestrel/server'\nimport {\n\tDEFAULT_MCP_CACHE_TTL,\n\tDEFAULT_MCP_LIMITS,\n\tJSONRPC_INVALID_PARAMS,\n\tJSONRPC_INVALID_REQUEST,\n\tJSONRPC_METHOD_NOT_FOUND,\n\tJSONRPC_PARSE_ERROR,\n\tJSONRPC_SERVER_ERROR,\n\tMCP_META_SERVER,\n\tMCP_MISSING_CAPABILITY,\n\tMCP_UNSUPPORTED_VERSION,\n\tSUPPORTED_PROTOCOL_VERSIONS,\n} from './constants.js'\nimport {\n\tbuildCallResult,\n\tbuildDiscoverResult,\n\tbuildInitializeResult,\n\tbuildJSONRPCError,\n\tbuildJSONRPCResult,\n\tbuildModernResult,\n\tbuildSubscriptionAcknowledgement,\n\tbuildSubscriptionFilter,\n\tbuildSubscriptionResult,\n\tbuildToolDescriptors,\n\tmatchesSubscriptionNotification,\n\tserializeStream,\n\tstampSubscriptionNotification,\n} from './helpers.js'\nimport { inferEra } from './inferers.js'\nimport { MCPMethodManager } from './MCPMethodManager.js'\nimport { parseJSONRPCMessage, parseMCPInputState, parseRequestContext } from './parsers.js'\nimport {\n\tisElicitRequestFormParams,\n\tisElicitResult,\n\tisBoundedJSON,\n\tisBoundedString,\n\tisFormElicitationSupported,\n\tisModernRequest,\n\tisSubscriptionFilter,\n} from './validators.js'\n\n/**\n * A transport-agnostic Model Context Protocol server — dispatches JSON-RPC 2.0\n * requests over a live {@link ToolManagerInterface}, with NO transport coupling.\n *\n * @remarks\n * - **Two entry points.** `dispatch(request)` runs an already-parsed request and\n * resolves a {@link JSONRPCResponse} — or `undefined` for a NOTIFICATION (a\n * request with no `id`). `handle(message)` is the string boundary: it\n * `JSON.parse`s the raw message (a failure → a `-32700` response), narrows it to\n * a request (a non-request → a `-32600` response), dispatches, and serializes the\n * response back to a string (`undefined` for a notification).\n * - **Dual-era dispatch.** A request carrying the reserved modern version key uses\n * modern metadata validation and the registered method seam. Every other request\n * uses the legacy `initialize` / `ping` / `tools/list` / `tools/call` switch. The\n * wire era is selected per request and never stored.\n * - **One modern seam.** `server/discover`, `tools/list`, `tools/call`, and\n * `subscriptions/listen` are\n * registered on `methods` at construction and resolved from it on every dispatch —\n * the same path a later method or a consumer's own takes, with an unregistered\n * method still answering `-32601`.\n * - **Provider-agnostic.** Imports only core siblings — JSON-RPC + the tool registry,\n * no HTTP, no model. Wire fields are narrowed via the contracts guards (no `as`).\n * - **Observable (§13).** The owned `emitter` fires `request` at the top of every\n * dispatch; the emitter isolates a listener throw and routes it to its `error` handler\n * (the `error` option), so a listener throw can never escape the dispatch.\n *\n * @example\n * ```ts\n * const tools = createToolManager()\n * tools.add(createTool({ name: 'add', execute: (a) => Number(a.x) + Number(a.y) }))\n * const server = new MCPServer({ identity: { name: 'demo', version: '1.0.0' }, tools })\n * await server.handle('{\"jsonrpc\":\"2.0\",\"method\":\"ping\",\"id\":1}') // '{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{}}'\n * ```\n */\nexport class MCPServer implements MCPServerInterface {\n\treadonly #emitter: Emitter<MCPServerEventMap>\n\treadonly #options: MCPServerOptions\n\treadonly #methods: MCPMethodManager\n\treadonly #limits: Required<MCPLimitOptions>\n\t#subscriptions = 0\n\n\tconstructor(options: MCPServerOptions) {\n\t\tthis.#emitter = new Emitter<MCPServerEventMap>({\n\t\t\t...(options.on !== undefined ? { on: options.on } : {}),\n\t\t\t...(options.error !== undefined ? { error: options.error } : {}),\n\t\t})\n\t\tthis.#options = options\n\t\tthis.#limits = {\n\t\t\tmessage: sanitizeBudget(options.limit?.message, DEFAULT_MCP_LIMITS.message),\n\t\t\tmetadata: sanitizeBudget(options.limit?.metadata, DEFAULT_MCP_LIMITS.metadata),\n\t\t\tkeys: sanitizeBudget(options.limit?.keys, DEFAULT_MCP_LIMITS.keys),\n\t\t\tstate: sanitizeBudget(options.limit?.state, DEFAULT_MCP_LIMITS.state),\n\t\t\tcontent: sanitizeBudget(options.limit?.content, DEFAULT_MCP_LIMITS.content),\n\t\t\tsubscriptions: sanitizeBudget(options.limit?.subscriptions, DEFAULT_MCP_LIMITS.subscriptions),\n\t\t\tdepth: sanitizeBudget(options.limit?.depth, DEFAULT_MCP_LIMITS.depth),\n\t\t}\n\t\tthis.#methods = new MCPMethodManager()\n\t\tthis.#register()\n\t}\n\n\tget emitter(): EmitterInterface<MCPServerEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tget identity(): MCPIdentity {\n\t\treturn this.#options.identity\n\t}\n\n\tget methods(): MCPMethodManagerInterface {\n\t\treturn this.#methods\n\t}\n\n\tasync dispatch(\n\t\trequest: JSONRPCRequest,\n\t\toptions: MCPDispatchOptions = {},\n\t): Promise<JSONRPCResponse | MCPStream | undefined> {\n\t\tconst id = request.id ?? null\n\t\tconst modern = isModernRequest(request)\n\t\tconst era = modern ? 'modern' : 'legacy'\n\t\tthis.#emitter.emit('request', request.method, id, era)\n\t\t// JSON-RPC: a request with NO `id` is a NOTIFICATION — it is handled (the\n\t\t// `request` event already fired) but NEVER produces a response, whatever its\n\t\t// method (`notifications/initialized`, a fire-and-forget `ping`, an unknown\n\t\t// method — all silent). So short-circuit here, and the branches below only ever\n\t\t// run for an id-bearing request that expects a reply.\n\t\tif (request.id === undefined) {\n\t\t\treturn undefined\n\t\t}\n\t\tconst metadata = request.params?.['_meta']\n\t\tif (\n\t\t\tmetadata !== undefined &&\n\t\t\t!isBoundedJSON(metadata, {\n\t\t\t\tbytes: this.#limits.metadata,\n\t\t\t\tkeys: this.#limits.keys,\n\t\t\t\tdepth: this.#limits.depth,\n\t\t\t})\n\t\t) {\n\t\t\treturn buildJSONRPCError(\n\t\t\t\tid,\n\t\t\t\tJSONRPC_INVALID_PARAMS,\n\t\t\t\t'Invalid params: `_meta` exceeds the configured limit or contains an unsafe value',\n\t\t\t)\n\t\t}\n\t\treturn modern ? this.#modern(request, id, options) : this.#legacy(request, id)\n\t}\n\n\tasync handle(\n\t\tmessage: string,\n\t\toptions?: MCPDispatchOptions,\n\t): Promise<string | MCPTextStream | undefined> {\n\t\tif (!isBoundedString(message, this.#limits.message)) {\n\t\t\treturn JSON.stringify(buildJSONRPCError(null, JSONRPC_PARSE_ERROR, 'Parse error'))\n\t\t}\n\t\tlet parsed: unknown\n\t\ttry {\n\t\t\tparsed = JSON.parse(message)\n\t\t} catch {\n\t\t\treturn JSON.stringify(buildJSONRPCError(null, JSONRPC_PARSE_ERROR, 'Parse error'))\n\t\t}\n\t\tconst decoded = parseJSONRPCMessage(parsed)\n\t\t// Only a REQUEST is dispatchable — a response (or any non-message) is invalid input.\n\t\tif (decoded === undefined || !('method' in decoded)) {\n\t\t\treturn JSON.stringify(buildJSONRPCError(null, JSONRPC_INVALID_REQUEST, 'Invalid Request'))\n\t\t}\n\t\tconst answer = await this.dispatch(decoded, options)\n\t\tif (answer === undefined) return undefined\n\t\t// The ONE narrowing point (§4.3): a held-open answer becomes the string mirror of\n\t\t// itself, so the string boundary stays a mirror of the typed core.\n\t\treturn Symbol.asyncIterator in answer ? serializeStream(answer) : JSON.stringify(answer)\n\t}\n\n\tasync #legacy(request: JSONRPCRequest, id: string | number | null): Promise<JSONRPCResponse> {\n\t\tswitch (request.method) {\n\t\t\tcase 'initialize': {\n\t\t\t\tconst requested = request.params?.['protocolVersion']\n\t\t\t\treturn buildJSONRPCResult(\n\t\t\t\t\tid,\n\t\t\t\t\tbuildInitializeResult(\n\t\t\t\t\t\tthis.#options.identity.name,\n\t\t\t\t\t\tthis.#options.identity.version,\n\t\t\t\t\t\tisString(requested) ? requested : undefined,\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t}\n\t\t\tcase 'ping':\n\t\t\t\treturn buildJSONRPCResult(id, {})\n\t\t\tcase 'tools/list':\n\t\t\t\treturn buildJSONRPCResult(id, {\n\t\t\t\t\ttools: buildToolDescriptors(this.#options.tools),\n\t\t\t\t})\n\t\t\tcase 'tools/call': {\n\t\t\t\tconst result = await this.#runTool(request, id)\n\t\t\t\treturn 'jsonrpc' in result ? result : buildJSONRPCResult(id, result)\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\treturn buildJSONRPCError(\n\t\t\t\t\tid,\n\t\t\t\t\tJSONRPC_METHOD_NOT_FOUND,\n\t\t\t\t\t`Method not found: ${request.method}`,\n\t\t\t\t)\n\t\t}\n\t}\n\n\t// Register the built-in modern methods on the seam `#modern` resolves from — the\n\t// point of the seam is that these four are not special: they are the first four\n\t// registrations, and a later one (or a consumer's) replaces or joins them in place.\n\t#register(): void {\n\t\tthis.#methods.add('server/discover', (request) => this.#discover(request))\n\t\tthis.#methods.add('tools/list', (request) => this.#list(request))\n\t\tthis.#methods.add('tools/call', (request, options) => this.#call(request, options))\n\t\tthis.#methods.add('subscriptions/listen', (request, options) =>\n\t\t\tthis.#subscribe(request, options),\n\t\t)\n\t}\n\n\tasync #modern(\n\t\trequest: JSONRPCRequest,\n\t\tid: string | number | null,\n\t\toptions: MCPDispatchOptions,\n\t): Promise<JSONRPCResponse | MCPStream | undefined> {\n\t\tconst context = parseRequestContext(request)\n\t\tif (context === undefined) {\n\t\t\treturn buildJSONRPCError(\n\t\t\t\tid,\n\t\t\t\tJSONRPC_INVALID_PARAMS,\n\t\t\t\t'Invalid params: malformed modern request metadata',\n\t\t\t)\n\t\t}\n\t\tif (inferEra(context.version) === undefined) {\n\t\t\treturn buildJSONRPCError(\n\t\t\t\tid,\n\t\t\t\tMCP_UNSUPPORTED_VERSION,\n\t\t\t\t`Unsupported protocol version: ${context.version}`,\n\t\t\t\t{ supported: SUPPORTED_PROTOCOL_VERSIONS, requested: context.version },\n\t\t\t)\n\t\t}\n\t\tconst handler = this.#methods.method(request.method)\n\t\tif (handler === undefined) {\n\t\t\treturn buildJSONRPCError(id, JSONRPC_METHOD_NOT_FOUND, `Method not found: ${request.method}`)\n\t\t}\n\t\treturn handler(request, options)\n\t}\n\n\t// The built-in `server/discover` handler.\n\tasync #discover(request: JSONRPCRequest): Promise<JSONRPCResponse> {\n\t\treturn buildJSONRPCResult(request.id ?? null, buildDiscoverResult(this.#options))\n\t}\n\n\t// The built-in modern `tools/list` handler — a cacheable result, so it carries both\n\t// schema-coupled cache stamps.\n\tasync #list(request: JSONRPCRequest): Promise<JSONRPCResponse> {\n\t\treturn buildJSONRPCResult(\n\t\t\trequest.id ?? null,\n\t\t\tbuildModernResult(\n\t\t\t\t{ tools: buildToolDescriptors(this.#options.tools) },\n\t\t\t\tthis.#options.identity,\n\t\t\t\tthis.#options.cache?.ttl ?? DEFAULT_MCP_CACHE_TTL,\n\t\t\t\tthis.#options.cache?.scope,\n\t\t\t),\n\t\t)\n\t}\n\n\t// The built-in modern `tools/call` handler — stamped, and NOT cacheable, so it\n\t// carries no cache fields.\n\tasync #call(request: JSONRPCRequest, options: MCPDispatchOptions = {}): Promise<JSONRPCResponse> {\n\t\tconst id = request.id ?? null\n\t\tconst input = await this.#input(request, options)\n\t\tif (input !== undefined) return input\n\t\tconst result = await this.#runTool(request, id)\n\t\treturn 'jsonrpc' in result\n\t\t\t? result\n\t\t\t: buildJSONRPCResult(id, buildModernResult(result, this.#options.identity))\n\t}\n\n\t// The built-in modern `tools/call` input mechanism. It is deliberately reachable\n\t// only from `#call`: the other modern handlers cannot produce `input_required`.\n\tasync #input(\n\t\trequest: JSONRPCRequest,\n\t\toptions: MCPDispatchOptions,\n\t): Promise<JSONRPCResponse | undefined> {\n\t\tconst configured = this.#options.input\n\t\tif (configured === undefined) return undefined\n\t\tconst id = request.id\n\t\tif (id === undefined) return undefined\n\t\tconst params = request.params\n\t\tconst name = params?.['name']\n\t\tif (!isString(name)) return undefined\n\t\tconst rawArguments = params?.['arguments']\n\t\tconst args = isRecord(rawArguments) ? rawArguments : {}\n\t\tconst requestState = params?.['requestState']\n\t\tconst inputResponses = params?.['inputResponses']\n\t\tif (requestState === undefined && inputResponses === undefined) {\n\t\t\tconst elicitation = await configured.elicit({ request, name, arguments: args }, options)\n\t\t\tif (elicitation === undefined) return undefined\n\t\t\tconst principal = await configured.principal(request)\n\t\t\treturn this.#required(request, name, elicitation, principal)\n\t\t}\n\t\tif (!isBoundedString(requestState, this.#limits.state) || !isRecord(inputResponses)) {\n\t\t\treturn buildJSONRPCError(\n\t\t\t\tid,\n\t\t\t\tJSONRPC_INVALID_PARAMS,\n\t\t\t\t'Invalid params: `inputResponses` and `requestState` are required together',\n\t\t\t)\n\t\t}\n\t\tconst verified = await verifyToken(requestState, configured.secret)\n\t\tconst state = parseMCPInputState(verified)\n\t\tconst principal = await configured.principal(request)\n\t\tif (\n\t\t\tstate === undefined ||\n\t\t\tstate.principal !== principal ||\n\t\t\tstate.ttl !== configured.ttl ||\n\t\t\tstate.origin === id ||\n\t\t\tstate.name !== name ||\n\t\t\t!Object.hasOwn(inputResponses, state.key)\n\t\t) {\n\t\t\treturn buildJSONRPCError(\n\t\t\t\tid,\n\t\t\t\tJSONRPC_INVALID_PARAMS,\n\t\t\t\t'Invalid params: request state could not be verified for this retry',\n\t\t\t)\n\t\t}\n\t\tconst response = inputResponses[state.key]\n\t\tif (!isElicitResult(response)) {\n\t\t\treturn buildJSONRPCError(\n\t\t\t\tid,\n\t\t\t\tJSONRPC_INVALID_PARAMS,\n\t\t\t\t'Invalid params: the elicitation response is missing or malformed',\n\t\t\t)\n\t\t}\n\t\tconst elicitation = await configured.elicit(\n\t\t\t{\n\t\t\t\trequest,\n\t\t\t\tname,\n\t\t\t\targuments: args,\n\t\t\t\tresponse,\n\t\t\t\t...(state.state !== undefined ? { state: state.state } : {}),\n\t\t\t},\n\t\t\toptions,\n\t\t)\n\t\treturn elicitation === undefined\n\t\t\t? undefined\n\t\t\t: this.#required(request, name, elicitation, principal)\n\t}\n\n\t// Build one form-mode round and seal the call-in-hand state. The random map key is\n\t// minted here, never accepted from the consumer, and is carried inside the HMAC payload.\n\tasync #required(\n\t\trequest: JSONRPCRequest,\n\t\tname: string,\n\t\telicitation: MCPElicitation,\n\t\tprincipal: string,\n\t): Promise<JSONRPCResponse> {\n\t\tconst id = request.id\n\t\tif (id === undefined) {\n\t\t\treturn buildJSONRPCError(null, JSONRPC_INVALID_REQUEST, 'Invalid Request')\n\t\t}\n\t\tconst context = parseRequestContext(request)\n\t\tif (context === undefined || !isFormElicitationSupported(context.capabilities)) {\n\t\t\treturn buildJSONRPCError(\n\t\t\t\tid,\n\t\t\t\tMCP_MISSING_CAPABILITY,\n\t\t\t\t'Server requires the elicitation capability for this request',\n\t\t\t\t{ requiredCapabilities: { elicitation: {} } },\n\t\t\t)\n\t\t}\n\t\tif (\n\t\t\t!isElicitRequestFormParams(elicitation.request) ||\n\t\t\tprincipal.length === 0 ||\n\t\t\t!Number.isFinite(this.#options.input?.ttl) ||\n\t\t\t(this.#options.input?.ttl ?? 0) <= 0\n\t\t) {\n\t\t\treturn buildJSONRPCError(\n\t\t\t\tid,\n\t\t\t\tJSONRPC_INVALID_PARAMS,\n\t\t\t\t'Invalid params: elicitation policy returned an invalid form or signing context',\n\t\t\t)\n\t\t}\n\t\tconst configured = this.#options.input\n\t\tif (configured === undefined) {\n\t\t\treturn buildJSONRPCError(\n\t\t\t\tid,\n\t\t\t\tJSONRPC_INVALID_PARAMS,\n\t\t\t\t'Invalid params: input is not configured',\n\t\t\t)\n\t\t}\n\t\tconst key = crypto.randomUUID()\n\t\tconst protectedState = {\n\t\t\tprincipal,\n\t\t\tttl: configured.ttl,\n\t\t\torigin: id,\n\t\t\tkey,\n\t\t\tname,\n\t\t\t...(elicitation.state !== undefined ? { state: elicitation.state } : {}),\n\t\t}\n\t\tif (\n\t\t\t!isBoundedJSON(protectedState, {\n\t\t\t\tbytes: this.#limits.state,\n\t\t\t\tdepth: this.#limits.depth,\n\t\t\t})\n\t\t) {\n\t\t\treturn buildJSONRPCError(\n\t\t\t\tid,\n\t\t\t\tJSONRPC_INVALID_PARAMS,\n\t\t\t\t'Invalid params: request state exceeds the configured limit',\n\t\t\t)\n\t\t}\n\t\tconst requestState = await signToken(JSON.stringify(protectedState), {\n\t\t\tsecret: configured.secret,\n\t\t\tttl: configured.ttl,\n\t\t})\n\t\tif (!isBoundedString(requestState, this.#limits.state)) {\n\t\t\treturn buildJSONRPCError(\n\t\t\t\tid,\n\t\t\t\tJSONRPC_INVALID_PARAMS,\n\t\t\t\t'Invalid params: request state exceeds the configured limit',\n\t\t\t)\n\t\t}\n\t\treturn buildJSONRPCResult(id, {\n\t\t\tresultType: 'input_required',\n\t\t\tinputRequests: {\n\t\t\t\t[key]: {\n\t\t\t\t\tmethod: 'elicitation/create',\n\t\t\t\t\tparams: { ...elicitation.request, mode: 'form' },\n\t\t\t\t},\n\t\t\t},\n\t\t\trequestState,\n\t\t\t_meta: { [MCP_META_SERVER]: this.#options.identity },\n\t\t})\n\t}\n\n\t// The built-in modern `subscriptions/listen` handler validates the client's filter,\n\t// then returns the event-driven generator that owns acknowledgement and closure order.\n\tasync #subscribe(\n\t\trequest: JSONRPCRequest,\n\t\toptions: MCPDispatchOptions,\n\t): Promise<JSONRPCResponse | MCPStream> {\n\t\tconst id = request.id\n\t\tif (id === undefined) {\n\t\t\treturn buildJSONRPCError(null, JSONRPC_INVALID_REQUEST, 'Invalid Request')\n\t\t}\n\t\tconst requested = request.params?.['notifications']\n\t\tif (!isSubscriptionFilter(requested)) {\n\t\t\treturn buildJSONRPCError(\n\t\t\t\tid,\n\t\t\t\tJSONRPC_INVALID_PARAMS,\n\t\t\t\t'Invalid params: a valid `notifications` filter is required',\n\t\t\t)\n\t\t}\n\t\treturn this.#subscription(requested, id, options)\n\t}\n\n\tasync *#subscription(\n\t\trequested: SubscriptionFilter,\n\t\tid: string | number,\n\t\toptions: MCPDispatchOptions,\n\t): MCPStream {\n\t\tif (this.#subscriptions >= this.#limits.subscriptions) {\n\t\t\treturn buildJSONRPCError(\n\t\t\t\tid,\n\t\t\t\tJSONRPC_SERVER_ERROR,\n\t\t\t\t'Server limit reached: too many live subscriptions',\n\t\t\t)\n\t\t}\n\t\tthis.#subscriptions += 1\n\t\ttry {\n\t\t\tconst configured = this.#options.subscription\n\t\t\tconst notifications = buildSubscriptionFilter(requested, configured?.notifications ?? {})\n\t\t\tyield buildSubscriptionAcknowledgement(notifications, id)\n\t\t\tif (configured !== undefined) {\n\t\t\t\tconst source = await configured.listen(notifications, options)\n\t\t\t\tfor await (const notification of source) {\n\t\t\t\t\tif (matchesSubscriptionNotification(notification, notifications)) {\n\t\t\t\t\t\tyield stampSubscriptionNotification(notification, id)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn buildSubscriptionResult(id, this.#options.identity)\n\t\t} finally {\n\t\t\tthis.#subscriptions -= 1\n\t\t}\n\t}\n\n\t// Run a `tools/call`: narrow `params.name` (string) + `params.arguments` (record,\n\t// default `{}`) with no `as`, execute the tool (the manager isolates a throw into\n\t// `success: false`), and map the result to an MCP tool-call result. Shared by both\n\t// eras — only the result STAMPING differs between them.\n\tasync #runTool(\n\t\trequest: JSONRPCRequest,\n\t\tid: string | number | null,\n\t): Promise<MCPCallResult | JSONRPCResponse> {\n\t\tconst params = request.params\n\t\tconst name = params?.['name']\n\t\tif (!isString(name)) {\n\t\t\treturn buildJSONRPCError(\n\t\t\t\tid,\n\t\t\t\tJSONRPC_INVALID_PARAMS,\n\t\t\t\t'Invalid params: a string `name` is required',\n\t\t\t)\n\t\t}\n\t\tconst rawArguments = params?.['arguments']\n\t\tconst args = isRecord(rawArguments) ? rawArguments : {}\n\t\tconst callId = request.id === undefined ? crypto.randomUUID() : String(request.id)\n\t\tconst result = await this.#options.tools.execute({ id: callId, name, arguments: args })\n\t\tif (!result.success && !isBoundedString(result.error, this.#limits.content)) {\n\t\t\treturn buildJSONRPCError(\n\t\t\t\tid,\n\t\t\t\tJSONRPC_SERVER_ERROR,\n\t\t\t\t'Server limit exceeded: tool content is too large',\n\t\t\t)\n\t\t}\n\t\tif (\n\t\t\tresult.success &&\n\t\t\tresult.value !== undefined &&\n\t\t\t!isBoundedJSON(result.value, {\n\t\t\t\tbytes: this.#limits.content,\n\t\t\t\tdepth: this.#limits.depth,\n\t\t\t})\n\t\t) {\n\t\t\treturn buildJSONRPCError(\n\t\t\t\tid,\n\t\t\t\tJSONRPC_SERVER_ERROR,\n\t\t\t\t'Server limit exceeded: tool content is too large or unsafe',\n\t\t\t)\n\t\t}\n\t\tconst built = attempt(() => buildCallResult(result))\n\t\treturn built.success\n\t\t\t? built.value\n\t\t\t: buildJSONRPCError(id, JSONRPC_SERVER_ERROR, 'Server could not serialize tool content')\n\t}\n}\n","import type { EmitterInterface } from '@orkestrel/emitter'\nimport type { ToolInterface } from '@orkestrel/tool'\nimport type {\n\tClientTransportInterface,\n\tJSONRPCMessage,\n\tJSONRPCRequest,\n\tMCPClientEventMap,\n\tMCPClientInterface,\n\tMCPClientOptions,\n\tMCPDiscoverResult,\n\tMCPEra,\n\tMCPIdentity,\n\tMCPVersion,\n} from './types.js'\nimport { Emitter } from '@orkestrel/emitter'\nimport { Tool } from '@orkestrel/tool'\nimport { isArray, isNumber, isRecord, isString } from '@orkestrel/contract'\nimport {\n\tDEFAULT_MCP_CLIENT_NAME,\n\tDEFAULT_MCP_CLIENT_VERSION,\n\tDEFAULT_MCP_PROBE_TIMEOUT,\n\tDEFAULT_MCP_REQUEST_TIMEOUT,\n\tJSONRPC_INVALID_PARAMS,\n\tJSONRPC_INVALID_REQUEST,\n\tJSONRPC_METHOD_NOT_FOUND,\n\tMCP_META_CAPABILITIES,\n\tMCP_META_CLIENT,\n\tMCP_META_VERSION,\n\tMCP_MODERN_VERSION,\n\tMCP_PROTOCOL_VERSION,\n\tMCP_UNSUPPORTED_VERSION,\n} from './constants.js'\nimport { MCPError, isMCPError } from './errors.js'\nimport { inferEra, inferVersion } from './inferers.js'\nimport { isJSONRPCResponse, isMCPVersion, isRequestId } from './validators.js'\n\n/**\n * A transport-agnostic Model Context Protocol CLIENT — connects to a REMOTE MCP server\n * over an injected {@link ClientTransportInterface}, negotiates the modern or legacy\n * wire era, and exposes the server's tools as local {@link ToolInterface}s an agent can run.\n *\n * @remarks\n * - **The mirror of `MCPServer`.** The server DISPATCHES requests over a tool registry;\n * this client ISSUES them over a transport. `connect` probes `server/discover` unless\n * pinned legacy, falls back to `initialize` only for a legacy peer, and exposes the\n * negotiated `version`; `tools()` lists the remote tools and wraps each as a\n * local {@link ToolInterface} whose `execute` calls back through `call`; `call` runs a\n * remote `tools/call` and returns the tool's value (a remote `isError: true` throws\n * locally, so an agent's {@link import('@orkestrel/tool').ToolManagerInterface}\n * isolates it into a `success: false` result just like a local throw).\n * - **Request↔response correlation.** Each request is tagged with a monotonic numeric\n * `id` ({@link #nextId}); a single transport `message` subscription resolves / rejects\n * the matching {@link #pending} entry by `id`. A message that is NOT a response to a\n * pending request is a server NOTIFICATION — re-surfaced on the `notification` event.\n * - **Per-request deadline.** Each `#request` receives its own deadline: ordinary calls use\n * `this.#timeout`, while an explicitly bounded discovery uses the shorter probe deadline.\n * `AbortSignal.timeout` (never a raw `setTimeout`) rejects only that pending request.\n * - **Transport-agnostic.** Imports only core siblings (JSON-RPC + the tool vocabulary);\n * the concrete transport is injected. Wire fields are narrowed via the contracts\n * guards (no `as`).\n * - **Observable (§13).** The owned `emitter` fires `connect` / `disconnect` /\n * `notification` / `error`; the emitter isolates a listener throw and routes it to its\n * `error` handler (the `error` option), so a listener throw can never escape.\n *\n * @example\n * ```ts\n * const client = new MCPClient({ transport, identity: { name: 'agent', version: '1.0.0' } })\n * await client.connect()\n * const tools = await client.tools()\n * agent.context.tools.add(tools) // the remote tools are now the agent's\n * const value = await client.call('search', { query: 'mcp' })\n * ```\n */\nexport class MCPClient implements MCPClientInterface {\n\treadonly #emitter: Emitter<MCPClientEventMap>\n\treadonly #transport: ClientTransportInterface\n\treadonly #identity: MCPIdentity\n\treadonly #capabilities: Readonly<Record<string, unknown>>\n\treadonly #pin: MCPVersion | undefined\n\treadonly #timeout: number\n\treadonly #probe: number | undefined\n\t// The in-flight requests, keyed by JSON-RPC id, each holding its promise settlers —\n\t// resolved on the matching response, rejected on an error response, the deadline, or\n\t// `disconnect`. Genuinely private glue (§5): the settler shape lives inline here.\n\treadonly #pending = new Map<\n\t\tstring | number,\n\t\t{\n\t\t\treadonly resolve: (value: unknown) => void\n\t\t\treadonly reject: (reason?: unknown) => void\n\t\t\treadonly method: string\n\t\t\treadonly deadline?: AbortSignal\n\t\t\treadonly timeout?: () => void\n\t\t}\n\t>()\n\t#nextId = 0\n\t#connected = false\n\t#version: MCPVersion | undefined = undefined\n\t#era: MCPEra | undefined = undefined\n\t#offer: MCPVersion\n\n\tconstructor(options: MCPClientOptions) {\n\t\tthis.#emitter = new Emitter<MCPClientEventMap>({\n\t\t\t...(options.on !== undefined ? { on: options.on } : {}),\n\t\t\t...(options.error !== undefined ? { error: options.error } : {}),\n\t\t})\n\t\tthis.#transport = options.transport\n\t\tthis.#identity = options.identity ?? {\n\t\t\tname: DEFAULT_MCP_CLIENT_NAME,\n\t\t\tversion: DEFAULT_MCP_CLIENT_VERSION,\n\t\t}\n\t\tthis.#capabilities = options.capabilities ?? {}\n\t\tthis.#pin = options.version\n\t\tthis.#offer = options.version ?? MCP_MODERN_VERSION\n\t\tthis.#timeout = options.timeout ?? DEFAULT_MCP_REQUEST_TIMEOUT\n\t\tthis.#probe =\n\t\t\toptions.timeout === undefined\n\t\t\t\t? undefined\n\t\t\t\t: Math.min(options.timeout, DEFAULT_MCP_PROBE_TIMEOUT)\n\t\t// One message subscription for the client's whole life: a response settles its\n\t\t// pending request by id; anything else is a server notification.\n\t\tthis.#transport.emitter.on('message', (message) => this.#receive(message))\n\t}\n\n\tget emitter(): EmitterInterface<MCPClientEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tget connected(): boolean {\n\t\treturn this.#connected\n\t}\n\n\tget version(): MCPVersion | undefined {\n\t\treturn this.#version\n\t}\n\n\tget transport(): ClientTransportInterface {\n\t\treturn this.#transport\n\t}\n\n\ton<K extends keyof MCPClientEventMap>(\n\t\tevent: K,\n\t\thandler: (...args: MCPClientEventMap[K]) => void,\n\t): void {\n\t\tthis.#emitter.on(event, handler)\n\t}\n\n\tasync connect(): Promise<void> {\n\t\tif (this.#connected) return\n\t\tawait this.#transport.start()\n\t\tif (this.#era === 'legacy' || (this.#pin !== undefined && inferEra(this.#pin) === 'legacy')) {\n\t\t\tawait this.#initialize(this.#pin ?? MCP_PROTOCOL_VERSION)\n\t\t\treturn\n\t\t}\n\n\t\tlet discovery: MCPDiscoverResult\n\t\ttry {\n\t\t\ttry {\n\t\t\t\tdiscovery = await this.discover()\n\t\t\t} catch (error) {\n\t\t\t\tif (!isMCPError(error) || error.code !== MCP_UNSUPPORTED_VERSION) throw error\n\t\t\t\tif (this.#pin !== undefined) throw error\n\t\t\t\tconst supported = isRecord(error.context) ? error.context['supported'] : undefined\n\t\t\t\tconst retry = isArray(supported)\n\t\t\t\t\t? inferVersion(supported.filter((version): version is string => isString(version)))\n\t\t\t\t\t: undefined\n\t\t\t\tif (retry === undefined) throw error\n\t\t\t\tthis.#offer = retry\n\t\t\t\tdiscovery = await this.discover()\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconst fallback =\n\t\t\t\tthis.#pin !== MCP_MODERN_VERSION &&\n\t\t\t\tthis.#era === undefined &&\n\t\t\t\t(!isMCPError(error) || error.code !== MCP_UNSUPPORTED_VERSION)\n\t\t\tif (!fallback) throw error\n\t\t\tawait this.#initialize(MCP_PROTOCOL_VERSION)\n\t\t\treturn\n\t\t}\n\n\t\tconst version = inferVersion(discovery.supportedVersions)\n\t\tif (version === undefined) {\n\t\t\tthrow new MCPError(\n\t\t\t\t'MCP server supports no compatible protocol version',\n\t\t\t\tMCP_UNSUPPORTED_VERSION,\n\t\t\t\t{\n\t\t\t\t\tsupported: discovery.supportedVersions,\n\t\t\t\t},\n\t\t\t)\n\t\t}\n\t\tthis.#version = version\n\t\tthis.#era = 'modern'\n\t\tthis.#connected = true\n\t\tthis.#emitter.emit('connect')\n\t}\n\n\tasync discover(): Promise<MCPDiscoverResult> {\n\t\tconst result = await this.#request(\n\t\t\t'server/discover',\n\t\t\tundefined,\n\t\t\tthis.#probe,\n\t\t\tthis.#version ?? this.#offer,\n\t\t)\n\t\tif (!isRecord(result)) {\n\t\t\tthrow new MCPError(\n\t\t\t\t'MCP server returned a malformed discovery result',\n\t\t\t\tJSONRPC_INVALID_PARAMS,\n\t\t\t\tresult,\n\t\t\t)\n\t\t}\n\t\tconst advertised = result['supportedVersions']\n\t\tconst capabilities = result['capabilities']\n\t\tconst ttl = result['ttlMs']\n\t\tconst scope = result['cacheScope']\n\t\tconst instructions = result['instructions']\n\t\tconst metadata = result['_meta']\n\t\tconst resultType = result['resultType']\n\t\tif (\n\t\t\t!isArray(advertised) ||\n\t\t\t!isRecord(capabilities) ||\n\t\t\t!isNumber(ttl) ||\n\t\t\t(scope !== 'public' && scope !== 'private') ||\n\t\t\t(resultType !== undefined && resultType !== 'complete') ||\n\t\t\t(instructions !== undefined && !isString(instructions)) ||\n\t\t\t(metadata !== undefined && !isRecord(metadata))\n\t\t) {\n\t\t\tthrow new MCPError(\n\t\t\t\t'MCP server returned a malformed discovery result',\n\t\t\t\tJSONRPC_INVALID_PARAMS,\n\t\t\t\tresult,\n\t\t\t)\n\t\t}\n\t\tconst supportedVersions: MCPVersion[] = []\n\t\tfor (const version of advertised) {\n\t\t\tif (isMCPVersion(version)) supportedVersions.push(version)\n\t\t}\n\t\treturn {\n\t\t\tsupportedVersions,\n\t\t\tcapabilities,\n\t\t\tresultType: resultType ?? 'complete',\n\t\t\tttlMs: ttl,\n\t\t\tcacheScope: scope,\n\t\t\t...(instructions === undefined ? {} : { instructions }),\n\t\t\t...(metadata === undefined ? {} : { _meta: metadata }),\n\t\t}\n\t}\n\n\tasync disconnect(): Promise<void> {\n\t\tif (!this.#connected) return\n\t\tthis.#connected = false\n\t\tthis.#version = undefined\n\t\t// Reject every still-pending request so no caller hangs past a disconnect, then\n\t\t// clear the map and tear the transport down.\n\t\tfor (const id of this.#pending.keys()) {\n\t\t\tthis.#settle(id, new Error('MCP client disconnected'), true)\n\t\t}\n\t\tawait this.#transport.close()\n\t\tthis.#emitter.emit('disconnect')\n\t}\n\n\tasync tools(): Promise<readonly ToolInterface[]> {\n\t\tconst result = await this.#request('tools/list', undefined, this.#timeout)\n\t\t// The wire shape is `{ tools: MCPToolDescriptor[] }` — narrow it (§14): a\n\t\t// non-record / non-array `tools` yields no tools rather than throwing.\n\t\tif (!isRecord(result) || !isArray(result['tools'])) return []\n\t\tconst tools: ToolInterface[] = []\n\t\tfor (const descriptor of result['tools']) {\n\t\t\tif (!isRecord(descriptor) || !isString(descriptor['name'])) continue\n\t\t\tconst name = descriptor['name']\n\t\t\ttools.push(this.#tool(name, descriptor))\n\t\t}\n\t\treturn tools\n\t}\n\n\tasync call(name: string, args: Readonly<Record<string, unknown>>): Promise<unknown> {\n\t\tconst result = await this.#request('tools/call', { name, arguments: args }, this.#timeout)\n\t\t// The inverse of the server's `buildCallResult`: concat the result's text blocks,\n\t\t// then either throw (a remote `isError`) or parse the JSON value.\n\t\tconst text = this.#text(result)\n\t\tif (isRecord(result) && result['isError'] === true) {\n\t\t\tthrow new Error(text.length > 0 ? text : `MCP tool '${name}' failed`)\n\t\t}\n\t\t// A success carries the value JSON-serialized into the text block(s); parse it,\n\t\t// falling back to the raw string when it is not JSON (the inverse of the server's\n\t\t// `JSON.stringify`, whose value-less result is an empty text block).\n\t\tif (text.length === 0) return undefined\n\t\ttry {\n\t\t\treturn JSON.parse(text)\n\t\t} catch {\n\t\t\treturn text\n\t\t}\n\t}\n\n\t// Issue a request and await its correlated response, bounded by the per-request\n\t// deadline. A monotonic numeric id keys the pending settlers; `AbortSignal.timeout`\n\t// (the taverna idiom — never a raw setTimeout) rejects the pending request if the\n\t// server never answers. The transport `send` is awaited so a write failure rejects\n\t// here rather than leaving a pending request to time out.\n\t#request(\n\t\tmethod: string,\n\t\tparams: Readonly<Record<string, unknown>> | undefined,\n\t\tdeadline: number | undefined,\n\t\tversion?: MCPVersion,\n\t): Promise<unknown> {\n\t\tthis.#nextId += 1\n\t\tconst id = this.#nextId\n\t\tconst timeout = deadline\n\t\tconst modern = version ?? (this.#era === 'modern' ? this.#version : undefined)\n\t\tconst stamped =\n\t\t\tmodern === undefined\n\t\t\t\t? params\n\t\t\t\t: {\n\t\t\t\t\t\t...(params ?? {}),\n\t\t\t\t\t\t_meta: {\n\t\t\t\t\t\t\t[MCP_META_VERSION]: modern,\n\t\t\t\t\t\t\t[MCP_META_CAPABILITIES]: this.#capabilities,\n\t\t\t\t\t\t\t[MCP_META_CLIENT]: this.#identity,\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\tconst request: JSONRPCRequest = {\n\t\t\tjsonrpc: '2.0',\n\t\t\tid,\n\t\t\tmethod,\n\t\t\t...(stamped === undefined ? {} : { params: stamped }),\n\t\t}\n\t\treturn new Promise<unknown>((resolve, reject) => {\n\t\t\tif (timeout === undefined) {\n\t\t\t\tthis.#pending.set(id, { resolve, reject, method })\n\t\t\t\tthis.#transport.send(request).catch((error: unknown) => {\n\t\t\t\t\tthis.#settle(id, error instanceof Error ? error : new Error(String(error)), true)\n\t\t\t\t})\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst signal = AbortSignal.timeout(timeout)\n\t\t\tconst abort = this.#timeoutRequest.bind(this, id, method, timeout)\n\t\t\tsignal.addEventListener('abort', abort, { once: true })\n\t\t\tthis.#pending.set(id, { resolve, reject, method, deadline: signal, timeout: abort })\n\t\t\tthis.#transport.send(request).catch((error: unknown) => {\n\t\t\t\tthis.#settle(id, error instanceof Error ? error : new Error(String(error)), true)\n\t\t\t})\n\t\t})\n\t}\n\n\t// Handle one inbound transport message: a response settles its pending request by\n\t// id (an error response rejects, a result resolves); anything else (a message with\n\t// no matching pending id) is a server-initiated notification, re-surfaced on the\n\t// `notification` event.\n\t#receive(message: JSONRPCMessage): void {\n\t\tif (isJSONRPCResponse(message) && isRequestId(message.id)) {\n\t\t\tconst pending = this.#pending.get(message.id)\n\t\t\tif (pending !== undefined) {\n\t\t\t\tif (\n\t\t\t\t\tpending.method === 'server/discover' &&\n\t\t\t\t\t(message.error === undefined ||\n\t\t\t\t\t\t(message.error.code !== JSONRPC_METHOD_NOT_FOUND &&\n\t\t\t\t\t\t\tmessage.error.code !== JSONRPC_INVALID_REQUEST))\n\t\t\t\t) {\n\t\t\t\t\tthis.#era = 'modern'\n\t\t\t\t}\n\t\t\t\tif (message.error !== undefined) {\n\t\t\t\t\tthis.#settle(\n\t\t\t\t\t\tmessage.id,\n\t\t\t\t\t\tnew MCPError(message.error.message, message.error.code, message.error.data),\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t)\n\t\t\t\t} else {\n\t\t\t\t\tconst resultType = isRecord(message.result) ? message.result['resultType'] : undefined\n\t\t\t\t\tif (\n\t\t\t\t\t\tisRecord(message.result) &&\n\t\t\t\t\t\tObject.hasOwn(message.result, 'resultType') &&\n\t\t\t\t\t\tresultType !== 'complete'\n\t\t\t\t\t) {\n\t\t\t\t\t\tthis.#settle(\n\t\t\t\t\t\t\tmessage.id,\n\t\t\t\t\t\t\tnew MCPError(\n\t\t\t\t\t\t\t\t`MCP result type '${String(resultType)}' is not supported`,\n\t\t\t\t\t\t\t\tJSONRPC_INVALID_PARAMS,\n\t\t\t\t\t\t\t\t{ resultType },\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.#settle(message.id, message.result, false)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\t// Not a correlated response — a server notification (or an unsolicited response).\n\t\tthis.#emitter.emit('notification', message)\n\t}\n\n\t// Wrap one remote tool descriptor as a local tool: map `inputSchema` → `parameters`\n\t// (the inverse of the server's rename, no `as`), carry `description` when present,\n\t// and bind `execute` to a remote `tools/call` via `call`.\n\t#tool(name: string, descriptor: Readonly<Record<string, unknown>>): ToolInterface {\n\t\tconst inputSchema = descriptor['inputSchema']\n\t\tconst description = descriptor['description']\n\t\tconst options: {\n\t\t\tname: string\n\t\t\tdescription?: string\n\t\t\tparameters?: Readonly<Record<string, unknown>>\n\t\t\texecute: (args: Readonly<Record<string, unknown>>) => Promise<unknown>\n\t\t} = {\n\t\t\tname,\n\t\t\texecute: this.call.bind(this, name),\n\t\t}\n\t\tif (isString(description)) options.description = description\n\t\tif (isRecord(inputSchema)) options.parameters = inputSchema\n\t\treturn new Tool(options)\n\t}\n\n\t// Concatenate an MCP tool-call result's text content blocks into one string — the\n\t// inverse of the server splitting a value into text block(s). Total (§14): a\n\t// non-record result, a non-array `content`, or a non-string `text` contributes\n\t// nothing rather than throwing.\n\t#text(result: unknown): string {\n\t\tif (!isRecord(result) || !isArray(result['content'])) return ''\n\t\tconst parts: string[] = []\n\t\tfor (const block of result['content']) {\n\t\t\tif (isRecord(block) && isString(block['text'])) parts.push(block['text'])\n\t\t}\n\t\treturn parts.join('\\n')\n\t}\n\n\tasync #initialize(version: MCPVersion): Promise<void> {\n\t\tconst result = await this.#request(\n\t\t\t'initialize',\n\t\t\t{\n\t\t\t\tprotocolVersion: version,\n\t\t\t\tcapabilities: {},\n\t\t\t\tclientInfo: this.#identity,\n\t\t\t},\n\t\t\tthis.#timeout,\n\t\t)\n\t\tconst protocol = isRecord(result) ? result['protocolVersion'] : undefined\n\t\tif (protocol === undefined) {\n\t\t\tawait this.#transport.close()\n\t\t\tthrow new Error('MCP server returned no protocol version')\n\t\t}\n\t\tif (!isString(protocol)) {\n\t\t\tawait this.#transport.close()\n\t\t\tthrow new Error('MCP server returned a malformed protocol version')\n\t\t}\n\t\tif (!isMCPVersion(protocol) || inferEra(protocol) !== 'legacy') {\n\t\t\tawait this.#transport.close()\n\t\t\tthrow new Error(`MCP server negotiated unsupported protocol version '${protocol}'`)\n\t\t}\n\t\tthis.#version = protocol\n\t\tthis.#era = 'legacy'\n\t\tthis.#connected = true\n\t\tawait this.#transport.send({ jsonrpc: '2.0', method: 'notifications/initialized' })\n\t\tthis.#emitter.emit('connect')\n\t}\n\n\t#timeoutRequest(id: string | number, method: string, timeout: number): void {\n\t\tthis.#settle(id, new Error(`MCP request '${method}' timed out after ${timeout}ms`), true)\n\t}\n\n\t#settle(id: string | number, value: unknown, failed: boolean): void {\n\t\tconst pending = this.#pending.get(id)\n\t\tif (pending === undefined) return\n\t\tthis.#pending.delete(id)\n\t\tif (pending.deadline !== undefined && pending.timeout !== undefined) {\n\t\t\tpending.deadline.removeEventListener('abort', pending.timeout)\n\t\t}\n\t\tif (failed) pending.reject(value)\n\t\telse pending.resolve(value)\n\t}\n}\n","import type {\n\tClientTransportEventMap,\n\tClientTransportInterface,\n\tJSONRPCMessage,\n\tMCPClientInterface,\n\tMCPClientOptions,\n\tMCPServerInterface,\n\tMCPServerOptions,\n\tMCPTransportInterface,\n} from './types.js'\nimport { Emitter } from '@orkestrel/emitter'\nimport { MCPClient } from './MCPClient.js'\nimport { MCPServer } from './MCPServer.js'\n\n/**\n * Create a transport-agnostic Model Context Protocol server — exposes a live\n * {@link import('@orkestrel/tool').ToolManagerInterface} over JSON-RPC 2.0\n * (`initialize` / `ping` / `tools/list` / `tools/call`).\n *\n * @remarks\n * Pump raw message strings through `handle` (parse → dispatch → serialize) from a\n * transport, or call the typed `dispatch` directly with an already-parsed request.\n * The server is provider-agnostic — JSON-RPC plus the tool registry, with no HTTP\n * and no model. The {@link import('@orkestrel/tool').ToolManagerInterface} already\n * isolates a thrown tool into a `success: false` result (surfaced as an MCP\n * `isError: true` tool result), so a misbehaving tool never crashes a dispatch. Subscribe to the\n * `request` event via `server.emitter.on('request', …)` for tracing.\n *\n * @param options - `identity` (the server identity), `tools` (the live\n * registry to expose), optional `instructions`, and the reserved `on`\n * {@link import('@orkestrel/emitter').EmitterHooks} (see {@link MCPServerOptions})\n * @returns A working {@link MCPServerInterface}\n *\n * @example\n * ```ts\n * import { createMCPServer, createTool, createToolManager } from '@src/core'\n *\n * const tools = createToolManager()\n * tools.add(createTool({ name: 'add', execute: (a) => Number(a.x) + Number(a.y) }))\n *\n * const server = createMCPServer({ identity: { name: 'calculator', version: '1.0.0' }, tools })\n * server.emitter.on('request', (method, id) => log(method, id))\n *\n * // A transport pumps message strings through `handle`:\n * const reply = await server.handle('{\"jsonrpc\":\"2.0\",\"method\":\"tools/list\",\"id\":1}')\n * // reply → '{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"tools\":[{\"name\":\"add\",\"inputSchema\":{\"type\":\"object\"}}]}}'\n * ```\n */\nexport function createMCPServer(options: MCPServerOptions): MCPServerInterface {\n\treturn new MCPServer(options)\n}\n\n/**\n * Create a transport-agnostic Model Context Protocol CLIENT — connects to a REMOTE\n * MCP server over an injected {@link import('./types.js').ClientTransportInterface},\n * runs the `initialize` handshake, and exposes the server's tools as local\n * {@link import('@orkestrel/tool').ToolInterface}s an agent can run.\n *\n * @remarks\n * The egress mirror of {@link createMCPServer}: where the server exposes a local tool\n * registry over MCP, the client USES a remote server's tools. `connect()` handshakes,\n * validates and exposes the negotiated protocol, `tools()` lists + wraps the remote\n * tools (each `execute` calls back over the wire),\n * and `call(name, args)` runs a remote `tools/call` (a remote tool failure throws\n * locally, so an agent's {@link import('@orkestrel/tool').ToolManagerInterface}\n * isolates it). The transport is injected — a concrete one (the HTTP transport over\n * `fetch`) lives in `@src/server`; the client itself is provider-agnostic. Subscribe\n * to `connect` / `disconnect` / `notification` via `client.on(...)` (or\n * `client.emitter.on(...)`).\n *\n * @param options - `transport` (the carrier; REQUIRED), an optional `identity`\n * (the client identity), `timeout` (the per-request deadline), and the reserved `on`\n * {@link import('@orkestrel/emitter').EmitterHooks} (see {@link MCPClientOptions})\n * @returns A working {@link MCPClientInterface}\n *\n * @example\n * ```ts\n * import { createMCPClient } from '@src/core'\n * import { createHTTPClientTransport } from '@src/server'\n *\n * const client = createMCPClient({\n * \ttransport: createHTTPClientTransport({ url: 'http://localhost:3000/mcp' }),\n * })\n * await client.connect()\n * agent.context.tools.add(await client.tools()) // give the agent the remote tools\n * const value = await client.call('search', { query: 'mcp' })\n * ```\n */\nexport function createMCPClient(options: MCPClientOptions): MCPClientInterface {\n\treturn new MCPClient(options)\n}\n\n/**\n * Adapt an {@link MCPTransportInterface} (the environment-agnostic duplex message\n * channel) into a {@link ClientTransportInterface} — the additive bridge that lets\n * `createMCPClient` run over the new port without any change to `MCPClient`'s\n * existing shape.\n *\n * @remarks\n * Hand the RESULT to `createMCPClient({ transport })`, then pass the SAME\n * `transport` to {@link import('./helpers.js').bindClient} to complete the inbound\n * wiring: `send` serializes each outbound {@link JSONRPCMessage} and writes it via\n * `transport.send`; `close` closes the underlying\n * `transport`; `start` is a no-op (the duplex channel is already open by the time\n * it is handed in — there is no separate connect step at this layer); `session` is\n * always `undefined` (session correlation is a higher-level concern the duplex port\n * does not carry). Inbound delivery (`emitter`'s `message` / `close` events) is\n * `bindClient`'s job, not this factory's — the returned object exposes a `message`-\n * capable emitter for `bindClient` to push onto.\n *\n * @param transport - The duplex channel to adapt\n * @returns A {@link ClientTransportInterface} `createMCPClient` can drive\n *\n * @example\n * ```ts\n * const client = createMCPClient({ transport: createDuplexClientTransport(transport) })\n * const unbind = bindClient(client, transport)\n * await client.connect()\n * ```\n */\nexport function createDuplexClientTransport(\n\ttransport: MCPTransportInterface,\n): ClientTransportInterface {\n\tconst emitter = new Emitter<ClientTransportEventMap>()\n\treturn {\n\t\temitter,\n\t\tsession: undefined,\n\t\tasync start(): Promise<void> {\n\t\t\t// The duplex channel is already open by the time it is handed in — no separate\n\t\t\t// connect step at this layer.\n\t\t},\n\t\tasync send(message: JSONRPCMessage): Promise<void> {\n\t\t\tawait transport.send(JSON.stringify(message))\n\t\t},\n\t\tasync close(): Promise<void> {\n\t\t\tawait transport.close()\n\t\t},\n\t}\n}\n"],"mappings":"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"}