@devlab.group/agent-commerce 1.2.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/mcp.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- import { H as HttpProtocolAdapter } from './protocol-adapter-BAKGnuZ4.js';
1
+ import { H as HttpProtocolAdapter } from './protocol-adapter-CaMZj6Wm.js';
2
2
  import 'node:http';
3
- import './runtime-Bqg9qW3t.js';
3
+ import './runtime-CKq3d_3K.js';
4
+ import './authorization-CPDcpJVa.js';
4
5
 
5
6
  /**
6
7
  * MCP protocol adapter.
package/dist/mcp.js CHANGED
@@ -1,4 +1,4 @@
1
- import { PACKAGE_VERSION, toCommerceError, CommerceError, PAYMENT_INPUT_FIELD, toErrorEnvelope, DELIVERY_SUMMARY_META_KEY, toDeliverySummary, toPaymentRequiredEnvelope } from './chunk-EIACECVM.js';
1
+ import { PACKAGE_VERSION, toCommerceError, CommerceError, extractReservedInputFields, PAYMENT_INPUT_FIELD, toErrorEnvelope, DELIVERY_SUMMARY_META_KEY, toDeliverySummary, toPaymentRequiredEnvelope } from './chunk-ZDVJ7EVL.js';
2
2
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3
3
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
4
4
  import { ListToolsRequestSchema, CallToolRequestSchema, LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/sdk/types.js';
@@ -33,14 +33,6 @@ function buildDescriptor(implementationVersion) {
33
33
  function toRecord(value) {
34
34
  return value;
35
35
  }
36
- function extractPaymentSubmission(rawArgs, resource) {
37
- const { [PAYMENT_INPUT_FIELD]: paymentValue, ...input } = rawArgs;
38
- const method = resource?.paymentMethods[0];
39
- if (typeof paymentValue === "string" && paymentValue.length > 0 && method !== void 0) {
40
- return { input, payment: { method, payload: paymentValue } };
41
- }
42
- return { input };
43
- }
44
36
  function deliveredResult(outcome) {
45
37
  const body = outcome.body;
46
38
  const text = typeof body === "string" ? body : JSON.stringify(body ?? null);
@@ -335,14 +327,20 @@ var McpProtocolAdapter = class {
335
327
  new CommerceError("RESOURCE_NOT_FOUND", `Unknown tool "${resourceId}".`, { resourceId })
336
328
  );
337
329
  }
338
- const { input, payment } = extractPaymentSubmission(rawArgs, resource);
330
+ const requestId = context.ids.next("mcp");
331
+ const { input, payment, authorization } = extractReservedInputFields(
332
+ rawArgs,
333
+ resource,
334
+ requestId
335
+ );
339
336
  const request = {
340
- requestId: context.ids.next("mcp"),
337
+ requestId,
341
338
  resourceId,
342
339
  input,
343
340
  protocol: "mcp",
344
341
  receivedAt: context.clock.nowIso(),
345
- ...payment !== void 0 ? { payment } : {}
342
+ ...payment !== void 0 ? { payment } : {},
343
+ ...authorization !== void 0 ? { authorization } : {}
346
344
  };
347
345
  await this.acquireToolCallSlot(signal);
348
346
  try {
package/dist/mcp.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/protocols/mcp/descriptor.ts","../src/protocols/mcp/result-mapping.ts","../src/protocols/mcp/tool-mapping.ts","../src/protocols/mcp/adapter.ts"],"names":[],"mappings":"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","file":"mcp.js","sourcesContent":["/**\n * Adapter self-description.\n *\n * `supportedSpec` reports the MCP protocol revision this adapter targets, as\n * negotiated by the installed @modelcontextprotocol/sdk@1.30.0 build.\n *\n * Verified against the shipped SDK (not guessed):\n * `dist/esm/types.js` exports `LATEST_PROTOCOL_VERSION = '2025-11-25'` and\n * `SUPPORTED_PROTOCOL_VERSIONS = [LATEST_PROTOCOL_VERSION, '2025-06-18',\n * '2025-03-26', '2024-11-05', '2024-10-07']`. `dist/esm/server/index.js`\n * (`_oninitialize`) negotiates by echoing the client-requested version when\n * it is in `SUPPORTED_PROTOCOL_VERSIONS`, and falling back to\n * `LATEST_PROTOCOL_VERSION` otherwise — so `LATEST_PROTOCOL_VERSION` is the\n * single most accurate value to report as \"the\" supported spec revision.\n */\nimport { LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/sdk/types.js';\nimport type { AdapterDescriptor } from '../../core/index.js';\n\n/** This package's own version — independent of the negotiated MCP spec revision. */\nexport { PACKAGE_VERSION } from '../../version.js';\n\n/** The MCP protocol revision this adapter targets (see module doc above). */\nexport const MCP_SUPPORTED_SPEC = LATEST_PROTOCOL_VERSION;\n\n/** Tool-oriented capabilities this adapter actually implements. */\nexport const MCP_CAPABILITIES: readonly string[] = ['tools/list', 'tools/call'];\n\n/**\n * MCP surfaces this adapter does not implement in this release. Kept explicit\n * so `doctor` / the support matrix never imply blanket protocol compatibility.\n *\n * `dns-rebinding-protection` is not a missing *feature* so much as a\n * delegated one: this transport does not validate `Origin`/`Host` itself\n * (see adapter.ts's module doc for why) — the gateway's `onRequest` hook\n * does, for `/mcp` and the HTTP routes together. Listed here so alpha\n * honesty holds even for a security property, not just a protocol surface:\n * an operator reading this adapter's own descriptor should not conclude it\n * provides Origin validation on its own.\n */\nexport const MCP_UNSUPPORTED: readonly string[] = [\n 'resources',\n 'prompts',\n 'sampling',\n 'completions',\n 'elicitation',\n 'roots',\n 'logging',\n 'notifications/tools/list_changed',\n 'tasks',\n 'dns-rebinding-protection',\n];\n\nexport function buildDescriptor(implementationVersion: string): AdapterDescriptor {\n return {\n name: 'mcp',\n kind: 'protocol',\n implementationVersion,\n supportedSpec: MCP_SUPPORTED_SPEC,\n capabilities: MCP_CAPABILITIES,\n status: 'stable',\n unsupported: MCP_UNSUPPORTED,\n };\n}\n","/**\n * Maps execution-pipeline results and payment-proof input to their MCP wire\n * representation. Uses only the frozen wire helpers from core\n * (`toErrorEnvelope`, `toPaymentRequiredEnvelope`) so the MCP adapter, the\n * HTTP route and the demo buyer agent can never drift apart.\n */\n\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport {\n type CommerceError,\n type CommerceResource,\n DELIVERY_SUMMARY_META_KEY,\n type DeliveredOutcome,\n type ExecutionOutcome,\n PAYMENT_INPUT_FIELD,\n type PaymentRequiredOutcome,\n type PaymentSubmission,\n toDeliverySummary,\n toErrorEnvelope,\n toPaymentRequiredEnvelope,\n} from '../../core/index.js';\n\nfunction toRecord(value: object): Record<string, unknown> {\n return value as Record<string, unknown>;\n}\n\n/**\n * Splits raw MCP tool arguments into resource input and an optional payment\n * submission. `_payment` never leaks into the input handed to the pipeline.\n *\n * The payment method is derived from the resource's own `paymentMethods`\n * (never hard-coded) — this adapter does not decide which rail a resource\n * uses, that is core/config's job. If a `_payment` proof is supplied for a\n * resource with no configured payment method (or an unrecognised resource),\n * it is dropped rather than forwarded under an invented method: the pipeline\n * then treats the request as unpaid and decides for itself (free delivery,\n * or a rejection) — never a payment-method guess made in this adapter.\n */\nexport function extractPaymentSubmission(\n rawArgs: Record<string, unknown>,\n resource: CommerceResource | undefined,\n): {\n input: Record<string, unknown>;\n payment?: PaymentSubmission;\n} {\n const { [PAYMENT_INPUT_FIELD]: paymentValue, ...input } = rawArgs;\n const method = resource?.paymentMethods[0];\n if (typeof paymentValue === 'string' && paymentValue.length > 0 && method !== undefined) {\n return { input, payment: { method, payload: paymentValue } };\n }\n return { input };\n}\n\nexport function deliveredResult(outcome: DeliveredOutcome): CallToolResult {\n const body = outcome.body;\n const text = typeof body === 'string' ? body : JSON.stringify(body ?? null);\n const isStructured = typeof body === 'object' && body !== null && !Array.isArray(body);\n return {\n content: [{ type: 'text', text }],\n ...(isStructured ? { structuredContent: toRecord(body) } : {}),\n _meta: { [DELIVERY_SUMMARY_META_KEY]: toRecord(toDeliverySummary(outcome)) },\n };\n}\n\nexport function paymentRequiredResult(outcome: PaymentRequiredOutcome): CallToolResult {\n const envelope = toPaymentRequiredEnvelope(outcome);\n const p = envelope.payment;\n const text = `Payment required: ${p.amount} ${p.currency} to ${p.destination} for resource \"${outcome.resourceId}\". Retry the call with a ${p.provider} payment proof in the \"${PAYMENT_INPUT_FIELD}\" input field.`;\n return {\n isError: true,\n content: [{ type: 'text', text }],\n structuredContent: toRecord(envelope),\n };\n}\n\nexport function errorResult(error: CommerceError): CallToolResult {\n const envelope = toErrorEnvelope(error);\n return {\n isError: true,\n content: [{ type: 'text', text: `${envelope.code}: ${envelope.message}` }],\n structuredContent: toRecord(envelope),\n };\n}\n\nexport function mapOutcome(outcome: ExecutionOutcome): CallToolResult {\n return outcome.kind === 'delivered' ? deliveredResult(outcome) : paymentRequiredResult(outcome);\n}\n","/**\n * Maps a canonical `CommerceResource` to an MCP `Tool`.\n *\n * One tool per resource: tool name = resource id, description carries a\n * clear price notice for paid resources, and input schema is the canonical\n * JSON Schema (preserved as-is, including per-property descriptions) with the\n * reserved `_payment` property added for paid resources.\n */\n\nimport type { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport {\n type CommerceResource,\n PAYMENT_INPUT_FIELD,\n type PaymentMethodName,\n} from '../../core/index.js';\n\n/**\n * MCP tool names must match SEP-986: 1-128 chars of [A-Za-z0-9._-].\n *\n * Mirrors the pattern enforced by @modelcontextprotocol/sdk@1.30.0 itself\n * (`dist/esm/shared/toolNameValidation.js`: `TOOL_NAME_REGEX =\n * /^[A-Za-z0-9._-]{1,128}$/`), read from the installed build rather than\n * guessed. We validate independently (instead of importing that internal,\n * unexported module path) so a resource with an illegal id fails loudly here\n * instead of being silently registered and warned about by the SDK.\n */\nexport const MCP_TOOL_NAME_PATTERN = /^[A-Za-z0-9._-]{1,128}$/;\n\nexport function isValidToolName(id: string): boolean {\n return MCP_TOOL_NAME_PATTERN.test(id);\n}\n\nexport function isPaidResource(resource: CommerceResource): boolean {\n return resource.pricing.type !== 'free';\n}\n\n/**\n * The rail a resource actually accepts, per its own canonical configuration.\n * Never hard-coded here — the adapter does not decide which payment method a\n * resource uses, it only reflects what the resource declares. `undefined`\n * when the resource lists none (still possible for a priced resource; the\n * pipeline is the one that decides what happens then, not this adapter).\n */\nfunction primaryPaymentMethod(resource: CommerceResource): PaymentMethodName | undefined {\n return resource.paymentMethods[0];\n}\n\n/** Human-facing note on how to supply a proof, generic when no rail is configured. */\nfunction paymentProofNote(resource: CommerceResource): string {\n const method = primaryPaymentMethod(resource);\n const rail = method !== undefined ? `a ${method}` : 'a';\n return `Requires ${rail} payment proof in the \"${PAYMENT_INPUT_FIELD}\" input field (obtained from a previous payment-required response).`;\n}\n\n/**\n * Description for the reserved `_payment` input property. Mentions x402's\n * `PAYMENT-SIGNATURE` header convention by name only when the resource\n * actually lists x402 as its method — a different future rail would have a\n * different proof encoding, so that detail must not be asserted for it.\n */\nfunction paymentInputFieldDescription(resource: CommerceResource): string {\n const method = primaryPaymentMethod(resource);\n if (method === 'x402') {\n return 'x402 payment proof (base64 PAYMENT-SIGNATURE value) returned from a previous payment-required response.';\n }\n if (method !== undefined) {\n return `${method} payment proof (base64-encoded) returned from a previous payment-required response.`;\n }\n return 'Payment proof returned from a previous payment-required response.';\n}\n\n/**\n * Tool description. For a paid resource this appends a clear, unavoidable\n * price notice so an agent can see the resource costs money before calling\n * it — never buried only in the input schema.\n */\nexport function buildToolDescription(resource: CommerceResource): string {\n const base = resource.description ?? resource.name;\n switch (resource.pricing.type) {\n case 'free':\n return base;\n case 'fixed': {\n const { amount, currency } = resource.pricing;\n return `${base} Costs ${amount} ${currency} per call. ${paymentProofNote(resource)}`;\n }\n case 'dynamic':\n return `${base} Requires payment (amount determined at request time). ${paymentProofNote(resource)}`;\n }\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Builds the MCP `Tool.inputSchema` from the canonical `CommerceResource.inputSchema`.\n *\n * The canonical schema is already JSON Schema, so it is carried through\n * verbatim (properties, descriptions, `required`, and any other JSON Schema\n * keyword) — only `type` is forced to the literal `'object'` MCP requires,\n * and `properties`/`required` are merged rather than replaced. For a paid\n * resource, the reserved optional `_payment` string property is added.\n */\nexport function buildInputSchema(resource: CommerceResource): Tool['inputSchema'] {\n const base = resource.inputSchema;\n const baseIsObject = isPlainObject(base);\n\n const basePropertyEntries: readonly [string, object][] =\n baseIsObject && isPlainObject(base.properties)\n ? Object.entries(base.properties).filter((entry): entry is [string, object] =>\n isPlainObject(entry[1]),\n )\n : [];\n const properties: Record<string, object> = Object.fromEntries(basePropertyEntries);\n\n if (isPaidResource(resource)) {\n // Overwrites any resource-declared `_payment` property. Config is\n // responsible for rejecting that collision at load time — this is not\n // re-checked here.\n properties[PAYMENT_INPUT_FIELD] = {\n type: 'string',\n description: paymentInputFieldDescription(resource),\n };\n }\n\n const required =\n baseIsObject && Array.isArray(base.required)\n ? base.required.filter((v): v is string => typeof v === 'string')\n : [];\n\n const extra = baseIsObject\n ? Object.fromEntries(\n Object.entries(base).filter(\n ([key]) => key !== 'type' && key !== 'properties' && key !== 'required',\n ),\n )\n : {};\n\n return {\n ...extra,\n type: 'object',\n properties,\n ...(required.length > 0 ? { required } : {}),\n };\n}\n","/**\n * MCP protocol adapter.\n *\n * One MCP tool per canonical resource exposed via `exposedVia: ['mcp']`.\n * Every `tools/call` builds a `CanonicalRequest` and goes through\n * `context.pipeline.execute()` — this file never calls a merchant backend and\n * never inspects a payment object, it only surfaces what the pipeline\n * returns.\n *\n * Transport: Streamable HTTP, **stateless** mode (no `sessionIdGenerator`,\n * i.e. session id generation left undefined). A fresh low-level `Server` +\n * `StreamableHTTPServerTransport` pair is created per HTTP request and torn\n * down when the response closes —\n * this is the pattern @modelcontextprotocol/sdk@1.30.0's own\n * `examples/server/simpleStatelessStreamableHttp.js` uses, and it avoids\n * holding cross-request session state the gateway has no lifecycle hook for.\n *\n * Tool registration uses the low-level `Server` (`setRequestHandler` for\n * `ListToolsRequestSchema` / `CallToolRequestSchema`) rather than the\n * higher-level `McpServer.registerTool`. `McpServer.registerTool`'s\n * `inputSchema` only accepts a Zod schema or a raw Zod shape\n * (`server/zod-compat.d.ts`: `AnySchema = z3.ZodTypeAny | z4.$ZodType`) — it\n * does not accept a raw JSON Schema object. The canonical\n * `CommerceResource.inputSchema` is already JSON Schema, and the MCP wire\n * format for `Tool.inputSchema` *is* JSON Schema, so building `Tool` objects\n * directly (via the low-level `Server`) carries it through verbatim with no\n * lossy JSON-Schema-to-Zod conversion. `Server` is marked `@deprecated` in\n * favour of `McpServer`'s ergonomics, but remains fully supported — its\n * documented use is exactly this kind of advanced, non-Zod case.\n *\n * Origin/Host validation (DNS-rebinding protection): deliberately NOT done\n * here. `StreamableHTTPServerTransport` is constructed with no\n * `allowedHosts`/`allowedOrigins`/`enableDnsRebindingProtection` — all three\n * are `@deprecated` in the pinned SDK's own\n * `webStandardStreamableHttp.d.ts`, in favour of exactly the fix applied\n * here: an allowlist enforced by the *host* before a request ever reaches an\n * adapter. `src/gateway`'s `onRequest` hook is that enforcement point —\n * it covers `/mcp` and the HTTP routes together, so there is one allowlist\n * for the whole gateway instead of one per adapter. This adapter has no\n * config surface to build a second one from: `McpAdapterOptions` is frozen\n * (docs/contracts.md) to `{ mountPath?, serverName?, serverVersion? }`, and\n * the only signal available without a contract change —\n * `context.publicBaseUrl` — is one string that may not match what a\n * reverse-proxied deployment's `Host`/`Origin` headers actually carry. A\n * second, narrower allowlist built from it would not add coverage the\n * gateway's hook doesn't already provide; it would only add a second place\n * that can reject legitimate traffic the gateway just allowed, for a\n * deprecated code path upstream is steering consumers away from. Revisit\n * this if the adapter is ever meant to be mounted somewhere other than this\n * gateway. See `descriptor.unsupported` — this reliance on the host is\n * recorded there too, not just here, so `doctor`/`.well-known` surface it.\n */\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';\nimport type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';\nimport {\n CallToolRequestSchema,\n type CallToolResult,\n ListToolsRequestSchema,\n type Tool,\n} from '@modelcontextprotocol/sdk/types.js';\nimport {\n type AdapterDescriptor,\n type AdapterHealth,\n type CanonicalRequest,\n CommerceError,\n type CommerceResource,\n type HttpProtocolAdapter,\n type ProtocolAdapterContext,\n toCommerceError,\n} from '../../core/index.js';\nimport { buildDescriptor, PACKAGE_VERSION } from './descriptor.js';\nimport { errorResult, extractPaymentSubmission, mapOutcome } from './result-mapping.js';\nimport {\n buildInputSchema,\n buildToolDescription,\n isValidToolName,\n MCP_TOOL_NAME_PATTERN,\n} from './tool-mapping.js';\n\nexport interface McpAdapterOptions {\n /** Path prefix the gateway mounts this adapter at. Default '/mcp'. */\n readonly mountPath?: string;\n /** MCP `Implementation.name` reported during initialize. */\n readonly serverName?: string;\n /** MCP `Implementation.version` reported during initialize. Default: this package's version. */\n readonly serverVersion?: string;\n}\n\ninterface RegisteredTool {\n readonly resource: CommerceResource;\n readonly tool: Tool;\n}\n\ninterface SkippedResource {\n readonly id: string;\n readonly reason: string;\n}\n\nconst DEFAULT_MOUNT_PATH = '/mcp';\nconst DEFAULT_SERVER_NAME = 'agent-commerce';\n\n/**\n * The pinned MCP SDK's Streamable HTTP transport\n * accepts a JSON-RPC **batch** (a bare array in the POST body) and dispatches\n * every element to this adapter's `tools/call` handler in one synchronous\n * `for` loop with no `await` between iterations and no cap on the array's\n * length (`webStandardStreamableHttp.js`'s `handlePostRequest`, via\n * `shared/protocol.js`'s `_onrequest`, which fires the handler and returns\n * without waiting for it to settle). Nothing between the transport and this\n * adapter enforces stateless mode's own precondition that `tools/call`\n * requires no prior `initialize` — so one POST, no handshake, N `tools/call`\n * messages, is a legal request that becomes N concurrent\n * `context.pipeline.execute()` calls, each of which may end in a live\n * `fetch()` to the merchant's backend. 8 keeps a handful of genuinely\n * concurrent tool calls (the common case for an agent working a multi-step\n * task) from ever queuing, while still bounding the worst case to a small,\n * fixed number of simultaneous outbound connections regardless of how large\n * a batch a caller sends. The worst case measured without it was 5000\n * concurrent backend calls from a single request.\n */\nconst MAX_CONCURRENT_TOOL_CALLS = 8;\n\n/**\n * The semaphore above bounds concurrency but not\n * queue depth — `acquireToolCallSlot` pushed one resolver per waiting call\n * onto `toolCallWaiters` with no ceiling, so an oversized batch (thousands\n * of `tools/call` messages, still well under the gateway's own 1 MB body\n * cap) queued in full and then *ran* in full, including the ~30 seconds\n * after the client had already disconnected. 64 is 8x\n * MAX_CONCURRENT_TOOL_CALLS: enough that a legitimate short burst from one\n * agent never gets rejected (the measured honest case tops out at a\n * handful of concurrent calls), while capping the adapter's total\n * exposure — in flight plus queued — to a small, fixed number of real\n * `pipeline.execute()` calls no matter how large a batch a caller sends.\n * Calls beyond the queue fail fast with no backend call at all, rather\n * than piling up behind it.\n *\n * Scope note: this cap is per `McpProtocolAdapter` instance.\n * The gateway's own SSE-subscriber cap is per gateway instance. Both\n * happen to be one-per-process today, so the two read the same in\n * practice — but they are not the same scope, and that stops being true\n * the moment either one is ever instantiated more than once per process.\n */\nconst MAX_QUEUED_TOOL_CALLS = 64;\n\nexport class McpProtocolAdapter implements HttpProtocolAdapter {\n readonly name = 'mcp' as const;\n readonly mountPath: string;\n readonly descriptor: AdapterDescriptor;\n\n private readonly serverName: string;\n private readonly serverVersion: string;\n\n private context: ProtocolAdapterContext | undefined;\n private started = false;\n private tools: readonly RegisteredTool[] = [];\n private toolsByResourceId: ReadonlyMap<string, CommerceResource> = new Map();\n private skipped: readonly SkippedResource[] = [];\n private readonly activeTransports = new Set<StreamableHTTPServerTransport>();\n\n // Counting semaphore bounding concurrent `context.pipeline.execute()`\n // calls. Lives on the adapter instance (one per gateway mount, for the\n // process lifetime), not per-request, so the cap holds across concurrent\n // `/mcp` requests too — not just within one oversized batch. A request\n // only ever waits here once MAX_CONCURRENT_TOOL_CALLS executions are\n // already in flight adapter-wide, which is the throttle working as\n // intended, not two unrelated single-call requests blocking each other.\n private inFlightToolCalls = 0;\n private readonly toolCallWaiters: Array<() => void> = [];\n\n constructor(options: McpAdapterOptions = {}) {\n this.mountPath = options.mountPath ?? DEFAULT_MOUNT_PATH;\n this.serverName = options.serverName ?? DEFAULT_SERVER_NAME;\n this.serverVersion = options.serverVersion ?? PACKAGE_VERSION;\n this.descriptor = buildDescriptor(PACKAGE_VERSION);\n }\n\n async start(context: ProtocolAdapterContext): Promise<void> {\n this.context = context;\n this.started = false;\n\n let resources: readonly CommerceResource[] = [];\n try {\n resources = context.resources.listExposedVia('mcp');\n } catch (err) {\n context.logger.error(\n { adapter: 'mcp', err: toCommerceError(err).toInfo() },\n 'mcp adapter: failed to list mcp-exposed resources',\n );\n resources = [];\n }\n\n const tools: RegisteredTool[] = [];\n const toolsByResourceId = new Map<string, CommerceResource>();\n const skipped: SkippedResource[] = [];\n\n for (const resource of resources) {\n try {\n if (!isValidToolName(resource.id)) {\n skipped.push({\n id: resource.id,\n reason: `resource id is not a legal MCP tool name (must match ${MCP_TOOL_NAME_PATTERN.source})`,\n });\n continue;\n }\n if (toolsByResourceId.has(resource.id)) {\n skipped.push({ id: resource.id, reason: 'duplicate tool name' });\n continue;\n }\n const tool: Tool = {\n name: resource.id,\n description: buildToolDescription(resource),\n inputSchema: buildInputSchema(resource),\n };\n tools.push({ resource, tool });\n toolsByResourceId.set(resource.id, resource);\n } catch (err) {\n skipped.push({\n id: resource.id,\n reason: `failed to build MCP tool: ${toCommerceError(err).message}`,\n });\n }\n }\n\n for (const s of skipped) {\n context.logger.warn(\n { adapter: 'mcp', resourceId: s.id, reason: s.reason },\n 'mcp adapter: resource skipped',\n );\n }\n\n this.tools = tools;\n this.toolsByResourceId = toolsByResourceId;\n this.skipped = skipped;\n this.started = true;\n\n context.logger.info(\n {\n adapter: 'mcp',\n mountPath: this.mountPath,\n toolCount: tools.length,\n skippedCount: skipped.length,\n },\n 'mcp adapter started',\n );\n }\n\n async handleHttp(req: IncomingMessage, res: ServerResponse): Promise<void> {\n try {\n if (!this.started || !this.context) {\n this.writeJsonRpcError(res, 503, 'MCP adapter is not running.');\n return;\n }\n if (req.method !== 'POST') {\n this.writeJsonRpcError(res, 405, 'Method not allowed. This endpoint only accepts POST.');\n return;\n }\n\n // one AbortController per HTTP request, aborted\n // from the same `res` 'close' handler that already tears down the\n // transport/server pair. `handleToolCall` checks this after acquiring\n // its concurrency slot — never mid-`pipeline.execute()`, since a call\n // that already reached settlement must be allowed to finish (aborting\n // there is worse than finishing: the buyer may already be charged).\n const abortController = new AbortController();\n const server = this.buildServer(abortController.signal);\n // Stateless mode: omitting `sessionIdGenerator` (rather than setting it\n // to `undefined`) is required under `exactOptionalPropertyTypes`, and\n // has identical runtime behaviour — see\n // dist/esm/server/webStandardStreamableHttp.js: session handling is\n // gated on `!this.sessionIdGenerator`, true either way.\n const transport = new StreamableHTTPServerTransport();\n this.activeTransports.add(transport);\n\n const cleanup = (): void => {\n abortController.abort();\n this.activeTransports.delete(transport);\n transport.close().catch(() => {});\n server.close().catch(() => {});\n };\n res.once('close', cleanup);\n\n // `StreamableHTTPServerTransport implements Transport` per the SDK's\n // own declaration; the cast works around its `onclose`/`onerror`\n // accessors being typed `T | undefined` where `Transport` declares a\n // bare optional `T`, which only conflicts under this project's\n // `exactOptionalPropertyTypes`.\n await server.connect(transport as Transport);\n await transport.handleRequest(req, res);\n } catch (err) {\n this.context?.logger.error(\n { adapter: 'mcp', err: toCommerceError(err).toInfo() },\n 'mcp adapter: request handling failed',\n );\n this.writeJsonRpcError(res, 500, 'Internal server error.');\n }\n }\n\n async health(): Promise<AdapterHealth> {\n const checkedAt = this.context?.clock.nowIso() ?? new Date().toISOString();\n try {\n if (!this.started || !this.context) {\n return { status: 'fail', detail: 'MCP adapter has not been started.', checkedAt };\n }\n const toolCount = this.tools.length;\n if (this.skipped.length > 0) {\n const detail = `${toolCount} tool(s) registered; ${this.skipped.length} resource(s) skipped: ${this.skipped\n .map((s) => `${s.id} (${s.reason})`)\n .join('; ')}`;\n return { status: 'warn', detail, checkedAt };\n }\n return { status: 'pass', detail: `${toolCount} tool(s) registered.`, checkedAt };\n } catch (err) {\n return {\n status: 'fail',\n detail: `mcp adapter health check failed: ${toCommerceError(err).message}`,\n checkedAt,\n };\n }\n }\n\n async stop(): Promise<void> {\n this.started = false;\n const transports = [...this.activeTransports];\n this.activeTransports.clear();\n await Promise.all(\n transports.map(async (transport) => {\n try {\n await transport.close();\n } catch {\n // best-effort cleanup — stop() must be idempotent and never throw.\n }\n }),\n );\n this.context = undefined;\n }\n\n private writeJsonRpcError(res: ServerResponse, status: number, message: string): void {\n if (res.headersSent) return;\n res.writeHead(status, { 'content-type': 'application/json' });\n res.end(JSON.stringify({ jsonrpc: '2.0', error: { code: -32000, message }, id: null }));\n }\n\n private buildServer(signal: AbortSignal): Server {\n const server = new Server(\n { name: this.serverName, version: this.serverVersion },\n { capabilities: { tools: {} } },\n );\n server.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: this.tools.map((t) => t.tool),\n }));\n server.setRequestHandler(CallToolRequestSchema, async (request) =>\n this.handleToolCall(request.params.name, request.params.arguments ?? {}, signal),\n );\n return server;\n }\n\n private async handleToolCall(\n resourceId: string,\n rawArgs: Record<string, unknown>,\n signal: AbortSignal,\n ): Promise<CallToolResult> {\n const context = this.context;\n if (!context) {\n return errorResult(new CommerceError('INTERNAL_ERROR', 'MCP adapter is not running.'));\n }\n try {\n // Defence in depth: `tools/list` only ever advertises mcp-exposed,\n // legal-name resources, but a client can still send `tools/call` for\n // any name. Gate here too (core also enforces exposedVia in the\n // pipeline) — do not rely on core alone. Message stays identical to a\n // genuinely unknown id so we never reveal that a resource exists but\n // is scoped to another protocol.\n const resource = this.toolsByResourceId.get(resourceId);\n if (!resource) {\n return errorResult(\n new CommerceError('RESOURCE_NOT_FOUND', `Unknown tool \"${resourceId}\".`, { resourceId }),\n );\n }\n const { input, payment } = extractPaymentSubmission(rawArgs, resource);\n const request: CanonicalRequest = {\n requestId: context.ids.next('mcp'),\n resourceId,\n input,\n protocol: 'mcp',\n receivedAt: context.clock.nowIso(),\n ...(payment !== undefined ? { payment } : {}),\n };\n await this.acquireToolCallSlot(signal);\n try {\n // the only cancellation point. A call queued\n // behind a full semaphore, whose caller has since disconnected,\n // must not start a fresh pipeline.execute() (and possibly a live\n // merchant-backend fetch) — that is the \"runs for 30s after the\n // client left\" bug. Checked here and nowhere else: once execute()\n // is called it may reach settle(), and an in-flight payment must be\n // allowed to finish rather than be abandoned mid-flight.\n if (signal.aborted) {\n // deliberately *not* GATEWAY_BUSY. That code\n // means \"transient, back off and retry\" — true for the queue-full\n // case below, false here: there is no caller left to retry, so\n // telling one to would be meaningless. PROTOCOL_UNSUPPORTED is the\n // least dishonest fit among the frozen codes (non-retryable, which\n // is the one property that matters for a response nobody reads),\n // not a precise description of \"the caller went away\" — none of\n // the frozen codes names that condition. Left flagged as a known\n // gap rather than reused past what it's honestly for.\n return errorResult(\n new CommerceError(\n 'PROTOCOL_UNSUPPORTED',\n 'Client disconnected before this call started.',\n ),\n );\n }\n const outcome = await context.pipeline.execute(request);\n return mapOutcome(outcome);\n } finally {\n // Always release, even if execute() throws — a stranded permit\n // would shrink MAX_CONCURRENT_TOOL_CALLS by one forever and\n // eventually deadlock the adapter, which is worse.\n this.releaseToolCallSlot();\n }\n } catch (err) {\n return errorResult(toCommerceError(err));\n }\n }\n\n /**\n * Blocks until fewer than MAX_CONCURRENT_TOOL_CALLS executions are in\n * flight, or throws if the queue behind that gate is already full or the\n * caller disconnected while waiting. Throwing\n * here never leaks a permit: `inFlightToolCalls` is only incremented on\n * the success path below, after every rejection point.\n */\n private async acquireToolCallSlot(signal: AbortSignal): Promise<void> {\n if (this.toolCallWaiters.length >= MAX_QUEUED_TOOL_CALLS) {\n // GATEWAY_BUSY, not PROTOCOL_UNSUPPORTED. This\n // is load shedding, which is transient by definition — the caller\n // should back off and retry, matching the message below. Before\n // GATEWAY_BUSY existed this threw PROTOCOL_UNSUPPORTED (HTTP 501,\n // `retryable: false`), so the envelope told an agent framework keyed\n // on the machine-readable flag that a momentary throttle was a\n // permanent capability gap — contradicting this exact message.\n throw new CommerceError(\n 'GATEWAY_BUSY',\n 'Too many tool calls already queued on this adapter; retry later.',\n );\n }\n // `while`, not `if`. A wake-up only means a slot\n // was *freed*, not that this waiter is now entitled to it regardless of\n // what else has happened since — re-check the same condition the loop\n // waited on rather than assume one wake-up means one free slot forever.\n // (Currently that assumption would also happen to hold, since\n // `releaseToolCallSlot` decrements before waking the next waiter and JS\n // has no thread to race it — but that is a scheduling fact about this\n // file, not something `if` states, and it is exactly the kind of thing\n // a later refactor breaks silently. `while` doesn't depend on it.)\n while (this.inFlightToolCalls >= MAX_CONCURRENT_TOOL_CALLS) {\n await new Promise<void>((resolve) => this.toolCallWaiters.push(resolve));\n if (signal.aborted) {\n // This waiter is declining the slot that was just freed for it —\n // pass it straight to the next waiter in line instead of stranding\n // everyone behind it. Without this, a disconnect partway through a\n // deep queue leaves every later waiter's promise waiting on a\n // wake-up call that only its own dedicated release() would have\n // sent — and that release never comes, because this waiter never\n // takes the slot that would have produced it.\n this.toolCallWaiters.shift()?.();\n // PROTOCOL_UNSUPPORTED, not GATEWAY_BUSY —\n // same reasoning as the other disconnect check above. Non-retryable\n // is correct here (nobody is listening to retry); \"unsupported\" is\n // not a precise name for \"the caller left\", it's just the least\n // dishonest fit among the frozen codes.\n throw new CommerceError('PROTOCOL_UNSUPPORTED', 'Client disconnected while queued.');\n }\n }\n this.inFlightToolCalls++;\n }\n\n private releaseToolCallSlot(): void {\n this.inFlightToolCalls--;\n // Wake the oldest waiter, if any; it will re-increment once it resumes.\n this.toolCallWaiters.shift()?.();\n }\n}\n\nexport function createMcpAdapter(options?: McpAdapterOptions): HttpProtocolAdapter {\n return new McpProtocolAdapter(options ?? {});\n}\n"]}
1
+ {"version":3,"sources":["../src/protocols/mcp/descriptor.ts","../src/protocols/mcp/result-mapping.ts","../src/protocols/mcp/tool-mapping.ts","../src/protocols/mcp/adapter.ts"],"names":[],"mappings":";;;;;AAsBO,IAAM,kBAAA,GAAqB,uBAAA;AAG3B,IAAM,gBAAA,GAAsC,CAAC,YAAA,EAAc,YAAY,CAAA;AAcvE,IAAM,eAAA,GAAqC;AAAA,EAChD,WAAA;AAAA,EACA,SAAA;AAAA,EACA,UAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,OAAA;AAAA,EACA,SAAA;AAAA,EACA,kCAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAA;AAEO,SAAS,gBAAgB,qBAAA,EAAkD;AAChF,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,KAAA;AAAA,IACN,IAAA,EAAM,UAAA;AAAA,IACN,qBAAA;AAAA,IACA,aAAA,EAAe,kBAAA;AAAA,IACf,YAAA,EAAc,gBAAA;AAAA,IACd,MAAA,EAAQ,QAAA;AAAA,IACR,WAAA,EAAa;AAAA,GACf;AACF;;;AC1CA,SAAS,SAAS,KAAA,EAAwC;AACxD,EAAA,OAAO,KAAA;AACT;AAEO,SAAS,gBAAgB,OAAA,EAA2C;AACzE,EAAA,MAAM,OAAO,OAAA,CAAQ,IAAA;AACrB,EAAA,MAAM,IAAA,GAAO,OAAO,IAAA,KAAS,QAAA,GAAW,OAAO,IAAA,CAAK,SAAA,CAAU,QAAQ,IAAI,CAAA;AAC1E,EAAA,MAAM,YAAA,GAAe,OAAO,IAAA,KAAS,QAAA,IAAY,SAAS,IAAA,IAAQ,CAAC,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA;AACrF,EAAA,OAAO;AAAA,IACL,SAAS,CAAC,EAAE,IAAA,EAAM,MAAA,EAAQ,MAAM,CAAA;AAAA,IAChC,GAAI,eAAe,EAAE,iBAAA,EAAmB,SAAS,IAAI,CAAA,KAAM,EAAC;AAAA,IAC5D,KAAA,EAAO,EAAE,CAAC,yBAAyB,GAAG,QAAA,CAAS,iBAAA,CAAkB,OAAO,CAAC,CAAA;AAAE,GAC7E;AACF;AAEO,SAAS,sBAAsB,OAAA,EAAiD;AACrF,EAAA,MAAM,QAAA,GAAW,0BAA0B,OAAO,CAAA;AAClD,EAAA,MAAM,IAAI,QAAA,CAAS,OAAA;AACnB,EAAA,MAAM,OAAO,CAAA,kBAAA,EAAqB,CAAA,CAAE,MAAM,CAAA,CAAA,EAAI,EAAE,QAAQ,CAAA,IAAA,EAAO,CAAA,CAAE,WAAW,kBAAkB,OAAA,CAAQ,UAAU,4BAA4B,CAAA,CAAE,QAAQ,0BAA0B,mBAAmB,CAAA,cAAA,CAAA;AACnM,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,IAAA;AAAA,IACT,SAAS,CAAC,EAAE,IAAA,EAAM,MAAA,EAAQ,MAAM,CAAA;AAAA,IAChC,iBAAA,EAAmB,SAAS,QAAQ;AAAA,GACtC;AACF;AAEO,SAAS,YAAY,KAAA,EAAsC;AAChE,EAAA,MAAM,QAAA,GAAW,gBAAgB,KAAK,CAAA;AACtC,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,IAAA;AAAA,IACT,OAAA,EAAS,CAAC,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,CAAA,EAAG,QAAA,CAAS,IAAI,CAAA,EAAA,EAAK,QAAA,CAAS,OAAO,IAAI,CAAA;AAAA,IACzE,iBAAA,EAAmB,SAAS,QAAQ;AAAA,GACtC;AACF;AAEO,SAAS,WAAW,OAAA,EAA2C;AACpE,EAAA,OAAO,QAAQ,IAAA,KAAS,WAAA,GAAc,gBAAgB,OAAO,CAAA,GAAI,sBAAsB,OAAO,CAAA;AAChG;;;AC/BO,IAAM,qBAAA,GAAwB,yBAAA;AAE9B,SAAS,gBAAgB,EAAA,EAAqB;AACnD,EAAA,OAAO,qBAAA,CAAsB,KAAK,EAAE,CAAA;AACtC;AAEO,SAAS,eAAe,QAAA,EAAqC;AAClE,EAAA,OAAO,QAAA,CAAS,QAAQ,IAAA,KAAS,MAAA;AACnC;AASA,SAAS,qBAAqB,QAAA,EAA2D;AACvF,EAAA,OAAO,QAAA,CAAS,eAAe,CAAC,CAAA;AAClC;AAGA,SAAS,iBAAiB,QAAA,EAAoC;AAC5D,EAAA,MAAM,MAAA,GAAS,qBAAqB,QAAQ,CAAA;AAC5C,EAAA,MAAM,IAAA,GAAO,MAAA,KAAW,MAAA,GAAY,CAAA,EAAA,EAAK,MAAM,CAAA,CAAA,GAAK,GAAA;AACpD,EAAA,OAAO,CAAA,SAAA,EAAY,IAAI,CAAA,uBAAA,EAA0B,mBAAmB,CAAA,mEAAA,CAAA;AACtE;AAQA,SAAS,6BAA6B,QAAA,EAAoC;AACxE,EAAA,MAAM,MAAA,GAAS,qBAAqB,QAAQ,CAAA;AAC5C,EAAA,IAAI,WAAW,MAAA,EAAQ;AACrB,IAAA,OAAO,yGAAA;AAAA,EACT;AACA,EAAA,IAAI,WAAW,MAAA,EAAW;AACxB,IAAA,OAAO,GAAG,MAAM,CAAA,mFAAA,CAAA;AAAA,EAClB;AACA,EAAA,OAAO,mEAAA;AACT;AAOO,SAAS,qBAAqB,QAAA,EAAoC;AACvE,EAAA,MAAM,IAAA,GAAO,QAAA,CAAS,WAAA,IAAe,QAAA,CAAS,IAAA;AAC9C,EAAA,QAAQ,QAAA,CAAS,QAAQ,IAAA;AAAM,IAC7B,KAAK,MAAA;AACH,MAAA,OAAO,IAAA;AAAA,IACT,KAAK,OAAA,EAAS;AACZ,MAAA,MAAM,EAAE,MAAA,EAAQ,QAAA,EAAS,GAAI,QAAA,CAAS,OAAA;AACtC,MAAA,OAAO,CAAA,EAAG,IAAI,CAAA,OAAA,EAAU,MAAM,IAAI,QAAQ,CAAA,WAAA,EAAc,gBAAA,CAAiB,QAAQ,CAAC,CAAA,CAAA;AAAA,IACpF;AAAA,IACA,KAAK,SAAA;AACH,MAAA,OAAO,CAAA,EAAG,IAAI,CAAA,uDAAA,EAA0D,gBAAA,CAAiB,QAAQ,CAAC,CAAA,CAAA;AAAA;AAExG;AAEA,SAAS,cAAc,KAAA,EAAkD;AACvE,EAAA,OAAO,OAAO,UAAU,QAAA,IAAY,KAAA,KAAU,QAAQ,CAAC,KAAA,CAAM,QAAQ,KAAK,CAAA;AAC5E;AAWO,SAAS,iBAAiB,QAAA,EAAiD;AAChF,EAAA,MAAM,OAAO,QAAA,CAAS,WAAA;AACtB,EAAA,MAAM,YAAA,GAAe,cAAc,IAAI,CAAA;AAEvC,EAAA,MAAM,mBAAA,GACJ,YAAA,IAAgB,aAAA,CAAc,IAAA,CAAK,UAAU,IACzC,MAAA,CAAO,OAAA,CAAQ,IAAA,CAAK,UAAU,CAAA,CAAE,MAAA;AAAA,IAAO,CAAC,KAAA,KACtC,aAAA,CAAc,KAAA,CAAM,CAAC,CAAC;AAAA,MAExB,EAAC;AACP,EAAA,MAAM,UAAA,GAAqC,MAAA,CAAO,WAAA,CAAY,mBAAmB,CAAA;AAEjF,EAAA,IAAI,cAAA,CAAe,QAAQ,CAAA,EAAG;AAI5B,IAAA,UAAA,CAAW,mBAAmB,CAAA,GAAI;AAAA,MAChC,IAAA,EAAM,QAAA;AAAA,MACN,WAAA,EAAa,6BAA6B,QAAQ;AAAA,KACpD;AAAA,EACF;AAEA,EAAA,MAAM,WACJ,YAAA,IAAgB,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,QAAQ,CAAA,GACvC,IAAA,CAAK,QAAA,CAAS,MAAA,CAAO,CAAC,CAAA,KAAmB,OAAO,CAAA,KAAM,QAAQ,IAC9D,EAAC;AAEP,EAAA,MAAM,KAAA,GAAQ,eACV,MAAA,CAAO,WAAA;AAAA,IACL,MAAA,CAAO,OAAA,CAAQ,IAAI,CAAA,CAAE,MAAA;AAAA,MACnB,CAAC,CAAC,GAAG,CAAA,KAAM,QAAQ,MAAA,IAAU,GAAA,KAAQ,gBAAgB,GAAA,KAAQ;AAAA;AAC/D,MAEF,EAAC;AAEL,EAAA,OAAO;AAAA,IACL,GAAG,KAAA;AAAA,IACH,IAAA,EAAM,QAAA;AAAA,IACN,UAAA;AAAA,IACA,GAAI,QAAA,CAAS,MAAA,GAAS,IAAI,EAAE,QAAA,KAAa;AAAC,GAC5C;AACF;;;AC3CA,IAAM,kBAAA,GAAqB,MAAA;AAC3B,IAAM,mBAAA,GAAsB,gBAAA;AAqB5B,IAAM,yBAAA,GAA4B,CAAA;AAuBlC,IAAM,qBAAA,GAAwB,EAAA;AAEvB,IAAM,qBAAN,MAAwD;AAAA,EACpD,IAAA,GAAO,KAAA;AAAA,EACP,SAAA;AAAA,EACA,UAAA;AAAA,EAEQ,UAAA;AAAA,EACA,aAAA;AAAA,EAET,OAAA;AAAA,EACA,OAAA,GAAU,KAAA;AAAA,EACV,QAAmC,EAAC;AAAA,EACpC,iBAAA,uBAA+D,GAAA,EAAI;AAAA,EACnE,UAAsC,EAAC;AAAA,EAC9B,gBAAA,uBAAuB,GAAA,EAAmC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASnE,iBAAA,GAAoB,CAAA;AAAA,EACX,kBAAqC,EAAC;AAAA,EAEvD,WAAA,CAAY,OAAA,GAA6B,EAAC,EAAG;AAC3C,IAAA,IAAA,CAAK,SAAA,GAAY,QAAQ,SAAA,IAAa,kBAAA;AACtC,IAAA,IAAA,CAAK,UAAA,GAAa,QAAQ,UAAA,IAAc,mBAAA;AACxC,IAAA,IAAA,CAAK,aAAA,GAAgB,QAAQ,aAAA,IAAiB,eAAA;AAC9C,IAAA,IAAA,CAAK,UAAA,GAAa,gBAAgB,eAAe,CAAA;AAAA,EACnD;AAAA,EAEA,MAAM,MAAM,OAAA,EAAgD;AAC1D,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AACf,IAAA,IAAA,CAAK,OAAA,GAAU,KAAA;AAEf,IAAA,IAAI,YAAyC,EAAC;AAC9C,IAAA,IAAI;AACF,MAAA,SAAA,GAAY,OAAA,CAAQ,SAAA,CAAU,cAAA,CAAe,KAAK,CAAA;AAAA,IACpD,SAAS,GAAA,EAAK;AACZ,MAAA,OAAA,CAAQ,MAAA,CAAO,KAAA;AAAA,QACb,EAAE,SAAS,KAAA,EAAO,GAAA,EAAK,gBAAgB,GAAG,CAAA,CAAE,QAAO,EAAE;AAAA,QACrD;AAAA,OACF;AACA,MAAA,SAAA,GAAY,EAAC;AAAA,IACf;AAEA,IAAA,MAAM,QAA0B,EAAC;AACjC,IAAA,MAAM,iBAAA,uBAAwB,GAAA,EAA8B;AAC5D,IAAA,MAAM,UAA6B,EAAC;AAEpC,IAAA,KAAA,MAAW,YAAY,SAAA,EAAW;AAChC,MAAA,IAAI;AACF,QAAA,IAAI,CAAC,eAAA,CAAgB,QAAA,CAAS,EAAE,CAAA,EAAG;AACjC,UAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,YACX,IAAI,QAAA,CAAS,EAAA;AAAA,YACb,MAAA,EAAQ,CAAA,qDAAA,EAAwD,qBAAA,CAAsB,MAAM,CAAA,CAAA;AAAA,WAC7F,CAAA;AACD,UAAA;AAAA,QACF;AACA,QAAA,IAAI,iBAAA,CAAkB,GAAA,CAAI,QAAA,CAAS,EAAE,CAAA,EAAG;AACtC,UAAA,OAAA,CAAQ,KAAK,EAAE,EAAA,EAAI,SAAS,EAAA,EAAI,MAAA,EAAQ,uBAAuB,CAAA;AAC/D,UAAA;AAAA,QACF;AACA,QAAA,MAAM,IAAA,GAAa;AAAA,UACjB,MAAM,QAAA,CAAS,EAAA;AAAA,UACf,WAAA,EAAa,qBAAqB,QAAQ,CAAA;AAAA,UAC1C,WAAA,EAAa,iBAAiB,QAAQ;AAAA,SACxC;AACA,QAAA,KAAA,CAAM,IAAA,CAAK,EAAE,QAAA,EAAU,IAAA,EAAM,CAAA;AAC7B,QAAA,iBAAA,CAAkB,GAAA,CAAI,QAAA,CAAS,EAAA,EAAI,QAAQ,CAAA;AAAA,MAC7C,SAAS,GAAA,EAAK;AACZ,QAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,UACX,IAAI,QAAA,CAAS,EAAA;AAAA,UACb,MAAA,EAAQ,CAAA,0BAAA,EAA6B,eAAA,CAAgB,GAAG,EAAE,OAAO,CAAA;AAAA,SAClE,CAAA;AAAA,MACH;AAAA,IACF;AAEA,IAAA,KAAA,MAAW,KAAK,OAAA,EAAS;AACvB,MAAA,OAAA,CAAQ,MAAA,CAAO,IAAA;AAAA,QACb,EAAE,SAAS,KAAA,EAAO,UAAA,EAAY,EAAE,EAAA,EAAI,MAAA,EAAQ,EAAE,MAAA,EAAO;AAAA,QACrD;AAAA,OACF;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,KAAA,GAAQ,KAAA;AACb,IAAA,IAAA,CAAK,iBAAA,GAAoB,iBAAA;AACzB,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AACf,IAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AAEf,IAAA,OAAA,CAAQ,MAAA,CAAO,IAAA;AAAA,MACb;AAAA,QACE,OAAA,EAAS,KAAA;AAAA,QACT,WAAW,IAAA,CAAK,SAAA;AAAA,QAChB,WAAW,KAAA,CAAM,MAAA;AAAA,QACjB,cAAc,OAAA,CAAQ;AAAA,OACxB;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAAA,EAEA,MAAM,UAAA,CAAW,GAAA,EAAsB,GAAA,EAAoC;AACzE,IAAA,IAAI;AACF,MAAA,IAAI,CAAC,IAAA,CAAK,OAAA,IAAW,CAAC,KAAK,OAAA,EAAS;AAClC,QAAA,IAAA,CAAK,iBAAA,CAAkB,GAAA,EAAK,GAAA,EAAK,6BAA6B,CAAA;AAC9D,QAAA;AAAA,MACF;AACA,MAAA,IAAI,GAAA,CAAI,WAAW,MAAA,EAAQ;AACzB,QAAA,IAAA,CAAK,iBAAA,CAAkB,GAAA,EAAK,GAAA,EAAK,sDAAsD,CAAA;AACvF,QAAA;AAAA,MACF;AAQA,MAAA,MAAM,eAAA,GAAkB,IAAI,eAAA,EAAgB;AAC5C,MAAA,MAAM,MAAA,GAAS,IAAA,CAAK,WAAA,CAAY,eAAA,CAAgB,MAAM,CAAA;AAMtD,MAAA,MAAM,SAAA,GAAY,IAAI,6BAAA,EAA8B;AACpD,MAAA,IAAA,CAAK,gBAAA,CAAiB,IAAI,SAAS,CAAA;AAEnC,MAAA,MAAM,UAAU,MAAY;AAC1B,QAAA,eAAA,CAAgB,KAAA,EAAM;AACtB,QAAA,IAAA,CAAK,gBAAA,CAAiB,OAAO,SAAS,CAAA;AACtC,QAAA,SAAA,CAAU,KAAA,EAAM,CAAE,KAAA,CAAM,MAAM;AAAA,QAAC,CAAC,CAAA;AAChC,QAAA,MAAA,CAAO,KAAA,EAAM,CAAE,KAAA,CAAM,MAAM;AAAA,QAAC,CAAC,CAAA;AAAA,MAC/B,CAAA;AACA,MAAA,GAAA,CAAI,IAAA,CAAK,SAAS,OAAO,CAAA;AAOzB,MAAA,MAAM,MAAA,CAAO,QAAQ,SAAsB,CAAA;AAC3C,MAAA,MAAM,SAAA,CAAU,aAAA,CAAc,GAAA,EAAK,GAAG,CAAA;AAAA,IACxC,SAAS,GAAA,EAAK;AACZ,MAAA,IAAA,CAAK,SAAS,MAAA,CAAO,KAAA;AAAA,QACnB,EAAE,SAAS,KAAA,EAAO,GAAA,EAAK,gBAAgB,GAAG,CAAA,CAAE,QAAO,EAAE;AAAA,QACrD;AAAA,OACF;AACA,MAAA,IAAA,CAAK,iBAAA,CAAkB,GAAA,EAAK,GAAA,EAAK,wBAAwB,CAAA;AAAA,IAC3D;AAAA,EACF;AAAA,EAEA,MAAM,MAAA,GAAiC;AACrC,IAAA,MAAM,SAAA,GAAY,KAAK,OAAA,EAAS,KAAA,CAAM,QAAO,IAAA,iBAAK,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AACzE,IAAA,IAAI;AACF,MAAA,IAAI,CAAC,IAAA,CAAK,OAAA,IAAW,CAAC,KAAK,OAAA,EAAS;AAClC,QAAA,OAAO,EAAE,MAAA,EAAQ,MAAA,EAAQ,MAAA,EAAQ,qCAAqC,SAAA,EAAU;AAAA,MAClF;AACA,MAAA,MAAM,SAAA,GAAY,KAAK,KAAA,CAAM,MAAA;AAC7B,MAAA,IAAI,IAAA,CAAK,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAG;AAC3B,QAAA,MAAM,MAAA,GAAS,GAAG,SAAS,CAAA,qBAAA,EAAwB,KAAK,OAAA,CAAQ,MAAM,CAAA,sBAAA,EAAyB,IAAA,CAAK,OAAA,CACjG,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,EAAG,CAAA,CAAE,EAAE,CAAA,EAAA,EAAK,CAAA,CAAE,MAAM,CAAA,CAAA,CAAG,CAAA,CAClC,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA;AACb,QAAA,OAAO,EAAE,MAAA,EAAQ,MAAA,EAAQ,MAAA,EAAQ,SAAA,EAAU;AAAA,MAC7C;AACA,MAAA,OAAO,EAAE,MAAA,EAAQ,MAAA,EAAQ,QAAQ,CAAA,EAAG,SAAS,wBAAwB,SAAA,EAAU;AAAA,IACjF,SAAS,GAAA,EAAK;AACZ,MAAA,OAAO;AAAA,QACL,MAAA,EAAQ,MAAA;AAAA,QACR,MAAA,EAAQ,CAAA,iCAAA,EAAoC,eAAA,CAAgB,GAAG,EAAE,OAAO,CAAA,CAAA;AAAA,QACxE;AAAA,OACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,IAAA,GAAsB;AAC1B,IAAA,IAAA,CAAK,OAAA,GAAU,KAAA;AACf,IAAA,MAAM,UAAA,GAAa,CAAC,GAAG,IAAA,CAAK,gBAAgB,CAAA;AAC5C,IAAA,IAAA,CAAK,iBAAiB,KAAA,EAAM;AAC5B,IAAA,MAAM,OAAA,CAAQ,GAAA;AAAA,MACZ,UAAA,CAAW,GAAA,CAAI,OAAO,SAAA,KAAc;AAClC,QAAA,IAAI;AACF,UAAA,MAAM,UAAU,KAAA,EAAM;AAAA,QACxB,CAAA,CAAA,MAAQ;AAAA,QAER;AAAA,MACF,CAAC;AAAA,KACH;AACA,IAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AAAA,EACjB;AAAA,EAEQ,iBAAA,CAAkB,GAAA,EAAqB,MAAA,EAAgB,OAAA,EAAuB;AACpF,IAAA,IAAI,IAAI,WAAA,EAAa;AACrB,IAAA,GAAA,CAAI,SAAA,CAAU,MAAA,EAAQ,EAAE,cAAA,EAAgB,oBAAoB,CAAA;AAC5D,IAAA,GAAA,CAAI,GAAA,CAAI,IAAA,CAAK,SAAA,CAAU,EAAE,SAAS,KAAA,EAAO,KAAA,EAAO,EAAE,IAAA,EAAM,OAAQ,OAAA,EAAQ,EAAG,EAAA,EAAI,IAAA,EAAM,CAAC,CAAA;AAAA,EACxF;AAAA,EAEQ,YAAY,MAAA,EAA6B;AAC/C,IAAA,MAAM,SAAS,IAAI,MAAA;AAAA,MACjB,EAAE,IAAA,EAAM,IAAA,CAAK,UAAA,EAAY,OAAA,EAAS,KAAK,aAAA,EAAc;AAAA,MACrD,EAAE,YAAA,EAAc,EAAE,KAAA,EAAO,IAAG;AAAE,KAChC;AACA,IAAA,MAAA,CAAO,iBAAA,CAAkB,wBAAwB,aAAa;AAAA,MAC5D,OAAO,IAAA,CAAK,KAAA,CAAM,IAAI,CAAC,CAAA,KAAM,EAAE,IAAI;AAAA,KACrC,CAAE,CAAA;AACF,IAAA,MAAA,CAAO,iBAAA;AAAA,MAAkB,qBAAA;AAAA,MAAuB,OAAO,OAAA,KACrD,IAAA,CAAK,cAAA,CAAe,OAAA,CAAQ,MAAA,CAAO,IAAA,EAAM,OAAA,CAAQ,MAAA,CAAO,SAAA,IAAa,EAAC,EAAG,MAAM;AAAA,KACjF;AACA,IAAA,OAAO,MAAA;AAAA,EACT;AAAA,EAEA,MAAc,cAAA,CACZ,UAAA,EACA,OAAA,EACA,MAAA,EACyB;AACzB,IAAA,MAAM,UAAU,IAAA,CAAK,OAAA;AACrB,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,OAAO,WAAA,CAAY,IAAI,aAAA,CAAc,gBAAA,EAAkB,6BAA6B,CAAC,CAAA;AAAA,IACvF;AACA,IAAA,IAAI;AAOF,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,iBAAA,CAAkB,GAAA,CAAI,UAAU,CAAA;AACtD,MAAA,IAAI,CAAC,QAAA,EAAU;AACb,QAAA,OAAO,WAAA;AAAA,UACL,IAAI,cAAc,oBAAA,EAAsB,CAAA,cAAA,EAAiB,UAAU,CAAA,EAAA,CAAA,EAAM,EAAE,YAAY;AAAA,SACzF;AAAA,MACF;AACA,MAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,GAAA,CAAI,IAAA,CAAK,KAAK,CAAA;AACxC,MAAA,MAAM,EAAE,KAAA,EAAO,OAAA,EAAS,aAAA,EAAc,GAAI,0BAAA;AAAA,QACxC,OAAA;AAAA,QACA,QAAA;AAAA,QACA;AAAA,OACF;AACA,MAAA,MAAM,OAAA,GAA4B;AAAA,QAChC,SAAA;AAAA,QACA,UAAA;AAAA,QACA,KAAA;AAAA,QACA,QAAA,EAAU,KAAA;AAAA,QACV,UAAA,EAAY,OAAA,CAAQ,KAAA,CAAM,MAAA,EAAO;AAAA,QACjC,GAAI,OAAA,KAAY,KAAA,CAAA,GAAY,EAAE,OAAA,KAAY,EAAC;AAAA,QAC3C,GAAI,aAAA,KAAkB,KAAA,CAAA,GAAY,EAAE,aAAA,KAAkB;AAAC,OACzD;AACA,MAAA,MAAM,IAAA,CAAK,oBAAoB,MAAM,CAAA;AACrC,MAAA,IAAI;AAQF,QAAA,IAAI,OAAO,OAAA,EAAS;AAUlB,UAAA,OAAO,WAAA;AAAA,YACL,IAAI,aAAA;AAAA,cACF,sBAAA;AAAA,cACA;AAAA;AACF,WACF;AAAA,QACF;AACA,QAAA,MAAM,OAAA,GAAU,MAAM,OAAA,CAAQ,QAAA,CAAS,QAAQ,OAAO,CAAA;AACtD,QAAA,OAAO,WAAW,OAAO,CAAA;AAAA,MAC3B,CAAA,SAAE;AAIA,QAAA,IAAA,CAAK,mBAAA,EAAoB;AAAA,MAC3B;AAAA,IACF,SAAS,GAAA,EAAK;AACZ,MAAA,OAAO,WAAA,CAAY,eAAA,CAAgB,GAAG,CAAC,CAAA;AAAA,IACzC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,oBAAoB,MAAA,EAAoC;AACpE,IAAA,IAAI,IAAA,CAAK,eAAA,CAAgB,MAAA,IAAU,qBAAA,EAAuB;AAQxD,MAAA,MAAM,IAAI,aAAA;AAAA,QACR,cAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF;AAUA,IAAA,OAAO,IAAA,CAAK,qBAAqB,yBAAA,EAA2B;AAC1D,MAAA,MAAM,IAAI,QAAc,CAAC,OAAA,KAAY,KAAK,eAAA,CAAgB,IAAA,CAAK,OAAO,CAAC,CAAA;AACvE,MAAA,IAAI,OAAO,OAAA,EAAS;AAQlB,QAAA,IAAA,CAAK,eAAA,CAAgB,OAAM,IAAI;AAM/B,QAAA,MAAM,IAAI,aAAA,CAAc,sBAAA,EAAwB,mCAAmC,CAAA;AAAA,MACrF;AAAA,IACF;AACA,IAAA,IAAA,CAAK,iBAAA,EAAA;AAAA,EACP;AAAA,EAEQ,mBAAA,GAA4B;AAClC,IAAA,IAAA,CAAK,iBAAA,EAAA;AAEL,IAAA,IAAA,CAAK,eAAA,CAAgB,OAAM,IAAI;AAAA,EACjC;AACF,CAAA;AAEO,SAAS,iBAAiB,OAAA,EAAkD;AACjF,EAAA,OAAO,IAAI,kBAAA,CAAmB,OAAA,IAAW,EAAE,CAAA;AAC7C","file":"mcp.js","sourcesContent":["/**\n * Adapter self-description.\n *\n * `supportedSpec` reports the MCP protocol revision this adapter targets, as\n * negotiated by the installed @modelcontextprotocol/sdk@1.30.0 build.\n *\n * Verified against the shipped SDK (not guessed):\n * `dist/esm/types.js` exports `LATEST_PROTOCOL_VERSION = '2025-11-25'` and\n * `SUPPORTED_PROTOCOL_VERSIONS = [LATEST_PROTOCOL_VERSION, '2025-06-18',\n * '2025-03-26', '2024-11-05', '2024-10-07']`. `dist/esm/server/index.js`\n * (`_oninitialize`) negotiates by echoing the client-requested version when\n * it is in `SUPPORTED_PROTOCOL_VERSIONS`, and falling back to\n * `LATEST_PROTOCOL_VERSION` otherwise — so `LATEST_PROTOCOL_VERSION` is the\n * single most accurate value to report as \"the\" supported spec revision.\n */\nimport { LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/sdk/types.js';\nimport type { AdapterDescriptor } from '../../core/index.js';\n\n/** This package's own version — independent of the negotiated MCP spec revision. */\nexport { PACKAGE_VERSION } from '../../version.js';\n\n/** The MCP protocol revision this adapter targets (see module doc above). */\nexport const MCP_SUPPORTED_SPEC = LATEST_PROTOCOL_VERSION;\n\n/** Tool-oriented capabilities this adapter actually implements. */\nexport const MCP_CAPABILITIES: readonly string[] = ['tools/list', 'tools/call'];\n\n/**\n * MCP surfaces this adapter does not implement in this release. Kept explicit\n * so `doctor` / the support matrix never imply blanket protocol compatibility.\n *\n * `dns-rebinding-protection` is not a missing *feature* so much as a\n * delegated one: this transport does not validate `Origin`/`Host` itself\n * (see adapter.ts's module doc for why) — the gateway's `onRequest` hook\n * does, for `/mcp` and the HTTP routes together. Listed here so alpha\n * honesty holds even for a security property, not just a protocol surface:\n * an operator reading this adapter's own descriptor should not conclude it\n * provides Origin validation on its own.\n */\nexport const MCP_UNSUPPORTED: readonly string[] = [\n 'resources',\n 'prompts',\n 'sampling',\n 'completions',\n 'elicitation',\n 'roots',\n 'logging',\n 'notifications/tools/list_changed',\n 'tasks',\n 'dns-rebinding-protection',\n];\n\nexport function buildDescriptor(implementationVersion: string): AdapterDescriptor {\n return {\n name: 'mcp',\n kind: 'protocol',\n implementationVersion,\n supportedSpec: MCP_SUPPORTED_SPEC,\n capabilities: MCP_CAPABILITIES,\n status: 'stable',\n unsupported: MCP_UNSUPPORTED,\n };\n}\n","/**\n * Maps execution-pipeline results and payment-proof input to their MCP wire\n * representation. Uses only the frozen wire helpers from core\n * (`toErrorEnvelope`, `toPaymentRequiredEnvelope`) so the MCP adapter, the\n * HTTP route and the demo buyer agent can never drift apart.\n */\n\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport {\n type CommerceError,\n DELIVERY_SUMMARY_META_KEY,\n type DeliveredOutcome,\n type ExecutionOutcome,\n PAYMENT_INPUT_FIELD,\n type PaymentRequiredOutcome,\n toDeliverySummary,\n toErrorEnvelope,\n toPaymentRequiredEnvelope,\n} from '../../core/index.js';\n\nfunction toRecord(value: object): Record<string, unknown> {\n return value as Record<string, unknown>;\n}\n\nexport function deliveredResult(outcome: DeliveredOutcome): CallToolResult {\n const body = outcome.body;\n const text = typeof body === 'string' ? body : JSON.stringify(body ?? null);\n const isStructured = typeof body === 'object' && body !== null && !Array.isArray(body);\n return {\n content: [{ type: 'text', text }],\n ...(isStructured ? { structuredContent: toRecord(body) } : {}),\n _meta: { [DELIVERY_SUMMARY_META_KEY]: toRecord(toDeliverySummary(outcome)) },\n };\n}\n\nexport function paymentRequiredResult(outcome: PaymentRequiredOutcome): CallToolResult {\n const envelope = toPaymentRequiredEnvelope(outcome);\n const p = envelope.payment;\n const text = `Payment required: ${p.amount} ${p.currency} to ${p.destination} for resource \"${outcome.resourceId}\". Retry the call with a ${p.provider} payment proof in the \"${PAYMENT_INPUT_FIELD}\" input field.`;\n return {\n isError: true,\n content: [{ type: 'text', text }],\n structuredContent: toRecord(envelope),\n };\n}\n\nexport function errorResult(error: CommerceError): CallToolResult {\n const envelope = toErrorEnvelope(error);\n return {\n isError: true,\n content: [{ type: 'text', text: `${envelope.code}: ${envelope.message}` }],\n structuredContent: toRecord(envelope),\n };\n}\n\nexport function mapOutcome(outcome: ExecutionOutcome): CallToolResult {\n return outcome.kind === 'delivered' ? deliveredResult(outcome) : paymentRequiredResult(outcome);\n}\n","/**\n * Maps a canonical `CommerceResource` to an MCP `Tool`.\n *\n * One tool per resource: tool name = resource id, description carries a\n * clear price notice for paid resources, and input schema is the canonical\n * JSON Schema (preserved as-is, including per-property descriptions) with the\n * reserved `_payment` property added for paid resources.\n */\n\nimport type { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport {\n type CommerceResource,\n PAYMENT_INPUT_FIELD,\n type PaymentMethodName,\n} from '../../core/index.js';\n\n/**\n * MCP tool names must match SEP-986: 1-128 chars of [A-Za-z0-9._-].\n *\n * Mirrors the pattern enforced by @modelcontextprotocol/sdk@1.30.0 itself\n * (`dist/esm/shared/toolNameValidation.js`: `TOOL_NAME_REGEX =\n * /^[A-Za-z0-9._-]{1,128}$/`), read from the installed build rather than\n * guessed. We validate independently (instead of importing that internal,\n * unexported module path) so a resource with an illegal id fails loudly here\n * instead of being silently registered and warned about by the SDK.\n */\nexport const MCP_TOOL_NAME_PATTERN = /^[A-Za-z0-9._-]{1,128}$/;\n\nexport function isValidToolName(id: string): boolean {\n return MCP_TOOL_NAME_PATTERN.test(id);\n}\n\nexport function isPaidResource(resource: CommerceResource): boolean {\n return resource.pricing.type !== 'free';\n}\n\n/**\n * The rail a resource actually accepts, per its own canonical configuration.\n * Never hard-coded here — the adapter does not decide which payment method a\n * resource uses, it only reflects what the resource declares. `undefined`\n * when the resource lists none (still possible for a priced resource; the\n * pipeline is the one that decides what happens then, not this adapter).\n */\nfunction primaryPaymentMethod(resource: CommerceResource): PaymentMethodName | undefined {\n return resource.paymentMethods[0];\n}\n\n/** Human-facing note on how to supply a proof, generic when no rail is configured. */\nfunction paymentProofNote(resource: CommerceResource): string {\n const method = primaryPaymentMethod(resource);\n const rail = method !== undefined ? `a ${method}` : 'a';\n return `Requires ${rail} payment proof in the \"${PAYMENT_INPUT_FIELD}\" input field (obtained from a previous payment-required response).`;\n}\n\n/**\n * Description for the reserved `_payment` input property. Mentions x402's\n * `PAYMENT-SIGNATURE` header convention by name only when the resource\n * actually lists x402 as its method — a different future rail would have a\n * different proof encoding, so that detail must not be asserted for it.\n */\nfunction paymentInputFieldDescription(resource: CommerceResource): string {\n const method = primaryPaymentMethod(resource);\n if (method === 'x402') {\n return 'x402 payment proof (base64 PAYMENT-SIGNATURE value) returned from a previous payment-required response.';\n }\n if (method !== undefined) {\n return `${method} payment proof (base64-encoded) returned from a previous payment-required response.`;\n }\n return 'Payment proof returned from a previous payment-required response.';\n}\n\n/**\n * Tool description. For a paid resource this appends a clear, unavoidable\n * price notice so an agent can see the resource costs money before calling\n * it — never buried only in the input schema.\n */\nexport function buildToolDescription(resource: CommerceResource): string {\n const base = resource.description ?? resource.name;\n switch (resource.pricing.type) {\n case 'free':\n return base;\n case 'fixed': {\n const { amount, currency } = resource.pricing;\n return `${base} Costs ${amount} ${currency} per call. ${paymentProofNote(resource)}`;\n }\n case 'dynamic':\n return `${base} Requires payment (amount determined at request time). ${paymentProofNote(resource)}`;\n }\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Builds the MCP `Tool.inputSchema` from the canonical `CommerceResource.inputSchema`.\n *\n * The canonical schema is already JSON Schema, so it is carried through\n * verbatim (properties, descriptions, `required`, and any other JSON Schema\n * keyword) — only `type` is forced to the literal `'object'` MCP requires,\n * and `properties`/`required` are merged rather than replaced. For a paid\n * resource, the reserved optional `_payment` string property is added.\n */\nexport function buildInputSchema(resource: CommerceResource): Tool['inputSchema'] {\n const base = resource.inputSchema;\n const baseIsObject = isPlainObject(base);\n\n const basePropertyEntries: readonly [string, object][] =\n baseIsObject && isPlainObject(base.properties)\n ? Object.entries(base.properties).filter((entry): entry is [string, object] =>\n isPlainObject(entry[1]),\n )\n : [];\n const properties: Record<string, object> = Object.fromEntries(basePropertyEntries);\n\n if (isPaidResource(resource)) {\n // Overwrites any resource-declared `_payment` property. Config is\n // responsible for rejecting that collision at load time — this is not\n // re-checked here.\n properties[PAYMENT_INPUT_FIELD] = {\n type: 'string',\n description: paymentInputFieldDescription(resource),\n };\n }\n\n const required =\n baseIsObject && Array.isArray(base.required)\n ? base.required.filter((v): v is string => typeof v === 'string')\n : [];\n\n const extra = baseIsObject\n ? Object.fromEntries(\n Object.entries(base).filter(\n ([key]) => key !== 'type' && key !== 'properties' && key !== 'required',\n ),\n )\n : {};\n\n return {\n ...extra,\n type: 'object',\n properties,\n ...(required.length > 0 ? { required } : {}),\n };\n}\n","/**\n * MCP protocol adapter.\n *\n * One MCP tool per canonical resource exposed via `exposedVia: ['mcp']`.\n * Every `tools/call` builds a `CanonicalRequest` and goes through\n * `context.pipeline.execute()` — this file never calls a merchant backend and\n * never inspects a payment object, it only surfaces what the pipeline\n * returns.\n *\n * Transport: Streamable HTTP, **stateless** mode (no `sessionIdGenerator`,\n * i.e. session id generation left undefined). A fresh low-level `Server` +\n * `StreamableHTTPServerTransport` pair is created per HTTP request and torn\n * down when the response closes —\n * this is the pattern @modelcontextprotocol/sdk@1.30.0's own\n * `examples/server/simpleStatelessStreamableHttp.js` uses, and it avoids\n * holding cross-request session state the gateway has no lifecycle hook for.\n *\n * Tool registration uses the low-level `Server` (`setRequestHandler` for\n * `ListToolsRequestSchema` / `CallToolRequestSchema`) rather than the\n * higher-level `McpServer.registerTool`. `McpServer.registerTool`'s\n * `inputSchema` only accepts a Zod schema or a raw Zod shape\n * (`server/zod-compat.d.ts`: `AnySchema = z3.ZodTypeAny | z4.$ZodType`) — it\n * does not accept a raw JSON Schema object. The canonical\n * `CommerceResource.inputSchema` is already JSON Schema, and the MCP wire\n * format for `Tool.inputSchema` *is* JSON Schema, so building `Tool` objects\n * directly (via the low-level `Server`) carries it through verbatim with no\n * lossy JSON-Schema-to-Zod conversion. `Server` is marked `@deprecated` in\n * favour of `McpServer`'s ergonomics, but remains fully supported — its\n * documented use is exactly this kind of advanced, non-Zod case.\n *\n * Origin/Host validation (DNS-rebinding protection): deliberately NOT done\n * here. `StreamableHTTPServerTransport` is constructed with no\n * `allowedHosts`/`allowedOrigins`/`enableDnsRebindingProtection` — all three\n * are `@deprecated` in the pinned SDK's own\n * `webStandardStreamableHttp.d.ts`, in favour of exactly the fix applied\n * here: an allowlist enforced by the *host* before a request ever reaches an\n * adapter. `src/gateway`'s `onRequest` hook is that enforcement point —\n * it covers `/mcp` and the HTTP routes together, so there is one allowlist\n * for the whole gateway instead of one per adapter. This adapter has no\n * config surface to build a second one from: `McpAdapterOptions` is frozen\n * (docs/contracts.md) to `{ mountPath?, serverName?, serverVersion? }`, and\n * the only signal available without a contract change —\n * `context.publicBaseUrl` — is one string that may not match what a\n * reverse-proxied deployment's `Host`/`Origin` headers actually carry. A\n * second, narrower allowlist built from it would not add coverage the\n * gateway's hook doesn't already provide; it would only add a second place\n * that can reject legitimate traffic the gateway just allowed, for a\n * deprecated code path upstream is steering consumers away from. Revisit\n * this if the adapter is ever meant to be mounted somewhere other than this\n * gateway. See `descriptor.unsupported` — this reliance on the host is\n * recorded there too, not just here, so `doctor`/`.well-known` surface it.\n */\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';\nimport type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';\nimport {\n CallToolRequestSchema,\n type CallToolResult,\n ListToolsRequestSchema,\n type Tool,\n} from '@modelcontextprotocol/sdk/types.js';\nimport {\n type AdapterDescriptor,\n type AdapterHealth,\n type CanonicalRequest,\n CommerceError,\n type CommerceResource,\n extractReservedInputFields,\n type HttpProtocolAdapter,\n type ProtocolAdapterContext,\n toCommerceError,\n} from '../../core/index.js';\nimport { buildDescriptor, PACKAGE_VERSION } from './descriptor.js';\nimport { errorResult, mapOutcome } from './result-mapping.js';\nimport {\n buildInputSchema,\n buildToolDescription,\n isValidToolName,\n MCP_TOOL_NAME_PATTERN,\n} from './tool-mapping.js';\n\nexport interface McpAdapterOptions {\n /** Path prefix the gateway mounts this adapter at. Default '/mcp'. */\n readonly mountPath?: string;\n /** MCP `Implementation.name` reported during initialize. */\n readonly serverName?: string;\n /** MCP `Implementation.version` reported during initialize. Default: this package's version. */\n readonly serverVersion?: string;\n}\n\ninterface RegisteredTool {\n readonly resource: CommerceResource;\n readonly tool: Tool;\n}\n\ninterface SkippedResource {\n readonly id: string;\n readonly reason: string;\n}\n\nconst DEFAULT_MOUNT_PATH = '/mcp';\nconst DEFAULT_SERVER_NAME = 'agent-commerce';\n\n/**\n * The pinned MCP SDK's Streamable HTTP transport\n * accepts a JSON-RPC **batch** (a bare array in the POST body) and dispatches\n * every element to this adapter's `tools/call` handler in one synchronous\n * `for` loop with no `await` between iterations and no cap on the array's\n * length (`webStandardStreamableHttp.js`'s `handlePostRequest`, via\n * `shared/protocol.js`'s `_onrequest`, which fires the handler and returns\n * without waiting for it to settle). Nothing between the transport and this\n * adapter enforces stateless mode's own precondition that `tools/call`\n * requires no prior `initialize` — so one POST, no handshake, N `tools/call`\n * messages, is a legal request that becomes N concurrent\n * `context.pipeline.execute()` calls, each of which may end in a live\n * `fetch()` to the merchant's backend. 8 keeps a handful of genuinely\n * concurrent tool calls (the common case for an agent working a multi-step\n * task) from ever queuing, while still bounding the worst case to a small,\n * fixed number of simultaneous outbound connections regardless of how large\n * a batch a caller sends. The worst case measured without it was 5000\n * concurrent backend calls from a single request.\n */\nconst MAX_CONCURRENT_TOOL_CALLS = 8;\n\n/**\n * The semaphore above bounds concurrency but not\n * queue depth — `acquireToolCallSlot` pushed one resolver per waiting call\n * onto `toolCallWaiters` with no ceiling, so an oversized batch (thousands\n * of `tools/call` messages, still well under the gateway's own 1 MB body\n * cap) queued in full and then *ran* in full, including the ~30 seconds\n * after the client had already disconnected. 64 is 8x\n * MAX_CONCURRENT_TOOL_CALLS: enough that a legitimate short burst from one\n * agent never gets rejected (the measured honest case tops out at a\n * handful of concurrent calls), while capping the adapter's total\n * exposure — in flight plus queued — to a small, fixed number of real\n * `pipeline.execute()` calls no matter how large a batch a caller sends.\n * Calls beyond the queue fail fast with no backend call at all, rather\n * than piling up behind it.\n *\n * Scope note: this cap is per `McpProtocolAdapter` instance.\n * The gateway's own SSE-subscriber cap is per gateway instance. Both\n * happen to be one-per-process today, so the two read the same in\n * practice — but they are not the same scope, and that stops being true\n * the moment either one is ever instantiated more than once per process.\n */\nconst MAX_QUEUED_TOOL_CALLS = 64;\n\nexport class McpProtocolAdapter implements HttpProtocolAdapter {\n readonly name = 'mcp' as const;\n readonly mountPath: string;\n readonly descriptor: AdapterDescriptor;\n\n private readonly serverName: string;\n private readonly serverVersion: string;\n\n private context: ProtocolAdapterContext | undefined;\n private started = false;\n private tools: readonly RegisteredTool[] = [];\n private toolsByResourceId: ReadonlyMap<string, CommerceResource> = new Map();\n private skipped: readonly SkippedResource[] = [];\n private readonly activeTransports = new Set<StreamableHTTPServerTransport>();\n\n // Counting semaphore bounding concurrent `context.pipeline.execute()`\n // calls. Lives on the adapter instance (one per gateway mount, for the\n // process lifetime), not per-request, so the cap holds across concurrent\n // `/mcp` requests too — not just within one oversized batch. A request\n // only ever waits here once MAX_CONCURRENT_TOOL_CALLS executions are\n // already in flight adapter-wide, which is the throttle working as\n // intended, not two unrelated single-call requests blocking each other.\n private inFlightToolCalls = 0;\n private readonly toolCallWaiters: Array<() => void> = [];\n\n constructor(options: McpAdapterOptions = {}) {\n this.mountPath = options.mountPath ?? DEFAULT_MOUNT_PATH;\n this.serverName = options.serverName ?? DEFAULT_SERVER_NAME;\n this.serverVersion = options.serverVersion ?? PACKAGE_VERSION;\n this.descriptor = buildDescriptor(PACKAGE_VERSION);\n }\n\n async start(context: ProtocolAdapterContext): Promise<void> {\n this.context = context;\n this.started = false;\n\n let resources: readonly CommerceResource[] = [];\n try {\n resources = context.resources.listExposedVia('mcp');\n } catch (err) {\n context.logger.error(\n { adapter: 'mcp', err: toCommerceError(err).toInfo() },\n 'mcp adapter: failed to list mcp-exposed resources',\n );\n resources = [];\n }\n\n const tools: RegisteredTool[] = [];\n const toolsByResourceId = new Map<string, CommerceResource>();\n const skipped: SkippedResource[] = [];\n\n for (const resource of resources) {\n try {\n if (!isValidToolName(resource.id)) {\n skipped.push({\n id: resource.id,\n reason: `resource id is not a legal MCP tool name (must match ${MCP_TOOL_NAME_PATTERN.source})`,\n });\n continue;\n }\n if (toolsByResourceId.has(resource.id)) {\n skipped.push({ id: resource.id, reason: 'duplicate tool name' });\n continue;\n }\n const tool: Tool = {\n name: resource.id,\n description: buildToolDescription(resource),\n inputSchema: buildInputSchema(resource),\n };\n tools.push({ resource, tool });\n toolsByResourceId.set(resource.id, resource);\n } catch (err) {\n skipped.push({\n id: resource.id,\n reason: `failed to build MCP tool: ${toCommerceError(err).message}`,\n });\n }\n }\n\n for (const s of skipped) {\n context.logger.warn(\n { adapter: 'mcp', resourceId: s.id, reason: s.reason },\n 'mcp adapter: resource skipped',\n );\n }\n\n this.tools = tools;\n this.toolsByResourceId = toolsByResourceId;\n this.skipped = skipped;\n this.started = true;\n\n context.logger.info(\n {\n adapter: 'mcp',\n mountPath: this.mountPath,\n toolCount: tools.length,\n skippedCount: skipped.length,\n },\n 'mcp adapter started',\n );\n }\n\n async handleHttp(req: IncomingMessage, res: ServerResponse): Promise<void> {\n try {\n if (!this.started || !this.context) {\n this.writeJsonRpcError(res, 503, 'MCP adapter is not running.');\n return;\n }\n if (req.method !== 'POST') {\n this.writeJsonRpcError(res, 405, 'Method not allowed. This endpoint only accepts POST.');\n return;\n }\n\n // one AbortController per HTTP request, aborted\n // from the same `res` 'close' handler that already tears down the\n // transport/server pair. `handleToolCall` checks this after acquiring\n // its concurrency slot — never mid-`pipeline.execute()`, since a call\n // that already reached settlement must be allowed to finish (aborting\n // there is worse than finishing: the buyer may already be charged).\n const abortController = new AbortController();\n const server = this.buildServer(abortController.signal);\n // Stateless mode: omitting `sessionIdGenerator` (rather than setting it\n // to `undefined`) is required under `exactOptionalPropertyTypes`, and\n // has identical runtime behaviour — see\n // dist/esm/server/webStandardStreamableHttp.js: session handling is\n // gated on `!this.sessionIdGenerator`, true either way.\n const transport = new StreamableHTTPServerTransport();\n this.activeTransports.add(transport);\n\n const cleanup = (): void => {\n abortController.abort();\n this.activeTransports.delete(transport);\n transport.close().catch(() => {});\n server.close().catch(() => {});\n };\n res.once('close', cleanup);\n\n // `StreamableHTTPServerTransport implements Transport` per the SDK's\n // own declaration; the cast works around its `onclose`/`onerror`\n // accessors being typed `T | undefined` where `Transport` declares a\n // bare optional `T`, which only conflicts under this project's\n // `exactOptionalPropertyTypes`.\n await server.connect(transport as Transport);\n await transport.handleRequest(req, res);\n } catch (err) {\n this.context?.logger.error(\n { adapter: 'mcp', err: toCommerceError(err).toInfo() },\n 'mcp adapter: request handling failed',\n );\n this.writeJsonRpcError(res, 500, 'Internal server error.');\n }\n }\n\n async health(): Promise<AdapterHealth> {\n const checkedAt = this.context?.clock.nowIso() ?? new Date().toISOString();\n try {\n if (!this.started || !this.context) {\n return { status: 'fail', detail: 'MCP adapter has not been started.', checkedAt };\n }\n const toolCount = this.tools.length;\n if (this.skipped.length > 0) {\n const detail = `${toolCount} tool(s) registered; ${this.skipped.length} resource(s) skipped: ${this.skipped\n .map((s) => `${s.id} (${s.reason})`)\n .join('; ')}`;\n return { status: 'warn', detail, checkedAt };\n }\n return { status: 'pass', detail: `${toolCount} tool(s) registered.`, checkedAt };\n } catch (err) {\n return {\n status: 'fail',\n detail: `mcp adapter health check failed: ${toCommerceError(err).message}`,\n checkedAt,\n };\n }\n }\n\n async stop(): Promise<void> {\n this.started = false;\n const transports = [...this.activeTransports];\n this.activeTransports.clear();\n await Promise.all(\n transports.map(async (transport) => {\n try {\n await transport.close();\n } catch {\n // best-effort cleanup — stop() must be idempotent and never throw.\n }\n }),\n );\n this.context = undefined;\n }\n\n private writeJsonRpcError(res: ServerResponse, status: number, message: string): void {\n if (res.headersSent) return;\n res.writeHead(status, { 'content-type': 'application/json' });\n res.end(JSON.stringify({ jsonrpc: '2.0', error: { code: -32000, message }, id: null }));\n }\n\n private buildServer(signal: AbortSignal): Server {\n const server = new Server(\n { name: this.serverName, version: this.serverVersion },\n { capabilities: { tools: {} } },\n );\n server.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: this.tools.map((t) => t.tool),\n }));\n server.setRequestHandler(CallToolRequestSchema, async (request) =>\n this.handleToolCall(request.params.name, request.params.arguments ?? {}, signal),\n );\n return server;\n }\n\n private async handleToolCall(\n resourceId: string,\n rawArgs: Record<string, unknown>,\n signal: AbortSignal,\n ): Promise<CallToolResult> {\n const context = this.context;\n if (!context) {\n return errorResult(new CommerceError('INTERNAL_ERROR', 'MCP adapter is not running.'));\n }\n try {\n // Defence in depth: `tools/list` only ever advertises mcp-exposed,\n // legal-name resources, but a client can still send `tools/call` for\n // any name. Gate here too (core also enforces exposedVia in the\n // pipeline) — do not rely on core alone. Message stays identical to a\n // genuinely unknown id so we never reveal that a resource exists but\n // is scoped to another protocol.\n const resource = this.toolsByResourceId.get(resourceId);\n if (!resource) {\n return errorResult(\n new CommerceError('RESOURCE_NOT_FOUND', `Unknown tool \"${resourceId}\".`, { resourceId }),\n );\n }\n const requestId = context.ids.next('mcp');\n const { input, payment, authorization } = extractReservedInputFields(\n rawArgs,\n resource,\n requestId,\n );\n const request: CanonicalRequest = {\n requestId,\n resourceId,\n input,\n protocol: 'mcp',\n receivedAt: context.clock.nowIso(),\n ...(payment !== undefined ? { payment } : {}),\n ...(authorization !== undefined ? { authorization } : {}),\n };\n await this.acquireToolCallSlot(signal);\n try {\n // the only cancellation point. A call queued\n // behind a full semaphore, whose caller has since disconnected,\n // must not start a fresh pipeline.execute() (and possibly a live\n // merchant-backend fetch) — that is the \"runs for 30s after the\n // client left\" bug. Checked here and nowhere else: once execute()\n // is called it may reach settle(), and an in-flight payment must be\n // allowed to finish rather than be abandoned mid-flight.\n if (signal.aborted) {\n // deliberately *not* GATEWAY_BUSY. That code\n // means \"transient, back off and retry\" — true for the queue-full\n // case below, false here: there is no caller left to retry, so\n // telling one to would be meaningless. PROTOCOL_UNSUPPORTED is the\n // least dishonest fit among the frozen codes (non-retryable, which\n // is the one property that matters for a response nobody reads),\n // not a precise description of \"the caller went away\" — none of\n // the frozen codes names that condition. Left flagged as a known\n // gap rather than reused past what it's honestly for.\n return errorResult(\n new CommerceError(\n 'PROTOCOL_UNSUPPORTED',\n 'Client disconnected before this call started.',\n ),\n );\n }\n const outcome = await context.pipeline.execute(request);\n return mapOutcome(outcome);\n } finally {\n // Always release, even if execute() throws — a stranded permit\n // would shrink MAX_CONCURRENT_TOOL_CALLS by one forever and\n // eventually deadlock the adapter, which is worse.\n this.releaseToolCallSlot();\n }\n } catch (err) {\n return errorResult(toCommerceError(err));\n }\n }\n\n /**\n * Blocks until fewer than MAX_CONCURRENT_TOOL_CALLS executions are in\n * flight, or throws if the queue behind that gate is already full or the\n * caller disconnected while waiting. Throwing\n * here never leaks a permit: `inFlightToolCalls` is only incremented on\n * the success path below, after every rejection point.\n */\n private async acquireToolCallSlot(signal: AbortSignal): Promise<void> {\n if (this.toolCallWaiters.length >= MAX_QUEUED_TOOL_CALLS) {\n // GATEWAY_BUSY, not PROTOCOL_UNSUPPORTED. This\n // is load shedding, which is transient by definition — the caller\n // should back off and retry, matching the message below. Before\n // GATEWAY_BUSY existed this threw PROTOCOL_UNSUPPORTED (HTTP 501,\n // `retryable: false`), so the envelope told an agent framework keyed\n // on the machine-readable flag that a momentary throttle was a\n // permanent capability gap — contradicting this exact message.\n throw new CommerceError(\n 'GATEWAY_BUSY',\n 'Too many tool calls already queued on this adapter; retry later.',\n );\n }\n // `while`, not `if`. A wake-up only means a slot\n // was *freed*, not that this waiter is now entitled to it regardless of\n // what else has happened since — re-check the same condition the loop\n // waited on rather than assume one wake-up means one free slot forever.\n // (Currently that assumption would also happen to hold, since\n // `releaseToolCallSlot` decrements before waking the next waiter and JS\n // has no thread to race it — but that is a scheduling fact about this\n // file, not something `if` states, and it is exactly the kind of thing\n // a later refactor breaks silently. `while` doesn't depend on it.)\n while (this.inFlightToolCalls >= MAX_CONCURRENT_TOOL_CALLS) {\n await new Promise<void>((resolve) => this.toolCallWaiters.push(resolve));\n if (signal.aborted) {\n // This waiter is declining the slot that was just freed for it —\n // pass it straight to the next waiter in line instead of stranding\n // everyone behind it. Without this, a disconnect partway through a\n // deep queue leaves every later waiter's promise waiting on a\n // wake-up call that only its own dedicated release() would have\n // sent — and that release never comes, because this waiter never\n // takes the slot that would have produced it.\n this.toolCallWaiters.shift()?.();\n // PROTOCOL_UNSUPPORTED, not GATEWAY_BUSY —\n // same reasoning as the other disconnect check above. Non-retryable\n // is correct here (nobody is listening to retry); \"unsupported\" is\n // not a precise name for \"the caller left\", it's just the least\n // dishonest fit among the frozen codes.\n throw new CommerceError('PROTOCOL_UNSUPPORTED', 'Client disconnected while queued.');\n }\n }\n this.inFlightToolCalls++;\n }\n\n private releaseToolCallSlot(): void {\n this.inFlightToolCalls--;\n // Wake the oldest waiter, if any; it will re-increment once it resumes.\n this.toolCallWaiters.shift()?.();\n }\n}\n\nexport function createMcpAdapter(options?: McpAdapterOptions): HttpProtocolAdapter {\n return new McpProtocolAdapter(options ?? {});\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  import { IncomingMessage, ServerResponse } from 'node:http';
2
- import { I as IsoTimestamp, k as PaymentResult, p as ProtocolName, m as PaymentSubmission, j as PaymentRequirement, A as AdapterDescriptor, R as ResourceRegistry, L as Logger, c as Clock, d as IdGenerator, a as AdapterHealth } from './runtime-Bqg9qW3t.js';
2
+ import { I as IsoTimestamp, m as PaymentResult, q as ProtocolName, b as PaymentSubmission, l as PaymentRequirement, A as AdapterDescriptor, R as ResourceRegistry, L as Logger, C as Clock, e as IdGenerator, c as AdapterHealth } from './runtime-CKq3d_3K.js';
3
+ import { d as AuthorizationRecord, b as AuthorizationSubmission, a as AuthorizationRequirement } from './authorization-CPDcpJVa.js';
3
4
 
4
5
  /**
5
6
  * Canonical commerce events.
@@ -8,7 +9,7 @@ import { I as IsoTimestamp, k as PaymentResult, p as ProtocolName, m as PaymentS
8
9
  * logs, payment attempts, backend calls and receipts are correlatable.
9
10
  */
10
11
 
11
- declare const COMMERCE_EVENT_TYPES: readonly ["resource.discovered", "resource.requested", "payment.required", "payment.rejected", "payment.verified", "payment.settled", "backend.called", "backend.failed", "resource.delivered"];
12
+ declare const COMMERCE_EVENT_TYPES: readonly ["resource.discovered", "resource.requested", "payment.required", "payment.rejected", "payment.verified", "payment.settled", "authorization.verified", "authorization.rejected", "backend.called", "backend.failed", "resource.delivered"];
12
13
  type CommerceEventType = (typeof COMMERCE_EVENT_TYPES)[number];
13
14
  interface CommerceEvent {
14
15
  readonly id: string;
@@ -46,6 +47,11 @@ interface CommerceReceipt {
46
47
  readonly resourceId: string;
47
48
  /** Absent for free resources. */
48
49
  readonly payment?: PaymentResult;
50
+ /**
51
+ * Present only when the resource required one. A method and a digest, so the
52
+ * receipt records that consent existed without storing the proof of it.
53
+ */
54
+ readonly authorization?: AuthorizationRecord;
49
55
  readonly deliveredAt: IsoTimestamp;
50
56
  readonly backendStatus: number;
51
57
  readonly durationMs?: number;
@@ -101,6 +107,12 @@ interface CanonicalRequest {
101
107
  readonly protocol: ProtocolName;
102
108
  /** Payment proof, when the client is retrying after a challenge. */
103
109
  readonly payment?: PaymentSubmission;
110
+ /**
111
+ * Authorization proof, when the resource requires one. Independent of
112
+ * `payment`: neither substitutes for the other, and a resource requiring
113
+ * authorization needs both.
114
+ */
115
+ readonly authorization?: AuthorizationSubmission;
104
116
  readonly receivedAt: IsoTimestamp;
105
117
  /** Non-secret transport metadata (client id, user agent, …). */
106
118
  readonly metadata?: Readonly<Record<string, unknown>>;
@@ -123,6 +135,11 @@ interface PaymentRequiredOutcome {
123
135
  readonly requestId: string;
124
136
  readonly resourceId: string;
125
137
  readonly requirement: PaymentRequirement;
138
+ /**
139
+ * Authorization the buyer must also present on the retry, when the resource
140
+ * requires one. Absent for the ordinary paid resource.
141
+ */
142
+ readonly authorization?: readonly AuthorizationRequirement[];
126
143
  }
127
144
  /**
128
145
  * Result of a pipeline execution.
@@ -239,4 +256,4 @@ interface AdapterHttpRoute {
239
256
  }
240
257
  declare function isHttpProtocolAdapter(adapter: ProtocolAdapter): adapter is HttpProtocolAdapter;
241
258
 
242
- export { type AdapterHttpRoute as A, type CommerceEvent as C, type DeliveredOutcome as D, type ExecutionPipeline as E, type HttpProtocolAdapter as H, type PaymentRequiredOutcome as P, type PaymentAttempt as a, type CommerceReceipt as b, type ProtocolAdapter as c, COMMERCE_EVENT_TYPES as d, type CanonicalRequest as e, type CommerceEventType as f, type EventSink as g, type ExecutionOutcome as h, type ProtocolAdapterContext as i, isHttpProtocolAdapter as j };
259
+ export { type AdapterHttpRoute as A, type CommerceEvent as C, type DeliveredOutcome as D, type ExecutionPipeline as E, type HttpProtocolAdapter as H, type PaymentRequiredOutcome as P, type PaymentAttempt as a, type CommerceReceipt as b, type ProtocolAdapter as c, type ProtocolAdapterContext as d, COMMERCE_EVENT_TYPES as e, type CanonicalRequest as f, type CommerceEventType as g, type EventSink as h, type ExecutionOutcome as i, isHttpProtocolAdapter as j };
@@ -17,12 +17,12 @@ type JsonSchema = Record<string, unknown>;
17
17
  *
18
18
  * The runtime list is the definition and the type is derived from it, so a
19
19
  * caller that has to *check* a name (config validation, the OpenAPI
20
- * importer's `--expose`) reads the same three strings the type is built from
20
+ * importer's `--expose`) reads the same strings the type is built from
21
21
  * rather than keeping a second copy that can drift.
22
22
  */
23
- type ProtocolName = 'http' | 'mcp' | 'a2a';
23
+ type ProtocolName = 'http' | 'mcp' | 'a2a' | 'acp';
24
24
  /**
25
- * The same three names as a value, for code that has to *check* one at
25
+ * The same names as a value, for code that has to *check* one at
26
26
  * runtime - config validation, the OpenAPI importer's `--expose`. Typed
27
27
  * against `ProtocolName` so an unsupported name cannot enter the list, which
28
28
  * is what keeps this from becoming a second definition that drifts.
@@ -30,6 +30,15 @@ type ProtocolName = 'http' | 'mcp' | 'a2a';
30
30
  declare const PROTOCOL_NAMES: readonly ProtocolName[];
31
31
  /** Payment methods a resource can accept in this release. */
32
32
  type PaymentMethodName = 'x402';
33
+ /**
34
+ * Authorization methods a resource can require in this release.
35
+ *
36
+ * Deliberately not a `ProtocolName` and not a `PaymentMethodName`: an
37
+ * authorization method is neither a transport nor a payment rail. It proves
38
+ * the purchase was approved, and sits beside the payment rather than
39
+ * replacing it.
40
+ */
41
+ type AuthorizationMethodName = 'ap2';
33
42
  /** ISO-8601 timestamp string, always UTC with millisecond precision. */
34
43
  type IsoTimestamp = string;
35
44
  /**
@@ -54,7 +63,7 @@ interface AdapterHealth {
54
63
  */
55
64
  interface AdapterDescriptor {
56
65
  readonly name: string;
57
- readonly kind: 'protocol' | 'payment' | 'storage';
66
+ readonly kind: 'protocol' | 'payment' | 'storage' | 'authorization';
58
67
  /** Version of this adapter implementation (independent of the spec). */
59
68
  readonly implementationVersion: string;
60
69
  /** Exact pinned specification revision this adapter targets. */
@@ -140,6 +149,17 @@ interface CommerceResource {
140
149
  readonly pricing: Pricing;
141
150
  readonly exposedVia: readonly ProtocolName[];
142
151
  readonly paymentMethods: readonly PaymentMethodName[];
152
+ /**
153
+ * Authorization the buyer must present in addition to payment.
154
+ *
155
+ * Opt-in per resource and absent by default, so every resource configured
156
+ * before this existed behaves exactly as it did. It sits beside
157
+ * `paymentMethods` rather than inside it: an authorization method is not a
158
+ * payment rail and must never be selectable as one.
159
+ */
160
+ readonly authorization?: {
161
+ readonly required: readonly AuthorizationMethodName[];
162
+ };
143
163
  }
144
164
  /** Read-only view of every configured resource. */
145
165
  interface ResourceRegistry {
@@ -317,4 +337,4 @@ interface IdGenerator {
317
337
  }
318
338
  declare const systemClock: Clock;
319
339
 
320
- export { type AdapterDescriptor as A, type BackendHandler as B, type CommerceResource as C, type DecimalAmount as D, type IsoTimestamp as I, type JsonSchema as J, type Logger as L, NOOP_LOGGER as N, type PaymentMethodName as P, type ResourceRegistry as R, type AdapterHealth as a, type PaymentProvider as b, type Clock as c, type IdGenerator as d, type BackendMethod as e, DEFAULT_BACKEND_TIMEOUT_MS as f, PROTOCOL_NAMES as g, type PaymentChallenge as h, type PaymentContext as i, type PaymentRequirement as j, type PaymentResult as k, type PaymentSettlementContext as l, type PaymentSubmission as m, type PaymentVerificationContext as n, type Pricing as o, type ProtocolName as p, systemClock as s };
340
+ export { type AdapterDescriptor as A, type BackendHandler as B, type Clock as C, type DecimalAmount as D, type IsoTimestamp as I, type JsonSchema as J, type Logger as L, NOOP_LOGGER as N, type PaymentMethodName as P, type ResourceRegistry as R, type CommerceResource as a, type PaymentSubmission as b, type AdapterHealth as c, type PaymentProvider as d, type IdGenerator as e, type AuthorizationMethodName as f, type BackendMethod as g, DEFAULT_BACKEND_TIMEOUT_MS as h, PROTOCOL_NAMES as i, type PaymentChallenge as j, type PaymentContext as k, type PaymentRequirement as l, type PaymentResult as m, type PaymentSettlementContext as n, type PaymentVerificationContext as o, type Pricing as p, type ProtocolName as q, systemClock as s };
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Pinned AP2 identifiers and key policy.
3
+ *
4
+ * AP2 v0.2.0 (2026-04-28, commit b4587ac) is the tagged release this gateway
5
+ * verifies against; unversioned `main` is never implemented against. Config,
6
+ * the verifier and `doctor` all read these, so a bump lands in one place.
7
+ */
8
+ declare const AP2_SPEC_VERSION = "0.2.0";
9
+ /**
10
+ * Autonomous mode needs open mandates, cnf-bound agent keys and constraint
11
+ * evaluation over `checkout.line_items`. Half of that would be worse than a
12
+ * declared Direct-only profile, so it is refused rather than partly served.
13
+ */
14
+ declare const AP2_MODES: readonly ["direct"];
15
+ type Ap2Mode = (typeof AP2_MODES)[number];
16
+ /**
17
+ * One entry, so `alg=none` and the HMAC family are excluded by construction
18
+ * rather than by a check that has to remember them
19
+ */
20
+ declare const AP2_SIGNING_ALGORITHM = "ES256";
21
+ /**
22
+ * Compared against this literal, never as a prefix. `mandate.checkout.open.1`
23
+ * carries spending constraints this release does not evaluate, so accepting it
24
+ * would tell a buyer their limits were checked when nothing read them.
25
+ */
26
+ declare const AP2_CHECKOUT_MANDATE_VCT = "mandate.checkout.1";
27
+ /**
28
+ * The checkout profile every merchant checkout JWT must declare.
29
+ *
30
+ * Ours, not AP2's: AP2 leaves the checkout payload outside its scope, so the
31
+ * claims a paid-resource invocation needs had to be specified somewhere.
32
+ *
33
+ * A bare name, matching the gateway's other wire identifiers
34
+ * (`agent-commerce/delivery`, `agent-commerce/v1.0.0`). A profile id is a
35
+ * namespace and is never dereferenced, so a URL would only tie the wire format
36
+ * to a domain. Frozen once released: merchants sign it into every checkout JWT.
37
+ */
38
+ declare const AP2_CHECKOUT_PROFILE = "agent-commerce/ap2/checkout/v1";
39
+ /** Seconds of clock skew tolerated on mandate and checkout time claims */
40
+ declare const AP2_DEFAULT_CLOCK_SKEW_SECONDS = 60;
41
+ /**
42
+ * Skew wide enough to cover a mandate's validity window stops `exp` rejecting
43
+ * anything. An operator needing more than five minutes has a clock to fix.
44
+ */
45
+ declare const AP2_MAX_CLOCK_SKEW_SECONDS = 300;
46
+
47
+ /**
48
+ * AP2 trust configuration and the shape a successful verification produces.
49
+ *
50
+ * Trust types live here, not in `src/config`, so the dependency points the way
51
+ * `X402FacilitatorConfig` does: the subsystem owns its own config shape and
52
+ * the loader imports it.
53
+ */
54
+
55
+ /** One inline public verification key, trusted because an operator wrote it here */
56
+ interface Ap2TrustedKey {
57
+ readonly kid: string;
58
+ /** A public P-256 JWK. Validated member by member at config load */
59
+ readonly jwk: Readonly<Record<string, string>>;
60
+ }
61
+ /** One trusted issuer and the keys it signs with */
62
+ interface Ap2TrustedIssuer {
63
+ readonly issuer: string;
64
+ /**
65
+ * Per issuer, not one gateway-wide value: the mandate is addressed to the
66
+ * merchant and the checkout JWT it binds to the gateway
67
+ */
68
+ readonly audience: string;
69
+ readonly keys: readonly Ap2TrustedKey[];
70
+ }
71
+ /**
72
+ * Discriminated on `enabled`, like `AcpProtocolConfig`: an enabled config
73
+ * carries everything the verifier needs, so nothing downstream asserts on an
74
+ * optional field
75
+ */
76
+ type Ap2AuthorizationConfig = {
77
+ readonly enabled: false;
78
+ } | {
79
+ readonly enabled: true;
80
+ readonly specVersion: typeof AP2_SPEC_VERSION;
81
+ readonly mode: Ap2Mode;
82
+ readonly trust: {
83
+ /** Signers of the Checkout Mandate itself */
84
+ readonly mandateIssuers: readonly Ap2TrustedIssuer[];
85
+ /** Signers of the merchant checkout JWT the mandate binds */
86
+ readonly checkoutIssuers: readonly Ap2TrustedIssuer[];
87
+ };
88
+ readonly clockSkewSeconds: number;
89
+ /** Its own SQLite file. An authorization replay is not a payment replay */
90
+ readonly replay: {
91
+ readonly path: string;
92
+ };
93
+ };
94
+ /** The enabled half, which is all the verifier ever runs against */
95
+ type EnabledAp2Config = Extract<Ap2AuthorizationConfig, {
96
+ enabled: true;
97
+ }>;
98
+
99
+ export { AP2_CHECKOUT_MANDATE_VCT as A, type EnabledAp2Config as E, AP2_CHECKOUT_PROFILE as a, AP2_DEFAULT_CLOCK_SKEW_SECONDS as b, AP2_MAX_CLOCK_SKEW_SECONDS as c, AP2_SIGNING_ALGORITHM as d, AP2_SPEC_VERSION as e, type Ap2AuthorizationConfig as f, type Ap2Mode as g, type Ap2TrustedIssuer as h, type Ap2TrustedKey as i };
package/dist/x402.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { X as X402FacilitatorConfig } from './guardrails-Dmwi63KB.js';
2
2
  export { F as FacilitatorAuth } from './guardrails-Dmwi63KB.js';
3
- import { L as Logger, c as Clock, d as IdGenerator, b as PaymentProvider } from './runtime-Bqg9qW3t.js';
3
+ import { L as Logger, C as Clock, e as IdGenerator, d as PaymentProvider } from './runtime-CKq3d_3K.js';
4
4
 
5
5
  interface NetworkProfile {
6
6
  /** CAIP-2 identifier, e.g. `eip155:84532`. */
package/dist/x402.js CHANGED
@@ -1,6 +1,6 @@
1
- import { assertPayToIsNotDevAddress, resolveX402Deployment, assertDevKeyIsLocalOnly, describeDeploymentMode } from './chunk-5TKNTWMC.js';
2
- export { SUPPORTED_NETWORK_IDS } from './chunk-5TKNTWMC.js';
3
- import { CommerceError, systemClock, NOOP_LOGGER, PACKAGE_VERSION } from './chunk-EIACECVM.js';
1
+ import { assertPayToIsNotDevAddress, resolveX402Deployment, assertDevKeyIsLocalOnly, describeDeploymentMode } from './chunk-IUR3Q7DE.js';
2
+ export { SUPPORTED_NETWORK_IDS } from './chunk-IUR3Q7DE.js';
3
+ import { CommerceError, systemClock, NOOP_LOGGER, PACKAGE_VERSION } from './chunk-ZDVJ7EVL.js';
4
4
  import { PaymentRequirementsV2Schema, PaymentPayloadV2Schema } from '@x402/core/schemas';
5
5
  import { getAddress, toHex, isAddress, createWalletClient, http, publicActions, createPublicClient, HttpRequestError, TimeoutError, WaitForTransactionReceiptTimeoutError, encodeAbiParameters, keccak256, ContractFunctionRevertedError, ContractFunctionExecutionError } from 'viem';
6
6
  import { privateKeyToAccount } from 'viem/accounts';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devlab.group/agent-commerce",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "Open-source, self-hosted, non-custodial commerce and payment orchestration gateway for AI agents.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -16,6 +16,10 @@
16
16
  "types": "./dist/index.d.ts",
17
17
  "import": "./dist/index.js"
18
18
  },
19
+ "./ap2": {
20
+ "types": "./dist/ap2.d.ts",
21
+ "import": "./dist/ap2.js"
22
+ },
19
23
  "./mcp": {
20
24
  "types": "./dist/mcp.d.ts",
21
25
  "import": "./dist/mcp.js"
@@ -89,6 +93,8 @@
89
93
  "dependencies": {
90
94
  "@clack/prompts": "1.7.0",
91
95
  "@scalar/openapi-parser": "0.29.0",
96
+ "ajv": "8.20.0",
97
+ "ajv-formats": "3.0.1",
92
98
  "better-sqlite3": "13.0.3",
93
99
  "commander": "15.0.0",
94
100
  "fastify": "5.12.0",
@@ -100,8 +106,11 @@
100
106
  "peerDependencies": {
101
107
  "@coinbase/x402": "2.1.0",
102
108
  "@modelcontextprotocol/sdk": "1.30.0",
109
+ "@sd-jwt/core": "0.20.1",
103
110
  "@x402/core": "2.23.0",
104
111
  "@x402/evm": "2.23.0",
112
+ "canonicalize": "5.0.0",
113
+ "jose": "6.2.12",
105
114
  "viem": "2.55.18"
106
115
  },
107
116
  "peerDependenciesMeta": {
@@ -111,12 +120,21 @@
111
120
  "@modelcontextprotocol/sdk": {
112
121
  "optional": true
113
122
  },
123
+ "@sd-jwt/core": {
124
+ "optional": true
125
+ },
114
126
  "@x402/core": {
115
127
  "optional": true
116
128
  },
117
129
  "@x402/evm": {
118
130
  "optional": true
119
131
  },
132
+ "canonicalize": {
133
+ "optional": true
134
+ },
135
+ "jose": {
136
+ "optional": true
137
+ },
120
138
  "viem": {
121
139
  "optional": true
122
140
  }
@@ -126,6 +144,7 @@
126
144
  "@biomejs/biome": "2.5.9",
127
145
  "@coinbase/x402": "2.1.0",
128
146
  "@modelcontextprotocol/sdk": "1.30.0",
147
+ "@sd-jwt/core": "0.20.1",
129
148
  "@types/better-sqlite3": "9.6.0",
130
149
  "@types/node": "24.13.3",
131
150
  "@types/react": "19.2.18",
@@ -134,6 +153,8 @@
134
153
  "@vitest/coverage-v8": "4.1.10",
135
154
  "@x402/core": "2.23.0",
136
155
  "@x402/evm": "2.23.0",
156
+ "canonicalize": "5.0.0",
157
+ "jose": "6.2.12",
137
158
  "pino-pretty": "13.1.2",
138
159
  "react": "19.0.8",
139
160
  "react-dom": "19.0.8",
@@ -145,13 +166,16 @@
145
166
  "vitest": "4.1.10"
146
167
  },
147
168
  "overrides": {
148
- "@x402/core": {
169
+ "@coinbase/x402": {
149
170
  "zod": "3.25.76"
150
171
  },
151
- "@x402/evm": {
172
+ "@sd-jwt/core": {
173
+ "@owf/identity-common": "0.3.2"
174
+ },
175
+ "@x402/core": {
152
176
  "zod": "3.25.76"
153
177
  },
154
- "@coinbase/x402": {
178
+ "@x402/evm": {
155
179
  "zod": "3.25.76"
156
180
  }
157
181
  }