@devlab.group/agent-commerce 0.1.0-alpha.0 → 0.2.0-beta.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/README.md +41 -22
- package/dist/{chunk-CZ6ZDAYD.js → chunk-ASK67X56.js} +9 -7
- package/dist/chunk-ASK67X56.js.map +1 -0
- package/dist/chunk-MQMKQGAB.js +199 -0
- package/dist/chunk-MQMKQGAB.js.map +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +253 -49
- package/dist/cli/index.js.map +1 -1
- package/dist/guardrails-Di_yI_DW.d.ts +25 -0
- package/dist/index.d.ts +36 -18
- package/dist/index.js +74 -33
- package/dist/index.js.map +1 -1
- package/dist/mcp.d.ts +2 -2
- package/dist/mcp.js +2 -2
- package/dist/mcp.js.map +1 -1
- package/dist/{protocol-adapter-C0goMgLK.d.ts → protocol-adapter-CtB0sOnV.d.ts} +2 -3
- package/dist/{runtime-LCk2TzGN.d.ts → runtime-Bie-9FAM.d.ts} +15 -3
- package/dist/x402.d.ts +69 -17
- package/dist/x402.js +265 -216
- package/dist/x402.js.map +1 -1
- package/package.json +13 -7
- package/dist/chunk-CZ6ZDAYD.js.map +0 -1
package/dist/mcp.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { H as HttpProtocolAdapter } from './protocol-adapter-
|
|
1
|
+
import { H as HttpProtocolAdapter } from './protocol-adapter-CtB0sOnV.js';
|
|
2
2
|
import 'node:http';
|
|
3
|
-
import './runtime-
|
|
3
|
+
import './runtime-Bie-9FAM.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* 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-
|
|
1
|
+
import { PACKAGE_VERSION, toCommerceError, CommerceError, PAYMENT_INPUT_FIELD, toErrorEnvelope, DELIVERY_SUMMARY_META_KEY, toDeliverySummary, toPaymentRequiredEnvelope } from './chunk-ASK67X56.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';
|
|
@@ -92,7 +92,7 @@ function paymentProofNote(resource) {
|
|
|
92
92
|
function paymentInputFieldDescription(resource) {
|
|
93
93
|
const method = primaryPaymentMethod(resource);
|
|
94
94
|
if (method === "x402") {
|
|
95
|
-
return "x402 payment proof (base64
|
|
95
|
+
return "x402 payment proof (base64 PAYMENT-SIGNATURE value) returned from a previous payment-required response.";
|
|
96
96
|
}
|
|
97
97
|
if (method !== void 0) {
|
|
98
98
|
return `${method} payment proof (base64-encoded) returned from a previous payment-required response.`;
|
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 v0.1.0-alpha. 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 * `X-PAYMENT` header convention by name only when the resource actually lists\n * x402 as its method — a different future rail would have a different proof\n * 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 X-PAYMENT 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":"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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,12 +1,11 @@
|
|
|
1
1
|
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
-
import { I as IsoTimestamp, j as PaymentResult, o as ProtocolName, l as PaymentSubmission, i as PaymentRequirement, A as AdapterDescriptor, R as ResourceRegistry, L as Logger, c as Clock, d as IdGenerator, a as AdapterHealth } from './runtime-
|
|
2
|
+
import { I as IsoTimestamp, j as PaymentResult, o as ProtocolName, l as PaymentSubmission, i as PaymentRequirement, A as AdapterDescriptor, R as ResourceRegistry, L as Logger, c as Clock, d as IdGenerator, a as AdapterHealth } from './runtime-Bie-9FAM.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Canonical commerce events.
|
|
6
6
|
*
|
|
7
7
|
* FROZEN CONTRACT. Every event in a single flow shares one `requestId` so that
|
|
8
|
-
* logs, payment attempts, backend calls and receipts are correlatable
|
|
9
|
-
*.
|
|
8
|
+
* logs, payment attempts, backend calls and receipts are correlatable.
|
|
10
9
|
*/
|
|
11
10
|
|
|
12
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"];
|
|
@@ -81,7 +81,7 @@ declare const DEFAULT_BACKEND_TIMEOUT_MS = 10000;
|
|
|
81
81
|
* Canonical pricing.
|
|
82
82
|
*
|
|
83
83
|
* `dynamic` exists in the type system for forward compatibility but is
|
|
84
|
-
* REJECTED by config validation in
|
|
84
|
+
* REJECTED by config validation in this release.
|
|
85
85
|
*/
|
|
86
86
|
type Pricing = {
|
|
87
87
|
readonly type: 'free';
|
|
@@ -140,6 +140,18 @@ interface PaymentChallenge {
|
|
|
140
140
|
/** Provider protocol version, e.g. the x402 `x402Version` value as a string. */
|
|
141
141
|
readonly version: string;
|
|
142
142
|
readonly accepts: readonly Readonly<Record<string, unknown>>[];
|
|
143
|
+
/**
|
|
144
|
+
* The provider's own challenge document, verbatim — for x402 v2 the
|
|
145
|
+
* `PaymentRequired` object a buyer's client consumes.
|
|
146
|
+
*
|
|
147
|
+
* `accepts` alone is not that document: v2 moves the resource description
|
|
148
|
+
* out of the individual requirements and up onto the envelope, and the
|
|
149
|
+
* protocol version rides there too. Protocol adapters that have a native
|
|
150
|
+
* channel for it (the HTTP `PAYMENT-REQUIRED` header) emit this as-is
|
|
151
|
+
* rather than reassembling it, so every surface offers the same challenge
|
|
152
|
+
* instead of each building its own from parts. Opaque to core.
|
|
153
|
+
*/
|
|
154
|
+
readonly envelope?: Readonly<Record<string, unknown>>;
|
|
143
155
|
}
|
|
144
156
|
/**
|
|
145
157
|
* What the buyer must pay, in canonical terms, plus the provider-native
|
|
@@ -163,8 +175,8 @@ interface PaymentRequirement {
|
|
|
163
175
|
/**
|
|
164
176
|
* Opaque payment proof supplied by the buyer's client.
|
|
165
177
|
*
|
|
166
|
-
* For x402 over HTTP this is the base64 `
|
|
167
|
-
* is the same string carried in the tool input's `_payment` field.
|
|
178
|
+
* For x402 over HTTP this is the base64 `PAYMENT-SIGNATURE` header value; over
|
|
179
|
+
* MCP it is the same string carried in the tool input's `_payment` field.
|
|
168
180
|
*/
|
|
169
181
|
interface PaymentSubmission {
|
|
170
182
|
readonly method: PaymentMethodName;
|
package/dist/x402.d.ts
CHANGED
|
@@ -1,16 +1,54 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { X as X402FacilitatorConfig } from './guardrails-Di_yI_DW.js';
|
|
2
|
+
export { F as FacilitatorAuth } from './guardrails-Di_yI_DW.js';
|
|
3
|
+
import { L as Logger, c as Clock, d as IdGenerator, b as PaymentProvider } from './runtime-Bie-9FAM.js';
|
|
4
|
+
|
|
5
|
+
interface NetworkProfile {
|
|
6
|
+
/** CAIP-2 identifier, e.g. `eip155:84532`. */
|
|
7
|
+
readonly id: string;
|
|
8
|
+
/** Signed into the buyer's EIP-712 domain. */
|
|
9
|
+
readonly chainId: number;
|
|
10
|
+
readonly displayName: string;
|
|
11
|
+
readonly kind: 'testnet' | 'mainnet';
|
|
12
|
+
/**
|
|
13
|
+
* The USDC deployment this network is expected to settle in. Enforced only
|
|
14
|
+
* on mainnet (see `guardrails.ts`) — a testnet is where a mock token is a
|
|
15
|
+
* legitimate thing to point at.
|
|
16
|
+
*/
|
|
17
|
+
readonly canonicalAsset?: {
|
|
18
|
+
readonly symbol: string;
|
|
19
|
+
readonly address: string;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
declare const SUPPORTED_NETWORK_IDS: readonly string[];
|
|
23
|
+
/**
|
|
24
|
+
* What this deployment actually is, as opposed to what it is called.
|
|
25
|
+
*
|
|
26
|
+
* `local` is a property of the *facilitator*, not the network: settling
|
|
27
|
+
* through the in-process facilitator against a dev node is local regardless of
|
|
28
|
+
* the CAIP-2 id that node answers to. This distinction is the whole reason
|
|
29
|
+
* diagnostics can say `eip155:84532` without claiming to be on public Base
|
|
30
|
+
* Sepolia.
|
|
31
|
+
*/
|
|
32
|
+
type DeploymentMode = 'local' | 'testnet' | 'mainnet';
|
|
2
33
|
|
|
3
34
|
/**
|
|
4
35
|
* CLIENT-SIDE payment helper.
|
|
5
36
|
*
|
|
6
37
|
* This module is used by the demo buyer agent (`demo/agent`) and by the
|
|
7
|
-
* payment E2E test suite to build and EIP-712-sign an x402 `exact`/EVM
|
|
38
|
+
* payment E2E test suite to build and EIP-712-sign an x402 v2 `exact`/EVM
|
|
8
39
|
* payment authorisation, entirely on the buyer's side.
|
|
9
40
|
*
|
|
10
41
|
* The gateway NEVER calls this module and NEVER holds a buyer private key.
|
|
11
42
|
* `buyerPrivateKey` here is always an Anvil well-known
|
|
12
43
|
* development key (LOCAL DEVELOPMENT ONLY — DO NOT FUND) supplied by whoever
|
|
13
44
|
* is driving the demo/test, not something the provider or gateway manages.
|
|
45
|
+
*
|
|
46
|
+
* It signs the EIP-712 authorisation directly rather than going through the
|
|
47
|
+
* SDK's `x402Client`, for one reason: `overrides`. The negative payment tests
|
|
48
|
+
* need authorisations that are deliberately wrong — wrong recipient, short
|
|
49
|
+
* amount, reused nonce, expired window — and a conforming client will not
|
|
50
|
+
* produce those. Interop with a real SDK client is proved separately, by a
|
|
51
|
+
* test that pays the gateway using `x402Client` itself.
|
|
14
52
|
*/
|
|
15
53
|
interface CreatePaymentProofOptions {
|
|
16
54
|
/** Buyer's dev-only private key. LOCAL DEVELOPMENT ONLY — DO NOT FUND. */
|
|
@@ -27,23 +65,34 @@ interface CreatePaymentProofOptions {
|
|
|
27
65
|
readonly validAfter?: number;
|
|
28
66
|
};
|
|
29
67
|
}
|
|
30
|
-
/** Returns the base64 `
|
|
68
|
+
/** Returns the base64 `PAYMENT-SIGNATURE` value to send back to the gateway. */
|
|
31
69
|
declare function createPaymentProof(options: CreatePaymentProofOptions): Promise<string>;
|
|
32
70
|
|
|
33
71
|
/**
|
|
34
|
-
* x402 payment provider — `exact` scheme, EVM,
|
|
72
|
+
* x402 payment provider — protocol version 2, `exact` scheme, EVM,
|
|
73
|
+
* EIP-3009 `transferWithAuthorization`.
|
|
35
74
|
*
|
|
36
75
|
* Implements the frozen `PaymentProvider` interface (src/core/domain/payment.ts).
|
|
37
76
|
* `verify()` never moves funds; only `settle()` does, and only after a
|
|
38
77
|
* successful `verify()` (enforced by the gateway's execution pipeline, not by
|
|
39
78
|
* this file, but this file never calls settle-like RPCs from verify()).
|
|
40
79
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
80
|
+
* Verification and settlement run through the SDK's own `x402Facilitator`
|
|
81
|
+
* with the `exact`/EVM scheme registered against a single CAIP-2 network. The
|
|
82
|
+
* facilitator is in-process — it is the same code a hosted facilitator runs,
|
|
83
|
+
* pointed at the local dev chain — so there is no network hop and no third
|
|
84
|
+
* party in the settlement path.
|
|
85
|
+
*
|
|
86
|
+
* The SDK behaviour relied on here is verified, not assumed: see the notes
|
|
87
|
+
* beside each call site below.
|
|
43
88
|
*/
|
|
44
89
|
|
|
45
90
|
interface X402ProviderOptions {
|
|
46
|
-
/**
|
|
91
|
+
/**
|
|
92
|
+
* CAIP-2 network identifier, e.g. `eip155:84532`. The chain id it carries is
|
|
93
|
+
* part of the EIP-712 domain the buyer signs, so it is read from this value
|
|
94
|
+
* rather than defaulted.
|
|
95
|
+
*/
|
|
47
96
|
readonly network: string;
|
|
48
97
|
/** RPC endpoint. Local chain: http://127.0.0.1:8545 */
|
|
49
98
|
readonly rpcUrl: string;
|
|
@@ -58,20 +107,23 @@ interface X402ProviderOptions {
|
|
|
58
107
|
readonly payTo: `0x${string}`;
|
|
59
108
|
readonly maxTimeoutSeconds?: number;
|
|
60
109
|
/**
|
|
61
|
-
*
|
|
62
|
-
*
|
|
110
|
+
* Which facilitator verifies and broadcasts.
|
|
111
|
+
*
|
|
112
|
+
* `local` runs the facilitator in this process against the dev chain, and
|
|
113
|
+
* its `signerPrivateKey` must be an Anvil well-known key — LOCAL DEVELOPMENT
|
|
114
|
+
* ONLY — DO NOT FUND. `remote` calls an HTTP facilitator, and this gateway
|
|
115
|
+
* then holds no signing key at all.
|
|
63
116
|
*/
|
|
64
|
-
readonly facilitator:
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
};
|
|
117
|
+
readonly facilitator: X402FacilitatorConfig;
|
|
118
|
+
/**
|
|
119
|
+
* Required to be `true` before anything settles on a mainnet. Never a
|
|
120
|
+
* default — see `guardrails.ts`.
|
|
121
|
+
*/
|
|
122
|
+
readonly allowMainnet?: boolean;
|
|
71
123
|
readonly logger?: Logger;
|
|
72
124
|
readonly clock?: Clock;
|
|
73
125
|
readonly ids?: IdGenerator;
|
|
74
126
|
}
|
|
75
127
|
declare function createX402PaymentProvider(options: X402ProviderOptions): PaymentProvider;
|
|
76
128
|
|
|
77
|
-
export { type CreatePaymentProofOptions, type X402ProviderOptions, createPaymentProof, createX402PaymentProvider, createX402PaymentProvider as x402 };
|
|
129
|
+
export { type CreatePaymentProofOptions, type DeploymentMode, type NetworkProfile, SUPPORTED_NETWORK_IDS, X402FacilitatorConfig, type X402ProviderOptions, createPaymentProof, createX402PaymentProvider, createX402PaymentProvider as x402 };
|