Repository navigation
fix(server): keep the Mcp-Param check on a tool with a number-typed header - #2960
Conversation
…eader #2762 makes the declaration scan report a tool as invalid when it puts `x-mcp-header` on a `number`-typed parameter, as the 2026-07-28 spec requires of clients. `createMcpHandler` compared the `Mcp-Param-*` headers of a `tools/call` with the body only when the scan was valid. So for such a tool the whole check went away, its valid string, integer and boolean parameters included: a call whose header disagrees with the body was answered 200 where 2.3.0 answers 400 with -32020. The scan now keeps walking after a `number` fault. When those are the only faults it returns the declarations next to the reason, and the handler checks whatever declarations the scan returns. The result is still invalid, so a client still drops the tool from `tools/list` and the server still warns when tools are listed. The server then checks exactly the calls 2.3.0 checks. The header of the number-typed parameter itself is still required and compared as a number. A tool with another fault as well was not checked in 2.3.0 and is not checked now. `registerTool` does not throw for such a tool, because that would stop a server at startup after an upgrade. Also here: one sentence in the 2026-07-28 migration page on the tool no longer being listed, a server test for the check, a client test that `listTools()` drops the tool (only a unit test of the scan covered #2762), and three comments in mcpParamHeaders.ts that no longer matched the code.
🦋 Changeset detectedLatest commit: fbdfbec The changes in this PR will be included in the next version bump. This PR includes changesets to release 6 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
@modelcontextprotocol/client
@modelcontextprotocol/codemod
@modelcontextprotocol/core
@modelcontextprotocol/server
@modelcontextprotocol/server-legacy
@modelcontextprotocol/express
@modelcontextprotocol/fastify
@modelcontextprotocol/hono
@modelcontextprotocol/node
commit: |
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012VRbFCp41otcScXE1YY3es
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012VRbFCp41otcScXE1YY3es
There was a problem hiding this comment.
I re-reviewed the latest push and found no bugs; the two docs follow-ups address the points I raised earlier, and the remaining question is a design call rather than a defect, so a maintainer look to confirm the intended client/server contract is still worthwhile.
What was reviewed:
- The reworded changeset against the code: the stdio carve-out matches the early return in client.ts:2557, and "a call that carries a value for a declared parameter" matches validateMcpParamHeaders skipping absent/null body values (mcpParamHeaders.ts:355).
- The scanner's early-return paths once more: a non-number fault still returns without declarations, so the handler gate at createMcpHandler.ts:833 only widens the check for number-only-invalid tools, as the changeset says.
- The remaining design point (server validates a spec-invalid declaration that an upgraded client will never mirror) is now stated in both the changeset and the migration guide, so it is a deliberate, documented choice for the owners to confirm.
Extended reasoning...
The change touches the shared x-mcp-header scanner in core-internal, the tools/call header gate in createMcpHandler, two tests, a changeset and a migration paragraph; the only new commit since my last review is a one-line changeset rewording. It touches request validation (400 / -32020 on Mcp-Param-* mismatch) but no auth, crypto or data-exposure surface. All paths are covered by the repository-wide CODEOWNERS team, and the PR embeds a cross-package behaviour decision (client excludes the tool, server keeps validating it) that a maintainer should confirm, so I deferred rather than approved despite finding no bugs.
Requested by Felix Weinberger · Slack thread
Follow-up to #2762.
Before: #2762 makes the declaration scan report a tool as invalid when it puts
x-mcp-headeron anumber-typed parameter.createMcpHandlercompared theMcp-Param-*headers with the body only when the scan was valid, so for such a tool the whole check went away, valid string, integer and boolean parameters included: atools/callwhose header disagrees with the body got 200 where released 2.3.0 answers 400 with-32020.After: The scan keeps walking after a
numberfault. When those are the tool's only faults it returns the declarations next to the reason, and the handler checks whatever declarations the scan returns. The result is still invalid, so clients still drop the tool fromtools/listand the server still warns;registerTooldoes not throw. Between an upgraded client and an upgraded server, a call by name of such a tool is answered 400 again, as against a 2.3.0 server; with #2762 alone it was 200. A tool with another fault as well was not checked in 2.3.0 and is not checked now.How it was verified: Against released 2.3.0 over 13 tool shapes and 68 request cases (status, error code, the header named in the error, whether the handler ran),
maintoday differs in 20 cases and this change in 0. The new server test fails without either source change (expected [200, …] to deeply equal [400, -32020, 'Mcp-Param-Region']); the new client test fails as soon asnumberis permitted again. core-internal, client and server suites pass; typecheck, ESLint, Prettier,sync-snippets --checkanddocs:checkare clean. Changeset:@modelcontextprotocol/serverpatch.🤖 Generated with Claude Code
https://claude.ai/code/session_012VRbFCp41otcScXE1YY3es
Generated by Claude Code