@devlab.group/agent-commerce 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +73 -71
  2. package/dist/ap2.d.ts +20 -23
  3. package/dist/ap2.js +53 -75
  4. package/dist/ap2.js.map +1 -1
  5. package/dist/authorization-BpbWGGrf.d.ts +115 -0
  6. package/dist/{chunk-PBYN7EK2.js → chunk-74BSEXB5.js} +10 -9
  7. package/dist/chunk-74BSEXB5.js.map +1 -0
  8. package/dist/chunk-AFI2CEZS.js +10 -0
  9. package/dist/chunk-AFI2CEZS.js.map +1 -0
  10. package/dist/{chunk-NKNXVDHN.js → chunk-ATTWSFQP.js} +45 -66
  11. package/dist/chunk-ATTWSFQP.js.map +1 -0
  12. package/dist/{chunk-5GEWKNIH.js → chunk-IVJC5YLE.js} +63 -27
  13. package/dist/chunk-IVJC5YLE.js.map +1 -0
  14. package/dist/{chunk-US622BKF.js → chunk-RAJGPGJG.js} +5 -8
  15. package/dist/chunk-RAJGPGJG.js.map +1 -0
  16. package/dist/{chunk-6D2EZ5ME.js → chunk-V2V2E7HX.js} +2 -2
  17. package/dist/{chunk-6D2EZ5ME.js.map → chunk-V2V2E7HX.js.map} +1 -1
  18. package/dist/cli/index.js +501 -494
  19. package/dist/cli/index.js.map +1 -1
  20. package/dist/{constants-6mypC60h.d.ts → constants-Bkq04FRZ.d.ts} +1 -3
  21. package/dist/guardrails-71XwtXlT.d.ts +31 -0
  22. package/dist/index.d.ts +230 -265
  23. package/dist/index.js +1050 -607
  24. package/dist/index.js.map +1 -1
  25. package/dist/mcp.d.ts +6 -59
  26. package/dist/mcp.js +61 -53
  27. package/dist/mcp.js.map +1 -1
  28. package/dist/mpp.d.ts +4 -4
  29. package/dist/mpp.js +21 -19
  30. package/dist/mpp.js.map +1 -1
  31. package/dist/protocol-adapter-DTkrXTev.d.ts +238 -0
  32. package/dist/runtime-CiYbgGpi.d.ts +303 -0
  33. package/dist/{types-CJtwLu1c.d.ts → types-O6lg3Q5V.d.ts} +17 -23
  34. package/dist/x402.d.ts +43 -75
  35. package/dist/x402.js +10 -9
  36. package/dist/x402.js.map +1 -1
  37. package/package.json +1 -1
  38. package/dist/authorization-DA7mjy_O.d.ts +0 -123
  39. package/dist/chunk-5GEWKNIH.js.map +0 -1
  40. package/dist/chunk-NKNXVDHN.js.map +0 -1
  41. package/dist/chunk-PBYN7EK2.js.map +0 -1
  42. package/dist/chunk-US622BKF.js.map +0 -1
  43. package/dist/guardrails-Dmwi63KB.d.ts +0 -38
  44. package/dist/protocol-adapter-APRjs1E2.d.ts +0 -273
  45. package/dist/runtime-DC5XQ9Cc.d.ts +0 -351
package/dist/mcp.d.ts CHANGED
@@ -1,67 +1,14 @@
1
- import { H as HttpProtocolAdapter } from './protocol-adapter-APRjs1E2.js';
1
+ import { H as HttpProtocolAdapter } from './protocol-adapter-DTkrXTev.js';
2
2
  import 'node:http';
3
- import './runtime-DC5XQ9Cc.js';
4
- import './authorization-DA7mjy_O.js';
5
-
6
- /**
7
- * MCP protocol adapter.
8
- *
9
- * One MCP tool per canonical resource exposed via `exposedVia: ['mcp']`.
10
- * Every `tools/call` builds a `CanonicalRequest` and goes through
11
- * `context.pipeline.execute()` — this file never calls a merchant backend and
12
- * never inspects a payment object, it only surfaces what the pipeline
13
- * returns.
14
- *
15
- * Transport: Streamable HTTP, **stateless** mode (no `sessionIdGenerator`,
16
- * i.e. session id generation left undefined). A fresh low-level `Server` +
17
- * `StreamableHTTPServerTransport` pair is created per HTTP request and torn
18
- * down when the response closes —
19
- * this is the pattern @modelcontextprotocol/sdk@1.30.0's own
20
- * `examples/server/simpleStatelessStreamableHttp.js` uses, and it avoids
21
- * holding cross-request session state the gateway has no lifecycle hook for.
22
- *
23
- * Tool registration uses the low-level `Server` (`setRequestHandler` for
24
- * `ListToolsRequestSchema` / `CallToolRequestSchema`) rather than the
25
- * higher-level `McpServer.registerTool`. `McpServer.registerTool`'s
26
- * `inputSchema` only accepts a Zod schema or a raw Zod shape
27
- * (`server/zod-compat.d.ts`: `AnySchema = z3.ZodTypeAny | z4.$ZodType`) — it
28
- * does not accept a raw JSON Schema object. The canonical
29
- * `CommerceResource.inputSchema` is already JSON Schema, and the MCP wire
30
- * format for `Tool.inputSchema` *is* JSON Schema, so building `Tool` objects
31
- * directly (via the low-level `Server`) carries it through verbatim with no
32
- * lossy JSON-Schema-to-Zod conversion. `Server` is marked `@deprecated` in
33
- * favour of `McpServer`'s ergonomics, but remains fully supported — its
34
- * documented use is exactly this kind of advanced, non-Zod case.
35
- *
36
- * Origin/Host validation (DNS-rebinding protection): deliberately NOT done
37
- * here. `StreamableHTTPServerTransport` is constructed with no
38
- * `allowedHosts`/`allowedOrigins`/`enableDnsRebindingProtection` — all three
39
- * are `@deprecated` in the pinned SDK's own
40
- * `webStandardStreamableHttp.d.ts`, in favour of exactly the fix applied
41
- * here: an allowlist enforced by the *host* before a request ever reaches an
42
- * adapter. `src/gateway`'s `onRequest` hook is that enforcement point —
43
- * it covers `/mcp` and the HTTP routes together, so there is one allowlist
44
- * for the whole gateway instead of one per adapter. This adapter has no
45
- * config surface to build a second one from: `McpAdapterOptions` is frozen
46
- * (docs/contracts.md) to `{ mountPath?, serverName?, serverVersion? }`, and
47
- * the only signal available without a contract change —
48
- * `context.publicBaseUrl` — is one string that may not match what a
49
- * reverse-proxied deployment's `Host`/`Origin` headers actually carry. A
50
- * second, narrower allowlist built from it would not add coverage the
51
- * gateway's hook doesn't already provide; it would only add a second place
52
- * that can reject legitimate traffic the gateway just allowed, for a
53
- * deprecated code path upstream is steering consumers away from. Revisit
54
- * this if the adapter is ever meant to be mounted somewhere other than this
55
- * gateway. See `descriptor.unsupported` — this reliance on the host is
56
- * recorded there too, not just here, so `doctor`/`.well-known` surface it.
57
- */
3
+ import './runtime-CiYbgGpi.js';
4
+ import './authorization-BpbWGGrf.js';
58
5
 
59
6
  interface McpAdapterOptions {
60
- /** Path prefix the gateway mounts this adapter at. Default '/mcp'. */
7
+ /** Path prefix the gateway mounts this adapter at. Default '/mcp' */
61
8
  readonly mountPath?: string;
62
- /** MCP `Implementation.name` reported during initialize. */
9
+ /** MCP `Implementation.name` reported during initialize */
63
10
  readonly serverName?: string;
64
- /** MCP `Implementation.version` reported during initialize. Default: this package's version. */
11
+ /** MCP `Implementation.version` reported during initialize. Default: this package's version */
65
12
  readonly serverVersion?: string;
66
13
  }
67
14
  declare function createMcpAdapter(options?: McpAdapterOptions): HttpProtocolAdapter;
package/dist/mcp.js CHANGED
@@ -1,4 +1,5 @@
1
- import { PACKAGE_VERSION, toCommerceError, CommerceError, extractReservedInputFields, PAYMENT_INPUT_FIELD, toErrorEnvelope, DELIVERY_SUMMARY_META_KEY, toDeliverySummary, toPaymentRequiredEnvelope } from './chunk-5GEWKNIH.js';
1
+ import { MCP_TOOL_NAME_PATTERN } from './chunk-AFI2CEZS.js';
2
+ import { PACKAGE_VERSION, toLogInfo, toCommerceError, CommerceError, extractReservedInputFields, isRecord, PAYMENT_INPUT_FIELD, AUTHORIZATION_INPUT_FIELD, toErrorEnvelope, DELIVERY_SUMMARY_META_KEY, toDeliverySummary, toPaymentRequiredEnvelope } from './chunk-IVJC5YLE.js';
2
3
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3
4
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
4
5
  import { ListToolsRequestSchema, CallToolRequestSchema, LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/sdk/types.js';
@@ -36,10 +37,9 @@ function toRecord(value) {
36
37
  function deliveredResult(outcome) {
37
38
  const body = outcome.body;
38
39
  const text = typeof body === "string" ? body : JSON.stringify(body ?? null);
39
- const isStructured = typeof body === "object" && body !== null && !Array.isArray(body);
40
40
  return {
41
41
  content: [{ type: "text", text }],
42
- ...isStructured ? { structuredContent: toRecord(body) } : {},
42
+ ...isRecord(body) ? { structuredContent: body } : {},
43
43
  _meta: { [DELIVERY_SUMMARY_META_KEY]: toRecord(toDeliverySummary(outcome)) }
44
44
  };
45
45
  }
@@ -66,7 +66,6 @@ function mapOutcome(outcome) {
66
66
  }
67
67
 
68
68
  // src/protocols/mcp/tool-mapping.ts
69
- var MCP_TOOL_NAME_PATTERN = /^[A-Za-z0-9._-]{1,128}$/;
70
69
  function isValidToolName(id) {
71
70
  return MCP_TOOL_NAME_PATTERN.test(id);
72
71
  }
@@ -94,6 +93,13 @@ function paymentInputFieldDescription(resource) {
94
93
  }
95
94
  return "Payment proof returned from a previous payment-required response.";
96
95
  }
96
+ function requiredAuthorization(resource) {
97
+ return resource.authorization?.required ?? [];
98
+ }
99
+ function authorizationNote(resource) {
100
+ const methods = requiredAuthorization(resource);
101
+ return methods.length > 0 ? ` Also requires ${methods.join(" and ")} authorization in the "${AUTHORIZATION_INPUT_FIELD}" input field.` : "";
102
+ }
97
103
  function buildToolDescription(resource) {
98
104
  const base = resource.description ?? resource.name;
99
105
  switch (resource.pricing.type) {
@@ -101,20 +107,17 @@ function buildToolDescription(resource) {
101
107
  return base;
102
108
  case "fixed": {
103
109
  const { amount, currency } = resource.pricing;
104
- return `${base} Costs ${amount} ${currency} per call. ${paymentProofNote(resource)}`;
110
+ return `${base} Costs ${amount} ${currency} per call. ${paymentProofNote(resource)}${authorizationNote(resource)}`;
105
111
  }
106
112
  case "dynamic":
107
- return `${base} Requires payment (amount determined at request time). ${paymentProofNote(resource)}`;
113
+ return `${base} Requires payment (amount determined at request time). ${paymentProofNote(resource)}${authorizationNote(resource)}`;
108
114
  }
109
115
  }
110
- function isPlainObject(value) {
111
- return typeof value === "object" && value !== null && !Array.isArray(value);
112
- }
113
116
  function buildInputSchema(resource) {
114
117
  const base = resource.inputSchema;
115
- const baseIsObject = isPlainObject(base);
116
- const basePropertyEntries = baseIsObject && isPlainObject(base.properties) ? Object.entries(base.properties).filter(
117
- (entry) => isPlainObject(entry[1])
118
+ const baseIsObject = isRecord(base);
119
+ const basePropertyEntries = baseIsObject && isRecord(base.properties) ? Object.entries(base.properties).filter(
120
+ (entry) => isRecord(entry[1])
118
121
  ) : [];
119
122
  const properties = Object.fromEntries(basePropertyEntries);
120
123
  if (isPaidResource(resource)) {
@@ -123,6 +126,18 @@ function buildInputSchema(resource) {
123
126
  description: paymentInputFieldDescription(resource)
124
127
  };
125
128
  }
129
+ const methods = requiredAuthorization(resource);
130
+ if (methods.length > 0) {
131
+ properties[AUTHORIZATION_INPUT_FIELD] = {
132
+ type: "object",
133
+ description: "Authorization this resource requires in addition to payment: the method and its serialized proof.",
134
+ properties: {
135
+ method: { type: "string", enum: [...methods] },
136
+ payload: { type: "string", minLength: 1 }
137
+ },
138
+ required: ["method", "payload"]
139
+ };
140
+ }
126
141
  const required = baseIsObject && Array.isArray(base.required) ? base.required.filter((v) => typeof v === "string") : [];
127
142
  const extra = baseIsObject ? Object.fromEntries(
128
143
  Object.entries(base).filter(
@@ -154,13 +169,9 @@ var McpProtocolAdapter = class {
154
169
  toolsByResourceId = /* @__PURE__ */ new Map();
155
170
  skipped = [];
156
171
  activeTransports = /* @__PURE__ */ new Set();
157
- // Counting semaphore bounding concurrent `context.pipeline.execute()`
158
- // calls. Lives on the adapter instance (one per gateway mount, for the
159
- // process lifetime), not per-request, so the cap holds across concurrent
160
- // `/mcp` requests too — not just within one oversized batch. A request
161
- // only ever waits here once MAX_CONCURRENT_TOOL_CALLS executions are
162
- // already in flight adapter-wide, which is the throttle working as
163
- // intended, not two unrelated single-call requests blocking each other.
172
+ // Counting semaphore on `pipeline.execute()`. It lives on the adapter, not
173
+ // the request, so the cap holds across concurrent `/mcp` requests as well
174
+ // as within one batch.
164
175
  inFlightToolCalls = 0;
165
176
  toolCallWaiters = [];
166
177
  constructor(options = {}) {
@@ -177,7 +188,7 @@ var McpProtocolAdapter = class {
177
188
  resources = context.resources.listExposedVia("mcp");
178
189
  } catch (err) {
179
190
  context.logger.error(
180
- { adapter: "mcp", err: toCommerceError(err).toInfo() },
191
+ { adapter: "mcp", err: toLogInfo(err) },
181
192
  "mcp adapter: failed to list mcp-exposed resources"
182
193
  );
183
194
  resources = [];
@@ -259,7 +270,7 @@ var McpProtocolAdapter = class {
259
270
  await transport.handleRequest(req, res);
260
271
  } catch (err) {
261
272
  this.context?.logger.error(
262
- { adapter: "mcp", err: toCommerceError(err).toInfo() },
273
+ { adapter: "mcp", err: toLogInfo(err) },
263
274
  "mcp adapter: request handling failed"
264
275
  );
265
276
  this.writeJsonRpcError(res, 500, "Internal server error.");
@@ -267,23 +278,15 @@ var McpProtocolAdapter = class {
267
278
  }
268
279
  async health() {
269
280
  const checkedAt = this.context?.clock.nowIso() ?? (/* @__PURE__ */ new Date()).toISOString();
270
- try {
271
- if (!this.started || !this.context) {
272
- return { status: "fail", detail: "MCP adapter has not been started.", checkedAt };
273
- }
274
- const toolCount = this.tools.length;
275
- if (this.skipped.length > 0) {
276
- const detail = `${toolCount} tool(s) registered; ${this.skipped.length} resource(s) skipped: ${this.skipped.map((s) => `${s.id} (${s.reason})`).join("; ")}`;
277
- return { status: "warn", detail, checkedAt };
278
- }
279
- return { status: "pass", detail: `${toolCount} tool(s) registered.`, checkedAt };
280
- } catch (err) {
281
- return {
282
- status: "fail",
283
- detail: `mcp adapter health check failed: ${toCommerceError(err).message}`,
284
- checkedAt
285
- };
281
+ if (!this.started || !this.context) {
282
+ return { status: "fail", detail: "MCP adapter has not been started.", checkedAt };
283
+ }
284
+ const toolCount = this.tools.length;
285
+ if (this.skipped.length > 0) {
286
+ const detail = `${toolCount} tool(s) registered; ${this.skipped.length} resource(s) skipped: ${this.skipped.map((s) => `${s.id} (${s.reason})`).join("; ")}`;
287
+ return { status: "warn", detail, checkedAt };
286
288
  }
289
+ return { status: "pass", detail: `${toolCount} tool(s) registered.`, checkedAt };
287
290
  }
288
291
  async stop() {
289
292
  this.started = false;
@@ -361,39 +364,44 @@ var McpProtocolAdapter = class {
361
364
  this.releaseToolCallSlot();
362
365
  }
363
366
  } catch (err) {
364
- return errorResult(toCommerceError(err));
367
+ const error = toCommerceError(err);
368
+ context.logger.warn(
369
+ { adapter: "mcp", resourceId, err: toLogInfo(error) },
370
+ "mcp adapter: execution failed"
371
+ );
372
+ return errorResult(error);
365
373
  }
366
374
  }
367
375
  /**
368
- * Blocks until fewer than MAX_CONCURRENT_TOOL_CALLS executions are in
369
- * flight, or throws if the queue behind that gate is already full or the
370
- * caller disconnected while waiting. Throwing
371
- * here never leaks a permit: `inFlightToolCalls` is only incremented on
372
- * the success path below, after every rejection point.
376
+ * Takes a permit, or queues for one when MAX_CONCURRENT_TOOL_CALLS are in
377
+ * flight. Throws when the queue is full or the caller disconnected while
378
+ * queued; a throw never leaks a permit.
373
379
  */
374
380
  async acquireToolCallSlot(signal) {
381
+ if (this.inFlightToolCalls < MAX_CONCURRENT_TOOL_CALLS) {
382
+ this.inFlightToolCalls++;
383
+ return;
384
+ }
375
385
  if (this.toolCallWaiters.length >= MAX_QUEUED_TOOL_CALLS) {
376
386
  throw new CommerceError(
377
387
  "GATEWAY_BUSY",
378
388
  "Too many tool calls already queued on this adapter; retry later."
379
389
  );
380
390
  }
381
- while (this.inFlightToolCalls >= MAX_CONCURRENT_TOOL_CALLS) {
382
- await new Promise((resolve) => this.toolCallWaiters.push(resolve));
383
- if (signal.aborted) {
384
- this.toolCallWaiters.shift()?.();
385
- throw new CommerceError("PROTOCOL_UNSUPPORTED", "Client disconnected while queued.");
386
- }
391
+ await new Promise((resolve) => this.toolCallWaiters.push(resolve));
392
+ if (signal.aborted) {
393
+ this.releaseToolCallSlot();
394
+ throw new CommerceError("PROTOCOL_UNSUPPORTED", "Client disconnected while queued.");
387
395
  }
388
- this.inFlightToolCalls++;
389
396
  }
390
397
  releaseToolCallSlot() {
391
- this.inFlightToolCalls--;
392
- this.toolCallWaiters.shift()?.();
398
+ const next = this.toolCallWaiters.shift();
399
+ if (next !== void 0) next();
400
+ else this.inFlightToolCalls--;
393
401
  }
394
402
  };
395
403
  function createMcpAdapter(options) {
396
- return new McpProtocolAdapter(options ?? {});
404
+ return new McpProtocolAdapter(options);
397
405
  }
398
406
 
399
407
  export { createMcpAdapter, createMcpAdapter as mcp };
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 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, in the proof\n * encoding of the resource's own rail.\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 === 'mpp') {\n return 'MPP credential (the full \"Authorization: Payment ...\" value) for the challenge in 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
+ {"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` is the SDK's `LATEST_PROTOCOL_VERSION`. The SDK's\n * `initialize` echoes a requested version it supports, older ones included,\n * and otherwise answers with this one, so it is the best single value to\n * report.\n */\nimport { LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/sdk/types.js';\nimport type { AdapterDescriptor } from '../../core';\n\n// The MCP protocol revision this adapter targets\nconst MCP_SUPPORTED_SPEC = LATEST_PROTOCOL_VERSION;\n\n// Tool-oriented capabilities this adapter implements\nconst MCP_CAPABILITIES: readonly string[] = ['tools/list', 'tools/call'];\n\n/**\n * MCP surfaces this adapter does not implement, listed so its descriptor never\n * implies blanket protocol compatibility.\n *\n * `dns-rebinding-protection` is delegated rather than missing: the gateway's\n * `onRequest` hook validates Host and Origin for `/mcp` (see adapter.ts), and\n * the adapter provides none 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 pipeline outcomes and errors to MCP tool results through the core wire\n * helpers (`toErrorEnvelope`, `toPaymentRequiredEnvelope`,\n * `toDeliverySummary`). The A2A adapter uses all three and the HTTP route the\n * two envelopes, so each shape is defined once.\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';\nimport { isRecord } from '../../core/is-record';\n\nfunction toRecord(value: object): Record<string, unknown> {\n return value as Record<string, unknown>;\n}\n\nfunction deliveredResult(outcome: DeliveredOutcome): CallToolResult {\n const body = outcome.body;\n const text = typeof body === 'string' ? body : JSON.stringify(body ?? null);\n return {\n content: [{ type: 'text', text }],\n ...(isRecord(body) ? { structuredContent: body } : {}),\n _meta: { [DELIVERY_SUMMARY_META_KEY]: toRecord(toDeliverySummary(outcome)) },\n };\n}\n\nfunction 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`: the tool name is the\n * resource id, the description carries a price notice for a paid resource,\n * and the input schema is the canonical JSON Schema plus the reserved\n * `_payment` and `_authorization` properties the resource accepts\n */\n\nimport type { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport {\n AUTHORIZATION_INPUT_FIELD,\n type CommerceResource,\n PAYMENT_INPUT_FIELD,\n type PaymentMethodName,\n} from '../../core';\nimport { isRecord } from '../../core/is-record';\nimport { MCP_TOOL_NAME_PATTERN } from './constants';\n\nexport function isValidToolName(id: string): boolean {\n return MCP_TOOL_NAME_PATTERN.test(id);\n}\n\nfunction isPaidResource(resource: CommerceResource): boolean {\n return resource.pricing.type !== 'free';\n}\n\n// The rail a `_payment` proof is labeled with (see `extractReservedInputFields`),\n// `undefined` when the resource lists none\nfunction primaryPaymentMethod(resource: CommerceResource): PaymentMethodName | undefined {\n return resource.paymentMethods[0];\n}\n\n// How to supply a proof, generic when the resource names no rail\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, in the proof\n * encoding of the resource's own rail\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 === 'mpp') {\n return 'MPP credential (the full \"Authorization: Payment ...\" value) for the challenge in 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// The authorization methods the resource requires, empty when it requires none\nfunction requiredAuthorization(resource: CommerceResource): readonly string[] {\n return resource.authorization?.required ?? [];\n}\n\nfunction authorizationNote(resource: CommerceResource): string {\n const methods = requiredAuthorization(resource);\n return methods.length > 0\n ? ` Also requires ${methods.join(' and ')} authorization in the \"${AUTHORIZATION_INPUT_FIELD}\" input field.`\n : '';\n}\n\n/**\n * Tool description. A paid resource gets a price notice appended, so an agent\n * sees the cost before calling, not 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)}${authorizationNote(resource)}`;\n }\n case 'dynamic':\n return `${base} Requires payment (amount determined at request time). ${paymentProofNote(resource)}${authorizationNote(resource)}`;\n }\n}\n\n/**\n * Builds the MCP `Tool.inputSchema` from the canonical `CommerceResource.inputSchema`.\n *\n * Every keyword is carried through except that `type` is forced to the\n * `'object'` MCP requires, `properties` keeps only object-valued entries and\n * `required` only strings. A paid resource gains the optional `_payment`\n * string property, and a resource requiring authorization the optional\n * `_authorization` object. Both are declared because a resource's input schema\n * is closed by default, and a client that validates arguments against it\n * would otherwise refuse to send them.\n */\nexport function buildInputSchema(resource: CommerceResource): Tool['inputSchema'] {\n const base = resource.inputSchema;\n const baseIsObject = isRecord(base);\n\n const basePropertyEntries: readonly [string, object][] =\n baseIsObject && isRecord(base.properties)\n ? Object.entries(base.properties).filter((entry): entry is [string, object] =>\n isRecord(entry[1]),\n )\n : [];\n const properties: Record<string, object> = Object.fromEntries(basePropertyEntries);\n\n // Both overwrite a resource-declared property of the same name; config\n // rejects that collision at load time\n if (isPaidResource(resource)) {\n properties[PAYMENT_INPUT_FIELD] = {\n type: 'string',\n description: paymentInputFieldDescription(resource),\n };\n }\n const methods = requiredAuthorization(resource);\n if (methods.length > 0) {\n properties[AUTHORIZATION_INPUT_FIELD] = {\n type: 'object',\n description:\n 'Authorization this resource requires in addition to payment: the method and its serialized proof.',\n properties: {\n method: { type: 'string', enum: [...methods] },\n payload: { type: 'string', minLength: 1 },\n },\n required: ['method', 'payload'],\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 mcp-exposed canonical resource. Every `tools/call` builds a\n * `CanonicalRequest` and goes through `context.pipeline.execute()`; this file\n * never calls a merchant backend and never inspects a payment object.\n *\n * Transport: Streamable HTTP in stateless mode (no `sessionIdGenerator`). A\n * fresh low-level `Server` and `StreamableHTTPServerTransport` pair is created\n * per HTTP request and torn down when the response closes, the pattern of the\n * SDK's `examples/server/simpleStatelessStreamableHttp.js`, so no session\n * state outlives a request.\n *\n * Tools are registered on the low-level `Server`, not through\n * `McpServer.registerTool`, whose `inputSchema` accepts only a Zod schema or\n * shape. `CommerceResource.inputSchema` and the MCP wire `Tool.inputSchema`\n * are both JSON Schema, so building `Tool` objects directly carries the schema\n * through with no lossy conversion. The SDK marks `Server` `@deprecated` but\n * still documents it for advanced cases such as this one.\n *\n * Host and Origin validation (DNS-rebinding protection) is not done here. The\n * SDK deprecates the transport's `allowedHosts`, `allowedOrigins` and\n * `enableDnsRebindingProtection` in favor of validation by the host. The\n * gateway's server-wide `onRequest` hook checks every request, `/mcp`\n * included, and `McpAdapterOptions` offers nothing to build a second\n * allowlist from. Mounted outside this gateway, the adapter has no such\n * protection, which is why `MCP_UNSUPPORTED`, published at\n * `/.well-known/agent-commerce`, lists `dns-rebinding-protection`.\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';\nimport { toLogInfo } from '../../core/errors';\nimport { PACKAGE_VERSION } from '../../version';\nimport { MCP_TOOL_NAME_PATTERN } from './constants';\nimport { buildDescriptor } from './descriptor';\nimport { errorResult, mapOutcome } from './result-mapping';\nimport { buildInputSchema, buildToolDescription, isValidToolName } from './tool-mapping';\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 SDK's transport accepts a JSON-RPC batch of any length and dispatches\n * every element to the `tools/call` handler without waiting for any to\n * settle, and stateless mode needs no `initialize` first. One POST can\n * therefore start N concurrent `pipeline.execute()` calls, each possibly a\n * live fetch to the merchant. 8 lets an agent's usual handful of concurrent\n * calls run without queuing.\n */\nconst MAX_CONCURRENT_TOOL_CALLS = 8;\n\n/**\n * Bounds the queue behind the semaphore, per adapter instance. Without it an\n * oversized batch would queue in full and then run in full. 64 is 8x\n * MAX_CONCURRENT_TOOL_CALLS, room for a legitimate burst; calls beyond it fail\n * fast with GATEWAY_BUSY and reach no backend.\n */\nconst MAX_QUEUED_TOOL_CALLS = 64;\n\nclass 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 on `pipeline.execute()`. It lives on the adapter, not\n // the request, so the cap holds across concurrent `/mcp` requests as well\n // as within one batch.\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: toLogInfo(err) },\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 // Aborted when the response closes. `handleToolCall` checks it only\n // before `pipeline.execute()`: a call that may already have settled\n // must finish, or the buyer is charged for nothing.\n const abortController = new AbortController();\n const server = this.buildServer(abortController.signal);\n // Stateless: `sessionIdGenerator` is omitted rather than set to\n // `undefined`, as `exactOptionalPropertyTypes` requires; the SDK treats\n // both the same\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 // The transport implements `Transport`; the cast only bridges its\n // `onclose`/`onerror` typed `T | undefined`, which conflicts with a bare\n // optional `T` under `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: toLogInfo(err) },\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 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 }\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: 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 // `tools/list` advertises only mcp-exposed resources, but a client can\n // call any name. The answer is the one an unknown id gets, so it never\n // reveals a resource 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 last cancellation point: a queued call whose caller has left\n // must not start a pipeline run, while a started one may reach\n // settle() and must finish\n if (signal.aborted) {\n // No error code names \"the caller left\". PROTOCOL_UNSUPPORTED is the\n // closest non-retryable one; GATEWAY_BUSY would invite a retry\n // nobody is left to make.\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 released: a stranded permit shrinks the cap for good and\n // eventually deadlocks the adapter\n this.releaseToolCallSlot();\n }\n } catch (err) {\n const error = toCommerceError(err);\n context.logger.warn(\n { adapter: 'mcp', resourceId, err: toLogInfo(error) },\n 'mcp adapter: execution failed',\n );\n return errorResult(error);\n }\n }\n\n /**\n * Takes a permit, or queues for one when MAX_CONCURRENT_TOOL_CALLS are in\n * flight. Throws when the queue is full or the caller disconnected while\n * queued; a throw never leaks a permit.\n */\n private async acquireToolCallSlot(signal: AbortSignal): Promise<void> {\n if (this.inFlightToolCalls < MAX_CONCURRENT_TOOL_CALLS) {\n this.inFlightToolCalls++;\n return;\n }\n if (this.toolCallWaiters.length >= MAX_QUEUED_TOOL_CALLS) {\n // Load shedding is transient, so GATEWAY_BUSY tells the caller to back\n // off and retry\n throw new CommerceError(\n 'GATEWAY_BUSY',\n 'Too many tool calls already queued on this adapter; retry later.',\n );\n }\n // Resolved by releaseToolCallSlot, which hands its permit straight to the\n // oldest waiter, so a call arriving later cannot take it first\n await new Promise<void>((resolve) => this.toolCallWaiters.push(resolve));\n if (signal.aborted) {\n // This waiter now holds a permit it will not use; pass it on\n this.releaseToolCallSlot();\n // Non-retryable, for the same reason as the check in handleToolCall\n throw new CommerceError('PROTOCOL_UNSUPPORTED', 'Client disconnected while queued.');\n }\n }\n\n private releaseToolCallSlot(): void {\n const next = this.toolCallWaiters.shift();\n // Handing the permit over leaves the in-flight count unchanged\n if (next !== undefined) next();\n else this.inFlightToolCalls--;\n }\n}\n\nexport function createMcpAdapter(options?: McpAdapterOptions): HttpProtocolAdapter {\n return new McpProtocolAdapter(options);\n}\n"]}
package/dist/mpp.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- export { a as MPPX_VERSION, b as MPP_PROFILE, c as MPP_SPEC_COMMIT, d as MPP_SPEC_DRAFTS, e as MPP_SPEC_REPOSITORY, f as MPP_SUPPORTED_SPEC } from './constants-6mypC60h.js';
2
- import { A as AdapterDescriptor, L as Logger, C as Clock, e as IdGenerator, d as PaymentProvider } from './runtime-DC5XQ9Cc.js';
3
- import { X as X402FacilitatorConfig } from './guardrails-Dmwi63KB.js';
1
+ export { a as MPPX_VERSION, b as MPP_PROFILE, c as MPP_SPEC_COMMIT, d as MPP_SPEC_DRAFTS, e as MPP_SPEC_REPOSITORY, f as MPP_SUPPORTED_SPEC } from './constants-Bkq04FRZ.js';
2
+ import { A as AdapterDescriptor, L as Logger, C as Clock, e as IdGenerator, d as PaymentProvider } from './runtime-CiYbgGpi.js';
3
+ import { X as X402FacilitatorConfig } from './guardrails-71XwtXlT.js';
4
4
 
5
5
  /**
6
6
  * Describes the MPP profile and its unsupported variants.
@@ -32,7 +32,7 @@ interface MppProviderOptions {
32
32
  readonly facilitator: X402FacilitatorConfig;
33
33
  /** Must be `true` before anything settles on a mainnet. Never a default */
34
34
  readonly allowMainnet?: boolean;
35
- /** Must be `true` to settle on a mainnet through a facilitator that takes no credential */
35
+ /** Required on mainnet when facilitator auth is `none` */
36
36
  readonly allowUnauthenticatedFacilitator?: boolean;
37
37
  readonly logger?: Logger;
38
38
  /**
package/dist/mpp.js CHANGED
@@ -1,8 +1,8 @@
1
- import { MPP_PROFILE, MPP_NETWORKS, MPP_SUPPORTED_SPEC, MPP_DEFAULT_NETWORK, MPP_MIN_CHALLENGE_SECRET_LENGTH, isMppNetwork, MPP_SPEC_DRAFTS } from './chunk-6D2EZ5ME.js';
2
- export { MPPX_VERSION, MPP_PROFILE, MPP_SPEC_COMMIT, MPP_SPEC_DRAFTS, MPP_SPEC_REPOSITORY, MPP_SUPPORTED_SPEC } from './chunk-6D2EZ5ME.js';
3
- import { createX402PaymentProvider, parseCanonicalAmount, computeReplayKey } from './chunk-NKNXVDHN.js';
4
- import './chunk-PBYN7EK2.js';
5
- import { PACKAGE_VERSION, systemClock, CommerceError } from './chunk-5GEWKNIH.js';
1
+ import { MPP_PROFILE, MPP_NETWORKS, MPP_SUPPORTED_SPEC, MPP_DEFAULT_NETWORK, MPP_MIN_CHALLENGE_SECRET_LENGTH, isMppNetwork, MPP_SPEC_DRAFTS } from './chunk-V2V2E7HX.js';
2
+ export { MPPX_VERSION, MPP_PROFILE, MPP_SPEC_COMMIT, MPP_SPEC_DRAFTS, MPP_SPEC_REPOSITORY, MPP_SUPPORTED_SPEC } from './chunk-V2V2E7HX.js';
3
+ import { createX402PaymentProvider, DEFAULT_IDS, parseCanonicalAmount, computeReplayKey } from './chunk-ATTWSFQP.js';
4
+ import './chunk-74BSEXB5.js';
5
+ import { PACKAGE_VERSION, systemClock, CommerceError } from './chunk-IVJC5YLE.js';
6
6
  import { Challenge, Credential, Method, Receipt, PaymentRequest, Errors } from 'mppx';
7
7
  import { Methods } from 'mppx/evm';
8
8
  import { charge } from 'mppx/evm/server';
@@ -41,9 +41,6 @@ var MPP_DESCRIPTOR = {
41
41
  "discovery extension"
42
42
  ]
43
43
  };
44
- var DEFAULT_IDS = {
45
- next: (prefix) => `${prefix ? `${prefix}_` : ""}${crypto.randomUUID()}`
46
- };
47
44
  var DEFAULT_CHALLENGE_TTL_SECONDS = 300;
48
45
  var VERIFICATION_REASONS = [
49
46
  ["EVM authorization challenge hash mismatch", "wrong_nonce"],
@@ -120,6 +117,7 @@ function createMppProviderWithSettlement(options, settlement) {
120
117
  const recipient = getAddress(options.recipient);
121
118
  const asset = getAddress(options.asset);
122
119
  const ids = options.ids ?? DEFAULT_IDS;
120
+ let settlementTermsChecked = false;
123
121
  const method = charge({
124
122
  currency: asset,
125
123
  recipient,
@@ -152,7 +150,10 @@ function createMppProviderWithSettlement(options, settlement) {
152
150
  details: { amount: context.amount }
153
151
  });
154
152
  }
155
- await settlementRequirement(context);
153
+ if (!settlementTermsChecked) {
154
+ await settlementRequirement(context);
155
+ settlementTermsChecked = true;
156
+ }
156
157
  const expires = new Date(clock.now().getTime() + ttlSeconds * 1e3);
157
158
  const challenge = Challenge.fromMethod(Methods.charge, {
158
159
  secretKey: options.challengeSecret,
@@ -185,7 +186,7 @@ function createMppProviderWithSettlement(options, settlement) {
185
186
  provider: "mpp",
186
187
  version: MPP_SPEC_DRAFTS.core,
187
188
  accepts: [challenge],
188
- // Serialised here because the HTTP route, which sends it as
189
+ // Serialized here because the HTTP route, which sends it as
189
190
  // `WWW-Authenticate`, is in the main entry and cannot import mppx
190
191
  envelope: { wwwAuthenticate: Challenge.serialize(challenge) }
191
192
  }
@@ -230,7 +231,9 @@ function createMppProviderWithSettlement(options, settlement) {
230
231
  // validateCredential proved it equals the 32-byte challenge hash
231
232
  nonce: credential.payload.nonce
232
233
  });
233
- const x402Verification = await settlement.verify(await toX402Context(context));
234
+ const x402Verification = await settlement.verify(
235
+ await toX402Context(context, credential.payload)
236
+ );
234
237
  if (x402Verification.status !== "verified") {
235
238
  return rejected(requirement, x402Verification.rejectionReason ?? "settlement_rejected");
236
239
  }
@@ -249,8 +252,8 @@ function createMppProviderWithSettlement(options, settlement) {
249
252
  replayKey
250
253
  };
251
254
  }
252
- async function toX402Context(context) {
253
- const { requestId, requirement, resource, submission } = context;
255
+ async function toX402Context(context, authorization) {
256
+ const { requestId, requirement, resource } = context;
254
257
  const x402Requirement = await settlementRequirement({
255
258
  requestId,
256
259
  resource,
@@ -262,7 +265,7 @@ function createMppProviderWithSettlement(options, settlement) {
262
265
  requestId,
263
266
  resource,
264
267
  requirement: x402Requirement,
265
- submission: toX402Submission(x402Requirement, submission)
268
+ submission: toX402Submission(x402Requirement, authorization)
266
269
  };
267
270
  }
268
271
  async function settlementRequirement(context) {
@@ -283,8 +286,9 @@ function createMppProviderWithSettlement(options, settlement) {
283
286
  "MPP settle() called without a successful verify()"
284
287
  );
285
288
  }
289
+ const authorization = Credential.deserialize(submission.payload).payload;
286
290
  const settled = await settlement.settle({
287
- ...await toX402Context({ requestId, requirement, resource, submission }),
291
+ ...await toX402Context({ requestId, requirement, resource}, authorization),
288
292
  verification: { ...verification, provider: "x402" }
289
293
  });
290
294
  const result = {
@@ -328,10 +332,8 @@ function bindingMismatch(echoed, issued, resourceId) {
328
332
  if (canonical(got) !== canonical(want)) return "wrong_terms";
329
333
  return void 0;
330
334
  }
331
- function toX402Submission(x402Requirement, submission) {
332
- const { signature, from, to, value, validAfter, validBefore, nonce } = Credential.deserialize(
333
- submission.payload
334
- ).payload;
335
+ function toX402Submission(x402Requirement, authorization) {
336
+ const { signature, from, to, value, validAfter, validBefore, nonce } = authorization;
335
337
  const payment = {
336
338
  x402Version: 2,
337
339
  accepted: x402Requirement.challenge.accepts[0],