mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
3635 字
10 分钟
MCP 无状态化解读:把会话还给应用层
2026-08-01

7 月 28 日,MCP(Model Context Protocol)发了个让我盯着屏幕愣了几秒的大版本:把自己最核心的功能之一,协议级会话(session),整个删掉了。更反常识的是,我追了三天讨论,几乎所有人都在说删得好。这篇讲清无状态化(stateless)到底改了什么、为什么全网叫好、你的 server 要不要跟着改,末尾顺手检讨我 6 月旧文里一个已经失效的前提。

先交代消化过程:公告当天我把原文啃了两遍,之后几天泡在社区讨论里,又用官方 SDK 写了个最小 server 动手验证。这篇是消化完的产出,不追热点节奏,追确定性。

无状态化到底改了什么:一张对比表说清#

改动集中在传输层。按官方公告和规范文本的表述:传输层走向无状态,协议级 session 和 initialize 握手被移除,会话语义上移到应用层。翻译成人话:以前 client 连上 server 要先握手、领一个会话身份,之后每次调用都挂在这个会话上;现在这个环节没有了,每次请求自带全部信息,server 处理完就忘。

改版前的会话模型长什么样,值得复述一遍,它是后面所有讨论的地基。client 连上 server,第一件事不是干活,是 initialize 握手:互报版本、协商能力、领一个会话身份;之后的每次工具调用都挂在这个身份上,server 端为它留一份对应状态。这套模型在”一个 client 对一个 server”的本地场景没什么毛病,一旦 server 要上服务器、面向很多 client,就处处别扭。

什么没变也得说清,不然恐慌会传染。Client/Server 架构没变,Tools、Resources、Prompts 三类原语没变,工具定义用 JSON Schema 描述的惯例没变。MCP 还是那个 MCP,动的只是”会话归谁管”这一层。

维度改版前改版后
会话(session)协议级,server 端持有,请求绑定在会话上协议层移除,会话语义上移到应用层
initialize 握手连接建立后先协商能力,才能正式调用移除,请求即用
部署语义会话粘住实例,扩容要操心会话往哪搬请求自包含,打到任意实例等价
失败重试重试要顾及会话一致性换实例重发即可,前提是调用本身幂等

一句话概括这张表:改版前,会话是协议的财产;改版后,会话是应用的财产。 状态搬家这件事,我画成了图:

flowchart LR subgraph Before["改版前"] direction TB A["应用层<br>不用管会话"] --> B["协议层<br>session + initialize<br>状态锚在连接上"] end subgraph After["改版后"] direction TB C["应用层<br>自己管会话"] --> D["协议层<br>单次请求,无状态"] end Before -->|"状态上移"| After

从插件协议到 HTTP 级基础设施:无状态白送三样东西#

判断一个协议是”插件”还是”基础设施”,有个土办法:想象它的 server 要服务 100 万用户,运维半夜被告警叫醒时,手里有没有现成的家伙式。写 Web 后端的人都背过这堂入门课:想让服务能水平扩容(horizontal scaling),第一步就是把服务改成无状态。MCP 改版前把这套积累全浪费了:一个长在 HTTP 上的协议,却要求 server 记住每条连接的状态。

白送的第一样是负载均衡(load balancing)。 改版前一个会话必须粘在一个实例上,术语叫粘性会话(sticky session),扩容、滚动发版、实例宕机,每一样都得额外设计,做过老系统的人都懂,会话粘住了实例,连发个版都得挑深夜;改版后请求自包含,负载均衡器随便分发,落到哪个副本都一样。

第二样是重试。 以前请求失败不能随便换个实例重发,因为会话状态只活在原来那台机器的记忆里;现在失败就换一台重发,只要调用本身幂等(idempotent),调用方什么都不用多做。

第三样是网关缓存(gateway cache)。 像工具列表这种问一百遍答案都一样的请求,从此有了被网关拦下直接回缓存的想象空间。我两周前实测过 Coding Agent 的 token 账单,工具定义是每轮常驻前缀的大头之一,这类请求将来若真能在网关层缓存,取回路径会短一截。要说明这是间接推论,规范文本没承诺这种用法,但门确实开了。

三样加起来指向同一个结论:MCP 从”给 AI 应用装的插件协议”,变成了能按普通 Web 服务的方式部署、扩容、运维的东西。 一个月前 WebKit 官方推出 Safari MCP server,当时大家的观感是”官方下场示范”;现在协议把部署门槛又降了一截,这类官方 server 可以真的按基础设施的标准去做。

误区拆解:无状态等于丢了会话能力#

常见理解:session 都删了,MCP 是不是就不会话了?多轮任务里 server 每轮失忆,Agent 退回”每次重新自我介绍”的原始时代。这是这几天社区里的高频质疑,也是我刷到公告时的第一反应。

为何错:状态没有消失,只是搬家了。删掉的是”协议层替你管会话”这项默认服务,不是会话本身。类比就在 Web 里:HTTP 从出生那天起就是无状态的,购物车和登录态从来不是 HTTP 提供的,而是 Cookie、JWT 这些应用层机制几十年里长出来的分工:协议管单次请求,应用管跨请求状态。没有人因为 HTTP 无状态,就说 Web 做不了电商。JWT 那一代甚至把状态直接签进令牌里随身携带,和”每次请求自带全部信息”是同一个思路。

正确理解:无状态化是 MCP 在补这堂课:协议只负责把单次调用可靠送达,跨调用的上下文归应用层管。对 Agent 开发者,会话的落点反而更清楚了:客户端侧的对话历史、项目记忆文件(我写过 CLAUDE.md 使用指南),或者专门的外部存储。状态没有丢,只是从协议层收回到应用层,这是全文我最想让你带走的一句。

动手验证:一个最小无状态 MCP server#

光读公告不算消化,我抽了一个下午用官方 SDK 写了个最小 server,验证两件事:不做 initialize 握手,工具调用能不能直接跑通;两个进程轮流接请求,结果是否一致。先看改版前大家习惯的写法,问题就藏在这几行里:

# 改版前的典型写法(示意):会话状态长在 server 进程里
sessions: dict[str, dict] = {}
async def handle(session_id: str, request: dict):
sess = sessions.setdefault(session_id, {"history": []})
sess["history"].append(request) # 同一个会话必须路由回同一个进程
return do_something(sess) # 业务逻辑依赖这份进程内状态

这个进程内的 sessions 字典,就是无状态化要拆掉的东西。改写后的最小 server 如下。各家 SDK 对新规范的跟进还在进行中,下面是伪代码级示意,类名与导入路径以官方 SDK 文档为准,别直接抄:

# 最小无状态 MCP server(伪代码级,具体 API 以官方 SDK 文档为准)
# 验证目标:server 端不挂任何会话状态,同一请求打到哪个实例结果都一致
from mcp.server import Server # 导入路径以你所用 SDK 的文档为准
app = Server("word-counter")
TOOL_SCHEMA = {
"name": "count_words",
"description": "统计一段文本的词数",
"inputSchema": {
"type": "object",
"properties": {"text": {"type": "string"}},
"required": ["text"],
},
}
@app.list_tools() # 工具列表是纯函数:不依赖任何调用历史
async def list_tools():
return [TOOL_SCHEMA]
@app.call_tool() # 每次调用自包含:状态只在参数里
async def call_tool(name: str, arguments: dict):
if name != "count_words":
raise ValueError(f"unknown tool: {name}")
# 自查:函数体里读不到任何全局可变状态
return [{"type": "text", "text": str(len(arguments["text"].split()))}]
# 验证方法:同一份代码开两个进程,请求轮流打到两边
# 预期:不握手直接调用可通;两边返回完全一致

两个验证都过了。不握手直接调用,通;同一份代码开两个进程,请求轮流打到两边,返回完全一致;中途杀掉一个进程,后续请求换另一个照样答。进程变成了可丢弃的,这就是无状态最直白的含义。 昨天 Simon Willison 的解读发出来,我拿自己的验证结果对着读了一遍,思路能对上,这才敢动笔。

也交代一个卡点:第一版我差点把查询缓存挂回全局变量,手比脑子快,旧习惯还在。写无状态 server 最该提防的是自己的手指头,凡是 self. 后面跟着会变的东西,都值得多看一眼。

两个口径也要交代:我验证的是行为,不是性能和并发;SDK 对新规范的支持还在变动,你动手那天以当时的官方文档为准。

无状态的代价:长连接与有状态工具要多做的功#

叫好归叫好,代价必须摆上桌面。无状态化不是免费午餐,是责任转移:以前协议替你管的事,现在应用层自己做。

最直接的受影响方是长连接场景。流式输出、进度通知这类依赖”一条活着的连接”的体验,改版前有协议级会话兜底;改版后连接管理、断线后的续传,都上移到应用层自己实现,这类 server 的改造量是实打实的。Web 那边的参照很清楚:无状态是常态,长连接是特例,特例就得自己多花做功。

第二类是自带状态的工具,典型是有缓存的搜索 server。我 6 月设想过一类带查询缓存和增量索引的检索工具,那种进程内状态现在要么外置到专门存储,要么接受缓存随实例漂移、命中率下降。协议层会话本来就不该放重状态,这次改版等于把”别把状态藏进程里”从最佳实践升级成了硬约束。

你的 server 长什么样无状态化后的影响要不要额外做功
纯计算型:转格式、统计、单次查询几乎纯受益,扩容随便扩基本不用
自带进程内缓存的搜索型缓存随实例漂移,命中率可能掉要:状态外置到存储层
多轮依赖型:上一步输出喂下一步协议不再帮你传递中间状态要:应用层自己带上下文
长连接流式型会话兜底没了要:补连接管理与续传

诚实版结论:server 是纯函数式的,这次改版对你是纯利好;状态藏在进程里的,这次改版等于强制做一次架构体检,而这个体检反正躲不掉,早做早省心。

我的旧方案怎么办:记忆不该长在 server 端#

6 月底我写过 Agent 记忆架构全景,其中”MCP 与 RAG 的协同”一节画了张时序图,隐含前提是 MCP server 端持有会话记忆:Agent 每轮来检索,server 记得上一轮进行到哪。无状态化之后这个前提没了:会话记忆要么上移到 Agent 应用层,要么外置到专门存储,server 退回一个纯检索函数。有意思的是,那篇的核心论点本来就是记忆该归应用侧结构化管理,方向没被推翻,被推翻的只是那张图:server 从记忆的宿主降级成了记忆的搬运工。写这一节,也算给当时照着图搭方案的读者递个更正。

迁移检查清单:五条判断你的 server 要不要改#

  1. 搜代码里的会话状态。 全局字典、self.sessions、按连接 id 存的东西,出现任何一样,你的 server 就在改造名单上;一样都没有,基本不用动。
  2. 查握手依赖。 有没有逻辑默认”initialize 之后才能干活”,比如把能力协商的结果缓存起来。改版后请求即用,这类前置假设要清掉。
  3. 盘进程内状态。 缓存、计数器、增量索引,凡是在进程里越攒越多的,规划外置方案,别指望协议再帮你兜。
  4. 看部署配置。 配了会话亲和(session affinity)、粘性路由的,改版后可以拆掉,负载均衡换最普通的轮询都行。
  5. 测长连接行为。 有流式输出或进度通知的,把”连接断了怎么办”的应用层方案补上,协议不再负责这一块。

今天只做一个动作:打开你自己的 MCP server 项目,全局搜 session,搜出来的每一行就是你的改造清单。没有 server、只是 MCP 用户的话,什么都不用做,等客户端跟进就行。

一句话结论(2026-08-01):MCP 7 月 28 日的大版本把传输层改成无状态,移除协议级 session 与 initialize 握手,会话语义上移到应用层;状态没有消失,只是从协议搬回应用,换来负载均衡、重试、网关缓存这些 HTTP 级能力。

最后坦白一件事:两周前那篇 token 账单的结尾,我说数据齐了就写暑期第三篇,主题是 OpenCode 的账单实测。跳票了,MCP 这次改版等不了人,OpenCode 的账单往后放放。接下来我盯两件事:各客户端和 SDK 对无状态化的实际跟进进度,规范落地到大家真用上还有多远;以及 Safari MCP server 这类官方出品的示范效应,部署门槛降下来之后,“每个产品都配一个 MCP server”会不会从新闻变成日常。有结论再写。

参考链接#

  1. MCP 官方公告:传输层无状态化(2026-07-28)
  2. Simon Willison:Stateless MCP 解读(2026-07-31)
  3. WebKit:Introducing the Safari MCP Server for Web Developers(2026-07-03)
  4. MCP 官网:modelcontextprotocol.io
分享

如果这篇文章对你有帮助,欢迎分享给更多人!

MCP 无状态化解读:把会话还给应用层
https://www.moonzj.com/posts/mcp-stateless/
作者
张敬
发布于
2026-08-01
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

相关文章 智能推荐
1
Agent 记忆架构全景 — 从虚拟上下文管理到 MCP 驱动的 RAG
技术 聚焦长期运行智能体的记忆瓶颈:上下文窗口有限、信息容易被遗忘、调试成本高。结合 MCP、RAG、Skills、Hooks 等技术,提供一套结构化、可落地的记忆方案。
2
Kimi K3 记忆架构拆解:KDA 把遗忘变成了学出来的能力
技术 Kimi K3 用 KDA 恒定状态递归记忆、MLA 周期精确检索和 AttnRes 深度回读,把记忆的淘汰与检索从向量库外挂移进了模型权重。本文拆解 KDA 谱系与宏循环结构,讲清它和 RAG 外挂的区别与边界,读完你能判断自己的 Agent 要不要继续外挂记忆。
3
Agent 的第一次"越狱"不是提示注入,是共谋
技术 约 18,000 个自称 OpenAI 的自主 agent 曾把一个德文 wiki 当成秘密留言板,共享答案、交换沙箱逃逸技巧。本文拆解 agent 威胁模型的三代升级:犯错、泄密、共谋,解释为什么单机沙箱防不住网络副作用,并给出检查 NO_PROXY、配置 egress 白名单等五条当晚可用的自查清单。
4
DeepSeek Harness 上手三天:一切皆插件是真的
技术 DeepSeek Harness(dsh)08-13 开源,npx 一行命令十分钟跑起来。本文是三天上手实录:四种模式怎么选、Claude Code 的 skills 和 hooks 对应什么、三个值得抄走的上下文细节,附十分钟上手清单与设计 9 分成熟度 6 分的结论。
5
大模型斩杀线:被杀的从来不是模型
技术 大模型斩杀线不是某次降价事件,而是一条随前沿能力上移的能力/价格比基准线。本文用 V4-Flash 的 0.28 美元与 82.7 分、08-06 涨价和 K3 开放权重三个锚点,拆解它斩的不是模型而是旧定价结构,附当天可用的三步验价比方法和实例。

目录