Skip to content

Commit bf5c3a3

Browse files
committed
fix(mcp): strip outputSchema from proxied tool definitions
MCP SDK 1.28.0 clients validate structuredContent against outputSchema via AJV. When the proxy forwards tool definitions with outputSchema, downstream clients reject valid upstream responses. Strip outputSchema so the proxy stays transparent.
1 parent 026630b commit bf5c3a3

3 files changed

Lines changed: 16 additions & 4 deletions

File tree

packages/x402-proxy/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "x402-proxy",
33
"private": true,
4-
"version": "0.10.10",
4+
"version": "0.10.11",
55
"description": "curl for x402 paid APIs. Auto-pays any endpoint on Base, Solana, and Tempo.",
66
"type": "module",
77
"sideEffects": false,

packages/x402-proxy/src/commands/mcp.test.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
} from "./mcp.js";
99

1010
describe("cloneTool", () => {
11-
it("preserves outputSchema and extra tool metadata", () => {
11+
it("strips outputSchema and preserves other tool metadata", () => {
1212
const tool = {
1313
name: "surf_web_search",
1414
title: "Web Search",
@@ -23,7 +23,16 @@ describe("cloneTool", () => {
2323
execution: { taskSupport: "optional" },
2424
};
2525

26-
expect(cloneTool(tool)).toEqual(tool);
26+
const cloned = cloneTool(tool);
27+
expect(cloned).not.toHaveProperty("outputSchema");
28+
expect(cloned).toEqual({
29+
name: "surf_web_search",
30+
title: "Web Search",
31+
description: "Search the web",
32+
inputSchema: { type: "object" },
33+
annotations: { readOnlyHint: true },
34+
execution: { taskSupport: "optional" },
35+
});
2736
});
2837
});
2938

packages/x402-proxy/src/commands/mcp.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,10 @@ const X402_PAYMENT_META_KEY = "x402/payment";
5656
const X402_PAYMENT_RESPONSE_META_KEY = "x402/payment-response";
5757

5858
export function cloneTool(tool: ToolDefinition): ToolDefinition {
59-
return { ...tool };
59+
// Strip outputSchema so downstream clients don't attempt AJV validation
60+
// of structuredContent — the proxy passes data through as-is.
61+
const { outputSchema: _, ...rest } = tool as ToolDefinition & { outputSchema?: unknown };
62+
return rest as ToolDefinition;
6063
}
6164

6265
export function cloneResource(resource: ResourceDefinition): ResourceDefinition {

0 commit comments

Comments
 (0)