快速结论:当 MCP Python SDK 客户端在“尚未调用过 tools/list”的会话里直接发起 tools/call,而工具参数带有 x-mcp-header 注解时,客户端无法生成 Mcp-Param-* 请求头,服务端返回 -32020(HeaderMismatch),旧版本客户端不会重新列取工具也不会重试。优先确认 SDK 版本是否已包含重试修复(#3627),以及调用前是否已通过 list_tools() 取得工具 schema。
适用环境:Issue 中确认的复现环境为 Python SDK mcp 2.1.1,后续在 v2.2.0 标签上复查仍可复现;协议版本协商为 2026-07-28;客户端为 SDK 自带 Client + streamable_http_client,服务端为 SDK 自带 MCPServer(未涉及第三方服务端)。Issue 未提供操作系统、CUDA、显卡等信息,不作补充。
最快修复方案:暂无确认的一步修复方案(Issue 闭环时未给出单个开关或配置项)。可优先尝试:升级到包含 #3627 的 SDK 版本,使 Client.call_tool 在收到 -32020 后自动重新 tools/list 并重发一次;若无法升级,则在首次 call_tool 前显式调用一次 list_tools(),让客户端吸收 x-mcp-header 映射后再发起调用。
注意事项:#3627 只修复了重试这一半,且仅作用于 Client.call_tool,ClientSession.call_tool 仍然只发送一次;Issue 中提到的预加载入口(public pre-load API)与 _resolve_param_headers 返回空映射时的告警均未加入,因此每个新会话仍可能额外付出一次 tools/list 的往返开销。预加载说明在规范发布前已被移除(modelcontextprotocol/modelcontextprotocol#3071),若要新增需走新的公开 API 讨论。另外,若工具列表已吸收、服务端仍拒绝,则属于永久性不匹配,不应依赖自动重试。
问题场景
使用 MCP Python SDK 搭建客户端与服务端,服务端工具参数通过 Annotated[..., Field(json_schema_extra={"x-mcp-header": "owner"})] 声明为请求头参数。客户端新建 ClientSession 后未先调用 tools/list,直接对同一工具发起 tools/call。此时客户端没有该工具的 inputSchema,无法构造 Mcp-Param-owner 等请求头,服务端以 HTTP 400 返回 -32020 HeaderMismatch。对照组“先 list_tools() 再调用”可以成功返回结果,说明问题出在客户端未列取 schema 的路径上,而非工具定义本身。
报错原文
== a session that never listed ==
negotiated: 2026-07-28
MCPError code=-32020
message="Mcp-Param-owner header is missing but the request body's 'owner' argument is present"
== a session that listed first ==
result: [TextContent(type='text', text='fetched for octocat', ...)]
Client never retries after -32020 HeaderMismatch, and there is no public way to pre-load the x-mcp-header map (SEP-2243 client SHOULD/MAY both unimplemented)
原因分析
SEP-2243 对客户端提出两条要求:其一(SHOULD),当服务端因 Mcp-Param-* 头缺失或不匹配而拒绝请求时,客户端应调用 tools/list 获取最新 inputSchema,再带正确请求头重试原请求;其二(MAY),客户端可通过其他途径(如上一会话或配置)预加载工具定义,从而无需先调用 tools/list 即可发出请求头。
Issue 指出 SDK 两条都未实现:mcp/client/ 下没有任何代码读取 HEADER_MISMATCH,该错误只在服务端侧产生;ClientSession._resolve_param_headers 在缺少 schema 时静默返回 {};_x_mcp_header_maps 为私有属性,唯一写入方是 _absorb_tool_listing,应用层无法自行注入映射。由于 x-mcp-header 注解来自 tools/list 返回的工具 schema,未列取过工具的客户端在调用时无法计算请求头,这是静默空映射叠加“不重试”共同导致的失败。可能原因还包括服务端侧的注解校验缺失(见姊妹 Issue #3484),它在服务端侧放大了这一不匹配。
环境排查
- 确认
mcpSDK 版本:Issue 复现于 2.1.1,v2.2.0上复查仍存在;确认是否已包含 #3627 的重试修复。 - 确认协商协议版本是否为
2026-07-28(仅在协商到该版本时才会走 SEP-2243 相关路径)。 - 确认调用方是
Client.call_tool还是ClientSession.call_tool,后者不在 #3627 修复范围内。 - 确认业务代码是否在首次
call_tool前调用了list_tools()。 - 确认服务端工具参数是否带有
x-mcp-header注解,以及服务端是否对请求头与请求体做了严格校验。 - Issue 未提供操作系统、Python 版本、CUDA、显卡等信息,无需据此排查。
解决步骤
- 先核对复现条件:新建会话后不调用
list_tools(),直接call_tool带注解参数的工具,确认返回 HTTP 400 且错误码为-32020,错误信息提示某个Mcp-Param-*头缺失。 - 确认 SDK 版本是否已包含 #3627。若已包含,使用
Client.call_tool发起调用,客户端会在首次-32020后重新列取工具、重建请求头映射并重发一次;不要改用ClientSession.call_tool,它仍是单次发送。 - 若无法升级或使用的是
ClientSession.call_tool,可优先尝试在首次call_tool前显式执行一次list_tools(),触发_absorb_tool_listing吸收x-mcp-header映射,再正常调用。Issue 中“先列再调”的对照路径已验证可成功,但作为规避手段尚未在文档中正式推荐。 - 若工具列表已吸收、服务端仍返回
-32020,说明头值与服务端校验不一致,属于永久性不匹配,不要依赖自动重试;应对比客户端计算出的头映射与服务端期望值,必要时排查服务端注解校验(参见 #3484)。 - 若确实需要“无
list_tools直接带头发请求”的预加载能力,当前 SDK 未提供公开入口;Issue 中建议的构造参数或校验型 setter 尚未落地,可关注后续 Issue 或 PR,不要尝试直接写入私有属性_x_mcp_header_maps。
验证方法
在未预先列取工具的会话中,对带 x-mcp-header 注解的工具发起一次 call_tool:使用含 #3627 的 Client.call_tool 时,应能正常返回工具结果,而不再出现 MCPError code=-32020;服务端日志中应能看到一次 tools/list 与随后的重试调用,且重试仅发生一次。若升级后仍报同一错误,则应检查调用入口是否为 ClientSession.call_tool,或排查头值是否与服务端校验不符。
参考来源
modelcontextprotocol/python-sdk #3483
相关链接:修复 PR #3627、服务端姊妹 Issue #3484、Header parameters 文档。
AI 工具推荐
想把多个 AI 模型放在一个入口?
GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。
推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。
这个方案解决了吗?
可以继续搜索完整报错,或查看同一工具的其他排查指南。


