快速结论:当 MCP Streamable HTTP 客户端携带旧 Mcp-Session-Id 发请求、而服务端因重启或会话超时返回 404 时,客户端会报 Session terminated 并把传输层永久置为不可用,而不是按规范重新初始化。优先排查服务端是否发生过重启、部署切换或空闲超时,以及客户端是否使用旧 session id 继续请求。
适用环境:Issue 已确认可复现的环境为 mcp 1.28.1 / Python 3.11.15,以及 mcp 2.2.0 / Python 3.14.7;报告者最初在 mcp 1.28.1 / Python 3.11 上遇到。仓库标签包含 bug、v2、v1。
最快修复方案:暂无确认的一步修复方案。该 Issue 已被关闭为重复问题,跟踪链接为 modelcontextprotocol/python-sdk #1676,尚未在本 Issue 中合入修复。
注意事项:Issue 评论中提到的修复分支仅限 src/mcp/client/streamable_http.py,属于可优先尝试的参考方案,但未在本 Issue 中合并;如果 session id 由调用方通过自定义 header 传入,恢复行为可能不生效。
问题场景
使用 MCP Python SDK 的 Streamable HTTP 客户端连接托管 MCP 服务端时触发。典型场景包括:服务端正常部署重启、进程重启后不再认识旧 session id、或者 SDK 服务端因 session_idle_timeout(默认 30 分钟)移除空闲会话。此时客户端如果继续使用旧 Mcp-Session-Id 发起请求,服务端会返回 HTTP 404;客户端没有丢弃旧 session id,也没有重新发送 InitializeRequest,而是直接把错误暴露给上层,并让传输层保持不可用。
报错原文
Streamable HTTP client treats 404 as terminal instead of re-initializing, as the spec requires
Session terminated
{"error": {"code": -32600, "message": "Session not found"}}
原因分析
最可能的原因是 StreamableHTTPTransport 对 404 的处理逻辑不完整。在 src/mcp/client/streamable_http.py 中,收到 404 后会调用 _send_session_terminated_error,发送 JSONRPCError(code=32600, message="Session terminated") 并返回;代码中没有重新初始化路径,已存储的 session id 不会被丢弃,也不会自动发送新的 InitializeRequest,失败的请求也不会被重试。因此服务端一旦返回 404,客户端后续请求会继续携带旧 session id,持续失败。
环境排查
- 确认
mcp版本:已知受影响版本包括 1.28.1 和 2.2.0。 - 确认 Python 版本:已复现环境包括 Python 3.11.15 和 Python 3.14.7。
- 确认服务端是否重启过、是否发生部署切换,或客户端是否空闲超过
session_idle_timeout(默认 30 分钟)。 - 确认失败请求是否携带旧的
Mcp-Session-Id,以及客户端在 404 后是否没有发送新的initialize。 - 确认 session id 来源:如果由调用方通过自定义 header 提供,Issue 中的修复思路不保证恢复行为。
解决步骤
- 先确认服务端返回 404 的原因:是重启、部署切换,还是空闲超时导致 session 被移除。
- 检查客户端日志中是否出现
Session terminated,并确认后续请求是否仍在使用旧 session id。 - 抓取传输层请求序列,确认 404 之后是否缺少自动
initialize;Issue 中复现显示 outbound methods 只有连续的tools/list,没有initialize。 - 如需推进修复,可参考 Issue 评论中的方案:在携带 session id 的请求收到 404 后,丢弃旧 session id,重新执行初始化握手,并只重试原请求一次;如果重试仍为 404 或初始化失败,再正常暴露错误。
- 并发请求同时命中旧 session 时,需要锁和状态检查,确保只进行一次重新初始化;GET stream 也需要切换到新 session,旧 stream 停止重连。
- 该 Issue 已被关闭为 #1676 的重复问题,建议跟踪 #1676 或对应修复 PR 的合入状态。
验证方法
复现验证时,可以模拟服务端重启或切换 session manager,使携带旧 session id 的请求返回 404;修复生效后,客户端应在 404 后自动发送新的 initialize,存储新的 session id,并重试原请求一次。Issue 评论中新增的测试覆盖了真实服务端重启后的恢复、并发请求命中过期 session、恢复后第二次 404、重新初始化失败以及 GET stream 切换到新 session;这些测试在未修复前全部失败。
参考来源
modelcontextprotocol/python-sdk #3556
AI 工具推荐
想把多个 AI 模型放在一个入口?
GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。
推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。
这个方案解决了吗?
可以继续搜索完整报错,或查看同一工具的其他排查指南。


![RuntimeError: [json.exception.type_error.302] type must be number, but is number](https://www.chat-gpts.plus/wp-content/uploads/2026/10/1251-6c29e56c-768x403.jpg)