@devlab.group/agent-commerce 1.6.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +187 -2
- package/README.md +6 -6
- package/dist/ap2.d.ts +2 -2
- package/dist/ap2.js +94 -28
- package/dist/ap2.js.map +1 -1
- package/dist/{chunk-V2V2E7HX.js → chunk-3LUJHVKX.js} +4 -4
- package/dist/{chunk-V2V2E7HX.js.map → chunk-3LUJHVKX.js.map} +1 -1
- package/dist/{chunk-IVJC5YLE.js → chunk-53WXXIPR.js} +3 -3
- package/dist/{chunk-IVJC5YLE.js.map → chunk-53WXXIPR.js.map} +1 -1
- package/dist/chunk-CKJRITWY.js +113 -0
- package/dist/chunk-CKJRITWY.js.map +1 -0
- package/dist/chunk-HOZA3IWP.js +115 -0
- package/dist/chunk-HOZA3IWP.js.map +1 -0
- package/dist/{chunk-ATTWSFQP.js → chunk-RKBGCPCK.js} +78 -25
- package/dist/chunk-RKBGCPCK.js.map +1 -0
- package/dist/{chunk-RAJGPGJG.js → chunk-SYEGCNJZ.js} +3 -3
- package/dist/{chunk-RAJGPGJG.js.map → chunk-SYEGCNJZ.js.map} +1 -1
- package/dist/{chunk-74BSEXB5.js → chunk-TWRUNWDR.js} +11 -4
- package/dist/chunk-TWRUNWDR.js.map +1 -0
- package/dist/cli/index.js +143 -34
- package/dist/cli/index.js.map +1 -1
- package/dist/{constants-Bkq04FRZ.d.ts → constants-BSBRlKRR.d.ts} +2 -2
- package/dist/index.d.ts +42 -22
- package/dist/index.js +1254 -377
- package/dist/index.js.map +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +247 -94
- package/dist/mcp.js.map +1 -1
- package/dist/mpp.d.ts +6 -2
- package/dist/mpp.js +65 -28
- package/dist/mpp.js.map +1 -1
- package/dist/{guardrails-71XwtXlT.d.ts → payment-flow-DCS882tR.d.ts} +9 -1
- package/dist/{protocol-adapter-DTkrXTev.d.ts → protocol-adapter-DonxfAwa.d.ts} +2 -0
- package/dist/{types-O6lg3Q5V.d.ts → types-CVw6Sf46.d.ts} +11 -0
- package/dist/x402.d.ts +11 -3
- package/dist/x402.js +4 -4
- package/package.json +22 -17
- package/dist/chunk-74BSEXB5.js.map +0 -1
- package/dist/chunk-AFI2CEZS.js +0 -10
- package/dist/chunk-AFI2CEZS.js.map +0 -1
- package/dist/chunk-ATTWSFQP.js.map +0 -1
package/dist/mcp.d.ts
CHANGED
package/dist/mcp.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { MCP_TOOL_NAME_PATTERN } from './chunk-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { ListToolsRequestSchema, CallToolRequestSchema, LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/sdk/types.js';
|
|
1
|
+
import { MCP_TOOL_NAME_PATTERN, readCappedBody, MCP_MODERN_PROTOCOL_REVISION, x402ErrorCode, settlementFailure, settlementResponseFromDetails, x402McpPaymentSubmission, X402_MCP_PAYMENT_META_KEY, X402_MCP_PAYMENT_RESPONSE_META_KEY, settlementResponse, X402_MCP_ERROR_META_KEY } from './chunk-HOZA3IWP.js';
|
|
2
|
+
import { mcpPaymentRequired, MPP_MCP_CREDENTIAL_META_KEY, receiptObject, MPP_MCP_RECEIPT_META_KEY, MPP_MCP_PAYMENT_REQUIRED_META_KEY } from './chunk-CKJRITWY.js';
|
|
3
|
+
import { PACKAGE_VERSION, toLogInfo, toCommerceError, CommerceError, extractReservedInputFields, isRecord, PAYMENT_INPUT_FIELD, AUTHORIZATION_INPUT_FIELD, toErrorEnvelope, DELIVERY_SUMMARY_META_KEY, toDeliverySummary, toPaymentRequiredEnvelope } from './chunk-53WXXIPR.js';
|
|
4
|
+
import { createMcpHandler, Server, ProtocolError, ProtocolErrorCode, LATEST_PROTOCOL_VERSION } from '@modelcontextprotocol/server';
|
|
6
5
|
|
|
7
|
-
var MCP_SUPPORTED_SPEC = LATEST_PROTOCOL_VERSION
|
|
6
|
+
var MCP_SUPPORTED_SPEC = `${MCP_MODERN_PROTOCOL_REVISION}, ${LATEST_PROTOCOL_VERSION}`;
|
|
8
7
|
var MCP_CAPABILITIES = ["tools/list", "tools/call"];
|
|
9
8
|
var MCP_UNSUPPORTED = [
|
|
10
9
|
"resources",
|
|
@@ -16,7 +15,15 @@ var MCP_UNSUPPORTED = [
|
|
|
16
15
|
"logging",
|
|
17
16
|
"notifications/tools/list_changed",
|
|
18
17
|
"tasks",
|
|
19
|
-
"dns-rebinding-protection"
|
|
18
|
+
"dns-rebinding-protection",
|
|
19
|
+
"authorization",
|
|
20
|
+
"sessions",
|
|
21
|
+
"subscriptions",
|
|
22
|
+
"pagination",
|
|
23
|
+
"HTTP+SSE transport",
|
|
24
|
+
// mppx reads challenges and refusals from tool-result `_meta`.
|
|
25
|
+
"MPP payment-required as JSON-RPC error -32042",
|
|
26
|
+
"MPP verification failure as JSON-RPC error -32043"
|
|
20
27
|
];
|
|
21
28
|
function buildDescriptor(implementationVersion) {
|
|
22
29
|
return {
|
|
@@ -30,41 +37,6 @@ function buildDescriptor(implementationVersion) {
|
|
|
30
37
|
};
|
|
31
38
|
}
|
|
32
39
|
|
|
33
|
-
// src/protocols/mcp/result-mapping.ts
|
|
34
|
-
function toRecord(value) {
|
|
35
|
-
return value;
|
|
36
|
-
}
|
|
37
|
-
function deliveredResult(outcome) {
|
|
38
|
-
const body = outcome.body;
|
|
39
|
-
const text = typeof body === "string" ? body : JSON.stringify(body ?? null);
|
|
40
|
-
return {
|
|
41
|
-
content: [{ type: "text", text }],
|
|
42
|
-
...isRecord(body) ? { structuredContent: body } : {},
|
|
43
|
-
_meta: { [DELIVERY_SUMMARY_META_KEY]: toRecord(toDeliverySummary(outcome)) }
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
function paymentRequiredResult(outcome) {
|
|
47
|
-
const envelope = toPaymentRequiredEnvelope(outcome);
|
|
48
|
-
const p = envelope.payment;
|
|
49
|
-
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.`;
|
|
50
|
-
return {
|
|
51
|
-
isError: true,
|
|
52
|
-
content: [{ type: "text", text }],
|
|
53
|
-
structuredContent: toRecord(envelope)
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
function errorResult(error) {
|
|
57
|
-
const envelope = toErrorEnvelope(error);
|
|
58
|
-
return {
|
|
59
|
-
isError: true,
|
|
60
|
-
content: [{ type: "text", text: `${envelope.code}: ${envelope.message}` }],
|
|
61
|
-
structuredContent: toRecord(envelope)
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
function mapOutcome(outcome) {
|
|
65
|
-
return outcome.kind === "delivered" ? deliveredResult(outcome) : paymentRequiredResult(outcome);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
40
|
// src/protocols/mcp/tool-mapping.ts
|
|
69
41
|
function isValidToolName(id) {
|
|
70
42
|
return MCP_TOOL_NAME_PATTERN.test(id);
|
|
@@ -75,18 +47,25 @@ function isPaidResource(resource) {
|
|
|
75
47
|
function primaryPaymentMethod(resource) {
|
|
76
48
|
return resource.paymentMethods[0];
|
|
77
49
|
}
|
|
50
|
+
function proofCarriers(method) {
|
|
51
|
+
const field = `the "${PAYMENT_INPUT_FIELD}" argument`;
|
|
52
|
+
if (method === "x402") return `_meta["${X402_MCP_PAYMENT_META_KEY}"] or ${field}`;
|
|
53
|
+
if (method === "mpp") return `_meta["${MPP_MCP_CREDENTIAL_META_KEY}"] or ${field}`;
|
|
54
|
+
return field;
|
|
55
|
+
}
|
|
78
56
|
function paymentProofNote(resource) {
|
|
79
57
|
const method = primaryPaymentMethod(resource);
|
|
80
|
-
const rail = method !== void 0 ? `
|
|
81
|
-
return `Requires ${rail} payment proof in
|
|
58
|
+
const rail = method !== void 0 ? `an ${method}` : "a";
|
|
59
|
+
return `Requires ${rail} payment proof in ${proofCarriers(method)}, built from the payment-required response.`;
|
|
82
60
|
}
|
|
61
|
+
var OMIT_NOTE = "Omit it when the client sends the proof in _meta.";
|
|
83
62
|
function paymentInputFieldDescription(resource) {
|
|
84
63
|
const method = primaryPaymentMethod(resource);
|
|
85
64
|
if (method === "x402") {
|
|
86
|
-
return
|
|
65
|
+
return `x402 payment proof (base64 PAYMENT-SIGNATURE value) for a previous payment-required response. ${OMIT_NOTE}`;
|
|
87
66
|
}
|
|
88
67
|
if (method === "mpp") {
|
|
89
|
-
return
|
|
68
|
+
return `MPP credential (the full "Authorization: Payment ..." value) for the challenge in a previous payment-required response. ${OMIT_NOTE}`;
|
|
90
69
|
}
|
|
91
70
|
if (method !== void 0) {
|
|
92
71
|
return `${method} payment proof (base64-encoded) returned from a previous payment-required response.`;
|
|
@@ -152,11 +131,92 @@ function buildInputSchema(resource) {
|
|
|
152
131
|
};
|
|
153
132
|
}
|
|
154
133
|
|
|
134
|
+
// src/protocols/mcp/result-mapping.ts
|
|
135
|
+
function toRecord(value) {
|
|
136
|
+
return value;
|
|
137
|
+
}
|
|
138
|
+
function deliveredResult(outcome) {
|
|
139
|
+
const body = outcome.body;
|
|
140
|
+
const text = typeof body === "string" ? body : JSON.stringify(body ?? null);
|
|
141
|
+
const payment = outcome.payment;
|
|
142
|
+
const receipt = payment?.provider === "mpp" ? receiptObject(payment.metadata?.["receipt"]) : void 0;
|
|
143
|
+
return {
|
|
144
|
+
content: [{ type: "text", text }],
|
|
145
|
+
...isRecord(body) ? { structuredContent: body } : {},
|
|
146
|
+
_meta: {
|
|
147
|
+
[DELIVERY_SUMMARY_META_KEY]: toRecord(toDeliverySummary(outcome)),
|
|
148
|
+
...payment?.provider === "x402" ? { [X402_MCP_PAYMENT_RESPONSE_META_KEY]: settlementResponse(payment) } : {},
|
|
149
|
+
...receipt !== void 0 ? { [MPP_MCP_RECEIPT_META_KEY]: receipt } : {}
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
function structuredError(structured, sentence, meta) {
|
|
154
|
+
return {
|
|
155
|
+
isError: true,
|
|
156
|
+
content: [
|
|
157
|
+
{ type: "text", text: JSON.stringify(structured) },
|
|
158
|
+
{ type: "text", text: sentence }
|
|
159
|
+
],
|
|
160
|
+
structuredContent: structured,
|
|
161
|
+
...meta !== void 0 ? { _meta: meta } : {}
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function withX402Challenge(envelope, challenge) {
|
|
165
|
+
return { ...challenge, ...envelope };
|
|
166
|
+
}
|
|
167
|
+
function paymentRequiredResult(outcome) {
|
|
168
|
+
const envelope = toPaymentRequiredEnvelope(outcome);
|
|
169
|
+
const p = envelope.payment;
|
|
170
|
+
const x402Required = p.provider === "x402" ? p.envelope : void 0;
|
|
171
|
+
const structured = x402Required !== void 0 ? withX402Challenge(toRecord(envelope), x402Required) : toRecord(envelope);
|
|
172
|
+
const mppRequired = p.provider === "mpp" ? mcpPaymentRequired(p.envelope) : void 0;
|
|
173
|
+
let meta;
|
|
174
|
+
if (x402Required !== void 0) meta = { [X402_MCP_ERROR_META_KEY]: x402Required };
|
|
175
|
+
else if (mppRequired !== void 0) meta = { [MPP_MCP_PAYMENT_REQUIRED_META_KEY]: mppRequired };
|
|
176
|
+
return structuredError(
|
|
177
|
+
structured,
|
|
178
|
+
`Payment required: ${p.amount} ${p.currency} to ${p.destination} for resource "${outcome.resourceId}". Retry with an ${p.provider} payment proof in ${proofCarriers(p.provider)}.`,
|
|
179
|
+
meta
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
function errorResult(error, rail) {
|
|
183
|
+
const envelope = toErrorEnvelope(error);
|
|
184
|
+
const details = error.details;
|
|
185
|
+
const challenge = details?.["challenge"];
|
|
186
|
+
const refused = error.httpStatus === 402 && isRecord(challenge);
|
|
187
|
+
const x402Required = rail === "x402" && refused ? { ...challenge, error: x402ErrorCode(error.code, details?.["reason"]) } : void 0;
|
|
188
|
+
const structured = x402Required !== void 0 ? withX402Challenge(toRecord(envelope), x402Required) : toRecord(envelope);
|
|
189
|
+
let meta;
|
|
190
|
+
if (rail === "x402") {
|
|
191
|
+
const settlement = error.code === "PAYMENT_SETTLEMENT_FAILED" ? settlementFailure(details) : settlementResponseFromDetails(details);
|
|
192
|
+
if (settlement !== void 0 || x402Required !== void 0) {
|
|
193
|
+
meta = {
|
|
194
|
+
...x402Required !== void 0 ? { [X402_MCP_ERROR_META_KEY]: x402Required } : {},
|
|
195
|
+
...settlement !== void 0 ? { [X402_MCP_PAYMENT_RESPONSE_META_KEY]: settlement } : {}
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
} else if (rail === "mpp" && refused) {
|
|
199
|
+
const required = mcpPaymentRequired(challenge, {
|
|
200
|
+
code: error.code,
|
|
201
|
+
reason: details?.["reason"],
|
|
202
|
+
detail: error.message
|
|
203
|
+
});
|
|
204
|
+
if (required !== void 0) meta = { [MPP_MCP_PAYMENT_REQUIRED_META_KEY]: required };
|
|
205
|
+
}
|
|
206
|
+
return structuredError(structured, `${envelope.code}: ${envelope.message}`, meta);
|
|
207
|
+
}
|
|
208
|
+
function mapOutcome(outcome) {
|
|
209
|
+
return outcome.kind === "delivered" ? deliveredResult(outcome) : paymentRequiredResult(outcome);
|
|
210
|
+
}
|
|
211
|
+
|
|
155
212
|
// src/protocols/mcp/adapter.ts
|
|
156
213
|
var DEFAULT_MOUNT_PATH = "/mcp";
|
|
157
214
|
var DEFAULT_SERVER_NAME = "agent-commerce";
|
|
158
215
|
var MAX_CONCURRENT_TOOL_CALLS = 8;
|
|
216
|
+
var MAX_REQUEST_BODY_BYTES = 256 * 1024;
|
|
159
217
|
var MAX_QUEUED_TOOL_CALLS = 64;
|
|
218
|
+
var MCP_BATCH_PROTOCOL_REVISION = "2025-03-26";
|
|
219
|
+
var TOOLS_LIST_CACHE_HINT = { ttlMs: 6e4, cacheScope: "public" };
|
|
160
220
|
var McpProtocolAdapter = class {
|
|
161
221
|
name = "mcp";
|
|
162
222
|
mountPath;
|
|
@@ -168,7 +228,7 @@ var McpProtocolAdapter = class {
|
|
|
168
228
|
tools = [];
|
|
169
229
|
toolsByResourceId = /* @__PURE__ */ new Map();
|
|
170
230
|
skipped = [];
|
|
171
|
-
|
|
231
|
+
handler;
|
|
172
232
|
// Counting semaphore on `pipeline.execute()`. It lives on the adapter, not
|
|
173
233
|
// the request, so the cap holds across concurrent `/mcp` requests as well
|
|
174
234
|
// as within one batch.
|
|
@@ -232,6 +292,14 @@ var McpProtocolAdapter = class {
|
|
|
232
292
|
this.tools = tools;
|
|
233
293
|
this.toolsByResourceId = toolsByResourceId;
|
|
234
294
|
this.skipped = skipped;
|
|
295
|
+
this.handler = createMcpHandler(
|
|
296
|
+
(ctx) => this.buildServer(ctx.requestInfo?.signal ?? new AbortController().signal),
|
|
297
|
+
{
|
|
298
|
+
legacy: "stateless",
|
|
299
|
+
// Reporting only: a request the SDK rejects is already answered
|
|
300
|
+
onerror: (err) => context.logger.debug({ adapter: "mcp", err: toLogInfo(err) }, "mcp adapter: SDK error")
|
|
301
|
+
}
|
|
302
|
+
);
|
|
235
303
|
this.started = true;
|
|
236
304
|
context.logger.info(
|
|
237
305
|
{
|
|
@@ -245,7 +313,7 @@ var McpProtocolAdapter = class {
|
|
|
245
313
|
}
|
|
246
314
|
async handleHttp(req, res) {
|
|
247
315
|
try {
|
|
248
|
-
if (!this.started || !this.context) {
|
|
316
|
+
if (!this.started || !this.context || !this.handler) {
|
|
249
317
|
this.writeJsonRpcError(res, 503, "MCP adapter is not running.");
|
|
250
318
|
return;
|
|
251
319
|
}
|
|
@@ -254,20 +322,39 @@ var McpProtocolAdapter = class {
|
|
|
254
322
|
return;
|
|
255
323
|
}
|
|
256
324
|
const abortController = new AbortController();
|
|
257
|
-
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
325
|
+
res.once("close", () => abortController.abort());
|
|
326
|
+
const read = await readCappedBody(req, MAX_REQUEST_BODY_BYTES);
|
|
327
|
+
if (read.kind === "too-large") {
|
|
328
|
+
this.writeJsonRpcError(
|
|
329
|
+
res,
|
|
330
|
+
413,
|
|
331
|
+
`Request body exceeds the ${MAX_REQUEST_BODY_BYTES}-byte limit.`
|
|
332
|
+
);
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
if (read.kind !== "ok") {
|
|
336
|
+
this.writeJsonRpcError(res, 400, "Could not read the request body.");
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
const body = parseJson(read.text);
|
|
340
|
+
const version = req.headers["mcp-protocol-version"];
|
|
341
|
+
if (Array.isArray(body) && version !== void 0 && version !== MCP_BATCH_PROTOCOL_REVISION) {
|
|
342
|
+
this.writeJsonRpcError(
|
|
343
|
+
res,
|
|
344
|
+
400,
|
|
345
|
+
`Invalid Request: JSON-RPC batches are supported only in MCP ${MCP_BATCH_PROTOCOL_REVISION}.`
|
|
346
|
+
);
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
const malformed = isModernRequest(req) ? void 0 : malformedToolCall(body);
|
|
350
|
+
if (malformed !== void 0) {
|
|
351
|
+
this.writeJsonRpcError(res, 200, malformed.message, -32602, malformed.id);
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
const response = await this.handler.fetch(
|
|
355
|
+
toWebRequest(req, read.text, abortController.signal)
|
|
356
|
+
);
|
|
357
|
+
await writeWebResponse(response, res);
|
|
271
358
|
} catch (err) {
|
|
272
359
|
this.context?.logger.error(
|
|
273
360
|
{ adapter: "mcp", err: toLogInfo(err) },
|
|
@@ -290,55 +377,60 @@ var McpProtocolAdapter = class {
|
|
|
290
377
|
}
|
|
291
378
|
async stop() {
|
|
292
379
|
this.started = false;
|
|
293
|
-
const
|
|
294
|
-
this.
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
} catch {
|
|
300
|
-
}
|
|
301
|
-
})
|
|
302
|
-
);
|
|
380
|
+
const handler = this.handler;
|
|
381
|
+
this.handler = void 0;
|
|
382
|
+
try {
|
|
383
|
+
await handler?.close();
|
|
384
|
+
} catch {
|
|
385
|
+
}
|
|
303
386
|
this.context = void 0;
|
|
304
387
|
}
|
|
305
|
-
|
|
388
|
+
// Use general JSON-RPC codes for transport errors
|
|
389
|
+
writeJsonRpcError(res, status, message, code = status >= 500 ? -32603 : -32600, id = null) {
|
|
306
390
|
if (res.headersSent) return;
|
|
307
|
-
res.writeHead(status, {
|
|
308
|
-
|
|
391
|
+
res.writeHead(status, {
|
|
392
|
+
"content-type": "application/json",
|
|
393
|
+
// RFC 9110 requires Allow on a 405, and this endpoint takes only POST
|
|
394
|
+
...status === 405 ? { allow: "POST" } : {}
|
|
395
|
+
});
|
|
396
|
+
res.end(JSON.stringify({ jsonrpc: "2.0", error: { code, message }, id }));
|
|
309
397
|
}
|
|
310
398
|
buildServer(signal) {
|
|
311
399
|
const server = new Server(
|
|
312
400
|
{ name: this.serverName, version: this.serverVersion },
|
|
313
|
-
{ capabilities: { tools: {} } }
|
|
401
|
+
{ capabilities: { tools: {} }, cacheHints: { "tools/list": TOOLS_LIST_CACHE_HINT } }
|
|
314
402
|
);
|
|
315
|
-
server.setRequestHandler(
|
|
316
|
-
|
|
317
|
-
|
|
403
|
+
server.setRequestHandler("tools/list", async (request) => {
|
|
404
|
+
if (request.params?.cursor !== void 0) {
|
|
405
|
+
throw new ProtocolError(ProtocolErrorCode.InvalidParams, "Invalid cursor.");
|
|
406
|
+
}
|
|
407
|
+
return { tools: this.tools.map((t) => t.tool) };
|
|
408
|
+
});
|
|
318
409
|
server.setRequestHandler(
|
|
319
|
-
|
|
320
|
-
async (request) => this.handleToolCall(
|
|
410
|
+
"tools/call",
|
|
411
|
+
async (request) => this.handleToolCall(
|
|
412
|
+
request.params.name,
|
|
413
|
+
request.params.arguments ?? {},
|
|
414
|
+
request.params._meta,
|
|
415
|
+
signal
|
|
416
|
+
)
|
|
321
417
|
);
|
|
322
418
|
return server;
|
|
323
419
|
}
|
|
324
|
-
async handleToolCall(resourceId, rawArgs, signal) {
|
|
420
|
+
async handleToolCall(resourceId, rawArgs, meta, signal) {
|
|
325
421
|
const context = this.context;
|
|
326
422
|
if (!context) {
|
|
327
423
|
return errorResult(new CommerceError("INTERNAL_ERROR", "MCP adapter is not running."));
|
|
328
424
|
}
|
|
425
|
+
const resource = this.toolsByResourceId.get(resourceId);
|
|
426
|
+
if (!resource) {
|
|
427
|
+
throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Unknown tool "${resourceId}".`);
|
|
428
|
+
}
|
|
329
429
|
try {
|
|
330
|
-
const resource = this.toolsByResourceId.get(resourceId);
|
|
331
|
-
if (!resource) {
|
|
332
|
-
return errorResult(
|
|
333
|
-
new CommerceError("RESOURCE_NOT_FOUND", `Unknown tool "${resourceId}".`, { resourceId })
|
|
334
|
-
);
|
|
335
|
-
}
|
|
336
430
|
const requestId = context.ids.next("mcp");
|
|
337
|
-
const
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
requestId
|
|
341
|
-
);
|
|
431
|
+
const fields = extractReservedInputFields(rawArgs, resource, requestId);
|
|
432
|
+
const { input, authorization } = fields;
|
|
433
|
+
const payment = paymentFromMeta(meta, resource) ?? fields.payment;
|
|
342
434
|
const request = {
|
|
343
435
|
requestId,
|
|
344
436
|
resourceId,
|
|
@@ -369,7 +461,7 @@ var McpProtocolAdapter = class {
|
|
|
369
461
|
{ adapter: "mcp", resourceId, err: toLogInfo(error) },
|
|
370
462
|
"mcp adapter: execution failed"
|
|
371
463
|
);
|
|
372
|
-
return errorResult(error);
|
|
464
|
+
return errorResult(error, resource.paymentMethods[0]);
|
|
373
465
|
}
|
|
374
466
|
}
|
|
375
467
|
/**
|
|
@@ -400,6 +492,67 @@ var McpProtocolAdapter = class {
|
|
|
400
492
|
else this.inFlightToolCalls--;
|
|
401
493
|
}
|
|
402
494
|
};
|
|
495
|
+
function toWebRequest(req, body, signal) {
|
|
496
|
+
const headers = new Headers();
|
|
497
|
+
for (const [name, value] of Object.entries(req.headers)) {
|
|
498
|
+
if (value !== void 0) headers.set(name, Array.isArray(value) ? value.join(", ") : value);
|
|
499
|
+
}
|
|
500
|
+
return new Request(new URL(req.url ?? "/", "http://localhost"), {
|
|
501
|
+
method: req.method ?? "POST",
|
|
502
|
+
headers,
|
|
503
|
+
body,
|
|
504
|
+
signal
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
function isModernRequest(req) {
|
|
508
|
+
if (req.headers["mcp-method"] !== void 0) return true;
|
|
509
|
+
const version = req.headers["mcp-protocol-version"];
|
|
510
|
+
return typeof version === "string" && version >= MCP_MODERN_PROTOCOL_REVISION;
|
|
511
|
+
}
|
|
512
|
+
function parseJson(body) {
|
|
513
|
+
try {
|
|
514
|
+
return JSON.parse(body);
|
|
515
|
+
} catch {
|
|
516
|
+
return void 0;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
function malformedToolCall(message) {
|
|
520
|
+
if (!isRecord(message) || message["method"] !== "tools/call") return void 0;
|
|
521
|
+
const id = message["id"];
|
|
522
|
+
if (typeof id !== "string" && typeof id !== "number") return void 0;
|
|
523
|
+
const params = message["params"];
|
|
524
|
+
let problem;
|
|
525
|
+
if (!isRecord(params)) problem = "params must be an object";
|
|
526
|
+
else if (typeof params["name"] !== "string") problem = '"name" must be a string';
|
|
527
|
+
else if (params["arguments"] !== void 0 && !isRecord(params["arguments"])) {
|
|
528
|
+
problem = '"arguments" must be an object';
|
|
529
|
+
} else if (params["_meta"] !== void 0 && !isRecord(params["_meta"])) {
|
|
530
|
+
problem = '"_meta" must be an object';
|
|
531
|
+
}
|
|
532
|
+
return problem === void 0 ? void 0 : { id, message: `Invalid tools/call params: ${problem}.` };
|
|
533
|
+
}
|
|
534
|
+
async function writeWebResponse(response, res) {
|
|
535
|
+
res.writeHead(response.status, Object.fromEntries(response.headers));
|
|
536
|
+
if (response.body !== null) {
|
|
537
|
+
for await (const chunk of response.body) {
|
|
538
|
+
if (res.destroyed) break;
|
|
539
|
+
res.write(chunk);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
res.end();
|
|
543
|
+
}
|
|
544
|
+
function paymentFromMeta(meta, resource) {
|
|
545
|
+
const method = resource.paymentMethods[0];
|
|
546
|
+
if (method === "x402") {
|
|
547
|
+
const payload = x402McpPaymentSubmission(meta?.[X402_MCP_PAYMENT_META_KEY]);
|
|
548
|
+
if (payload !== void 0) return { method, payload };
|
|
549
|
+
}
|
|
550
|
+
const credential = meta?.[MPP_MCP_CREDENTIAL_META_KEY];
|
|
551
|
+
if (method === "mpp" && isRecord(credential)) {
|
|
552
|
+
return { method, payload: JSON.stringify(credential) };
|
|
553
|
+
}
|
|
554
|
+
return void 0;
|
|
555
|
+
}
|
|
403
556
|
function createMcpAdapter(options) {
|
|
404
557
|
return new McpProtocolAdapter(options);
|
|
405
558
|
}
|