MCP C# SDK 2.0 默认启用无状态 HTTP,新增多轮往返请求
微软发布官方 MCP C# SDK 2.0,实现 MCP 规范 2026-07-28 修订版:Streamable HTTP 服务器默认改为无状态,握手和会话请求头被移除,请求头可用于基础设施路由。由于无状态连接不再支持服务器中途向客户端索取输入,SDK 引入多轮往返请求(MRTR)作为替代。随后发布的 2.1 至 2.3 版本继续补齐兼容能力与细节修复。
一次“重新设计”的规范修订
MCP(Model Context Protocol,模型上下文协议)是一个开放协议,用来标准化应用程序如何向大语言模型提供上下文和工具。C# SDK 由微软参与维护,基于 ASP.NET Core 构建。
SDK 团队称,2026-07-28 修订版是协议发布以来最大的一次改动,因为 MCP 在 HTTP 上的运行方式被重新设计了。2.0 版本之外,8 月至 10 月间又陆续发布了 2.1、2.2、2.3 三个次要版本。
无状态化:握手和会话 ID 都不再需要
新版本最核心的变化是把 Streamable HTTP 服务器默认设为无状态:
initialize握手和Mcp-Session-Id请求头被移除。协议版本与功能声明改为随每个请求一起发送,因此任意一个服务器实例都能处理任意请求,不再需要粘性路由(把同一会话固定打到同一台机器)或共享会话存储。HttpServerTransportOptions.Stateless现在默认为true;确实需要会话能力的服务器可以显式设为false。- 客户端会先探测
server/discover,遇到旧服务器时自动回退到传统握手。 - 只适用于有状态模式的配置、以及传统 SSE 端点,现在会分别抛出
MCP9006、MCP9004警告。
这套改动直接决定了后面几项设计:既然每个请求自带全部上下文,网关和负载均衡器就不必再“记住”谁是谁。
请求头可路由,但请求体仍是权威
tools/call 请求新增 Mcp-Method、Mcp-Name 请求头,另有特性支持把工具参数提升为 Mcp-Param-* 请求头。这样负载均衡器、网关可以直接根据请求头做路由决策,无需解析请求体。
不过请求体依然是权威来源:一旦请求头与请求体信息不一致,服务端会返回 HeaderMismatch 错误。
MRTR:无状态连接下如何“反问”客户端
无状态化移除了服务器在一次调用过程中向客户端索取输入的通道。替代方案是 MRTR(多轮往返请求,Multi-Round Trip Request):
- 工具抛出
InputRequiredException,其中包含一个或多个输入请求,可用InputRequest.ForElicitation(向用户征求信息)、ForSampling(请求模型采样)或ForRootsList构建,并附带一段不透明的requestState。 - 客户端收集响应后,通过
inputResponses重新发起调用。
如果注册了对应处理程序,McpClient 会自动完成这一流程。对于使用 2025-11-25 或更早版本客户端的有状态会话,SDK 会桥接到旧的“服务器发起请求”机制;而在无状态的低版本连接上,该请求会抛出 McpException。
此外,遵循 SEP-2577,Roots、采样和日志相关 API 被标记为废弃,警告码为 MCP9005。
兼容性与破坏性变更
稳定的 1.x API 仍可继续使用,例外是 Tasks:它已移入 ModelContextProtocol.Extensions.Tasks 包,且与 1.3、1.4 中的实验版本不兼容。面向 MCP App 场景的 ModelContextProtocol.Extensions.Apps 包则为实验性质。
OAuth 行为也更严格了:加入 RFC 9207 的签发者(issuer)校验,强制对外声明支持 PKCE S256,动态客户端注册时自动推断应用类型。包支持的目标框架包括 .NET 8、9、10 以及 .NET Standard 2.0。
2.1 至 2.3:小步补齐
- 2.1:新增可选的
subscriptions/listen处理器,用于自定义服务器端通知流;当server/discover在 HTTP 层失败时回退到initialize。 - 2.2:引入
HttpServerSessionMode,让使用 2025-11-25 和 2026-07-28 两个修订版的客户端共享同一端点;修复了McpHeaderEncoder.DecodeValue中的异常。 - 2.3:将
McpClient.ServerInfo设为可空,这是源码级破坏性变更,因为服务器可能不在server/discover中返回可选的身份元数据;文档同时提醒,不要将服务器自报的身份信息用于安全决策。Streamable HTTP 现在会等到第一个协议消息到达后才发送响应头,因此长时间静默运行的处理器可能需要输出进度信息,或设置更长的 HTTP 超时。其他变更包括:列出工具、提示词和资源时保留注册顺序;暴露McpClientOptions.TimeProvider便于编写确定性的超时测试;把 OAuth 排除在DiscoverProbeTimeout之外;在等待优雅退出前先关闭 stdio 服务器的输入。
对正在做 AI 编程工具或“氛围编程”(vibe coding)类产品的团队来说,无状态化意味着 MCP 服务端可以像普通无状态 Web 服务一样横向扩容,放进现有网关后面即可,不必为会话绑定单独设计一层路由。
待解的安全疑问
有读者在博文评论区提问:协议如何防止相关内容被篡改或在跨会话时被重用?目前评论区尚无官方回复。团队表示,下一阶段重点是端到端身份认证与授权。
SDK 已在 NuGet 上提供,文档见项目站点,2.0 至 2.3 的发布说明可在 GitHub 查看。
关键要点
- 2.0 默认关闭会话:
initialize握手与Mcp-Session-Id被移除,协议版本随请求发送,任何实例都能处理任何请求。 - 请求头(
Mcp-Method、Mcp-Name、Mcp-Param-*)可用于网关路由,但请求体仍是权威来源,不一致即报HeaderMismatch。 - 无状态下服务器无法中途索要输入,改由 MRTR 通过
InputRequiredException与inputResponses完成多轮交互。 - 升级时注意 Tasks 包迁移、
McpClient.ServerInfo可空等破坏性变更,以及废弃警告MCP9005。