接入 MCP:分清标准传输与客户端扩展
文章区分 MCP 的两种标准传输:本地子进程 stdio 与远程 Streamable HTTP,以及 Claude Code 支持的兼容路径。传输层承载相同的 JSON-RPC 消息,与服务端暴露哪些工具、资源和提示词相互独立。
AI 深度解读
给 Claude Code 接 MCP,选本地进程还是远程 HTTP,改变的不只是配置写法,还包括谁负责启动服务、日志往哪里写、断线后该查环境还是等重连。原文的核心结论是:MCP 标准化的传输方式只有 stdio 和 Streamable HTTP,Claude Code 支持的其他连接方式需要单独看待。
对开发者更有用的一点是,传输方式不决定服务器提供什么工具。把连接、协议和能力发现分清,才能避免换一次部署方式,就把工具接口和排障逻辑一起推倒重来。
本地进程和远程服务,究竟差在哪
MCP 的传输层(transport)负责把消息从客户端送到服务器。原文介绍的两条标准路径,使用的都是 JSON-RPC 消息,区别在于消息经过什么通道。
stdio 适合本地集成。Claude Code 启动一个子进程,通过标准输入向它发送消息,再从标准输出读取响应。服务器的业务逻辑由自己实现,子进程的生命周期则由 Claude Code 管理。进程退出,连接也就消失。
这里有个很容易踩的坑:stdio 服务器的标准输出只能写合法的 MCP 消息,日志应写到标准错误。
对 Node 开发者来说,如果把原来脚本中的 console.log 调试输出原封不动留下,就可能把日志混进协议通道。它不再是供人阅读的终端输出,而是客户端正在解析的数据流。
Streamable HTTP 则把进程边界换成了网络边界。客户端通过 HTTP 请求发送 JSON-RPC 消息,服务器可以返回普通 JSON 响应,也可以返回服务器发送事件(SSE)流。服务器还可以通过 HTTP GET 请求建立 SSE 流,用于向客户端发送消息。
所以,选 Streamable HTTP 不代表彻底告别 SSE。需要区分的是:Streamable HTTP 可以使用 SSE 流,而旧的 HTTP-plus-SSE 是另一套传输设计。
原文指出,Streamable HTTP 已替代 2024-11-05 协议修订版中的旧 HTTP-plus-SSE。规范保留向后兼容路径,但新服务器应采用 Streamable HTTP。
部署形态也随之变化。本地脚本可以直接访问机器上的系统资源;远程端点则可以独立部署、认证、监控,并由多个客户端共享。选哪条路,首先取决于工具需要运行在哪里,以及谁来维护它。
换了连接方式,为什么工具接口不用跟着换
原文最值得保留的设计判断,是把三件事分开:
- 连接层决定消息如何送达。
- 协议层规定消息的共同格式与交互含义。
- 更上层处理能力发现,以及这些能力如何进入 Agent 的可用范围。
无论服务器是本地可执行程序,还是 HTTPS 端点,都可以参与初始化,通过 tools/list 列出工具,再接受 tools/call 调用。这些操作在 MCP 层的含义不应因为传输方式而改变。
假设服务器提供一个 create_issue 工具,它的业务含义不会因为从子进程迁到远程服务,就变成另一种工具。需要调整的是消息如何到达服务器,以及网络认证、连接恢复等外围工作。
传输层负责送消息,不能据此推断服务器暴露了哪些能力。
这个边界对阅读客户端源码也有帮助。看到一个连接适配器,只能说明客户端有办法与某个组件交换消息,还不能证明它提供了工具,更不能证明工具已经出现在模型的工具列表里。
原文还举了进程内集成这个极端例子:双方就在同一进程中,没有子进程,也没有网络请求,却仍然可以向上提供统一的 MCP 形态接口。这样,能力发现代码就不必针对远程服务、本地程序和内置集成各写一套。
不过,原文在这里解释的是抽象设计,没有给出具体实现代码。它也没有展开 create_issue 如何进入模型工具列表、如何避免重名、如何应用权限。这些被留给下一篇,不能从「已经连通」直接推导出「模型已经能调用」。
Claude Code 能连四类服务器,不等于协议有四种标准
按原文转述的 Claude Code 公开文档,可配置的服务器类型包括本地 stdio、远程 HTTP、旧版远程 SSE 和远程 WebSocket。其中,JSON 配置接受 streamable-http 作为远程 HTTP 类型的别名。
这份产品支持列表,要和 MCP 的标准传输列表分开看。
旧版 SSE 连接用于兼容仍然暴露旧端点的服务。原文称 Claude Code 已将其标为弃用,并建议能用 HTTP 时优先使用 HTTP。WebSocket 则提供持久双向连接,适合服务器需要主动推送事件的场景;如果只需要请求与响应,原文引用的产品建议仍然是 HTTP。
MCP 允许可插拔的自定义传输,但「允许扩展」不保证「所有客户端都支持」。面向多个客户端开发第三方服务器时,stdio 和 Streamable HTTP 才是原文强调的互操作基础。
同样的区分也适用于故障恢复。以下数字描述的是原文所述的 Claude Code 客户端行为,不能当成 MCP 协议要求:
- 本地 stdio 首次连接失败,不会自动重试。在交互会话中,服务器会被标记为失败,可以通过
/mcp重新连接;非交互运行则等待后续运行或工具调用提供再次启动的机会。 - 远程连接中途断开,最多尝试重连 5 次,采用从 1 秒开始的指数退避。
- HTTP 或 SSE 首次连接遇到暂时性错误,最多重试 3 次。这条规则不适用于 stdio 或 WebSocket。
这些策略背后是不同的排障起点。本地启动失败,先查可执行文件、启动参数、环境和进程崩溃;远程失败,则还要考虑超时、代理临时错误和连接中断。
原文没有把所有失败都归为可重试错误。认证错误、找不到端点,通常需要修配置。具体错误如何分类、不同运行时是否存在差异,文中没有完整展开,不能只凭一个「最多重试几次」就推算全部恢复行为。
我的判断
这篇最有价值的地方,是把协议标准、客户端支持和内部实现分开了。开发者读源码时,很容易因为多个适配器复用了消息处理逻辑,就把它们都视为对外可用的标准接入方式。原文给出的边界,能减少这种误判。
它对重试的解释也合理:进程没启动起来和网络暂时不通,值得采用不同的默认处理。但这是运维策略的解释,不是经过对照实验验证的结论。文章没有给出成功率、恢复耗时或不同策略的比较数据。
「本地失败先查环境,远程中断允许有限重试」可以当排障顺序,不能当错误定律。本地进程也可能短暂失败,远程端点也可能一直配置错误。
同样,原文没有证明 HTTP 比 WebSocket 更快,也没有比较两者的资源开销。选择标准传输的主要理由是互操作与部署适配,不能替它补上性能优势。
还要留一个时效性问号:文章多次使用「当前文档」描述 Claude Code,却没有给出对应产品版本或文档快照日期。两种标准传输的概念边界可以拿来理解架构;具体别名、弃用状态和重试次数,落地时仍应核对所用版本。
能拿来做什么
- 给 Claude Code 接本地 Node 脚本时,先检查标准输出是否混入调试日志,再检查启动命令、参数和环境。交互会话中可以通过
/mcp重新连接,避免反复等待不会发生的首次自动重试。 - 把本地工具改为团队共享服务时,可以沿用
tools/list、tools/call对应的工具语义,把迁移工作集中到 Streamable HTTP 接入、认证、部署和监控上。 - 开发面向多个 MCP 客户端的服务器时,优先评估 stdio 和 Streamable HTTP。只有明确知道目标客户端支持什么,才选择旧版 SSE、WebSocket 或自定义传输。
- 排查「服务器连上了,模型却没有工具」时,把连接成功与工具发现分开验证。继续检查服务器是否声明了工具、客户端如何处理工具名称与权限;原文没有给出这部分实现,不能靠切换传输方式代替排查。