学 MCP 的时候,真正让人卡住的不是写 Server,而是配置好之后客户端界面直接弹连接失败。最近把 Codex 的 Base URL 指到 TaoToken 之后,这套排查顺序顺了很多。Claude Desktop 当时只给一句连接失败,没有更多细节,于是只能挨个试:先把相对路径改成绝对路径,再查 Python 版本,最后才想到去看日志。现在模型调用先通了,Codex 就能读 claude_desktop_config.json 和 MCP Server 的启动日志,按日志里实际抛出的内容做判断,而不是靠猜路径写法。整个过程用到的 API Key 从落地页创建,填进工具的 Base URL 只有 https://taotoken.net/api 一个。
1. 卡住的那步:claude_desktop_config.json 配好,界面提示连接失败
1.1 失败现场
按常见的配置模板写好 claude_desktop_config.json 后重启客户端,MCP Server 名字出现在列表里,但状态一直是连接失败。Claude Desktop 的提示非常简短,不会告诉你是因为 args 里用了相对路径,还是 Python 版本不够,又或者是 server.py 在 import 阶段就抛了异常。没有日志的情况下,排障只能靠试:改路径、换版本,甚至把 SDK 重装一遍,每改一次都要重启一次客户端,效率很低。
1.2 为什么用 Codex 而不是继续盯配置面板
Claude Desktop 的界面只消费 MCP Server 的状态,不给你展开 stderr。Codex 却可以直接读文件、看配置、对比日志。问题是 Codex 自己也需要一条稳定的模型通道,如果官方入口额度不够,排查会中途断在认证上。把 Codex 的模型调用先接通,它就变成一个能读 claude_desktop_config.json、能帮你总结日志的排查助手,而不是只会「再重启一次试试」的黑盒。
1.3 TaoToken 在这条排障链路里的位置
TaoToken 在这里的角色是统一接入通道,让 Codex 的模型请求可以正常完成,仅此而已。MCP Server 本身是本地 stdio 进程,它不经过 TaoToken;Claude Desktop 和 MCP Server 之间的 JSON-RPC 也照常走本地管道。把这两件事分开想,后面排查会很清晰:模型通道负责 Codex 能不能回答,MCP Server 的日志负责告诉 Codex 到底哪里失败,两者互不干扰。配置出问题时,也不会出现「模型通道的问题伪装成 MCP 问题」的干扰项。
2. 拿到 Key 后,先把 Codex 的 Base URL 指到 TaoToken
2.1 创建 API Key
打开 TaoToken 注册并登录,进入控制台创建一个 API Key。复制出来的字符串统一用 YOUR_API_KEY 代替,不要随手贴进聊天记录。模型 ID 先不用记,等配置 Codex 时,从模型广场当时的列表里复制一个就行,以页面显示为准。
2.2 编辑 ~/.codex/config.toml
Codex CLI 的供应商配置在 ~/.codex/config.toml,修改 model_provider 和 base_url 两处:
model = "YOUR_MODEL_ID" # 从 TaoToken 模型广场复制 model_provider = "taotoken" [model_providers.taotoken] name = "TaoToken" base_url = "https://taotoken.net/api" env_key = "OPENAI_API_KEY"再把 Key 放进环境变量:
export OPENAI_API_KEY="YOUR_API_KEY"macOS/Linux 写进 ~/.zshrc 或 ~/.bashrc;Windows 在系统环境变量里新建。设置完重新打开终端再生效。
注意:base_url 只填 https://taotoken.net/api,末尾不要加 /v1,更不要填官网落地页。落地页管账号、Key、模型广场和用量,不进配置文件。
2.3 验证通路
在项目目录下运行 codex,输入:「读一下 server.py,告诉我这个 MCP Server 注册了哪些 Tools。」如果 Codex 能列出 list_files 或你实际注册的名字,说明模型调用已经通了。此时不要急着让它改文件,先回到排障主线上:我们还需要一个稳定复现的失败现场。
3. 复现连接失败:args 里的相对路径如何变成绝对路径
3.1 相对路径为什么会让 Server 起不来
我第一次记下的失败配置长这样:
{ "mcpServers": { "demo-server": { "command": "python", "args": ["./server.py"] } } }客户端启动子进程时,工作目录不一定是你的项目目录。相对路径 ./server.py 在那个工作目录里找不到文件,MCP Server 进程起不来,界面就报连接失败。把这段配置原样写回去,重启客户端,就能稳定复现同一个错误。排障最难的是没有稳定的失败现场,而这段配置可以随时给你一个。
3.2 绝对路径和 Windows 格式要注意的细节
解决办法是给 args 绝对路径:
{ "mcpServers": { "demo-server": { "command": "python", "args": ["D:/workspace/mcp_demo/server.py"] } } }Windows 路径建议用正斜杠。JSON 字符串里如果写成 D:\workspace,反斜杠会被当成转义符,等于给自己埋雷。用 D:/workspace/... 最简洁,也不会触发转义问题。
3.3 让 Codex 先读配置再动手
改配置之前,让 Codex 先做一次检查。把 claude_desktop_config.json 的完整路径告诉它,例如 D:/workspace/mcp_demo/claude_desktop_config.json,然后输入:
「读取这个配置文件,检查 mcpServers 下每个 server 的 command 和 args 是否都用了绝对路径,列出相对路径和 JSON 转义风险点。」
Codex 会逐项返回检查结果。注意,这一步它只是读文件文本并做判断,真正修改文件还是你自己来。这样做的价值在于:以后每次遇到连接失败,你会先让它读配置,而不是凭记忆去猜哪一行写错。读完配置还是定位不到,就进第 4 节看日志。
4. 看 stderr 和 Inspector 日志,让 Codex 定位启动失败根因
4.1 在终端直接启动 server.py
改完路径依然失败的话,不要继续改 JSON,直接在项目目录跑一次:
python server.py正常的 stdio server 启动后不会有任何提示,只是挂在那里等待输入;如果有 import 错误、语法错误或者 SDK 版本不匹配,stderr 会立刻把完整堆栈打出来。把这段报错原样贴回 Codex,附上 server.py 开头几行 import,它就能判断是依赖缺失、Python 版本问题,还是路径本身没生效。
4.2 把日志输出加进 server.py
如果客户端能连上,但工具列表是空的,在 server.py 顶部加一行日志配置:
import logging logging.basicConfig(level=logging.DEBUG)重新启动后,日志会显示 JSON-RPC 的 initialize 握手、list_tools 调用等过程。Codex 根据日志里 failed to handle request 这类关键输出缩小范围。日志的作用是把「看不见的协议通信」变成「可以贴回对话的文本」。
4.3 Python 版本不兼容也别忽略
MCP 官方 SDK 需要 Python 3.10 以上。先确认版本:
python --version如果本机默认 Python 是 3.9,SDK 可能导入失败或运行时报 TypeError。用 pyenv 切一个高版本再试:
pyenv install 3.11 pyenv local 3.11这些命令改的是你本机环境,请自己在终端执行,跑完把结果贴回 Codex,让它继续分析。
4.4 Codex 如何对照日志输出
把 stderr 或 Inspector 面板里的错误文本完整贴给 Codex,最好连 server.py 的关键函数一起给它。它会结合堆栈信息定位到具体代码行,然后给你两条路:改代码还是改配置。这条通道在这里的贡献,是让 Codex 的模型调用保持稳定,排查过程不会因为官方入口额度中断而停在半路。
5. 注册成功后,用 Codex 对照 Resources 和 Tools 列表
5.1 MCP 三要素:Resources、Tools、Prompts
MCP 三个核心概念需要分清。Resources 是只读数据,比如文件内容、配置、查询结果;Tools 是可以执行的操作,比如 list_files、write_file;Prompts 是可复用的提示模板。对一个文件类 MCP Server 来说,Resources 暴露文件 URI,Tools 暴露操作入口,客户端通过 list_tools 拿到工具清单。这里写一个最小例子,帮助你理解 list_tools 长什么样:
from mcp.server import Server from mcp.server.stdio import stdio_server from mcp.types import Tool server = Server("demo-server") @server.list_tools() async def list_tools(): return [ Tool( name="list_files", description="List files in the current directory", inputSchema={"type": "object", "properties": {}}, ) ]当 server.py 里只有这个 list_tools 时,成功注册后,客户端或 Inspector 里应该能看到一个叫 list_files 的 Tool。
5.2 注册成功后能看到什么
配置正确并且启动成功后,客户端会调用 list_tools,工具列表里出现 server.py 中注册的名字。启动 Inspector 用 npx @modelcontextprotocol/inspector python server.py,Tools 和 Resources 是两个独立标签。Codex 可以读 server.py,帮你把 @server.list_tools() 注册的名字和 Inspector 里显示的名字逐项对照,避免出现「代码里叫 list_files,界面里显示的是另一个名字」这种错位。这一步不需要重启客户端,Codex 直接比较两份文本就能给出结论。
5.3 把成功状态保存成 mcp-baseline.md
排障最怕没有参照物。把 Inspector 里 Tools 的名字、Resources 的 URI 前缀复制到项目下的 mcp-baseline.md。下次再报连接失败,让 Codex 读这个基线文件对比:「这次 list_tools 返回空,上次基线里有两个工具,差异在哪里。」这就把经验从「我记得好像改过路径」变成「文件里有白纸黑字的成功状态」。
6. 把排障步骤沉淀成可复现的调试清单
6.1 五步调试清单
- 检查 claude_desktop_config.json:command 和 args 是否都是绝对路径,JSON 转义是否正确。
- 在项目目录运行 python server.py:观察 stderr,有报错就原样贴给 Codex。
- 在 server.py 加 logging:重启客户端,看 JSON-RPC 握手日志。
- 确认 Python 版本高于 3.10,必要时用 pyenv 切换。
- 启动成功后用 Inspector 导出 Tools/Resources,保存为 mcp-baseline.md。
这套清单不依赖具体模型品牌,换到哪台机器都能用。Codex 的任务是每一步都给你检查结果和判断依据,真正执行命令的是你自己。
6.2 再遇到连接失败时的判断顺序
先看第 2 步的 stderr,再看第 3 步的日志,最后才动路径。很多连接失败在终端一启动就已经明确了原因,根本不需要反复改配置。Codex 的模型通路打通之后,MCP 学习可以从「配置靠猜」进入「按日志归因」的阶段。整套流程里,Key 统一从 https://taotoken.net/?utm_source=taotoken_aicg_blog_end 创建,模型 ID 也以模型广场当前列表为准。
配置保存后,先在 TaoToken 模型对话 里用同一把 Key 发一条测试消息,确认模型 ID 和 Base URL 没填错。接下来要长期写代码的话,可以打开 Coding Plan 看套餐够不够;Key 在 控制台 API Keys 创建。以后回到 Claude Code、CC Switch 这类工具,也可以对照 Claude Code 接入文档 里的 Base URL 写法。