MCP 现在无状态了吗?你自己的 MCP 服务器需要改什么
是的。从 2026-07-28 规范开始,MCP 在协议层已经是无状态的。initialize 握手与 Mcp-Session-Id 被移除。每个请求自行携带协议版本、客户端身份与能力,因此远程请求无需粘性路由,也能由任意健康实例处理。
但这里有一个关键限定:无状态 MCP 不等于无状态软件。购物篮、浏览器任务、审批流程与已付款订单仍可能需要持久状态。区别在于,这些状态必须在应用层显式建模、寻址与保护,而不能隐藏在 MCP 传输会话中。
本文只解决传输与迁移问题。如果你需要权限与租户隔离方案,请阅读企业级 MCP 授权架构。如果你想知道安全控制究竟应放在哪里,请继续阅读为什么 MCP 不是完整的安全边界。
需要迁移远程 MCP 服务器,同时避免破坏现有客户端?
规划 MCP 架构审查最直接的答案是什么?
MCP 2026-07-28 是一个由无状态、自包含请求组成的协议。协议状态消失了,应用状态仍然允许,而且经常不可缺少。
官方规范已把“无状态、自包含请求”和“按请求协商能力”列为基础协议特性。在 Streamable HTTP 中,每条消息都是一个新的 POST。响应可以是单个 JSON 对象,也可以是仅属于该请求的 SSE 流。旧版独立 GET 流、协议会话、Mcp-Session-Id 与 SSE 恢复机制都不属于本次修订。
MCP 2026-07-28 改了什么?
| 问题 | 2025-11-25 及更早版本 | 2026-07-28 |
|---|---|---|
| 启动流程 | initialize,然后发送 notifications/initialized | 不再握手;客户端可选调用 server/discover |
| 协议会话 | 服务器可以签发 Mcp-Session-Id | 没有协议会话,也没有会话 ID |
| 请求上下文 | 版本与能力只协商一次 | 版本、client info 与能力在每个请求的 _meta 中传递 |
| HTTP 路由 | 可能需要会话亲和或共享 session store | 任意实例都能处理自包含请求 |
| HTTP 元数据 | 网关经常需要解析 JSON body | MCP-Protocol-Version、Mcp-Method 与部分请求的 Mcp-Name 为必填 |
| 向客户端索取输入 | 服务器可以通过 SSE 发起请求 | 返回 input_required;客户端携带 inputResponses 与可选 requestState 重试 |
| 长时间任务 | 核心协议内的实验性 Tasks | 通过官方 Tasks 扩展与持久 task handle 完成 |
| 列表结果 | 变更通知与轮询 | 确定性顺序,并返回 ttlMs 与 cacheScope |
MCP 2026-07-28 官方 changelog列出了完整的 breaking changes,其中还包括新的 resultType、取消流恢复、支持 JSON Schema 2020-12、新错误码,以及对 Roots、Sampling、Logging 和旧 HTTP+SSE 的弃用计划。
无状态 MCP 服务器还能保存数据吗?
可以。它只是不能让后续请求依赖不可见的协议会话内存。
假设一个工具打开浏览器,另一个工具继续同一次自动化。第一次响应可以返回随机且不透明的 browser_id。客户端在下一次调用时带回这个 handle。服务器检查调用者与过期时间后,再从 Durable Object、数据库或其他存储中解析它。这个工作流有状态,但每个 MCP 请求仍然自包含。
- 单个请求:把状态保留在局部变量中,并直接返回最终结果。
- 连续几轮输入:在
input_required中返回受完整性保护的requestState,并将其绑定到认证主体、原始操作与过期时间。 - 长时间任务:使用MCP Tasks 扩展与持久
taskId。 - 业务实体:返回
order_id、basket_id或document_id等应用 handle,并在每次使用时重新授权。 - 持续变更通知:使用
subscriptions/listen。打开的 SSE 响应只属于该请求,并不是协议会话。
不要把 secret 或可修改的业务状态直接放进可读的 bearer handle。应优先使用不透明 ID,或者经过认证与加密的状态 token,并严格限制大小、audience 与有效期。
所有 MCP 服务器都需要迁移吗?
每个实现都应接受审计,但工作量不同。
| 当前服务器 | 可能需要的工作 | 优先级 |
|---|---|---|
| 本地 stdio,不依赖会话功能 | 升级 SDK、schema、按请求元数据与 discovery 行为 | 中 |
| 远程 Streamable HTTP,不存储会话 | 增加现代 wire contract、请求头校验、result type、缓存元数据与兼容测试 | 高 |
使用 Mcp-Session-Id、粘性路由或 session map | 把业务状态外置,建立 dual-era 路径,待客户端迁移后再移除会话基础设施 | 最高 |
| 旧 HTTP+SSE | 先迁移到 Streamable HTTP,再完成无状态切换 | 最高 |
| 依赖 Sampling、Roots 或协议 Logging | 这些功能已弃用,需要设计替代方案 | 高 |
服务器可以在运行时无状态,却仍使用旧协议。它也可以支持新无状态协议,同时保存应用数据。请分别审计网络协议行为与数据生命周期。
你自己的 MCP 服务器应当改什么?
- 清点隐藏的连接状态。搜索 session map、sticky cookie、
Mcp-Session-Id、跨请求复用的 transport、按连接变化的工具列表,以及 SSE event store。把每一项标记为协议状态、短期请求状态或持久业务状态。 - 实现现代 discovery。服务器必须支持
server/discover,并返回支持版本、能力、server info、instructions、ttlMs与cacheScope。不要用服务器自报信息做安全判断。 - 校验每个请求的元数据。在
_meta中要求版本与客户端数据。HTTP 请求还需要MCP-Protocol-Version、Mcp-Method,以及适用时的Mcp-Name。请求头与 body 不一致时,必须返回HeaderMismatch。 - 让结果符合新规范并可缓存。普通结果增加
resultType: "complete"。让tools/list保持确定顺序。尤其当授权会改变工具集合时,应正确设置ttlMs与cacheScope。 - 用显式 handle 代替隐式状态。Handle 必须难以猜测、绑定主体、限制权限且可撤销。修改操作必须幂等,避免断流重试造成重复扣款、发送或删除。
- 有计划地支持两个时代。Dual-era 服务器可以无状态处理现代请求,同时为旧客户端保留
initialize。隔离这条路径,监控使用量,并设定下线日期。 - 测试架构,而不只是 handler。在真实 round-robin 后把连续请求发送到不同实例。测试缺失与冲突请求头、不支持的版本、过期 handle、重放、取消、重试和跨租户访问。
Streamable HTTP 官方规范定义了请求头与 mismatch 行为。决定直接切换还是 dual-era 上线前,还应阅读版本与向后兼容矩阵。
我们对 Wavect 自己的 MCP 做了哪些修改?
2026 年 7 月 31 日,我们用同一份清单审查了自己的 Cloudflare Pages Function。由于不需要保留旧客户端,我们直接完成了切换。
- 进程与协议都已无状态:handler 没有内存 session map,现在只接受自包含的
2026-07-28请求。 - 业务状态已经显式化:commerce 工具使用 quote ID、order ID、access token 与 idempotency key,而不是传输会话。
- 现代 discovery 已上线:
server/discover返回支持版本、capabilities、server info、instructions 与缓存元数据。 - HTTP contract 已强制执行:请求必须携带
MCP-Protocol-Version、Mcp-Method,工具调用还必须携带Mcp-Name。服务器会校验请求头与 body 一致性,并显式验证 origin。 - 响应已使用 2026 结构:discovery、列表与工具调用都包含
resultType;确定性列表还包含准确的缓存元数据。 - 旧 lifecycle 已移除:
initialize、ping与notifications/initialized会返回 method not found,不再保留旧协议契约。
这说明“我们不保存 MCP session”并不是完整迁移结论。运行拓扑、协议版本和响应 schema 可能处于不同阶段。对我们的服务器而言,业务状态重构很小,wire contract、安全检查与 conformance test 才是主要工作。

"无状态 MCP 移除的是隐藏的传输内存,不是持久工作流。让状态显式、经过认证,并且能够安全重试。"
生产迁移应该如何上线?
- 记录现有客户端版本、transport、会话功能与错误率。
- 在改变生产流量前,为现代请求与结果结构增加 conformance test。
- 根据你对客户端的控制程度,部署 dual-era endpoint 或独立现代 endpoint。
- 先迁移内部与 canary 客户端,并强制连续调用落到不同实例。
- 监控版本错误、header mismatch、重试、延迟、重复副作用与授权失败。
- 发布客户端迁移日期与 rollback window。不要因为一次 SDK 测试成功就删除旧存储。
- 只有当遥测证明旧流量与会话依赖已经消失,才能移除粘性路由与 session store。
Cloudflare 在MCP SDK v2 迁移指南中说明了无状态 handler 与有会话功能的分阶段迁移。即使你使用其他 runtime,这种区分协议状态与应用状态的方法仍然有效。
选择 MCP 开发伙伴时应问什么?
- 生产服务器会支持哪些协议版本与客户端时代?
- 哪些状态只属于请求,哪些是持久数据,哪些仍依赖传输会话?
- Handle 如何绑定身份、tenant、操作与有效期?
- 支付、写入与外部副作用如何通过幂等性避免重复执行?
- 团队能否证明连续两个调用可以由不同实例完成?
- 网关与 origin 如何把 HTTP 请求头和 JSON body 互相校验?
- 哪些内容会缓存多久,私有工具列表是否可能进入共享缓存?
- 仍有哪些弃用功能,它们的替代方案是什么?
- 关闭旧路径需要哪些证据:遥测、客户端清单、rollback test 与下线日期?
如果方案只写“升级 SDK”,它还不完整。商业交付应包含状态清单、兼容决策、威胁模型、迁移测试、canary 证据与回滚计划。
常见问题
MCP 现在完全无状态吗?
2026-07-28 协议核心是无状态的。应用仍可通过显式 handle、storage、Tasks 与 request state 保存持久状态。
Streamable HTTP 还存在吗?
存在。它仍是标准远程 transport,但每条消息都是独立 POST,旧 GET stream 与协议会话已被移除。
还需要发送 initialize 吗?
现代请求不需要。请使用每次请求的元数据,并按需调用 server/discover。Dual-era 服务器仍可为旧客户端处理 initialize。
还需要 Redis 或 Durable Objects 吗?
MCP 协议会话不再需要。Job、订单、浏览器实例、锁、rate limit 与其他应用状态仍可能需要持久存储。
可以立刻移除 sticky session 吗?
只有现代流量已在不同实例之间通过测试,并且遥测确认受支持客户端不再依赖旧路径时才可以。
最终思考
MCP 已在协议扩展性真正需要的地方变为无状态:没有 initialize 生命周期,没有 Mcp-Session-Id,也不需要隐藏连接状态来理解请求。你的产品仍可有状态。请把状态放在显式、经过授权的 handle 后面;实现 discovery、必填请求头、现代结果结构与缓存语义;保留可监控的兼容路径;并在删除旧基础设施前,用 round-robin 证明迁移结果。