应用代理

MCP Server 连不上怎么排查:本地 stdio 与远程 SSE 分开看,附 Nginx 反代配置

MCP 连不上,先分型再动手。本地 stdio 由客户端直接拉起一个进程,压根不经过网络;远程 HTTP/SSE 才会撞上代理、长连接被切、证书和企业网关。这两类的原因几乎没有交集,混在一起查就会陷入「改一个变量试一次」的循环。

分型只看一个信号:报错是进程没起来(命令找不到、依赖缺失),还是网络没通(超时、握手后无数据)。前者翻客户端启动日志,后者才轮到 Clash。Agent 侧用法见如何使用 Claude Code、如何使用 Codex CLI;统一多上游见 9Router 配置。

两种传输,两种病

本地 stdio 远程 HTTP / SSE
怎么跑 客户端启动本地命令,走标准输入输出 客户端向一个 URL 发请求,服务端流式回传
典型失败 命令找不到、依赖缺失、权限不足、路径写错 超时、握手后无数据、会话莫名断开
和代理有关吗 基本无关 强相关
先看什么 客户端日志里的启动报错 能否出站、有没有增量数据

远程连不上:按这个顺序查

  1. 出站通不通。端点在境外时,先确认运行客户端的进程能出海:开 Tun,或在启动客户端的终端里设 HTTPS_PROXY。改完重开终端或重启客户端再试。
  2. 回环有没有被误代理。本地起的 MCP 服务用 127.0.0.1 访问,代理变量却把它一起代理走,就会出现「服务明明在跑却连不上」。把回环写进 NO_PROXY。
  3. 是不是握手成功但没数据。这最能说明问题:连接建立了,工具列表却一直空着,八成是流被中间层缓冲住了,而不是网络不通。
  4. 会话是不是被定时掐断。用几分钟就断、每次断的间隔还挺规律,通常是某一层的读超时或空闲超时在起作用。
  5. 证书与网关。公司网络里的 TLS 中间盒会让客户端拒绝连接;这类要么让 IT 放行,要么换网络验证。

自建服务端时,最常踩的一组配置

如果远程 MCP 是你自己放在 VPS 上、前面挂了 Nginx,那么「连上但不返回」几乎总是缓冲问题:反向代理默认会把响应攒够一批再发,而 SSE 需要边产生边送。对应的做法是在该 location 上关掉缓冲与缓存、保持 HTTP/1.1 长连接、不要压缩,并把读超时放长:

location /mcp {
    proxy_pass http://127.0.0.1:8000;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_buffering off;
    proxy_cache off;
    gzip off;
    proxy_read_timeout 86400s;
}

更省事的方向是换传输:MCP 规范里的 Streamable HTTP 把长连接拆成一次次独立请求,网络抖动时单次失败可重试,不会整段会话报废,反代配置也回归常规。新部署优先选它,SSE 更适合本机或内网。

另外,别把 MCP 服务裸奔在公网。它常常握着文件系统或内部 API 的操作能力,至少要有 TLS 与鉴权;把工具权限收敛到只读也是有效的减面手段。

网络抖动是常态,不是故障

合盖休眠、从 Wi-Fi 切到热点、代理换节点重连——这些都会打断长连接。合理预期是「需要重连」,而不是每次都去翻配置。经常在移动场景用远程 MCP 的人,选 Streamable HTTP 的收益比调超时更大。相关:休眠唤醒后断网、代理开了却打不开。

最小复现

  1. 只留一个 MCP 服务,其它先禁用。
  2. 在命令行直连端点,看数据是逐条到达还是最后一次性吐出——后者就是缓冲。
  3. 确认代理方式只启用一种(Tun 或变量)。
  4. 成功后再逐个加回其它服务,每加一个跑一次最小请求。

客户端下载见下载中心;连接与日志的读法见日志排错。