快速结论:当使用基于 MCP Python SDK 构建的客户端连接严格校验 JSON-RPC 参数的服务器(如 Meta Ads MCP)时,SDK 会在每个请求的 params 里无条件附带空的 _meta:{},导致服务器返回 HTTP 400。优先排查客户端发出的请求体中是否携带了空的 _meta 字段。
适用环境:MCP Python SDK(current main,涉及 src/mcp/shared/jsonrpc_dispatcher.py);Python 3.12;受影响的服务端为 Meta hosted Ads MCP(https://mcp.facebook.com/ads)。
最快修复方案:升级到包含 PR #3628 的 SDK 版本,该版本已按报告中的建议修改为仅在 _meta 非空时才发送该字段。
注意事项:该修复未在真实 Meta Ads 端点上实际验证过,如果升级后仍无法连接,需要另开新 Issue。修复仅针对空 _meta 的发送逻辑,不涉及更广泛的重构。若自行打补丁,需确保在 trace context 注入之后再判断 _meta 是否为空,并保留调用方传入的非空 metadata 和注入的 progressToken。
问题场景
用户使用基于 MCP Python SDK 构建的客户端(下游报告来自 Hermes Agent)连接需要严格校验 JSON-RPC 参数的 MCP 服务器,例如 Meta hosted Ads MCP(https://mcp.facebook.com/ads)。在 initialize 阶段即被服务器拒绝,导致该服务器从所有基于此 SDK 构建的客户端都无法访问。
报错原文
HTTP 400
-32602 "_meta for Request must be a dict or null"
说明:服务端返回 HTTP 400,错误码 -32602,提示信息为 _meta for Request must be a dict or null。需要注意的是,_meta: null 同样会被拒绝,该字段必须完全不存在。
原因分析
最可能的原因是 JSONRPCDispatcher.send_raw_request 无条件地把 _meta 附加到 params 上。当没有设置 progress 回调、且 otel tracer 为 no-op(默认情况)时,out_meta 保持为空字典 {},于是每个请求都会携带 _meta: {} 上线。严格校验的服务器(如 Meta Ads MCP)会因此拒绝请求。相比之下,Meta 文档中提到的其他 MCP 客户端(Claude Code、ChatGPT)不会发送空的 _meta,因此可以正常连接。这是协议兼容性 bug,而非安全问题。
环境排查
- 确认 MCP SDK 版本或所基于的 commit,重点检查
src/mcp/shared/jsonrpc_dispatcher.py中send_raw_request的逻辑。 - 确认 Python 版本(报告中为 3.12)。
- 确认是否设置了 progress 回调,以及 otel tracer 是否为 no-op(默认)。
- 确认目标服务端是否为严格校验的 MCP 服务器(如 Meta hosted Ads MCP)。
- 用 curl 对真实服务端做最小复现:携带
_meta:{}时返回 400,不带时返回 200。
解决步骤
- 升级到包含 PR #3628 的 SDK 版本。该 PR 采用了报告中的修复思路:
_meta仅在非空时才被发送。 - 如果暂无法升级,可优先尝试按报告中的建议在本地打补丁,将无条件赋值改为条件发送,例如仅在
out_meta非空时写入out_params["_meta"],否则从out_params中删除_meta。 - 补丁位置应放在
inject_trace_context(out_meta)之后,这样真实 trace context 仍会被发送。 - 确保补丁不修改调用方传入的原始 params,并保留非空的调用方 metadata 与注入的
progressToken。 - 若请求本身没有任何 params(如
ping、tools/list),修复后也不应再带出空的params成员,以保持 v1 发送的形态。
验证方法
检查客户端发出的 JSON-RPC 请求体:在无 progress 回调、tracer 为 no-op 的情况下,请求中不应再出现 _meta:{},也不应出现 _meta:null。可用 curl 对目标服务器复现:不带 _meta 时应返回 200,携带空 _meta 时应返回 400,以此确认差异。最终确认方式为客户端能否成功完成 initialize。由于该修复未在真实 Meta Ads 端点上验证过,若仍被拒绝,需另开新 Issue。
参考来源
modelcontextprotocol/python-sdk #3473
相关 PR:#3474(因 missing-issue-link 策略被自动关闭)、#3628(已合并修复)。
AI 工具推荐
想把多个 AI 模型放在一个入口?
GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。
推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。
这个方案解决了吗?
可以继续搜索完整报错,或查看同一工具的其他排查指南。

![[Bug]: s3_v2 async 500/503 retries are bypassed by HTTPStatusError](https://www.chat-gpts.plus/wp-content/uploads/2026/10/42868-cdeacc24-768x403.jpg)
![[Bug]: timestamp_granularities=["segment", "word"] only returns the last granularity for Whisper](https://www.chat-gpts.plus/wp-content/uploads/2026/10/35937-6543e9b1-768x403.jpg)