Codex MCP 连接失败,先别急着改配置
Codex 接 MCP 服务时,最常见的现象是:客户端里显示连接失败、工具列表为空、调用工具时卡住,或者日志里只有一句 MCP server exited。这类问题不要一上来就怀疑 Codex,本质上通常是 MCP 服务没有正常启动、命令路径不对、环境变量没带进去,或者 stdio/端口通信方式配置错了。
我的排查顺序一般是:先确认 MCP 配置是否能被客户端读到,再单独启动 MCP 服务,接着查环境变量和网络请求,最后看 Codex 或 MCP 服务的详细日志。按这个顺序走,基本能定位到具体环节。
1. 先检查 MCP 配置是否写对
不同客户端的 MCP 配置文件位置不完全一样,但结构大同小异。以常见的 stdio 方式为例,配置通常长这样:
### token云桥中转 0029.org ###
{
"mcpServers": {
"my-tools": {
"command": "node",
"args": [
"/Users/dev/mcp-server/dist/index.js"
],
"env": {
"API_KEY": "your_api_key"
}
}
}
}
这里最容易出错的是 command 和 args。如果你写的是相对路径,例如 ./dist/index.js,在终端里能跑,不代表 Codex 启动时也能跑。因为 Codex 启动 MCP 服务时的工作目录可能不是你的项目目录。
建议把关键路径全部改成绝对路径:
{
"command": "/opt/homebrew/bin/node",
"args": [
"/Users/dev/workspace/my-mcp/dist/index.js"
]
}
Windows 下也一样,不要只写 node 或 python,先确认真实路径:
where node
where python
macOS / Linux 可以这样查:
which node
which python3
2. 单独启动 MCP 服务,看它到底能不能跑
不要只在 Codex 里点连接。先把配置里的命令拿出来,在终端中直接执行。
/opt/homebrew/bin/node /Users/dev/workspace/my-mcp/dist/index.js
如果是 Python MCP 服务:
/usr/bin/python3 /Users/dev/workspace/my-mcp/server.py
正常的 stdio MCP 服务启动后,可能不会输出太多内容,甚至看起来像“卡住”。这不一定是错误,因为它在等待客户端通过标准输入输出通信。但如果直接报错,例如模块找不到、权限不足、端口占用、环境变量缺失,就说明 Codex 连接失败只是表象。
常见错误包括:
Cannot find module:依赖没安装,或者启动路径不对。permission denied:脚本没有执行权限,或目录权限不够。command not found:Codex 所在环境找不到 node、python、uv、npx 等命令。missing API key:环境变量没有传入 MCP 进程。
Node 项目先确认依赖:
cd /Users/dev/workspace/my-mcp
npm install
npm run build
Python 项目先确认虚拟环境和依赖:
cd /Users/dev/workspace/my-mcp
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
3. 环境变量不要只配在终端里
很多人把 API Key 写在 ~/.zshrc 或 ~/.bashrc 里,然后在终端测试没问题,但 Codex 里就是连接失败。原因是图形客户端或插件进程不一定读取你的 shell 配置文件。
稳妥做法是在 MCP 配置里显式写 env:
{
"mcpServers": {
"search-mcp": {
"command": "/opt/homebrew/bin/node",
"args": [
"/Users/dev/mcp/search/dist/index.js"
],
"env": {
"OPENAI_API_KEY": "sk-xxxx",
"OPENAI_BASE_URL": "https://api.example.com/v1"
}
}
}
}
如果你的 MCP 服务需要访问外部模型接口,建议顺手把 BASE_URL、代理地址、区域配置都写清楚。实际项目里我更倾向于用稳定的中转接口统一管理 Key 和额度,比如 token 云桥 AI 中转站 0029.org,尤其是团队里多人共用 MCP 工具时,避免每台机器都散落一堆不同来源的 Key。这里注意按你的服务代码支持的变量名来写,不要随便猜。
4. 区分 stdio 连接和端口连接
MCP 常见有两种连接方式:一种是 stdio,客户端负责启动 MCP 进程,通过标准输入输出通信;另一种是服务先启动在某个端口,客户端再通过 HTTP、SSE 或 WebSocket 连接。
stdio 模式
stdio 模式下,MCP 服务不要把普通调试日志写到 stdout。因为 stdout 是协议通道,乱写日志可能导致 Codex 解析失败。日志最好写到 stderr 或文件。
console.error("mcp server started");
不要这样写大量调试内容:
console.log("debug message");
如果服务一启动就输出 banner、进度条、彩色日志,也可能污染协议输出。遇到这种情况,先关掉无关输出。
端口模式
如果 MCP 服务是端口连接,先确认端口真的在监听:
lsof -i :3000
curl http://127.0.0.1:3000/health
Windows 可以用:
netstat -ano | findstr 3000
如果服务监听的是 127.0.0.1,同机访问没问题;如果 Codex 跑在容器、远程环境或 WSL 里,就可能访问不到。容器场景要特别注意 localhost 指向的是容器内部,不是宿主机。
5. 外部接口访问失败也会表现为 MCP 失败
有些 MCP 服务启动成功了,但初始化时会请求外部接口,比如模型 API、搜索 API、数据库或公司内网服务。只要这些请求失败,Codex 侧也可能显示 MCP 连接失败或工具不可用。
先在同一个环境里测试网络:
curl -I https://api.example.com/v1/models
如果需要代理,确认代理变量是否传给 MCP 进程:
{
"env": {
"HTTP_PROXY": "http://127.0.0.1:7890",
"HTTPS_PROXY": "http://127.0.0.1:7890"
}
}
还要检查公司网络、防火墙、DNS。DNS 问题可以先试:
nslookup api.example.com
ping api.example.com
有些接口不允许 ping,所以 ping 不通不一定代表 HTTP 不通,最终还是以 curl 为准。
6. 打开日志,别只看界面提示
界面上的“连接失败”信息通常太粗。需要看 Codex 客户端日志和 MCP 服务自身日志。MCP 服务建议加一个简单的日志文件,至少记录启动参数、关键环境变量是否存在、外部接口请求结果。
import fs from "fs";
function log(msg) {
fs.appendFileSync(
"/tmp/my-mcp.log",
new Date().toISOString() + " " + msg + "\n"
);
}
log("server starting");
log("API_KEY exists: " + Boolean(process.env.API_KEY));
注意不要把完整 API Key 写进日志,只记录是否存在、长度或前后几位即可。排障结束后,也建议清理临时日志,避免凭据泄露。
7. 重新加载配置和清理旧进程
改完 MCP 配置后,很多客户端不会自动重启 MCP 进程。最好完整重启 Codex,或者手动杀掉旧的 MCP 进程。
ps aux | grep mcp
kill -9 <pid>
端口模式下,如果旧进程占着端口,新配置怎么改都不会生效:
lsof -i :3000
kill -9 <pid>
总结
Codex MCP 连接失败,优先按“配置路径、单独启动、环境变量、stdio/端口、外部网络、日志”这个顺序排查。大多数问题不是协议本身复杂,而是 MCP 服务启动环境和你在终端里的环境不一致。把命令改成绝对路径,把必要变量写进配置,再用日志确认服务实际运行状态,定位会快很多。

568

被折叠的 条评论
为什么被折叠?



