modelcontextprotocol / modelcontextprotocol/python-sdk
Mcp-Name accepts an orphan header, while Mcp-Param-* rejects it as a routing spoof
还没有人认领这个 Issue。
- 主要语言
- Python
- 星标
- 24.3k
- 派生
- 4k
- 平均合并
- 1 天 1 小时
- 30 天内合并 PR
- 31
描述
What
validate_mcp_param_headers rejects an orphan Mcp-Param-* header, one present when the body argument is absent or null. classify_inbound_request accepts an orphan Mcp-Name header.
The Mcp-Param-* posture is deliberate and documented, in tests/shared/test_inbound.py:
"""SDK-defined posture on a spec gap: an orphan header is the routing-spoof case; go rejects too, ts skips."""
The Mcp-Name path has no equivalent branch. src/mcp/shared/inbound.py, line 447 on main:
body_value = cast("Mapping[str, Any]", body["params"]).get(name_key)
if body_value is not None and decode_header_value(headers.get(MCP_NAME_HEADER)) != body_value:
When body_value is None the whole check is skipped, including the case where a header claims a name.
Reproducer
from mcp.shared.inbound import (
MCP_METHOD_HEADER, MCP_NAME_HEADER, MCP_PROTOCOL_VERSION_HEADER,
InboundModernRoute, classify_inbound_request,
)
V = "2026-07-28"
body = {"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {
"arguments": {},
"_meta": {"io.modelcontextprotocol/protocolVersion": V,
"io.modelcontextprotocol/clientCapabilities": {}}}}
result = classify_inbound_request(body, headers={
MCP_PROTOCOL_VERSION_HEADER: V,
MCP_METHOD_HEADER: "tools/call",
MCP_NAME_HEADER: "ping", # claims a tool the body never names
})
assert isinstance(result, InboundModernRoute) # passes today
Same shape for resources/read with uri.
Why this looks like an inconsistency rather than a decision
The existing Mcp-Name test covers a different case:
def test_header_rung_does_not_require_name_header_when_body_omits_the_named_param() -> None:
"""SDK-defined: ... the param's absence is INVALID_PARAMS later, not HEADER_MISMATCH here."""
matching_headers omits Mcp-Name when the body lacks the param, so this pins "body omits the param and no header is sent". That rationale reads correctly for that case: nobody asserted a name, so the defect is the missing param and INVALID_PARAMS is the right answer.
It does not obviously extend to a client that did assert one. There the header and body disagree, which is the condition the routing-spoof posture exists for, and Mcp-Name is the header an intermediary is most likely to route on, since it names the tool or resource rather than a secondary parameter.
To be clear about impact: the malformed request fails INVALID_PARAMS downstream either way, so nothing executes. The concrete cost is an intermediary routing or rate-limiting on a name the body never contained.
Ask
Is the Mcp-Param-* posture intended to apply to Mcp-Name? If so the fix mirrors the sibling branch, rejecting when body_value is None and the header is present, with a test alongside test_validate_mcp_param_headers_rejects_orphan_header_for_absent_or_null_argument.
If the asymmetry is intentional, a note in that test's docstring saying so would prevent the next reader drawing the same conclusion I did.
Happy to open the PR either way once you say which you would prefer.
AI disclosure per AI_POLICY: I directed this investigation and reviewed the result. The research and drafting were done by Claude Code, which found this while probing SEP-2243 handling with adversarial tests, having implemented the same validation in a TypeScript resource server. 87 probes against encode_header_value and decode_header_value found no defects there, including non-canonical base64, invalid UTF-8 and sentinel-literal collisions, so this is the only finding. Verified against main rather than the released 2.0.0 wheel.
贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
调研方向
从 src/mcp/shared/inbound.py 中 447 行附近的 classify_inbound_request 分支开始,然后阅读 tests/shared/test_inbound.py,尤其是 test_validate_mcp_param_headers_rejects_orphan_header_for_absent_or_null_argument 和现有的 Mcp-Name 测试。与维护者确认预期的处理方式;完成的标准是提供回归测试及相应的验证,或者提供一个解释这种有意不对称性的测试 docstring。
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- python
- 领域
- api, security
- Issue 类型
- 缺陷
- 难度
- 3/5
- 预计耗时
- 1-2 天
- 活跃度
- 冷清
- 描述清晰度
- 基本清楚
- 新手友好度
- 42/100