From 117fe9de4e8b50ed176a0b53406e8eb65dd5cb76 Mon Sep 17 00:00:00 2001 From: clancy Date: Sun, 5 Jul 2026 12:06:30 +0800 Subject: [PATCH] fix: strip unsupported regex patterns from tool schemas --- src/server.test.ts | 42 +++++++++++++++++++++++++++++++++++++----- src/server.ts | 22 ++++++++++++++++++++++ 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/src/server.test.ts b/src/server.test.ts index 663dbad..cc6e440 100644 --- a/src/server.test.ts +++ b/src/server.test.ts @@ -33,10 +33,9 @@ describe("MCP server tools/list", () => { const tools = await getToolList(); for (const tool of tools) { const schema = tool.inputSchema as Record; - expect( - schema.$schema, - `Tool "${tool.name}" is missing $schema or has wrong draft`, - ).toBe("https://json-schema.org/draft/2020-12/schema"); + expect(schema.$schema, `Tool "${tool.name}" is missing $schema or has wrong draft`).toBe( + "https://json-schema.org/draft/2020-12/schema", + ); } }); @@ -60,7 +59,40 @@ describe("MCP server tools/list", () => { for (const tool of tools) { const found = findNestedSchemaKeys(tool.inputSchema); - expect(found, `Tool "${tool.name}" has nested $schema keys at: ${found.join(", ")}`).toHaveLength(0); + expect( + found, + `Tool "${tool.name}" has nested $schema keys at: ${found.join(", ")}`, + ).toHaveLength(0); + } + }); + + it("no tool inputSchema exposes regex lookaround patterns", async () => { + const tools = await getToolList(); + + function findLookaroundPatterns(obj: unknown, path = ""): string[] { + if (obj === null || typeof obj !== "object") return []; + if (Array.isArray(obj)) { + return obj.flatMap((item, i) => findLookaroundPatterns(item, `${path}[${i}]`)); + } + + const record = obj as Record; + const found: string[] = []; + for (const [key, value] of Object.entries(record)) { + const currentPath = path ? `${path}.${key}` : key; + if (key === "pattern" && typeof value === "string" && /\(\?; + if (usesUnsupportedRegexSyntax(record.pattern)) { + delete record.pattern; + } + + for (const child of Object.values(record)) { + stripUnsupportedRegexPatterns(child); + } +} + // Claude's API requires JSON Schema draft 2020-12. The MCP SDK's built-in // Zod→JSON Schema converter emits draft-07 by default, which causes a 400 // error on tools/list. We bypass the SDK's auto-generated handler by @@ -63,6 +84,7 @@ function toDraft2020_12JsonSchema(schema: ZodObject): Record; stripNestedSchemaKeys(result); + stripUnsupportedRegexPatterns(result); result.$schema = JSON_SCHEMA_2020_12; return result; }