@fitzzero/quickdraw-core 5.0.0 → 5.1.0

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.
Files changed (68) hide show
  1. package/README.md +343 -49
  2. package/dist/{admin-BiU4LRZS.d.ts → admin-DKwkIh5i.d.ts} +25 -10
  3. package/dist/{adminSchemas-k5a1Ov7b.d.ts → adminSchemas-2DUA_hZ8.d.ts} +15 -9
  4. package/dist/{auth-CMyRkfjZ.d.ts → auth-BhWqdyb-.d.ts} +2 -2
  5. package/dist/{caller-DHzK3oiI.d.ts → caller-CXTFswBO.d.ts} +28 -6
  6. package/dist/{chunk-2XJFNVHW.js → chunk-2PWMUVC7.js} +1 -1
  7. package/dist/{chunk-2XJFNVHW.js.map → chunk-2PWMUVC7.js.map} +1 -1
  8. package/dist/{chunk-5IC5VZ7T.js → chunk-2UELNHDD.js} +3 -3
  9. package/dist/{chunk-XFDOGTMC.js → chunk-3674EIRT.js} +4 -4
  10. package/dist/{chunk-DNCAI3KY.js → chunk-4DIQHASK.js} +1 -1
  11. package/dist/chunk-4DIQHASK.js.map +1 -0
  12. package/dist/{chunk-LLLYILEP.js → chunk-A6DJBGOG.js} +411 -43
  13. package/dist/chunk-A6DJBGOG.js.map +1 -0
  14. package/dist/{chunk-B2UQ27GH.js → chunk-CDKG4TFA.js} +25 -5
  15. package/dist/{chunk-B2UQ27GH.js.map → chunk-CDKG4TFA.js.map} +1 -1
  16. package/dist/{chunk-IRGAGRVG.js → chunk-JZBCLNDU.js} +4 -4
  17. package/dist/{chunk-XUSN5WKU.js → chunk-KNDDCVQJ.js} +4 -4
  18. package/dist/{chunk-5YRQ26LF.js → chunk-RT6OILOI.js} +1 -1
  19. package/dist/chunk-RT6OILOI.js.map +1 -0
  20. package/dist/{chunk-7QIY2DDX.js → chunk-VJTFXHOK.js} +2 -2
  21. package/dist/{chunk-7QIY2DDX.js.map → chunk-VJTFXHOK.js.map} +1 -1
  22. package/dist/chunk-XNLWBZIG.js +9 -0
  23. package/dist/chunk-XNLWBZIG.js.map +1 -0
  24. package/dist/cli/quickdraw-docs.js +241 -27
  25. package/dist/cli/quickdraw-docs.js.map +1 -1
  26. package/dist/client/index.d.ts +7 -7
  27. package/dist/client/index.js +5 -5
  28. package/dist/{clientTypes-B3o_99Xq.d.ts → clientTypes-Bc-G8n-U.d.ts} +3 -3
  29. package/dist/{connection-DuN8GvcD.d.ts → connection-Cr1BU07W.d.ts} +2 -2
  30. package/dist/{createServer-DUacdfKl.d.ts → createServer-CP9eDHZZ.d.ts} +30 -9
  31. package/dist/{createTestApp-DFLXoTKm.d.ts → createTestApp-UKVGEmOf.d.ts} +6 -6
  32. package/dist/{envelope-nf5eGB-a.d.ts → envelope-Cp3YcVxC.d.ts} +1 -1
  33. package/dist/{http--uoooIH5.d.ts → http-Djj2Inuu.d.ts} +6 -6
  34. package/dist/index.d.ts +6 -6
  35. package/dist/index.js +27 -7
  36. package/dist/index.js.map +1 -1
  37. package/dist/{infer-Dw21kmLw.d.ts → infer-Teo1xpsd.d.ts} +17 -0
  38. package/dist/{metrics-C0WvB7-I.d.ts → metrics-BdBu5o8G.d.ts} +2 -2
  39. package/dist/prisma/index.d.ts +4 -4
  40. package/dist/prisma/index.js +1 -1
  41. package/dist/server/auth/index.d.ts +14 -5
  42. package/dist/server/auth/index.js +0 -5
  43. package/dist/server/auth/index.js.map +1 -1
  44. package/dist/server/index.d.ts +120 -33
  45. package/dist/server/index.js +146 -193
  46. package/dist/server/index.js.map +1 -1
  47. package/dist/server/mcp/index.d.ts +51 -11
  48. package/dist/server/mcp/index.js +129 -8
  49. package/dist/server/mcp/index.js.map +1 -1
  50. package/dist/server/otel.d.ts +3 -3
  51. package/dist/{sharing-n4ss-ONM.d.ts → sharing-DVa8W-yR.d.ts} +3 -3
  52. package/dist/testing/client.d.ts +13 -13
  53. package/dist/testing/client.js +6 -6
  54. package/dist/testing/index.d.ts +156 -12
  55. package/dist/testing/index.js +1037 -22
  56. package/dist/testing/index.js.map +1 -1
  57. package/dist/testing/mock.d.ts +5 -5
  58. package/dist/testing/mock.js +5 -5
  59. package/dist/{types-Bwg3kIEc.d.ts → types-Cu0vmx7c.d.ts} +8 -2
  60. package/dist/utils/index.d.ts +1 -1
  61. package/package.json +1 -1
  62. package/dist/chunk-5YRQ26LF.js.map +0 -1
  63. package/dist/chunk-DNCAI3KY.js.map +0 -1
  64. package/dist/chunk-LLLYILEP.js.map +0 -1
  65. /package/dist/{chunk-5IC5VZ7T.js.map → chunk-2UELNHDD.js.map} +0 -0
  66. /package/dist/{chunk-XFDOGTMC.js.map → chunk-3674EIRT.js.map} +0 -0
  67. /package/dist/{chunk-IRGAGRVG.js.map → chunk-JZBCLNDU.js.map} +0 -0
  68. /package/dist/{chunk-XUSN5WKU.js.map → chunk-KNDDCVQJ.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/server/mcp/tools.ts","../../../src/server/mcp/session.ts","../../../src/server/mcp/custom.ts","../../../src/server/mcp/registry.ts","../../../src/server/mcp/result.ts","../../../src/server/mcp/stdio.ts","../../../src/server/mcp/stderr.ts","../../../src/server/mcp/bootstrap.ts","../../../src/server/mcp/http.ts"],"sourcesContent":["// Tools from contracts (RFC 0003 section 10): one tool per method, made when\n// the registry is built, from what the contract already holds: the input\n// schema, the kind and the `describe` text. 4.1 wrote tool metadata ahead of\n// time by parsing service source files with regular expressions\n// (4.1 `src/server/mcp/generateToolMetadata.ts:255`); nothing is generated\n// ahead of time here.\n//\n// A tool's `inputSchema` is the method input's Standard JSON Schema (Zod 4.2\n// or later), drafted as JSON Schema draft-07, the dialect MCP clients of the\n// 2024-11-05 protocol read. MCP tool arguments are always an object, so:\n//\n// - an object input is the arguments themselves;\n// - an input with no JSON Schema form that accepts `undefined`\n// (`z.undefined()`, `z.void()`) is a tool without arguments;\n// - any other input (a string, a union) is the `input` argument.\n\nimport type { MethodKind } from \"../../contract/methods\";\nimport {\n hasJsonSchema,\n type StandardSchemaV1,\n type StandardSchemaWithJSON,\n} from \"../../contract/standardSchema\";\nimport type { AnyService } from \"../service\";\nimport type { DescribeToolsOptions, McpInputSchema, McpTool } from \"./types\";\n\n/** How a tool's arguments become its input. */\nexport type ArgumentsMode = \"object\" | \"wrapped\" | \"none\";\n\n/** A tool's argument schema, and how its arguments become the input. */\nexport interface ToolInput {\n readonly schema: McpInputSchema;\n readonly mode: ArgumentsMode;\n}\n\n/** A method's tool, with the method it calls. */\nexport interface MethodTool extends ToolInput {\n readonly tool: McpTool;\n readonly service: string;\n readonly method: string;\n}\n\ntype Fail = (message: string) => never;\n\nconst JSON_SCHEMA_TARGET = \"draft-07\";\n\nconst NO_ARGUMENTS: McpInputSchema = Object.freeze({\n type: \"object\",\n properties: Object.freeze({}),\n});\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** True when the schema accepts `undefined` without awaiting anything. */\nfunction acceptsUndefined(schema: StandardSchemaV1): boolean {\n try {\n const result: unknown = schema[\"~standard\"].validate(undefined);\n return isRecord(result) && typeof result.then !== \"function\" && result.issues === undefined;\n } catch {\n return false;\n }\n}\n\n/** The JSON Schema of a schema's input, or why the schema could not write one. */\nfunction draftJsonSchema(schema: StandardSchemaWithJSON): Record<string, unknown> | Error {\n try {\n const json: unknown = schema[\"~standard\"].jsonSchema.input({ target: JSON_SCHEMA_TARGET });\n return isRecord(json) ? json : new Error(\"the schema did not return an object\");\n } catch (error) {\n return error instanceof Error ? error : new Error(String(error));\n }\n}\n\n/**\n * The argument schema of a tool whose input is `schema`, and how its\n * arguments become that input. Fails when the schema cannot describe itself\n * as JSON Schema, naming `label` (what the tool calls) and the fix; `instead`\n * is the other way out. A method can be left out with `exclude`.\n */\nexport function toolInputOf(\n label: string,\n schema: StandardSchemaV1,\n fail: Fail,\n instead = `leave ${label} out with exclude`,\n): ToolInput {\n if (!hasJsonSchema(schema)) {\n fail(\n `the input schema of ${label} cannot describe itself as JSON Schema, which an MCP tool needs: use Zod 4.2 or later for that schema, or ${instead}`,\n );\n }\n const json = draftJsonSchema(schema);\n if (json instanceof Error) {\n if (acceptsUndefined(schema)) {\n return { schema: NO_ARGUMENTS, mode: \"none\" };\n }\n fail(\n `the input schema of ${label} cannot be written as JSON Schema (${json.message}): change that schema, or ${instead}`,\n );\n }\n if (json.type === \"object\") {\n return { schema: json as McpInputSchema, mode: \"object\" };\n }\n const { $schema: dialect, ...input } = json;\n return {\n schema: {\n ...(dialect === undefined ? {} : { $schema: dialect }),\n type: \"object\",\n properties: { input },\n ...(acceptsUndefined(schema) ? {} : { required: [\"input\"] }),\n },\n mode: \"wrapped\",\n };\n}\n\n/** The input a call passes to a tool's handler or method, from the tool's arguments. */\nexport function inputOf(mode: ArgumentsMode, args: unknown): unknown {\n if (mode === \"object\") {\n return args ?? {};\n }\n return mode === \"wrapped\" && isRecord(args) ? args.input : undefined;\n}\n\n/** Whether a method is selected by `include` and `exclude`, after checking every reference names one. */\nfunction selector(\n services: readonly AnyService[],\n options: DescribeToolsOptions,\n fail: Fail,\n): (service: string, method: string) => boolean {\n const known = new Set<string>();\n for (const service of services) {\n known.add(service.name);\n for (const method of Object.keys(service.contract.methods)) {\n known.add(`${service.name}.${method}`);\n }\n }\n const refs = (key: \"include\" | \"exclude\"): ReadonlySet<string> | undefined => {\n const list: unknown = options[key];\n if (list === undefined) {\n return undefined;\n }\n if (!Array.isArray(list) || !list.every((ref) => typeof ref === \"string\")) {\n fail(`${key} must be a list of \"service\" and \"service.method\" names`);\n }\n const unknownRef = list.find((ref) => !known.has(ref));\n if (unknownRef !== undefined) {\n fail(`${key} names \"${unknownRef}\", which is not a service or method being served`);\n }\n return new Set(list);\n };\n const include = refs(\"include\");\n const exclude = refs(\"exclude\");\n const names = (set: ReadonlySet<string>, service: string, method: string): boolean =>\n set.has(service) || set.has(`${service}.${method}`);\n return (service, method) =>\n (include === undefined || names(include, service, method)) &&\n (exclude === undefined || !names(exclude, service, method));\n}\n\n/** The function that names a method's tool: the `name` option, checked, or `{service}_{method}`. */\nfunction toolNamer(\n options: DescribeToolsOptions,\n fail: Fail,\n): (service: string, method: string) => string {\n const { name } = options;\n if (name !== undefined && typeof name !== \"function\") {\n fail(\"name must be a function of (service, method)\");\n }\n return (service, method) => {\n const named: unknown = name === undefined ? `${service}_${method}` : name(service, method);\n if (typeof named !== \"string\" || named === \"\") {\n const shown = typeof named === \"string\" ? `\"\"` : String(named);\n fail(`name returned ${shown} for ${service}.${method}; a tool name is a non-empty string`);\n }\n return named;\n };\n}\n\nfunction describeMethod(service: string, method: string, kind: MethodKind, text: unknown): string {\n return typeof text === \"string\" && text !== \"\" ? text : `${service}.${method} (${kind})`;\n}\n\n/**\n * The method tools of `services`, in service order and then contract order,\n * with what each calls. Fails on a reference, name or schema that cannot\n * make a tool; `fail` prefixes the message with the caller's name.\n */\nexport function planMethodTools(\n services: readonly AnyService[],\n options: DescribeToolsOptions,\n fail: Fail,\n): MethodTool[] {\n const given: unknown = services;\n if (!Array.isArray(given)) {\n fail(\"services must be an array of services from qd.defineService\");\n }\n const selected = selector(services, options, fail);\n const toolName = toolNamer(options, fail);\n const planned: MethodTool[] = [];\n for (const service of services) {\n for (const [method, def] of Object.entries(service.contract.methods)) {\n if (!selected(service.name, method)) {\n continue;\n }\n const label = `${service.name}.${method}`;\n const input = toolInputOf(label, def.input, fail);\n const tool: McpTool = {\n name: toolName(service.name, method),\n description: describeMethod(service.name, method, def.kind, def.describe),\n inputSchema: input.schema,\n ...(def.kind === \"query\" ? { annotations: { readOnlyHint: true } } : {}),\n };\n planned.push({ ...input, tool: Object.freeze(tool), service: service.name, method });\n }\n }\n return planned;\n}\n\n/** Fails when two tools share a name. `owners` names what each tool comes from, for the message. */\nexport function checkUniqueNames(\n tools: readonly { readonly tool: McpTool; readonly owner: string }[],\n fail: Fail,\n): void {\n const seen = new Map<string, string>();\n for (const { tool, owner } of tools) {\n const first = seen.get(tool.name);\n if (first !== undefined) {\n fail(`two tools are named \"${tool.name}\": ${first} and ${owner}`);\n }\n seen.set(tool.name, owner);\n }\n}\n\n/**\n * The MCP tools of `services`: one per contract method, named\n * `{service}_{method}` unless `name` says otherwise, described by the\n * method's `describe` text, with the input schema's JSON Schema as\n * `inputSchema` and `readOnlyHint` on every query. Throws when a method's\n * input schema cannot describe itself as JSON Schema (use Zod 4.2 or later),\n * when `include` or `exclude` names something that is not served, and when\n * two tools would share a name.\n *\n * @example\n * describeTools([taskService], { exclude: [\"taskService.purge\"] });\n */\nexport function describeTools<const S extends readonly AnyService[]>(\n services: S,\n options: DescribeToolsOptions<S> = {},\n): McpTool[] {\n const fail: Fail = (message) => {\n throw new TypeError(`describeTools: ${message}`);\n };\n const planned = planMethodTools(services, options as DescribeToolsOptions, fail);\n checkUniqueNames(\n planned.map((entry) => ({ tool: entry.tool, owner: `${entry.service}.${entry.method}` })),\n fail,\n );\n return planned.map((entry) => entry.tool);\n}\n","// What a tool call runs as: the principal the registry's `principal` hook\n// maps the session or token to, the `ctx.mcp` fields its `context` hook adds,\n// and a synthetic connection id. An MCP call has no socket, so the session id\n// stands in for one: the queries of one stdio session share one concurrency\n// lane (RFC 0003 section 9, step 2), exactly as a socket's queries do.\n\nimport type { Logger } from \"../../contract/logger\";\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport { lazyMembers, type CallOptions } from \"../caller\";\nimport type { Dispatcher } from \"../dispatcher\";\nimport { toQuickdrawError } from \"../pipeline/errors\";\nimport { describeError } from \"../pipeline/metrics\";\nimport type { DispatchRequest, DispatchResult } from \"../pipeline/request\";\nimport { toPrincipal } from \"../transports/auth\";\nimport type { McpContext, Principal } from \"../types\";\nimport type { McpCallOptions, McpCallResult, McpRequest } from \"./types\";\n\n/** Who a tool call acts for, what it adds to `ctx.mcp`, and the connection it counts against. */\nexport interface McpSession {\n readonly principal: Principal | null;\n readonly mcp: McpContext | undefined;\n readonly connectionId: string;\n}\n\n/** The registry's `principal` option, as the bridge calls it. */\nexport type PrincipalHook = (request: McpRequest) => unknown;\n\n/** The registry's `context` option, as the bridge calls it. */\nexport type ContextHook = (request: McpRequest, principal: Principal | null) => unknown;\n\n/** What resolving sessions and making calls in them needs. */\nexport interface SessionSettings {\n readonly dispatcher: Pick<Dispatcher, \"call\">;\n readonly principal: PrincipalHook | undefined;\n readonly context: ContextHook | undefined;\n readonly logger: Logger;\n}\n\nconst CATEGORY = \"quickdraw.mcp\";\n\nasync function principalOf(\n settings: SessionSettings,\n request: McpRequest,\n): Promise<Principal | null> {\n if (settings.principal === undefined) {\n return null;\n }\n try {\n return toPrincipal(await settings.principal(request));\n } catch (error) {\n settings.logger.error(\"MCP authentication failed\", {\n category: CATEGORY,\n transport: request.transport,\n error: describeError(error),\n });\n throw new QuickdrawError(\"UNAUTHENTICATED\", \"Authentication failed\");\n }\n}\n\nasync function contextOf(\n settings: SessionSettings,\n request: McpRequest,\n principal: Principal | null,\n): Promise<McpContext | undefined> {\n if (settings.context === undefined) {\n return undefined;\n }\n const fields: unknown = await settings.context(request, principal);\n if (fields === undefined) {\n return undefined;\n }\n if (typeof fields !== \"object\" || fields === null) {\n throw new TypeError(\"createMcpRegistry: context must return an object, the fields of ctx.mcp\");\n }\n return fields as McpContext;\n}\n\n/**\n * Resolves who a call on `request` acts for and its `ctx.mcp` fields. Rejects\n * with `UNAUTHENTICATED` when the `principal` hook fails; a failing `context`\n * hook rejects with its own error.\n */\nexport async function openSession(\n settings: SessionSettings,\n request: McpRequest,\n): Promise<McpSession> {\n const principal = await principalOf(settings, request);\n const mcp = await contextOf(settings, request, principal);\n return { principal, mcp, connectionId: `mcp:${request.sessionId}` };\n}\n\n/** A failed call's result. An `INTERNAL` failure is logged with what was thrown. */\nexport function failure(settings: SessionSettings, error: unknown, tool: string): McpCallResult {\n const converted = toQuickdrawError(error);\n if (converted.code === \"INTERNAL\") {\n settings.logger.error(`The MCP tool \"${tool}\" failed`, {\n category: CATEGORY,\n tool,\n error: describeError(converted),\n });\n }\n return { ok: false, error: converted };\n}\n\n/**\n * Hands `result` to the transport's `respond`, when it gave one, and returns\n * it. An error `respond` throws is logged and does not change the result.\n */\nexport function settle(\n settings: SessionSettings,\n options: McpCallOptions,\n result: McpCallResult,\n): McpCallResult {\n try {\n options.respond?.(result);\n } catch (error) {\n settings.logger.error(\"An MCP transport failed to send a reply\", {\n category: CATEGORY,\n error: describeError(error),\n });\n }\n return result;\n}\n\n/** A dispatcher result as a tool call's result. MCP calls never send a version, so never \"not modified\". */\nexport function fromDispatch(result: DispatchResult): McpCallResult {\n if (!result.ok) {\n return { ok: false, error: result.error };\n }\n return { ok: true, data: result.notModified === true ? undefined : result.data };\n}\n\n/** The dispatcher request of one method call made in `session`. */\nexport function sessionRequest(\n session: McpSession,\n call: Pick<DispatchRequest, \"service\" | \"method\" | \"input\" | \"signal\" | \"respond\">,\n): DispatchRequest {\n return {\n ...call,\n principal: session.principal,\n transport: \"mcp\",\n connectionId: session.connectionId,\n mcp: session.mcp,\n };\n}\n\ntype MethodFunction = (input?: unknown, options?: CallOptions) => Promise<unknown>;\n\n/**\n * An in-process caller acting in `session`: each call goes through the\n * dispatcher as an MCP call, with the session's principal, connection and\n * `ctx.mcp`, so a custom tool cannot reach past what the agent may do.\n */\nexport function sessionCaller(\n settings: SessionSettings,\n session: McpSession,\n signal: AbortSignal,\n): object {\n return lazyMembers((service) =>\n lazyMembers<MethodFunction>((method) => async (input, options) => {\n const request = sessionRequest(session, {\n service,\n method,\n input,\n signal: options?.signal ?? signal,\n });\n const result = await settings.dispatcher.call(request);\n if (!result.ok) {\n throw result.error;\n }\n return result.notModified === true ? undefined : result.data;\n }),\n );\n}\n","// Custom tools (RFC 0003 section 10): an app's own tools, served beside the\n// ones generated from contracts. 4.1's registry had no hook for them\n// (4.1 `src/server/mcp/McpRegistry.ts:13`), so apps that needed one ran a\n// bridge of their own. A custom tool fails closed like a method: unless it\n// declares `access: \"public\"`, an anonymous caller is refused before anything\n// runs. A custom tool that gives a Standard Schema has its arguments\n// validated before its handler runs, as a method's input is, and every\n// handler gets a caller that acts in the same session.\n\nimport { isStandardSchema, type StandardSchemaV1 } from \"../../contract/standardSchema\";\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport { NEVER_ABORTED } from \"../context\";\nimport { parseInput } from \"../pipeline/validation\";\nimport { failure, sessionCaller, type McpSession, type SessionSettings } from \"./session\";\nimport { inputOf, toolInputOf, type ArgumentsMode, type ToolInput } from \"./tools\";\nimport type {\n McpCallOptions,\n McpCallResult,\n McpInputSchema,\n McpTool,\n McpToolAccess,\n McpToolCall,\n} from \"./types\";\n\n/** A checked custom tool. */\nexport interface CustomTool {\n readonly tool: McpTool;\n /** Who may call it; `\"authenticated\"` unless the tool said otherwise. */\n readonly access: McpToolAccess;\n readonly mode: ArgumentsMode;\n /** The schema that validates the arguments, when the tool gave a Standard Schema. */\n readonly schema: StandardSchemaV1 | undefined;\n readonly handler: (call: McpToolCall) => unknown;\n}\n\ntype Fail = (message: string) => never;\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction argumentsOf(owner: string, inputSchema: unknown, fail: Fail): ToolInput {\n if (isStandardSchema(inputSchema)) {\n return toolInputOf(owner, inputSchema, fail, \"give the tool a JSON Schema object instead\");\n }\n if (isRecord(inputSchema) && inputSchema.type === \"object\") {\n return { schema: inputSchema as McpInputSchema, mode: \"object\" };\n }\n return fail(\n `${owner}: inputSchema must be a Standard Schema, or a JSON Schema whose type is \"object\"`,\n );\n}\n\nfunction accessOf(owner: string, access: unknown, fail: Fail): McpToolAccess {\n if (access === undefined) {\n return \"authenticated\";\n }\n if (access !== \"public\" && access !== \"authenticated\") {\n fail(`${owner}: access must be \"public\" or \"authenticated\"`);\n }\n return access;\n}\n\nfunction checkCustomTool(value: unknown, index: number, fail: Fail): CustomTool {\n if (!isRecord(value)) {\n fail(`customTools[${index}] must be { name, description, inputSchema, handler }`);\n }\n const { name, description, inputSchema, annotations, handler } = value;\n if (typeof name !== \"string\" || name === \"\") {\n fail(`customTools[${index}] needs a name, a non-empty string`);\n }\n const owner = `custom tool \"${name}\"`;\n if (typeof description !== \"string\" || description === \"\") {\n fail(`${owner} needs a description, a non-empty string`);\n }\n if (typeof handler !== \"function\") {\n fail(`${owner} needs a handler function`);\n }\n if (annotations !== undefined && !isRecord(annotations)) {\n fail(`${owner}: annotations must be an object of hints`);\n }\n const access = accessOf(owner, value.access, fail);\n const input = argumentsOf(owner, inputSchema, fail);\n const tool: McpTool = {\n name,\n description,\n inputSchema: input.schema,\n ...(annotations === undefined ? {} : { annotations }),\n };\n return {\n tool: Object.freeze(tool),\n access,\n mode: input.mode,\n schema: isStandardSchema(inputSchema) ? inputSchema : undefined,\n handler: handler as CustomTool[\"handler\"],\n };\n}\n\n/** Checks the registry's `customTools` option. */\nexport function checkCustomTools(value: unknown, fail: Fail): CustomTool[] {\n if (value === undefined) {\n return [];\n }\n if (!Array.isArray(value)) {\n fail(\"customTools must be an array of { name, description, inputSchema, handler }\");\n }\n return value.map((tool: unknown, index) => checkCustomTool(tool, index, fail));\n}\n\n/**\n * Runs a custom tool with the arguments `args` in `session`: refuses an\n * anonymous caller unless the tool's access is `\"public\"`\n * (`UNAUTHENTICATED`), validates the arguments when the tool gave a Standard\n * Schema (`VALIDATION` with the issues otherwise), then runs the handler.\n * Never rejects.\n */\nexport async function runCustomTool(\n settings: SessionSettings,\n custom: CustomTool,\n args: unknown,\n session: McpSession,\n options: McpCallOptions,\n): Promise<McpCallResult> {\n const { name } = custom.tool;\n const signal = options.signal ?? NEVER_ABORTED;\n try {\n if (custom.access === \"authenticated\" && session.principal === null) {\n throw new QuickdrawError(\"UNAUTHENTICATED\", \"Authentication required\");\n }\n const input = inputOf(custom.mode, args);\n const parsed =\n custom.schema === undefined\n ? input\n : await parseInput(custom.schema, input, `the tool \"${name}\"`);\n const data: unknown = await custom.handler({\n arguments: parsed,\n principal: session.principal,\n mcp: session.mcp,\n caller: sessionCaller(settings, session, signal) as McpToolCall[\"caller\"],\n signal,\n request: options.request,\n });\n return { ok: true, data };\n } catch (error) {\n return failure(settings, error, name);\n }\n}\n","// `createMcpRegistry` (RFC 0003 section 10): the tools of an app's services,\n// generated from their contracts, plus the app's own, and one `call` every\n// MCP transport uses. It replaces 4.1's `McpRegistry`\n// (4.1 `src/server/mcp/McpRegistry.ts:13`), which validated input, checked\n// access and ran handlers itself, as whatever user the tool's `userId`\n// argument named. Here a method's tool call goes through the dispatcher with\n// transport `\"mcp\"`, so validation, access checks and limits apply exactly as\n// for a socket call; the transport says who is calling through `principal`,\n// and `context` adds the session's own fields to the handler's `ctx.mcp`.\n\nimport { consoleLogger, type Logger } from \"../../contract/logger\";\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport type { Dispatcher, PrincipalOfServices } from \"../dispatcher\";\nimport type { AnyService } from \"../service\";\nimport type { AuthenticateResult } from \"../transports/auth\";\nimport type { MaybePromise } from \"../types\";\nimport { checkCustomTools, runCustomTool, type CustomTool } from \"./custom\";\nimport {\n failure,\n fromDispatch,\n openSession,\n sessionRequest,\n settle,\n type McpSession,\n type SessionSettings,\n} from \"./session\";\nimport { checkUniqueNames, inputOf, planMethodTools, type MethodTool } from \"./tools\";\nimport type {\n DescribeToolsOptions,\n McpCallOptions,\n McpCallResult,\n McpContextOfServices,\n McpCustomTool,\n McpRequest,\n McpTool,\n McpToolInputSchema,\n} from \"./types\";\n\n/**\n * Options of {@link createMcpRegistry}. `Tools` are the custom tools' input\n * schema types, one per tool, which type each handler's `arguments`.\n */\nexport interface McpRegistryOptions<\n S extends readonly AnyService[],\n Tools extends readonly McpToolInputSchema[] = readonly McpToolInputSchema[],\n> extends DescribeToolsOptions<S> {\n /** The services whose methods become tools. The dispatcher must serve each of them. */\n readonly services: S;\n /** The dispatcher every method's tool calls through, with transport `\"mcp\"`. */\n readonly dispatcher: Pick<Dispatcher, \"call\" | \"registry\">;\n /**\n * Says who an MCP session or request acts for: a principal, a user id when\n * a bare `{ userId }` is a principal of the app's type, or nothing for an\n * anonymous caller, who may call `\"public\"` methods and `\"public\"` custom\n * tools only. A stdio server usually reads a token from its environment;\n * an HTTP request carries one as a bearer token. Throwing fails the call\n * with `UNAUTHENTICATED`. Without it every call is anonymous.\n */\n readonly principal?: (\n request: McpRequest,\n ) => MaybePromise<AuthenticateResult<PrincipalOfServices<S>>>;\n /**\n * The fields handlers see as `ctx.mcp` on calls from this registry, typed\n * by the app's `QuickdrawTypes[\"mcp\"]`: the scopes of the agent's token,\n * for example. Runs per call, after `principal`.\n */\n readonly context?: (\n request: McpRequest,\n principal: PrincipalOfServices<S> | null,\n ) => MaybePromise<McpContextOfServices<S>>;\n /** The app's own tools, listed after the generated ones. */\n readonly customTools?: { readonly [K in keyof Tools]: McpCustomTool<S, Tools[K]> };\n /** Receives tool failures and authentication errors. Default: the console. */\n readonly logger?: Logger;\n}\n\n/** The tools an MCP transport serves, and the one way to call them. */\nexport interface McpRegistry {\n /**\n * Every tool, generated ones first, as `tools/list` and `GET /mcp/tools`\n * return them: the same list for every caller, never filtered by the\n * principal, so an agent may see tools whose calls are refused. A\n * registry's `include`/`exclude` decide the list; serve agents of\n * different reach from separate registries.\n */\n readonly tools: readonly McpTool[];\n /** True when a tool has this name. */\n has(name: string): boolean;\n /**\n * Calls the tool `name` with the client's `args` in the session of\n * `options.request`. Resolves with the tool's value or its failure (an\n * unknown name is `NOT_FOUND`), after `options.respond` was given it.\n * Never rejects.\n */\n call(name: string, args: unknown, options: McpCallOptions): Promise<McpCallResult>;\n /**\n * Calls a method's tool by its service and method name with the method's\n * `input` as it is, without the tool's argument mapping: the shape 4.1's\n * HTTP route took. A method that is not a tool is `NOT_FOUND`.\n */\n callMethod(\n service: string,\n method: string,\n input: unknown,\n options: McpCallOptions,\n ): Promise<McpCallResult>;\n}\n\ntype Entry =\n | ({ readonly kind: \"method\" } & MethodTool)\n | ({ readonly kind: \"custom\" } & CustomTool);\n\ninterface RegistrySettings extends SessionSettings {\n /** Every tool by name, in listing order. */\n readonly entries: ReadonlyMap<string, Entry>;\n /** The method tools by {@link methodKey}. */\n readonly methods: ReadonlyMap<string, MethodTool>;\n}\n\ntype Fail = (message: string) => never;\n\n/** A method's key, unambiguous whatever characters its names hold. */\nfunction methodKey(service: string, method: string): string {\n return `${service}\\u0000${method}`;\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction checkHook(name: string, hook: unknown, fail: Fail): void {\n if (hook !== undefined && typeof hook !== \"function\") {\n fail(`${name} must be a function of the MCP request`);\n }\n}\n\n/** Fails unless `dispatcher` serves every one of `services`, as the very same service objects. */\nfunction checkDispatcher(dispatcher: unknown, services: unknown, fail: Fail): void {\n if (\n !isRecord(dispatcher) ||\n typeof dispatcher.call !== \"function\" ||\n !isRecord(dispatcher.registry) ||\n !(dispatcher.registry.services instanceof Map)\n ) {\n fail(\"dispatcher must be a dispatcher from createDispatcher or qd.createServer\");\n }\n if (!Array.isArray(services)) {\n fail(\"services must be an array of services from qd.defineService\");\n }\n const served = dispatcher.registry.services as ReadonlyMap<string, unknown>;\n for (const service of services) {\n const name: unknown = isRecord(service) ? service.name : undefined;\n if (typeof name !== \"string\" || served.get(name) !== service) {\n fail(\n `the dispatcher does not serve ${typeof name === \"string\" ? name : \"one of the services\"}; pass services the dispatcher was created with`,\n );\n }\n }\n}\n\nfunction resolveRegistry(options: McpRegistryOptions<readonly AnyService[]>): RegistrySettings {\n const fail: Fail = (message) => {\n throw new TypeError(`createMcpRegistry: ${message}`);\n };\n if (!isRecord(options)) {\n fail(\"options must be an object with services and dispatcher\");\n }\n checkDispatcher(options.dispatcher, options.services, fail);\n checkHook(\"principal\", options.principal, fail);\n checkHook(\"context\", options.context, fail);\n const methodTools = planMethodTools(options.services, options, fail);\n const customTools = checkCustomTools(options.customTools, fail);\n const entries: Entry[] = [\n ...methodTools.map((tool) => ({ kind: \"method\" as const, ...tool })),\n ...customTools.map((tool) => ({ kind: \"custom\" as const, ...tool })),\n ];\n checkUniqueNames(\n entries.map((entry) => ({\n tool: entry.tool,\n owner: entry.kind === \"method\" ? `${entry.service}.${entry.method}` : \"a custom tool\",\n })),\n fail,\n );\n return {\n dispatcher: options.dispatcher,\n principal: options.principal,\n context: options.context as SessionSettings[\"context\"],\n logger: options.logger ?? consoleLogger,\n entries: new Map(entries.map((entry) => [entry.tool.name, entry])),\n methods: new Map(methodTools.map((tool) => [methodKey(tool.service, tool.method), tool])),\n };\n}\n\n/** Runs `run` in the session of `options.request`, or fails the call when the session cannot open. */\nasync function inSession(\n settings: RegistrySettings,\n name: string,\n options: McpCallOptions,\n run: (session: McpSession) => Promise<McpCallResult>,\n): Promise<McpCallResult> {\n let session: McpSession;\n try {\n session = await openSession(settings, options.request);\n } catch (error) {\n return settle(settings, options, failure(settings, error, name));\n }\n return run(session);\n}\n\n/** Calls a method through the dispatcher, which hands the result to `respond` before it flushes. */\nasync function dispatchMethod(\n settings: RegistrySettings,\n tool: MethodTool,\n input: unknown,\n session: McpSession,\n options: McpCallOptions,\n): Promise<McpCallResult> {\n const { respond } = options;\n const request = sessionRequest(session, {\n service: tool.service,\n method: tool.method,\n input,\n signal: options.signal,\n respond: respond === undefined ? undefined : (result) => respond(fromDispatch(result)),\n });\n return fromDispatch(await settings.dispatcher.call(request));\n}\n\nfunction callTool(\n settings: RegistrySettings,\n name: string,\n args: unknown,\n options: McpCallOptions,\n): Promise<McpCallResult> {\n const entry = settings.entries.get(name);\n if (entry === undefined) {\n const error = new QuickdrawError(\"NOT_FOUND\", `Unknown tool \"${name}\"`);\n return Promise.resolve(settle(settings, options, { ok: false, error }));\n }\n if (entry.kind === \"method\") {\n const input = inputOf(entry.mode, args);\n return inSession(settings, name, options, (session) =>\n dispatchMethod(settings, entry, input, session, options),\n );\n }\n return inSession(settings, name, options, async (session) =>\n settle(settings, options, await runCustomTool(settings, entry, args, session, options)),\n );\n}\n\nfunction callMethodTool(\n settings: RegistrySettings,\n service: string,\n method: string,\n input: unknown,\n options: McpCallOptions,\n): Promise<McpCallResult> {\n const tool = settings.methods.get(methodKey(service, method));\n if (tool === undefined) {\n const error = new QuickdrawError(\"NOT_FOUND\", `${service}.${method} is not an MCP tool`);\n return Promise.resolve(settle(settings, options, { ok: false, error }));\n }\n return inSession(settings, tool.tool.name, options, (session) =>\n dispatchMethod(settings, tool, input, session, options),\n );\n}\n\n/**\n * Builds the MCP tools of `services` (see `describeTools`) and the app's\n * `customTools`, served by `dispatcher`. Throws at once when a method's\n * input schema cannot describe itself as JSON Schema (use Zod 4.2 or later\n * for it, or `exclude` the method), when two tools share a name, or when the\n * dispatcher does not serve one of the services.\n *\n * @example\n * const registry = createMcpRegistry({\n * services: [taskService, projectService],\n * dispatcher: server.dispatcher,\n * principal: (request) => verifyAgentToken(request.transport === \"http\" ? request.token : process.env.AGENT_TOKEN),\n * context: (request) => ({ scopes: scopesOf(request) }),\n * });\n */\nexport function createMcpRegistry<\n const S extends readonly AnyService[],\n const Tools extends readonly McpToolInputSchema[] = [],\n>(options: McpRegistryOptions<S, Tools>): McpRegistry {\n const settings = resolveRegistry(options as unknown as McpRegistryOptions<readonly AnyService[]>);\n const tools = Object.freeze([...settings.entries.values()].map((entry) => entry.tool));\n return Object.freeze({\n tools,\n has: (name: string) => settings.entries.has(name),\n call: (name: string, args: unknown, callOptions: McpCallOptions) =>\n callTool(settings, name, args, callOptions),\n callMethod: (service: string, method: string, input: unknown, callOptions: McpCallOptions) =>\n callMethodTool(settings, service, method, input, callOptions),\n });\n}\n","// A tool call's result in the shape of MCP's `tools/call` result, as 4.1\n// wrote it (4.1 `src/server/mcp/McpStdioServer.ts:85-96`): one text block\n// holding the value as indented JSON. A failure is a tool error (`isError`)\n// whose text is the error's wire form, `{ code, message, data? }`, so the\n// agent sees the code; 4.1 answered a failed call with a JSON-RPC error\n// instead. An `INTERNAL` failure keeps its generic message (`toWire`).\n\nimport { toWire } from \"../../protocol/errors\";\nimport type { McpCallResult, McpTextContent, McpToolResult } from \"./types\";\n\nfunction jsonText(value: unknown): McpTextContent {\n // `JSON.stringify` returns `undefined` for `undefined` (a method that\n // returns nothing) and for a function.\n const text: string | undefined = JSON.stringify(value, null, 2);\n return { type: \"text\", text: text ?? \"null\" };\n}\n\n/**\n * The `tools/call` result of a tool call. Throws when the value cannot be\n * written as JSON (a `BigInt` or a cycle); a transport answers that with an\n * `INTERNAL` tool error.\n *\n * @example\n * toToolResult(await registry.call(name, args, { request }));\n */\nexport function toToolResult(result: McpCallResult): McpToolResult {\n if (!result.ok) {\n return { content: [jsonText(toWire(result.error))], isError: true };\n }\n return { content: [jsonText(result.data)] };\n}\n","// The MCP stdio server: JSON-RPC 2.0, one message per line, on stdin and\n// stdout (RFC 0003 section 10). Ported from 4.1's `createMcpStdioServer`\n// (4.1 `src/server/mcp/McpStdioServer.ts:22`), keeping its wire format:\n// protocol version 2024-11-05, `initialize`, `ping`, `tools/list` and\n// `tools/call`, a tool's value as one block of JSON text, and the same\n// JSON-RPC error codes. What changed:\n//\n// - tools come from the registry, and who is calling from its `principal`\n// hook, rather than from a `userId` argument any agent could set;\n// - a failed call is a tool result with `isError` whose text carries the\n// error's code, where 4.1 answered with a JSON-RPC error;\n// - requests are handled concurrently, so the session's queries share one\n// concurrency lane, and `notifications/cancelled` stops a call in flight\n// (MCP sends no reply for a cancelled request);\n// - notifications never get a reply, and a JSON-RPC response from the client\n// is ignored;\n// - it never exits the process: `closed` resolves once stdin ends and every\n// call still running has answered (a client that writes its requests and\n// closes stdin still gets every reply), while `close()` and a broken\n// stream cancel the calls in flight instead.\n//\n// Anything else that writes to stdout corrupts the protocol, so start the\n// server through `bootstrapMcpServer`, which sends console output to stderr.\n\nimport { randomUUID } from \"node:crypto\";\nimport { createInterface } from \"node:readline\";\nimport type { Readable, Writable } from \"node:stream\";\nimport type { Logger } from \"../../contract/logger\";\nimport { INTERNAL_MESSAGE, QuickdrawError } from \"../../protocol/errors\";\nimport { describeError } from \"../pipeline/metrics\";\nimport type { McpRegistry } from \"./registry\";\nimport { toToolResult } from \"./result\";\nimport { stderrLogger } from \"./stderr\";\nimport type { McpCallResult, McpStdioRequest } from \"./types\";\n\n/** The MCP protocol version the stdio server speaks: 4.1's. */\nexport const MCP_PROTOCOL_VERSION = \"2024-11-05\";\n\n/** Options of {@link createMcpStdioServer}. */\nexport interface McpStdioServerOptions {\n /** The tools to serve. */\n readonly registry: McpRegistry;\n /** The server's name, sent in `initialize`'s `serverInfo`. */\n readonly name: string;\n /** The server's version, sent in `initialize`'s `serverInfo`. */\n readonly version: string;\n /** Where messages arrive. Default `process.stdin`. */\n readonly input?: Readable;\n /** Where replies go. Default `process.stdout`. */\n readonly output?: Writable;\n /** Receives the server's own problems. Default: one line per entry on stderr. */\n readonly logger?: Logger;\n}\n\n/** A running stdio server. */\nexport interface McpStdioServer {\n /** The session id every call of this server carries, and its synthetic connection. */\n readonly sessionId: string;\n /**\n * Resolves once the input has ended and every message in flight has been\n * handled: when stdin ends, the calls still running finish and their\n * replies are written first.\n */\n readonly closed: Promise<void>;\n /** Stops reading and cancels the calls in flight (no reply is written for them); resolves as `closed` does. */\n close(): Promise<void>;\n}\n\ntype RequestId = string | number;\n\ninterface Session {\n readonly registry: McpRegistry;\n readonly serverInfo: { readonly name: string; readonly version: string };\n readonly request: McpStdioRequest;\n readonly output: Writable;\n readonly logger: Logger;\n /** The `tools/call` requests in flight, by id, so they can be cancelled. */\n readonly calls: Map<RequestId, AbortController>;\n /** Every message still being handled. */\n readonly pending: Set<Promise<void>>;\n /** False once the output failed. */\n writable: boolean;\n}\n\nconst PARSE_ERROR = -32700;\nconst INVALID_REQUEST = -32600;\nconst METHOD_NOT_FOUND = -32601;\nconst INVALID_PARAMS = -32602;\nconst CATEGORY = \"quickdraw.mcp\";\n\nconst INTERNAL_FAILURE: McpCallResult = Object.freeze({\n ok: false,\n error: new QuickdrawError(\"INTERNAL\", INTERNAL_MESSAGE),\n});\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** MCP request ids are strings or numbers, never `null`. */\nfunction isRequestId(value: unknown): value is RequestId {\n return typeof value === \"string\" || (typeof value === \"number\" && Number.isFinite(value));\n}\n\n/** Writes one message as one line; returns its size in bytes. */\nfunction write(session: Session, message: object): number | undefined {\n if (!session.writable) {\n return undefined;\n }\n const line = `${JSON.stringify(message)}\\n`;\n session.output.write(line);\n return Buffer.byteLength(line);\n}\n\nfunction reply(session: Session, id: RequestId, result: unknown): number | undefined {\n return write(session, { jsonrpc: \"2.0\", id, result });\n}\n\nfunction replyError(session: Session, id: RequestId | null, code: number, message: string): void {\n write(session, { jsonrpc: \"2.0\", id, error: { code, message } });\n}\n\nfunction replyToolResult(\n session: Session,\n id: RequestId,\n result: McpCallResult,\n): number | undefined {\n let content: unknown;\n try {\n content = toToolResult(result);\n } catch (error) {\n session.logger.error(\n \"A tool's value could not be written as JSON; it was answered with INTERNAL\",\n {\n category: CATEGORY,\n error: describeError(error),\n },\n );\n content = toToolResult(INTERNAL_FAILURE);\n }\n return reply(session, id, content);\n}\n\nasync function callTool(session: Session, id: RequestId, params: unknown): Promise<void> {\n if (!isRecord(params) || typeof params.name !== \"string\") {\n replyError(session, id, INVALID_PARAMS, \"tools/call needs params { name, arguments? }\");\n return;\n }\n const { name } = params;\n if (!session.registry.has(name)) {\n replyError(session, id, INVALID_PARAMS, `Unknown tool: ${name}`);\n return;\n }\n if (session.calls.has(id)) {\n replyError(session, id, INVALID_REQUEST, `Request ${JSON.stringify(id)} is already in flight`);\n return;\n }\n const controller = new AbortController();\n session.calls.set(id, controller);\n const release = (): void => {\n if (session.calls.get(id) === controller) {\n session.calls.delete(id);\n }\n };\n try {\n await session.registry.call(name, params.arguments, {\n request: session.request,\n signal: controller.signal,\n respond: (result) => {\n release();\n // A cancelled call gets no reply, nor does one whose session ended.\n return controller.signal.aborted ? undefined : replyToolResult(session, id, result);\n },\n });\n } finally {\n release();\n }\n}\n\nasync function onRequest(\n session: Session,\n id: RequestId,\n method: string,\n params: unknown,\n): Promise<void> {\n switch (method) {\n case \"initialize\":\n reply(session, id, {\n protocolVersion: MCP_PROTOCOL_VERSION,\n serverInfo: session.serverInfo,\n capabilities: { tools: {} },\n });\n return;\n case \"ping\":\n reply(session, id, {});\n return;\n case \"tools/list\":\n reply(session, id, { tools: session.registry.tools });\n return;\n case \"tools/call\":\n await callTool(session, id, params);\n return;\n default:\n replyError(session, id, METHOD_NOT_FOUND, `Method not found: ${method}`);\n }\n}\n\n/** `notifications/cancelled` stops a call in flight; every other notification needs nothing. */\nfunction onNotification(session: Session, method: string, params: unknown): void {\n if (method === \"notifications/cancelled\" && isRecord(params) && isRequestId(params.requestId)) {\n session.calls.get(params.requestId)?.abort();\n }\n}\n\nconst UNPARSABLE = Symbol(\"unparsable\");\n\nfunction parse(line: string): unknown {\n try {\n return JSON.parse(line) as unknown;\n } catch {\n return UNPARSABLE;\n }\n}\n\nasync function onLine(session: Session, line: string): Promise<void> {\n if (line.trim() === \"\") {\n return;\n }\n const message = parse(line);\n if (message === UNPARSABLE) {\n replyError(session, null, PARSE_ERROR, \"Parse error\");\n return;\n }\n if (!isRecord(message)) {\n replyError(session, null, INVALID_REQUEST, \"Invalid Request\");\n return;\n }\n const { id, method, params } = message;\n if (typeof method !== \"string\") {\n // A response to a request this server never sends: answering it could loop.\n if (!(\"result\" in message) && !(\"error\" in message)) {\n replyError(session, isRequestId(id) ? id : null, INVALID_REQUEST, \"Invalid Request\");\n }\n return;\n }\n if (id === undefined) {\n onNotification(session, method, params);\n return;\n }\n if (!isRequestId(id)) {\n replyError(session, null, INVALID_REQUEST, \"Invalid Request\");\n return;\n }\n await onRequest(session, id, method, params);\n}\n\n/** Handles one message, keeping track of it until it is done. */\nfunction track(session: Session, work: Promise<void>): void {\n const handled = work.catch((error: unknown) => {\n session.logger.error(\"The MCP stdio server failed to handle a message\", {\n category: CATEGORY,\n error: describeError(error),\n });\n });\n session.pending.add(handled);\n void handled.then(() => session.pending.delete(handled));\n}\n\nfunction openSession(options: McpStdioServerOptions): Session {\n if (\n typeof options !== \"object\" ||\n options === null ||\n typeof options.registry?.call !== \"function\"\n ) {\n throw new TypeError(\"createMcpStdioServer: registry must come from createMcpRegistry\");\n }\n if (typeof options.name !== \"string\" || typeof options.version !== \"string\") {\n throw new TypeError(\"createMcpStdioServer: name and version must be strings, for serverInfo\");\n }\n return {\n registry: options.registry,\n serverInfo: Object.freeze({ name: options.name, version: options.version }),\n request: Object.freeze({ transport: \"stdio\", sessionId: randomUUID() }),\n output: options.output ?? process.stdout,\n logger: options.logger ?? stderrLogger,\n calls: new Map(),\n pending: new Set(),\n writable: true,\n };\n}\n\n/**\n * Serves `registry`'s tools over MCP's stdio transport: JSON-RPC messages,\n * one per line, read from stdin and answered on stdout. The server is one\n * session: its calls carry one session id and share one concurrency lane,\n * and the registry's `principal` and `context` hooks see the same\n * `{ transport: \"stdio\", sessionId }` request on every call. It never exits\n * the process.\n *\n * @example\n * // mcp-server.ts, started through bootstrapMcpServer\n * const registry = createMcpRegistry({ services, dispatcher, principal: () => agentFromEnv() });\n * const server = createMcpStdioServer({ registry, name: \"my-app\", version: \"1.0.0\" });\n * await server.closed;\n * await prisma.$disconnect();\n */\nexport function createMcpStdioServer(options: McpStdioServerOptions): McpStdioServer {\n const session = openSession(options);\n const lines = createInterface({\n input: options.input ?? process.stdin,\n crlfDelay: Infinity,\n terminal: false,\n });\n // Ending stdin lets the calls in flight answer; `close()` and a broken stream cancel them.\n let cancel = false;\n const stop = (): void => {\n cancel = true;\n lines.close();\n };\n const fail = (error: Error): void => {\n session.logger.warn(\"The MCP stdio stream failed; the session ends\", {\n category: CATEGORY,\n error: describeError(error),\n });\n stop();\n };\n const onOutputError = (error: Error): void => {\n session.writable = false;\n fail(error);\n };\n session.output.on(\"error\", onOutputError);\n lines.on(\"error\", fail);\n lines.on(\"line\", (line) => track(session, onLine(session, line)));\n const closed = new Promise<void>((resolve) => {\n lines.once(\"close\", () => {\n for (const controller of cancel ? session.calls.values() : []) {\n controller.abort();\n }\n void Promise.allSettled([...session.pending]).then(() => {\n session.output.off(\"error\", onOutputError);\n resolve();\n });\n });\n });\n return Object.freeze({\n sessionId: session.request.sessionId,\n closed,\n close: () => {\n stop();\n return closed;\n },\n });\n}\n","// Writing to stderr. An MCP stdio server owns stdout for the protocol, so its\n// own log lines, and everything `bootstrapMcpServer` takes from the console,\n// go to stderr instead.\n\nimport { format, inspect } from \"node:util\";\nimport type { Logger } from \"../../contract/logger\";\n\n/** Writes one line to stderr, formatting the arguments as `console.log` would. */\nexport function writeStderr(...args: unknown[]): void {\n process.stderr.write(`${format(...args)}\\n`);\n}\n\nfunction entry(level: string): (message: string, meta?: Record<string, unknown>) => void {\n return (message, meta) => {\n const details = meta === undefined ? \"\" : ` ${inspect(meta, { breakLength: Infinity })}`;\n process.stderr.write(`[${level}] ${message}${details}\\n`);\n };\n}\n\n/** A logger that writes each entry to stderr as one line. */\nexport const stderrLogger: Logger = {\n debug: entry(\"DEBUG\"),\n info: entry(\"INFO\"),\n warn: entry(\"WARN\"),\n error: entry(\"ERROR\"),\n child: () => stderrLogger,\n};\n","// `bootstrapMcpServer`: loads the module that starts an MCP stdio server\n// after sending console output to stderr, so nothing but the protocol\n// reaches stdout, not even what that module's imports log while loading.\n// Ported from 4.1 (4.1 `src/server/mcp/McpBootstrap.ts:12`) with two\n// changes: a relative path is resolved against the working directory (4.1\n// handed it to `import()`, which resolves it against the package's own file,\n// so a relative path never found the app's module), and a module that fails\n// to load sets the exit code instead of calling `process.exit`.\n\nimport { resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { writeStderr } from \"./stderr\";\n\nfunction specifierOf(serverModule: string | URL): string {\n if (serverModule instanceof URL) {\n return serverModule.href;\n }\n return serverModule.startsWith(\"file:\")\n ? serverModule\n : pathToFileURL(resolve(serverModule)).href;\n}\n\n/**\n * Sends `console.log`, `info`, `warn` and `debug` to stderr, sets\n * `MCP_MODE=true` (and `LOG_LEVEL=warn` unless it is set), then imports\n * `serverModule`, the module that creates the stdio server. A path is\n * resolved against the working directory; pass a URL to resolve it against\n * the calling module. Resolves once the module has loaded. When it fails to\n * load, the error goes to stderr and the process exit code becomes 1.\n *\n * @example\n * // mcp.ts: the MCP client runs `node dist/mcp.js`\n * import { bootstrapMcpServer } from \"@fitzzero/quickdraw-core/server/mcp\";\n * await bootstrapMcpServer(new URL(\"./mcp-server.js\", import.meta.url));\n */\nexport async function bootstrapMcpServer(serverModule: string | URL): Promise<void> {\n process.env.MCP_MODE = \"true\";\n process.env.LOG_LEVEL ??= \"warn\";\n // The console methods that write to stdout; `console.error` writes to stderr already.\n Object.assign(console, {\n log: writeStderr,\n info: writeStderr,\n warn: writeStderr,\n debug: writeStderr,\n });\n try {\n await import(specifierOf(serverModule));\n } catch (error) {\n writeStderr(\"Bootstrap error:\", error);\n process.exitCode = 1;\n }\n}\n","// The MCP HTTP routes (RFC 0003 section 10), ported from 4.1's\n// `createMcpRoutes` (4.1 `src/server/mcp/McpHttpRoutes.ts:12`) onto the\n// registry, keeping its wire format:\n//\n// GET {path}/tools -> { tools }\n// POST {path}/invoke { service, method, payload } -> { success: true, data }\n//\n// `invoke` also takes `{ name, arguments }`, which reaches every tool, the\n// app's own included. Like the HTTP transport, the routes are a plain Node\n// request handler rather than an `express.Router`, so they mount with\n// `app.use(router)` on Express 4 or 5 and also serve a bare Node server.\n//\n// What changed from 4.1: the registry's `principal` hook decides who a bearer\n// token stands for, and a request without one is anonymous (only `\"public\"`\n// methods and custom tools pass) where 4.1 refused it; a failure answers\n// with its error code's HTTP status and `{ success: false, error, code,\n// data? }` where 4.1 answered 500 and `{ error }`; `invoke` needs\n// `Content-Type: application/json`, as every HTTP transport call does; and a\n// client that goes away cancels its call. Each request is a session of its\n// own.\n\nimport { randomUUID } from \"node:crypto\";\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { consoleLogger, type Logger } from \"../../contract/logger\";\nimport {\n httpStatus,\n INTERNAL_MESSAGE,\n QuickdrawError,\n toWire,\n type ErrorCode,\n} from \"../../protocol/errors\";\nimport { describeError } from \"../pipeline/metrics\";\nimport { unreadable } from \"../transports/ack\";\nimport { isJsonRequest, readJsonInput, type HttpRequest } from \"../transports/body\";\nimport type { HttpRouter } from \"../transports/http\";\nimport type { McpRegistry } from \"./registry\";\nimport type { McpCallOptions, McpCallResult, McpHttpRequest } from \"./types\";\n\n/** Options of {@link createMcpHttpRouter}. */\nexport interface McpHttpRouterOptions {\n /** The tools to serve. */\n readonly registry: McpRegistry;\n /** The prefix of the routes: `GET {path}/tools` and `POST {path}/invoke`. Default `\"/mcp\"`, as in 4.1. */\n readonly path?: string;\n /**\n * The largest request body read, in bytes. Default 1 MiB. A body the app's\n * own JSON parser already read (`express.json()`) is used as it is.\n */\n readonly maxBodyBytes?: number;\n /** Default: the console. */\n readonly logger?: Logger;\n}\n\n/** What `invoke` answers: 4.1's `{ success, data }`, or a failure's message, code and data. */\nexport type McpHttpReply =\n | { readonly success: true; readonly data: unknown }\n | {\n readonly success: false;\n readonly error: string;\n readonly code: ErrorCode;\n readonly data?: unknown;\n };\n\ninterface Settings {\n readonly registry: McpRegistry;\n readonly prefix: string;\n readonly maxBodyBytes: number;\n readonly logger: Logger;\n}\n\n/** What an `invoke` body names: any tool by name, or a method's tool by service and method. */\ntype Target =\n | { readonly kind: \"tool\"; readonly name: string; readonly args: unknown }\n | {\n readonly kind: \"method\";\n readonly service: string;\n readonly method: string;\n readonly input: unknown;\n };\n\nconst DEFAULT_MAX_BODY_BYTES = 1_048_576;\nconst CATEGORY = \"quickdraw.mcp\";\nconst NOT_JSON = \"Send the call as a JSON body with Content-Type: application/json\";\nconst NO_TARGET =\n \"Send { name, arguments } to call a tool, or { service, method, payload } to call a method's tool\";\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction failure(error: QuickdrawError): McpCallResult {\n return { ok: false, error };\n}\n\nfunction replyOf(result: McpCallResult): [number, McpHttpReply] {\n if (result.ok) {\n return [200, { success: true, data: result.data }];\n }\n const { code, message, data } = toWire(result.error);\n const reply = { success: false as const, error: message, code };\n return [httpStatus(code), data === undefined ? reply : { ...reply, data }];\n}\n\n/** Writes a JSON body, unless the response already ended; returns its size in bytes. */\nfunction send(res: ServerResponse, status: number, body: string): number | undefined {\n if (res.headersSent || res.writableEnded || res.destroyed) {\n return undefined;\n }\n const bytes = Buffer.byteLength(body);\n res.statusCode = status;\n res.setHeader(\"content-type\", \"application/json; charset=utf-8\");\n res.setHeader(\"content-length\", bytes);\n res.end(body);\n return bytes;\n}\n\nfunction sendResult(\n settings: Settings,\n res: ServerResponse,\n result: McpCallResult,\n): number | undefined {\n const [status, reply] = replyOf(result);\n let body: string;\n try {\n body = JSON.stringify(reply);\n } catch (error) {\n settings.logger.error(\n \"An MCP call's reply could not be encoded; it was answered with INTERNAL\",\n {\n category: CATEGORY,\n error: describeError(error),\n },\n );\n const [internal, fallback] = replyOf(failure(new QuickdrawError(\"INTERNAL\", INTERNAL_MESSAGE)));\n return send(res, internal, JSON.stringify(fallback));\n }\n return send(res, status, body);\n}\n\nfunction routeOf(req: IncomingMessage, prefix: string): \"tools\" | \"invoke\" | undefined {\n const path = (req.url ?? \"\").split(\"?\", 1)[0] ?? \"\";\n if (req.method === \"GET\" && path === `${prefix}/tools`) {\n return \"tools\";\n }\n return req.method === \"POST\" && path === `${prefix}/invoke` ? \"invoke\" : undefined;\n}\n\nfunction targetOf(body: unknown): Target | undefined {\n if (!isRecord(body)) {\n return undefined;\n }\n if (typeof body.name === \"string\") {\n return { kind: \"tool\", name: body.name, args: body.arguments };\n }\n if (typeof body.service === \"string\" && typeof body.method === \"string\") {\n return { kind: \"method\", service: body.service, method: body.method, input: body.payload };\n }\n return undefined;\n}\n\n/** The session an `invoke` request stands for, with its bearer token. */\nfunction requestOf(req: IncomingMessage): McpHttpRequest {\n const header = req.headers.authorization;\n const token = typeof header === \"string\" && header.startsWith(\"Bearer \") ? header.slice(7) : \"\";\n return {\n transport: \"http\",\n sessionId: randomUUID(),\n token: token.trim() === \"\" ? null : token.trim(),\n headers: req.headers,\n req,\n };\n}\n\nasync function invoke(settings: Settings, req: HttpRequest, res: ServerResponse): Promise<void> {\n const controller = new AbortController();\n // `req` closes once its body was read; `res` closes when the client leaves.\n res.once(\"close\", () => {\n if (!res.writableFinished) {\n controller.abort();\n }\n });\n if (!isJsonRequest(req)) {\n sendResult(settings, res, failure(unreadable(NOT_JSON)));\n return;\n }\n let body: unknown;\n try {\n body = await readJsonInput(req, settings.maxBodyBytes);\n } catch (error) {\n const reason =\n error instanceof QuickdrawError ? error : unreadable(\"The request body could not be read\");\n sendResult(settings, res, failure(reason));\n return;\n }\n const target = targetOf(body);\n if (target === undefined) {\n sendResult(settings, res, failure(unreadable(NO_TARGET)));\n return;\n }\n const options: McpCallOptions = {\n request: requestOf(req),\n signal: controller.signal,\n respond: (result) => sendResult(settings, res, result),\n };\n await (target.kind === \"tool\"\n ? settings.registry.call(target.name, target.args, options)\n : settings.registry.callMethod(target.service, target.method, target.input, options));\n}\n\n/** `\"/mcp/\"` and `\"mcp\"` become `\"/mcp\"`; `\"/\"` becomes `\"\"`, serving `/tools` and `/invoke`. */\nfunction normalizePath(path: string): string {\n const trimmed = path.replace(/^\\/+|\\/+$/g, \"\");\n return trimmed === \"\" ? \"\" : `/${trimmed}`;\n}\n\nfunction resolveSettings(options: McpHttpRouterOptions): Settings {\n if (typeof options !== \"object\" || options === null || !isRecord(options.registry)) {\n throw new TypeError(\"createMcpHttpRouter: registry must come from createMcpRegistry\");\n }\n const maxBodyBytes = options.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;\n if (!Number.isSafeInteger(maxBodyBytes) || maxBodyBytes < 1) {\n throw new TypeError(\n \"createMcpHttpRouter: maxBodyBytes must be a whole number of bytes, 1 or more\",\n );\n }\n return {\n registry: options.registry,\n prefix: normalizePath(options.path ?? \"/mcp\"),\n maxBodyBytes,\n logger: options.logger ?? consoleLogger,\n };\n}\n\n/**\n * Serves `registry`'s tools over HTTP: `GET /mcp/tools` lists them (the\n * same list for every caller: it is not filtered by the principal), and\n * `POST /mcp/invoke` calls one with `{ name, arguments }`, or a method's\n * tool with 4.1's `{ service, method, payload }`, as the bearer token's\n * principal. Mount it with `app.use(router)` on Express 4 or 5, or pass it to\n * `http.createServer`. A request it does not serve goes to `next`, or gets a\n * 404 when there is no `next`.\n *\n * @example\n * app.use(createMcpHttpRouter({ registry }));\n */\nexport function createMcpHttpRouter(options: McpHttpRouterOptions): HttpRouter {\n const settings = resolveSettings(options);\n return (req, res, next) => {\n const route = routeOf(req, settings.prefix);\n if (route === undefined) {\n if (next === undefined) {\n sendResult(settings, res, failure(new QuickdrawError(\"NOT_FOUND\", \"Not found\")));\n } else {\n next();\n }\n return;\n }\n if (route === \"tools\") {\n send(res, 200, JSON.stringify({ tools: settings.registry.tools }));\n return;\n }\n invoke(settings, req, res).catch((error: unknown) => {\n settings.logger.error(\"The MCP HTTP routes failed to serve a call\", {\n category: CATEGORY,\n error: describeError(error),\n });\n sendResult(settings, res, failure(new QuickdrawError(\"INTERNAL\", INTERNAL_MESSAGE)));\n });\n };\n}\n"],"mappings":"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","names":["entry","isRecord","isRecord","entry","CATEGORY","isRecord","callTool","openSession","resolve","randomUUID","CATEGORY","isRecord","failure","reply","randomUUID"]}
1
+ {"version":3,"sources":["../../../src/server/mcp/tools.ts","../../../src/server/mcp/session.ts","../../../src/server/mcp/custom.ts","../../../src/server/mcp/registry.ts","../../../src/server/mcp/result.ts","../../../src/server/mcp/stdio.ts","../../../src/server/mcp/stderr.ts","../../../src/server/mcp/bootstrap.ts","../../../src/server/mcp/http.ts"],"sourcesContent":["// Tools from contracts (RFC 0003 section 10): one tool per method, made when\n// the registry is built, from what the contract already holds: the input\n// schema, the kind and the `describe` text. 4.1 wrote tool metadata ahead of\n// time by parsing service source files with regular expressions\n// (4.1 `src/server/mcp/generateToolMetadata.ts:255`); nothing is generated\n// ahead of time here.\n//\n// A tool's `inputSchema` is the method input's Standard JSON Schema (Zod 4.2\n// or later), drafted as JSON Schema draft-07, the dialect MCP clients of the\n// 2024-11-05 protocol read. MCP tool arguments are always an object, so:\n//\n// - an object input is the arguments themselves;\n// - an input with no JSON Schema form that accepts `undefined`\n// (`z.undefined()`, `z.void()`) is a tool without arguments;\n// - any other input (a string, a union) is the `input` argument.\n//\n// A registry's `bind` names arguments it fills from the principal: they are\n// left out of the `inputSchema` of each object input that has them, and may\n// not appear in any other input.\n\nimport type { MethodKind } from \"../../contract/methods\";\nimport { defaultToolName } from \"../../contract/toolName\";\nimport {\n hasJsonSchema,\n type StandardSchemaV1,\n type StandardSchemaWithJSON,\n} from \"../../contract/standardSchema\";\nimport type { AnyService } from \"../service\";\nimport type { DescribeToolsOptions, McpInputSchema, McpTool } from \"./types\";\n\n/** How a tool's arguments become its input. */\nexport type ArgumentsMode = \"object\" | \"wrapped\" | \"none\";\n\n/** A tool's argument schema, and how its arguments become the input. */\nexport interface ToolInput {\n readonly schema: McpInputSchema;\n readonly mode: ArgumentsMode;\n}\n\n/** A method's tool, with the method it calls. */\nexport interface MethodTool extends ToolInput {\n readonly tool: McpTool;\n readonly service: string;\n readonly method: string;\n /** The arguments the registry's `bind` fills, which `tool.inputSchema` leaves out. */\n readonly bound: readonly string[];\n}\n\ntype Fail = (message: string) => never;\n\nconst JSON_SCHEMA_TARGET = \"draft-07\";\n\nconst NO_ARGUMENTS: McpInputSchema = Object.freeze({\n type: \"object\",\n properties: Object.freeze({}),\n});\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** True when the schema accepts `undefined` without awaiting anything. */\nfunction acceptsUndefined(schema: StandardSchemaV1): boolean {\n try {\n const result: unknown = schema[\"~standard\"].validate(undefined);\n return isRecord(result) && typeof result.then !== \"function\" && result.issues === undefined;\n } catch {\n return false;\n }\n}\n\n/** The JSON Schema of a schema's input, or why the schema could not write one. */\nfunction draftJsonSchema(schema: StandardSchemaWithJSON): Record<string, unknown> | Error {\n try {\n const json: unknown = schema[\"~standard\"].jsonSchema.input({ target: JSON_SCHEMA_TARGET });\n return isRecord(json) ? json : new Error(\"the schema did not return an object\");\n } catch (error) {\n return error instanceof Error ? error : new Error(String(error));\n }\n}\n\n/**\n * The argument schema of a tool whose input is `schema`, and how its\n * arguments become that input. Fails when the schema cannot describe itself\n * as JSON Schema, naming `label` (what the tool calls) and the fix; `instead`\n * is the other way out. A method can be left out with `exclude`.\n */\nexport function toolInputOf(\n label: string,\n schema: StandardSchemaV1,\n fail: Fail,\n instead = `leave ${label} out with exclude`,\n): ToolInput {\n if (!hasJsonSchema(schema)) {\n fail(\n `the input schema of ${label} cannot describe itself as JSON Schema, which an MCP tool needs: use Zod 4.2 or later for that schema, or ${instead}`,\n );\n }\n const json = draftJsonSchema(schema);\n if (json instanceof Error) {\n if (acceptsUndefined(schema)) {\n return { schema: NO_ARGUMENTS, mode: \"none\" };\n }\n fail(\n `the input schema of ${label} cannot be written as JSON Schema (${json.message}): change that schema, or ${instead}`,\n );\n }\n if (json.type === \"object\") {\n return { schema: json as McpInputSchema, mode: \"object\" };\n }\n const { $schema: dialect, ...input } = json;\n return {\n schema: {\n ...(dialect === undefined ? {} : { $schema: dialect }),\n type: \"object\",\n properties: { input },\n ...(acceptsUndefined(schema) ? {} : { required: [\"input\"] }),\n },\n mode: \"wrapped\",\n };\n}\n\n/** The input a call passes to a tool's handler or method, from the tool's arguments. */\nexport function inputOf(mode: ArgumentsMode, args: unknown): unknown {\n if (mode === \"object\") {\n return args ?? {};\n }\n return mode === \"wrapped\" && isRecord(args) ? args.input : undefined;\n}\n\n/** Whether a method is selected by `include` and `exclude`, after checking every reference names one. */\nfunction selector(\n services: readonly AnyService[],\n options: DescribeToolsOptions,\n fail: Fail,\n): (service: string, method: string) => boolean {\n const known = new Set<string>();\n for (const service of services) {\n known.add(service.name);\n for (const method of Object.keys(service.contract.methods)) {\n known.add(`${service.name}.${method}`);\n }\n }\n const refs = (key: \"include\" | \"exclude\"): ReadonlySet<string> | undefined => {\n const list: unknown = options[key];\n if (list === undefined) {\n return undefined;\n }\n if (!Array.isArray(list) || !list.every((ref) => typeof ref === \"string\")) {\n fail(`${key} must be a list of \"service\" and \"service.method\" names`);\n }\n const unknownRef = list.find((ref) => !known.has(ref));\n if (unknownRef !== undefined) {\n fail(`${key} names \"${unknownRef}\", which is not a service or method being served`);\n }\n return new Set(list);\n };\n const include = refs(\"include\");\n const exclude = refs(\"exclude\");\n const names = (set: ReadonlySet<string>, service: string, method: string): boolean =>\n set.has(service) || set.has(`${service}.${method}`);\n return (service, method) =>\n (include === undefined || names(include, service, method)) &&\n (exclude === undefined || !names(exclude, service, method));\n}\n\n/** The function that names a method's tool: the `name` option, checked, or `{service}_{method}`. */\nfunction toolNamer(\n options: DescribeToolsOptions,\n fail: Fail,\n): (service: string, method: string) => string {\n const { name } = options;\n if (name !== undefined && typeof name !== \"function\") {\n fail(\"name must be a function of (service, method)\");\n }\n return (service, method) => {\n const named: unknown =\n name === undefined ? defaultToolName(service, method) : name(service, method);\n if (typeof named !== \"string\" || named === \"\") {\n const shown = typeof named === \"string\" ? `\"\"` : String(named);\n fail(`name returned ${shown} for ${service}.${method}; a tool name is a non-empty string`);\n }\n return named;\n };\n}\n\nfunction describeMethod(service: string, method: string, kind: MethodKind, text: unknown): string {\n return typeof text === \"string\" && text !== \"\" ? text : `${service}.${method} (${kind})`;\n}\n\nfunction propertiesOf(schema: unknown): string[] {\n return isRecord(schema) && isRecord(schema.properties) ? Object.keys(schema.properties) : [];\n}\n\n/** The properties a JSON Schema's `anyOf`, `oneOf` and `allOf` branches declare, through nested branches. */\nfunction branchProperties(schema: unknown, found = new Set<string>()): Set<string> {\n if (!isRecord(schema)) {\n return found;\n }\n for (const keyword of [\"anyOf\", \"oneOf\", \"allOf\"]) {\n const branches: unknown = schema[keyword];\n for (const branch of Array.isArray(branches) ? (branches as unknown[]) : []) {\n for (const key of propertiesOf(branch)) {\n found.add(key);\n }\n branchProperties(branch, found);\n }\n }\n return found;\n}\n\n/**\n * The arguments of `bind` that are properties of the object input of\n * `label`. Fails when one of them is a property of an input that is not an\n * object, or of one of its `anyOf`, `oneOf` or `allOf` branches, where it\n * cannot be filled. An input without arguments has none.\n */\nfunction boundArguments(\n label: string,\n input: ToolInput,\n bind: readonly string[],\n fail: Fail,\n): string[] {\n if (input.mode === \"object\") {\n const properties = propertiesOf(input.schema);\n return bind.filter((key) => properties.includes(key));\n }\n const wrapped: unknown = input.schema.properties?.input;\n const unbindable = branchProperties(wrapped, new Set(propertiesOf(wrapped)));\n const misplaced = bind.find((key) => unbindable.has(key));\n if (misplaced !== undefined) {\n fail(\n `bind.${misplaced} names a property of the input of ${label}, which is not an object: bind fills properties of object inputs only; leave ${label} out with exclude, or make its input an object`,\n );\n }\n return [];\n}\n\n/** An object input's schema without the bound arguments, as the tool lists it. */\nfunction withoutArguments(schema: McpInputSchema, bound: readonly string[]): McpInputSchema {\n const kept = (key: string) => !bound.includes(key);\n const { properties = {}, required, ...rest } = schema;\n const stillRequired = required?.filter(kept) ?? [];\n return {\n ...rest,\n properties: Object.fromEntries(Object.entries(properties).filter(([key]) => kept(key))),\n ...(stillRequired.length === 0 ? {} : { required: stillRequired }),\n };\n}\n\n/**\n * The method tools of `services`, in service order and then contract order,\n * with what each calls. Fails on a reference, name or schema that cannot\n * make a tool; `fail` prefixes the message with the caller's name. `bind`\n * names the arguments a registry fills from the principal.\n */\nexport function planMethodTools(\n services: readonly AnyService[],\n options: DescribeToolsOptions,\n fail: Fail,\n bind: readonly string[] = [],\n): MethodTool[] {\n const given: unknown = services;\n if (!Array.isArray(given)) {\n fail(\"services must be an array of services from qd.defineService\");\n }\n const selected = selector(services, options, fail);\n const toolName = toolNamer(options, fail);\n const planned: MethodTool[] = [];\n for (const service of services) {\n for (const [method, def] of Object.entries(service.contract.methods)) {\n if (!selected(service.name, method)) {\n continue;\n }\n const label = `${service.name}.${method}`;\n const input = toolInputOf(label, def.input, fail);\n const bound = boundArguments(label, input, bind, fail);\n const tool: McpTool = {\n name: toolName(service.name, method),\n description: describeMethod(service.name, method, def.kind, def.describe),\n inputSchema: bound.length === 0 ? input.schema : withoutArguments(input.schema, bound),\n ...(def.kind === \"query\" ? { annotations: { readOnlyHint: true } } : {}),\n };\n planned.push({ ...input, tool: Object.freeze(tool), service: service.name, method, bound });\n }\n }\n return planned;\n}\n\n/** Fails when two tools share a name. `owners` names what each tool comes from, for the message. */\nexport function checkUniqueNames(\n tools: readonly { readonly tool: McpTool; readonly owner: string }[],\n fail: Fail,\n): void {\n const seen = new Map<string, string>();\n for (const { tool, owner } of tools) {\n const first = seen.get(tool.name);\n if (first !== undefined) {\n fail(`two tools are named \"${tool.name}\": ${first} and ${owner}`);\n }\n seen.set(tool.name, owner);\n }\n}\n\n/**\n * The MCP tools of `services`: one per contract method, named\n * `{service}_{method}` unless `name` says otherwise, described by the\n * method's `describe` text, with the input schema's JSON Schema as\n * `inputSchema` and `readOnlyHint` on every query. Throws when a method's\n * input schema cannot describe itself as JSON Schema (use Zod 4.2 or later),\n * when `include` or `exclude` names something that is not served, and when\n * two tools would share a name.\n *\n * @example\n * describeTools([taskService], { exclude: [\"taskService.purge\"] });\n */\nexport function describeTools<const S extends readonly AnyService[]>(\n services: S,\n options: DescribeToolsOptions<S> = {},\n): McpTool[] {\n const fail: Fail = (message) => {\n throw new TypeError(`describeTools: ${message}`);\n };\n const planned = planMethodTools(services, options as DescribeToolsOptions, fail);\n checkUniqueNames(\n planned.map((entry) => ({ tool: entry.tool, owner: `${entry.service}.${entry.method}` })),\n fail,\n );\n return planned.map((entry) => entry.tool);\n}\n","// What a tool call runs as: the principal the registry's `principal` hook\n// maps the session or token to, the `ctx.mcp` fields its `context` hook adds,\n// and a synthetic connection id. An MCP call has no socket, so the session id\n// stands in for one: the queries of one stdio session share one concurrency\n// lane (RFC 0003 section 9, step 2), exactly as a socket's queries do.\n\nimport type { Logger } from \"../../contract/logger\";\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport { lazyMembers, type CallOptions } from \"../caller\";\nimport type { Dispatcher } from \"../dispatcher\";\nimport { toQuickdrawError } from \"../pipeline/errors\";\nimport { describeError } from \"../pipeline/metrics\";\nimport type { DispatchRequest, DispatchResult } from \"../pipeline/request\";\nimport { toPrincipal } from \"../transports/auth\";\nimport type { McpContext, Principal } from \"../types\";\nimport type { McpCallOptions, McpCallResult, McpRequest } from \"./types\";\n\n/** Who a tool call acts for, what it adds to `ctx.mcp`, and the connection it counts against. */\nexport interface McpSession {\n readonly principal: Principal | null;\n readonly mcp: McpContext | undefined;\n readonly connectionId: string;\n}\n\n/** The registry's `principal` option, as the bridge calls it. */\nexport type PrincipalHook = (request: McpRequest) => unknown;\n\n/** The registry's `context` option, as the bridge calls it. */\nexport type ContextHook = (request: McpRequest, principal: Principal | null) => unknown;\n\n/** What resolving sessions and making calls in them needs. */\nexport interface SessionSettings {\n readonly dispatcher: Pick<Dispatcher, \"call\">;\n readonly principal: PrincipalHook | undefined;\n readonly context: ContextHook | undefined;\n readonly logger: Logger;\n}\n\nconst CATEGORY = \"quickdraw.mcp\";\n\nasync function principalOf(\n settings: SessionSettings,\n request: McpRequest,\n): Promise<Principal | null> {\n if (settings.principal === undefined) {\n return null;\n }\n try {\n return toPrincipal(await settings.principal(request));\n } catch (error) {\n settings.logger.error(\"MCP authentication failed\", {\n category: CATEGORY,\n transport: request.transport,\n error: describeError(error),\n });\n throw new QuickdrawError(\"UNAUTHENTICATED\", \"Authentication failed\");\n }\n}\n\nasync function contextOf(\n settings: SessionSettings,\n request: McpRequest,\n principal: Principal | null,\n): Promise<McpContext | undefined> {\n if (settings.context === undefined) {\n return undefined;\n }\n const fields: unknown = await settings.context(request, principal);\n if (fields === undefined) {\n return undefined;\n }\n if (typeof fields !== \"object\" || fields === null) {\n throw new TypeError(\"createMcpRegistry: context must return an object, the fields of ctx.mcp\");\n }\n return fields as McpContext;\n}\n\n/**\n * Resolves who a call on `request` acts for and its `ctx.mcp` fields. Rejects\n * with `UNAUTHENTICATED` when the `principal` hook fails; a failing `context`\n * hook rejects with its own error.\n */\nexport async function openSession(\n settings: SessionSettings,\n request: McpRequest,\n): Promise<McpSession> {\n const principal = await principalOf(settings, request);\n const mcp = await contextOf(settings, request, principal);\n return { principal, mcp, connectionId: `mcp:${request.sessionId}` };\n}\n\n/** A failed call's result. An `INTERNAL` failure is logged with what was thrown. */\nexport function failure(settings: SessionSettings, error: unknown, tool: string): McpCallResult {\n const converted = toQuickdrawError(error);\n if (converted.code === \"INTERNAL\") {\n settings.logger.error(`The MCP tool \"${tool}\" failed`, {\n category: CATEGORY,\n tool,\n error: describeError(converted),\n });\n }\n return { ok: false, error: converted };\n}\n\n/**\n * Hands `result` to the transport's `respond`, when it gave one, and returns\n * it. An error `respond` throws is logged and does not change the result.\n */\nexport function settle(\n settings: SessionSettings,\n options: McpCallOptions,\n result: McpCallResult,\n): McpCallResult {\n try {\n options.respond?.(result);\n } catch (error) {\n settings.logger.error(\"An MCP transport failed to send a reply\", {\n category: CATEGORY,\n error: describeError(error),\n });\n }\n return result;\n}\n\n/** A dispatcher result as a tool call's result. MCP calls never send a version, so never \"not modified\". */\nexport function fromDispatch(result: DispatchResult): McpCallResult {\n if (!result.ok) {\n return { ok: false, error: result.error };\n }\n return { ok: true, data: result.notModified === true ? undefined : result.data };\n}\n\n/** The dispatcher request of one method call made in `session`. */\nexport function sessionRequest(\n session: McpSession,\n call: Pick<DispatchRequest, \"service\" | \"method\" | \"input\" | \"signal\" | \"respond\">,\n): DispatchRequest {\n return {\n ...call,\n principal: session.principal,\n transport: \"mcp\",\n connectionId: session.connectionId,\n mcp: session.mcp,\n };\n}\n\ntype MethodFunction = (input?: unknown, options?: CallOptions) => Promise<unknown>;\n\n/**\n * An in-process caller acting in `session`: each call goes through the\n * dispatcher as an MCP call, with the session's principal, connection and\n * `ctx.mcp`, so a custom tool cannot reach past what the agent may do.\n */\nexport function sessionCaller(\n settings: SessionSettings,\n session: McpSession,\n signal: AbortSignal,\n): object {\n return lazyMembers((service) =>\n lazyMembers<MethodFunction>((method) => async (input, options) => {\n const request = sessionRequest(session, {\n service,\n method,\n input,\n signal: options?.signal ?? signal,\n });\n const result = await settings.dispatcher.call(request);\n if (!result.ok) {\n throw result.error;\n }\n return result.notModified === true ? undefined : result.data;\n }),\n );\n}\n","// Custom tools (RFC 0003 section 10): an app's own tools, served beside the\n// ones generated from contracts. 4.1's registry had no hook for them\n// (4.1 `src/server/mcp/McpRegistry.ts:13`), so apps that needed one ran a\n// bridge of their own. A custom tool fails closed like a method: unless it\n// declares `access: \"public\"`, an anonymous caller is refused before anything\n// runs. A custom tool that gives a Standard Schema has its arguments\n// validated before its handler runs, as a method's input is, and every\n// handler gets a caller that acts in the same session.\n\nimport { isStandardSchema, type StandardSchemaV1 } from \"../../contract/standardSchema\";\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport { NEVER_ABORTED } from \"../context\";\nimport { parseInput } from \"../pipeline/validation\";\nimport { failure, sessionCaller, type McpSession, type SessionSettings } from \"./session\";\nimport { inputOf, toolInputOf, type ArgumentsMode, type ToolInput } from \"./tools\";\nimport type {\n McpCallOptions,\n McpCallResult,\n McpInputSchema,\n McpTool,\n McpToolAccess,\n McpToolCall,\n} from \"./types\";\n\n/** A checked custom tool. */\nexport interface CustomTool {\n readonly tool: McpTool;\n /** Who may call it; `\"authenticated\"` unless the tool said otherwise. */\n readonly access: McpToolAccess;\n readonly mode: ArgumentsMode;\n /** The schema that validates the arguments, when the tool gave a Standard Schema. */\n readonly schema: StandardSchemaV1 | undefined;\n readonly handler: (call: McpToolCall) => unknown;\n}\n\ntype Fail = (message: string) => never;\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction argumentsOf(owner: string, inputSchema: unknown, fail: Fail): ToolInput {\n if (isStandardSchema(inputSchema)) {\n return toolInputOf(owner, inputSchema, fail, \"give the tool a JSON Schema object instead\");\n }\n if (isRecord(inputSchema) && inputSchema.type === \"object\") {\n return { schema: inputSchema as McpInputSchema, mode: \"object\" };\n }\n return fail(\n `${owner}: inputSchema must be a Standard Schema, or a JSON Schema whose type is \"object\"`,\n );\n}\n\nfunction accessOf(owner: string, access: unknown, fail: Fail): McpToolAccess {\n if (access === undefined) {\n return \"authenticated\";\n }\n if (access !== \"public\" && access !== \"authenticated\") {\n fail(`${owner}: access must be \"public\" or \"authenticated\"`);\n }\n return access;\n}\n\nfunction checkCustomTool(value: unknown, index: number, fail: Fail): CustomTool {\n if (!isRecord(value)) {\n fail(`customTools[${index}] must be { name, description, inputSchema, handler }`);\n }\n const { name, description, inputSchema, annotations, handler } = value;\n if (typeof name !== \"string\" || name === \"\") {\n fail(`customTools[${index}] needs a name, a non-empty string`);\n }\n const owner = `custom tool \"${name}\"`;\n if (typeof description !== \"string\" || description === \"\") {\n fail(`${owner} needs a description, a non-empty string`);\n }\n if (typeof handler !== \"function\") {\n fail(`${owner} needs a handler function`);\n }\n if (annotations !== undefined && !isRecord(annotations)) {\n fail(`${owner}: annotations must be an object of hints`);\n }\n const access = accessOf(owner, value.access, fail);\n const input = argumentsOf(owner, inputSchema, fail);\n const tool: McpTool = {\n name,\n description,\n inputSchema: input.schema,\n ...(annotations === undefined ? {} : { annotations }),\n };\n return {\n tool: Object.freeze(tool),\n access,\n mode: input.mode,\n schema: isStandardSchema(inputSchema) ? inputSchema : undefined,\n handler: handler as CustomTool[\"handler\"],\n };\n}\n\n/** Checks the registry's `customTools` option. */\nexport function checkCustomTools(value: unknown, fail: Fail): CustomTool[] {\n if (value === undefined) {\n return [];\n }\n if (!Array.isArray(value)) {\n fail(\"customTools must be an array of { name, description, inputSchema, handler }\");\n }\n return value.map((tool: unknown, index) => checkCustomTool(tool, index, fail));\n}\n\n/**\n * Runs a custom tool with the arguments `args` in `session`: refuses an\n * anonymous caller unless the tool's access is `\"public\"`\n * (`UNAUTHENTICATED`), validates the arguments when the tool gave a Standard\n * Schema (`VALIDATION` with the issues otherwise), then runs the handler.\n * Never rejects.\n */\nexport async function runCustomTool(\n settings: SessionSettings,\n custom: CustomTool,\n args: unknown,\n session: McpSession,\n options: McpCallOptions,\n): Promise<McpCallResult> {\n const { name } = custom.tool;\n const signal = options.signal ?? NEVER_ABORTED;\n try {\n if (custom.access === \"authenticated\" && session.principal === null) {\n throw new QuickdrawError(\"UNAUTHENTICATED\", \"Authentication required\");\n }\n const input = inputOf(custom.mode, args);\n const parsed =\n custom.schema === undefined\n ? input\n : await parseInput(custom.schema, input, `the tool \"${name}\"`);\n const data: unknown = await custom.handler({\n arguments: parsed,\n principal: session.principal,\n mcp: session.mcp,\n caller: sessionCaller(settings, session, signal) as McpToolCall[\"caller\"],\n signal,\n request: options.request,\n });\n return { ok: true, data };\n } catch (error) {\n return failure(settings, error, name);\n }\n}\n","// `createMcpRegistry` (RFC 0003 section 10): the tools of an app's services,\n// generated from their contracts, plus the app's own, and one `call` every\n// MCP transport uses. It replaces 4.1's `McpRegistry`\n// (4.1 `src/server/mcp/McpRegistry.ts:13`), which validated input, checked\n// access and ran handlers itself, as whatever user the tool's `userId`\n// argument named. Here a method's tool call goes through the dispatcher with\n// transport `\"mcp\"`, so validation, access checks and limits apply exactly as\n// for a socket call; the transport says who is calling through `principal`,\n// and `context` adds the session's own fields to the handler's `ctx.mcp`.\n// `bind` fills chosen arguments from that principal instead of the agent, so\n// an agent bound to one task cannot name another in its calls.\n\nimport { consoleLogger, type Logger } from \"../../contract/logger\";\nimport { QuickdrawError } from \"../../protocol/errors\";\nimport type { Dispatcher, PrincipalOfServices } from \"../dispatcher\";\nimport type { AnyService } from \"../service\";\nimport type { AuthenticateResult } from \"../transports/auth\";\nimport type { MaybePromise } from \"../types\";\nimport { checkCustomTools, runCustomTool, type CustomTool } from \"./custom\";\nimport {\n failure,\n fromDispatch,\n openSession,\n sessionRequest,\n settle,\n type McpSession,\n type SessionSettings,\n} from \"./session\";\nimport { checkUniqueNames, inputOf, planMethodTools, type MethodTool } from \"./tools\";\nimport type {\n DescribeToolsOptions,\n McpBindCall,\n McpBinder,\n McpCallOptions,\n McpCallResult,\n McpContextOfServices,\n McpCustomTool,\n McpRequest,\n McpTool,\n McpToolInputSchema,\n} from \"./types\";\n\n/**\n * Options of {@link createMcpRegistry}. `Tools` are the custom tools' input\n * schema types, one per tool, which type each handler's `arguments`.\n */\nexport interface McpRegistryOptions<\n S extends readonly AnyService[],\n Tools extends readonly McpToolInputSchema[] = readonly McpToolInputSchema[],\n> extends DescribeToolsOptions<S> {\n /** The services whose methods become tools. The dispatcher must serve each of them. */\n readonly services: S;\n /** The dispatcher every method's tool calls through, with transport `\"mcp\"`. */\n readonly dispatcher: Pick<Dispatcher, \"call\" | \"registry\">;\n /**\n * Says who an MCP session or request acts for: a principal, a user id when\n * a bare `{ userId }` is a principal of the app's type, or nothing for an\n * anonymous caller, who may call `\"public\"` methods and `\"public\"` custom\n * tools only. A stdio server usually reads a token from its environment;\n * an HTTP request carries one as a bearer token. Throwing fails the call\n * with `UNAUTHENTICATED`. Without it every call is anonymous.\n */\n readonly principal?: (\n request: McpRequest,\n ) => MaybePromise<AuthenticateResult<PrincipalOfServices<S>>>;\n /**\n * The fields handlers see as `ctx.mcp` on calls from this registry, typed\n * by the app's `QuickdrawTypes[\"mcp\"]`: the scopes of the agent's token,\n * for example. Runs per call, after `principal`.\n */\n readonly context?: (\n request: McpRequest,\n principal: PrincipalOfServices<S> | null,\n ) => MaybePromise<McpContextOfServices<S>>;\n /**\n * Arguments filled from who is calling instead of by the agent, by name:\n * `{ taskId: ({ principal }) => principal.claims?.taskId }`. Each one is\n * left out of the `inputSchema` of every method's tool whose object input\n * has it, and each call of such a tool, by `call` or `callMethod`, gets the\n * binder's value before its input is validated. The call is refused\n * before the method runs when the caller is anonymous (`UNAUTHENTICATED`),\n * or when the binder returns `undefined` or `null` or the caller sent the\n * argument with another value (`FORBIDDEN`); a binder that throws fails it\n * with `INTERNAL`, or with the code of a `QuickdrawError`. Custom tools are\n * never bound. Binding is not access control: the same principal reaches\n * the method over a socket or HTTP with nothing bound, so the method's\n * access must still confine it.\n */\n readonly bind?: Readonly<Record<string, McpBinder<S>>>;\n /** The app's own tools, listed after the generated ones. */\n readonly customTools?: { readonly [K in keyof Tools]: McpCustomTool<S, Tools[K]> };\n /** Receives tool failures and authentication errors. Default: the console. */\n readonly logger?: Logger;\n}\n\n/** The tools an MCP transport serves, and the one way to call them. */\nexport interface McpRegistry {\n /**\n * Every tool, generated ones first, as `tools/list` and `GET /mcp/tools`\n * return them: the same list for every caller, never filtered by the\n * principal, so an agent may see tools whose calls are refused. A\n * registry's `include`/`exclude` decide the list; serve agents of\n * different reach from separate registries.\n */\n readonly tools: readonly McpTool[];\n /** True when a tool has this name. */\n has(name: string): boolean;\n /**\n * Calls the tool `name` with the client's `args` in the session of\n * `options.request`. Resolves with the tool's value or its failure (an\n * unknown name is `NOT_FOUND`), after `options.respond` was given it.\n * Never rejects.\n */\n call(name: string, args: unknown, options: McpCallOptions): Promise<McpCallResult>;\n /**\n * Calls a method's tool by its service and method name with the method's\n * `input` as it is, without the tool's argument mapping: the shape 4.1's\n * HTTP route took. Bound arguments are filled as for `call`. A method that\n * is not a tool is `NOT_FOUND`.\n */\n callMethod(\n service: string,\n method: string,\n input: unknown,\n options: McpCallOptions,\n ): Promise<McpCallResult>;\n}\n\ntype Entry =\n | ({ readonly kind: \"method\" } & MethodTool)\n | ({ readonly kind: \"custom\" } & CustomTool);\n\n/** A function of the registry's `bind` option, as the bridge calls it. */\ntype BindHook = (call: McpBindCall) => unknown;\n\ninterface RegistrySettings extends SessionSettings {\n /** Every tool by name, in listing order. */\n readonly entries: ReadonlyMap<string, Entry>;\n /** The method tools by {@link methodKey}. */\n readonly methods: ReadonlyMap<string, MethodTool>;\n /** The `bind` option's functions by the argument each fills. */\n readonly binders: ReadonlyMap<string, BindHook>;\n}\n\ntype Fail = (message: string) => never;\n\n/** A method's key, unambiguous whatever characters its names hold. */\nfunction methodKey(service: string, method: string): string {\n return `${service}\\u0000${method}`;\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction checkHook(name: string, hook: unknown, fail: Fail): void {\n if (hook !== undefined && typeof hook !== \"function\") {\n fail(`${name} must be a function of the MCP request`);\n }\n}\n\n/** Fails unless `dispatcher` serves every one of `services`, as the very same service objects. */\nfunction checkDispatcher(dispatcher: unknown, services: unknown, fail: Fail): void {\n if (\n !isRecord(dispatcher) ||\n typeof dispatcher.call !== \"function\" ||\n !isRecord(dispatcher.registry) ||\n !(dispatcher.registry.services instanceof Map)\n ) {\n fail(\"dispatcher must be a dispatcher from createDispatcher or qd.createServer\");\n }\n if (!Array.isArray(services)) {\n fail(\"services must be an array of services from qd.defineService\");\n }\n const served = dispatcher.registry.services as ReadonlyMap<string, unknown>;\n for (const service of services) {\n const name: unknown = isRecord(service) ? service.name : undefined;\n if (typeof name !== \"string\" || served.get(name) !== service) {\n fail(\n `the dispatcher does not serve ${typeof name === \"string\" ? name : \"one of the services\"}; pass services the dispatcher was created with`,\n );\n }\n }\n}\n\n/** Checks the registry's `bind` option: an object of functions, one per argument. */\nfunction checkBinders(bind: unknown, fail: Fail): ReadonlyMap<string, BindHook> {\n if (bind === undefined) {\n return new Map();\n }\n if (!isRecord(bind) || Array.isArray(bind)) {\n fail(\"bind must be an object of functions, one per argument it fills\");\n }\n const binders = new Map<string, BindHook>();\n for (const [key, binder] of Object.entries(bind)) {\n if (typeof binder !== \"function\") {\n fail(`bind.${key} must be a function of the call, returning the argument's value`);\n }\n binders.set(key, binder as BindHook);\n }\n return binders;\n}\n\n/** Fails when an argument of `bind` is in no tool's object input: a misspelled name would bind nothing. */\nfunction checkBound(\n binders: ReadonlyMap<string, BindHook>,\n methodTools: readonly MethodTool[],\n fail: Fail,\n): void {\n for (const key of binders.keys()) {\n if (!methodTools.some((tool) => tool.bound.includes(key))) {\n fail(\n `bind.${key} fills nothing: no method served as a tool has \"${key}\" in its object input`,\n );\n }\n }\n}\n\nfunction resolveRegistry(options: McpRegistryOptions<readonly AnyService[]>): RegistrySettings {\n const fail: Fail = (message) => {\n throw new TypeError(`createMcpRegistry: ${message}`);\n };\n if (!isRecord(options)) {\n fail(\"options must be an object with services and dispatcher\");\n }\n checkDispatcher(options.dispatcher, options.services, fail);\n checkHook(\"principal\", options.principal, fail);\n checkHook(\"context\", options.context, fail);\n const binders = checkBinders(options.bind, fail);\n const methodTools = planMethodTools(options.services, options, fail, [...binders.keys()]);\n checkBound(binders, methodTools, fail);\n const customTools = checkCustomTools(options.customTools, fail);\n const entries: Entry[] = [\n ...methodTools.map((tool) => ({ kind: \"method\" as const, ...tool })),\n ...customTools.map((tool) => ({ kind: \"custom\" as const, ...tool })),\n ];\n checkUniqueNames(\n entries.map((entry) => ({\n tool: entry.tool,\n owner: entry.kind === \"method\" ? `${entry.service}.${entry.method}` : \"a custom tool\",\n })),\n fail,\n );\n return {\n dispatcher: options.dispatcher,\n principal: options.principal,\n context: options.context as SessionSettings[\"context\"],\n logger: options.logger ?? consoleLogger,\n entries: new Map(entries.map((entry) => [entry.tool.name, entry])),\n methods: new Map(methodTools.map((tool) => [methodKey(tool.service, tool.method), tool])),\n binders,\n };\n}\n\n/** Runs `run` in the session of `options.request`, or fails the call when the session cannot open. */\nasync function inSession(\n settings: RegistrySettings,\n name: string,\n options: McpCallOptions,\n run: (session: McpSession) => Promise<McpCallResult>,\n): Promise<McpCallResult> {\n let session: McpSession;\n try {\n session = await openSession(settings, options.request);\n } catch (error) {\n return settle(settings, options, failure(settings, error, name));\n }\n return run(session);\n}\n\n/**\n * The input of a call of a tool with bound arguments: `input` with each of\n * them filled by its binder. Rejects with `UNAUTHENTICATED` for an anonymous\n * caller, `VALIDATION` when the arguments are not an object, and `FORBIDDEN`\n * when a binder has no value or the caller sent another one.\n */\nasync function bindInput(\n settings: RegistrySettings,\n tool: MethodTool,\n input: unknown,\n session: McpSession,\n request: McpRequest,\n): Promise<unknown> {\n const { principal } = session;\n if (principal === null) {\n throw new QuickdrawError(\"UNAUTHENTICATED\", \"Authentication required\");\n }\n const given: unknown = input ?? {};\n if (!isRecord(given) || Array.isArray(given)) {\n throw new QuickdrawError(\"VALIDATION\", `Invalid input for ${tool.service}.${tool.method}`, {\n issues: [{ path: [], message: \"Expected an object\" }],\n });\n }\n const call: McpBindCall = {\n principal,\n mcp: session.mcp,\n request,\n service: tool.service,\n method: tool.method,\n };\n const filled: [string, unknown][] = [];\n for (const [key, binder] of settings.binders) {\n if (!tool.bound.includes(key)) {\n continue;\n }\n const value = await binder(call);\n if (value === undefined || value === null) {\n throw new QuickdrawError(\"FORBIDDEN\", `\"${key}\" is bound to the caller, who has none`);\n }\n // The binder's value replaces what the caller sent. Another value is\n // refused rather than replaced in silence, so an agent never believes it\n // called with the value it named.\n const sent = Object.hasOwn(given, key) ? given[key] : undefined;\n if (sent !== undefined && JSON.stringify(sent) !== JSON.stringify(value)) {\n throw new QuickdrawError(\n \"FORBIDDEN\",\n `\"${key}\" is bound to the caller and cannot be set to another value`,\n );\n }\n filled.push([key, value]);\n }\n return { ...given, ...Object.fromEntries(filled) };\n}\n\n/** Calls a method through the dispatcher, which hands the result to `respond` before it flushes. */\nasync function dispatchMethod(\n settings: RegistrySettings,\n tool: MethodTool,\n input: unknown,\n session: McpSession,\n options: McpCallOptions,\n): Promise<McpCallResult> {\n let bound = input;\n if (tool.bound.length > 0) {\n try {\n bound = await bindInput(settings, tool, input, session, options.request);\n } catch (error) {\n return settle(settings, options, failure(settings, error, tool.tool.name));\n }\n }\n const { respond } = options;\n const request = sessionRequest(session, {\n service: tool.service,\n method: tool.method,\n input: bound,\n signal: options.signal,\n respond: respond === undefined ? undefined : (result) => respond(fromDispatch(result)),\n });\n return fromDispatch(await settings.dispatcher.call(request));\n}\n\nfunction callTool(\n settings: RegistrySettings,\n name: string,\n args: unknown,\n options: McpCallOptions,\n): Promise<McpCallResult> {\n const entry = settings.entries.get(name);\n if (entry === undefined) {\n const error = new QuickdrawError(\"NOT_FOUND\", `Unknown tool \"${name}\"`);\n return Promise.resolve(settle(settings, options, { ok: false, error }));\n }\n if (entry.kind === \"method\") {\n const input = inputOf(entry.mode, args);\n return inSession(settings, name, options, (session) =>\n dispatchMethod(settings, entry, input, session, options),\n );\n }\n return inSession(settings, name, options, async (session) =>\n settle(settings, options, await runCustomTool(settings, entry, args, session, options)),\n );\n}\n\nfunction callMethodTool(\n settings: RegistrySettings,\n service: string,\n method: string,\n input: unknown,\n options: McpCallOptions,\n): Promise<McpCallResult> {\n const tool = settings.methods.get(methodKey(service, method));\n if (tool === undefined) {\n const error = new QuickdrawError(\"NOT_FOUND\", `${service}.${method} is not an MCP tool`);\n return Promise.resolve(settle(settings, options, { ok: false, error }));\n }\n return inSession(settings, tool.tool.name, options, (session) =>\n dispatchMethod(settings, tool, input, session, options),\n );\n}\n\n/**\n * Builds the MCP tools of `services` (see `describeTools`) and the app's\n * `customTools`, served by `dispatcher`. Throws at once when a method's\n * input schema cannot describe itself as JSON Schema (use Zod 4.2 or later\n * for it, or `exclude` the method), when two tools share a name, when the\n * dispatcher does not serve one of the services, or when an argument of\n * `bind` is in no tool's object input or is in an input that is not an\n * object.\n *\n * @example\n * const registry = createMcpRegistry({\n * services: [taskService, projectService],\n * dispatcher: server.dispatcher,\n * principal: (request) => verifyAgentToken(request.transport === \"http\" ? request.token : process.env.AGENT_TOKEN),\n * context: (request) => ({ scopes: scopesOf(request) }),\n * });\n */\nexport function createMcpRegistry<\n const S extends readonly AnyService[],\n const Tools extends readonly McpToolInputSchema[] = [],\n>(options: McpRegistryOptions<S, Tools>): McpRegistry {\n const settings = resolveRegistry(options as unknown as McpRegistryOptions<readonly AnyService[]>);\n const tools = Object.freeze([...settings.entries.values()].map((entry) => entry.tool));\n return Object.freeze({\n tools,\n has: (name: string) => settings.entries.has(name),\n call: (name: string, args: unknown, callOptions: McpCallOptions) =>\n callTool(settings, name, args, callOptions),\n callMethod: (service: string, method: string, input: unknown, callOptions: McpCallOptions) =>\n callMethodTool(settings, service, method, input, callOptions),\n });\n}\n","// A tool call's result in the shape of MCP's `tools/call` result, as 4.1\n// wrote it (4.1 `src/server/mcp/McpStdioServer.ts:85-96`): one text block\n// holding the value as indented JSON. A failure is a tool error (`isError`)\n// whose text is the error's wire form, `{ code, message, data? }`, so the\n// agent sees the code; 4.1 answered a failed call with a JSON-RPC error\n// instead. An `INTERNAL` failure keeps its generic message (`toWire`).\n\nimport { toWire } from \"../../protocol/errors\";\nimport type { McpCallResult, McpTextContent, McpToolResult } from \"./types\";\n\nfunction jsonText(value: unknown): McpTextContent {\n // `JSON.stringify` returns `undefined` for `undefined` (a method that\n // returns nothing) and for a function.\n const text: string | undefined = JSON.stringify(value, null, 2);\n return { type: \"text\", text: text ?? \"null\" };\n}\n\n/**\n * The `tools/call` result of a tool call. Throws when the value cannot be\n * written as JSON (a `BigInt` or a cycle); a transport answers that with an\n * `INTERNAL` tool error.\n *\n * @example\n * toToolResult(await registry.call(name, args, { request }));\n */\nexport function toToolResult(result: McpCallResult): McpToolResult {\n if (!result.ok) {\n return { content: [jsonText(toWire(result.error))], isError: true };\n }\n return { content: [jsonText(result.data)] };\n}\n","// The MCP stdio server: JSON-RPC 2.0, one message per line, on stdin and\n// stdout (RFC 0003 section 10). Ported from 4.1's `createMcpStdioServer`\n// (4.1 `src/server/mcp/McpStdioServer.ts:22`), keeping its wire format:\n// protocol version 2024-11-05, `initialize`, `ping`, `tools/list` and\n// `tools/call`, a tool's value as one block of JSON text, and the same\n// JSON-RPC error codes. What changed:\n//\n// - tools come from the registry, and who is calling from its `principal`\n// hook, rather than from a `userId` argument any agent could set;\n// - a failed call is a tool result with `isError` whose text carries the\n// error's code, where 4.1 answered with a JSON-RPC error;\n// - requests are handled concurrently, so the session's queries share one\n// concurrency lane, and `notifications/cancelled` stops a call in flight\n// (MCP sends no reply for a cancelled request);\n// - notifications never get a reply, and a JSON-RPC response from the client\n// is ignored;\n// - it never exits the process: `closed` resolves once stdin ends and every\n// call still running has answered (a client that writes its requests and\n// closes stdin still gets every reply), while `close()` and a broken\n// stream cancel the calls in flight instead.\n//\n// Anything else that writes to stdout corrupts the protocol, so start the\n// server through `bootstrapMcpServer`, which sends console output to stderr.\n\nimport { randomUUID } from \"node:crypto\";\nimport { createInterface } from \"node:readline\";\nimport type { Readable, Writable } from \"node:stream\";\nimport type { Logger } from \"../../contract/logger\";\nimport { INTERNAL_MESSAGE, QuickdrawError } from \"../../protocol/errors\";\nimport { describeError } from \"../pipeline/metrics\";\nimport type { McpRegistry } from \"./registry\";\nimport { toToolResult } from \"./result\";\nimport { stderrLogger } from \"./stderr\";\nimport type { McpCallResult, McpStdioRequest } from \"./types\";\n\n/** The MCP protocol version the stdio server speaks: 4.1's. */\nexport const MCP_PROTOCOL_VERSION = \"2024-11-05\";\n\n/** Options of {@link createMcpStdioServer}. */\nexport interface McpStdioServerOptions {\n /** The tools to serve. */\n readonly registry: McpRegistry;\n /** The server's name, sent in `initialize`'s `serverInfo`. */\n readonly name: string;\n /** The server's version, sent in `initialize`'s `serverInfo`. */\n readonly version: string;\n /** Where messages arrive. Default `process.stdin`. */\n readonly input?: Readable;\n /** Where replies go. Default `process.stdout`. */\n readonly output?: Writable;\n /** Receives the server's own problems. Default: one line per entry on stderr. */\n readonly logger?: Logger;\n}\n\n/** A running stdio server. */\nexport interface McpStdioServer {\n /** The session id every call of this server carries, and its synthetic connection. */\n readonly sessionId: string;\n /**\n * Resolves once the input has ended and every message in flight has been\n * handled: when stdin ends, the calls still running finish and their\n * replies are written first.\n */\n readonly closed: Promise<void>;\n /** Stops reading and cancels the calls in flight (no reply is written for them); resolves as `closed` does. */\n close(): Promise<void>;\n}\n\ntype RequestId = string | number;\n\ninterface Session {\n readonly registry: McpRegistry;\n readonly serverInfo: { readonly name: string; readonly version: string };\n readonly request: McpStdioRequest;\n readonly output: Writable;\n readonly logger: Logger;\n /** The `tools/call` requests in flight, by id, so they can be cancelled. */\n readonly calls: Map<RequestId, AbortController>;\n /** Every message still being handled. */\n readonly pending: Set<Promise<void>>;\n /** False once the output failed. */\n writable: boolean;\n}\n\nconst PARSE_ERROR = -32700;\nconst INVALID_REQUEST = -32600;\nconst METHOD_NOT_FOUND = -32601;\nconst INVALID_PARAMS = -32602;\nconst CATEGORY = \"quickdraw.mcp\";\n\nconst INTERNAL_FAILURE: McpCallResult = Object.freeze({\n ok: false,\n error: new QuickdrawError(\"INTERNAL\", INTERNAL_MESSAGE),\n});\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** MCP request ids are strings or numbers, never `null`. */\nfunction isRequestId(value: unknown): value is RequestId {\n return typeof value === \"string\" || (typeof value === \"number\" && Number.isFinite(value));\n}\n\n/** Writes one message as one line; returns its size in bytes. */\nfunction write(session: Session, message: object): number | undefined {\n if (!session.writable) {\n return undefined;\n }\n const line = `${JSON.stringify(message)}\\n`;\n session.output.write(line);\n return Buffer.byteLength(line);\n}\n\nfunction reply(session: Session, id: RequestId, result: unknown): number | undefined {\n return write(session, { jsonrpc: \"2.0\", id, result });\n}\n\nfunction replyError(session: Session, id: RequestId | null, code: number, message: string): void {\n write(session, { jsonrpc: \"2.0\", id, error: { code, message } });\n}\n\nfunction replyToolResult(\n session: Session,\n id: RequestId,\n result: McpCallResult,\n): number | undefined {\n let content: unknown;\n try {\n content = toToolResult(result);\n } catch (error) {\n session.logger.error(\n \"A tool's value could not be written as JSON; it was answered with INTERNAL\",\n {\n category: CATEGORY,\n error: describeError(error),\n },\n );\n content = toToolResult(INTERNAL_FAILURE);\n }\n return reply(session, id, content);\n}\n\nasync function callTool(session: Session, id: RequestId, params: unknown): Promise<void> {\n if (!isRecord(params) || typeof params.name !== \"string\") {\n replyError(session, id, INVALID_PARAMS, \"tools/call needs params { name, arguments? }\");\n return;\n }\n const { name } = params;\n if (!session.registry.has(name)) {\n replyError(session, id, INVALID_PARAMS, `Unknown tool: ${name}`);\n return;\n }\n if (session.calls.has(id)) {\n replyError(session, id, INVALID_REQUEST, `Request ${JSON.stringify(id)} is already in flight`);\n return;\n }\n const controller = new AbortController();\n session.calls.set(id, controller);\n const release = (): void => {\n if (session.calls.get(id) === controller) {\n session.calls.delete(id);\n }\n };\n try {\n await session.registry.call(name, params.arguments, {\n request: session.request,\n signal: controller.signal,\n respond: (result) => {\n release();\n // A cancelled call gets no reply, nor does one whose session ended.\n return controller.signal.aborted ? undefined : replyToolResult(session, id, result);\n },\n });\n } finally {\n release();\n }\n}\n\nasync function onRequest(\n session: Session,\n id: RequestId,\n method: string,\n params: unknown,\n): Promise<void> {\n switch (method) {\n case \"initialize\":\n reply(session, id, {\n protocolVersion: MCP_PROTOCOL_VERSION,\n serverInfo: session.serverInfo,\n capabilities: { tools: {} },\n });\n return;\n case \"ping\":\n reply(session, id, {});\n return;\n case \"tools/list\":\n reply(session, id, { tools: session.registry.tools });\n return;\n case \"tools/call\":\n await callTool(session, id, params);\n return;\n default:\n replyError(session, id, METHOD_NOT_FOUND, `Method not found: ${method}`);\n }\n}\n\n/** `notifications/cancelled` stops a call in flight; every other notification needs nothing. */\nfunction onNotification(session: Session, method: string, params: unknown): void {\n if (method === \"notifications/cancelled\" && isRecord(params) && isRequestId(params.requestId)) {\n session.calls.get(params.requestId)?.abort();\n }\n}\n\nconst UNPARSABLE = Symbol(\"unparsable\");\n\nfunction parse(line: string): unknown {\n try {\n return JSON.parse(line) as unknown;\n } catch {\n return UNPARSABLE;\n }\n}\n\nasync function onLine(session: Session, line: string): Promise<void> {\n if (line.trim() === \"\") {\n return;\n }\n const message = parse(line);\n if (message === UNPARSABLE) {\n replyError(session, null, PARSE_ERROR, \"Parse error\");\n return;\n }\n if (!isRecord(message)) {\n replyError(session, null, INVALID_REQUEST, \"Invalid Request\");\n return;\n }\n const { id, method, params } = message;\n if (typeof method !== \"string\") {\n // A response to a request this server never sends: answering it could loop.\n if (!(\"result\" in message) && !(\"error\" in message)) {\n replyError(session, isRequestId(id) ? id : null, INVALID_REQUEST, \"Invalid Request\");\n }\n return;\n }\n if (id === undefined) {\n onNotification(session, method, params);\n return;\n }\n if (!isRequestId(id)) {\n replyError(session, null, INVALID_REQUEST, \"Invalid Request\");\n return;\n }\n await onRequest(session, id, method, params);\n}\n\n/** Handles one message, keeping track of it until it is done. */\nfunction track(session: Session, work: Promise<void>): void {\n const handled = work.catch((error: unknown) => {\n session.logger.error(\"The MCP stdio server failed to handle a message\", {\n category: CATEGORY,\n error: describeError(error),\n });\n });\n session.pending.add(handled);\n void handled.then(() => session.pending.delete(handled));\n}\n\nfunction openSession(options: McpStdioServerOptions): Session {\n if (\n typeof options !== \"object\" ||\n options === null ||\n typeof options.registry?.call !== \"function\"\n ) {\n throw new TypeError(\"createMcpStdioServer: registry must come from createMcpRegistry\");\n }\n if (typeof options.name !== \"string\" || typeof options.version !== \"string\") {\n throw new TypeError(\"createMcpStdioServer: name and version must be strings, for serverInfo\");\n }\n return {\n registry: options.registry,\n serverInfo: Object.freeze({ name: options.name, version: options.version }),\n request: Object.freeze({ transport: \"stdio\", sessionId: randomUUID() }),\n output: options.output ?? process.stdout,\n logger: options.logger ?? stderrLogger,\n calls: new Map(),\n pending: new Set(),\n writable: true,\n };\n}\n\n/**\n * Serves `registry`'s tools over MCP's stdio transport: JSON-RPC messages,\n * one per line, read from stdin and answered on stdout. The server is one\n * session: its calls carry one session id and share one concurrency lane,\n * and the registry's `principal` and `context` hooks see the same\n * `{ transport: \"stdio\", sessionId }` request on every call. It never exits\n * the process.\n *\n * @example\n * // mcp-server.ts, started through bootstrapMcpServer\n * const registry = createMcpRegistry({ services, dispatcher, principal: () => agentFromEnv() });\n * const server = createMcpStdioServer({ registry, name: \"my-app\", version: \"1.0.0\" });\n * await server.closed;\n * await prisma.$disconnect();\n */\nexport function createMcpStdioServer(options: McpStdioServerOptions): McpStdioServer {\n const session = openSession(options);\n const lines = createInterface({\n input: options.input ?? process.stdin,\n crlfDelay: Infinity,\n terminal: false,\n });\n // Ending stdin lets the calls in flight answer; `close()` and a broken stream cancel them.\n let cancel = false;\n const stop = (): void => {\n cancel = true;\n lines.close();\n };\n const fail = (error: Error): void => {\n session.logger.warn(\"The MCP stdio stream failed; the session ends\", {\n category: CATEGORY,\n error: describeError(error),\n });\n stop();\n };\n const onOutputError = (error: Error): void => {\n session.writable = false;\n fail(error);\n };\n session.output.on(\"error\", onOutputError);\n lines.on(\"error\", fail);\n lines.on(\"line\", (line) => track(session, onLine(session, line)));\n const closed = new Promise<void>((resolve) => {\n lines.once(\"close\", () => {\n for (const controller of cancel ? session.calls.values() : []) {\n controller.abort();\n }\n void Promise.allSettled([...session.pending]).then(() => {\n session.output.off(\"error\", onOutputError);\n resolve();\n });\n });\n });\n return Object.freeze({\n sessionId: session.request.sessionId,\n closed,\n close: () => {\n stop();\n return closed;\n },\n });\n}\n","// Writing to stderr. An MCP stdio server owns stdout for the protocol, so its\n// own log lines, and everything `bootstrapMcpServer` takes from the console,\n// go to stderr instead.\n\nimport { format, inspect } from \"node:util\";\nimport type { Logger } from \"../../contract/logger\";\n\n/** Writes one line to stderr, formatting the arguments as `console.log` would. */\nexport function writeStderr(...args: unknown[]): void {\n process.stderr.write(`${format(...args)}\\n`);\n}\n\nfunction entry(level: string): (message: string, meta?: Record<string, unknown>) => void {\n return (message, meta) => {\n const details = meta === undefined ? \"\" : ` ${inspect(meta, { breakLength: Infinity })}`;\n process.stderr.write(`[${level}] ${message}${details}\\n`);\n };\n}\n\n/** A logger that writes each entry to stderr as one line. */\nexport const stderrLogger: Logger = {\n debug: entry(\"DEBUG\"),\n info: entry(\"INFO\"),\n warn: entry(\"WARN\"),\n error: entry(\"ERROR\"),\n child: () => stderrLogger,\n};\n","// `bootstrapMcpServer`: loads the module that starts an MCP stdio server\n// after sending console output to stderr, so nothing but the protocol\n// reaches stdout, not even what that module's imports log while loading.\n// Ported from 4.1 (4.1 `src/server/mcp/McpBootstrap.ts:12`) with two\n// changes: a relative path is resolved against the working directory (4.1\n// handed it to `import()`, which resolves it against the package's own file,\n// so a relative path never found the app's module), and a module that fails\n// to load sets the exit code instead of calling `process.exit`.\n\nimport { resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { writeStderr } from \"./stderr\";\n\nfunction specifierOf(serverModule: string | URL): string {\n if (serverModule instanceof URL) {\n return serverModule.href;\n }\n return serverModule.startsWith(\"file:\")\n ? serverModule\n : pathToFileURL(resolve(serverModule)).href;\n}\n\n/**\n * Sends `console.log`, `info`, `warn` and `debug` to stderr, sets\n * `MCP_MODE=true` (and `LOG_LEVEL=warn` unless it is set), then imports\n * `serverModule`, the module that creates the stdio server. A path is\n * resolved against the working directory; pass a URL to resolve it against\n * the calling module. Resolves once the module has loaded. When it fails to\n * load, the error goes to stderr and the process exit code becomes 1.\n *\n * @example\n * // mcp.ts: the MCP client runs `node dist/mcp.js`\n * import { bootstrapMcpServer } from \"@fitzzero/quickdraw-core/server/mcp\";\n * await bootstrapMcpServer(new URL(\"./mcp-server.js\", import.meta.url));\n */\nexport async function bootstrapMcpServer(serverModule: string | URL): Promise<void> {\n process.env.MCP_MODE = \"true\";\n process.env.LOG_LEVEL ??= \"warn\";\n // The console methods that write to stdout; `console.error` writes to stderr already.\n Object.assign(console, {\n log: writeStderr,\n info: writeStderr,\n warn: writeStderr,\n debug: writeStderr,\n });\n try {\n await import(specifierOf(serverModule));\n } catch (error) {\n writeStderr(\"Bootstrap error:\", error);\n process.exitCode = 1;\n }\n}\n","// The MCP HTTP routes (RFC 0003 section 10), ported from 4.1's\n// `createMcpRoutes` (4.1 `src/server/mcp/McpHttpRoutes.ts:12`) onto the\n// registry, keeping its wire format:\n//\n// GET {path}/tools -> { tools }\n// POST {path}/invoke { service, method, payload } -> { success: true, data }\n//\n// `invoke` also takes `{ name, arguments }`, which reaches every tool, the\n// app's own included. Like the HTTP transport, the routes are a plain Node\n// request handler rather than an `express.Router`, so they mount with\n// `app.use(router)` on Express 4 or 5 and also serve a bare Node server.\n//\n// What changed from 4.1: the registry's `principal` hook decides who a bearer\n// token stands for, and a request without one is anonymous (only `\"public\"`\n// methods and custom tools pass) where 4.1 refused it; a failure answers\n// with its error code's HTTP status and `{ success: false, error, code,\n// data? }` where 4.1 answered 500 and `{ error }`; `invoke` needs\n// `Content-Type: application/json`, as every HTTP transport call does; and a\n// client that goes away cancels its call. Each request is a session of its\n// own.\n\nimport { randomUUID } from \"node:crypto\";\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport { consoleLogger, type Logger } from \"../../contract/logger\";\nimport {\n httpStatus,\n INTERNAL_MESSAGE,\n QuickdrawError,\n toWire,\n type ErrorCode,\n} from \"../../protocol/errors\";\nimport { describeError } from \"../pipeline/metrics\";\nimport { unreadable } from \"../transports/ack\";\nimport { isJsonRequest, readJsonInput, type HttpRequest } from \"../transports/body\";\nimport type { HttpRouter } from \"../transports/http\";\nimport type { McpRegistry } from \"./registry\";\nimport type { McpCallOptions, McpCallResult, McpHttpRequest } from \"./types\";\n\n/** Options of {@link createMcpHttpRouter}. */\nexport interface McpHttpRouterOptions {\n /** The tools to serve. */\n readonly registry: McpRegistry;\n /** The prefix of the routes: `GET {path}/tools` and `POST {path}/invoke`. Default `\"/mcp\"`, as in 4.1. */\n readonly path?: string;\n /**\n * The largest request body read, in bytes. Default 1 MiB. A body the app's\n * own JSON parser already read (`express.json()`) is used as it is.\n */\n readonly maxBodyBytes?: number;\n /** Default: the console. */\n readonly logger?: Logger;\n}\n\n/** What `invoke` answers: 4.1's `{ success, data }`, or a failure's message, code and data. */\nexport type McpHttpReply =\n | { readonly success: true; readonly data: unknown }\n | {\n readonly success: false;\n readonly error: string;\n readonly code: ErrorCode;\n readonly data?: unknown;\n };\n\ninterface Settings {\n readonly registry: McpRegistry;\n readonly prefix: string;\n readonly maxBodyBytes: number;\n readonly logger: Logger;\n}\n\n/** What an `invoke` body names: any tool by name, or a method's tool by service and method. */\ntype Target =\n | { readonly kind: \"tool\"; readonly name: string; readonly args: unknown }\n | {\n readonly kind: \"method\";\n readonly service: string;\n readonly method: string;\n readonly input: unknown;\n };\n\nconst DEFAULT_MAX_BODY_BYTES = 1_048_576;\nconst CATEGORY = \"quickdraw.mcp\";\nconst NOT_JSON = \"Send the call as a JSON body with Content-Type: application/json\";\nconst NO_TARGET =\n \"Send { name, arguments } to call a tool, or { service, method, payload } to call a method's tool\";\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction failure(error: QuickdrawError): McpCallResult {\n return { ok: false, error };\n}\n\nfunction replyOf(result: McpCallResult): [number, McpHttpReply] {\n if (result.ok) {\n return [200, { success: true, data: result.data }];\n }\n const { code, message, data } = toWire(result.error);\n const reply = { success: false as const, error: message, code };\n return [httpStatus(code), data === undefined ? reply : { ...reply, data }];\n}\n\n/** Writes a JSON body, unless the response already ended; returns its size in bytes. */\nfunction send(res: ServerResponse, status: number, body: string): number | undefined {\n if (res.headersSent || res.writableEnded || res.destroyed) {\n return undefined;\n }\n const bytes = Buffer.byteLength(body);\n res.statusCode = status;\n res.setHeader(\"content-type\", \"application/json; charset=utf-8\");\n res.setHeader(\"content-length\", bytes);\n res.end(body);\n return bytes;\n}\n\nfunction sendResult(\n settings: Settings,\n res: ServerResponse,\n result: McpCallResult,\n): number | undefined {\n const [status, reply] = replyOf(result);\n let body: string;\n try {\n body = JSON.stringify(reply);\n } catch (error) {\n settings.logger.error(\n \"An MCP call's reply could not be encoded; it was answered with INTERNAL\",\n {\n category: CATEGORY,\n error: describeError(error),\n },\n );\n const [internal, fallback] = replyOf(failure(new QuickdrawError(\"INTERNAL\", INTERNAL_MESSAGE)));\n return send(res, internal, JSON.stringify(fallback));\n }\n return send(res, status, body);\n}\n\nfunction routeOf(req: IncomingMessage, prefix: string): \"tools\" | \"invoke\" | undefined {\n const path = (req.url ?? \"\").split(\"?\", 1)[0] ?? \"\";\n if (req.method === \"GET\" && path === `${prefix}/tools`) {\n return \"tools\";\n }\n return req.method === \"POST\" && path === `${prefix}/invoke` ? \"invoke\" : undefined;\n}\n\nfunction targetOf(body: unknown): Target | undefined {\n if (!isRecord(body)) {\n return undefined;\n }\n if (typeof body.name === \"string\") {\n return { kind: \"tool\", name: body.name, args: body.arguments };\n }\n if (typeof body.service === \"string\" && typeof body.method === \"string\") {\n return { kind: \"method\", service: body.service, method: body.method, input: body.payload };\n }\n return undefined;\n}\n\n/** The session an `invoke` request stands for, with its bearer token. */\nfunction requestOf(req: IncomingMessage): McpHttpRequest {\n const header = req.headers.authorization;\n const token = typeof header === \"string\" && header.startsWith(\"Bearer \") ? header.slice(7) : \"\";\n return {\n transport: \"http\",\n sessionId: randomUUID(),\n token: token.trim() === \"\" ? null : token.trim(),\n headers: req.headers,\n req,\n };\n}\n\nasync function invoke(settings: Settings, req: HttpRequest, res: ServerResponse): Promise<void> {\n const controller = new AbortController();\n // `req` closes once its body was read; `res` closes when the client leaves.\n res.once(\"close\", () => {\n if (!res.writableFinished) {\n controller.abort();\n }\n });\n if (!isJsonRequest(req)) {\n sendResult(settings, res, failure(unreadable(NOT_JSON)));\n return;\n }\n let body: unknown;\n try {\n body = await readJsonInput(req, settings.maxBodyBytes);\n } catch (error) {\n const reason =\n error instanceof QuickdrawError ? error : unreadable(\"The request body could not be read\");\n sendResult(settings, res, failure(reason));\n return;\n }\n const target = targetOf(body);\n if (target === undefined) {\n sendResult(settings, res, failure(unreadable(NO_TARGET)));\n return;\n }\n const options: McpCallOptions = {\n request: requestOf(req),\n signal: controller.signal,\n respond: (result) => sendResult(settings, res, result),\n };\n await (target.kind === \"tool\"\n ? settings.registry.call(target.name, target.args, options)\n : settings.registry.callMethod(target.service, target.method, target.input, options));\n}\n\n/** `\"/mcp/\"` and `\"mcp\"` become `\"/mcp\"`; `\"/\"` becomes `\"\"`, serving `/tools` and `/invoke`. */\nfunction normalizePath(path: string): string {\n const trimmed = path.replace(/^\\/+|\\/+$/g, \"\");\n return trimmed === \"\" ? \"\" : `/${trimmed}`;\n}\n\nfunction resolveSettings(options: McpHttpRouterOptions): Settings {\n if (typeof options !== \"object\" || options === null || !isRecord(options.registry)) {\n throw new TypeError(\"createMcpHttpRouter: registry must come from createMcpRegistry\");\n }\n const maxBodyBytes = options.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;\n if (!Number.isSafeInteger(maxBodyBytes) || maxBodyBytes < 1) {\n throw new TypeError(\n \"createMcpHttpRouter: maxBodyBytes must be a whole number of bytes, 1 or more\",\n );\n }\n return {\n registry: options.registry,\n prefix: normalizePath(options.path ?? \"/mcp\"),\n maxBodyBytes,\n logger: options.logger ?? consoleLogger,\n };\n}\n\n/**\n * Serves `registry`'s tools over HTTP: `GET /mcp/tools` lists them (the\n * same list for every caller: it is not filtered by the principal), and\n * `POST /mcp/invoke` calls one with `{ name, arguments }`, or a method's\n * tool with 4.1's `{ service, method, payload }`, as the bearer token's\n * principal. Mount it with `app.use(router)` on Express 4 or 5, or pass it to\n * `http.createServer`. A request it does not serve goes to `next`, or gets a\n * 404 when there is no `next`.\n *\n * @example\n * app.use(createMcpHttpRouter({ registry }));\n */\nexport function createMcpHttpRouter(options: McpHttpRouterOptions): HttpRouter {\n const settings = resolveSettings(options);\n return (req, res, next) => {\n const route = routeOf(req, settings.prefix);\n if (route === undefined) {\n if (next === undefined) {\n sendResult(settings, res, failure(new QuickdrawError(\"NOT_FOUND\", \"Not found\")));\n } else {\n next();\n }\n return;\n }\n if (route === \"tools\") {\n send(res, 200, JSON.stringify({ tools: settings.registry.tools }));\n return;\n }\n invoke(settings, req, res).catch((error: unknown) => {\n settings.logger.error(\"The MCP HTTP routes failed to serve a call\", {\n category: CATEGORY,\n error: describeError(error),\n });\n sendResult(settings, res, failure(new QuickdrawError(\"INTERNAL\", INTERNAL_MESSAGE)));\n });\n };\n}\n"],"mappings":"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","names":["entry","isRecord","isRecord","entry","CATEGORY","isRecord","callTool","openSession","resolve","randomUUID","CATEGORY","isRecord","failure","reply","randomUUID"]}
@@ -1,8 +1,8 @@
1
1
  import { Meter, Tracer } from '@opentelemetry/api';
2
- import { C as CallRecord } from '../metrics-C0WvB7-I.js';
3
- import '../infer-Dw21kmLw.js';
2
+ import { C as CallRecord } from '../metrics-BdBu5o8G.js';
3
+ import '../infer-Teo1xpsd.js';
4
4
  import '../errors-S-bxEIBC.js';
5
- import '../types-Bwg3kIEc.js';
5
+ import '../types-Cu0vmx7c.js';
6
6
 
7
7
  /** Options of {@link otelOnCall}: a meter, a tracer, or both. */
8
8
  interface OtelOnCallOptions {
@@ -1,6 +1,6 @@
1
- import { X as RowSchema, d as StandardSchemaV1, c as InferOutput, Q as QueryDef, A as AccessLevel, p as MutationDef, b as ACL } from './infer-Dw21kmLw.js';
2
- import { P as KitSchema, I as IdInput } from './admin-BiU4LRZS.js';
3
- import { h as SearchInput, j as SearchQuery, i as SearchPage } from './adminSchemas-k5a1Ov7b.js';
1
+ import { X as RowSchema, d as StandardSchemaV1, c as InferOutput, Q as QueryDef, A as AccessLevel, p as MutationDef, b as ACL } from './infer-Teo1xpsd.js';
2
+ import { P as KitSchema, I as IdInput } from './admin-DKwkIh5i.js';
3
+ import { h as SearchInput, j as SearchQuery, i as SearchPage } from './adminSchemas-2DUA_hZ8.js';
4
4
 
5
5
  /** Type-only: marks a method the search kit made. Never set. */
6
6
  interface SearchTag {
@@ -1,26 +1,26 @@
1
1
  import { QueryClient } from '@tanstack/react-query';
2
2
  import { RenderResult } from '@testing-library/react';
3
3
  import * as React from 'react';
4
- import { Q as QuickdrawClient } from '../clientTypes-B3o_99Xq.js';
5
- import { Q as QuickdrawConnection } from '../connection-DuN8GvcD.js';
6
- import { ae as ContractMap } from '../infer-Dw21kmLw.js';
7
- import { P as PrincipalOfServices } from '../http--uoooIH5.js';
8
- import { A as AnyService } from '../caller-DHzK3oiI.js';
9
- import { T as TestApp } from '../createTestApp-DFLXoTKm.js';
4
+ import { Q as QuickdrawClient } from '../clientTypes-Bc-G8n-U.js';
5
+ import { Q as QuickdrawConnection } from '../connection-Cr1BU07W.js';
6
+ import { ae as ContractMap } from '../infer-Teo1xpsd.js';
7
+ import { P as PrincipalOfServices } from '../http-Djj2Inuu.js';
8
+ import { A as AnyService } from '../caller-CXTFswBO.js';
9
+ import { T as TestApp } from '../createTestApp-UKVGEmOf.js';
10
10
  export { EntityMock, MethodStub, MockChannelMember, MockClient, MockClientOptions, MockCollectionMember, MockEntityMembers, MockEventMember, MockMethodMember, MockRealtimeMembers, MockScope, MockServiceClient, MockSession, MockStreamMember, StreamMock, createMockClient } from './mock.js';
11
11
  import '../errors-S-bxEIBC.js';
12
12
  import '../keys-CqKkljVN.js';
13
- import '../adminSchemas-k5a1Ov7b.js';
14
- import '../envelope-nf5eGB-a.js';
13
+ import '../adminSchemas-2DUA_hZ8.js';
14
+ import '../envelope-Cp3YcVxC.js';
15
15
  import 'socket.io-client';
16
16
  import 'node:http';
17
17
  import '../logger-BY28acW-.js';
18
- import '../types-Bwg3kIEc.js';
19
- import '../metrics-C0WvB7-I.js';
20
- import '../auth-CMyRkfjZ.js';
18
+ import '../types-Cu0vmx7c.js';
19
+ import '../metrics-BdBu5o8G.js';
20
+ import '../auth-BhWqdyb-.js';
21
21
  import 'socket.io';
22
- import '../createServer-DUacdfKl.js';
23
- import '../admin-BiU4LRZS.js';
22
+ import '../createServer-CP9eDHZZ.js';
23
+ import '../admin-DKwkIh5i.js';
24
24
 
25
25
  /**
26
26
  * Adds what jsdom lacks for component tests against a real server: no-op
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  createMockClient
3
- } from "../chunk-XFDOGTMC.js";
3
+ } from "../chunk-3674EIRT.js";
4
4
  import {
5
5
  QuickdrawProvider
6
- } from "../chunk-IRGAGRVG.js";
6
+ } from "../chunk-JZBCLNDU.js";
7
7
  import {
8
8
  QuickdrawContext
9
- } from "../chunk-XUSN5WKU.js";
10
- import "../chunk-B2UQ27GH.js";
11
- import "../chunk-7QIY2DDX.js";
12
- import "../chunk-5YRQ26LF.js";
9
+ } from "../chunk-KNDDCVQJ.js";
10
+ import "../chunk-CDKG4TFA.js";
11
+ import "../chunk-VJTFXHOK.js";
12
+ import "../chunk-RT6OILOI.js";
13
13
  import "../chunk-47AEXVDM.js";
14
14
  import "../chunk-Z2LZ7IZ7.js";
15
15
  import "../chunk-YSWH776Y.js";