1. 概览
一句话总结:协议从”有状态、靠长连接”变成”无状态、靠 HTTP 请求”。
2026 年 7 月 28 日,MCP 发布了算得上”有史以来最大”的一次规范修订。
同一时间,官方四套 Tier 1 SDK(TypeScript、Python、Go、C#)同步更新。
MCP SDK 月下载量已突破 4 亿(TS/Python 累计超 20 亿),部署服务器过万;
但新规范生态跟进极慢,抽样 1470+ 公开服务器中完全合规的仅 2 个,尚未出现全面切换。
2. 变更的初衷和重点
2.1 为什么改
MCP 2024 年诞生时,本质上只是为单机笔记本设计的协议:
- 一个客户端、一个服务器、一条 stdio 管道、一个与进程同生死的长连接会话(Session)。
- 对本地单机调用而言,这个设计极其精准且够用。
但当它被推向生产环境时,企业不得不为这套“本地模型”付出四笔沉重代价:
- Serverless 适配瘫痪:旧协议强依赖长连接和 Session,而 Serverless(AWS Lambda、Cloud Run、Cloudflare Workers)没有常驻进程,在物理层面就无法运行。
- 架构被迫退回十年前:因为状态绑定在特定实例上,水平扩展只能依靠 Sticky Session(粘性路由)或 Redis 存 Session。一个普通的 Web 服务,被迫重新处理长连接状态同步。
- 网关限流与审计失效:所有操作共享同一个 HTTP 管道,网关在 HTTP 层无法感知具体行为。想区分“调用工具”还是“获取列表”,只能拆解 JSON-RPC Body,效率与安全双重受损。
- 长任务与主动交互死锁:服务器要中途请求用户确认或等待模型补全,只能靠死挂着的 SSE 流;长耗时任务同步死等,极易引发超时断开。
正如 MCP 创建者之一 David Soria Parra 所言:“这次改动的核心,就是把状态从服务器挪到线上(Wire)去。”
无状态化之后,服务器不再依赖 Redis 和粘性路由,
挂在一台最普通的轮询负载均衡(Round-Robin Load Balancer)后面即可轻松横向扩展。
2.2 改了什么
8 个核心变更
| # | 变更 | 落地的 SEP | 一句话影响 |
|---|---|---|---|
| 1 | 移除协议级 Session、Mcp-Session-Id | SEP-2567 | 服务器不再”记住”你,需要跨调用的状态用显式句柄 |
| 2 | 移除 initialize 握手,身份装进 _meta | SEP-2575 | 每个请求自带协议版本、客户端信息,不再有”初始化了吗”这个分支 |
| 3 | 新增 server/discover RPC | SEP-2575 | 客户端可以随时探测服务器能力,替代握手时的一次性声明 |
| 4 | 路由信息放进 HTTP Header(Mcp-Method 等) | SEP-2243 | 网关不拆包就能路由、限流、审计 |
| 5 | 列表接口加 ttlMs + cacheScope 缓存 | SEP-2549 | 无状态后列表天然跨连接一致,客户端可按 Cache-Control 思路缓存 |
| 6 | 服务器主动交互改为 Multi Round-Trip(MRTR) | SEP-2322 | 服务器返回”我需要输入”,客户端收集后重发原请求,不用占着连接 |
| 7 | MCP Apps(沙箱 UI);Tasks 转正 | SEP-1865 / SEP-2663 | 工具能吐可交互界面;长任务改轮询 + 进度更新 |
| 8 | 授权加固;Roots/Sampling/Logging 弃用 | SEP-2468 / SEP-2577 | iss 参数必须校验;DCR 迁移到 CIMD;弃用功能最少保留 12 个月 |
其中 1、2、5、6 是变动最大的四条,后面第 3 节看细节。
2.3 一块基石:SEP-2596 生命周期政策
这轮修订先立规矩,再改协议。SEP-2596 给功能定义了 Active → Deprecated → Removed 三态,并承诺最少 12 个月弃用窗口(安全问题可缩短到 90 天)。也就是说,今天标了废弃的功能,至少一年内不会消失。这是官方对”别逼大家一夜迁移”的制度化承诺。
3. 新老详细对比
3.1 协议核心
| 维度 | 老版(2025 及更早) | 新版(2026-07-28) |
|---|---|---|
| 状态模型 | 有状态:长连接 + Session(Mcp-Session-Id) | 无状态:请求/响应解耦,状态由显式句柄承载(类似数据库游标、S3 upload_id) |
| 初始化 | initialize / initialized 握手 | 无握手;server/discover 发布能力;身份进 _meta |
| 客户端身份 | 握手时一次性声明 | 每个请求的 _meta 都带:io.modelcontextprotocol/clientInfo |
| 负载均衡 | 需要粘性路由 + 共享会话存储(Redis) | 普通轮询即可,实例重启对客户端透明 |
| 路由/限流 | 网关需解析 JSON-RPC Body | HTTP Header(Mcp-Method、Mcp-Name),网关零拆包 |
| 服务器主动交互 | 长期 SSE 流(采样、elicitation) | MRTR:返回 resultType: "input_required",客户端收集输入后重发原请求 |
| 列表缓存 | 无协议级缓存,靠 SSE 推送变更 | tools/list 等返回 ttlMs + cacheScope(public/private) |
| 取消通知 | SSE notifications/cancelled | 关闭该请求对应的 SSE 响应流 |
| 幂等/恢复 | 断线重连续会话 | 无会话可续;状态靠显式句柄,任意实例可接管 |
3.2 一个典型请求,前后对比
老版,身份信息只在握手时给过一次:
1 | // initialize 请求(仅此一次) |
新版,每个请求都是完整的,身份跟着请求走:
1 | { |
注意 _meta 里的 key 用了反域名命名空间(io.modelcontextprotocol/...),这是新规范的扩展机制反哺进了核心,后续所有扩展字段都会沿用这个习惯。
3.3 服务器主动交互:SSE 流 vs 多轮往返
老模型:服务器要中途要东西(用户确认、模型补全),就通过挂着的 SSE 流反向发请求。这要求连接始终钉在同一台实例上。
新模型:服务器返回一个”中间结果”,不再等输入。
1 | // 服务器第一次响应:要求输入 |
客户端(或模型)收集好输入后,带上 requestState 重发原请求:
1 | { |
因为状态随请求走,重试打到哪台实例都无所谓。requestState 是安全边界:它对客户端不透明但不可信,客户端可能篡改后再丢回来,必须签名或加密,绝不要在线上传裸的内部状态然后当场信任。
3.4 能力与扩展
| 维度 | 老版 | 新版 |
|---|---|---|
| 富交互 UI | 无标准 | MCP Apps:工具返回沙箱内 HTML/UI 模板,用户在对话框里直接交互 |
| 长任务 | 同步阻塞式结果 | tasks/get 轮询 + tasks/update 进度更新;tasks/list 已删除;服务器可主动返回任务句柄 |
| 采样(Sampling) | 服务器向模型要补全 | 协议级弃用(SEP-2577),由 MRTR 模式替代 |
| Roots | 客户端向服务器暴露本地路径 | 弃用(客户端支持度一直很低) |
| Logging | session 级 logging/setLevel | 改为每请求的 logLevel |
| 授权 | Dynamic Client Registration | iss 参数校验(RFC 9207)+ Client ID Metadata Documents(CIMD) |
4. 参考资料
- The 2026-07-28 Specification – Model Context Protocol Blog
- Protocol versions(era 对比矩阵与 API)– TypeScript SDK 文档
- MCP Goes Stateless: What the Spec Breaks in Your Server(迁移指南)– Code With Seb
- Bringing MCP 2026-07-28 to Claude – Claude Blog
- SEP-2567: Sessionless MCP · SEP-2596: Spec feature lifecycle and deprecation
- Specification draft: versioning(兼容矩阵)
- We probed all 1,472 public MCP servers. Two pass – Web After AI
- MCP 2026-07-28: what the stateless core removes – PacketNebula
- Bringing New Enterprise-Ready MCP Spec Brings New Security Challenges – SecurityWeek
- Scaling AI Agent Infrastructure with the MCP Stateless updates – Google Developers Blog