agents 0.19.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -19
- package/dist/{agent-tool-types-BNUGGBzQ.d.ts → agent-tool-types-Btk9ETS-.d.ts} +997 -356
- package/dist/agent-tool-types.d.ts +1 -1
- package/dist/{agent-tools-BFbzVLFc.d.ts → agent-tools-UuScsJg3.d.ts} +2 -2
- package/dist/agent-tools.d.ts +1 -1
- package/dist/browser/ai.js +1 -1
- package/dist/browser/index.js +1 -1
- package/dist/chat/index.d.ts +2 -2
- package/dist/chat-sdk/index.d.ts +1 -1
- package/dist/client-invoker-BNSZxAkv.d.ts +20 -0
- package/dist/client-invoker-VNZ7X0nn.js +57 -0
- package/dist/client-invoker-VNZ7X0nn.js.map +1 -0
- package/dist/{client-CcjiFpTf.js → client-zqKcsyFa.js} +434 -168
- package/dist/client-zqKcsyFa.js.map +1 -0
- package/dist/client.d.ts +1 -1
- package/dist/{connector-CdldGF3h.js → connector-KEJnl6e5.js} +2 -2
- package/dist/connector-KEJnl6e5.js.map +1 -0
- package/dist/{do-oauth-client-provider-D4ZwyBDu.d.ts → do-oauth-client-provider-VTZj2VtM.d.ts} +23 -11
- package/dist/experimental/webmcp.js +1 -1
- package/dist/handler-stateless-8hQN_kC3.js +367 -0
- package/dist/handler-stateless-8hQN_kC3.js.map +1 -0
- package/dist/handler-stateless-C_bo-Ytq.d.ts +107 -0
- package/dist/index.d.ts +12 -12
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/mcp/client.d.ts +22 -18
- package/dist/mcp/client.js +1 -1
- package/dist/mcp/do-oauth-client-provider.d.ts +1 -1
- package/dist/mcp/do-oauth-client-provider.js +25 -12
- package/dist/mcp/do-oauth-client-provider.js.map +1 -1
- package/dist/mcp/index.d.ts +48 -34
- package/dist/mcp/index.js +84 -79
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/server.d.ts +17 -0
- package/dist/mcp/server.js +2 -0
- package/dist/mcp/x402.d.ts +21 -9
- package/dist/mcp/x402.js +8 -7
- package/dist/mcp/x402.js.map +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/serializable.d.ts +1 -1
- package/dist/sub-routing.d.ts +6 -6
- package/dist/workflows.d.ts +1 -1
- package/docs/human-in-the-loop.md +63 -82
- package/docs/mcp-client.md +31 -7
- package/docs/mcp-servers.md +125 -88
- package/docs/securing-mcp-servers.md +9 -6
- package/package.json +28 -7
- package/dist/client-CcjiFpTf.js.map +0 -1
- package/dist/connector-CdldGF3h.js.map +0 -1
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
a as McpAuthContext,
|
|
3
|
+
i as createStatelessMcpHandler,
|
|
4
|
+
n as StatelessMcpHandler,
|
|
5
|
+
o as getMcpAuthContext,
|
|
6
|
+
r as StatelessMcpServerInput,
|
|
7
|
+
t as CreateStatelessMcpHandlerOptions
|
|
8
|
+
} from "../handler-stateless-C_bo-Ytq.js";
|
|
9
|
+
export {
|
|
10
|
+
type CreateStatelessMcpHandlerOptions as CreateMcpHandlerOptions,
|
|
11
|
+
type CreateStatelessMcpHandlerOptions,
|
|
12
|
+
type McpAuthContext,
|
|
13
|
+
type StatelessMcpHandler,
|
|
14
|
+
type StatelessMcpServerInput,
|
|
15
|
+
createStatelessMcpHandler as createMcpHandler,
|
|
16
|
+
getMcpAuthContext
|
|
17
|
+
};
|
package/dist/mcp/x402.d.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
n as LegacyCallToolResultSchema,
|
|
3
|
+
t as CompatibleMcpClient
|
|
4
|
+
} from "../client-invoker-BNSZxAkv.js";
|
|
1
5
|
import { ZodRawShape } from "zod";
|
|
2
|
-
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
3
6
|
import {
|
|
4
7
|
CallToolRequest,
|
|
8
|
+
CallToolRequestOptions
|
|
9
|
+
} from "@modelcontextprotocol/client";
|
|
10
|
+
import {
|
|
5
11
|
CallToolResult,
|
|
6
|
-
CallToolResultSchema,
|
|
7
|
-
CompatibilityCallToolResultSchema,
|
|
8
12
|
ToolAnnotations
|
|
9
13
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
10
14
|
import {
|
|
@@ -16,7 +20,6 @@ import {
|
|
|
16
20
|
FacilitatorConfig,
|
|
17
21
|
FacilitatorConfig as FacilitatorConfig$1
|
|
18
22
|
} from "@x402/core/server";
|
|
19
|
-
import { RequestOptions } from "@modelcontextprotocol/sdk/shared/protocol.js";
|
|
20
23
|
import {
|
|
21
24
|
Network,
|
|
22
25
|
Network as Network$1,
|
|
@@ -65,10 +68,19 @@ interface X402AugmentedClient {
|
|
|
65
68
|
| ((payment: PaymentRequirements$1[]) => Promise<boolean>)
|
|
66
69
|
| null,
|
|
67
70
|
params: CallToolRequest["params"],
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
71
|
+
options?: CallToolRequestOptions
|
|
72
|
+
): Promise<CallToolResult>;
|
|
73
|
+
/**
|
|
74
|
+
* @deprecated Prefer the request-options overload. Explicit legacy result
|
|
75
|
+
* schemas remain honored through the SDK v2 request funnel.
|
|
76
|
+
*/
|
|
77
|
+
callTool(
|
|
78
|
+
x402ConfirmationCallback:
|
|
79
|
+
| ((payment: PaymentRequirements$1[]) => Promise<boolean>)
|
|
80
|
+
| null,
|
|
81
|
+
params: CallToolRequest["params"],
|
|
82
|
+
resultSchema: LegacyCallToolResultSchema,
|
|
83
|
+
options?: CallToolRequestOptions
|
|
72
84
|
): Promise<CallToolResult>;
|
|
73
85
|
}
|
|
74
86
|
type X402ClientConfig = {
|
|
@@ -88,7 +100,7 @@ type X402ClientConfig = {
|
|
|
88
100
|
version?: number /** Confirmation callback for payment approval */;
|
|
89
101
|
confirmationCallback?: (payment: PaymentRequirements$1[]) => Promise<boolean>;
|
|
90
102
|
};
|
|
91
|
-
declare function withX402Client<T extends
|
|
103
|
+
declare function withX402Client<T extends CompatibleMcpClient>(
|
|
92
104
|
client: T,
|
|
93
105
|
x402Config: X402ClientConfig
|
|
94
106
|
): X402AugmentedClient & T;
|
package/dist/mcp/x402.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { t as bindMcpClient } from "../client-invoker-VNZ7X0nn.js";
|
|
1
2
|
import { HTTPFacilitatorClient, x402ResourceServer } from "@x402/core/server";
|
|
2
3
|
import { x402Client } from "@x402/core/client";
|
|
3
4
|
import { registerExactEvmScheme } from "@x402/evm/exact/server";
|
|
@@ -147,6 +148,7 @@ function withX402(server, cfg) {
|
|
|
147
148
|
return server;
|
|
148
149
|
}
|
|
149
150
|
function withX402Client(client, x402Config) {
|
|
151
|
+
const invoker = bindMcpClient(client);
|
|
150
152
|
const { account } = x402Config;
|
|
151
153
|
const maxPaymentValue = x402Config.maxPaymentValue ?? BigInt(1e5);
|
|
152
154
|
const paymentClient = new x402Client();
|
|
@@ -158,9 +160,8 @@ function withX402Client(client, x402Config) {
|
|
|
158
160
|
return matching.length > 0 ? matching : reqs;
|
|
159
161
|
});
|
|
160
162
|
}
|
|
161
|
-
const _listTools = client.listTools.bind(client);
|
|
162
163
|
const listTools = async (params, options) => {
|
|
163
|
-
const toolsRes = await
|
|
164
|
+
const toolsRes = await invoker.listTools(params, options);
|
|
164
165
|
return {
|
|
165
166
|
...toolsRes,
|
|
166
167
|
tools: toolsRes.tools.map((tool) => {
|
|
@@ -176,9 +177,9 @@ function withX402Client(client, x402Config) {
|
|
|
176
177
|
})
|
|
177
178
|
};
|
|
178
179
|
};
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
const res = await
|
|
180
|
+
const callToolWithPayment = async (x402ConfirmationCallback, params, schemaOrOptions, options) => {
|
|
181
|
+
const invoke = (callParams) => invoker.callTool(callParams, schemaOrOptions, options);
|
|
182
|
+
const res = await invoke(params);
|
|
182
183
|
const maybeX402Error = res._meta?.["x402/error"];
|
|
183
184
|
if (res.isError && maybeX402Error && maybeX402Error.accepts && Array.isArray(maybeX402Error.accepts) && maybeX402Error.accepts.length > 0) {
|
|
184
185
|
const accepts = maybeX402Error.accepts;
|
|
@@ -228,13 +229,13 @@ function withX402Client(client, x402Config) {
|
|
|
228
229
|
};
|
|
229
230
|
}
|
|
230
231
|
const token = btoa(JSON.stringify(paymentPayload));
|
|
231
|
-
return
|
|
232
|
+
return invoke({
|
|
232
233
|
...params,
|
|
233
234
|
_meta: {
|
|
234
235
|
...params._meta,
|
|
235
236
|
"x402/payment": token
|
|
236
237
|
}
|
|
237
|
-
}
|
|
238
|
+
});
|
|
238
239
|
}
|
|
239
240
|
return res;
|
|
240
241
|
};
|
package/dist/mcp/x402.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"x402.js","names":[],"sources":["../../src/mcp/x402.ts"],"sourcesContent":["/**\n * X402 MCP Integration (v2)\n *\n * Based on:\n * - Coinbase's x402 (Apache 2.0): https://github.com/coinbase/x402\n * - @ethanniser and his work at https://github.com/ethanniser/x402-mcp\n */\n\nimport type {\n McpServer,\n RegisteredTool,\n ToolCallback\n} from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { Client as MCPClient } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport type {\n CallToolResultSchema,\n CompatibilityCallToolResultSchema,\n CallToolRequest,\n CallToolResult,\n ToolAnnotations\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport type { ZodRawShape } from \"zod\";\nimport type { RequestOptions } from \"@modelcontextprotocol/sdk/shared/protocol.js\";\n\n// v2 imports from @x402/core\nimport { x402ResourceServer, HTTPFacilitatorClient } from \"@x402/core/server\";\nimport type { FacilitatorConfig, ResourceConfig } from \"@x402/core/server\";\nimport { x402Client } from \"@x402/core/client\";\nimport type {\n PaymentPayload,\n PaymentRequirements,\n PaymentRequired,\n Network\n} from \"@x402/core/types\";\n\n// v2 imports from @x402/evm\nimport { registerExactEvmScheme as registerServerEvmScheme } from \"@x402/evm/exact/server\";\nimport { registerExactEvmScheme as registerClientEvmScheme } from \"@x402/evm/exact/client\";\nimport type { ClientEvmSigner } from \"@x402/evm\";\n\n// Re-export commonly used types for consumer convenience\nexport type {\n PaymentRequirements,\n PaymentRequired,\n Network\n} from \"@x402/core/types\";\nexport type { FacilitatorConfig } from \"@x402/core/server\";\nexport type { ClientEvmSigner } from \"@x402/evm\";\n\n/**\n * Map of legacy v1 network names to CAIP-2 identifiers.\n * Allows backward compatibility with v1 config.\n */\nconst LEGACY_NETWORK_MAP: Record<string, string> = {\n \"base-sepolia\": \"eip155:84532\",\n base: \"eip155:8453\",\n ethereum: \"eip155:1\",\n sepolia: \"eip155:11155111\"\n};\n\n/**\n * Normalize a network identifier to CAIP-2 format.\n * Accepts both legacy v1 names (\"base-sepolia\") and CAIP-2 (\"eip155:84532\").\n */\nexport function normalizeNetwork(network: string): Network {\n return (LEGACY_NETWORK_MAP[network] ?? network) as Network;\n}\n\n/*\n ======= SERVER SIDE =======\n*/\n\nexport type X402Config = {\n /**\n * Network identifier.\n * Accepts both legacy names (\"base-sepolia\") and CAIP-2 format (\"eip155:84532\").\n */\n network: string;\n /** Payment recipient address */\n recipient: `0x${string}`;\n /** Facilitator configuration. Defaults to https://x402.org/facilitator */\n facilitator?: FacilitatorConfig;\n /** @deprecated No longer used in v2. The protocol version is determined automatically. */\n version?: number;\n};\n\nexport interface X402AugmentedServer {\n paidTool<Args extends ZodRawShape>(\n name: string,\n description: string,\n priceUSD: number,\n paramsSchema: Args,\n annotations: ToolAnnotations,\n cb: ToolCallback<Args>\n ): RegisteredTool;\n}\n\nexport function withX402<T extends McpServer>(\n server: T,\n cfg: X402Config\n): T & X402AugmentedServer {\n const network = normalizeNetwork(cfg.network);\n const facilitatorConfig: FacilitatorConfig = cfg.facilitator ?? {\n url: \"https://x402.org/facilitator\"\n };\n\n // Create v2 resource server with facilitator client\n const facilitatorClient = new HTTPFacilitatorClient(facilitatorConfig);\n const resourceServer = new x402ResourceServer(facilitatorClient);\n registerServerEvmScheme(resourceServer);\n\n // Lazy initialization: fetch supported kinds from facilitator on first use\n let initPromise: Promise<void> | null = null;\n function ensureInitialized(): Promise<void> {\n if (!initPromise) {\n initPromise = resourceServer.initialize().catch((err) => {\n initPromise = null; // allow retry on failure\n throw err;\n });\n }\n return initPromise;\n }\n\n function paidTool<Args extends ZodRawShape>(\n name: string,\n description: string,\n priceUSD: number,\n paramsSchema: Args,\n annotations: ToolAnnotations,\n cb: ToolCallback<Args>\n ): RegisteredTool {\n return server.registerTool(\n name,\n {\n description,\n inputSchema: paramsSchema,\n annotations,\n _meta: {\n \"agents-x402/paymentRequired\": true,\n \"agents-x402/priceUSD\": priceUSD\n }\n },\n (async (args, extra) => {\n await ensureInitialized();\n\n // Build v2 payment requirements for this tool call\n const resourceConfig: ResourceConfig = {\n scheme: \"exact\",\n payTo: cfg.recipient,\n price: priceUSD,\n network,\n maxTimeoutSeconds: 300\n };\n\n let requirements: PaymentRequirements[];\n try {\n requirements =\n await resourceServer.buildPaymentRequirements(resourceConfig);\n } catch {\n const payload = { x402Version: 2, error: \"PRICE_COMPUTE_FAILED\" };\n return {\n isError: true,\n _meta: { \"x402/error\": payload },\n content: [{ type: \"text\", text: JSON.stringify(payload) }]\n } as const;\n }\n\n const resourceInfo = {\n url: `x402://${name}`,\n description,\n mimeType: \"application/json\"\n };\n\n // Get payment token from MCP _meta or HTTP headers\n // Support both v2 (PAYMENT-SIGNATURE) and v1 (X-PAYMENT) header names\n const headers = extra?.requestInfo?.headers ?? {};\n const token =\n (extra?._meta?.[\"x402/payment\"] as string | undefined) ??\n headers[\"PAYMENT-SIGNATURE\"] ??\n headers[\"X-PAYMENT\"];\n\n const paymentRequired = (\n reason = \"PAYMENT_REQUIRED\",\n extraFields: Record<string, unknown> = {}\n ) => {\n const payload = {\n x402Version: 2,\n error: reason,\n resource: resourceInfo,\n accepts: requirements,\n ...extraFields\n };\n return {\n isError: true,\n _meta: { \"x402/error\": payload },\n content: [{ type: \"text\", text: JSON.stringify(payload) }]\n } as const;\n };\n\n if (!token || typeof token !== \"string\") return paymentRequired();\n\n // Decode the payment payload (base64-encoded JSON)\n let paymentPayload: PaymentPayload;\n try {\n paymentPayload = JSON.parse(atob(token));\n } catch {\n return paymentRequired(\"INVALID_PAYMENT\");\n }\n\n // Find matching requirements for this payment\n const matchingReq = resourceServer.findMatchingRequirements(\n requirements,\n paymentPayload\n );\n if (!matchingReq) {\n return paymentRequired(\"INVALID_PAYMENT\");\n }\n\n // Verify payment with facilitator\n try {\n const vr = await resourceServer.verifyPayment(\n paymentPayload,\n matchingReq\n );\n if (!vr.isValid) {\n return paymentRequired(vr.invalidReason ?? \"INVALID_PAYMENT\", {\n payer: vr.payer\n });\n }\n } catch {\n return paymentRequired(\"INVALID_PAYMENT\");\n }\n\n // Execute the tool callback\n let result: CallToolResult;\n let failed = false;\n try {\n result = await cb(args, extra);\n if (\n result &&\n typeof result === \"object\" &&\n \"isError\" in result &&\n result.isError\n ) {\n failed = true;\n }\n } catch (e) {\n failed = true;\n result = {\n isError: true,\n content: [\n { type: \"text\", text: `Tool execution failed: ${String(e)}` }\n ]\n };\n }\n\n // Settle payment only on success\n if (!failed) {\n try {\n const s = await resourceServer.settlePayment(\n paymentPayload,\n matchingReq\n );\n if (s.success) {\n result._meta ??= {};\n result._meta[\"x402/payment-response\"] = {\n success: true,\n transaction: s.transaction,\n network: s.network,\n payer: s.payer\n };\n } else {\n return paymentRequired(s.errorReason ?? \"SETTLEMENT_FAILED\");\n }\n } catch {\n return paymentRequired(\"SETTLEMENT_FAILED\");\n }\n }\n\n return result;\n }) as ToolCallback<Args>\n );\n }\n\n Object.defineProperty(server, \"paidTool\", {\n value: paidTool,\n writable: false,\n enumerable: false,\n configurable: true\n });\n\n // Tell TS the object now also has the paidTool method\n return server as T & X402AugmentedServer;\n}\n\n/*\n ======= CLIENT SIDE =======\n*/\n\nexport interface X402AugmentedClient {\n callTool(\n x402ConfirmationCallback:\n | ((payment: PaymentRequirements[]) => Promise<boolean>)\n | null,\n params: CallToolRequest[\"params\"],\n resultSchema?:\n | typeof CallToolResultSchema\n | typeof CompatibilityCallToolResultSchema,\n options?: RequestOptions\n ): Promise<CallToolResult>;\n}\n\nexport type X402ClientConfig = {\n /**\n * EVM account/signer for signing payment authorizations.\n * Use `privateKeyToAccount()` from viem/accounts to create one.\n */\n account: ClientEvmSigner;\n /**\n * Preferred network identifier (optional).\n * Accepts both legacy names (\"base-sepolia\") and CAIP-2 format (\"eip155:84532\").\n * When set, the client prefers payment requirements matching this network.\n * If omitted, the client automatically selects from available requirements.\n */\n network?: string;\n /** Maximum payment value in atomic units (default: 0.10 USDC = 100000) */\n maxPaymentValue?: bigint;\n /** @deprecated No longer used in v2. The protocol version is determined automatically. */\n version?: number;\n /** Confirmation callback for payment approval */\n confirmationCallback?: (payment: PaymentRequirements[]) => Promise<boolean>;\n};\n\nexport function withX402Client<T extends MCPClient>(\n client: T,\n x402Config: X402ClientConfig\n): X402AugmentedClient & T {\n const { account } = x402Config;\n\n const maxPaymentValue = x402Config.maxPaymentValue ?? BigInt(100_000); // 0.10 USDC\n\n // Create v2 x402 payment client with EVM scheme support\n const paymentClient = new x402Client();\n registerClientEvmScheme(paymentClient, { signer: account });\n\n // If a preferred network is specified, register a policy to prefer it\n if (x402Config.network) {\n const preferredNetwork = normalizeNetwork(x402Config.network);\n paymentClient.registerPolicy((_version, reqs) => {\n const matching = reqs.filter((r) => r.network === preferredNetwork);\n return matching.length > 0 ? matching : reqs;\n });\n }\n\n const _listTools = client.listTools.bind(client);\n\n // Wrap the original method to include payment information in the description\n const listTools: typeof _listTools = async (params, options) => {\n const toolsRes = await _listTools(params, options);\n return {\n ...toolsRes,\n tools: toolsRes.tools.map((tool) => {\n let description = tool.description;\n // Check _meta for payment information (agents-x402/ is our extension for pre-advertising prices)\n if (tool._meta?.[\"agents-x402/paymentRequired\"]) {\n const cost = tool._meta?.[\"agents-x402/priceUSD\"]\n ? `$${tool._meta?.[\"agents-x402/priceUSD\"]}`\n : \"an unknown amount\";\n description += ` (This is a paid tool, you will be charged ${cost} for its execution)`;\n }\n return {\n ...tool,\n description\n };\n })\n };\n };\n\n const _callTool = client.callTool.bind(client);\n\n const callToolWithPayment = async (\n x402ConfirmationCallback:\n | ((payment: PaymentRequirements[]) => Promise<boolean>)\n | null,\n params: CallToolRequest[\"params\"],\n resultSchema?:\n | typeof CallToolResultSchema\n | typeof CompatibilityCallToolResultSchema,\n options?: RequestOptions\n ): ReturnType<typeof client.callTool> => {\n // Call the tool\n const res = await _callTool(params, resultSchema, options);\n\n // Check for x402 payment required error in response metadata\n const maybeX402Error = res._meta?.[\"x402/error\"] as\n | (PaymentRequired & Record<string, unknown>)\n | undefined;\n\n if (\n res.isError &&\n maybeX402Error &&\n maybeX402Error.accepts &&\n Array.isArray(maybeX402Error.accepts) &&\n maybeX402Error.accepts.length > 0\n ) {\n const accepts = maybeX402Error.accepts;\n const confirmationCallback =\n x402ConfirmationCallback ?? x402Config.confirmationCallback;\n\n // Use the confirmation callback if provided\n if (confirmationCallback && !(await confirmationCallback(accepts))) {\n return {\n isError: true,\n content: [{ type: \"text\", text: \"User declined payment\" }]\n };\n }\n\n // Check max payment value against the first requirement's amount\n const selectedReq = accepts[0];\n if (!selectedReq || selectedReq.scheme !== \"exact\") return res;\n\n let amount: bigint;\n try {\n amount = BigInt(selectedReq.amount);\n } catch {\n return res; // malformed amount — return original error\n }\n if (amount > maxPaymentValue) {\n return {\n isError: true,\n content: [\n {\n type: \"text\",\n text: `Payment exceeds client cap: ${amount} > ${maxPaymentValue}`\n }\n ]\n };\n }\n\n // Reconstruct the PaymentRequired response for the v2 x402 client\n const paymentRequiredResponse: PaymentRequired = {\n x402Version: (maybeX402Error.x402Version as number) ?? 2,\n resource: (maybeX402Error.resource as PaymentRequired[\"resource\"]) ?? {\n url: \"\",\n description: \"\",\n mimeType: \"application/json\"\n },\n accepts,\n extensions: maybeX402Error.extensions as\n | Record<string, unknown>\n | undefined\n };\n\n // Create the payment payload using the v2 x402 client\n let paymentPayload: PaymentPayload;\n try {\n paymentPayload = await paymentClient.createPaymentPayload(\n paymentRequiredResponse\n );\n } catch {\n return {\n isError: true,\n content: [{ type: \"text\", text: \"Failed to create payment payload\" }]\n };\n }\n\n // Encode the payment payload as a base64 JSON token for MCP transport\n const token = btoa(JSON.stringify(paymentPayload));\n\n // Retry the tool call with the payment token\n return _callTool(\n {\n ...params,\n _meta: {\n ...params._meta,\n \"x402/payment\": token\n }\n },\n resultSchema,\n options\n );\n }\n\n return res;\n };\n\n const _client = client as X402AugmentedClient & T;\n Object.defineProperty(_client, \"listTools\", {\n value: listTools,\n writable: false,\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(_client, \"callTool\", {\n value: callToolWithPayment,\n writable: false,\n enumerable: false,\n configurable: true\n });\n\n return _client;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"x402.js","names":[],"sources":["../../src/mcp/x402.ts"],"sourcesContent":["/**\n * X402 MCP Integration (v2)\n *\n * Based on:\n * - Coinbase's x402 (Apache 2.0): https://github.com/coinbase/x402\n * - @ethanniser and his work at https://github.com/ethanniser/x402-mcp\n */\n\nimport type {\n McpServer,\n RegisteredTool,\n ToolCallback\n} from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type {\n CallToolRequest,\n CallToolRequestOptions,\n Client as MCPClient\n} from \"@modelcontextprotocol/client\";\nimport type {\n CallToolResult,\n ToolAnnotations\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport {\n bindMcpClient,\n type CallToolSchemaOrOptions,\n type CompatibleMcpClient,\n type LegacyCallToolResultSchema\n} from \"./client-invoker\";\nimport type { ZodRawShape } from \"zod\";\n\n// v2 imports from @x402/core\nimport { x402ResourceServer, HTTPFacilitatorClient } from \"@x402/core/server\";\nimport type { FacilitatorConfig, ResourceConfig } from \"@x402/core/server\";\nimport { x402Client } from \"@x402/core/client\";\nimport type {\n PaymentPayload,\n PaymentRequirements,\n PaymentRequired,\n Network\n} from \"@x402/core/types\";\n\n// v2 imports from @x402/evm\nimport { registerExactEvmScheme as registerServerEvmScheme } from \"@x402/evm/exact/server\";\nimport { registerExactEvmScheme as registerClientEvmScheme } from \"@x402/evm/exact/client\";\nimport type { ClientEvmSigner } from \"@x402/evm\";\n\n// Re-export commonly used types for consumer convenience\nexport type {\n PaymentRequirements,\n PaymentRequired,\n Network\n} from \"@x402/core/types\";\nexport type { FacilitatorConfig } from \"@x402/core/server\";\nexport type { ClientEvmSigner } from \"@x402/evm\";\n\n/**\n * Map of legacy v1 network names to CAIP-2 identifiers.\n * Allows backward compatibility with v1 config.\n */\nconst LEGACY_NETWORK_MAP: Record<string, string> = {\n \"base-sepolia\": \"eip155:84532\",\n base: \"eip155:8453\",\n ethereum: \"eip155:1\",\n sepolia: \"eip155:11155111\"\n};\n\n/**\n * Normalize a network identifier to CAIP-2 format.\n * Accepts both legacy v1 names (\"base-sepolia\") and CAIP-2 (\"eip155:84532\").\n */\nexport function normalizeNetwork(network: string): Network {\n return (LEGACY_NETWORK_MAP[network] ?? network) as Network;\n}\n\n/*\n ======= SERVER SIDE =======\n*/\n\nexport type X402Config = {\n /**\n * Network identifier.\n * Accepts both legacy names (\"base-sepolia\") and CAIP-2 format (\"eip155:84532\").\n */\n network: string;\n /** Payment recipient address */\n recipient: `0x${string}`;\n /** Facilitator configuration. Defaults to https://x402.org/facilitator */\n facilitator?: FacilitatorConfig;\n /** @deprecated No longer used in v2. The protocol version is determined automatically. */\n version?: number;\n};\n\nexport interface X402AugmentedServer {\n paidTool<Args extends ZodRawShape>(\n name: string,\n description: string,\n priceUSD: number,\n paramsSchema: Args,\n annotations: ToolAnnotations,\n cb: ToolCallback<Args>\n ): RegisteredTool;\n}\n\nexport function withX402<T extends McpServer>(\n server: T,\n cfg: X402Config\n): T & X402AugmentedServer {\n const network = normalizeNetwork(cfg.network);\n const facilitatorConfig: FacilitatorConfig = cfg.facilitator ?? {\n url: \"https://x402.org/facilitator\"\n };\n\n // Create v2 resource server with facilitator client\n const facilitatorClient = new HTTPFacilitatorClient(facilitatorConfig);\n const resourceServer = new x402ResourceServer(facilitatorClient);\n registerServerEvmScheme(resourceServer);\n\n // Lazy initialization: fetch supported kinds from facilitator on first use\n let initPromise: Promise<void> | null = null;\n function ensureInitialized(): Promise<void> {\n if (!initPromise) {\n initPromise = resourceServer.initialize().catch((err) => {\n initPromise = null; // allow retry on failure\n throw err;\n });\n }\n return initPromise;\n }\n\n function paidTool<Args extends ZodRawShape>(\n name: string,\n description: string,\n priceUSD: number,\n paramsSchema: Args,\n annotations: ToolAnnotations,\n cb: ToolCallback<Args>\n ): RegisteredTool {\n return server.registerTool(\n name,\n {\n description,\n inputSchema: paramsSchema,\n annotations,\n _meta: {\n \"agents-x402/paymentRequired\": true,\n \"agents-x402/priceUSD\": priceUSD\n }\n },\n (async (args, extra) => {\n await ensureInitialized();\n\n // Build v2 payment requirements for this tool call\n const resourceConfig: ResourceConfig = {\n scheme: \"exact\",\n payTo: cfg.recipient,\n price: priceUSD,\n network,\n maxTimeoutSeconds: 300\n };\n\n let requirements: PaymentRequirements[];\n try {\n requirements =\n await resourceServer.buildPaymentRequirements(resourceConfig);\n } catch {\n const payload = { x402Version: 2, error: \"PRICE_COMPUTE_FAILED\" };\n return {\n isError: true,\n _meta: { \"x402/error\": payload },\n content: [{ type: \"text\", text: JSON.stringify(payload) }]\n } as const;\n }\n\n const resourceInfo = {\n url: `x402://${name}`,\n description,\n mimeType: \"application/json\"\n };\n\n // Get payment token from MCP _meta or HTTP headers\n // Support both v2 (PAYMENT-SIGNATURE) and v1 (X-PAYMENT) header names\n const headers = extra?.requestInfo?.headers ?? {};\n const token =\n (extra?._meta?.[\"x402/payment\"] as string | undefined) ??\n headers[\"PAYMENT-SIGNATURE\"] ??\n headers[\"X-PAYMENT\"];\n\n const paymentRequired = (\n reason = \"PAYMENT_REQUIRED\",\n extraFields: Record<string, unknown> = {}\n ) => {\n const payload = {\n x402Version: 2,\n error: reason,\n resource: resourceInfo,\n accepts: requirements,\n ...extraFields\n };\n return {\n isError: true,\n _meta: { \"x402/error\": payload },\n content: [{ type: \"text\", text: JSON.stringify(payload) }]\n } as const;\n };\n\n if (!token || typeof token !== \"string\") return paymentRequired();\n\n // Decode the payment payload (base64-encoded JSON)\n let paymentPayload: PaymentPayload;\n try {\n paymentPayload = JSON.parse(atob(token));\n } catch {\n return paymentRequired(\"INVALID_PAYMENT\");\n }\n\n // Find matching requirements for this payment\n const matchingReq = resourceServer.findMatchingRequirements(\n requirements,\n paymentPayload\n );\n if (!matchingReq) {\n return paymentRequired(\"INVALID_PAYMENT\");\n }\n\n // Verify payment with facilitator\n try {\n const vr = await resourceServer.verifyPayment(\n paymentPayload,\n matchingReq\n );\n if (!vr.isValid) {\n return paymentRequired(vr.invalidReason ?? \"INVALID_PAYMENT\", {\n payer: vr.payer\n });\n }\n } catch {\n return paymentRequired(\"INVALID_PAYMENT\");\n }\n\n // Execute the tool callback\n let result: CallToolResult;\n let failed = false;\n try {\n result = await cb(args, extra);\n if (\n result &&\n typeof result === \"object\" &&\n \"isError\" in result &&\n result.isError\n ) {\n failed = true;\n }\n } catch (e) {\n failed = true;\n result = {\n isError: true,\n content: [\n { type: \"text\", text: `Tool execution failed: ${String(e)}` }\n ]\n };\n }\n\n // Settle payment only on success\n if (!failed) {\n try {\n const s = await resourceServer.settlePayment(\n paymentPayload,\n matchingReq\n );\n if (s.success) {\n result._meta ??= {};\n result._meta[\"x402/payment-response\"] = {\n success: true,\n transaction: s.transaction,\n network: s.network,\n payer: s.payer\n };\n } else {\n return paymentRequired(s.errorReason ?? \"SETTLEMENT_FAILED\");\n }\n } catch {\n return paymentRequired(\"SETTLEMENT_FAILED\");\n }\n }\n\n return result;\n }) as ToolCallback<Args>\n );\n }\n\n Object.defineProperty(server, \"paidTool\", {\n value: paidTool,\n writable: false,\n enumerable: false,\n configurable: true\n });\n\n // Tell TS the object now also has the paidTool method\n return server as T & X402AugmentedServer;\n}\n\n/*\n ======= CLIENT SIDE =======\n*/\n\nexport interface X402AugmentedClient {\n callTool(\n x402ConfirmationCallback:\n | ((payment: PaymentRequirements[]) => Promise<boolean>)\n | null,\n params: CallToolRequest[\"params\"],\n options?: CallToolRequestOptions\n ): Promise<CallToolResult>;\n /**\n * @deprecated Prefer the request-options overload. Explicit legacy result\n * schemas remain honored through the SDK v2 request funnel.\n */\n callTool(\n x402ConfirmationCallback:\n | ((payment: PaymentRequirements[]) => Promise<boolean>)\n | null,\n params: CallToolRequest[\"params\"],\n resultSchema: LegacyCallToolResultSchema,\n options?: CallToolRequestOptions\n ): Promise<CallToolResult>;\n}\n\nexport type X402ClientConfig = {\n /**\n * EVM account/signer for signing payment authorizations.\n * Use `privateKeyToAccount()` from viem/accounts to create one.\n */\n account: ClientEvmSigner;\n /**\n * Preferred network identifier (optional).\n * Accepts both legacy names (\"base-sepolia\") and CAIP-2 format (\"eip155:84532\").\n * When set, the client prefers payment requirements matching this network.\n * If omitted, the client automatically selects from available requirements.\n */\n network?: string;\n /** Maximum payment value in atomic units (default: 0.10 USDC = 100000) */\n maxPaymentValue?: bigint;\n /** @deprecated No longer used in v2. The protocol version is determined automatically. */\n version?: number;\n /** Confirmation callback for payment approval */\n confirmationCallback?: (payment: PaymentRequirements[]) => Promise<boolean>;\n};\n\nexport function withX402Client<T extends CompatibleMcpClient>(\n client: T,\n x402Config: X402ClientConfig\n): X402AugmentedClient & T {\n const invoker = bindMcpClient(client);\n const { account } = x402Config;\n\n const maxPaymentValue = x402Config.maxPaymentValue ?? BigInt(100_000); // 0.10 USDC\n\n // Create v2 x402 payment client with EVM scheme support\n const paymentClient = new x402Client();\n registerClientEvmScheme(paymentClient, { signer: account });\n\n // If a preferred network is specified, register a policy to prefer it\n if (x402Config.network) {\n const preferredNetwork = normalizeNetwork(x402Config.network);\n paymentClient.registerPolicy((_version, reqs) => {\n const matching = reqs.filter((r) => r.network === preferredNetwork);\n return matching.length > 0 ? matching : reqs;\n });\n }\n\n const listTools = async (\n params?: Parameters<MCPClient[\"listTools\"]>[0],\n options?: Parameters<MCPClient[\"listTools\"]>[1]\n ) => {\n const toolsRes = await invoker.listTools(params, options);\n return {\n ...toolsRes,\n tools: toolsRes.tools.map((tool) => {\n let description = tool.description;\n // Check _meta for payment information (agents-x402/ is our extension for pre-advertising prices)\n if (tool._meta?.[\"agents-x402/paymentRequired\"]) {\n const cost = tool._meta?.[\"agents-x402/priceUSD\"]\n ? `$${tool._meta?.[\"agents-x402/priceUSD\"]}`\n : \"an unknown amount\";\n description += ` (This is a paid tool, you will be charged ${cost} for its execution)`;\n }\n return {\n ...tool,\n description\n };\n })\n };\n };\n\n const callToolWithPayment = async (\n x402ConfirmationCallback:\n | ((payment: PaymentRequirements[]) => Promise<boolean>)\n | null,\n params: CallToolRequest[\"params\"],\n schemaOrOptions?: CallToolSchemaOrOptions,\n options?: CallToolRequestOptions\n ): ReturnType<MCPClient[\"callTool\"]> => {\n const invoke = (callParams: CallToolRequest[\"params\"]) =>\n invoker.callTool(callParams, schemaOrOptions, options);\n const res = await invoke(params);\n\n // Check for x402 payment required error in response metadata\n const maybeX402Error = res._meta?.[\"x402/error\"] as\n | (PaymentRequired & Record<string, unknown>)\n | undefined;\n\n if (\n res.isError &&\n maybeX402Error &&\n maybeX402Error.accepts &&\n Array.isArray(maybeX402Error.accepts) &&\n maybeX402Error.accepts.length > 0\n ) {\n const accepts = maybeX402Error.accepts;\n const confirmationCallback =\n x402ConfirmationCallback ?? x402Config.confirmationCallback;\n\n // Use the confirmation callback if provided\n if (confirmationCallback && !(await confirmationCallback(accepts))) {\n return {\n isError: true,\n content: [{ type: \"text\", text: \"User declined payment\" }]\n };\n }\n\n // Check max payment value against the first requirement's amount\n const selectedReq = accepts[0];\n if (!selectedReq || selectedReq.scheme !== \"exact\") return res;\n\n let amount: bigint;\n try {\n amount = BigInt(selectedReq.amount);\n } catch {\n return res; // malformed amount — return original error\n }\n if (amount > maxPaymentValue) {\n return {\n isError: true,\n content: [\n {\n type: \"text\",\n text: `Payment exceeds client cap: ${amount} > ${maxPaymentValue}`\n }\n ]\n };\n }\n\n // Reconstruct the PaymentRequired response for the v2 x402 client\n const paymentRequiredResponse: PaymentRequired = {\n x402Version: (maybeX402Error.x402Version as number) ?? 2,\n resource: (maybeX402Error.resource as PaymentRequired[\"resource\"]) ?? {\n url: \"\",\n description: \"\",\n mimeType: \"application/json\"\n },\n accepts,\n extensions: maybeX402Error.extensions as\n | Record<string, unknown>\n | undefined\n };\n\n // Create the payment payload using the v2 x402 client\n let paymentPayload: PaymentPayload;\n try {\n paymentPayload = await paymentClient.createPaymentPayload(\n paymentRequiredResponse\n );\n } catch {\n return {\n isError: true,\n content: [{ type: \"text\", text: \"Failed to create payment payload\" }]\n };\n }\n\n // Encode the payment payload as a base64 JSON token for MCP transport\n const token = btoa(JSON.stringify(paymentPayload));\n\n // Retry the tool call with the payment token\n return invoke({\n ...params,\n _meta: {\n ...params._meta,\n \"x402/payment\": token\n }\n });\n }\n\n return res;\n };\n\n const _client = client as X402AugmentedClient & T;\n Object.defineProperty(_client, \"listTools\", {\n value: listTools,\n writable: false,\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(_client, \"callTool\", {\n value: callToolWithPayment,\n writable: false,\n enumerable: false,\n configurable: true\n });\n\n return _client;\n}\n"],"mappings":"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"}
|
package/dist/react.d.ts
CHANGED
package/dist/serializable.d.ts
CHANGED
package/dist/sub-routing.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
ln as
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
} from "./agent-tool-types-
|
|
2
|
+
cn as SubAgentPathMatch,
|
|
3
|
+
dn as routeSubAgentRequest,
|
|
4
|
+
ln as getSubAgentByName,
|
|
5
|
+
sn as SUB_PREFIX,
|
|
6
|
+
un as parseSubAgentPath
|
|
7
|
+
} from "./agent-tool-types-Btk9ETS-.js";
|
|
8
8
|
export {
|
|
9
9
|
SUB_PREFIX,
|
|
10
10
|
SubAgentPathMatch,
|
package/dist/workflows.d.ts
CHANGED
|
@@ -25,13 +25,14 @@ Human-in-the-loop (HITL) patterns allow agents to pause execution and wait for h
|
|
|
25
25
|
|
|
26
26
|
Agents SDK supports multiple human-in-the-loop patterns. Choose based on your use case:
|
|
27
27
|
|
|
28
|
-
| Use Case | Pattern
|
|
29
|
-
| ---------------------- |
|
|
30
|
-
| Long-running workflows | Workflow Approval
|
|
31
|
-
| AIChatAgent tools | `needsApproval`
|
|
32
|
-
| OpenAI Agents SDK | `needsApproval`
|
|
33
|
-
| Client-side tools | `onToolCall`
|
|
34
|
-
|
|
|
28
|
+
| Use Case | Pattern | Best For | Example |
|
|
29
|
+
| ---------------------- | --------------------- | -------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
30
|
+
| Long-running workflows | Workflow Approval | Multi-step processes, durable approval gates | [examples/workflows/](https://github.com/cloudflare/agents/tree/main/examples/workflows) |
|
|
31
|
+
| AIChatAgent tools | `needsApproval` | Chat-based tool calls with `@cloudflare/ai-chat` | [guides/human-in-the-loop/](https://github.com/cloudflare/agents/tree/main/guides/human-in-the-loop) |
|
|
32
|
+
| OpenAI Agents SDK | `needsApproval` | Using OpenAI's agent SDK with conditional approval | [openai-sdk/human-in-the-loop/](https://github.com/cloudflare/agents/tree/main/openai-sdk/human-in-the-loop) |
|
|
33
|
+
| Client-side tools | `onToolCall` | Tools that need browser APIs or user interaction | Pattern below |
|
|
34
|
+
| Stateless servers | Stateless Elicitation | Current MCP tools requesting structured input | [examples/mcp-elicitation-mrtr/](https://github.com/cloudflare/agents/tree/main/examples/mcp-elicitation-mrtr) |
|
|
35
|
+
| Legacy servers | Legacy Elicitation | Existing sessionful MCP deployments | [examples/mcp-elicitation/](https://github.com/cloudflare/agents/tree/main/examples/mcp-elicitation) |
|
|
35
36
|
|
|
36
37
|
### Decision Guide
|
|
37
38
|
|
|
@@ -452,85 +453,64 @@ See the complete example: [openai-sdk/human-in-the-loop/](https://github.com/clo
|
|
|
452
453
|
|
|
453
454
|
### MCP Elicitation
|
|
454
455
|
|
|
455
|
-
|
|
456
|
+
**Stateless Elicitation** uses multi-round-trip requests (MRTR). A handler returns `inputRequired(...)`; the client gathers the requested input and retries with SDK-managed state. No Worker remains suspended while the user responds.
|
|
456
457
|
|
|
457
458
|
```typescript
|
|
458
|
-
import {
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
});
|
|
466
|
-
|
|
467
|
-
onStart() {
|
|
468
|
-
this.server.registerTool(
|
|
469
|
-
"increase-counter",
|
|
470
|
-
{
|
|
471
|
-
description: "Increase the counter by a user-specified amount",
|
|
472
|
-
inputSchema: {
|
|
473
|
-
confirm: z.boolean().describe("Do you want to increase the counter?")
|
|
474
|
-
}
|
|
475
|
-
},
|
|
476
|
-
async ({ confirm }, extra) => {
|
|
477
|
-
if (!confirm) {
|
|
478
|
-
return { content: [{ type: "text", text: "Cancelled." }] };
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
// Request additional input from the user
|
|
482
|
-
const userInput = await this.server.server.elicitInput(
|
|
483
|
-
{
|
|
484
|
-
message: "By how much do you want to increase the counter?",
|
|
485
|
-
requestedSchema: {
|
|
486
|
-
type: "object",
|
|
487
|
-
properties: {
|
|
488
|
-
amount: {
|
|
489
|
-
type: "number",
|
|
490
|
-
title: "Amount",
|
|
491
|
-
description: "The amount to increase the counter by"
|
|
492
|
-
}
|
|
493
|
-
},
|
|
494
|
-
required: ["amount"]
|
|
495
|
-
}
|
|
496
|
-
},
|
|
497
|
-
{ relatedRequestId: extra.requestId }
|
|
498
|
-
);
|
|
499
|
-
|
|
500
|
-
// Check if user accepted or cancelled
|
|
501
|
-
if (userInput.action !== "accept" || !userInput.content) {
|
|
502
|
-
return { content: [{ type: "text", text: "Cancelled." }] };
|
|
503
|
-
}
|
|
459
|
+
import {
|
|
460
|
+
McpServer,
|
|
461
|
+
acceptedContent,
|
|
462
|
+
inputRequired
|
|
463
|
+
} from "@modelcontextprotocol/server";
|
|
464
|
+
import { createMcpHandler } from "agents/mcp/server";
|
|
465
|
+
import { z } from "zod";
|
|
504
466
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
467
|
+
function createServer() {
|
|
468
|
+
const server = new McpServer({ name: "my-server", version: "1.0.0" });
|
|
469
|
+
server.registerTool(
|
|
470
|
+
"ask-name",
|
|
471
|
+
{ inputSchema: z.object({}) },
|
|
472
|
+
async (_args, context) => {
|
|
473
|
+
const answer = acceptedContent(
|
|
474
|
+
context.mcpReq.inputResponses,
|
|
475
|
+
"name",
|
|
476
|
+
z.object({ name: z.string() })
|
|
477
|
+
);
|
|
478
|
+
if (!answer) {
|
|
479
|
+
return inputRequired({
|
|
480
|
+
inputRequests: {
|
|
481
|
+
name: inputRequired.elicit({
|
|
482
|
+
message: "What is your name?",
|
|
483
|
+
requestedSchema: {
|
|
484
|
+
type: "object",
|
|
485
|
+
properties: { name: { type: "string" } },
|
|
486
|
+
required: ["name"]
|
|
487
|
+
}
|
|
488
|
+
})
|
|
489
|
+
}
|
|
510
490
|
});
|
|
511
|
-
|
|
512
|
-
return {
|
|
513
|
-
content: [
|
|
514
|
-
{
|
|
515
|
-
type: "text",
|
|
516
|
-
text: `Counter increased by ${amount}, now at ${this.state.counter}`
|
|
517
|
-
}
|
|
518
|
-
]
|
|
519
|
-
};
|
|
520
491
|
}
|
|
492
|
+
return { content: [{ type: "text", text: `Hello ${answer.name}` }] };
|
|
493
|
+
}
|
|
494
|
+
);
|
|
495
|
+
return server;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
export default {
|
|
499
|
+
fetch(request, env, ctx) {
|
|
500
|
+
return createMcpHandler(createServer, { legacy: "reject" })(
|
|
501
|
+
request,
|
|
502
|
+
env,
|
|
503
|
+
ctx
|
|
521
504
|
);
|
|
522
505
|
}
|
|
523
|
-
}
|
|
506
|
+
} satisfies ExportedHandler;
|
|
524
507
|
```
|
|
525
508
|
|
|
526
|
-
|
|
509
|
+
The MCP client renders the JSON Schema form and the original operation remains pending from the application's perspective while the SDK completes the rounds.
|
|
527
510
|
|
|
528
|
-
|
|
529
|
-
- Uses **JSON Schema** for structured form-based input
|
|
530
|
-
- The **MCP client** (Claude Desktop, etc.) handles UI rendering
|
|
531
|
-
- Returns `{ action: "accept" | "decline", content: {...} }`
|
|
511
|
+
See the [Stateless Elicitation example](https://github.com/cloudflare/agents/tree/main/examples/mcp-elicitation-mrtr).
|
|
532
512
|
|
|
533
|
-
See the
|
|
513
|
+
**Legacy Elicitation** in existing Legacy deployments uses pushed `elicitation/create` requests over a stateful transport. See the explicitly legacy [examples/mcp-elicitation/](https://github.com/cloudflare/agents/tree/main/examples/mcp-elicitation) example when retaining `McpAgent` or `createLegacyMcpHandler` with `WorkerTransport`.
|
|
534
514
|
|
|
535
515
|
## State Patterns for Approvals
|
|
536
516
|
|
|
@@ -647,15 +627,16 @@ async submitForApproval(request: ApprovalRequest): Promise<string> {
|
|
|
647
627
|
|
|
648
628
|
## Complete Examples
|
|
649
629
|
|
|
650
|
-
| Pattern
|
|
651
|
-
|
|
|
652
|
-
| Workflow approval
|
|
653
|
-
| AIChatAgent tools
|
|
654
|
-
| OpenAI Agents SDK
|
|
655
|
-
|
|
|
630
|
+
| Pattern | Location | Description |
|
|
631
|
+
| --------------------- | -------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- |
|
|
632
|
+
| Workflow approval | [examples/workflows/](https://github.com/cloudflare/agents/tree/main/examples/workflows) | Multi-step task processing with approval gate |
|
|
633
|
+
| AIChatAgent tools | [guides/human-in-the-loop/](https://github.com/cloudflare/agents/tree/main/guides/human-in-the-loop) | Chat tool approval with needsApproval + onToolCall |
|
|
634
|
+
| OpenAI Agents SDK | [openai-sdk/human-in-the-loop/](https://github.com/cloudflare/agents/tree/main/openai-sdk/human-in-the-loop) | Conditional tool approval with modal |
|
|
635
|
+
| Stateless Elicitation | [examples/mcp-elicitation-mrtr/](https://github.com/cloudflare/agents/tree/main/examples/mcp-elicitation-mrtr) | Stateless multi-round input |
|
|
636
|
+
| Legacy Elicitation | [examples/mcp-elicitation/](https://github.com/cloudflare/agents/tree/main/examples/mcp-elicitation) | Stateful pushed input requests |
|
|
656
637
|
|
|
657
638
|
For detailed API documentation, see:
|
|
658
639
|
|
|
659
640
|
- [Workflows](./workflows.md) - `waitForApproval()`, `approveWorkflow()`, `rejectWorkflow()`
|
|
660
|
-
- [MCP Servers](./mcp-servers.md) - `
|
|
641
|
+
- [MCP Servers](./mcp-servers.md) - `inputRequired()` and legacy `elicitInput()`
|
|
661
642
|
- [Callable Methods](./callable-methods.md) - `@callable()` decorator for approval endpoints
|
package/docs/mcp-client.md
CHANGED
|
@@ -15,6 +15,12 @@ The MCP client capability lets your agent:
|
|
|
15
15
|
|
|
16
16
|
## Quick Start
|
|
17
17
|
|
|
18
|
+
Install the exact MCP client peer used by this Agents release:
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
pnpm add agents @modelcontextprotocol/client@2.0.0-beta.5
|
|
22
|
+
```
|
|
23
|
+
|
|
18
24
|
```typescript
|
|
19
25
|
import { Agent } from "agents";
|
|
20
26
|
|
|
@@ -95,6 +101,20 @@ await this.addMcpServer("internal", "https://internal-mcp.example.com/mcp", {
|
|
|
95
101
|
});
|
|
96
102
|
```
|
|
97
103
|
|
|
104
|
+
### Legacy OAuth metadata compatibility
|
|
105
|
+
|
|
106
|
+
SDK v2 validates authorization-server metadata issuers by default. A trusted Legacy server with known mismatched RFC 8414 metadata can opt out explicitly:
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
await this.addMcpServer("legacy", "https://legacy.example.com/mcp", {
|
|
110
|
+
transport: {
|
|
111
|
+
skipIssuerMetadataValidation: true
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
This weakens OAuth mix-up protection. Do not enable it for unknown servers or as a general fallback.
|
|
117
|
+
|
|
98
118
|
### Retry Options
|
|
99
119
|
|
|
100
120
|
Configure retry behavior for connection and reconnection attempts:
|
|
@@ -111,9 +131,13 @@ await this.addMcpServer("github", "https://mcp.github.com/mcp", {
|
|
|
111
131
|
|
|
112
132
|
These options are persisted and used when reconnecting after hibernation or after OAuth completion. Default: 3 attempts, 500ms base delay, 5s max delay. See [Retries](./retries.md) for more details.
|
|
113
133
|
|
|
114
|
-
###
|
|
134
|
+
### Protocol negotiation and elicitation
|
|
135
|
+
|
|
136
|
+
Agents uses the MCP v2 client and automatically negotiates the protocol version for every connection. It uses `server/discover` with Stateless servers and falls back to the `initialize` handshake on the same connection for Legacy Streamable HTTP, SSE, and RPC servers.
|
|
115
137
|
|
|
116
|
-
MCP servers can request input from the client during
|
|
138
|
+
MCP servers can request input from the client during `callTool`, `getPrompt`, or `readResource`. Stateless Elicitation returns an `input_required` result and completes through MRTR: the MCP SDK invokes the configured `elicitation/create` handler, sends its response, and continues the original request. Agents does not expose an intermediate continuation; the original call stays pending while human input is collected and eventually resolves to the ordinary tool, prompt, or resource result. Legacy Elicitation on Legacy servers continues to use pushed `elicitation/create` requests. Both generations share the same handlers.
|
|
139
|
+
|
|
140
|
+
Configure elicitation handlers before MCP connections are registered or restored:
|
|
117
141
|
|
|
118
142
|
```typescript
|
|
119
143
|
import { Agent } from "agents";
|
|
@@ -136,6 +160,8 @@ class MyAgent extends Agent<Env> {
|
|
|
136
160
|
|
|
137
161
|
The advertised modes are persisted with each MCP server, so a connection restored from storage after hibernation re-advertises the same modes at the handshake; the handlers themselves re-attach when `onStart()` runs. Configuring a handler after an MCP connection is already active updates the in-memory handler, but the server only sees new advertised elicitation modes after that connection reconnects.
|
|
138
162
|
|
|
163
|
+
Handlers and pending calls are memory-only. A Durable Object hibernation or isolate restart does not preserve an in-flight interactive call; callers must retry it after the connection is restored. Agents intentionally does not persist in-flight Stateless `requestState` or implement a manual/resumable continuation layer.
|
|
164
|
+
|
|
139
165
|
Connections advertise only the elicitation modes with configured handlers at the `initialize` handshake: configure `form` to advertise form-mode elicitation, `url` to advertise url-mode elicitation (MCP spec 2025-11-25 — url mode is used for sensitive flows like OAuth URLs), or both to advertise both modes. Without handlers, connections advertise no elicitation capability, so spec-compliant servers use their non-elicitation fallbacks instead of sending requests the agent cannot answer.
|
|
140
166
|
|
|
141
167
|
To override the advertised modes, declare them explicitly — an explicit declaration always wins and is persisted with the server options, surviving hibernation:
|
|
@@ -416,7 +442,7 @@ function Dashboard() {
|
|
|
416
442
|
onMcpUpdate: (mcpState) => {
|
|
417
443
|
setTools(mcpState.tools);
|
|
418
444
|
setServers(mcpState.servers);
|
|
419
|
-
}
|
|
445
|
+
},
|
|
420
446
|
});
|
|
421
447
|
|
|
422
448
|
return (
|
|
@@ -429,10 +455,8 @@ function Dashboard() {
|
|
|
429
455
|
))}
|
|
430
456
|
|
|
431
457
|
<h2>Available Tools ({tools.length})</h2>
|
|
432
|
-
{tools.map(tool => (
|
|
433
|
-
<div key={`${tool.serverId}-${tool.name}`}>
|
|
434
|
-
{tool.name}
|
|
435
|
-
</div>
|
|
458
|
+
{tools.map((tool) => (
|
|
459
|
+
<div key={`${tool.serverId}-${tool.name}`}>{tool.name}</div>
|
|
436
460
|
))}
|
|
437
461
|
</div>
|
|
438
462
|
);
|