Reject an orphan Mcp-Name header when the body omits the named param - #3270
Reject an orphan Mcp-Name header when the body omits the named param#3270hamodywe wants to merge 1 commit into
Conversation
classify_inbound_request's Mcp-Name check only ran when the body carried the name-bearing method's param (name_key). When the body omitted it, a present Mcp-Name header went unvalidated entirely -- an intermediary or client could set it to claim a different tool/prompt/resource than the request body actually names, with no rejection. validate_mcp_param_headers already treats this shape -- a header present with no matching body value -- as a rejection for Mcp-Param-* headers, on the same reasoning: a conforming client never emits the header unless the body value is present, so a header with nothing to match against did not come from this request. Mcp-Name had no equivalent check. Mirrors that handling: when the named param is absent, an absent header still passes (the param's own absence is INVALID_PARAMS elsewhere, not this rung's concern), but a present header is now rejected HEADER_MISMATCH. Adds test_header_rung_rejects_orphan_name_header_when_body_omits_the_named_param, parametrized over all of NAME_BEARING_METHODS. Confirmed it fails against the unpatched code (reverting just inbound.py, keeping the test) and passes with the fix. AI assistance disclosure: I used Claude to help investigate this issue and implement/test the fix; I've reviewed the change and reasoning above and can answer questions about it. Fixes modelcontextprotocol#3269
|
Thanks for the contribution. This repository only keeps pull requests open when they're linked to an issue that a maintainer has assigned to the author — CONTRIBUTING.md explains why and how we work. This PR has been closed for now because you aren't currently assigned to #3269. If a maintainer would like this change as a PR from you, they'll assign you to #3269 and this PR will reopen automatically — there's nothing more you need to do. (If you opened the issue, this PR already shows up on its timeline.) There's no need to open a new PR — this one will be reopened. While it's closed, please push any updates as new commits rather than force-pushing, since GitHub can't reopen a PR whose branch has been rewritten. Maintainers: reopening this PR, removing the |
classify_inbound_request's Mcp-Name check only ran when the body carried the name-bearing method's param (name_key). When the body omitted it, a present Mcp-Name header went unvalidated entirely -- an intermediary or client could set it to claim a different tool/prompt/resource than the request body actually names, with no rejection.
validate_mcp_param_headers already treats this shape -- a header present with no matching body value -- as a rejection for Mcp-Param-* headers, on the same reasoning: a conforming client never emits the header unless the body value is present, so a header with nothing to match against did not come from this request. Mcp-Name had no equivalent check.
Mirrors that handling: when the named param is absent, an absent header still passes (the param's own absence is INVALID_PARAMS elsewhere, not this rung's concern), but a present header is now rejected HEADER_MISMATCH.
Adds test_header_rung_rejects_orphan_name_header_when_body_omits_the_named_param, parametrized over all of NAME_BEARING_METHODS. Confirmed it fails against the unpatched code (reverting just inbound.py, keeping the test) and passes with the fix.
AI assistance disclosure: I used Claude to help investigate this issue and implement/test the fix; I've reviewed the change and reasoning above and can answer questions about it.
Fixes #3269
Motivation and Context
How Has This Been Tested?
Breaking Changes
Types of changes
Checklist
Additional context