From d1e72207f48609e3214a66c2a248c70a2a1abd6c Mon Sep 17 00:00:00 2001 From: morluto <76467478+morluto@users.noreply.github.com> Date: Thu, 16 Jul 2026 19:01:35 +0800 Subject: [PATCH] fix(mcp): align runtime unknown argument validation --- src/server/toolInputValidation.ts | 3 ++- src/server/toolRegistrationOptions.ts | 3 ++- tests/enhancedTools.test.ts | 22 ++++++++++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/server/toolInputValidation.ts b/src/server/toolInputValidation.ts index ef29abc76..f8973dc62 100644 --- a/src/server/toolInputValidation.ts +++ b/src/server/toolInputValidation.ts @@ -6,6 +6,7 @@ import { } from "../domain/errors.js"; import { projectInputIssues } from "../domain/inputIssueProjection.js"; import { err, ok, type Result } from "../domain/result.js"; +import { closeObjectSchemas } from "./toolRegistrationOptions.js"; /** Parse one MCP request exactly once and retain only schema-owned correction data. */ export const safeParseToolInput = ( @@ -41,7 +42,7 @@ const unknownArgumentIssues = ( throw new TypeError( "Tool input schema does not expose Standard JSON Schema", ); - jsonSchema = converter({ target: "draft-2020-12" }); + jsonSchema = closeObjectSchemas(converter({ target: "draft-2020-12" })); schemaCache.set(schema, jsonSchema); } return scanUnknownArguments(input, jsonSchema, jsonSchema, []); diff --git a/src/server/toolRegistrationOptions.ts b/src/server/toolRegistrationOptions.ts index 2552c3241..f5d6616f3 100644 --- a/src/server/toolRegistrationOptions.ts +++ b/src/server/toolRegistrationOptions.ts @@ -67,7 +67,8 @@ const inputJsonSchema = (schema: z.ZodObject): Record => { return converter({ target: "draft-2020-12" }); }; -const closeObjectSchemas = ( +/** Close fixed-shape JSON Schema objects while preserving explicit maps. */ +export const closeObjectSchemas = ( value: Readonly>, ): Record => { const closed = Object.fromEntries( diff --git a/tests/enhancedTools.test.ts b/tests/enhancedTools.test.ts index 06dc20cf7..3899b6a57 100644 --- a/tests/enhancedTools.test.ts +++ b/tests/enhancedTools.test.ts @@ -629,6 +629,28 @@ describe("enhanced MCP tools", () => { }, }, }); + const nestedMisspelled = await client.callTool({ + name: "analyze_function", + arguments: { + procedure: "0x1", + collection_offset: { commentz: 1 }, + }, + }); + expect(nestedMisspelled).toMatchObject({ + isError: true, + structuredContent: { + error: { + details: { + issues: [ + { + path: ["collection_offset", "commentz"], + reason: "unknown_argument", + }, + ], + }, + }, + }, + }); const bounded = await client.callTool({ name: "trace_feature", arguments: { query: "needle", max_operations: 101 },