无状态 MCP 入门指南
深度讲解 Model Context Protocol 在 2026-07-28 规范中的无状态更新,理解 MCP 如何连接 AI 助手和外部工具与数据的关键细节。
深度讲解 Model Context Protocol 在 2026-07-28 规范中的无状态更新,理解 MCP 如何连接 AI 助手和外部工具与数据的关键细节。
我最近到处都看到消息,说 MCP 刚刚变成了无状态协议,但我完全不知道这意味着什么。于是,我决定深入研究一下,并写下这篇文章。
Model Context Protocol(MCP)用于将 AI 助手连接到工具、数据库和外部应用。在 2026-07-28 规范修订版中,MCP 移除了协议层的会话,变成了无状态协议。
这一变化让远程 MCP server 更容易运维。它们可以在普通负载均衡器后面进行扩缩容,无须使用粘性路由或共享的 MCP 会话存储。客户端可以安全地缓存工具定义,Agent 也能更精细地控制要共享哪些应用资源。
但无状态并不意味着 MCP server 再也不能记住任何东西。浏览器仍然可以保留打开的标签页,数据库事务仍然可以包含尚未提交的更改,购物车里也仍然可以保存商品。区别在于客户端如何引用这些状态。
状态,是指系统在多次请求之间记住的信息。假设有一个控制 Web 浏览器的 MCP server。Agent 可能会先调用 open_browser,接着调用 navigate、click 和 take_screenshot。server 必须知道,这四个操作指向的是同一个浏览器。
在早期版本的 MCP 中,连接本身可以提供这部分上下文。客户端首先发起一个 initialize 请求。在 Streamable HTTP 模式下,server 可以返回一个 Mcp-Session-Id,客户端会把它附加到后续请求中。随后,server 便可以利用这个 ID 找回与该会话关联的信息。
当一个客户端只与一个 server 进程通信时,这种方式很自然。但当 MCP 服务部署在负载均衡器后的多台机器上时,情况就会变得更加复杂。如果 Server A 创建了一个会话,而下一次请求被转发到了 Server B,那么 Server B 就需要通过某种方式找回这个会话。基础设施团队通常有两种解决办法:使用粘性路由,让客户端始终连接到 Server A;或者建立一个所有 server 都能用于查询会话的共享数据库。
不同客户端对“会话”的定义也不相同。一个会话可能只持续一次工具调用、一轮对话、一次页面加载,也可能持续整个应用的生命周期。server 开发者可以把浏览器或购物车保存在会话中,但他们无法可靠地预测这些状态能存活多久,也无法确定哪些对话可能会共享它们。
在 2026-07-28 修订版中,initialize 和 notifications/initialized 握手流程已被移除。server 不再签发 MCP session ID,客户端也不再保存或重复发送这些 ID。
现在,每个请求都会携带理解该请求所需的协议信息,包括协议版本和客户端能力。客户端还可以调用 server/discover,在不创建会话的情况下了解 server 支持哪些版本和功能。
这意味着,任何兼容的 server 实例都可以理解传入的 MCP 请求,无须恢复此前握手阶段保存的信息。如果某个工具需要管理应用状态,例如一个正在运行的浏览器,那么服务仍然需要通过某种方式定位该资源。无状态 MCP 移除的是协议会话状态,而不是应用状态。
当工具需要在多次调用之间保留状态时,server 可以返回一个显式标识符,通常称为 handle。handle 并不是一种特殊的 MCP 数据类型。它只是一个普通值,由一个工具返回,再传递给另一个工具。
例如,浏览器 server 可以像这样工作:
// Open a browser and receive its handle
open_browser()
// Returns: { "browser_id": "browser_abc123" }
// Pass the handle into later calls
navigate({
"browser_id": "browser_abc123",
"url": "https://example.com"
})
浏览器仍然运行在 server 上,并继续保留它的标签页、Cookie 和浏览历史。不同调用之间的关系不再隐藏在连接内部,而是清楚地体现在工具参数中。
显式 handle 也让编排器能够更精细地控制共享状态。如果三个 Agent 一起购物,它们可以共享同一个 cart_id,同时各自拥有独立的 browser_id。单个 MCP 会话无法清晰地表达这两种不同的状态边界。
有些工具需要获得更多信息才能完成操作。例如,部署工具在发布到生产环境之前,可能需要请求用户确认。在 Multi Round-Trip Requests(MRTR)模式下,工具会返回一个 input_required 结果,说明它还需要哪些信息。该结果可能包含一个不透明的 requestState 值;客户端在重试原始调用时,会把这个值连同所需答案一起返回。继续执行所需的信息会跟随重试请求一同传输,而不再绑定到某个保持打开的连接上。
对于运行时间更长或需要持久化的工作,server 可以通过 Tasks 扩展使用 task handle。客户端稍后可以检查或更新任务,而无须一直保持网络连接。
在早期版本的 MCP 中,tools/list 返回的工具可能因会话而异。server 可能先公开一个 connect_database 工具,等数据库连接建立后,再添加 query_database。由于工具列表可能取决于会话历史,客户端无法安全地在其他地方复用它。
当 server 更新或用户权限发生变化时,工具列表仍然可能改变,但它不会再因 MCP 连接不同而变化。server 会返回 ttlMs 和 cacheScope,告诉客户端结果应在多长时间内保持有效,以及它能否被共享。这让编排器可以在多个 subagent 之间复用工具定义,从而减少重复请求,并提高 prompt cache 的复用率。
如果你正在开发或维护 MCP server:
更新 SDK 和版本配置:使用支持 2026-07-28 的 SDK;如果你的框架要求显式启用新版本,请开启对应配置。
用显式 handle 替代会话状态:返回 browser_id 或 connection_id 等标识符,并要求后续调用必须提供这些标识符。
规划资源清理机制:为临时资源设置过期策略,或提供显式的清理工具,不要再依赖连接关闭来回收资源。
对每个 handle 进行授权校验:ID 只是资源的名称,并不能证明调用方有权访问该资源。
确保带有副作用的操作可以安全重试:对于信用卡扣款或触发部署等操作,应在适当情况下使用 idempotency key。
MCP 最初采用面向连接的模型,这种模型非常适合运行在单台机器上的本地进程。随着整个生态逐渐扩展到云服务、托管网关和多 Agent 系统,连接层状态开始成为扩展瓶颈。
2026-07-28 规范将这些关注点拆分开来:协议细节随请求传输,应用状态使用显式 handle,交互式工作流传递 continuation state,工具定义也可以得到清晰可靠的缓存。MCP server 仍然会记住它们需要记住的一切,只是现在会在请求中直接为这些状态命名。
如需采取进一步措施,你可以考虑屏蔽此人和/或举报滥用行为。