无状态:MCP 传输层的未来

原文链接:https://aaif.io/blog/stateless-the-future-of-mcp-transports/


深入探讨 [Shaun Smith](https://www.linkedIn](https://www.linkedin.com/in/smithshaun/) 与 Kurtis Van Gent 在 MCPDev Summit North America 2026 上的演讲

MCP 的运营规模相当可观:Google Cloud 为其支持 AlloyDB、Spanner、Cloud SQL、Bigtable 和 Firestore 的 MCP 服务器维护可靠性。该团队的开源 MCP Toolbox for Databases 已被广泛采用,Toolbox for Databases Toolbox 已被快速采用,过去一个月内 GitHub 星标数超过 13,000,管理着 40 多个数据库上管理着超过 2000 万次工具调用。与此同时,Hugging Face 通过 Spaces 使用超过 2,500 个 MCP 服务器来提供关键的推理访问连接,并发布其观察到的通过传输端点连接的 MCP 客户端的详细公开数据。

两者都遇到了同样的障碍。MCP 目前的设计是有状态的。在有状态(stateful)是有状态的。而在这些团队运营的规模下,这会导致实际问题,并迫使采用新方法。对于 Hugging Face 来说,开销是可衡量的:一次工具调用可能产生超过 100 条 MCP 协议消息。Smith 的团队追踪了连接客户端与后续发起工具调用的客户端之间的转化率,而协议的“话多”特性对此比例不利。

状态问题

如今每个 MCP 会话都以初始化开始。在客户端能做任何有用的事情之前,它需要与服务器协商:交换协议版本、能力、会话 ID,所有这些上下文必须在连接的生命周期内持续存在。

这对于绑定到单个开发者机器的本地 stdio 服务器来说没问题。但一旦你添加了负载均衡器,问题就出问题了。

当请求可能到达池中的任意服务器,且每台服务器都需要知道之前请求中发生了什么才能正确响应时,你就面临协调问题。服务器必须保持同步。会话将你绑定到特定的连接生命周期。如果该连接断开,状态也随之丢失。

Van Gent 直言不讳:无状态协议意味着每个请求都携带处理它所需的一切。池中的任何服务器都可以处理它。区域可以故障并恢复。你不会丢失工作。调试也更简单——如果请求是自包含的,你可以直接检查它,而无需重建导致它的上下文。

他们在传输工作组中工作的目标是让 MCP 让 MCP 变成这样。

移除初始化

第一个也是最大的变化是 SEP-1442:移除初始化握手作为必需的步骤。

不再需要在实际工作开始之前进行单独的初始化阶段,协议协商将合并到第一个实际请求中。

  • 客户端发送一个 `tools/list 调用,并附带其协议版本。
  • 服务器要么接受并响应,或者返回它支持的版本列表,以便客户端重试。

一次往返,而不是一套仪式。请求本身就是协商。

这也让协议版本、客户端能力和服务器能力可以独立变化。目前,更新其中任何一个都可能需要拆除整个会话。在无状态世界中,一个在会话中途添加了对 elicitation 支持的客户端只需在下一个请求中说明即可,无需重启。

修复 Elicitation

状态问题在 elicitation 模式中最为明显:服务器在工具调用过程中需要向客户端询问后续问题。

如今,当服务器通过其 SSE 流发送 elicitation 请求时,客户端的响应会作为新的 HTTP 请求返回。该响应可能落在与发送原始 elicitation 的服务器可能完全不同。现在两台服务器必须协调。如果任一连接断开,整个交换就会崩溃。

这就是主要提供商尚未推出 elicitation 的原因。可靠性故事站不住脚。

SEP-2322 直接解决了这个问题。流程变为一系列独立的请求。

  1. 服务器返回一个中间结果,本质上说:“我需要更多信息。”
  2. 客户端收集该输入,并发送一个新的工具调用,其中包含之前的响应包含在内。
  3. 状态在请求中传递。任何服务器都可以处理它。elicitation 完成,工具调用也完成。

会话,澄清

用 Smith 的话来说,当前规范中的会话“几乎是传输的副作用。”对于 stdio,你的会话就是进程的生命周期。对于可流式 HTTP,服务器可能会也可能不会发出会话 ID,具体取决于实现选择。

这种模糊性带来了风险。如果某个 MCP 服务器开发者对“会话”(session)的含义做出了假设,那么两个对话线程最终可能会通过同一个服务器实例共享状态。一个对话的指令会影响另一个对话。Hugging Face 的 Smith 团队最初部署时完全没有使用会话,效果不错,但他们失去了追踪哪些客户端在发起哪些调用的能力,于是开始将会话 ID 用作分析钩子。

工作组最终达成的提案默认转向无会话协议是无会话协议。一种协议。一种常见模式已经完成了会话原本要做的绝大部分工作:将显式资源句柄作为工具调用参数传递。如果客户端告诉服务器它要操作哪个 Spanner 实例,服务器无需记住之前的请求。状态就在载荷(payload)中。

对于真正需要粘性(stickiness)的那部分部署场景,会话将移至扩展层,而非核心规范。

HTTP 标准化

Van Gent 解决的另一个问题与 JSON-RPC 如何与 HTTP 基础设施交互有关。

HTTP 的设计理念是路由信息位于请求的顶部,即头部(headers),前置且易于解析。代理、负载均衡器和中间件可以读取信封(envelope)并转发其余部分,无需解析完整载荷。

JSON-RPC 将所有内容放在请求体中。链中每个需要做出路由决策的节点都必须解析整个载荷才能完成路由。在大规模场景下,这会给每一跳增加开销。

SEP-2243 引入了 HTTP 标准化:JSON-RPC 载荷中的关键信息会被镜像到 HTTP 头部。方法名、资源名称、资源名称、被调用的工具,所有这些都在信封层面可见。对于包含路由相关参数的工具调用,服务器可以声明哪些字段应提升到头部,这样负载均衡器就能将 Spanner 调用路由到正确的区域和实例,而无需接触载荷。

下一步计划

传输层的变更正按计划在 6 月发布的规范中落地。SEP 月会陆续发布,留出两个月时间让各 SDK 进行实现,随后规范最终定稿。Smith 指出,一旦这些基础决策确定下来,目标就是不再频繁修改传输层。顺序很重要:先正确实现无状态,再在此基础上构建。

接下来,工作组正在考虑优化工作:用于资源新鲜度的 eTags)、工具列表的生存时间(time-to-live)提示(让客户端知道多久刷新一次),以及可插拔的传输层(支持 WebSockets、gRPC 和其他部署场景,同时不碎片化核心标准。

两场演讲的主线是一致的:MCP 早期设计中固有的假设对于本地 stdio 服务器是合理的,但实际部署情况不同。每月 2000 万次工具调用、覆盖 2500 台服务器,这需要基础设施层面的思考,而这正是传输工作组正在做的工作。

Shaun Smith 是 Hugging Face 的 MCP 核心维护者,与 Google Cloud 的 MCP 核心维护者 Kurtis Van Gent 共同领导传输工作组。传输工作组在 Agentic Agentic AI Foundation 下运作。了解更多信息并参与其中,请访问 aaif.io。

加入 AAIF Discord 的讨论,并探索 MCP GitHub 仓库 开始构建。