跳到主内容

MCP 传输方式对比:stdio 与 Streamable HTTP 怎么选

100%
MCP 传输方式对比:stdio 与 Streamable HTTP 怎么选

先给结论

选 MCP 传输方式只有一条主线判断:服务器必须碰用户本机(本地文件、桌面应用、 localhost 服务)就用 stdio;它是包装外部网络 API 、要给多个人用、需要正常 OAuth 的就用 Streamable HTTP 。协议语义在两种传输上完全一致,差别只在消息怎么打包送达、取消怎么做、以及由谁负责进程生命周期。

一句实践总结:stdio 是「你给每个人发一个安装包,每人机器上跑一份」;Streamable HTTP 是「你部署一份服务,所有人共用」。升级方式、鉴权方式、计费边界全部由此推导出来。

对照表

维度stdioStreamable HTTP
谁启动进程客户端启动子进程你作为服务自行部署
能触达范围仅使用者的机器任何能访问 URL 的人
鉴权方式环境变量、系统钥匙串OAuth 2.1 资源服务器等标准方案
升级方式用户重新安装你重新部署一次
消息格式换行分隔的 JSON-RPCHTTP POST + JSON 或 SSE 流
典型场景文件读写、本地脚本、原型SaaS 接入、团队共享能力

stdio:规则简单,违规代价大

工作方式:客户端把服务器当子进程拉起,服务器从 stdin 读 JSON-RPC 消息、往 stdout 写响应,消息之间用换行分隔且内部不得含换行。

三条必须记住的约束:

  1. 不得向 stdout 写任何非协议内容。日志、进度条、第三方库的启动横幅、依赖告警——每一个字节都是协议线上的一帧。
  2. 日志一律走 stderr,客户端不得把 stderr 输出当成错误信号。
  3. 优雅退出靠 stdin EOF:客户端关闭输入流,服务器应尽快退出,否则会被升级为终止信号。
「随机卡住」的真实成因
不带换行的半截输出是最致命的一类。比如在处理函数里先写一句提示语再返回结果,协议线上就变成「上一帧正常 JSON + 下一行半截文本」,那条响应不再是合法 JSON,客户端永远读不到它,最终表现为请求超时。
部分 SDK 做了防护(例如 Python 版在内部重定向标准输出),但这是尽力而为的行为,不要依赖它。正确做法:显式把日志配置到 stderr,并且在任何 print 之前就完成这件事。

Streamable HTTP:一个端点搞定所有

工作方式:服务器提供一个路径(约定为 /mcp),每条客户端消息发一次新的 HTTP POST,请求头必须同时声明支持 application/json 与 text/event-stream。服务器可以选择直接返回一个 JSON 对象,也可以返回一个请求级的 SSE 流。

它是替代早期「 HTTP + SSE 双端点」方案的新标准。旧方案需要两个端点、靠 endpoint 事件告知客户端往哪发消息;新方案把复杂度砍掉了一半。

服务端四条硬性要求

  • 接收任何连接时都必须校验 Origin 头,无效则返回 403,这是防 DNS 重绑定的必要手段。
  • 本地运行时只绑定 127.0.0.1,不要绑 0.0.0.0 。
  • 所有连接都要有恰当的身份验证。
  • 收到通知或响应类消息时返回 202 Accepted 空响应体。

流与重连

服务器可以先发一个带事件 ID 的空 SSE 事件做「预热」,随后随时可以关闭连接而不终止流;客户端应带着 Last-Event-ID 重连,并遵守服务器给出的重试间隔。响应发完后,服务器应正常终止该流。断开连接不等于客户端取消了请求,这一点在实现重试逻辑时尤其重要。

取消、元数据与自定义传输

  • 取消:stdio 上客户端发通知;HTTP 上直接关闭响应流。协议层面的规则一致。
  • 元数据:协议版本与能力都放在消息体里,HTTP 传输会把它镜像到请求头,方便中间件路由,但消息体始终是唯一事实来源。
  • 自定义传输:允许实现,只要保留 JSON-RPC 格式、消息模型与元数据模型;跑在可靠双向字节流上时,官方建议直接复用 stdio 的分帧方式。

迁移与兼容

如果你的服务还在用旧的 SSE 双端点方案,迁移要点是:合并成单一端点、每条消息一次 POST 、按 SSE 事件 ID 支持断线重连、补齐 Origin 校验。客户端与服务器可以通过初始化握手互相判定对方所处的协议阶段并降级处理。

相关阅读


stdio 服务器还需要处理网络认证吗?
通常不需要,凭证通过环境变量或系统钥匙串注入即可。如果一个 stdio 服务器非要做 OAuth 浏览器跳转,基本说明它其实更适合做成 HTTP 传输。

为什么我本地跑得好好的,别人连不上 HTTP 服务器?
最常见两个原因:绑定的是 127.0.0.1 而非对外地址,或者没配端口转发与防火墙。先确认服务是否真的在监听外部地址。

响应该返回 JSON 还是 SSE?
这是服务器的自由,客户端必须两种都支持。需要流式返回或要在响应前推送通知时用 SSE,简单一问一答用 JSON 更省资源。

可以用 WebSocket 之类的自定义传输吗?
可以。协议本身与传输无关,只要保留 JSON-RPC 消息格式与消息模型即可,但建议写清楚连接方式、分帧与取消语义,方便互操作。

这篇有帮助吗?
云上的幻象
云上的幻象查看主页

七彩云博客,分享 WordPress 建站实战与 AI 工具测评,覆盖服务器运维、站长工具、软件资源与电商运营干货,专注原创实用的主题插件、网站加速与安全优化教程。

779文章4评论

相关文章

评论 (0)

欢迎你,新朋友,感谢参与互动!文明发言,理性交流 · 首次评论将在审核后展示