先把当时的情况摆出来。把本地 stdio 的 MCP server 改成 streamable HTTP 部署到内网,Node 20 上用 @modelcontextprotocol/sdk 1.11 的客户端连 https://mcp.internal/rpc,握手阶段就回 406 Not Acceptable,服务端日志只留了一行 accept header mismatch。同一个地址用 curl 发 GET 是 200,用浏览器打开也正常。
这类报错背后常见的原因有几处,逐个排除就行。客户端只发了 application/json,没带 text/event-stream。少数情况下是反向代理把 Accept 头改写成了单一类型。
少数情况下是服务端开了严格模式,要求两个类型同时出现。不容易想到的是,旧版 SSE 传输和新地址混用,路径根本对不上。
先用 curl 同时带两个 Accept 类型,验证服务端本身没问题
curl -i -X POST https://mcp.internal/rpc -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}'
随后确认代理没有改写请求头
curl -sI https://mcp.internal/rpc | Select-String -Pattern 'accept|server'
客户端初始化时显式指定传输方式和请求头
python -c "print('use StreamableHTTPTransport with json + event-stream')"
末了把旧 SSE 地址和新 rpc 地址分开配置,避免互相顶掉
python mcp_client.py --transport streamable-http --url https://mcp.internal/rpc
别只看报错消失,验证要多做一步。initialize 返回 result 里的 protocolVersion 与 serverInfo,紧接着 tools/list 能拿到完整工具数组。
补一句。Node 的 fetch 默认 Accept 是通配符,部分网关会据此改写成单一类型,抓一次原始请求头比反复改客户端快。拖得越久,排查成本越高,因为现场状态会被后续操作覆盖。
