MCP 拒绝请求后会话仍在增长
Python MCP 返回拒绝响应,会话记录却继续增长。区分旧有状态路径与正常长连接,选择兼容的清理修复版本,并保留 Host 和认证检查。
MCP 服务返回了 400、406 或 421,客户端没有完成 initialize,服务端的会话记录和后台任务却越来越多。检查 Python SDK 的旧有状态 Streamable HTTP 路径:请求被拒绝,不一定意味着为它建立的临时会话也已清理。
这一表现涉及旧部署,包括已有故障反馈的 mcp 1.27.1、1.29.0,以及修复前的 2.x 实现。2.3.0 的会话管理代码已经在建立请求被拒绝、失败或取消后丢弃临时会话。不要仅凭某个 HTTP 状态码,就把同一根因套到所有 MCP 服务上。
找到的是未初始化会话,还是正常长连接
先在运行服务的同一个 Python 环境中确认安装版本:
python -m pip show mcp
随后对照服务日志和现有监控,确认错误请求是否没有携带 Mcp-Session-Id、是否没有成功初始化,以及拒绝响应后会话数是否持续增加。内部的 _server_instances 属于 SDK 实现细节,可以帮助检查相应版本的代码,不宜作为跨版本稳定接口。不要把会话 ID 或认证信息写进公开日志。
正常客户端的独立 GET 事件流、尚未结束的工具调用,本来就可能保留会话与任务。只看内存增长或字典大小,无法区分这些连接与没有客户端使用的残留记录。判断本问题需要把“建立请求已被拒绝”和“相应临时会话仍在存活”对应起来。
还要核对协议路径。2.x 中命名 2026-07-28 协议的请求使用无会话的现代处理器;旧握手协议或没有版本头的请求可能走兼容路径。stateless_http=True 也不保留同样的会话。认证中间件若在进入会话管理器之前就返回 401,则不能据此认定这里的残留缺陷。
修复应保留请求拒绝,补上会话清理
旧实现的问题在顺序:先注册 transport、启动后台会话任务,再让 transport 校验 Host、Accept、正文与 JSON-RPC 请求。后面的校验拒绝了请求,前面建立的状态却没有随之终止。
应选择包含相应清理修复、又与应用接口兼容的 SDK 版本。已核对的 2.3.0 实现会检查建立请求的响应状态;如果没有成功建立,便移除会话记录并终止 transport。现有应用仍在 1.x 时,应先核对迁移要求和所选发行版,不能把直接跨大版本升级当作所有部署的通用操作。
修复后的 Host、Origin 和认证检查仍要有效。把允许列表放宽、让原本的 421 请求变成成功请求,会改变访问边界,并没有验证临时会话清理。如果没有会话残留,问题只是 Invalid Host header,应另按Host 允许列表的检查方法处理。
2.3.0 的兼容会话还支持 session_idle_timeout 和 max_sessions。它们分别限制空闲时间和每个进程的会话数量,但不能替代建立失败后的清理;默认值与可用入口也不能照搬到旧版本。有效的 GET 流或正在回答的请求不应因为空闲超时被中途结束。
用拒绝请求和有效请求分别验收
在获准的测试环境中,用原先会失败的请求检查:响应仍然按预期被拒绝,完成清理后不再永久增加会话记录或遗留后台任务。再让真实客户端完成 initialize 和后续工具调用,确认正常会话仍可使用。
已删除或过期的会话 ID 返回 404 是另一种正常边界。不能用“所有请求都不再报错”作为成功标准,也不要为了消除残留而一律改成无状态模式;旧客户端需要的服务端请求和通知通道可能因此失去作用。


