技术 · 熟练
MCP 换了协议,你的 server 哪天连不上?
不是「要不要升」,是「哪几处改动会在下一次请求上炸」
2026-07-28 这版 MCP 是它 2024 年立项以来最大的一次改写:把「先握手、记住会话、粘在同一台机器上」整套拿掉,改成「每个请求自带身份、落到哪台都一样」。好处很直接 —— 原来必须做粘性会话、共享会话存储、网关深包检测的远端 server,现在可以直接挂在普通轮询负载均衡后面。代价是有三处改动不会给你缓冲期:错码、schema 解析、以及解析器假定的结构。这一页做的就是先分清「弃用」和「破坏性变更」——弃用的三项有 12 个月窗口,可以先记着;破坏性的那几处必须现在就改。接着按四步动作走:升 SDK → 删粘性依赖 → 改两处解析 → 给工具清单设一个有效期。关键动作只有一个:把「按字面匹配旧错码」的地方先找出来,那是最容易静默出错的一处。
方法 · 一图看懂
1
先分清「弃用」和「破坏性变更」 — 弃用三项(Roots / Sampling / Logging)有 ≥12 个月窗口,可以先记不用马上动;破坏性变更没有窗口,必须现在就改
2
改两处解析 — 资源缺失的错误码由 MCP 自定义 `-32002` 改为 JSON-RPC 标准 `-32602`;`inputSchema` 现在支持完整 JSON Schema 2020-12(`oneOf` / `anyOf` / `$ref`)
3
去掉会话粘性,换成两个请求头 — 不再有 `initialize` 握手与 `Mcp-Session-Id`;每个请求带 `MCP-Protocol-Version` 与 `Mcp-Method`
4
给 `tools/list` 设一个 `ttlMs` — 工具清单不常变就设一个宽松值,客户端在有效期内不用每轮重新发现工具
5
把长任务挪到 Tasks 扩展 — 小时级的批处理 / 长编码不再靠挂住一条 HTTP 连接,改用 task 句柄驱动(`tasks/get` / `tasks/update` / `tasks/cancel`)
原理 · 为什么有效
无状态改写的关键不是「少了一个握手」,是「每个请求自带全部身份信息」。旧版要先用 `initialize` 换一个 `Mcp-Session-Id`、之后每个请求带它,服务端就得把会话记住、还得保证同一个会话始终落在同一台实例上 —— 于是负载均衡要配粘性、会话要放共享存储、网关要拆包看会话 ID。新版把协议版本与客户端身份放进 `_meta`、把方法与工具名放进 `Mcp-Method` / `Mcp-Name` HTTP 头,任何一台实例都能独立处理任何一条请求,前提是那三样「为了记住会话而加的东西」已经不在了。同理,`ttlMs` 与 `cacheScope` 解决的是另一半成本:客户端每轮重新拉一次工具清单本来纯属浪费。
适用场景
适用:自己写或维护 MCP server 的人 · 把 MCP 服务部署在负载均衡 / Kubernetes 上的人 · 同时接多个 MCP 客户端、想保证兼容的人 · 用 MCP 跑多小时级自动化任务的人。
不适用:只用服务商自托管的官方 server、自己不部署的人 —— 那条路上这版改动由服务商消化,你只需要确认客户端支持新协议版本即可。
自测 · 5 问
我能不能列出自己接的 MCP server,各是自托管还是服务商托管?
我的 server 代码里有没有人在按字面匹配 `-32002` 这个错误码?
我的 `inputSchema` 解析器是不是假定扁平结构(只读 `properties` 第一层)?
我的 MCP 服务在负载均衡 / Kubernetes 上是不是配了 sessionAffinity 或共享会话存储?
我有没有多小时级的工具调用还在靠挂住一条 HTTP 连接?
怎么上手 · 验证步骤
四步,按顺序做:① 把 SDK 升到实现 2026-07-28 的版本(TypeScript 与 Python 是 Tier 1,先支持;Go / C# 随后)② 删掉所有为了会话粘性加的东西 —— sessionAffinity 配置、Redis 会话存储、按会话 ID 做的路由 ③ 改两处解析 —— 错误码从 `-32002` 改 `-32602`,schema 解析按 JSON Schema 2020-12 放宽 ④ 在 `tools/list` 响应里给一个 `ttlMs`(工具清单稳定就设宽松值)。
改完先跑一次最小验证:用两个不同实例轮询同一个 server,连发三次 `tools/list` 与一次「故意请求一个不存在的资源」。判据是两件事同时成立 —— 三次都成功(说明会话粘性真的去掉了),且缺资源那一次报的是 `-32602`(说明错码真的改了)。任一条不成立,就说明还有残留没清干净。