@devlab.group/agent-commerce 1.5.0 → 1.6.1
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 +73 -71
- package/dist/ap2.d.ts +20 -23
- package/dist/ap2.js +53 -75
- package/dist/ap2.js.map +1 -1
- package/dist/authorization-BpbWGGrf.d.ts +115 -0
- package/dist/chunk-AFI2CEZS.js +10 -0
- package/dist/chunk-AFI2CEZS.js.map +1 -0
- package/dist/{chunk-PBYN7EK2.js → chunk-CBJIT7QP.js} +10 -9
- package/dist/chunk-CBJIT7QP.js.map +1 -0
- package/dist/{chunk-NKNXVDHN.js → chunk-JKEKKXRJ.js} +45 -66
- package/dist/chunk-JKEKKXRJ.js.map +1 -0
- package/dist/{chunk-5GEWKNIH.js → chunk-N5KRK7YA.js} +63 -27
- package/dist/chunk-N5KRK7YA.js.map +1 -0
- package/dist/{chunk-6D2EZ5ME.js → chunk-V2V2E7HX.js} +2 -2
- package/dist/{chunk-6D2EZ5ME.js.map → chunk-V2V2E7HX.js.map} +1 -1
- package/dist/{chunk-US622BKF.js → chunk-VKDXMXHL.js} +5 -8
- package/dist/chunk-VKDXMXHL.js.map +1 -0
- package/dist/cli/index.js +501 -494
- package/dist/cli/index.js.map +1 -1
- package/dist/{constants-6mypC60h.d.ts → constants-Bkq04FRZ.d.ts} +1 -3
- package/dist/guardrails-71XwtXlT.d.ts +31 -0
- package/dist/index.d.ts +230 -265
- package/dist/index.js +1050 -607
- package/dist/index.js.map +1 -1
- package/dist/mcp.d.ts +6 -59
- package/dist/mcp.js +61 -53
- package/dist/mcp.js.map +1 -1
- package/dist/mpp.d.ts +4 -4
- package/dist/mpp.js +21 -19
- package/dist/mpp.js.map +1 -1
- package/dist/protocol-adapter-DTkrXTev.d.ts +238 -0
- package/dist/runtime-CiYbgGpi.d.ts +303 -0
- package/dist/{types-CJtwLu1c.d.ts → types-O6lg3Q5V.d.ts} +17 -23
- package/dist/x402.d.ts +43 -75
- package/dist/x402.js +10 -9
- package/dist/x402.js.map +1 -1
- package/package.json +7 -5
- package/dist/authorization-DA7mjy_O.d.ts +0 -123
- package/dist/chunk-5GEWKNIH.js.map +0 -1
- package/dist/chunk-NKNXVDHN.js.map +0 -1
- package/dist/chunk-PBYN7EK2.js.map +0 -1
- package/dist/chunk-US622BKF.js.map +0 -1
- package/dist/guardrails-Dmwi63KB.d.ts +0 -38
- package/dist/protocol-adapter-APRjs1E2.d.ts +0 -273
- 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-
|
|
1
|
+
import { H as HttpProtocolAdapter } from './protocol-adapter-DTkrXTev.js';
|
|
2
2
|
import 'node:http';
|
|
3
|
-
import './runtime-
|
|
4
|
-
import './authorization-
|
|
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 {
|
|
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-N5KRK7YA.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
|
-
...
|
|
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 =
|
|
116
|
-
const basePropertyEntries = baseIsObject &&
|
|
117
|
-
(entry) =>
|
|
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
|
|
158
|
-
//
|
|
159
|
-
//
|
|
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:
|
|
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:
|
|
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
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
369
|
-
* flight
|
|
370
|
-
*
|
|
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
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
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.
|
|
392
|
-
|
|
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-
|
|
2
|
-
import { A as AdapterDescriptor, L as Logger, C as Clock, e as IdGenerator, d as PaymentProvider } from './runtime-
|
|
3
|
-
import { X as X402FacilitatorConfig } from './guardrails-
|
|
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
|
-
/**
|
|
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-
|
|
2
|
-
export { MPPX_VERSION, MPP_PROFILE, MPP_SPEC_COMMIT, MPP_SPEC_DRAFTS, MPP_SPEC_REPOSITORY, MPP_SUPPORTED_SPEC } from './chunk-
|
|
3
|
-
import { createX402PaymentProvider, parseCanonicalAmount, computeReplayKey } from './chunk-
|
|
4
|
-
import './chunk-
|
|
5
|
-
import { PACKAGE_VERSION, systemClock, CommerceError } from './chunk-
|
|
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-JKEKKXRJ.js';
|
|
4
|
+
import './chunk-CBJIT7QP.js';
|
|
5
|
+
import { PACKAGE_VERSION, systemClock, CommerceError } from './chunk-N5KRK7YA.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
|
-
|
|
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
|
-
//
|
|
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(
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
332
|
-
const { signature, from, to, value, validAfter, validBefore, nonce } =
|
|
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],
|