快速结论:在 macOS 上跑 MCP Python SDK 测试套件时,深度嵌套请求体的用例会被判定为 INVALID_REQUEST(-32600),而测试期望 PARSE_ERROR(-32700)。核心原因通常不是 macOS 本身,而是 CPython 3.14 对深层 JSON 的解析行为发生了变化,优先排查 Python 版本而不是操作系统。
适用环境:MCP Python SDK;观察到于 GitHub macos-latest runner 与真实 macOS 26.5.1 arm64(M 系列)机器;Python 3.12.13 测试通过,Python 3.14.6 测试失败;同一提交(3a6f299 / 6affe5c)在 Ubuntu 与 Windows 上通过。CI 当时只跑 Ubuntu 和 Windows。
最快修复方案:暂无确认的一步修复方案。Issue 中给出的修复方向是改测试而非改服务端:要么让测试对版本敏感(≤3.13 期望 PARSE_ERROR,3.14+ 期望 INVALID_REQUEST),要么把“崩溃防护”断言改成在所有版本都无法解析的输入(例如 100k 层嵌套但结尾被截断,任何解释器下都不是合法 JSON),并单独断言“可解析但结构不对”的用例返回 INVALID_REQUEST。
注意事项:上述修复方向是 Issue 评论中提出的建议,尚未确认已合并;添加 macos-latest 到 CI 矩阵被指出是“方向搞错了”,因为分歧点在 stdlib json 而非操作系统,把 3.14 加入现有 Linux 矩阵同样能覆盖该问题(评论者只在本地验证了 stdlib 分歧,未在 Linux 上跑完整 server 测试)。
问题场景
运行 MCP Python SDK 的服务端测试套件时触发,具体用例是 tests/server/test_streamable_http_modern.py::test_modern_post_with_deeply_nested_body_is_parse_error_not_a_crash。该用例向 streamable HTTP 端点 POST 一个深度嵌套(约 100k 层)的 JSON 请求体,用于验证解析期间的 RecursionError 被正确归类为 parse error 而不是导致崩溃。在 Ubuntu 和 Windows 上通过,在 macOS 上失败。
报错原文
FAILED tests/server/test_streamable_http_modern.py::test_modern_post_with_deeply_nested_body_is_parse_error_not_a_crash
> assert response.json()["error"]["code"] == PARSE_ERROR
E assert -32600 == -32700
原因分析
最可能的原因是 CPython 版本差异,而不是操作系统差异。测试假设“深度嵌套会让 json.loads 抛出 RecursionError”,但评论中的实测表明这个前提在 3.14 已经不成立:
body = b"[" * 100_000 + b"]" * 100_000
# 3.12: json.loads raises RecursionError → caught at _streamable_http_modern.py:403 → PARSE_ERROR (-32700)
# 3.14: json.loads SUCCEEDS (returns a 100k-deep list)
# → JSONRPCRequest.model_validate(list) → ValidationError → _INVALID_BODY (L207, INVALID_REQUEST, -32600)
也就是说,在 3.14 上这个请求体是“合法 JSON 但不是合法 JSON-RPC 请求”,返回 INVALID_REQUEST 在规范上是正确的;失败路径根本不会走到 PARSE_ERROR 分支。评论者还将两个环节单独验证:pydantic_core.from_json(2.41.5)在 3.12 与 3.14 上行为一致(同样抛 ValueError),分歧只出现在 stdlib json.loads。因此服务端在 3.14 上表现正常(结构化 400、无崩溃),需要维护的是测试的前提。
环境排查
- Python 版本:重点确认是否为 3.14;Issue 中 3.12.13 通过、3.14.6 失败。
- 操作系统:macOS 26.5.1 arm64(M 系列)已复现;Ubuntu、Windows 通过。但结合上面的分析,OS 可能是干扰项。
- MCP Python SDK 提交版本:3a6f299、6affe5c。
- pydantic_core 版本:2.41.5(该版本下
from_json在 3.12/3.14 行为一致)。 - CI 矩阵:当时只含 Ubuntu 和 Windows,未覆盖 macOS 与 3.14。
解决步骤
- 先在同一台机器上切换 Python 版本复现:用 3.12.13 跑该用例应通过,用 3.14.6 跑应失败并返回 -32600,以确认是解释器版本而非平台问题。
- 单独验证 stdlib
json.loads对约 100k 层嵌套输入的行为:3.12 抛 RecursionError,3.14 成功返回深层列表。 - 确认服务端行为本身可接受:3.14 下返回结构化 400 且不崩溃,此时 INVALID_REQUEST 是符合规范的响应,无需修改服务端逻辑。
- 按 Issue 评论建议修改测试(可优先尝试):方案一,让断言版本敏感(≤3.13 期望 PARSE_ERROR,3.14+ 期望 INVALID_REQUEST);方案二,保留崩溃防护意图,把输入换成在所有版本都无法解析的形式(如 100k 层嵌套且结尾被截断),并单独断言“可解析但结构错误”的用例返回 INVALID_REQUEST。
- 考虑把 Python 3.14 加入现有 Linux CI 矩阵,而不仅是添加
macos-latest,以便稳定覆盖该分歧。
验证方法
在目标 Python 版本上重新运行该用例(评论中使用的命令形式为 uv run --frozen pytest tests/server/test_streamable_http_modern.py::test_modern_post_with_deeply_nested_body_is_parse_error_not_a_crash):如果测试前提已按解释器版本调整,3.12 与 3.14 应各自按预期断言通过;同时确认 POST 响应状态码均为 400 且服务端不崩溃。
参考来源
modelcontextprotocol/python-sdk #3146
AI 工具推荐
想把多个 AI 模型放在一个入口?
GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。
推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。
这个方案解决了吗?
可以继续搜索完整报错,或查看同一工具的其他排查指南。
![[Bug] Codex heterogeneous agent loses session continuity every turn (sessionId missing from stream_start, regression of #16855)](https://www.chat-gpts.plus/wp-content/uploads/2026/10/20231-3455eac7-768x403.jpg)

