@agentwares/agentguard 0.1.6 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/CHANGELOG.md +89 -0
  2. package/README.md +223 -16
  3. package/dist/audit-2YCMHMCP.js +17 -0
  4. package/dist/audit-2YCMHMCP.js.map +1 -0
  5. package/dist/chunk-3O6KWT3E.js +345 -0
  6. package/dist/chunk-3O6KWT3E.js.map +1 -0
  7. package/dist/chunk-5WRI5ZAA.js +31 -0
  8. package/dist/chunk-5WRI5ZAA.js.map +1 -0
  9. package/dist/chunk-6S7LYVOC.js +1033 -0
  10. package/dist/chunk-6S7LYVOC.js.map +1 -0
  11. package/dist/chunk-6TUQD666.js +828 -0
  12. package/dist/chunk-6TUQD666.js.map +1 -0
  13. package/dist/chunk-BKXXTWIS.js +119 -0
  14. package/dist/chunk-BKXXTWIS.js.map +1 -0
  15. package/dist/chunk-D66U3PVB.js +529 -0
  16. package/dist/chunk-D66U3PVB.js.map +1 -0
  17. package/dist/chunk-HPYZ3JDX.js +206 -0
  18. package/dist/chunk-HPYZ3JDX.js.map +1 -0
  19. package/dist/chunk-KRKZGAJ3.js +769 -0
  20. package/dist/chunk-KRKZGAJ3.js.map +1 -0
  21. package/dist/chunk-SUXQTT3X.js +1268 -0
  22. package/dist/chunk-SUXQTT3X.js.map +1 -0
  23. package/dist/chunk-TW5KJREH.js +190 -0
  24. package/dist/chunk-TW5KJREH.js.map +1 -0
  25. package/dist/chunk-VQWQ5TOM.js +113 -0
  26. package/dist/chunk-VQWQ5TOM.js.map +1 -0
  27. package/dist/chunk-X4M7YWQA.js +270 -0
  28. package/dist/chunk-X4M7YWQA.js.map +1 -0
  29. package/dist/chunk-ZSLWPKXI.js +1144 -0
  30. package/dist/chunk-ZSLWPKXI.js.map +1 -0
  31. package/dist/cli.js +8 -4725
  32. package/dist/cli.js.map +1 -1
  33. package/dist/fixtures/crm-server.js +6 -1272
  34. package/dist/fixtures/crm-server.js.map +1 -1
  35. package/dist/fixtures/demo-agent.js +4 -115
  36. package/dist/fixtures/demo-agent.js.map +1 -1
  37. package/dist/index.d.ts +76 -10
  38. package/dist/index.js +246 -5087
  39. package/dist/index.js.map +1 -1
  40. package/dist/init-CWROGV5I.js +15 -0
  41. package/dist/init-CWROGV5I.js.map +1 -0
  42. package/dist/proxy-3Z5YEZ4R.js +154 -0
  43. package/dist/proxy-3Z5YEZ4R.js.map +1 -0
  44. package/dist/tools-3LLDG3XQ.js +15 -0
  45. package/dist/tools-3LLDG3XQ.js.map +1 -0
  46. package/llms.txt +4 -0
  47. package/package.json +9 -3
  48. package/server.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../packages/mcp-kit/src/errors.ts","../../../../packages/mcp-kit/src/tool.ts","../../../../packages/mcp-kit/src/conformance-fixtures.ts","../../../../packages/mcp-kit/src/payment.ts","../../../../packages/mcp-kit/src/example.ts","../../../../packages/mcp-kit/src/server.ts","../../../../packages/mcp-kit/src/http.ts","../../../../packages/mcp-kit/src/node-http.ts","../../../../packages/x402/src/facilitator.ts","../../../../packages/x402/src/index.ts","../../../../packages/mcp-kit/src/stdio.ts","../../../../packages/mcp-kit/src/registry.ts","../../../../packages/mcp-kit/src/docs.ts","../../../../packages/mcp-kit/src/discovery.ts","../../src/fixtures/crm-server.ts"],"sourcesContent":["/**\n * Structured tool errors. Every error an agent sees carries `code`, `cause`, `fix` and\n * `retryable` (CLAUDE.md \"Writing for agents\") so the caller can decide what to do next\n * without reading prose.\n */\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\n\n/** Standard error codes. Products may add their own (e.g. `MONITOR_PAUSED`). */\nexport const ERROR_CODES = [\n \"INVALID_INPUT\",\n \"NOT_FOUND\",\n \"UNAUTHORIZED\",\n \"PAYMENT_REQUIRED\",\n \"RATE_LIMITED\",\n \"UPSTREAM_ERROR\",\n \"INTERNAL\",\n] as const;\n\nexport type StandardErrorCode = (typeof ERROR_CODES)[number];\n/** A standard code, or a product-specific UPPER_SNAKE code. */\nexport type ErrorCode = StandardErrorCode | (string & Record<never, never>);\n\n/** Wire shape of every error body (tool result text, structuredContent and HTTP JSON alike). */\nexport type ToolErrorBody = {\n code: string;\n /** what went wrong, in one sentence */\n cause: string;\n /** what the caller should do next */\n fix: string;\n /** whether the same call can succeed on retry without changes */\n retryable: boolean;\n /** machine-readable specifics, e.g. validation issues */\n details?: unknown;\n [extra: string]: unknown;\n};\n\nexport interface ToolErrorInit {\n code: ErrorCode;\n cause: string;\n fix: string;\n /** Defaults per code: PAYMENT_REQUIRED, RATE_LIMITED, UPSTREAM_ERROR are retryable; the rest are not. */\n retryable?: boolean;\n details?: unknown;\n /** HTTP status to use when the error is surfaced over plain HTTP. Defaults per code. */\n httpStatus?: number;\n /** Extra top-level fields merged into the serialized body (e.g. a 402's `accepts`). */\n extra?: Record<string, unknown>;\n}\n\nexport const DEFAULT_RETRYABLE: Readonly<Record<StandardErrorCode, boolean>> = {\n INVALID_INPUT: false,\n NOT_FOUND: false,\n UNAUTHORIZED: false,\n PAYMENT_REQUIRED: true,\n RATE_LIMITED: true,\n UPSTREAM_ERROR: true,\n INTERNAL: false,\n};\n\nexport const DEFAULT_HTTP_STATUS: Readonly<Record<StandardErrorCode, number>> = {\n INVALID_INPUT: 400,\n NOT_FOUND: 404,\n UNAUTHORIZED: 401,\n PAYMENT_REQUIRED: 402,\n RATE_LIMITED: 429,\n UPSTREAM_ERROR: 502,\n INTERNAL: 500,\n};\n\nexport const INTERNAL_FIX = \"retry; if it persists, report the request id\";\n\nfunction isStandardCode(code: string): code is StandardErrorCode {\n return (ERROR_CODES as readonly string[]).includes(code);\n}\n\n/** Throw this (or `toolError(...)`) from a handler to return a structured error to the caller. */\nexport class McpToolError extends Error {\n readonly code: string;\n override readonly cause: string;\n readonly fix: string;\n readonly retryable: boolean;\n readonly details?: unknown;\n readonly httpStatus: number;\n readonly extra?: Record<string, unknown>;\n\n constructor(init: ToolErrorInit) {\n super(`${init.code}: ${init.cause}`);\n this.name = \"McpToolError\";\n this.code = init.code;\n this.cause = init.cause;\n this.fix = init.fix;\n this.retryable =\n init.retryable ?? (isStandardCode(init.code) ? DEFAULT_RETRYABLE[init.code] : false);\n this.details = init.details;\n this.httpStatus =\n init.httpStatus ?? (isStandardCode(init.code) ? DEFAULT_HTTP_STATUS[init.code] : 500);\n this.extra = init.extra;\n }\n\n /** The body agents see: `{ code, cause, fix, retryable, details?, ...extra }`. */\n toJSON(): ToolErrorBody {\n const body: ToolErrorBody = {\n ...this.extra,\n code: this.code,\n cause: this.cause,\n fix: this.fix,\n retryable: this.retryable,\n };\n if (this.details !== undefined) body.details = this.details;\n return body;\n }\n}\n\n/** Build a structured error. Object form or `(code, cause, fix, extra?)`. */\nexport function toolError(init: ToolErrorInit): McpToolError;\nexport function toolError(\n code: ErrorCode,\n cause: string,\n fix: string,\n extra?: Omit<ToolErrorInit, \"code\" | \"cause\" | \"fix\">,\n): McpToolError;\nexport function toolError(\n codeOrInit: ErrorCode | ToolErrorInit,\n cause?: string,\n fix?: string,\n extra?: Omit<ToolErrorInit, \"code\" | \"cause\" | \"fix\">,\n): McpToolError {\n if (typeof codeOrInit === \"object\") return new McpToolError(codeOrInit);\n return new McpToolError({ code: codeOrInit, cause: cause ?? \"\", fix: fix ?? \"\", ...extra });\n}\n\nfunction describeUnknown(err: unknown): string {\n if (err instanceof Error) return err.message || err.name;\n if (typeof err === \"string\") return err;\n try {\n return JSON.stringify(err);\n } catch {\n return String(err);\n }\n}\n\n/** Coerce anything thrown into a `McpToolError`. Unknown errors become `INTERNAL`. */\nexport function normalizeError(err: unknown): McpToolError {\n if (err instanceof McpToolError) return err;\n return new McpToolError({\n code: \"INTERNAL\",\n cause: describeUnknown(err),\n fix: INTERNAL_FIX,\n retryable: false,\n });\n}\n\nexport interface ErrorResultOptions {\n /** Echoed in `_meta.requestId` so \"report the request id\" is actionable. */\n requestId?: string;\n /** Merged into `_meta` (always includes `httpStatus`). */\n meta?: Record<string, unknown>;\n}\n\n/**\n * Turn an error into a `CallToolResult` with `isError: true`. `content[0].text` is the JSON\n * body and `structuredContent` is the same object, so both text-only and structured clients\n * see `{ code, cause, fix, retryable }`.\n */\nexport function errorResult(err: unknown, opts: ErrorResultOptions = {}): CallToolResult {\n const error = normalizeError(err);\n const body = error.toJSON();\n const meta: Record<string, unknown> = { httpStatus: error.httpStatus };\n if (opts.requestId !== undefined) meta.requestId = opts.requestId;\n Object.assign(meta, opts.meta);\n return {\n isError: true,\n content: [{ type: \"text\", text: JSON.stringify(body) }],\n structuredContent: body,\n _meta: meta,\n };\n}\n\n/** True when a result is an error result produced by this kit (or shaped like one). */\nexport function isErrorResult(result: CallToolResult): boolean {\n return result.isError === true;\n}\n\n/** Read the `{ code, cause, fix, retryable }` body out of a tool result, if it is an error. */\nexport function readErrorBody(result: CallToolResult): ToolErrorBody | undefined {\n if (result.isError !== true) return undefined;\n const structured = result.structuredContent;\n if (structured && typeof structured.code === \"string\") return structured as ToolErrorBody;\n const first = result.content[0];\n if (first && first.type === \"text\") {\n try {\n const parsed: unknown = JSON.parse(first.text);\n if (parsed && typeof parsed === \"object\" && \"code\" in parsed) return parsed as ToolErrorBody;\n } catch {\n // not JSON\n }\n }\n return undefined;\n}\n","/**\n * `defineTool` — a typed tool definition with a naming lint, zod input validation and\n * structured error results. The same `ToolDef` is served over stdio and Streamable HTTP.\n */\nimport type { RequestHandlerExtra } from \"@modelcontextprotocol/sdk/shared/protocol.js\";\nimport type {\n CallToolResult,\n ServerNotification,\n ServerRequest,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport type { z } from \"zod\";\nimport { errorResult, toolError, type McpToolError } from \"./errors.js\";\n\n/** MCP tool annotations (hints for clients; not enforced by servers). */\nexport interface ToolAnnotations {\n title?: string;\n /** the tool does not modify anything */\n readOnlyHint?: boolean;\n /** the tool may perform destructive updates (default true when not read-only) */\n destructiveHint?: boolean;\n /** repeated calls with the same arguments have no additional effect */\n idempotentHint?: boolean;\n /** the tool interacts with external entities (default true) */\n openWorldHint?: boolean;\n}\n\nexport type LogLevel =\n \"debug\" | \"info\" | \"notice\" | \"warning\" | \"error\" | \"critical\" | \"alert\" | \"emergency\";\n\n/** Per-call context handed to handlers. Built from the SDK's `extra` by the server adapter. */\nexport interface ToolContext {\n /** HTTP request headers (empty over stdio). Use for `Authorization`, payment headers, etc. */\n headers: Headers;\n /** JSON-RPC request id (string form) — quote it in error reports. */\n requestId?: string;\n /** aborted when the client cancels the request */\n signal?: AbortSignal;\n /** transport session id, when the transport is stateful */\n sessionId?: string;\n /** true when the caller asked for a free sample (set by `withPayment`) */\n sample?: boolean;\n /** set by `withPayment`'s `authorize` when the caller is a known user */\n userId?: string;\n /**\n * The public URL this call arrived at, when it arrived over HTTP.\n *\n * `withPayment` quotes the tool's *name* as the resource by default, which is right for a\n * stdio MCP call and wrong for everything a payment facilitator does with it: a discovery\n * catalog keyed on `realestate_deal_memo` lists something no agent can fetch. An HTTP front\n * door sets this so settlements are attributed to a URL instead.\n */\n resourceUrl?: string;\n /** the request's `_meta` (e.g. `progressToken`) */\n meta?: Record<string, unknown>;\n /** send a log notification to the client (no-op when the transport cannot deliver it) */\n log?: (level: LogLevel, data: unknown) => Promise<void>;\n /** report progress; no-op unless the caller supplied a progress token */\n progress?: (progress: number, total?: number, message?: string) => Promise<void>;\n /**\n * The raw SDK request context — `sendRequest` for sampling (`sampling/createMessage`) and\n * elicitation (`elicitation/create`), `authInfo`, task helpers. Absent when invoked directly.\n */\n extra?: RequestHandlerExtra<ServerRequest, ServerNotification>;\n}\n\n/** Build a context for calling `tool.invoke` directly (tests, cron jobs, in-process use). */\nexport function createToolContext(init: Partial<ToolContext> = {}): ToolContext {\n const { headers, ...rest } = init;\n return { headers: headers ?? new Headers(), ...rest };\n}\n\nexport type ToolInput<TInput extends z.ZodObject> = z.output<TInput>;\nexport type ToolOutput<TOutput> = TOutput extends z.ZodType ? z.output<TOutput> : unknown;\n\nexport interface ToolDef<\n TInput extends z.ZodObject = z.ZodObject,\n TOutput extends z.ZodType | undefined = z.ZodType | undefined,\n> {\n /** `<namespace>_<verb>_<object>`, e.g. `agentcheck_create_monitor` */\n readonly name: string;\n readonly title?: string;\n /** written for a new teammate: what it does, when to use it, what it returns */\n readonly description: string;\n readonly input: TInput;\n /** when given, handler results are validated against it and returned as `structuredContent` */\n readonly output?: TOutput;\n readonly annotations?: ToolAnnotations;\n /** The business logic. Throw `toolError(...)` for structured errors. */\n handler(\n input: z.output<TInput>,\n ctx: ToolContext,\n ): ToolOutput<TOutput> | Promise<ToolOutput<TOutput>>;\n /** Validate raw input, run the handler and shape the result. Never throws. */\n invoke(rawInput: unknown, ctx: ToolContext): Promise<CallToolResult>;\n}\n\nexport interface DefineToolOptions<\n TInput extends z.ZodObject,\n TOutput extends z.ZodType | undefined,\n> {\n name: string;\n title?: string;\n description: string;\n input: TInput;\n output?: TOutput;\n annotations?: ToolAnnotations;\n handler(\n input: z.output<TInput>,\n ctx: ToolContext,\n ): ToolOutput<TOutput> | Promise<ToolOutput<TOutput>>;\n}\n\n/** `namespace_verb_object`: lowercase, digits, single underscores, at least one underscore. */\nexport const TOOL_NAME_PATTERN = /^[a-z][a-z0-9]*(_[a-z0-9]+)+$/;\nexport const MIN_NAMESPACE_LENGTH = 3;\nexport const MIN_DESCRIPTION_LENGTH = 20;\n\nexport function isValidToolName(name: string): boolean {\n if (!TOOL_NAME_PATTERN.test(name)) return false;\n const namespace = name.split(\"_\")[0] ?? \"\";\n return namespace.length >= MIN_NAMESPACE_LENGTH;\n}\n\n/** Naming lint: throws unless `name` is `<namespace>_<verb>_<object>` with a namespace of 3+ chars. */\nexport function assertToolName(name: string): void {\n if (!isValidToolName(name)) {\n throw new Error(\n `tool name must be namespaced: <namespace>_<verb>_<object>, got ${JSON.stringify(name)}`,\n );\n }\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) return false;\n const proto: unknown = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\n/** A handler may return a ready-made `CallToolResult` (e.g. image/audio content blocks). */\nexport function isCallToolResult(value: unknown): value is CallToolResult {\n if (!isPlainObject(value) || !Array.isArray(value.content)) return false;\n return value.content.every(\n (block: unknown) => isPlainObject(block) && typeof block.type === \"string\",\n );\n}\n\n/** Shape a handler's return value into a `CallToolResult`: JSON text plus `structuredContent`. */\nexport function toCallToolResult(value: unknown): CallToolResult {\n if (isCallToolResult(value)) return value;\n const text = typeof value === \"string\" ? value : JSON.stringify(value ?? null, null, 2);\n const result: CallToolResult = { content: [{ type: \"text\", text }] };\n if (isPlainObject(value)) result.structuredContent = value;\n return result;\n}\n\ninterface IssueLike {\n path: PropertyKey[];\n message: string;\n code?: string;\n}\n\nfunction issuePath(issue: IssueLike): string {\n return issue.path.map(String).join(\".\") || \"(root)\";\n}\n\n/** `INVALID_INPUT` with the offending field names in `fix` and the zod issues in `details`. */\nexport function invalidInputError(issues: readonly IssueLike[]): McpToolError {\n const fields = [...new Set(issues.map(issuePath))];\n const summary = issues.map((issue) => `${issuePath(issue)}: ${issue.message}`).join(\"; \");\n return toolError({\n code: \"INVALID_INPUT\",\n cause: `invalid input for ${fields.join(\", \")} — ${summary}`,\n fix: `fix ${fields.join(\", \")} to match the tool's inputSchema (see details.issues), then retry`,\n retryable: false,\n details: {\n fields,\n issues: issues.map((issue) => ({\n path: issue.path.map(String),\n code: issue.code,\n message: issue.message,\n })),\n },\n });\n}\n\n/**\n * Define a tool. Throws at definition time when the name is not namespaced or the description\n * is too short, so mistakes surface at boot rather than in an agent's transcript.\n */\nexport function defineTool<\n TInput extends z.ZodObject,\n TOutput extends z.ZodType | undefined = undefined,\n>(opts: DefineToolOptions<TInput, TOutput>): ToolDef<TInput, TOutput> {\n assertToolName(opts.name);\n if (\n typeof opts.description !== \"string\" ||\n opts.description.trim().length < MIN_DESCRIPTION_LENGTH\n ) {\n throw new Error(\n `tool ${opts.name}: description must be at least ${MIN_DESCRIPTION_LENGTH} characters — say what it does, when to use it and what it returns`,\n );\n }\n const { name, title, description, input, output, annotations } = opts;\n const handler = opts.handler.bind(opts);\n\n const tool: ToolDef<TInput, TOutput> = {\n name,\n title,\n description,\n input,\n output,\n annotations,\n handler,\n async invoke(rawInput, ctx) {\n // The SDK client validates any structuredContent against the advertised outputSchema, even\n // on error results, so tools with an output schema carry the error body in text only.\n const fail = (err: unknown): CallToolResult => {\n const result = errorResult(err, { requestId: ctx.requestId });\n if (output) delete result.structuredContent;\n return result;\n };\n const parsed = input.safeParse(rawInput ?? {});\n if (!parsed.success) return fail(invalidInputError(parsed.error.issues));\n try {\n const value: unknown = await handler(parsed.data, ctx);\n if (output && !isCallToolResult(value)) {\n const checked = output.safeParse(value);\n if (!checked.success) {\n throw toolError({\n code: \"INTERNAL\",\n cause: `tool ${name} returned a value that does not match its output schema — ${checked.error.issues\n .map((issue) => `${issuePath(issue)}: ${issue.message}`)\n .join(\"; \")}`,\n fix: \"this is a bug in the tool, not in your call; report it with the request id\",\n retryable: false,\n details: { issues: checked.error.issues },\n });\n }\n return toCallToolResult(checked.data);\n }\n return toCallToolResult(value);\n } catch (err) {\n return fail(err);\n }\n },\n };\n return tool;\n}\n","/**\n * Fixture tools, resources and prompts with the names and shapes the official conformance\n * suite (`@modelcontextprotocol/conformance`) expects. Add them to any kit server to run\n * `conformance server --url …` against it. Not for production.\n */\nimport { completable } from \"@modelcontextprotocol/sdk/server/completable.js\";\nimport { type McpServer, ResourceTemplate } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport {\n CreateMessageResultSchema,\n ElicitResultSchema,\n SubscribeRequestSchema,\n UnsubscribeRequestSchema,\n type ElicitRequest,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { z } from \"zod\";\nimport { toolError } from \"./errors.js\";\nimport { defineTool, type ToolContext, type ToolDef } from \"./tool.js\";\n\n/** 1×1 transparent PNG */\nconst PNG_BASE64 =\n \"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==\";\n/** 44-byte WAV header, zero samples */\nconst WAV_BASE64 = \"UklGRiQAAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YQAAAAA=\";\n\nconst STATIC_TEXT_URI = \"test://static-text\";\nconst STATIC_TEXT = \"This is a static text resource for testing.\";\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\n/** Form-mode elicitation schema (the params type is a union with URL-mode elicitation). */\ntype RequestedSchema = Extract<\n ElicitRequest[\"params\"],\n { requestedSchema: unknown }\n>[\"requestedSchema\"];\n\nfunction embeddedResource(): {\n type: \"resource\";\n resource: { uri: string; mimeType: string; text: string };\n} {\n return {\n type: \"resource\",\n resource: { uri: STATIC_TEXT_URI, mimeType: \"text/plain\", text: STATIC_TEXT },\n };\n}\n\nfunction requireExtra(ctx: ToolContext): NonNullable<ToolContext[\"extra\"]> {\n if (!ctx.extra) {\n throw toolError(\"INTERNAL\", \"no client connection in this context\", \"call this tool over MCP\");\n }\n return ctx.extra;\n}\n\nasync function elicit(\n ctx: ToolContext,\n message: string,\n requestedSchema: RequestedSchema,\n): Promise<string> {\n const result = await requireExtra(ctx).sendRequest(\n { method: \"elicitation/create\", params: { message, requestedSchema } },\n ElicitResultSchema,\n );\n return `Elicitation completed: action=${result.action}, content=${JSON.stringify(result.content ?? {})}`;\n}\n\n/** The tool fixtures the suite calls by name. */\nexport const conformanceTools: ToolDef[] = [\n defineTool({\n name: \"test_simple_text\",\n description: \"Conformance fixture: returns a fixed simple text response.\",\n input: z.object({}),\n handler: () => \"This is a simple text response for testing.\",\n }),\n defineTool({\n name: \"test_error_handling\",\n description: \"Conformance fixture: always returns an error result (isError: true).\",\n input: z.object({}),\n handler: () => {\n throw toolError({\n code: \"UPSTREAM_ERROR\",\n cause: \"This tool intentionally returns an error for testing\",\n fix: \"nothing to fix; this fixture always fails\",\n retryable: false,\n });\n },\n }),\n defineTool({\n name: \"test_image_content\",\n description: \"Conformance fixture: returns a 1x1 PNG image content block.\",\n input: z.object({}),\n handler: () => ({ content: [{ type: \"image\", data: PNG_BASE64, mimeType: \"image/png\" }] }),\n }),\n defineTool({\n name: \"test_audio_content\",\n description: \"Conformance fixture: returns an empty WAV audio content block.\",\n input: z.object({}),\n handler: () => ({ content: [{ type: \"audio\", data: WAV_BASE64, mimeType: \"audio/wav\" }] }),\n }),\n defineTool({\n name: \"test_embedded_resource\",\n description: \"Conformance fixture: returns an embedded text resource content block.\",\n input: z.object({}),\n handler: () => ({ content: [embeddedResource()] }),\n }),\n defineTool({\n name: \"test_multiple_content_types\",\n description: \"Conformance fixture: returns text, image and resource content blocks together.\",\n input: z.object({}),\n handler: () => ({\n content: [\n { type: \"text\", text: \"Mixed content response\" },\n { type: \"image\", data: PNG_BASE64, mimeType: \"image/png\" },\n embeddedResource(),\n ],\n }),\n }),\n defineTool({\n name: \"test_tool_with_logging\",\n description: \"Conformance fixture: emits three info log notifications while running.\",\n input: z.object({}),\n handler: async (_input, ctx) => {\n await ctx.log?.(\"info\", \"Tool execution started\");\n await sleep(50);\n await ctx.log?.(\"info\", \"Tool processing data\");\n await sleep(50);\n await ctx.log?.(\"info\", \"Tool execution completed\");\n return \"Tool execution completed with logging\";\n },\n }),\n defineTool({\n name: \"test_tool_with_progress\",\n description: \"Conformance fixture: reports progress 0/100, 50/100, 100/100 while running.\",\n input: z.object({}),\n handler: async (_input, ctx) => {\n await ctx.progress?.(0, 100, \"starting\");\n await sleep(50);\n await ctx.progress?.(50, 100, \"halfway\");\n await sleep(50);\n await ctx.progress?.(100, 100, \"done\");\n return \"Tool execution completed with progress\";\n },\n }),\n defineTool({\n name: \"test_sampling\",\n description: \"Conformance fixture: asks the client to sample a completion and returns it.\",\n input: z.object({ prompt: z.string().describe(\"Prompt to send to the client's model\") }),\n handler: async ({ prompt }, ctx) => {\n const result = await requireExtra(ctx).sendRequest(\n {\n method: \"sampling/createMessage\",\n params: {\n messages: [{ role: \"user\", content: { type: \"text\", text: prompt } }],\n maxTokens: 100,\n },\n },\n CreateMessageResultSchema,\n );\n const content = Array.isArray(result.content) ? result.content[0] : result.content;\n const text = content && content.type === \"text\" ? content.text : JSON.stringify(content);\n return `Sampling completed (${result.model}): ${text}`;\n },\n }),\n defineTool({\n name: \"test_elicitation\",\n description: \"Conformance fixture: asks the client for user input and reports the outcome.\",\n input: z.object({ message: z.string().describe(\"Message shown to the user\") }),\n handler: ({ message }, ctx) =>\n elicit(ctx, message, {\n type: \"object\",\n properties: {\n name: { type: \"string\", title: \"Name\", description: \"Your name\" },\n email: { type: \"string\", title: \"Email\", format: \"email\" },\n },\n required: [\"name\"],\n }),\n }),\n defineTool({\n name: \"test_elicitation_sep1034_defaults\",\n description: \"Conformance fixture: elicitation schema with defaults for every primitive type.\",\n input: z.object({}),\n handler: (_input, ctx) =>\n elicit(ctx, \"Please confirm your details\", {\n type: \"object\",\n properties: {\n name: { type: \"string\", title: \"Name\", default: \"John Doe\" },\n age: { type: \"integer\", title: \"Age\", default: 30 },\n score: { type: \"number\", title: \"Score\", default: 95.5 },\n status: {\n type: \"string\",\n title: \"Status\",\n enum: [\"active\", \"inactive\", \"pending\"],\n default: \"active\",\n },\n verified: { type: \"boolean\", title: \"Verified\", default: true },\n },\n }),\n }),\n defineTool({\n name: \"test_elicitation_sep1330_enums\",\n description:\n \"Conformance fixture: elicitation schema with titled, untitled and multi-select enums.\",\n input: z.object({}),\n handler: (_input, ctx) =>\n elicit(ctx, \"Pick some options\", {\n type: \"object\",\n properties: {\n untitledSingle: {\n type: \"string\",\n title: \"Untitled single\",\n enum: [\"red\", \"green\", \"blue\"],\n },\n titledSingle: {\n type: \"string\",\n title: \"Titled single\",\n oneOf: [\n { const: \"red\", title: \"Red\" },\n { const: \"green\", title: \"Green\" },\n { const: \"blue\", title: \"Blue\" },\n ],\n },\n legacyEnum: {\n type: \"string\",\n title: \"Legacy titled\",\n enum: [\"red\", \"green\", \"blue\"],\n enumNames: [\"Red\", \"Green\", \"Blue\"],\n },\n untitledMulti: {\n type: \"array\",\n title: \"Untitled multi\",\n items: { type: \"string\", enum: [\"red\", \"green\", \"blue\"] },\n },\n titledMulti: {\n type: \"array\",\n title: \"Titled multi\",\n items: {\n anyOf: [\n { const: \"red\", title: \"Red\" },\n { const: \"green\", title: \"Green\" },\n { const: \"blue\", title: \"Blue\" },\n ],\n },\n },\n },\n } as RequestedSchema),\n }),\n defineTool({\n name: \"json_schema_2020_12_tool\",\n description: \"Conformance fixture: input schema with a $defs reference to an address object.\",\n input: z.object({\n name: z.string(),\n address: z.object({ street: z.string(), city: z.string() }).meta({ id: \"address\" }),\n }),\n handler: (input) => input,\n }),\n];\n\n/** Register the resource and prompt fixtures on a kit server (call before connecting). */\nexport function registerConformanceFixtures(server: McpServer): void {\n server.server.registerCapabilities({ resources: { subscribe: true, listChanged: true } });\n\n server.registerResource(\n \"static-text\",\n STATIC_TEXT_URI,\n { title: \"Static text\", description: \"A static text resource\", mimeType: \"text/plain\" },\n async (uri) => ({ contents: [{ uri: uri.href, mimeType: \"text/plain\", text: STATIC_TEXT }] }),\n );\n server.registerResource(\n \"static-binary\",\n \"test://static-binary\",\n { title: \"Static binary\", description: \"A static binary resource\", mimeType: \"image/png\" },\n async (uri) => ({ contents: [{ uri: uri.href, mimeType: \"image/png\", blob: PNG_BASE64 }] }),\n );\n server.registerResource(\n \"watched-resource\",\n \"test://watched-resource\",\n {\n title: \"Watched resource\",\n description: \"Supports subscribe/unsubscribe\",\n mimeType: \"text/plain\",\n },\n async (uri) => ({ contents: [{ uri: uri.href, mimeType: \"text/plain\", text: \"watched\" }] }),\n );\n server.registerResource(\n \"template-data\",\n new ResourceTemplate(\"test://template/{id}/data\", { list: undefined }),\n { title: \"Template data\", description: \"Data for an id\", mimeType: \"text/plain\" },\n async (uri, variables) => ({\n contents: [\n { uri: uri.href, mimeType: \"text/plain\", text: `Data for id ${String(variables.id)}` },\n ],\n }),\n );\n server.server.setRequestHandler(SubscribeRequestSchema, async () => ({}));\n server.server.setRequestHandler(UnsubscribeRequestSchema, async () => ({}));\n\n server.registerPrompt(\n \"test_simple_prompt\",\n { description: \"A simple prompt without arguments\" },\n () => ({\n messages: [\n { role: \"user\", content: { type: \"text\", text: \"This is a simple prompt for testing.\" } },\n ],\n }),\n );\n server.registerPrompt(\n \"test_prompt_with_arguments\",\n {\n description: \"A prompt with two arguments\",\n argsSchema: {\n arg1: completable(z.string().describe(\"First argument\"), (value) =>\n [\"test\", \"testValue1\", \"testing\"].filter((v) => v.startsWith(value)),\n ),\n arg2: z.string().describe(\"Second argument\"),\n },\n },\n ({ arg1, arg2 }) => ({\n messages: [\n {\n role: \"user\",\n content: { type: \"text\", text: `Prompt with arg1=${arg1} and arg2=${arg2}` },\n },\n ],\n }),\n );\n server.registerPrompt(\n \"test_prompt_with_embedded_resource\",\n {\n description: \"A prompt that embeds a resource\",\n argsSchema: { resourceUri: z.string().describe(\"URI of the resource to embed\") },\n },\n ({ resourceUri }) => ({\n messages: [\n { role: \"user\", content: { type: \"text\", text: \"Here is the resource:\" } },\n {\n role: \"user\",\n content: {\n type: \"resource\",\n resource: { uri: resourceUri, mimeType: \"text/plain\", text: STATIC_TEXT },\n },\n },\n ],\n }),\n );\n server.registerPrompt(\n \"test_prompt_with_image\",\n { description: \"A prompt that includes an image\" },\n () => ({\n messages: [\n { role: \"user\", content: { type: \"text\", text: \"Describe this image:\" } },\n { role: \"user\", content: { type: \"image\", data: PNG_BASE64, mimeType: \"image/png\" } },\n ],\n }),\n );\n}\n","/**\n * `withPayment` — gate a tool behind a price. Wave 0: nothing is charged; callers without an\n * entitlement get a 402-shaped `PAYMENT_REQUIRED` result advertising both rails (x402 on Base,\n * Stripe MPP) with `comingSoon: true`, and `sample: true` returns an example for free.\n */\nimport {\n StubVerifier,\n buildPaymentRequired,\n type PaymentRequirement,\n paymentRequiredResponse,\n type PaymentRequiredBody,\n type PaymentVerifier,\n type SelfServe,\n type VerifyResult,\n} from \"@agentwares/x402\";\nimport { z } from \"zod\";\nimport { toolError, type McpToolError } from \"./errors.js\";\nimport { defineTool, type ToolContext, type ToolDef } from \"./tool.js\";\n\nexport interface AuthorizeResult {\n ok: boolean;\n userId?: string;\n /** why not, e.g. \"API key revoked\" — surfaced in `details.reason` */\n reason?: string;\n}\n\nexport interface WithPaymentOptions {\n /** price per successful call, in USD (e.g. 0.05) */\n priceUsd: number;\n /** Entitlement check (API key + credits, subscription tier). `ok: true` skips payment. */\n authorize?: (ctx: ToolContext) => Promise<AuthorizeResult> | AuthorizeResult;\n /** Payment verifier for the request headers. Default: `StubVerifier` (never accepts). */\n verifier?: PaymentVerifier;\n /** set once pay-per-call is live (drops `comingSoon`) */\n live?: boolean;\n /** name of the boolean input field that requests a free sample (default `sample`) */\n sampleField?: string;\n /** shown in the payment requirement */\n description?: string;\n /**\n * Discovery metadata for the x402 `bazaar` extension. Advertised in the 402 so a client can\n * echo it back; without that echo the facilitator will not catalog the resource, however\n * many payments settle against it.\n */\n bazaar?: Record<string, unknown>;\n payTo?: string;\n /** prepaid_credits rail: the URL that takes a card and funds a balance */\n creditsPayTo?: string;\n signupUrl?: string;\n /** the no-human purchase path, advertised in the 402 body once the card rail is live */\n selfServe?: SelfServe;\n /**\n * Called when a call that was already paid for then fails. A verifier that charges up\n * front (the prepaid wallet does) uses this to give the money back, so a caller is never\n * billed for an error. `receipt` is whatever the verifier returned.\n */\n onPaidFailure?: (\n ctx: ToolContext,\n verified: VerifyResult,\n error: unknown,\n ) => Promise<void> | void;\n /**\n * The paid work succeeded but the money did not arrive — an on-chain settlement that was\n * refused or a facilitator that went away. Never throw from here: the buyer has a valid\n * result and this is our accounting problem, not their failed request.\n */\n onSettlementFailure?: (ctx: ToolContext, verified: VerifyResult, reason?: string) => void;\n}\n\n/** A `McpToolError` whose body is the x402 `PaymentRequiredBody` (code `PAYMENT_REQUIRED`). */\nexport function paymentRequiredError(body: PaymentRequiredBody, reason?: string): McpToolError {\n const { code, cause, fix, retryable, ...rest } = body;\n return toolError({\n code,\n cause,\n fix,\n retryable,\n httpStatus: 402,\n details: reason !== undefined ? { reason } : undefined,\n extra: rest,\n });\n}\n\nfunction formatUsd(priceUsd: number): string {\n return priceUsd\n .toFixed(6)\n .replace(/0+$/, \"\")\n .replace(/\\.$/, \".00\")\n .replace(/\\.(\\d)$/, \".$10\");\n}\n\n/**\n * Wrap a tool so it requires an entitlement or payment. The returned tool has the same name,\n * schema and output, plus an optional boolean `sample` input (default false) documented as\n * \"return an example response at no charge\".\n *\n * Flow per call: `sample` → handler with `ctx.sample = true`; else `authorize` ok → handler\n * (with `ctx.userId`); else verifier accepts the request's payment headers → handler; else a\n * `PAYMENT_REQUIRED` error result (`_meta.httpStatus: 402`).\n */\nexport function withPayment(tool: ToolDef, opts: WithPaymentOptions): ToolDef {\n if (!Number.isFinite(opts.priceUsd) || opts.priceUsd < 0) {\n throw new Error(`withPayment(${tool.name}): priceUsd must be a non-negative number`);\n }\n const sampleField = opts.sampleField ?? \"sample\";\n if (sampleField in tool.input.shape) {\n throw new Error(\n `withPayment(${tool.name}): input already has a field named ${JSON.stringify(sampleField)}; pass sampleField to rename it`,\n );\n }\n const verifier: PaymentVerifier = opts.verifier ?? new StubVerifier();\n // A verifier that was configured is a rail that can actually be settled, so when it refuses\n // it knows why (\"insufficient credit: $0.00 available, $0.75 needed\") and its reason is the\n // one the caller can act on. Without one, `authorize`'s reason is all there is.\n const liveRail = opts.verifier !== undefined;\n const input = tool.input.extend({\n [sampleField]: z\n .boolean()\n .default(false)\n .describe(\n \"Set true to return an example response at no charge (sample mode). Default false.\",\n ),\n });\n const description = `${tool.description.trim()} Paid: $${formatUsd(opts.priceUsd)} per call; without credit you get a PAYMENT_REQUIRED result. Set ${sampleField}=true for a free example response.`;\n\n return defineTool({\n name: tool.name,\n title: tool.title,\n description,\n input,\n output: tool.output,\n annotations: tool.annotations,\n async handler(raw, ctx) {\n const record: Record<string, unknown> = { ...raw };\n const sample = record[sampleField] === true;\n delete record[sampleField];\n\n if (sample) return tool.handler(record, { ...ctx, sample: true });\n\n let reason: string | undefined;\n if (opts.authorize) {\n const auth = await opts.authorize(ctx);\n if (auth.ok) return tool.handler(record, { ...ctx, userId: auth.userId });\n reason = auth.reason;\n }\n\n // A tool name is not a resource. Over HTTP the front door knows the real URL and puts\n // it on the context; over stdio there is no URL and the name is the best there is.\n const resource = ctx.resourceUrl ?? tool.name;\n const required = buildPaymentRequired({\n resource,\n priceUsd: opts.priceUsd,\n live: opts.live,\n description: opts.description,\n payTo: opts.payTo,\n creditsPayTo: opts.creditsPayTo,\n signupUrl: opts.signupUrl,\n selfServe: opts.selfServe,\n // withPayment always adds a free `sample` flag to the tool's input schema\n sampleMode: true,\n ...(opts.bazaar ? { bazaar: opts.bazaar } : {}),\n });\n // What we advertise and what we accept are separate questions. `accepts` only lists\n // rails a caller could actually settle, and is empty when none is configured — but a\n // caller may still present credit or a payment header, so the verifier always runs.\n // The card rail is checked first because it is the one that can be settled today.\n const advertised =\n required.body.accepts.find((a) => a.rail === \"prepaid_credits\") ?? required.body.accepts[0];\n const requirement: PaymentRequirement = advertised ?? {\n rail: \"prepaid_credits\",\n amountUsd: String(required.body.priceUsd),\n resource,\n ...(opts.description ? { description: opts.description } : {}),\n };\n const verified = await verifier.verify(\n new Request(`https://mcp.local/${tool.name}`, { headers: ctx.headers }),\n requirement,\n );\n if (verified.ok) {\n let result: Awaited<ReturnType<typeof tool.handler>>;\n try {\n result = await tool.handler(record, ctx);\n } catch (error) {\n // Rails that already took the money refund here. Rails with a `settle` step have\n // not taken it yet, and the early return means they never will — the buyer is not\n // charged for a call that failed.\n await opts.onPaidFailure?.(ctx, verified, error);\n throw error;\n }\n // The work succeeded, so take the money. A settlement that fails now is lost\n // revenue, not a failed request: the buyer has already been served, and turning\n // this into an error would hand them the result *and* a 402.\n const settled = await verifier.settle?.(verified);\n if (settled && !settled.ok) {\n opts.onSettlementFailure?.(ctx, verified, settled.reason);\n }\n return result;\n }\n reason = liveRail ? (verified.reason ?? reason) : (reason ?? verified.reason);\n throw paymentRequiredError(required.body, reason);\n },\n });\n}\n\n/** Web-standard 402 `Response` for plain HTTP endpoints (re-export of `@agentwares/x402`). */\nexport const paymentRequiredHttpResponse = paymentRequiredResponse;\n\nexport { StubVerifier, buildPaymentRequired };\nexport type { PaymentRequiredBody, PaymentVerifier, SelfServe, VerifyResult };\n","/**\n * A tiny example server: two free tools and one paid tool. Used by the README, the HTTP\n * round-trip test and the conformance script.\n */\nimport { z } from \"zod\";\nimport { withPayment } from \"./payment.js\";\nimport { defineTool, type ToolDef } from \"./tool.js\";\n\nexport const exampleServerInfo = {\n name: \"mcp-kit-example\",\n version: \"0.1.0\",\n instructions:\n \"Example server built with @agentwares/mcp-kit. Call example_echo to check the connection, example_add to see typed structured output, and example_paid_lookup (sample=true first) to see how paid tools respond.\",\n};\n\nexport const exampleEcho = defineTool({\n name: \"example_echo\",\n title: \"Echo\",\n description:\n \"Echo a message back unchanged. Use it to check the connection and to see the result shape mcp-kit tools return (JSON text plus structuredContent).\",\n input: z.object({ message: z.string().describe(\"Text to echo back\") }),\n output: z.object({ message: z.string() }),\n annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },\n handler: ({ message }) => ({ message }),\n});\n\nexport const exampleAdd = defineTool({\n name: \"example_add\",\n title: \"Add\",\n description:\n \"Add two numbers and return their sum as { sum }. Demonstrates typed input and output schemas; send non-numbers to see an INVALID_INPUT error result.\",\n input: z.object({\n a: z.number().describe(\"First addend\"),\n b: z.number().describe(\"Second addend\"),\n }),\n output: z.object({ sum: z.number() }),\n annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },\n handler: ({ a, b }) => ({ sum: a + b }),\n});\n\nexport const examplePaidLookup = withPayment(\n defineTool({\n name: \"example_paid_lookup\",\n title: \"Paid lookup\",\n description:\n \"Look up a record by query and return { query, result, sample } (fake data). Demonstrates a paid tool: without an entitlement the call returns a PAYMENT_REQUIRED result with x402 and MPP payment options.\",\n input: z.object({ query: z.string().min(1).describe(\"What to look up\") }),\n output: z.object({ query: z.string(), result: z.string(), sample: z.boolean() }),\n annotations: { readOnlyHint: true, idempotentHint: true },\n handler: ({ query }, ctx) => ({\n query,\n result: ctx.sample ? `SAMPLE: example record for \"${query}\"` : `record for \"${query}\"`,\n sample: ctx.sample === true,\n }),\n }),\n { priceUsd: 0.05, description: \"One record lookup\" },\n);\n\nexport const exampleTools: ToolDef[] = [exampleEcho, exampleAdd, examplePaidLookup];\n","/**\n * `createMcpServer` — an SDK `McpServer` with every `ToolDef` registered, plus the manifest\n * helper used for `llms.txt` and docs.\n */\nimport { McpServer, type RegisteredTool } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { RequestHandlerExtra } from \"@modelcontextprotocol/sdk/shared/protocol.js\";\nimport {\n CallToolRequestSchema,\n ErrorCode,\n ListToolsRequestSchema,\n McpError,\n type ServerCapabilities,\n type ServerNotification,\n type ServerRequest,\n type Tool,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { z } from \"zod\";\nimport type { ToolAnnotations, ToolContext, ToolDef } from \"./tool.js\";\n\nexport interface McpServerOptions {\n /** server name as shown to clients, e.g. `agentcheck` */\n name: string;\n version: string;\n title?: string;\n websiteUrl?: string;\n /** shown to the model at connect time: what the server is for and how to start */\n instructions?: string;\n tools: ToolDef[];\n /** extra capabilities (tools and logging are always declared) */\n capabilities?: ServerCapabilities;\n}\n\ntype Extra = RequestHandlerExtra<ServerRequest, ServerNotification>;\n\nfunction isZodObject(schema: unknown): schema is z.ZodObject {\n return schema instanceof z.ZodObject;\n}\n\n/** Build a `ToolContext` from the SDK's request `extra` (headers, ids, signal, notifications). */\nexport function contextFromExtra(extra: Extra): ToolContext {\n const headers = new Headers();\n const raw = extra.requestInfo?.headers;\n if (raw) {\n for (const [key, value] of Object.entries(raw)) {\n if (Array.isArray(value)) for (const item of value) headers.append(key, item);\n else if (typeof value === \"string\") headers.append(key, value);\n }\n }\n const progressToken = extra._meta?.progressToken;\n return {\n headers,\n requestId: String(extra.requestId),\n signal: extra.signal,\n sessionId: extra.sessionId,\n meta: extra._meta,\n extra,\n log: async (level, data) => {\n await extra.sendNotification({ method: \"notifications/message\", params: { level, data } });\n },\n progress: async (progress, total, message) => {\n if (progressToken === undefined) return;\n await extra.sendNotification({\n method: \"notifications/progress\",\n params: { progressToken, progress, total, message },\n });\n },\n };\n}\n\n/**\n * Create an `McpServer` with all tools registered. Duplicate names throw.\n *\n * Tools are registered with the SDK (capabilities, enable/disable, list-changed notifications),\n * but `tools/list` and `tools/call` are served by the kit: the listing is exactly\n * `listToolManifest(tools)` (JSON Schema 2020-12, `additionalProperties: false`), and invalid\n * arguments or handler failures come back as in-band `{ code, cause, fix, retryable }` results\n * instead of bare JSON-RPC errors.\n */\nexport function createMcpServer(opts: McpServerOptions): McpServer {\n const byName = new Map<string, ToolDef>();\n for (const tool of opts.tools) {\n if (byName.has(tool.name)) throw new Error(`duplicate tool name: ${tool.name}`);\n byName.set(tool.name, tool);\n }\n\n const server = new McpServer(\n { name: opts.name, version: opts.version, title: opts.title, websiteUrl: opts.websiteUrl },\n { instructions: opts.instructions, capabilities: { logging: {}, ...opts.capabilities } },\n );\n\n const registered = new Map<string, RegisteredTool>();\n for (const tool of byName.values()) {\n const config: {\n title?: string;\n description: string;\n inputSchema: z.ZodObject;\n outputSchema?: z.ZodObject;\n annotations?: ToolAnnotations;\n } = {\n title: tool.title,\n description: tool.description,\n inputSchema: tool.input,\n annotations: tool.annotations,\n };\n if (isZodObject(tool.output)) config.outputSchema = tool.output;\n registered.set(\n tool.name,\n server.registerTool(tool.name, config, () => {\n throw new Error(\"unreachable: mcp-kit dispatches tools/call itself\");\n }),\n );\n }\n\n if (byName.size > 0) {\n server.server.setRequestHandler(ListToolsRequestSchema, async () => {\n const enabled = [...byName.values()].filter(\n (tool) => registered.get(tool.name)?.enabled !== false,\n );\n return {\n tools: listToolManifest(enabled).map((entry) => ({\n ...entry,\n inputSchema: entry.inputSchema as Tool[\"inputSchema\"],\n outputSchema: entry.outputSchema as Tool[\"outputSchema\"],\n })),\n };\n });\n server.server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {\n const name = request.params.name;\n const tool = byName.get(name);\n const entry = registered.get(name);\n if (!tool || !entry) throw new McpError(ErrorCode.InvalidParams, `Tool ${name} not found`);\n if (!entry.enabled) throw new McpError(ErrorCode.InvalidParams, `Tool ${name} disabled`);\n return tool.invoke(request.params.arguments ?? {}, contextFromExtra(extra));\n });\n }\n\n return server;\n}\n\nexport interface ToolManifestEntry {\n name: string;\n title?: string;\n description: string;\n inputSchema: Record<string, unknown>;\n outputSchema?: Record<string, unknown>;\n annotations?: ToolAnnotations;\n}\n\n/**\n * JSON Schema (2020-12) for a zod schema, as advertised to clients. Plain `z.object`s strip\n * unknown keys at runtime, so they are advertised with `additionalProperties: false` (strict\n * schemas keep agents from inventing parameters); `z.looseObject` keeps them open.\n */\nexport function toJsonSchema(\n schema: z.ZodType,\n io: \"input\" | \"output\" = \"input\",\n): Record<string, unknown> {\n const json = z.toJSONSchema(schema, { io, target: \"draft-2020-12\" }) as Record<string, unknown>;\n if (\n isZodObject(schema) &&\n schema._zod.def.catchall === undefined &&\n json.additionalProperties === undefined\n ) {\n json.additionalProperties = false;\n }\n return json;\n}\n\n/** Plain JSON description of the tools — for `llms.txt`, docs pages and registries. */\nexport function listToolManifest(tools: readonly ToolDef[]): ToolManifestEntry[] {\n return tools.map((tool) => {\n const entry: ToolManifestEntry = {\n name: tool.name,\n description: tool.description,\n inputSchema: toJsonSchema(tool.input, \"input\"),\n };\n if (tool.title !== undefined) entry.title = tool.title;\n if (isZodObject(tool.output)) entry.outputSchema = toJsonSchema(tool.output, \"output\");\n if (tool.annotations !== undefined) entry.annotations = tool.annotations;\n return entry;\n });\n}\n","/**\n * Web-standard Streamable HTTP handler: `(Request) => Promise<Response>`. Runs unchanged in\n * Next.js route handlers, Vercel Functions and Cloudflare Workers.\n *\n * Stateless by default: a fresh server and transport per request, closed when the response\n * finishes. Opt into `sessions: true` for a long-lived process that needs server→client\n * requests (sampling, elicitation) or the standalone GET stream.\n */\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { WebStandardStreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js\";\nimport { normalizeError } from \"./errors.js\";\nimport { createMcpServer, type McpServerOptions } from \"./server.js\";\n\nexport interface CorsOptions {\n /** `Access-Control-Allow-Origin` (default `*`) */\n origin?: string;\n methods?: string;\n headers?: string;\n exposeHeaders?: string;\n maxAge?: number;\n}\n\nexport interface SessionOptions {\n /** idle sessions are closed after this long (default 30 minutes) */\n ttlMs?: number;\n}\n\nexport interface HttpTransportOptions {\n /** `true` for permissive defaults, or explicit values. Off by default. */\n cors?: boolean | CorsOptions;\n /**\n * `true`: each POST is answered with one JSON body — simplest for curl and serverless\n * (default when stateless). `false`: answer with an SSE stream so `ctx.log` / `ctx.progress`\n * notifications and server→client requests reach the client mid-call (default with sessions).\n */\n jsonResponse?: boolean;\n /**\n * `false` (default): stateless — no session ids, safe on serverless. `true` (or options):\n * sessions kept in this process's memory under `Mcp-Session-Id`; needed for sampling,\n * elicitation and the standalone GET stream. Single long-lived process only.\n */\n sessions?: boolean | SessionOptions;\n /** Host header allow-list (DNS-rebinding protection for localhost servers). */\n allowedHosts?: string[];\n allowedOrigins?: string[];\n enableDnsRebindingProtection?: boolean;\n}\n\nexport type HttpHandlerOptions = McpServerOptions & HttpTransportOptions;\nexport type HttpHandler = (request: Request) => Promise<Response>;\n\nconst DEFAULT_CORS: Required<CorsOptions> = {\n origin: \"*\",\n methods: \"GET, POST, DELETE, OPTIONS\",\n headers:\n \"Content-Type, Accept, Authorization, Mcp-Session-Id, Mcp-Protocol-Version, Last-Event-ID, PAYMENT, X-PAYMENT\",\n exposeHeaders:\n \"Mcp-Session-Id, Mcp-Protocol-Version, WWW-Authenticate, X-Payment-Requirements, PAYMENT-REQUIRED\",\n maxAge: 86_400,\n};\n\nconst DEFAULT_SESSION_TTL_MS = 30 * 60_000;\n\nfunction corsHeaders(cors: boolean | CorsOptions | undefined): Record<string, string> {\n if (!cors) return {};\n const c = { ...DEFAULT_CORS, ...(typeof cors === \"object\" ? cors : {}) };\n return {\n \"Access-Control-Allow-Origin\": c.origin,\n \"Access-Control-Allow-Methods\": c.methods,\n \"Access-Control-Allow-Headers\": c.headers,\n \"Access-Control-Expose-Headers\": c.exposeHeaders,\n \"Access-Control-Max-Age\": String(c.maxAge),\n };\n}\n\nfunction jsonResponse(\n body: unknown,\n status: number,\n headers: Record<string, string> = {},\n): Response {\n return new Response(JSON.stringify(body), {\n status,\n headers: { \"Content-Type\": \"application/json\", \"Cache-Control\": \"no-store\", ...headers },\n });\n}\n\nfunction methodNotAllowed(method: string, allow: string, cors: Record<string, string>): Response {\n return jsonResponse(\n {\n code: \"METHOD_NOT_ALLOWED\",\n cause: `${method} is not supported here without a session`,\n fix: \"send JSON-RPC over POST with `Accept: application/json, text/event-stream` (start with `initialize`)\",\n retryable: false,\n },\n 405,\n { Allow: allow, ...cors },\n );\n}\n\nfunction splitOptions(\n opts: HttpHandlerOptions | (() => McpServer),\n transport: HttpTransportOptions,\n): { factory: () => McpServer; transport: HttpTransportOptions } {\n if (typeof opts === \"function\") return { factory: opts, transport };\n const {\n cors,\n jsonResponse,\n sessions,\n allowedHosts,\n allowedOrigins,\n enableDnsRebindingProtection,\n ...server\n } = opts;\n return {\n factory: () => createMcpServer(server),\n transport: {\n cors,\n jsonResponse,\n sessions,\n allowedHosts,\n allowedOrigins,\n enableDnsRebindingProtection,\n ...transport,\n },\n };\n}\n\ninterface TransportBase {\n enableJsonResponse: boolean;\n allowedHosts?: string[];\n allowedOrigins?: string[];\n enableDnsRebindingProtection?: boolean;\n}\n\ninterface HandlerContext {\n factory: () => McpServer;\n cors: Record<string, string>;\n transportBase: TransportBase;\n}\n\nfunction withCors(response: Response, cors: Record<string, string>): Response {\n const keys = Object.keys(cors);\n if (keys.length === 0) return response;\n const headers = new Headers(response.headers);\n for (const key of keys) headers.set(key, cors[key] ?? \"\");\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n}\n\nfunction errorResponse(err: unknown, cors: Record<string, string>): Response {\n const error = normalizeError(err);\n return jsonResponse(error.toJSON(), error.httpStatus, cors);\n}\n\nfunction createStatelessHandler({ factory, cors, transportBase }: HandlerContext): HttpHandler {\n return async (request) => {\n if (request.method !== \"POST\") return methodNotAllowed(request.method, \"POST, OPTIONS\", cors);\n\n const server = factory();\n const transport = new WebStandardStreamableHTTPServerTransport({\n ...transportBase,\n sessionIdGenerator: undefined,\n });\n let closed = false;\n const cleanup = async (): Promise<void> => {\n if (closed) return;\n closed = true;\n try {\n await server.close();\n } catch {\n // already closed\n }\n };\n\n try {\n await server.connect(transport);\n const response = withCors(await transport.handleRequest(request), cors);\n if (!response.body) {\n await cleanup();\n return response;\n }\n // Close server + transport once the body (JSON or SSE stream) has been fully written.\n request.signal?.addEventListener(\"abort\", () => void cleanup(), { once: true });\n const body = response.body.pipeThrough(\n new TransformStream<Uint8Array, Uint8Array>({ flush: () => cleanup() }),\n );\n return new Response(body, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n });\n } catch (err) {\n await cleanup();\n return errorResponse(err, cors);\n }\n };\n}\n\ninterface Session {\n server: McpServer;\n transport: WebStandardStreamableHTTPServerTransport;\n lastSeen: number;\n}\n\nfunction createStatefulHandler(\n { factory, cors, transportBase }: HandlerContext,\n options: SessionOptions,\n): HttpHandler {\n const ttlMs = options.ttlMs ?? DEFAULT_SESSION_TTL_MS;\n const sessions = new Map<string, Session>();\n\n const drop = (id: string): void => {\n const session = sessions.get(id);\n if (!session) return;\n sessions.delete(id);\n session.server.close().catch(() => undefined);\n };\n const sweep = (): void => {\n const now = Date.now();\n for (const [id, session] of sessions) if (now - session.lastSeen > ttlMs) drop(id);\n };\n\n return async (request) => {\n const sessionId = request.headers.get(\"mcp-session-id\");\n if (sessionId) {\n const session = sessions.get(sessionId);\n if (!session) {\n return jsonResponse(\n {\n code: \"NOT_FOUND\",\n cause: \"unknown or expired Mcp-Session-Id\",\n fix: \"send `initialize` again without an Mcp-Session-Id header and use the id from the response\",\n retryable: true,\n },\n 404,\n cors,\n );\n }\n session.lastSeen = Date.now();\n try {\n return withCors(await session.transport.handleRequest(request), cors);\n } catch (err) {\n return errorResponse(err, cors);\n }\n }\n\n if (request.method !== \"POST\") return methodNotAllowed(request.method, \"POST, OPTIONS\", cors);\n sweep();\n\n const server = factory();\n const transport = new WebStandardStreamableHTTPServerTransport({\n ...transportBase,\n sessionIdGenerator: () => crypto.randomUUID(),\n onsessioninitialized: (id) => {\n sessions.set(id, { server, transport, lastSeen: Date.now() });\n },\n onsessionclosed: (id) => {\n sessions.delete(id);\n },\n });\n\n try {\n await server.connect(transport);\n const previousOnClose = transport.onclose;\n transport.onclose = () => {\n previousOnClose?.();\n if (transport.sessionId) sessions.delete(transport.sessionId);\n };\n const response = withCors(await transport.handleRequest(request), cors);\n // Anything but a successful `initialize` leaves no session behind: release the server.\n if (!transport.sessionId) server.close().catch(() => undefined);\n return response;\n } catch (err) {\n server.close().catch(() => undefined);\n return errorResponse(err, cors);\n }\n };\n}\n\n/**\n * Create the request handler. Pass server options, or a factory returning a configured\n * `McpServer` (e.g. one with resources/prompts added) when you need more than tools.\n */\nexport function createHttpHandler(\n opts: HttpHandlerOptions | (() => McpServer),\n transportOptions: HttpTransportOptions = {},\n): HttpHandler {\n const { factory, transport: t } = splitOptions(opts, transportOptions);\n const cors = corsHeaders(t.cors);\n const sessions = t.sessions ? (typeof t.sessions === \"object\" ? t.sessions : {}) : undefined;\n const context: HandlerContext = {\n factory,\n cors,\n transportBase: {\n enableJsonResponse: t.jsonResponse ?? sessions === undefined,\n allowedHosts: t.allowedHosts,\n allowedOrigins: t.allowedOrigins,\n enableDnsRebindingProtection: t.enableDnsRebindingProtection,\n },\n };\n const handler = sessions\n ? createStatefulHandler(context, sessions)\n : createStatelessHandler(context);\n const allow = sessions ? \"GET, POST, DELETE, OPTIONS\" : \"POST, OPTIONS\";\n\n return async (request: Request): Promise<Response> => {\n if (request.method === \"OPTIONS\") {\n return new Response(null, { status: 204, headers: { Allow: allow, ...cors } });\n }\n return handler(request);\n };\n}\n\n/** Host header values a localhost server should accept (for `allowedHosts`). */\nexport function localhostHosts(port: number): string[] {\n const hosts = [\"localhost\", \"127.0.0.1\", \"[::1]\"];\n return [...hosts, ...hosts.map((h) => `${h}:${port}`)];\n}\n\nexport interface HealthInfo {\n name: string;\n version: string;\n /** tool count or the tool list */\n tools: number | readonly unknown[];\n}\n\n/** `GET /health` → `{ ok: true, name, version, tools }`. */\nexport function handleHealth(info: HealthInfo): Response {\n const tools = typeof info.tools === \"number\" ? info.tools : info.tools.length;\n return jsonResponse({ ok: true, name: info.name, version: info.version, tools }, 200);\n}\n","/**\n * Bridge a Web-standard `(Request) => Promise<Response>` handler onto `node:http` — for local\n * runs, tests and the conformance suite. Node-only; loaded lazily.\n */\nimport type { HttpHandler } from \"./http.js\";\n\nexport interface NodeHttpOptions {\n handler: HttpHandler;\n /** 0 picks a free port (default 8765) */\n port?: number;\n /** default 127.0.0.1 */\n host?: string;\n /** MCP endpoint path (default `/mcp`) */\n path?: string;\n /** optional `GET /health` responder */\n health?: () => Response;\n}\n\nexport interface NodeHttpServer {\n port: number;\n /** MCP endpoint URL, e.g. `http://127.0.0.1:8765/mcp` */\n url: string;\n close(): Promise<void>;\n}\n\n/** Start a `node:http` server that forwards `path` to the handler. */\nexport async function serveNodeHttp(opts: NodeHttpOptions): Promise<NodeHttpServer> {\n const http = await import(\"node:http\");\n const host = opts.host ?? \"127.0.0.1\";\n const path = opts.path ?? \"/mcp\";\n\n const server = http.createServer((req, res) => {\n void (async () => {\n const url = new URL(req.url ?? \"/\", `http://${req.headers.host ?? host}`);\n let response: Response;\n if (url.pathname === path) {\n const controller = new AbortController();\n res.on(\"close\", () => {\n if (!res.writableFinished) controller.abort();\n });\n const headers = new Headers();\n for (const [key, value] of Object.entries(req.headers)) {\n if (Array.isArray(value)) for (const item of value) headers.append(key, item);\n else if (typeof value === \"string\") headers.set(key, value);\n }\n const method = req.method ?? \"GET\";\n let body: Uint8Array<ArrayBuffer> | undefined;\n if (method !== \"GET\" && method !== \"HEAD\") {\n const chunks: Buffer[] = [];\n for await (const chunk of req) chunks.push(chunk as Buffer);\n body = new Uint8Array(Buffer.concat(chunks));\n }\n response = await opts.handler(\n new Request(url, { method, headers, body, signal: controller.signal }),\n );\n } else if (url.pathname === \"/health\" && opts.health) {\n response = opts.health();\n } else {\n response = new Response(\n JSON.stringify({\n code: \"NOT_FOUND\",\n cause: `no route for ${url.pathname}`,\n fix: `POST JSON-RPC to ${path}`,\n retryable: false,\n }),\n { status: 404, headers: { \"Content-Type\": \"application/json\" } },\n );\n }\n\n const outHeaders: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n outHeaders[key] = value;\n });\n res.writeHead(response.status, outHeaders);\n if (!response.body) {\n res.end();\n return;\n }\n const reader = response.body.getReader();\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n res.write(value);\n }\n } catch {\n // client went away mid-stream\n }\n res.end();\n })().catch((err: unknown) => {\n if (!res.headersSent) res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n code: \"INTERNAL\",\n cause: err instanceof Error ? err.message : String(err),\n fix: \"retry; if it persists, report the request id\",\n retryable: false,\n }),\n );\n });\n });\n\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject);\n server.listen(opts.port ?? 8765, host, () => resolve());\n });\n const address = server.address();\n const port = typeof address === \"object\" && address ? address.port : (opts.port ?? 8765);\n return {\n port,\n url: `http://${host}:${port}${path}`,\n close: () =>\n new Promise<void>((resolve, reject) => {\n server.closeAllConnections();\n server.close((err) => (err ? reject(err) : resolve()));\n }),\n };\n}\n","/**\n * x402 verification and settlement through a facilitator.\n *\n * The facilitator is the only piece we do not run: it checks the buyer's signature and\n * submits the on-chain transfer. It never holds the money — USDC moves from the buyer\n * straight to `payTo`, an address we control — so this is not custody, and swapping\n * facilitators is changing one URL.\n *\n * PayAI (https://facilitator.payai.network) is the default because it needs no account,\n * no API key and no business relationship, which is the property that matters: an\n * account is a dependency that can be closed. Coinbase's CDP facilitator implements the\n * same two endpoints and can be dropped in by setting X402_FACILITATOR_URL.\n *\n * Verification is free and moves nothing. Settlement moves money, so it is deliberately\n * a separate call the caller makes only after the work succeeded — a failed call is then\n * never charged at all, which is better than charging and refunding.\n */\nimport type { PaymentRail, PaymentRequirement, PaymentVerifier, VerifyResult } from \"./index.js\";\n\nexport const PAYAI_FACILITATOR_URL = \"https://facilitator.payai.network\";\n\n/** Circle's native USDC on Base mainnet. */\nexport const USDC_BASE = \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\";\n\n/** USDC is a 6-decimal token everywhere it is issued. */\nexport const USDC_DECIMALS = 6;\n\n/**\n * The EIP-712 domain of the asset being signed over. The facilitator needs it to reconstruct\n * the buyer's signature; without it, verification fails with\n * `invalid_exact_evm_missing_eip712_domain` and no payment can ever succeed.\n */\nexport const USDC_EIP712_DOMAIN = { name: \"USD Coin\", version: \"2\" };\n\n/**\n * CAIP-2 to the short network names the **v1** verify/settle envelope uses.\n *\n * Only the v1 path needs this. v2 carries CAIP-2 end to end, which is one of the reasons to\n * prefer it: no translation layer between what the 402 advertises and what the facilitator\n * is told.\n */\nconst SHORT_NETWORK: Record<string, string> = {\n \"eip155:8453\": \"base\",\n \"eip155:84532\": \"base-sepolia\",\n \"eip155:137\": \"polygon\",\n \"eip155:80002\": \"polygon-amoy\",\n \"eip155:42161\": \"arbitrum\",\n \"eip155:43114\": \"avalanche\",\n};\n\nexport function toShortNetwork(network: string): string {\n return SHORT_NETWORK[network] ?? network;\n}\n\n/**\n * The x402 `bazaar` extension — how a resource gets into a discovery catalog.\n *\n * There is no registration endpoint (the facilitator's OpenAPI description has only GETs\n * under /discovery). Settling a payment is necessary but **not** sufficient: the catalog is\n * built from this extension, which the resource server declares and the facilitator either\n * accepts or rejects. Without it a resource can be paid for indefinitely and never appear.\n *\n * The facilitator answers in an `EXTENSION-RESPONSES` header — base64 JSON keyed by\n * extension name, `{ bazaar: { status: \"success\" | \"processing\" | \"rejected\", … } }`. That\n * is the only direct feedback there is, so it is surfaced rather than discarded.\n */\nexport interface BazaarExtension {\n info: {\n input: Record<string, unknown>;\n output?: Record<string, unknown>;\n };\n /** JSON Schema (draft 2020-12) that validates `info`. Required by the extension. */\n schema: Record<string, unknown>;\n /** canonical route pattern for a parameterised path, e.g. `/v1/reserves/:symbol` */\n routeTemplate?: string;\n}\n\nexport interface BazaarStatus {\n status?: \"success\" | \"processing\" | \"rejected\";\n rejectedReason?: string;\n}\n\n/**\n * A `bazaar` extension for a plain GET endpoint that answers JSON.\n *\n * The schema is deliberately permissive: its job is to be a valid draft 2020-12 document\n * that `info` satisfies, not to constrain a shape only we produce.\n */\nexport function httpGetBazaar(options: {\n queryParams?: Record<string, string>;\n pathParams?: Record<string, string>;\n routeTemplate?: string;\n outputExample?: unknown;\n}): BazaarExtension {\n return {\n info: {\n input: {\n type: \"http\",\n method: \"GET\",\n ...(options.queryParams ? { queryParams: options.queryParams } : {}),\n ...(options.pathParams ? { pathParams: options.pathParams } : {}),\n },\n ...(options.outputExample !== undefined\n ? { output: { type: \"json\", example: options.outputExample } }\n : {}),\n },\n schema: {\n $schema: \"https://json-schema.org/draft/2020-12/schema\",\n type: \"object\",\n required: [\"input\"],\n properties: {\n input: { type: \"object\", required: [\"type\"], properties: { type: { type: \"string\" } } },\n output: { type: \"object\" },\n },\n },\n ...(options.routeTemplate ? { routeTemplate: options.routeTemplate } : {}),\n };\n}\n\nexport interface FacilitatorVerifierOptions {\n /** the address USDC is paid to — ours, self-custody */\n payTo: string;\n /** CAIP-2 chain, e.g. eip155:8453 */\n network: string;\n /** token contract; defaults to native USDC on Base */\n asset?: string;\n /** defaults to PayAI */\n facilitatorUrl?: string;\n /** optional bearer token; PayAI works without one, some facilitators require it */\n apiKey?: string;\n /** EIP-712 domain of the asset; defaults to USDC's. Required by the facilitator. */\n assetDomain?: { name: string; version: string };\n /**\n * Decimals of that asset. Defaults to USDC's six.\n *\n * Set it whenever `asset` is set. The price is signed in atomic units, so the wrong decimals\n * do not fail loudly — they authorise a transfer for the wrong amount, off by a factor of a\n * thousand or a million in whichever direction hurts.\n */\n assetDecimals?: number;\n /**\n * Envelope to speak to the facilitator. Defaults to 2.\n *\n * Both settle money identically — the buyer's signature is the same either way — but only\n * v2 settlements appear in the Bazaar discovery catalog, so v1 is a rail that works and\n * cannot be found. Set it to 1 only for a facilitator that rejects v2.\n */\n protocolVersion?: 1 | 2;\n /**\n * Discovery metadata for this resource. Without it the resource is payable but not\n * listable — see BazaarExtension. Ignored on the v1 path, which has no extensions.\n */\n bazaar?: BazaarExtension;\n fetchImpl?: typeof fetch;\n log?: (message: string, data?: Record<string, unknown>) => void;\n}\n\nexport interface SettleResult {\n ok: boolean;\n /** on-chain transaction hash when the transfer landed */\n transaction?: string;\n payer?: string;\n reason?: string;\n /** whether the facilitator catalogued the resource, when it said so */\n bazaar?: BazaarStatus;\n}\n\n/** What the buyer base64s into the X-PAYMENT header; forwarded to the facilitator verbatim. */\ninterface PaymentPayload {\n x402Version?: number;\n scheme?: string;\n network?: string;\n payload?: unknown;\n /** the client's echo of the server's extensions; its presence is what enables them */\n extensions?: Record<string, unknown>;\n}\n\ninterface VerifyResponse {\n isValid?: boolean;\n invalidReason?: string;\n invalidMessage?: string;\n payer?: string;\n}\n\ninterface SettleResponse {\n success?: boolean;\n errorReason?: string;\n errorMessage?: string;\n transaction?: string;\n network?: string;\n payer?: string;\n}\n\n/**\n * Decimal USD string to the token's atomic units.\n *\n * Done on the string rather than via floating point: 0.07 * 1e6 is 70000.00000000001, and\n * a price that rounds wrong is a payment the facilitator rejects for the wrong amount.\n */\nexport function toAtomicUnits(amountUsd: string, decimals = USDC_DECIMALS): string {\n const trimmed = amountUsd.trim();\n if (!/^\\d+(\\.\\d+)?$/.test(trimmed)) throw new Error(`not a decimal amount: ${amountUsd}`);\n const [whole = \"0\", fraction = \"\"] = trimmed.split(\".\");\n if (fraction.length > decimals) {\n throw new Error(`${amountUsd} has more than ${decimals} decimal places`);\n }\n return `${whole}${fraction.padEnd(decimals, \"0\")}`.replace(/^0+(?=\\d)/, \"\");\n}\n\n/** The buyer's payment, or undefined when the request carries none. */\nfunction readPaymentHeader(request: Request): PaymentPayload | undefined {\n const raw = request.headers.get(\"X-PAYMENT\") ?? request.headers.get(\"PAYMENT\");\n if (!raw) return undefined;\n try {\n // base64 JSON per the spec; tolerate a bare JSON body from a hand-rolled client\n const text = raw.trim().startsWith(\"{\") ? raw : new TextDecoder().decode(base64ToBytes(raw));\n return JSON.parse(text) as PaymentPayload;\n } catch {\n return undefined;\n }\n}\n\nfunction base64ToBytes(b64: string): Uint8Array {\n const binary = atob(b64.trim());\n const out = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i += 1) out[i] = binary.charCodeAt(i);\n return out;\n}\n\nexport interface FacilitatorVerifier extends PaymentVerifier {\n settle(verified: VerifyResult): Promise<SettleResult>;\n}\n\nexport function createFacilitatorVerifier(\n options: FacilitatorVerifierOptions,\n): FacilitatorVerifier {\n const base = (options.facilitatorUrl ?? PAYAI_FACILITATOR_URL).replace(/\\/+$/, \"\");\n const asset = options.asset ?? USDC_BASE;\n const doFetch = options.fetchImpl ?? fetch;\n const log = options.log ?? (() => undefined);\n const version = options.protocolVersion ?? 2;\n\n function requirementsFor(requirement: PaymentRequirement): Record<string, unknown> {\n // Without `extra` the facilitator cannot rebuild the signature and refuses every payment\n // with invalid_exact_evm_missing_eip712_domain.\n const extra = options.assetDomain ?? USDC_EIP712_DOMAIN;\n const amount = toAtomicUnits(requirement.amountUsd, options.assetDecimals);\n const maxTimeoutSeconds = requirement.maxTimeoutSeconds ?? 300;\n\n if (version === 2) {\n // v2 renamed maxAmountRequired to amount and carries CAIP-2 networks unchanged.\n //\n // `resource` is not in the v2 schema and the facilitator does not require it, but it is\n // the only thing that ties a settlement to a URL — a discovery catalog of resources\n // cannot list a payment that names no resource. It is accepted, so send it.\n return {\n scheme: \"exact\",\n network: options.network,\n amount,\n asset,\n payTo: options.payTo,\n maxTimeoutSeconds,\n resource: requirement.resource,\n description: requirement.description ?? \"\",\n mimeType: \"application/json\",\n extra,\n };\n }\n return {\n scheme: \"exact\",\n network: toShortNetwork(options.network),\n maxAmountRequired: amount,\n resource: requirement.resource,\n description: requirement.description ?? \"\",\n mimeType: \"application/json\",\n payTo: options.payTo,\n maxTimeoutSeconds,\n asset,\n extra,\n };\n }\n\n /**\n * The buyer's payload, restated in the envelope the facilitator accepts.\n *\n * v2 nests the terms the buyer agreed to as `accepted` *inside* the payload — that nesting\n * is the whole difference, and getting it wrong returns `invalid_payment_requirements:\n * \": Invalid input\"`, which names no field. v1 instead flattens scheme and network next to\n * the payload.\n */\n function payloadFor(\n payment: PaymentPayload,\n accepted: Record<string, unknown>,\n ): Record<string, unknown> {\n if (version === 2) {\n return {\n x402Version: 2,\n // Not required alongside `accepted`, but the facilitator's own OpenAPI description\n // lists scheme and network as required on a payment payload, and the discovery\n // catalog records a network per resource. Sending them costs nothing.\n scheme: payment.scheme ?? \"exact\",\n network: options.network,\n // A payload-level `resource` OBJECT — a string here is rejected. Every catalogued\n // entry carries url, type, method, description and mimeType, which is exactly this\n // shape, so this is the most likely thing the catalog is built from.\n resource: {\n url: accepted[\"resource\"],\n type: \"http\",\n method: \"GET\",\n description: accepted[\"description\"],\n mimeType: accepted[\"mimeType\"],\n },\n accepted,\n payload: payment.payload,\n // the client's echo, verbatim: the facilitator compares it against serverExtensions\n ...(payment.extensions ? { extensions: payment.extensions } : {}),\n };\n }\n return {\n x402Version: 1,\n scheme: payment.scheme ?? \"exact\",\n network: toShortNetwork(payment.network ?? options.network),\n payload: payment.payload,\n };\n }\n\n /**\n * v2 only: extensions the resource server declares.\n *\n * Sent **only when the client echoed one back**. Declaring an extension the client did not\n * echo is refused outright — `403 Extension validation failed: client must echo server\n * extensions` — so sending it unconditionally would turn every payment from an older client\n * into a refusal. Discovery is worth having; it is not worth failing a sale for.\n */\n function serverExtensions(payment: PaymentPayload, declared: unknown): Record<string, unknown> {\n const bazaar = declared ?? options.bazaar;\n if (version !== 2 || !bazaar) return {};\n if (!payment.extensions?.[\"bazaar\"]) return {};\n return { serverExtensions: { bazaar } };\n }\n\n type Call<T> =\n { reached: true; body: T; bazaar?: BazaarStatus } | { reached: false; error: string };\n\n /** `EXTENSION-RESPONSES`: base64 JSON keyed by extension name. Absent on the v1 path. */\n function readBazaarStatus(headers: Headers): BazaarStatus | undefined {\n const raw = headers.get(\"extension-responses\");\n if (!raw) return undefined;\n try {\n const text = new TextDecoder().decode(base64ToBytes(raw));\n return (JSON.parse(text) as Record<string, BazaarStatus>)[\"bazaar\"];\n } catch {\n return undefined;\n }\n }\n\n async function call<T>(path: string, body: unknown): Promise<Call<T>> {\n try {\n const res = await doFetch(`${base}${path}`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n ...(options.apiKey ? { authorization: `Bearer ${options.apiKey}` } : {}),\n },\n body: JSON.stringify(body),\n });\n // Check the status before the body. A facilitator answering 500 or 403 can still return\n // JSON carrying `isValid` or `success`, and reading it regardless means an error page\n // decides whether we were paid. This rail must fail closed.\n if (!res.ok && res.status >= 500) {\n return { reached: false, error: `facilitator returned HTTP ${res.status}` };\n }\n const bazaar = readBazaarStatus(res.headers);\n // A rejected declaration is silent otherwise: payments keep working and the resource\n // simply never appears in the catalog, which is the failure that took longest to see.\n if (bazaar?.status === \"rejected\") {\n log(\"x402 bazaar listing rejected\", { reason: bazaar.rejectedReason });\n }\n return { reached: true, body: (await res.json()) as T, ...(bazaar ? { bazaar } : {}) };\n } catch (err) {\n return { reached: false, error: err instanceof Error ? err.message : String(err) };\n }\n }\n\n return {\n /**\n * Checks the buyer's signature. Free, and moves nothing — call `settle` once the work\n * has actually succeeded.\n */\n async verify(request: Request, requirement: PaymentRequirement): Promise<VerifyResult> {\n const payment = readPaymentHeader(request);\n if (!payment) {\n return { ok: false, rail: \"x402\", reason: \"no payment header present\" };\n }\n const paymentRequirements = requirementsFor(requirement);\n const call1 = await call<VerifyResponse>(\"/verify\", {\n x402Version: version,\n paymentPayload: payloadFor(payment, paymentRequirements),\n // v2 keeps this alongside the payload as well as inside it. PayAI rejects the body\n // outright without it, so it is not the redundancy it looks like.\n paymentRequirements,\n ...serverExtensions(payment, requirement.bazaar),\n });\n if (!call1.reached) {\n // Fail closed: an unreachable facilitator must never be read as a valid payment.\n log(\"x402 facilitator unreachable\", { error: call1.error });\n return { ok: false, rail: \"x402\", reason: \"payment facilitator unreachable\" };\n }\n const verified = call1.body;\n if (!verified.isValid) {\n return {\n ok: false,\n rail: \"x402\",\n reason: verified.invalidReason\n ? `${verified.invalidReason}${verified.invalidMessage ? `: ${verified.invalidMessage}` : \"\"}`\n : \"payment refused by the facilitator\",\n };\n }\n return {\n ok: true,\n rail: \"x402\",\n // everything settle() needs, so it does not have to re-read the request\n receipt: {\n payment,\n paymentRequirements,\n payer: verified.payer,\n // settle() never sees the requirement again, so carry the declaration with it\n ...(requirement.bazaar ? { bazaar: requirement.bazaar } : {}),\n },\n };\n },\n\n /** Submits the transfer. Only call this once the paid work has succeeded. */\n async settle(verified: VerifyResult): Promise<SettleResult> {\n const receipt = verified.receipt as\n | {\n payment: PaymentPayload;\n paymentRequirements: Record<string, unknown>;\n bazaar?: unknown;\n }\n | undefined;\n if (!receipt?.payment) return { ok: false, reason: \"nothing to settle\" };\n const call2 = await call<SettleResponse>(\"/settle\", {\n x402Version: version,\n paymentPayload: payloadFor(receipt.payment, receipt.paymentRequirements),\n paymentRequirements: receipt.paymentRequirements,\n ...serverExtensions(receipt.payment, receipt.bazaar),\n });\n if (!call2.reached) {\n log(\"x402 settlement failed to reach the facilitator\", { error: call2.error });\n return { ok: false, reason: call2.error };\n }\n const result = call2.body;\n if (!result.success) {\n // The buyer already has the resource. Worth logging loudly: it is lost revenue,\n // not a failed request, and the caller should not turn it into an error.\n log(\"x402 settlement refused after the work was served\", {\n reason: result.errorReason,\n message: result.errorMessage,\n });\n return {\n ok: false,\n reason: result.errorReason ?? \"settlement refused\",\n ...(result.payer ? { payer: result.payer } : {}),\n };\n }\n if (call2.bazaar) log(\"x402 bazaar listing\", { ...call2.bazaar });\n // A settlement we cannot name cannot be made idempotent: the caller keys the credit on\n // this hash, and without one it would invent a fresh key per attempt and credit the same\n // authorisation again on every retry. Treat it as unsettled rather than as money.\n if (!result.transaction) {\n log(\"x402 settlement reported success with no transaction\", { payer: result.payer });\n return {\n ok: false,\n reason:\n \"the facilitator reported success but named no transaction, so the payment cannot be confirmed\",\n ...(result.payer ? { payer: result.payer } : {}),\n };\n }\n return {\n ok: true,\n transaction: result.transaction,\n ...(result.payer ? { payer: result.payer } : {}),\n ...(call2.bazaar ? { bazaar: call2.bazaar } : {}),\n };\n },\n };\n}\n\n/**\n * One verifier over several rails: try each in turn, first acceptance wins.\n *\n * A caller presents whatever it has — a USDC payment header or a prepaid key — and should\n * not have to be told which rail the server prefers. Refusals are reported from the rail\n * that got furthest: \"insufficient credit\" is useful, \"no payment header present\" from a\n * rail the caller never intended to use is noise.\n *\n * `settle` dispatches on the rail that accepted, so a rail that already took its money\n * during verification is never asked to take it twice.\n */\nexport function createAnyVerifier(verifiers: readonly PaymentVerifier[]): PaymentVerifier {\n return {\n async verify(request: Request, requirement: PaymentRequirement): Promise<VerifyResult> {\n const refusals: VerifyResult[] = [];\n for (const verifier of verifiers) {\n const result = await verifier.verify(request, requirement);\n if (result.ok) return result;\n refusals.push(result);\n }\n const informative = refusals.find(\n (r) => r.reason && !/no payment header|no API key/i.test(r.reason),\n );\n return informative ?? refusals[0] ?? { ok: false, reason: \"no payment presented\" };\n },\n async settle(verified: VerifyResult) {\n const owner = verifiers.find(\n (v) => v.settle && verified.rail !== undefined && railOf(v) === verified.rail,\n );\n const settled = await owner?.settle?.(verified);\n if (settled) return settled;\n // No verifier owns this rail's settlement. That is correct for a rail which already took\n // its money during verification (prepaid credits), and a bug for anything else — so say\n // which, rather than reporting a success nobody performed.\n if (verified.rail === \"prepaid_credits\") return { ok: true };\n return {\n ok: false,\n reason: `nothing settles the ${verified.rail ?? \"unknown\"} rail on this deployment`,\n };\n },\n };\n}\n\n/** Which rail a verifier settles. Only the facilitator verifier settles anything today. */\nfunction railOf(verifier: PaymentVerifier): PaymentRail | undefined {\n return \"settle\" in verifier && typeof verifier.settle === \"function\" ? \"x402\" : undefined;\n}\n","/**\n * @agentwares/x402 — 402 Payment Required helper + verifier interface.\n *\n * The 402 body advertises both rails. Both settle; only one of them settles without a person:\n *\n * - **prepaid_credits (card, via Stripe)** — live. `payTo` is a self-serve endpoint that mints a\n * prepaid key and hands back a Stripe Checkout URL, so an agent can go from a 402 to\n * a paid call without a human. The verifier lives in `@agentwares/billing`\n * (`createCreditsVerifier`), which is where the database and the Stripe client are.\n * - **x402 (USDC on Base)** — live, and the only rail an unattended agent can complete.\n * `createFacilitatorVerifier` checks the buyer's EIP-3009 signature with the PayAI\n * facilitator and settles after the work succeeds. `StubVerifier` remains for a\n * deployment with no receiving address, where it refuses rather than pretending.\n *\n * Nothing here holds funds.\n */\n\n/**\n * `prepaid_credits` is deliberately not called `mpp`. MPP is the Machine Payments Protocol\n * (Stripe + Tempo, March 2026): pre-authorised spending sessions an agent settles on its own.\n * This rail is a Stripe Checkout page that funds a balance — a different thing, needing a\n * person. An agent that knows MPP and sees `mpp` will attempt MPP semantics and fail, so the\n * name stays free for a real implementation.\n */\nimport { USDC_BASE, USDC_EIP712_DOMAIN, toAtomicUnits } from \"./facilitator.js\";\n\nexport type PaymentRail = \"x402\" | \"prepaid_credits\";\n\nexport interface PaymentRequirement {\n rail: PaymentRail;\n /** decimal USD string, e.g. \"0.05\" */\n amountUsd: string;\n /** resource being paid for, usually the request URL or tool name */\n resource: string;\n description?: string;\n /** x402: network + asset; mpp: currency */\n network?: string;\n /**\n * x402: the token's **contract address**, not its symbol.\n *\n * It used to be the string \"USDC\", which no client can act on — a buyer needs the address to\n * build the EIP-3009 signature. Every catalogued resource in the Bazaar carries an address\n * here; ours carried a ticker, and that alone made our 402s unpayable by anything but our\n * own script.\n */\n asset?: string;\n currency?: string;\n /**\n * x402: the settlement scheme. `exact` is the only one defined today, and a client that\n * does not see it cannot tell which signature to produce.\n */\n scheme?: string;\n /** x402: the price in the token's atomic units, which is what gets signed. */\n amount?: string;\n /**\n * x402: the EIP-712 domain of the asset. Without it a buyer cannot build the typed data and\n * the facilitator rejects the payment with `invalid_exact_evm_missing_eip712_domain`.\n */\n extra?: Record<string, unknown>;\n /** x402: the media type of what payment buys. */\n mimeType?: string;\n /** where to pay; absent while payments are not live */\n payTo?: string;\n /** seconds the quote is valid */\n maxTimeoutSeconds?: number;\n /**\n * True when settling this rail needs a person — today, a hosted Stripe Checkout card form.\n * An autonomous caller should pick a requirement without this flag; one that has it is\n * offered so an agent working alongside a human can hand the URL over rather than fail.\n */\n humanRequired?: boolean;\n /**\n * Discovery metadata for the x402 `bazaar` extension, when this resource declares one.\n * Carried per requirement rather than per verifier so a product with several priced routes\n * can describe each one; see BazaarExtension in ./facilitator.ts.\n */\n bazaar?: Record<string, unknown>;\n}\n\n/** Everything an agent needs to buy a key and fund it without a human. */\nexport interface SelfServe {\n /** POST here with no auth to get a key with a zero balance + a Checkout URL. */\n keysUrl: string;\n /** GET with the key to read the balance; POST to create another top-up. */\n creditsUrl?: string;\n /**\n * POST here with the key to fund it in USDC over x402 — the only top-up an unattended\n * agent can finish. `creditsUrl` ends at a hosted card page.\n */\n creditsX402Url?: string;\n /** credit pack sizes in USD */\n packsUsd: number[];\n /** header that makes a retried paid call charge only once */\n idempotencyHeader: \"Idempotency-Key\";\n}\n\nexport interface PaymentRequiredBody {\n code: \"PAYMENT_REQUIRED\";\n cause: string;\n fix: string;\n retryable: true;\n priceUsd: number;\n accepts: PaymentRequirement[];\n /** true while neither rail can actually be settled */\n comingSoon: boolean;\n /** how to pay today: API key + prepaid credits */\n alternatives: string[];\n /** present once the card rail is live: the whole no-human purchase path */\n selfServe?: SelfServe;\n /**\n * x402 v2 extensions. `bazaar` is discovery metadata a client is expected to echo back in\n * its payment payload; without that echo the facilitator will not catalog the resource, so\n * a resource that omits this is payable but permanently unlistable.\n */\n extensions?: Record<string, unknown>;\n}\n\nexport interface PaymentRequiredResponse {\n status: 402;\n headers: Record<string, string>;\n body: PaymentRequiredBody;\n}\n\nexport interface BuildPaymentRequiredOptions {\n resource: string;\n priceUsd: number;\n description?: string;\n /** set once a rail can actually be settled (drops `comingSoon`) */\n live?: boolean;\n /** x402 rail: the USDC address payment is sent to. Unset = the rail is not advertised. */\n payTo?: string;\n /** CAIP-2 chain for the x402 rail; Base mainnet unless the receive address lives elsewhere. */\n network?: string;\n /** x402 token contract address. Defaults to USDC on Base; set it when the chain differs. */\n asset?: string;\n /** EIP-712 domain of that token. Must match the asset or the facilitator rejects the payment. */\n assetDomain?: Record<string, unknown>;\n /**\n * Decimals of that token. Defaults to USDC's six.\n *\n * Set it whenever `asset` is set, and set the same value on the verifier. The price is signed\n * in atomic units, so the wrong decimals do not fail loudly — the 402 quotes an amount off by\n * a factor of a thousand or a million, and a buyer signs for exactly that.\n */\n assetDecimals?: number;\n /** prepaid_credits rail: the URL that takes a card and funds a balance. */\n creditsPayTo?: string;\n signupUrl?: string;\n /** the no-human purchase path; included in the body when the card rail is live */\n selfServe?: SelfServe;\n /**\n * Discovery metadata for the x402 `bazaar` extension. Advertised in the 402 so a client\n * can echo it; see BazaarExtension in ./facilitator.ts for why that echo is the whole\n * mechanism.\n */\n bazaar?: Record<string, unknown>;\n /**\n * True when this resource really does answer `sample=true` free and keyless.\n *\n * The 402's `fix` prose used to promise one unconditionally, which was a lie on every\n * product without sample mode and absurd on a credit top-up. An agent that believes it\n * spends a call finding out.\n */\n sampleMode?: boolean;\n}\n\n/** Base mainnet. The CDP facilitator also settles Polygon, Arbitrum, World and Solana. */\nexport const DEFAULT_X402_NETWORK = \"eip155:8453\";\n\nexport const X402_HEADER = \"X-Payment-Requirements\";\nexport const X402_REQUIRED_HEADER = \"PAYMENT-REQUIRED\";\n\nfunction toAmount(priceUsd: number): string {\n if (!Number.isFinite(priceUsd) || priceUsd < 0)\n throw new Error(\"priceUsd must be a non-negative number\");\n return priceUsd.toFixed(6).replace(/0+$/, \"\").replace(/\\.$/, \".0\");\n}\n\n/** Build the 402 response (status, headers, JSON body) for a paid resource. */\nexport function buildPaymentRequired(opts: BuildPaymentRequiredOptions): PaymentRequiredResponse {\n const amountUsd = toAmount(opts.priceUsd);\n // `accepts` is a promise that the rail can be settled, so a rail with nowhere to send the\n // money is left out entirely. The x402 entry used to be advertised with `payTo: undefined`\n // while no CDP account existed: an agent that picked it had no address to pay and burned a\n // retry on a method we could never have honoured.\n const creditsPayTo = opts.creditsPayTo ?? opts.selfServe?.keysUrl;\n const accepts: PaymentRequirement[] = [];\n if (opts.payTo) {\n // The fields a standard x402 client needs to construct a payment, in the shape every\n // catalogued resource in the Bazaar actually serves: `scheme`, the price in atomic units,\n // the token's contract address and its EIP-712 domain.\n //\n // These were missing. The entry carried `amountUsd: \"0.02\"` and `asset: \"USDC\"`, which is\n // readable by a person and unusable by a buyer: no scheme to pick, no atomic amount to\n // sign, and a ticker where the signature needs an address. Our own bootstrap script filled\n // the gaps from local knowledge, which is why payments settled in testing and never once\n // from outside. `rail` and `amountUsd` stay because they are useful and harmless.\n accepts.push({\n rail: \"x402\",\n scheme: \"exact\",\n amountUsd,\n amount: toAtomicUnits(amountUsd, opts.assetDecimals),\n resource: opts.resource,\n description: opts.description,\n mimeType: \"application/json\",\n network: opts.network ?? DEFAULT_X402_NETWORK,\n asset: opts.asset ?? USDC_BASE,\n extra: opts.assetDomain ?? USDC_EIP712_DOMAIN,\n payTo: opts.payTo,\n maxTimeoutSeconds: 300,\n ...(opts.bazaar ? { bazaar: opts.bazaar } : {}),\n });\n }\n if (creditsPayTo) {\n accepts.push({\n rail: \"prepaid_credits\",\n amountUsd,\n resource: opts.resource,\n description: opts.description,\n currency: \"usd\",\n payTo: creditsPayTo,\n maxTimeoutSeconds: 300,\n // funding a balance ends at a hosted Stripe Checkout page, which an agent cannot fill in\n humanRequired: true,\n });\n }\n const live = opts.live === true;\n const selfServe = opts.selfServe;\n // Say plainly which step a machine can do and which one it cannot. An agent that reads\n // \"pay the card form\" as an instruction to itself will loop: the Checkout URL is a hosted\n // web page.\n //\n // Order matters more than it looks. Many agents act on `fix` prose rather than parsing\n // `accepts`, so whatever is named first is what gets attempted. This text used to describe\n // only the card rail — the one that needs a person — while the USDC rail settled fine and\n // went unmentioned, which told every unattended caller to give up in front of a working\n // checkout. Lead with the rail that needs nobody.\n const x402Rail = accepts.find((a) => a.rail === \"x402\" && a.payTo);\n const usdcFix = x402Rail\n ? `Pay in USDC with no account and no human: take the \\`accepts\\` entry with ` +\n `\\`rail: \"x402\"\\`, sign an EIP-3009 transferWithAuthorization for ${x402Rail.amountUsd} ` +\n `USDC to ${x402Rail.payTo} on ${x402Rail.network}, and retry with it base64 in the ` +\n `X-PAYMENT header. The facilitator submits the transfer, so you need USDC and no gas. `\n : \"\";\n // Only when there is one. This was unconditional, so every 402 in the portfolio promised a\n // free sample — including products that have none, and including the credit top-up endpoint,\n // where it read as an offer of free credit.\n const sampleFix = opts.sampleMode\n ? \"Free first: retry with sample=true — no key, no payment. \"\n : \"\";\n const cardFix = selfServe\n ? `Or pay by card: POST ${selfServe.keysUrl} (no auth, no signup) returns a key and a Stripe ` +\n `Checkout URL. Funding that key needs a person at a browser; if you are running unattended, ` +\n `surface the URL to your operator rather than retrying, or use the USDC rail above. Once ` +\n `funded, send Authorization: Bearer <key>, plus Idempotency-Key so a repeated call is ` +\n `charged once.`\n : \"\";\n const liveFix =\n usdcFix || cardFix\n ? `${sampleFix}${usdcFix}${cardFix}`.trim()\n : \"Retry with a PAYMENT header satisfying one of `accepts`, or send an API key with credit balance.\";\n const body: PaymentRequiredBody = {\n code: \"PAYMENT_REQUIRED\",\n cause: live\n ? `This call costs $${amountUsd}. No valid payment or credit was presented.`\n : `This call costs $${amountUsd}. Pay-per-call (x402 / Stripe MPP) is coming soon; use an API key with prepaid credits.`,\n fix: live\n ? liveFix\n : `Create an API key${opts.signupUrl ? ` at ${opts.signupUrl}` : \"\"} and retry with Authorization: Bearer <key>. Try the free sample mode first.`,\n retryable: true,\n priceUsd: opts.priceUsd,\n accepts,\n comingSoon: !live,\n alternatives: [\n ...(creditsPayTo ? [\"api_key_credits\"] : []),\n ...(opts.sampleMode ? [\"sample_mode\"] : []),\n ],\n ...(selfServe ? { selfServe } : {}),\n ...(opts.bazaar ? { extensions: { bazaar: opts.bazaar } } : {}),\n };\n // The machine-readable header carries the extension too: a client that reads only the\n // header, which the spec allows, still sees what it has to echo.\n const encoded = JSON.stringify({\n x402Version: 2,\n accepts,\n resource: opts.resource,\n ...(opts.bazaar ? { extensions: { bazaar: opts.bazaar } } : {}),\n });\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"WWW-Authenticate\": `Payment realm=\"agentwares\", methods=\"x402 prepaid_credits\", price=\"${amountUsd} USD\"`,\n [X402_HEADER]: encoded,\n [X402_REQUIRED_HEADER]: btoa(encoded),\n \"Cache-Control\": \"no-store\",\n };\n return { status: 402, headers, body };\n}\n\nexport interface VerifyResult {\n ok: boolean;\n rail?: PaymentRail;\n receipt?: unknown;\n reason?: string;\n}\n\n/** Given a request, decide whether it carries a valid payment. */\nexport interface PaymentVerifier {\n verify(request: Request, requirement: PaymentRequirement): Promise<VerifyResult>;\n /**\n * Optional second step for rails where verifying and taking the money are separate acts.\n * x402 works this way: checking a signature is free, submitting the transfer is not, so\n * settlement happens only after the paid work succeeded and a failed call is never\n * charged. Rails that debit during `verify` (prepaid credits) leave this unimplemented\n * and refund through `onPaidFailure` instead.\n */\n settle?(verified: VerifyResult): Promise<{ ok: boolean; reason?: string }>;\n}\n\n/**\n * Never accepts a payment, never touches funds. Still the verifier for the x402/USDC rail\n * (no CDP account yet); the card rail uses `createCreditsVerifier` from @agentwares/billing.\n */\nexport class StubVerifier implements PaymentVerifier {\n async verify(request: Request, requirement: PaymentRequirement): Promise<VerifyResult> {\n const hasHeader = request.headers.has(\"PAYMENT\") || request.headers.has(\"X-PAYMENT\");\n return {\n ok: false,\n rail: requirement.rail,\n reason: hasHeader\n ? \"payments are not live yet (phase 2: wallet). Use an API key with credits.\"\n : \"no payment header present\",\n };\n }\n}\n\n/** Convenience: a Web-standard Response for the 402. */\nexport function paymentRequiredResponse(opts: BuildPaymentRequiredOptions): Response {\n const r = buildPaymentRequired(opts);\n return new Response(JSON.stringify(r.body), { status: r.status, headers: r.headers });\n}\n\nexport * from \"./facilitator.js\";\n","/**\n * `serveStdio` — the same tools over stdio (Claude Desktop, Cursor, `npx` launchers).\n * The only module in the kit that touches Node APIs; loaded lazily so Web-standard bundles\n * never pull it in.\n */\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { createMcpServer, type McpServerOptions } from \"./server.js\";\n\n/** Connect over stdio. Resolves when the transport closes (stdin ends). */\nexport async function serveStdio(serverOrOpts: McpServer | McpServerOptions): Promise<void> {\n const server = serverOrOpts instanceof McpServer ? serverOrOpts : createMcpServer(serverOrOpts);\n const { StdioServerTransport } = await import(\"@modelcontextprotocol/sdk/server/stdio.js\");\n const transport = new StdioServerTransport();\n await server.connect(transport);\n await new Promise<void>((resolve) => {\n const previous = transport.onclose;\n transport.onclose = () => {\n previous?.();\n resolve();\n };\n });\n}\n","/**\n * Official MCP registry: `server.json` generator and the GitHub Actions workflow that publishes\n * it on tag via `mcp-publisher` with GitHub OIDC (no secrets).\n *\n * Field names follow the 2025-12-11 server.json schema\n * (https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json).\n */\n\nexport const SERVER_JSON_SCHEMA_URL =\n \"https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json\";\n\n/** `^[a-zA-Z0-9.-]+/[a-zA-Z0-9._-]+$` — reverse-DNS namespace, one slash, server name. */\nexport const SERVER_NAME_PATTERN = /^[a-zA-Z0-9.-]+\\/[a-zA-Z0-9._-]+$/;\nconst MAX_DESCRIPTION_LENGTH = 100;\n\nexport interface ServerJsonRepository {\n url: string;\n source: \"github\";\n /** path inside a monorepo, e.g. `shelf/deal-memo` */\n subfolder?: string;\n}\n\nexport interface ServerJsonKeyValueInput {\n name: string;\n description?: string;\n isRequired?: boolean;\n isSecret?: boolean;\n default?: string;\n format?: \"string\" | \"number\" | \"boolean\" | \"filepath\";\n}\n\nexport interface ServerJsonNpmPackage {\n /** npm package name, e.g. `@agentwares/deal-memo-mcp` */\n identifier: string;\n version: string;\n /** default `npx` */\n runtimeHint?: string;\n environmentVariables?: ServerJsonKeyValueInput[];\n}\n\nexport interface GenerateServerJsonOptions {\n /** reverse-DNS, e.g. `io.github.agentwares/deal-memo` (OIDC publishing needs `io.github.<owner>/`) */\n name: string;\n /** ≤ 100 chars, capabilities not implementation */\n description: string;\n version: string;\n title?: string;\n repository: ServerJsonRepository;\n websiteUrl?: string;\n /** stdio package published to npm (package.json must carry `mcpName: <name>`) */\n npmPackage?: ServerJsonNpmPackage;\n /** hosted Streamable HTTP endpoint, e.g. `https://deal-memo.agentwares.dev/mcp` */\n remoteUrl?: string;\n /** headers the client must send to the remote (e.g. an API key input) */\n remoteHeaders?: ServerJsonKeyValueInput[];\n}\n\nexport interface ServerJsonPackage {\n registryType: \"npm\";\n registryBaseUrl: string;\n identifier: string;\n version: string;\n runtimeHint?: string;\n transport: { type: \"stdio\" };\n environmentVariables?: ServerJsonKeyValueInput[];\n}\n\nexport interface ServerJsonRemote {\n type: \"streamable-http\";\n url: string;\n headers?: ServerJsonKeyValueInput[];\n}\n\nexport interface ServerJson {\n $schema: string;\n name: string;\n description: string;\n title?: string;\n version: string;\n websiteUrl?: string;\n repository: ServerJsonRepository;\n packages?: ServerJsonPackage[];\n remotes?: ServerJsonRemote[];\n}\n\n/** Build a `server.json` object for the official MCP registry. Validates the fields it can. */\nexport function generateServerJson(opts: GenerateServerJsonOptions): ServerJson {\n if (!SERVER_NAME_PATTERN.test(opts.name)) {\n throw new Error(\n `server.json name must be reverse-DNS with exactly one slash (e.g. io.github.acme/my-server), got ${JSON.stringify(opts.name)}`,\n );\n }\n const description = opts.description.trim();\n if (description.length === 0 || description.length > MAX_DESCRIPTION_LENGTH) {\n throw new Error(\n `server.json description must be 1-${MAX_DESCRIPTION_LENGTH} characters, got ${description.length}`,\n );\n }\n if (!opts.version.trim()) throw new Error(\"server.json version is required\");\n if (!opts.npmPackage && !opts.remoteUrl) {\n throw new Error(\n \"server.json needs at least one of npmPackage (stdio) or remoteUrl (streamable-http)\",\n );\n }\n if (opts.remoteUrl !== undefined && !/^https?:\\/\\/\\S+$/.test(opts.remoteUrl)) {\n throw new Error(`remoteUrl must be an http(s) URL, got ${JSON.stringify(opts.remoteUrl)}`);\n }\n\n const json: ServerJson = {\n $schema: SERVER_JSON_SCHEMA_URL,\n name: opts.name,\n description,\n version: opts.version,\n repository: { ...opts.repository },\n };\n if (opts.title !== undefined) json.title = opts.title;\n if (opts.websiteUrl !== undefined) json.websiteUrl = opts.websiteUrl;\n if (opts.npmPackage) {\n const pkg: ServerJsonPackage = {\n registryType: \"npm\",\n registryBaseUrl: \"https://registry.npmjs.org\",\n identifier: opts.npmPackage.identifier,\n version: opts.npmPackage.version,\n runtimeHint: opts.npmPackage.runtimeHint ?? \"npx\",\n transport: { type: \"stdio\" },\n };\n if (opts.npmPackage.environmentVariables?.length) {\n pkg.environmentVariables = opts.npmPackage.environmentVariables;\n }\n json.packages = [pkg];\n }\n if (opts.remoteUrl !== undefined) {\n const remote: ServerJsonRemote = { type: \"streamable-http\", url: opts.remoteUrl };\n if (opts.remoteHeaders?.length) remote.headers = opts.remoteHeaders;\n json.remotes = [remote];\n }\n return json;\n}\n\nexport interface RegistryPublishWorkflowOptions {\n /** repo-relative path, e.g. `shelf/deal-memo/server.json` */\n serverJsonPath: string;\n /** tag glob that triggers publishing (default `mcp-*`) */\n tagPattern?: string;\n /** workflow display name */\n workflowName?: string;\n /** commands to run before publishing (e.g. build + npm publish); each becomes a step */\n beforePublish?: { name: string; run: string }[];\n /** pin the mcp-publisher release (default: latest) */\n publisherVersion?: string;\n}\n\nfunction yamlString(value: string): string {\n return JSON.stringify(value);\n}\n\n/**\n * GitHub Actions workflow (YAML) that publishes `server.json` to the official MCP registry\n * on tags matching `tagPattern`, authenticating with GitHub OIDC (`permissions.id-token: write`).\n * Steps follow the registry's github-actions guide: install mcp-publisher from GitHub releases,\n * `mcp-publisher login github-oidc`, `mcp-publisher publish`.\n */\nexport function registryPublishWorkflow(opts: RegistryPublishWorkflowOptions): string {\n const tagPattern = opts.tagPattern ?? \"mcp-*\";\n const name = opts.workflowName ?? \"Publish to MCP Registry\";\n const releasePath = opts.publisherVersion\n ? `download/${opts.publisherVersion}`\n : \"latest/download\";\n const before = (opts.beforePublish ?? [])\n .map(\n (step) =>\n ` - name: ${yamlString(step.name)}\\n run: |\\n${step.run\n .split(\"\\n\")\n .map((line) => ` ${line}`)\n .join(\"\\n\")}\\n\\n`,\n )\n .join(\"\");\n\n return `name: ${yamlString(name)}\n\non:\n push:\n tags: [${yamlString(tagPattern)}]\n\njobs:\n publish:\n runs-on: ubuntu-latest\n permissions:\n id-token: write\n contents: read\n env:\n SERVER_JSON: ${yamlString(opts.serverJsonPath)}\n\n steps:\n - name: Checkout code\n uses: actions/checkout@v5\n\n${before} - name: Install mcp-publisher\n run: |\n curl -L \"https://github.com/modelcontextprotocol/registry/releases/${releasePath}/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz\" | tar xz mcp-publisher\n\n - name: Authenticate to MCP Registry (GitHub OIDC)\n run: ./mcp-publisher login github-oidc\n\n - name: Publish server.json to MCP Registry\n run: |\n dir=\"$(dirname \"$SERVER_JSON\")\"\n if [ \"$(basename \"$SERVER_JSON\")\" != \"server.json\" ]; then cp \"$SERVER_JSON\" \"$dir/server.json\"; fi\n cd \"$dir\" && \"$GITHUB_WORKSPACE/mcp-publisher\" publish\n`;\n}\n","/**\n * Machine-readable docs every product ships: `llms.txt` and `pricing.json`.\n */\nimport { listToolManifest } from \"./server.js\";\nimport type { ToolDef } from \"./tool.js\";\n\nexport interface LlmsTxtLink {\n title: string;\n url: string;\n note?: string;\n}\n\nexport interface LlmsTxtSection {\n title: string;\n links: LlmsTxtLink[];\n}\n\nexport interface RenderLlmsTxtOptions {\n /** product name — becomes the H1 */\n name: string;\n /** one-line summary — becomes the blockquote */\n summary: string;\n /** optional paragraphs after the summary */\n description?: string;\n /** primary links (docs, MCP endpoint, pricing.json, openapi) */\n links: LlmsTxtLink[];\n /** extra sections, e.g. \"Optional\" */\n sections?: LlmsTxtSection[];\n /** when given, an \"MCP tools\" section lists name, description and input fields */\n tools?: readonly ToolDef[];\n}\n\nfunction renderLink(link: LlmsTxtLink): string {\n return `- [${link.title}](${link.url})${link.note ? `: ${link.note}` : \"\"}`;\n}\n\n/** Render an llms.txt document (https://llmstxt.org): H1, blockquote summary, link sections. */\nexport function renderLlmsTxt(opts: RenderLlmsTxtOptions): string {\n const lines: string[] = [`# ${opts.name.trim()}`, \"\", `> ${opts.summary.trim()}`, \"\"];\n if (opts.description) lines.push(opts.description.trim(), \"\");\n lines.push(\"## Links\", \"\", ...opts.links.map(renderLink), \"\");\n for (const section of opts.sections ?? []) {\n lines.push(`## ${section.title}`, \"\", ...section.links.map(renderLink), \"\");\n }\n if (opts.tools && opts.tools.length > 0) {\n lines.push(\"## MCP tools\", \"\");\n for (const entry of listToolManifest(opts.tools)) {\n const properties = entry.inputSchema.properties;\n const required = new Set(\n Array.isArray(entry.inputSchema.required) ? (entry.inputSchema.required as string[]) : [],\n );\n const fields =\n properties && typeof properties === \"object\"\n ? Object.keys(properties as Record<string, unknown>).map((key) =>\n required.has(key) ? key : `${key}?`,\n )\n : [];\n lines.push(\n `- \\`${entry.name}\\`${fields.length ? ` (${fields.join(\", \")})` : \"\"}: ${entry.description.trim()}`,\n );\n }\n lines.push(\"\");\n }\n return lines.join(\"\\n\");\n}\n\nexport interface PricingTier {\n /** stable id used in checkout, e.g. `starter` */\n id: string;\n name: string;\n /** 0 for free tiers */\n priceUsdMonthly: number;\n /** quotas, e.g. `{ monitors: 5, checks_per_day: 288 }` */\n limits: Record<string, number | string | boolean | null>;\n features: string[];\n checkoutUrl?: string;\n}\n\nexport interface PricingMeter {\n /** Stripe billing meter event name, e.g. `agentcheck_docs_eval_run` */\n eventName: string;\n unitPriceUsd: number;\n /** what one unit is, e.g. `run` */\n unit: string;\n description?: string;\n}\n\nexport interface PricingJsonOptions {\n product: string;\n currency: \"usd\";\n tiers: PricingTier[];\n meters?: PricingMeter[];\n checkoutUrl?: string;\n portalUrl?: string;\n updatedAt: string | Date;\n /**\n * Present when this product is parked or retired. The endpoints keep serving — see\n * `packages/config/src/lifecycle.ts` — but an agent reads this file as a commitment, and it\n * deserves to know nobody is maintaining this before it builds on it.\n */\n lifecycle?: {\n stage: string;\n since: string;\n reason: string;\n insteadUrl?: string;\n };\n}\n\nexport interface PricingJson {\n schema: \"agentwares.pricing/v1\";\n product: string;\n currency: \"usd\";\n tiers: PricingTier[];\n meters: PricingMeter[];\n checkoutUrl?: string;\n portalUrl?: string;\n /** absent while a product is active; see PricingJsonOptions */\n lifecycle?: { stage: string; since: string; reason: string; insteadUrl?: string };\n /** ISO 8601 */\n updatedAt: string;\n}\n\n/** Build the `pricing.json` object served next to every pricing page. */\nexport function pricingJson(opts: PricingJsonOptions): PricingJson {\n if (opts.tiers.length === 0) throw new Error(\"pricing.json needs at least one tier\");\n const ids = new Set<string>();\n for (const tier of opts.tiers) {\n if (ids.has(tier.id)) throw new Error(`pricing.json: duplicate tier id ${tier.id}`);\n ids.add(tier.id);\n if (!Number.isFinite(tier.priceUsdMonthly) || tier.priceUsdMonthly < 0) {\n throw new Error(`pricing.json: tier ${tier.id} has an invalid priceUsdMonthly`);\n }\n }\n const updatedAt = new Date(opts.updatedAt);\n if (Number.isNaN(updatedAt.getTime())) throw new Error(\"pricing.json: updatedAt is not a date\");\n\n const json: PricingJson = {\n schema: \"agentwares.pricing/v1\",\n product: opts.product,\n currency: opts.currency,\n tiers: opts.tiers,\n meters: opts.meters ?? [],\n updatedAt: updatedAt.toISOString(),\n };\n if (opts.checkoutUrl !== undefined) json.checkoutUrl = opts.checkoutUrl;\n if (opts.portalUrl !== undefined) json.portalUrl = opts.portalUrl;\n if (opts.lifecycle !== undefined) json.lifecycle = opts.lifecycle;\n return json;\n}\n","/**\n * The documents an agent or a registry fetches before it decides whether to use you.\n *\n * Checked against the primary sources on 10 September 2026, because the summaries are wrong\n * about this in ways that matter. Two paths that get recommended everywhere are not served\n * here on purpose:\n *\n * - `/.well-known/mcp.json` — no specification defines it. Six live examples were compared\n * and no two share a schema (`servers[]`, `mcpServers{}`, `{name,description,endpoint}`,\n * a registry `server.json`, …). A client that guesses wrong attempts a connection and\n * fails, rather than skipping gracefully, so publishing a seventh shape is worse than\n * publishing nothing.\n * - `/.well-known/mcp/server-card.json` — the MCP extension's own discovery document lists\n * this under \"alternatives considered, not recommended\". A server card is application\n * metadata, not site metadata, so it belongs at the MCP endpoint. `serverCardResponse`\n * serves it at `<mcp-url>/server-card`, which is the reserved location GitHub and\n * Hugging Face already use in production.\n *\n * Nothing here is invented. `ai-catalog.json` follows the AI Catalog specification, which is\n * what GitHub, Vercel, Hugging Face, Supabase, Apify and Zapier serve today and what\n * Hugging Face's `hf discover` reads. `security.txt` is RFC 9116. The server card follows the\n * MCP `ext-server-card` schema, which is still experimental and may change — the shape is\n * additive and inert, so a client that does not know it ignores it.\n *\n * One failure mode is worth more than the rest: **a 200 with the wrong body is worse than a\n * 404.** A framework catch-all that answers every unknown path with an HTML page will serve\n * HTML at `/.well-known/anything`, and a crawler trusting the status code parses it as JSON.\n * Every helper here returns an explicit content type, and anything not served must genuinely\n * 404.\n */\n\n/** RFC 9116 §2.5.3: `Expires` should be under a year out, and a stale file is worse than none. */\nexport interface SecurityTxtOptions {\n /** at least one; mailto: or https: */\n contact: string[];\n /** ISO 8601 instant this file stops being trustworthy */\n expires: string;\n policyUrl?: string;\n acknowledgmentsUrl?: string;\n preferredLanguages?: string;\n /** where this file canonically lives; helps a reader spot a copy served from elsewhere */\n canonicalUrl?: string;\n}\n\nexport function securityTxt(options: SecurityTxtOptions): string {\n const lines: string[] = [];\n for (const contact of options.contact) lines.push(`Contact: ${contact}`);\n lines.push(`Expires: ${options.expires}`);\n if (options.policyUrl) lines.push(`Policy: ${options.policyUrl}`);\n if (options.acknowledgmentsUrl) lines.push(`Acknowledgments: ${options.acknowledgmentsUrl}`);\n if (options.preferredLanguages) lines.push(`Preferred-Languages: ${options.preferredLanguages}`);\n if (options.canonicalUrl) lines.push(`Canonical: ${options.canonicalUrl}`);\n return `${lines.join(\"\\n\")}\\n`;\n}\n\nexport function securityTxtResponse(options: SecurityTxtOptions): Response {\n return new Response(securityTxt(options), {\n headers: {\n \"content-type\": \"text/plain; charset=utf-8\",\n \"cache-control\": \"public, max-age=86400\",\n \"access-control-allow-origin\": \"*\",\n },\n });\n}\n\n/**\n * One thing an agent can use, listed in the catalog.\n *\n * `type` is a media type, and it is how a reader decides whether it can consume the entry at\n * all — `application/mcp-server-card+json` for an MCP server, `application/json` for a REST\n * API with an OpenAPI description. Exactly one of `url` or `data` is allowed.\n */\nexport interface AiCatalogEntry {\n identifier: string;\n type: string;\n url?: string;\n data?: unknown;\n displayName?: string;\n description?: string;\n tags?: string[];\n /**\n * Two to five things somebody would actually ask, in their words. This is what makes an\n * entry findable rather than merely present, and it is the field most publishers skip.\n */\n representativeQueries?: string[];\n}\n\nexport interface AiCatalogOptions {\n /** the publisher's own domain; `identifier` values are namespaced under it */\n host: { displayName: string; identifier: string; documentationUrl?: string };\n entries: AiCatalogEntry[];\n}\n\n/** `urn:air:{publisher}:{namespace}:{name}` — the publisher must be a domain you control. */\nexport function airUrn(publisher: string, namespace: string, name: string): string {\n return `urn:air:${publisher}:${namespace}:${name}`;\n}\n\nexport function aiCatalog(options: AiCatalogOptions): Record<string, unknown> {\n return {\n specVersion: \"1.0\",\n host: options.host,\n entries: options.entries.map((e) => ({\n identifier: e.identifier,\n ...(e.displayName ? { displayName: e.displayName } : {}),\n type: e.type,\n ...(e.url ? { url: e.url } : {}),\n ...(e.data !== undefined ? { data: e.data } : {}),\n ...(e.description ? { description: e.description } : {}),\n ...(e.tags?.length ? { tags: e.tags } : {}),\n ...(e.representativeQueries?.length\n ? { representativeQueries: e.representativeQueries }\n : {}),\n })),\n };\n}\n\nexport function aiCatalogResponse(options: AiCatalogOptions): Response {\n return new Response(`${JSON.stringify(aiCatalog(options), null, 2)}\\n`, {\n headers: {\n // the spec's media type; unregistered with IANA, but it is what every live publisher sends\n \"content-type\": \"application/ai-catalog+json\",\n \"cache-control\": \"public, max-age=3600\",\n \"access-control-allow-origin\": \"*\",\n },\n });\n}\n\n/**\n * An MCP server card, served at `<streamable-http-url>/server-card`.\n *\n * `description` is capped at 100 characters by the schema, which is easy to violate and\n * awkward to debug, so it is enforced here instead of at whatever reads it.\n */\nexport interface ServerCardOptions {\n /** reverse-DNS with exactly one slash, e.g. `io.github.agentwares/stablecoin-attestations` */\n name: string;\n version: string;\n /** at most 100 characters */\n description: string;\n title?: string;\n websiteUrl?: string;\n repository?: { url: string; source?: string; id?: string };\n /** where the server actually answers */\n remotes?: { type: \"streamable-http\" | \"sse\"; url: string }[];\n}\n\nconst SERVER_CARD_NAME = /^[a-zA-Z0-9.-]+\\/[a-zA-Z0-9._-]+$/;\n\nexport function serverCard(options: ServerCardOptions): Record<string, unknown> {\n if (!SERVER_CARD_NAME.test(options.name)) {\n throw new Error(\n `server card name must be reverse-DNS with one slash, got ${JSON.stringify(options.name)}`,\n );\n }\n if (options.description.length > 100) {\n throw new Error(\n `server card description is capped at 100 characters, got ${options.description.length}`,\n );\n }\n return {\n // The schema pattern-requires this exact string. It 404s today, so publish the literal\n // and do not try to fetch it at runtime.\n $schema: \"https://static.modelcontextprotocol.io/schemas/v1/server-card.schema.json\",\n name: options.name,\n version: options.version,\n description: options.description,\n ...(options.title ? { title: options.title } : {}),\n ...(options.websiteUrl ? { websiteUrl: options.websiteUrl } : {}),\n ...(options.repository ? { repository: options.repository } : {}),\n ...(options.remotes?.length ? { remotes: options.remotes } : {}),\n };\n}\n\nexport function serverCardResponse(options: ServerCardOptions): Response {\n return new Response(`${JSON.stringify(serverCard(options), null, 2)}\\n`, {\n headers: {\n \"content-type\": \"application/mcp-server-card+json\",\n \"cache-control\": \"public, max-age=3600\",\n \"access-control-allow-origin\": \"*\",\n },\n });\n}\n","#!/usr/bin/env node\n/**\n * Fake CRM MCP server used by the tests, the demo agent and the README walkthrough. In-memory\n * contacts; every mutation is recorded so tests can assert what really happened upstream.\n *\n * node dist/fixtures/crm-server.js # stdio\n * node dist/fixtures/crm-server.js --http # Streamable HTTP on 127.0.0.1:<port> (prints the URL)\n */\nimport {\n createHttpHandler,\n createMcpServer,\n defineTool,\n handleHealth,\n localhostHosts,\n serveNodeHttp,\n serveStdio,\n toolError,\n type ToolDef,\n} from \"@agentwares/mcp-kit\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\n\nexport interface Contact {\n id: string;\n name: string;\n email: string;\n updated_at: string;\n}\n\nexport interface CrmState {\n contacts: Map<string, Contact>;\n mutations: { tool: string; args: unknown }[];\n emails: { to: string; subject: string }[];\n charges: { customer_id: string; amount_usd: number }[];\n}\n\nexport function seedState(): CrmState {\n const contacts = new Map<string, Contact>();\n for (const [id, name, email] of [\n [\"c_1\", \"Ada Lovelace\", \"ada@example.com\"],\n [\"c_2\", \"Grace Hopper\", \"grace@example.com\"],\n [\"c_3\", \"Linus Torvalds\", \"linus@example.com\"],\n ] as const) {\n contacts.set(id, { id, name, email, updated_at: \"2026-01-01T00:00:00.000Z\" });\n }\n return { contacts, mutations: [], emails: [], charges: [] };\n}\n\nlet counter = 0;\nconst nextId = (prefix: string): string => `${prefix}_${(++counter).toString(36).padStart(4, \"0\")}`;\n\nexport function crmTools(state: CrmState): ToolDef[] {\n const contactSchema = z.object({\n id: z.string(),\n name: z.string(),\n email: z.string(),\n updated_at: z.string(),\n });\n return [\n defineTool({\n name: \"crm_list_contacts\",\n description:\n \"List every contact in the CRM. Read-only; returns id, name, email and updated_at.\",\n input: z.object({ limit: z.number().int().min(1).max(500).default(100) }),\n output: z.object({ contacts: z.array(contactSchema), total: z.number() }),\n annotations: { readOnlyHint: true },\n handler: ({ limit }) => ({\n contacts: [...state.contacts.values()].slice(0, limit),\n total: state.contacts.size,\n }),\n }),\n defineTool({\n name: \"crm_get_contact\",\n description: \"Fetch one contact by id. Read-only; NOT_FOUND when the id does not exist.\",\n input: z.object({ id: z.string() }),\n output: contactSchema,\n annotations: { readOnlyHint: true },\n handler: ({ id }) => {\n const c = state.contacts.get(id);\n if (!c)\n throw toolError(\n \"NOT_FOUND\",\n `no contact ${id}`,\n \"call crm_list_contacts and use an existing id\",\n );\n return c;\n },\n }),\n defineTool({\n name: \"crm_search\",\n description:\n \"Search contacts by name or email substring. Returns matching contacts (no annotations on purpose).\",\n input: z.object({ query: z.string() }),\n handler: ({ query }) => ({\n contacts: [...state.contacts.values()].filter((c) =>\n `${c.name} ${c.email}`.toLowerCase().includes(query.toLowerCase()),\n ),\n }),\n }),\n defineTool({\n name: \"crm_create_contact\",\n description: \"Create a contact. Returns the new id and created_at timestamp.\",\n input: z.object({ name: z.string(), email: z.string() }),\n output: z.object({ id: z.string(), created_at: z.string() }),\n annotations: { readOnlyHint: false, destructiveHint: false },\n handler: ({ name, email }) => {\n const id = nextId(\"c\");\n const now = new Date().toISOString();\n state.contacts.set(id, { id, name, email, updated_at: now });\n state.mutations.push({ tool: \"crm_create_contact\", args: { name, email } });\n return { id, created_at: now };\n },\n }),\n defineTool({\n name: \"crm_update_contact\",\n description:\n \"Update fields on a contact. Returns the id and updated_at; NOT_FOUND for unknown ids.\",\n input: z.object({\n id: z.string(),\n fields: z.object({ name: z.string().optional(), email: z.string().optional() }),\n }),\n output: z.object({ id: z.string(), updated_at: z.string() }),\n annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true },\n handler: ({ id, fields }) => {\n const c = state.contacts.get(id);\n if (!c)\n throw toolError(\n \"NOT_FOUND\",\n `no contact ${id}`,\n \"call crm_list_contacts and use an existing id\",\n );\n Object.assign(c, fields, { updated_at: new Date().toISOString() });\n state.mutations.push({ tool: \"crm_update_contact\", args: { id, fields } });\n return { id, updated_at: c.updated_at };\n },\n }),\n defineTool({\n name: \"crm_delete_contact\",\n description: \"Permanently delete a contact. Irreversible. Returns { deleted, id }.\",\n input: z.object({ id: z.string() }),\n output: z.object({ deleted: z.boolean(), id: z.string() }),\n annotations: { readOnlyHint: false, destructiveHint: true },\n handler: ({ id }) => {\n const existed = state.contacts.delete(id);\n state.mutations.push({ tool: \"crm_delete_contact\", args: { id } });\n return { deleted: existed, id };\n },\n }),\n defineTool({\n name: \"crm_send_email\",\n description:\n \"Send an email to a contact through the CRM. Returns the message id and sent_at.\",\n input: z.object({ to: z.string(), subject: z.string(), body: z.string() }),\n output: z.object({ message_id: z.string(), sent_at: z.string() }),\n handler: ({ to, subject }) => {\n state.emails.push({ to, subject });\n state.mutations.push({ tool: \"crm_send_email\", args: { to, subject } });\n return { message_id: nextId(\"msg\"), sent_at: new Date().toISOString() };\n },\n }),\n defineTool({\n name: \"crm_charge_card\",\n description:\n \"Charge a customer's card on file (amount in cents). Returns the charge id and amount_usd.\",\n input: z.object({\n customer_id: z.string(),\n amount_cents: z.number().int().positive(),\n currency: z.string().default(\"usd\"),\n }),\n output: z.object({ charge_id: z.string(), amount_usd: z.number() }),\n handler: ({ customer_id, amount_cents }) => {\n const amount_usd = amount_cents / 100;\n state.charges.push({ customer_id, amount_usd });\n state.mutations.push({ tool: \"crm_charge_card\", args: { customer_id, amount_usd } });\n return { charge_id: nextId(\"ch\"), amount_usd };\n },\n }),\n defineTool({\n name: \"crm_frobnicate\",\n description:\n \"A tool with no annotations and no recognizable verb — exists to test `unknown` handling.\",\n input: z.object({}),\n handler: () => {\n state.mutations.push({ tool: \"crm_frobnicate\", args: {} });\n return { frobnicated: true };\n },\n }),\n defineTool({\n name: \"crm_fail\",\n description: \"Always returns a structured UPSTREAM_ERROR result, for error-path tests.\",\n input: z.object({}),\n annotations: { readOnlyHint: true },\n handler: () => {\n throw toolError(\"UPSTREAM_ERROR\", \"the CRM is having a bad day\", \"retry in a minute\", {\n retryable: true,\n });\n },\n }),\n ];\n}\n\nexport function createCrmMcpServer(state: CrmState = seedState()): McpServer {\n return createMcpServer({\n name: \"fake-crm\",\n version: \"0.1.0\",\n instructions: \"A fake CRM for agentguard tests. Nothing here is real.\",\n tools: crmTools(state),\n });\n}\n\nconst isMain = process.argv[1] !== undefined && /crm-server\\.[cm]?[jt]s$/.test(process.argv[1]);\nif (isMain) {\n const state = seedState();\n if (process.argv.includes(\"--http\")) {\n const portArg = process.argv.find((a) => a.startsWith(\"--port=\"));\n const port = portArg ? Number(portArg.slice(\"--port=\".length)) : 0;\n const handler = createHttpHandler(() => createCrmMcpServer(state), {\n sessions: true,\n jsonResponse: false,\n allowedHosts: port ? localhostHosts(port) : undefined,\n });\n const server = await serveNodeHttp({\n handler,\n port,\n health: () =>\n handleHealth({ name: \"fake-crm\", version: \"0.1.0\", tools: crmTools(state).length }),\n });\n console.log(`fake-crm listening at ${server.url}`);\n } else {\n // The proxy stops us with SIGTERM; exit on it so Node does not warn about the unsettled\n // top-level await into the parent's stderr at the end of the demo.\n for (const signal of [\"SIGTERM\", \"SIGINT\"] as const) process.on(signal, () => process.exit(0));\n await serveStdio(createCrmMcpServer(state));\n }\n}\n"],"mappings":"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","names":["z","z","z","z","jsonResponse","McpServer","z"]}
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,119 +1,8 @@
1
1
  #!/usr/bin/env node
2
-
3
- // src/fixtures/demo-agent.ts
4
- import { Client } from "@modelcontextprotocol/sdk/client/index.js";
5
- import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
6
- import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
7
- import { fileURLToPath } from "url";
8
- import path from "path";
9
- function summarize(result) {
10
- const text = result.content.find((c) => c.type === "text")?.text;
11
- const meta = result._meta?.agentguard;
12
- if (result.isError) {
13
- let code;
14
- try {
15
- code = JSON.parse(text ?? "{}").code;
16
- } catch {
17
- }
18
- return { ok: false, code, text };
19
- }
20
- return { ok: true, dryRun: meta?.dryRun, text };
21
- }
22
- async function runDemoAgent(client, opts = {}) {
23
- const steps = [];
24
- const log = opts.log ?? (() => void 0);
25
- const meta = opts.runId ? { runId: opts.runId } : void 0;
26
- const call = async (step, tool, args) => {
27
- const result = await client.callTool({
28
- name: tool,
29
- arguments: args,
30
- _meta: meta
31
- });
32
- const s = { step, tool, ...summarize(result) };
33
- steps.push(s);
34
- log(
35
- `${s.ok ? s.dryRun ? "faked " : "ok " : `${s.code ?? "error"}`.padEnd(6)} ${step}: ${tool}`
36
- );
37
- return s;
38
- };
39
- await call("read: list contacts", "crm_list_contacts", { limit: 10 });
40
- await call("read: get one", "crm_get_contact", { id: "c_1" });
41
- await call("write: create", "crm_create_contact", {
42
- name: "Demo Person",
43
- email: "demo@example.com"
44
- });
45
- await call("write: update", "crm_update_contact", { id: "c_1", fields: { name: "Ada L." } });
46
- await call("write: delete (destructive)", "crm_delete_contact", { id: "c_2" });
47
- await call("write: send email", "crm_send_email", {
48
- to: "ada@example.com",
49
- subject: "Hi",
50
- body: "Hello from the demo agent"
51
- });
52
- await call("spend: charge $12", "crm_charge_card", {
53
- customer_id: "c_1",
54
- amount_cents: 1200,
55
- currency: "usd"
56
- });
57
- const loops = opts.loop ?? 5;
58
- for (let i = 0; i < loops; i += 1) {
59
- const s = await call(`loop ${i + 1}/${loops}: identical update`, "crm_update_contact", {
60
- id: "c_3",
61
- fields: { name: "Same Thing" }
62
- });
63
- if (s.code === "LOOP_DETECTED") break;
64
- }
65
- const burst = opts.burst ?? 60;
66
- for (let i = 0; i < burst; i += 1) {
67
- const s = await call(`burst ${i + 1}/${burst}: create`, "crm_create_contact", {
68
- name: `Bulk ${i}`,
69
- email: `bulk${i}@example.com`
70
- });
71
- if (s.code === "CAP_EXCEEDED") break;
72
- }
73
- return steps;
74
- }
75
- var isMain = process.argv[1] !== void 0 && /demo-agent\.[cm]?[jt]s$/.test(process.argv[1]);
76
- if (isMain) {
77
- const argv = process.argv.slice(2);
78
- const arg = (name) => {
79
- const i = argv.indexOf(name);
80
- return i >= 0 ? argv[i + 1] : void 0;
81
- };
82
- const url = arg("--url");
83
- const config = arg("--config") ?? "agentguard.yaml";
84
- const client = new Client({ name: "agentguard-demo-agent", version: "0.1.0" });
85
- if (url) {
86
- await client.connect(
87
- new StreamableHTTPClientTransport(new URL(url), {
88
- requestInit: {
89
- headers: { "X-Run-Id": arg("--run-id") ?? `demo_${Date.now().toString(36)}` }
90
- }
91
- })
92
- );
93
- } else {
94
- const cli = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../cli.js");
95
- await client.connect(
96
- new StdioClientTransport({
97
- command: process.execPath,
98
- args: [cli, "proxy", "--config", config],
99
- stderr: "inherit"
100
- })
101
- );
102
- }
103
- try {
104
- const steps = await runDemoAgent(client, {
105
- log: (l) => console.log(l),
106
- runId: arg("--run-id")
107
- });
108
- const halts = steps.filter((s) => !s.ok).map((s) => s.code);
109
- console.log(
110
- `
111
- ${steps.length} calls; halts: ${halts.join(", ") || "none"}. Now run: agentguard report`
112
- );
113
- } finally {
114
- await client.close();
115
- }
116
- }
2
+ import {
3
+ runDemoAgent
4
+ } from "../chunk-BKXXTWIS.js";
5
+ import "../chunk-5WRI5ZAA.js";
117
6
  export {
118
7
  runDemoAgent
119
8
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/fixtures/demo-agent.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * A scripted \"agent\" that misbehaves on purpose: reads, then writes, then loops, then bursts\n * writes past the cap. Run it against the proxy to see dry-run diffs, LOOP_DETECTED and\n * CAP_EXCEEDED in `agentguard report`.\n *\n * node dist/fixtures/demo-agent.js --config agentguard.yaml # spawns `agentguard proxy` over stdio\n */\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { fileURLToPath } from \"node:url\";\nimport path from \"node:path\";\n\nexport interface DemoStep {\n step: string;\n tool: string;\n ok: boolean;\n code?: string;\n dryRun?: boolean;\n text?: string;\n}\n\nexport interface DemoOptions {\n /** how many writes to burst at the end (default 60 — past a `writes: 50` cap) */\n burst?: number;\n /** how many times to repeat the identical update (default 5 — past `max_repeats: 3`) */\n loop?: number;\n runId?: string;\n log?: (line: string) => void;\n}\n\nfunction summarize(result: CallToolResult): {\n ok: boolean;\n code?: string;\n dryRun?: boolean;\n text?: string;\n} {\n const text = result.content.find((c) => c.type === \"text\")?.text;\n const meta = (result._meta as { agentguard?: { dryRun?: boolean } } | undefined)?.agentguard;\n if (result.isError) {\n let code: string | undefined;\n try {\n code = (JSON.parse(text ?? \"{}\") as { code?: string }).code;\n } catch {\n // not JSON\n }\n return { ok: false, code, text };\n }\n return { ok: true, dryRun: meta?.dryRun, text };\n}\n\n/** Drive a connected client through the scripted scenario. Returns every step's outcome. */\nexport async function runDemoAgent(client: Client, opts: DemoOptions = {}): Promise<DemoStep[]> {\n const steps: DemoStep[] = [];\n const log = opts.log ?? (() => undefined);\n const meta = opts.runId ? { runId: opts.runId } : undefined;\n const call = async (\n step: string,\n tool: string,\n args: Record<string, unknown>,\n ): Promise<DemoStep> => {\n const result = (await client.callTool({\n name: tool,\n arguments: args,\n _meta: meta,\n })) as CallToolResult;\n const s = { step, tool, ...summarize(result) };\n steps.push(s);\n log(\n `${s.ok ? (s.dryRun ? \"faked \" : \"ok \") : `${s.code ?? \"error\"}`.padEnd(6)} ${step}: ${tool}`,\n );\n return s;\n };\n\n await call(\"read: list contacts\", \"crm_list_contacts\", { limit: 10 });\n await call(\"read: get one\", \"crm_get_contact\", { id: \"c_1\" });\n await call(\"write: create\", \"crm_create_contact\", {\n name: \"Demo Person\",\n email: \"demo@example.com\",\n });\n await call(\"write: update\", \"crm_update_contact\", { id: \"c_1\", fields: { name: \"Ada L.\" } });\n await call(\"write: delete (destructive)\", \"crm_delete_contact\", { id: \"c_2\" });\n await call(\"write: send email\", \"crm_send_email\", {\n to: \"ada@example.com\",\n subject: \"Hi\",\n body: \"Hello from the demo agent\",\n });\n await call(\"spend: charge $12\", \"crm_charge_card\", {\n customer_id: \"c_1\",\n amount_cents: 1200,\n currency: \"usd\",\n });\n\n const loops = opts.loop ?? 5;\n for (let i = 0; i < loops; i += 1) {\n const s = await call(`loop ${i + 1}/${loops}: identical update`, \"crm_update_contact\", {\n id: \"c_3\",\n fields: { name: \"Same Thing\" },\n });\n if (s.code === \"LOOP_DETECTED\") break;\n }\n\n const burst = opts.burst ?? 60;\n for (let i = 0; i < burst; i += 1) {\n const s = await call(`burst ${i + 1}/${burst}: create`, \"crm_create_contact\", {\n name: `Bulk ${i}`,\n email: `bulk${i}@example.com`,\n });\n if (s.code === \"CAP_EXCEEDED\") break;\n }\n return steps;\n}\n\nconst isMain = process.argv[1] !== undefined && /demo-agent\\.[cm]?[jt]s$/.test(process.argv[1]);\nif (isMain) {\n const argv = process.argv.slice(2);\n const arg = (name: string): string | undefined => {\n const i = argv.indexOf(name);\n return i >= 0 ? argv[i + 1] : undefined;\n };\n const url = arg(\"--url\");\n const config = arg(\"--config\") ?? \"agentguard.yaml\";\n const client = new Client({ name: \"agentguard-demo-agent\", version: \"0.1.0\" });\n if (url) {\n await client.connect(\n new StreamableHTTPClientTransport(new URL(url), {\n requestInit: {\n headers: { \"X-Run-Id\": arg(\"--run-id\") ?? `demo_${Date.now().toString(36)}` },\n },\n }),\n );\n } else {\n const cli = path.resolve(path.dirname(fileURLToPath(import.meta.url)), \"../cli.js\");\n await client.connect(\n new StdioClientTransport({\n command: process.execPath,\n args: [cli, \"proxy\", \"--config\", config],\n stderr: \"inherit\",\n }),\n );\n }\n try {\n const steps = await runDemoAgent(client, {\n log: (l) => console.log(l),\n runId: arg(\"--run-id\"),\n });\n const halts = steps.filter((s) => !s.ok).map((s) => s.code);\n console.log(\n `\\n${steps.length} calls; halts: ${halts.join(\", \") || \"none\"}. Now run: agentguard report`,\n );\n } finally {\n await client.close();\n }\n}\n"],"mappings":";;;AAQA,SAAS,cAAc;AACvB,SAAS,4BAA4B;AACrC,SAAS,qCAAqC;AAE9C,SAAS,qBAAqB;AAC9B,OAAO,UAAU;AAoBjB,SAAS,UAAU,QAKjB;AACA,QAAM,OAAO,OAAO,QAAQ,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM,GAAG;AAC5D,QAAM,OAAQ,OAAO,OAA6D;AAClF,MAAI,OAAO,SAAS;AAClB,QAAI;AACJ,QAAI;AACF,aAAQ,KAAK,MAAM,QAAQ,IAAI,EAAwB;AAAA,IACzD,QAAQ;AAAA,IAER;AACA,WAAO,EAAE,IAAI,OAAO,MAAM,KAAK;AAAA,EACjC;AACA,SAAO,EAAE,IAAI,MAAM,QAAQ,MAAM,QAAQ,KAAK;AAChD;AAGA,eAAsB,aAAa,QAAgB,OAAoB,CAAC,GAAwB;AAC9F,QAAM,QAAoB,CAAC;AAC3B,QAAM,MAAM,KAAK,QAAQ,MAAM;AAC/B,QAAM,OAAO,KAAK,QAAQ,EAAE,OAAO,KAAK,MAAM,IAAI;AAClD,QAAM,OAAO,OACX,MACA,MACA,SACsB;AACtB,UAAM,SAAU,MAAM,OAAO,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,WAAW;AAAA,MACX,OAAO;AAAA,IACT,CAAC;AACD,UAAM,IAAI,EAAE,MAAM,MAAM,GAAG,UAAU,MAAM,EAAE;AAC7C,UAAM,KAAK,CAAC;AACZ;AAAA,MACE,GAAG,EAAE,KAAM,EAAE,SAAS,WAAW,WAAY,GAAG,EAAE,QAAQ,OAAO,GAAG,OAAO,CAAC,CAAC,IAAI,IAAI,KAAK,IAAI;AAAA,IAChG;AACA,WAAO;AAAA,EACT;AAEA,QAAM,KAAK,uBAAuB,qBAAqB,EAAE,OAAO,GAAG,CAAC;AACpE,QAAM,KAAK,iBAAiB,mBAAmB,EAAE,IAAI,MAAM,CAAC;AAC5D,QAAM,KAAK,iBAAiB,sBAAsB;AAAA,IAChD,MAAM;AAAA,IACN,OAAO;AAAA,EACT,CAAC;AACD,QAAM,KAAK,iBAAiB,sBAAsB,EAAE,IAAI,OAAO,QAAQ,EAAE,MAAM,SAAS,EAAE,CAAC;AAC3F,QAAM,KAAK,+BAA+B,sBAAsB,EAAE,IAAI,MAAM,CAAC;AAC7E,QAAM,KAAK,qBAAqB,kBAAkB;AAAA,IAChD,IAAI;AAAA,IACJ,SAAS;AAAA,IACT,MAAM;AAAA,EACR,CAAC;AACD,QAAM,KAAK,qBAAqB,mBAAmB;AAAA,IACjD,aAAa;AAAA,IACb,cAAc;AAAA,IACd,UAAU;AAAA,EACZ,CAAC;AAED,QAAM,QAAQ,KAAK,QAAQ;AAC3B,WAAS,IAAI,GAAG,IAAI,OAAO,KAAK,GAAG;AACjC,UAAM,IAAI,MAAM,KAAK,QAAQ,IAAI,CAAC,IAAI,KAAK,sBAAsB,sBAAsB;AAAA,MACrF,IAAI;AAAA,MACJ,QAAQ,EAAE,MAAM,aAAa;AAAA,IAC/B,CAAC;AACD,QAAI,EAAE,SAAS,gBAAiB;AAAA,EAClC;AAEA,QAAM,QAAQ,KAAK,SAAS;AAC5B,WAAS,IAAI,GAAG,IAAI,OAAO,KAAK,GAAG;AACjC,UAAM,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,IAAI,KAAK,YAAY,sBAAsB;AAAA,MAC5E,MAAM,QAAQ,CAAC;AAAA,MACf,OAAO,OAAO,CAAC;AAAA,IACjB,CAAC;AACD,QAAI,EAAE,SAAS,eAAgB;AAAA,EACjC;AACA,SAAO;AACT;AAEA,IAAM,SAAS,QAAQ,KAAK,CAAC,MAAM,UAAa,0BAA0B,KAAK,QAAQ,KAAK,CAAC,CAAC;AAC9F,IAAI,QAAQ;AACV,QAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,QAAM,MAAM,CAAC,SAAqC;AAChD,UAAM,IAAI,KAAK,QAAQ,IAAI;AAC3B,WAAO,KAAK,IAAI,KAAK,IAAI,CAAC,IAAI;AAAA,EAChC;AACA,QAAM,MAAM,IAAI,OAAO;AACvB,QAAM,SAAS,IAAI,UAAU,KAAK;AAClC,QAAM,SAAS,IAAI,OAAO,EAAE,MAAM,yBAAyB,SAAS,QAAQ,CAAC;AAC7E,MAAI,KAAK;AACP,UAAM,OAAO;AAAA,MACX,IAAI,8BAA8B,IAAI,IAAI,GAAG,GAAG;AAAA,QAC9C,aAAa;AAAA,UACX,SAAS,EAAE,YAAY,IAAI,UAAU,KAAK,QAAQ,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC,GAAG;AAAA,QAC9E;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF,OAAO;AACL,UAAM,MAAM,KAAK,QAAQ,KAAK,QAAQ,cAAc,YAAY,GAAG,CAAC,GAAG,WAAW;AAClF,UAAM,OAAO;AAAA,MACX,IAAI,qBAAqB;AAAA,QACvB,SAAS,QAAQ;AAAA,QACjB,MAAM,CAAC,KAAK,SAAS,YAAY,MAAM;AAAA,QACvC,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAAA,EACF;AACA,MAAI;AACF,UAAM,QAAQ,MAAM,aAAa,QAAQ;AAAA,MACvC,KAAK,CAAC,MAAM,QAAQ,IAAI,CAAC;AAAA,MACzB,OAAO,IAAI,UAAU;AAAA,IACvB,CAAC;AACD,UAAM,QAAQ,MAAM,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI;AAC1D,YAAQ;AAAA,MACN;AAAA,EAAK,MAAM,MAAM,kBAAkB,MAAM,KAAK,IAAI,KAAK,MAAM;AAAA,IAC/D;AAAA,EACF,UAAE;AACA,UAAM,OAAO,MAAM;AAAA,EACrB;AACF;","names":[]}
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}