Skip to content

Latest commit

 

History

History
278 lines (197 loc) · 7.14 KB

File metadata and controls

278 lines (197 loc) · 7.14 KB

故障排查:从网络到 root shell 逐层检查

不要一遇到 MCP 连接失败就开放公网端口、关闭防火墙或重装服务。

按下面四层定位:

① systemd / Python 进程
        ↓
② TCP 监听 / SSH tunnel / Docker 私网
        ↓
③ MCP initialize / tools list
        ↓
④ exec_vps 真实工具调用

上一层没有通过,不要跳到下一层。

1. systemd 服务没有运行

检查:

systemctl status exec-vps-mcp.service --no-pager --full
journalctl -u exec-vps-mcp.service -n 100 --no-pager
systemctl cat exec-vps-mcp.service

常见原因:

  • /opt/exec-vps-mcp 不存在;
  • .venv/bin/python 没有创建;
  • 依赖没有安装;
  • systemd 单元仍指向旧路径;
  • Python 版本低于 3.10;
  • 端口已被其他进程占用。

直接验证 Python 入口:

cd /opt/exec-vps-mcp
.venv/bin/python -m unittest -v
.venv/bin/python server.py

手动运行只用于查看即时错误。完成后用 Ctrl+C 停止,再交还 systemd 管理,避免两个进程争用端口。

2. 服务运行,但端口没有监听

检查:

ss -lntp 'sport = :8798'
systemctl show exec-vps-mcp.service -p Environment -p ExecStart -p User

默认预期:

127.0.0.1:8798
User=root
MCP_HOST=127.0.0.1
MCP_PORT=8798

修改 unit 后必须运行:

systemctl daemon-reload
systemctl restart exec-vps-mcp.service

3. 本地 SSH tunnel 连不上

先确认普通 SSH:

ssh root@YOUR_SERVER_IP

再建立 tunnel,并增加诊断输出:

ssh -v -N -L 8798:127.0.0.1:8798 root@YOUR_SERVER_IP

如果提示本地端口占用:

Linux / macOS:

lsof -nP -iTCP:8798 -sTCP:LISTEN

Windows PowerShell:

Get-NetTCPConnection -LocalPort 8798 -State Listen

可以改用本地 18798

ssh -N -L 18798:127.0.0.1:8798 root@YOUR_SERVER_IP

然后同步修改 Codex URL:

url = "http://127.0.0.1:18798/mcp"

不要修改 VPS 服务端口来解决单纯的本地端口冲突。

4. Docker 容器访问不到宿主 MCP

先从真实网络取值:

docker network ls
docker network inspect YOUR_NETWORK

确认:

  • 客户端容器确实加入目标网络;
  • 使用的是该网络的宿主 bridge gateway;
  • MCP service 设置为 MCP_HOST=0.0.0.0
  • UFW 规则允许正确的 bridge、subnet、gateway 和 8798
  • 云厂商安全组没有把 8798 开到公网。

从客户端容器做 TCP/HTTP 探测,但不要携带任何生产凭据:

docker exec YOUR_CONTAINER python -c "import socket; socket.create_connection(('YOUR_BRIDGE_GATEWAY', 8798), 5); print('tcp ok')"

TCP 成功只证明网络可达,不证明 MCP initialize 和工具调用成功。

5. Agent 看不到 MCP server

先用对应客户端的管理命令检查:

codex mcp list
codex mcp --help
claude mcp get exec-vps
opencode mcp list

确认 URL、端口和配置入口属于当前实际运行的客户端。完整配置见 client-setup.md。例如 Codex 配置应位于当前 Codex host 使用的 ~/.codex/config.toml

[mcp_servers.exec-vps]
url = "http://127.0.0.1:8798/mcp"
enabled = true
required = true
enabled_tools = ["exec_vps"]
tool_timeout_sec = 130

Claude Code 应检查当前配置 scope;OpenCode 应确认读取的是当前项目或全局 opencode.json。修改后重启客户端或重新建立 session,不要假设已运行的 Agent 会自动重新加载全部 MCP 配置。

6. server 存在,但 exec_vps 不出现

检查:

  1. enabled_tools 是否拼写为 exec_vps
  2. 当前启动的是否是本仓库的 server.py
  3. systemd 是否仍指向旧目录;
  4. 服务重启后日志是否出现初始化错误;
  5. MCP 客户端是否已经重启并重新获取 tools list。

本地可用 MCP Inspector 检查工具目录:

npx -y @modelcontextprotocol/inspector

在 Inspector 中连接:

http://127.0.0.1:8798/mcp

先确认 tools list,再调用一条无副作用命令并检查结构化返回字段。

7. 工具调用 timeout

有两层 timeout:

exec_vps 参数上限:120 秒
Codex 示例 tool_timeout_sec:130 秒

客户端 timeout 应略大于服务端上限,让服务端有机会返回 timed_out: true 的结构化结果。

timeout 只限制 MCP 调用等待多久,并在超时后终止直接启动的 shell。它不是 sandbox、资源限制或完整的 process-tree containment;fork、后台运行或 daemonize 的后代进程可能继续存在。

如果命令本来需要持续运行,不要简单把 timeout 无限增大。把长期程序交给 systemd、tmux、容器运行时或它自己的 supervisor,再用 exec_vps 查询状态。

8. 结构化结果与输出截断

每次调用都返回同一结构:

{
  "exit_code": 0,
  "stdout": "...",
  "stderr": "...",
  "timed_out": false,
  "truncated": false
}

判断规则:

  • exit_code 始终直接报告 shell 退出状态;如果进程根本没有成功启动,则为 null
  • stdout 和 stderr 都为空时仍返回空字符串,不再用拼接文本代替退出码。
  • 不要只因为 stderr 非空就认定失败;有些程序会把进度或警告写到 stderr,应结合 exit_code 和命令语义判断。
  • stdout 与 stderr 分别最多返回 1 MiB。任一路超限时,truncatedtrue,返回内容只保留各自前 1 MiB。
  • 输出先落到临时文件,再按上限读取;这保护 Python 内存和 MCP response,但不限制命令自身的磁盘、CPU、网络或进程资源。

9. 误把 MCP 暴露到了公网

如果 ss 显示 0.0.0.0:8798,而你没有明确配置私有 Docker bridge 边界:

  1. 先停止 MCP 服务;
  2. 在云厂商安全组关闭公网 8798
  3. 核对 UFW / nftables / iptables;
  4. 把 systemd 中 MCP_HOST 恢复为 127.0.0.1
  5. daemon-reload 并重启服务;
  6. 从另一台公网机器确认 8798 不可达;
  7. 再恢复 SSH tunnel 使用。

命令:

systemctl stop exec-vps-mcp.service
systemctl edit --full exec-vps-mcp.service
systemctl daemon-reload
systemctl start exec-vps-mcp.service
ss -lntp 'sport = :8798'

不要为了恢复连接临时设置 0.0.0.0 后忘记收回。

10. root 命令造成服务异常

如果调用影响了 SSH、网络、防火墙或服务器启动:

  1. 停止继续发送猜测性命令;
  2. 使用云厂商控制台、VNC/串口或救援模式恢复;
  3. 先保存错误信息和被修改文件的元数据;
  4. 从已知备份恢复精确目标;
  5. 验证 SSH 和 MCP 之前,先验证系统基础网络与磁盘;
  6. 记录导致故障的命令和缺少的保护步骤。

这正是为什么 Agent 在修改 SSH、防火墙、网络、数据库和广泛路径前必须停下来与人确认。

11. 最小诊断回执

排查完成后,给人类的回执至少说明:

失败发生在哪一层
观察到的证据
执行了哪些只读检查
修改了哪些文件 / 服务
现在监听在哪个地址
MCP initialize 是否成功
exec_vps 无害调用是否成功
仍有什么风险
怎样回滚

不要用“应该好了”代替真实验证。