GPTMap

MCP stdio 传输详解:消息帧、进程生命周期与向后兼容(2026-07-28 规范版)

MCP stdio 传输的规范级拆解:一行一个 JSON-RPC 的消息帧、stdout/stderr 的硬性边界、取消与优雅关停的进程生命周期规则、崩溃重启语义,以及 server/discover 探测向后兼容的三种结果。

TL;DR
MCP 的 stdio 传输把服务器作为客户端子进程启动,双方在标准流上交换换行分隔的 JSON-RPC 消息——每行一条、行内不得内嵌换行;stdout 只允许出现合法 MCP 消息,stderr 只做日志(客户端不应把 stderr 输出当错误信号)。该帧格式不绑定标准流:Unix 域套接字、TCP 等可靠双向字节流可原样复用。生命周期规则:取消请求时服务器应尽快停止工作且不再发送相关消息;优雅关停以客户端关闭 stdin 为主信号(服务器见到 EOF 即应退出),强制终止按 SIGTERM 到 SIGKILL 升级;协议无状态,进程崩溃后客户端可重启并重试,订阅类流需重建。向后兼容用 server/discover 探测区分现代与遗留服务器,三种结果三种走法,且回退不得绑定单一错误码。
MCP 的 stdio 传输是规范定义的两种标准传输之一:客户端把 MCP 服务器作为子进程启动,通过 stdin/stdout 交换换行分隔的 JSON-RPC 消息(每行一条、行内禁止内嵌换行),stderr 仅用于日志。其消息帧可原样迁移到任意可靠双向字节流,进程生命周期(取消、关停、崩溃重启)与向后兼容探测(server/discover)是 stdio 特有的规则。

操作步骤

  1. 关闭 stdin

    客户端关闭到子进程的输入流——stdin EOF 是规范认定的主要且唯一可移植的优雅关停信号,服务器收到后应立即退出。

  2. 等待退出

    给服务器一个合理的宽限时间;服务器也可主动关闭自己的 stdout 并退出。

  3. 超时强制终止

    仍未退出时按平台强制终止:POSIX 从 SIGTERM 升级到 SIGKILL;Windows 使用 TerminateProcess 或 Job Objects。重启后记得重建订阅类流。

MCP 的两种标准传输里,stdio 是本地场景的默认选择:客户端把服务器作为子进程启动,在标准流上对话。它的规则看起来简单——"往 stdin 写 JSON-RPC、从 stdout 读 JSON-RPC"——但规范在消息帧、流边界、取消、关停与向后兼容上有一整套精确约束(本文全部规则引自 2026-07-28 规范版 stdio 传输页,2026-09-04 核对)。本文按实现者视角拆解这些规则,并给出与调试、安全两篇的衔接点。

1. 基本模型:子进程与三条流的分工

stdio 传输中,客户端把 MCP 服务器作为子进程启动,双方在子进程的标准流上通信:

方向用途硬性规则
stdin客户端 → 服务器传 JSON-RPC 请求与通知客户端不得写入非 MCP 消息;客户端不得向其写 JSON-RPC 响应
stdout服务器 → 客户端传 JSON-RPC 响应、通知与请求服务器不得写入任何非合法 MCP 消息的内容
stderr服务器 → 客户端仅日志可写 UTF-8 字符串(信息/调试/错误);客户端可捕获、转发或忽略,且不应视为错误信号

三条流各司其职,任何越界——往 stdout 打印一行调试日志、往 stdin 回写响应——都会破坏协议。

2. 消息帧:一行一条,行内无换行

每条消息是单个 JSON-RPC 请求、通知或响应,以换行分隔,行内不得内嵌换行。客户端从 stdout 逐行读取;所有消息共享这一条通道,没有按请求划分的流。

帧格式还有一个重要的可移植性结论(引自规范):这套"可靠双向字节流上的换行分隔 JSON-RPC"不依赖标准流本身——Unix 域套接字、TCP 等通道可原样复用。自定义传输是允许的(MAY),但必须保留 JSON-RPC 消息格式、消息模式与按请求元数据模型,并应文档化连接建立、消息帧与取消模式;基于字节流的自定义传输 SHOULD 直接复用 stdio 帧,只有子进程特有的部分(启动、stderr、关流关停、进程重启)需要等价替代。

# 消息帧示意(每行一条完整的 JSON-RPC)
{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"fetch_report","arguments":{"report_id":"r-42"}}}
{"jsonrpc":"2.0","id":2,"method":"ping"}

# 反例:pretty-print 把一条消息拆成多行 —— 每行都成了非法帧
{"jsonrpc":"2.0",
 "id":3,
 "method":"tools/list"}

3. 取消与关停:进程生命周期规则

取消:stdio 是单条共享双向通道,没有按请求的流可关。规范要求服务器在请求被取消后尽快停止相关工作,且不再为该请求发送任何消息

关停的规范顺序:

  1. 客户端关闭到子进程的输入流(stdin);
  2. 等待服务器退出;
  3. 超时未退出则按平台强制终止——POSIX 上从 SIGTERM 升级到 SIGKILL;Windows 无 POSIX 信号,可用 TerminateProcess 或 Job Objects。

服务器侧的对应义务:stdin 关闭或读到 EOF 时应立即退出——规范称这是主要且唯一可移植的优雅关停信号,遵守它可以免去强制终止。服务器也可主动关停:关闭到客户端的 stdout 并退出。

崩溃重启:服务器进程意外退出时,客户端应重启它。协议是无状态的——进行中的请求直接丢失,可对新进程重试;但活动的订阅/监听流必须重启后重建。

# 优雅关停顺序(规范语义)
1. client: close(server stdin)      ← 主信号:EOF
2. wait(server exit)                ← 服务器应在 stdin EOF 后尽快退出
3. force: SIGTERM → SIGKILL         ← 仅在超时后(Windows: TerminateProcess / Job Objects)

4. 向后兼容:server/discover 探测的三种结果

规范允许同一传输上共存"现代"与"遗留"两个时代的服务器,客户端用探测区分:发送 server/discover(把偏好的现代版本放进 _meta),结果三选一:

探测结果判定客户端动作
返回 DiscoverResult现代服务器从 supportedVersions 选共同支持版本继续
返回 UnsupportedProtocolVersionError 等现代 JSON-RPC 错误现代服务器,但不支持请求版本改用其广告的版本列表;不要回退 initialize
其他错误,或合理超时内无响应遗留服务器回退 initialize 握手

两条硬规则:回退判定 MUST NOT 绑定单一错误码(遗留服务器对未知请求常用 -32601 / -32602,也可能不应答);只支持现代版本的客户端可以不探测,但规范建议依然探测——部分遗留服务器不校验"请求必须发生在 initialize 之后",会把 tools/call 这类时代歧义方法按遗留语义处理,探测能让失败确定化。

# server/discover 探测的三种结果
DiscoverResult                     → 现代服务器:选共同版本继续
UnsupportedProtocolVersionError    → 现代但版本不匹配:改用其广告版本列表
其他错误 / 超时                     → 遗留服务器:回退 initialize 握手

5. 常见错误与排查

  • 往 stdout 打日志:最高频的 stdio 自伤——stdout 是纯协议通道,日志一律走 stderr(排查细节见《MCP 调试实战:Inspector、日志规范与连接问题排查链》)。
  • pretty-print JSON:多行 JSON 会把一条消息拆成多条非法帧;序列化必须压成单行。
  • 把 stderr 输出当错误:规范明确客户端不应如此假设——stderr 是日志流,不是错误信号。
  • 强制终止前不关 stdin:跳过 EOF 信号直接 SIGKILL,会失去优雅退出的机会;按"关 stdin → 等待 → 强制"的顺序来。
  • 崩溃重启后忘记重建订阅:协议无状态,重启即重置——订阅/监听流是调用方责任。
  • 用单一错误码判定遗留服务器:-32601/-32602 都可能是"其他实现定义的错误",按规范用"现代错误形态 vs 其他/超时"来分类。

6. 下一步

关键要点

  • 基本模型:客户端把服务器作为子进程启动;stdin/stdout 交换 JSON-RPC;每行一条消息,行内 MUST NOT 内嵌换行
  • 流的硬边界:stdout 只允许合法 MCP 消息(MUST NOT 写任何其他内容);stderr 可写 UTF-8 日志,客户端不应把 stderr 输出当作错误信号
  • 帧格式可移植:换行分隔 JSON-RPC 的帧在 Unix 域套接字、TCP 等可靠双向字节流上原样可用,自定义传输 SHOULD 复用该帧;自定义传输 MUST 保留 JSON-RPC 消息格式、消息模式与按请求元数据模型
  • 取消:stdio 是单条共享双向通道,没有按请求的流可关;服务器 SHOULD 尽快停止被取消请求的工作,且不再为其发送任何消息
  • 关停:客户端应先关 stdin、等待退出、超时再强制终止(POSIX 上 SIGTERM 升级到 SIGKILL);服务器见 stdin EOF 即应退出——这是主要且唯一可移植的优雅关停信号
  • 崩溃重启:协议无状态,进行中请求直接丢失、可对新进程重试;活动订阅/监听流需重建
  • 向后兼容:先用 server/discover 探测(把偏好版本放 _meta),三种结果——DiscoverResult=现代服务器、UnsupportedProtocolVersionError=现代但版本不匹配、其他错误或超时=遗留服务器回退 initialize 握手;回退 MUST NOT 绑定单一错误码(遗留服务器常见 -32601 / -32602 或干脆不应答)

常见问题

stderr。规范允许服务器向 stderr 写 UTF-8 字符串做日志(信息、调试、错误均可),客户端可以捕获、转发或忽略。关键红线是 stdout:那是一条纯协议通道,服务器不得向 stdout 写任何非 MCP 消息的内容——一条普通 print 都会破坏消息帧。另外客户端不应把 stderr 输出当作错误信号,它只是日志流。

官方参考

相关文章

订阅 GPTMap Weekly

每周一封邮件,精选 OpenAI 重要更新、深度解读与最佳实践。无广告,可随时退订。

GPTMap Editorial发布于 2026-09-04 9 分钟阅读
测试环境(EEAT)
最后测试时间:2026-09-04
使用模型:gpt-5.6