MCP 传输方式实战:stdio、Streamable HTTP、WebSocket 该选哪个

MCP 传输方式实战:stdio、Streamable HTTP、WebSocket 该选哪个

结论先放这儿

场景 选哪种 一句话理由
本地开发、桌面客户端(Claude Desktop、Cursor) stdio 一条启动命令,不碰网络
Server 部署到服务器、多客户端共享 Streamable HTTP 2025 年协议指定的远程方案
持续推送、长连接 WebSocket 全双工,生态还在完善

自建 MCP Server 那篇发出去之后,被问得最多的一个问题是「Server 搬到另一台机器上,stdio 还能用吗」。答案是不能。stdio 依赖进程间的管道,Server 和客户端必须挤在同一台机器上。要远程部署,就得换传输方式。

恰好一篇公开的实战文章把 stdio、HTTP+SSE、WebSocket 三种方式放在一起做了对比测试,框架值得借鉴。不过它有两处要修正。一是 2025-06-18 协议版本已经把旧的 SSE 传输标记废弃,远程部署的正解换成了 Streamable HTTP;二是文中部分 SDK API 与真实版本对不上,照抄会直接报错。本文沿用它的对比框架,代码以官方 SDK 实测为准。

一、传输层在协议里站什么位置

MCP 协议本身跟传输方式无关。它规定的是 JSON-RPC 2.0 的消息格式和握手、工具发现、调用这套流程,没规定消息走什么通道。跟 HTTP 可以跑在 TCP、TLS 或 QUIC 之上一个道理,通道换了,协议不变。

官方 Python SDK 里每种传输方式是独立模块,服务端代码写好之后,换传输只需动启动参数。这一点是后面所有选型讨论的基础,传输可替换,工具函数零改动。

二、stdio:本地开发的最短路径

客户端把 Server 当子进程拉起,stdin 发请求,stdout 收响应,stderr 留给日志。三步走完,没有端口、没有 URL。

python 复制代码
# server.py
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("tools")

@mcp.tool()
def add(a: int, b: int) -> int:
    """两数相加"""
    return a + b

if __name__ == "__main__":
    mcp.run()  # 默认 stdio,无需参数

客户端一侧用 stdio_client 拉起同一个脚本:

python 复制代码
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

params = StdioServerParameters(command="python", args=["server.py"])
async with stdio_client(params) as (read, write):
    async with ClientSession(read, write) as session:
        await session.initialize()
        result = await session.call_tool("add", {"a": 1, "b": 2})
        print(result.content[0].text)

代价也明确。同一台机器、一个进程只服务一个客户端、每次连接都要冷启动一次进程。开发阶段这些都不叫事,上了生产就是硬伤。

三、Streamable HTTP:远程部署的默认选择

2025-03-26 协议版本引入 Streamable HTTP,2025-06-18 版本把旧的「HTTP + SSE」传输标记废弃。新传输只保留一个 HTTP 端点,客户端 POST 消息上去,响应按需返回。简单调用回普通 JSON,需要推送时再升级成 SSE 流,一个端点干了两件事,旧方案里「请求走 POST、推送走 SSE 长连接」的双通道配置就不再需要了。

服务端改动只有一行:

python 复制代码
mcp.run(transport="streamable-http")  # 监听 8000 端口,端点路径 /mcp

客户端换成 streamablehttp_client,连接地址指向 /mcp:

python 复制代码
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

async with streamablehttp_client("http://localhost:8000/mcp") as (read, write, _):
    async with ClientSession(read, write) as session:
        await session.initialize()
        result = await session.call_tool("add", {"a": 1, "b": 2})
        print(result.content[0].text)

这个模式下 Server 可以挂在任何机器上,多客户端共享一个实例,前面还能加 Nginx 做反代、加鉴权做访问控制。之前扛量实战里的限流和熔断,也能直接套在这一层。

四、WebSocket:什么时候才轮到它

WebSocket 提供全双工通道,双方随时互发消息,天然适合「Server 持续推数据」的场景,比如日志流、监控数据的实时输出。

但实际项目里它排最后。官方 SDK 对 WebSocket 传输的支持还在完善,不少企业网络会拦截 WebSocket 连接,断线重连、心跳检测这些都要自己写。Streamable HTTP 在需要推送时升级成 SSE 流,延迟表现接近,工程成本低得多。拿不准的时候选 Streamable HTTP,踩坑概率小。

五、三种传输的切换成本

我做了一次真实切换,把上一篇的 Server 从 stdio 搬到 streamable-http。工具函数一行没动,改动只有两处。服务端 mcp.run() 加上 transport 参数,客户端连接代码从 stdio_client 换成 streamablehttp_client。总改动量个位数行。

维度 stdio Streamable HTTP WebSocket
通信范围 本地进程间 网络 网络
连接模式 一对一 多对一 多对一
推送能力 有(stderr 之外的双向管道) 有(按需升级 SSE 流) 有(原生全双工)
多客户端 不支持 支持 支持
远程部署 不支持 支持 支持
配置复杂度 低 中 中高
适合阶段 开发/本地 生产/远程 实时推送

六、三个真实踩坑

坑一,stdio 里 print 毁连接。 stdout 被 MCP 协议消息独占,在 Server 里用 print 打日志,日志会混进协议流,客户端直接解析失败。日志一律走 stderr,或者交给 logging 模块:

python 复制代码
import sys, logging
logging.basicConfig(level=logging.INFO, stream=sys.stderr)

坑二,旧客户端只认 /sse 路径。 2025-06-18 之前发布的客户端连的是 /sse 端点,升级服务端到 Streamable HTTP 后旧客户端会连不上。过渡期两个端点并存,等客户端都升完再下掉旧路径。

坑三,Nginx 缓冲截断流式响应。 Server 挂在 Nginx 后面时,SSE 流会被默认缓冲攒着,客户端半天收不到推送。反代配置要加这几行:

nginx 复制代码
proxy_buffering off;
proxy_http_version 1.1;
proxy_set_header Connection '';
proxy_read_timeout 86400s;

另外调试 Streamable HTTP 不需要 SDK,一条 curl 就能看见协议原貌。手动发一个 initialize 请求,响应里的 JSON-RPC 结构一目了然,这一招在协议篇里也用过:

bash 复制代码
curl -X POST http://localhost:8000/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}'

写在最后

传输方式的选择没那么玄学。本地开发用 stdio,远程部署用 Streamable HTTP,持续推送才考虑 WebSocket。真正要记住的只有一件事,传输层是可替换的,工具代码跟通道无关,先把工具逻辑写对,通道随场景换。

有一篇公开的实战文章把这个话题的对比框架搭得很好,本文的选型思路受它启发,协议演进和代码部分按 2025-06-18 规范与官方 SDK 重新校过。

来源:一篇公开的实战文章(MCP 传输方式对比测试,blog.csdn.net/2401_89160889/article/details/167495587),仅借鉴对比框架与踩坑思路,代码与协议版本以官方 SDK 实测为准。

相关推荐
Anesthesia丶7 小时前
基于 Qwen3-TTS 的多语言智能配音 Web 应用(Qwen3 TTS Studio)
python·ai·qwen-tts·agci
the局外人7 小时前
Python 中使用 SSE 实现大模型流式输出
后端·python·llm
阿里云云原生7 小时前
概率、插座与 5000 个爱因斯坦:专访阿里云研发副总裁周琦
agent
JaJian8 小时前
从0搭建企业级知识库-技术指南
agent
全栈紫升8 小时前
漫画拆解 agent-browser:从网页快照到动作验证
agent
桑年8 小时前
四、Pandas数据处理
人工智能·python·线性代数·pandas·数据可视化·数据处理
第九序言T8 小时前
Python 数据处理进阶(二十四)把脚本变成工具:argparse、logging 与定时任务
python·自动化·pandas
shelly聊外贸9 小时前
WhatsApp 聊天记录如何导出为 CSV?使用 Python 进行数据分析
开发语言·python·数据分析
I Am a robert girl9 小时前
从 FlowAct-R2 拆解“会说话的数字人“:流式多模态参考与主动式 Agent 规划
python·数字人·多模态大模型·扩散transformer·流式生成·agent规划
梯度下降者10 小时前
Python使用统计建模解决业务预测问题的常见操作步骤【教程】
python·可解释性·数据清洗·模型选择·业务预测