Model Context Protocol (MCP) 通过 JSON-RPC 格式来编码客户端与服务器之间的消息。但仅有消息格式还不够,双方还需要一个可靠的通道来传输这些消息。这个通道,在协议中被称为传输层(Transport)。MCP 官方定义了两种标准的传输机制:stdio 和 Streamable HTTP。
这两种传输机制在设计理念、应用场景和实现细节上存在显著差异。理解它们的区别,有助于在具体实践中选择最合适的方案。
stdio:本地子进程通信
stdio 传输机制是为本地环境设计的,其核心思想是简单、直接。在这种模式下,客户端会直接启动一个 MCP 服务器作为其子进程。
工作原理
当客户端启动服务器子进程后,一个专用的通信管道便建立了。客户端通过写入服务器进程的标准输入(stdin)来发送消息,并通过读取其标准输出(stdout)来接收消息。这种方式非常类似于在命令行中通过管道连接两个程序。
所有通过 stdin 和 stdout 传输的消息都必须是完整的 JSON-RPC 消息,并且以换行符分隔。为了保证通信的纯粹性,协议规定 stdout 不能输出任何非 MCP 消息的内容。服务器如果需要输出日志或其他调试信息,应该使用标准错误流(stderr),客户端可以选择捕_获、显示或忽略这些日志。
整个生命周期与客户端进程紧密绑定。当通信结束时,客户端会关闭服务器的 stdin 流,并终止该子进程,完成一次完整的会话。
生命周期管理
在 stdio 模式下,服务器的生命周期完全由客户端控制。通信的启动始于客户端创建子进程,而通信的关闭则由客户端发起。
标准的关闭流程是,客户端首先关闭通往服务器子进程的 stdin。服务器在检测到 stdin 关闭后,应自行清理资源并退出。如果服务器未能及时退出,客户端会依次发送 SIGTERM 和 SIGKILL 信号来强制终止进程。这种父子进程的管理模型,确保了资源的及时释放,避免了“僵尸进程”的产生。
这种模式非常适合集成在本地开发工具中,例如 IDE 插件或命令行工具,因为它们需要与语言服务器或其他本地服务进行高效、低延迟的交互,并且能够完全控制这些服务的生命周期。
Streamable HTTP:灵活的网络通信
与 stdio 的紧密耦合不同,Streamable HTTP 是一种为网络环境设计的、更加灵活和解耦的传输机制。在这种模式下,服务器是一个独立的进程,可以与客户端运行在不同的机器上,并且能够同时处理来自多个客户端的连接。
通信流程
Streamable HTTP 机制的核心是围绕一个统一的 MCP 端点(Endpoint)展开的,该端点同时支持 HTTP POST 和 HTTP GET 请求。
当客户端需要向服务器发送消息时,它会向该端点发起一个 HTTP POST 请求。请求体包含一个单独的 JSON-RPC 消息。如果发送的是一个通知(Notification)或响应(Response),服务器在成功接收后会返回 HTTP 202 Accepted 状态码,表示已接受。
如果发送的是一个请求(Request),服务器的响应则有两种可能。对于简单的请求,服务器可以直接在 HTTP 响应体中返回一个 application/json 格式的 JSON-RPC 响应。对于可能产生多个事件或需要流式返回数据的复杂请求,服务器会返回 Content-Type: text/event-stream,从而建立一个服务器发送事件(Server-Sent Events, SSE)流。通过这个 SSE 流,服务器可以持续向客户端推送消息,直到最终的 JSON-RPC 响应发送完毕,然后关闭流。
除了通过 POST 请求被动建立 SSE 流,客户端也可以主动发起一个 HTTP GET 请求来监听来自服务器的消息。这使得服务器可以在没有任何客户端请求的情况下,主动向客户端推送通知或发起请求。
会话与状态管理
由于 HTTP 本身是无状态的,Streamable HTTP 引入了会话管理机制来维持交互的上下文。在初始化阶段,服务器可以在响应头中通过 Mcp-Session-Id 返回一个唯一的会话 ID。
客户端在收到这个会话 ID 后,必须在后续的所有 HTTP 请求中都带上 Mcp-Session-Id 请求头。服务器以此来识别和关联来自同一客户端的连续请求,维持一个有状态的会话。
这种机制也为连接的恢复提供了可能。SSE 规范允许为每个事件附加一个 ID。如果连接意外中断,客户端在重新连接时可以带上 Last-Event-ID 头,请求服务器从上一次中断的地方继续推送消息,从而提升了网络不确定环境下的通信鲁棒性。
安全注意事项
Streamable HTTP 将通信暴露在网络上,因此带来了额外的安全考量。实现者必须关注几个关键点:
- 服务器必须验证
Origin请求头,以防止 DNS 重新绑定(DNS Rebinding)攻击。 - 在本地运行时,服务器应仅绑定到
localhost(127.0.0.1),而不是所有网络接口 (0.0.0.0),以避免局域网内其他设备的非授权访问。 - 服务器应对所有连接实施恰当的认证和授权机制。
忽略这些安全措施,可能会使本地运行的 MCP 服务器暴露给远程攻击者,造成严重的安全风险。
stdio 与 Streamable HTTP 的核心区别
深入了解了两种传输机制的工作方式后,我们可以将它们的核心差异归纳如下。这些差异直接决定了它们各自的适用场景。
| 特性 | stdio |
Streamable HTTP |
|---|---|---|
| 耦合模型 | 紧密耦合。客户端作为父进程,服务器作为子进程。 | 松散耦合。客户端和服务器是独立进程,通过网络通信。 |
| 生命周期 | 服务器的生命周期由客户端完全控制。 | 服务器独立运行,生命周期与客户端无关。 |
| 通信方式 | 标准输入 (stdin) 和标准输出 (stdout)。 |
HTTP POST, HTTP GET 以及服务器发送事件 (SSE)。 |
| 并发能力 | 通常是一对一的通信。 | 设计上支持处理多个客户端的并发连接。 |
| 会话管理 | 隐式会话,会话生命周期等同于进程生命周期。 | 显式会话管理,通过 Mcp-Session-Id HTTP 头来维持。 |
| 网络弹性 | 不适用,因为是本地进程间通信。 | 支持连接恢复,通过 SSE 的 Last-Event-ID 机制实现。 |
| 安全模型 | 相对安全,通信限制在本地,不暴露网络端口。 | 必须实施严格的网络安全策略,如认证、CORS、主机绑定等。 |
| 适用场景 | 本地开发工具、IDE 插件、桌面应用内集成。 | Web 应用、远程服务、需要多客户端连接的后端系统。 |
选择哪种传输方式,本质上是在简单性与灵活性之间做权衡。
stdio 模型胜在简单和高效。因为它不涉及网络协议栈,通信开销极低,且无需考虑复杂的网络安全问题。对于那些客户端和服务器注定在同一台机器上运行的场景,例如编辑器插件与语言服务器的集成,stdio 是一个理想的选择。
Streamable HTTP 则提供了更大的灵活性和扩展性。它允许客户端和服务器分离部署,支持多客户端连接,并内置了会话管理和连接恢复等高级功能。这使得 MCP 能够走出本地环境,应用于构建复杂的分布式系统和 Web 应用。当需要构建一个可供网页、移动应用或其他远程客户端访问的 MCP 服务时,Streamable HTTP 是唯一合适的标准选项。
开发必备:API 全流程管理神器 Apifox
介绍完上文的内容,我想额外介绍一个对开发者同样重要的效率工具 —— Apifox。作为一个集 API 文档、API 调试、API 设计、API 测试、API Mock、自动化测试等功能于一体的 API 管理工具,Apifox 可以说是开发者提升效率的必备工具之一。
如果你正在开发项目需要进行接口调试,不妨试试 Apifox。注册过程非常简单,你可以直接在这里注册使用。

注册成功后可以先看看官方提供的示例项目,这些案例都是经过精心设计的,能帮助你快速了解 Apifox 的主要功能。
使用 Apifox 的一大优势是它完全兼容 Postman 和 Swagger 数据格式,如果你之前使用过这些工具,数据导入会非常方便。而且它的界面设计非常友好,即使是第一次接触的新手也能很快上手,快去试试吧!
