stdio MCP 的 stdout 只能是 JSON-RPC,日志打 stderr

Codex 把 stdout 当严格协议。启动横幅、console.log、Content-Length 头都会 Transport closed 或列不出工具。探测用换行分隔的 initialize。

stdio MCP 的 stdout 是协议通道,不是日志。Codex 按一行一条 JSON-RPC 读,比不少其它客户端更严。mcp list 显示 enabled、你在终端里手工探测也通,但会话里一调工具就 Transport closed,先查有没有非 JSON 打到了 stdout。

自己探测时用换行,不要用 LSP 那种 Content-Length 头:

printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"probe","version":"0"}}}' | node ./server.js

第一行必须是 { 开头的 JSON。出现 [MCP Bridge]loadedconsole.log 横幅,就是协议被污染。把诊断改到 stderr 或文件,Windows 上 console.debug 有时仍会进 stdout,改成明确写 stderr。

只讲 Content-Length 的自写服务器,Codex 可能列得出 enabled、会话里却没有工具。改成默认输出换行 JSON,并新开会话再测。

这和另外两条 Windows 坑不是同一件事:Python stdio 握手字节根本到不了客户端,Node 往往正常;stderr 太吵可能堵满管道。日志已经离开 stdout 仍失败,再查那两条,不要先换服务器实现。HTTP MCP 走 url,不受这条 stdout 规则影响。

来源