1. 从一次真实的 MCP 连接断开说起
如果你在 Claude Code 里配好 MCP 服务器,满心期待地敲下claude,结果终端甩出一行MCP error -32000: Connection closed,那种感觉就像点了一份外卖,骑手到了楼下却告诉你餐洒了。这个报错在 Windows 上尤其高频,我自己第一次配 Playwright MCP 时,JSON 检查了三遍,格式没问题,可就是连不上。
先说清楚这个报错到底是什么。MCP 全称 Model Context Protocol,是 Claude Code 用来连接外部工具服务器的协议。它默认走 stdio 传输,也就是 Claude Code 启动时 fork 一个子进程跑 MCP Server,然后通过这个子进程的标准输入输出做 JSON-RPC 通信。-32000是 JSON-RPC 的错误码,Connection closed表示这条 stdio 通道断了。断的原因只有一个:子进程没能正常启动,或者启动后很快退出了。
这个报错适合谁看?适合所有在 Claude Code 里配过 MCP 但被连接断开卡住的人,尤其是 Windows 用户、用 npx 启动 MCP Server 的人、以及在企业网络环境下折腾依赖的人。它不是一个配置语法错误,JSON 写得再漂亮也可能报,因为问题出在进程启动这一层。
我试过最典型的复现场景是这样的:用claude mcp add-json加了一个 Playwright MCP,命令是npx,参数是包名。加的时候提示 Added,一启动就报 Connection closed。反复重试没用,claude --no-mcp禁用 MCP 后一切正常,说明问题就锁在 MCP 配置上。
排查这个问题的核心思路是:先确认 MCP Server 本身能不能独立跑起来,再确认 Claude Code 调用它的方式对不对。Windows 上npx的调用方式是最容易踩的坑,因为 npm 在 Windows 上是个.cmd脚本,不是直接可执行文件,Claude Code 直接 forknpx往往找不到或启动失败。下面我会把从环境准备到配置修正、再到验证和排障的完整路径拆开讲,每一步都给可复制的命令和配置。
2. 前置准备:TaoToken 接入与 Claude Code 环境确认
在动 MCP 配置之前,得先保证 Claude Code 本身能正常跑起来,并且模型调用链路是通的。我这边习惯用 TaoToken 来做模型接入,它的 API 地址是https://taotoken.net/api,兼容 Anthropic 的接口格式,Claude Code 可以直接对接。官网在https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=,注册后在控制台生成 API Key 就能用。
先确认 Node.js 版本。MCP Server 普遍要求 Node.js 18 以上,Playwright 这类还要更高。跑一下:
node --version npm --version如果低于 18,先去升级。接着确认 Claude Code 装好了:
npm install -g @anthropic-ai/claude-code claude --version然后是模型接入。Claude Code 需要知道用哪个 API 端点、哪个 Key、哪个模型。这几个信息通过环境变量或配置文件注入。我一般用环境变量的方式,干净利落:
export ANTHROPIC_BASE_URL="https://taotoken.net/api" export ANTHROPIC_API_KEY="你的TaoToken密钥" export ANTHROPIC_MODEL="claude-sonnet-4-20250514"Windows 的 PowerShell 里换成:
$env:ANTHROPIC_BASE_URL="https://taotoken.net/api" $env:ANTHROPIC_API_KEY="你的TaoToken密钥" $env:ANTHROPIC_MODEL="claude-sonnet-4-20250514"这里有个细节要注意:Base URL 填https://taotoken.net/api,不要多加路径。Claude Code 会自己拼接/v1/messages这类端点。Key 从 TaoToken 控制台的 API Keys 页面拿,模型 ID 按你实际要用的填。如果你不确定模型 ID 写什么,可以先去模型对话页面试一下,确认能正常返回再填进配置。
环境变量设好后,先别急着配 MCP,单独验证一下 Claude Code 能不能正常对话:
claude -p "说一句话确认连接正常"如果这一步就报错,那问题不在 MCP,而在模型接入。常见的是 401,说明 Key 不对或没生效;也可能是 base URL 拼错。确认这一步通了,再往下走 MCP 配置,排查范围才不会混在一起。
另外,MCP Server 的依赖建议提前装好,别指望 npx 每次现下载。npx 首次运行一个没装过的包会去 registry 拉,网络一抖就超时,进程起不来,Claude Code 那边看到的就是 Connection closed。所以前置准备里,把你要用的 MCP Server 全局装一遍:
npm install -g @executeautomation/playwright-mcp-server npm install -g @upstash/context7-mcp npm install -g @modelcontextprotocol/server-sequential-thinkingPlaywright 还要额外装浏览器二进制:
npx playwright install这一步会下载 Chromium、Firefox、WebKit,体积不小,但装完之后 MCP Server 启动就不会因为缺浏览器而崩。前置准备做扎实,后面排查能省一半时间。
3. 可复制配置:cmd /c 包装 npx 与 settings.json 片段
这一节是重点,直接给能复制粘贴的配置。先说结论:Windows 上配 MCP,command字段不要直接写npx,要写cmd,然后把npx和参数放进args里,用/c开头。这是解决大部分 Connection closed 的关键。
先看错误配置长什么样:
{ "mcpServers": { "playwright": { "command": "npx", "args": ["-y", "@executeautomation/playwright-mcp-server"] } } }这个在 macOS/Linux 上可能能跑,但在 Windows 上大概率报-32000。原因是 Windows 的npx实际是npx.cmd,Claude Code 用child_process.spawn直接调npx时,不会自动走 cmd 解释器,找不到可执行文件,子进程启动失败,stdio 立刻关闭。
正确的 Windows 配置:
{ "mcpServers": { "playwright": { "command": "cmd", "args": ["/c", "npx", "-y", "@executeautomation/playwright-mcp-server"] } } }cmd /c的意思是让 cmd 执行后面的命令然后退出。这样npx就能被正确解析成npx.cmd并运行。多个 MCP Server 一起配的完整片段:
{ "mcpServers": { "playwright": { "command": "cmd", "args": ["/c", "npx", "-y", "@executeautomation/playwright-mcp-server"], "timeout": 60000 }, "context7": { "command": "cmd", "args": ["/c", "npx", "-y", "@upstash/context7-mcp@latest"], "timeout": 60000 }, "sequential-thinking": { "command": "cmd", "args": ["/c", "npx", "-y", "@modelcontextprotocol/server-sequential-thinking"], "timeout": 60000 } } }这个片段放哪?Claude Code 读两个位置:用户级的~/.claude/settings.json,和项目级的.claude/settings.json。Windows 上~对应C:\Users\你的用户名。项目级优先于用户级。我一般把通用的 MCP 放用户级,项目特有的放项目级。
如果你用claude mcp add-json命令加,注意 JSON 要转义。Windows 的 cmd 里转义很烦,建议直接编辑 settings.json 文件,别用命令行加。编辑完保存,重启 Claude Code。
macOS/Linux 的配置就不需要cmd /c,直接:
{ "mcpServers": { "playwright": { "command": "npx", "args": ["-y", "@executeautomation/playwright-mcp-server"], "timeout": 60000 } } }但如果你在 macOS/Linux 上也遇到 Connection closed,可以试试用 node 直接路径启动,跳过 npx 的解析开销。先找到全局安装路径:
npm root -g假设输出/usr/local/lib/node_modules,那 Playwright MCP 的入口是:
{ "mcpServers": { "playwright": { "command": "node", "args": ["/usr/local/lib/node_modules/@executeautomation/playwright-mcp-server/dist/index.js"], "timeout": 60000 } } }Windows 上对应的路径类似C:\Users\你的用户名\AppData\Roaming\npm\node_modules\...,用npm root -g查出来再拼。用 node 直接跑入口文件,省掉了 npx 每次解析包、检查版本的过程,启动更快也更稳。
timeout字段建议都加上,60000 毫秒起步。有些 MCP Server 启动时要初始化浏览器或加载索引,默认超时可能不够,进程还没握手完就被判定失败,报的也是 Connection closed。
配置改完,用claude mcp list确认服务器被识别:
claude mcp list应该能看到你配的服务器名字。如果这里就看不到,说明 settings.json 路径不对或 JSON 有语法错误,先解决这个。
4. 验证请求:手动跑 MCP Server 与 JSON-RPC 握手
配置写对了不代表就能连上,得实际验证。最靠谱的办法是在配进 Claude Code 之前,先手动把 MCP Server 跑起来,看它能不能正常响应 JSON-RPC 请求。
第一步,手动启动 MCP Server:
npx -y @executeautomation/playwright-mcp-server正常的话,进程会停在那里等 stdin 输入,不会立刻退出。如果它秒退或者报错,那问题在 MCP Server 本身,跟 Claude Code 无关。常见的秒退原因:Node 版本不够、缺浏览器二进制、包没装全。
第二步,发一个 initialize 请求测试握手。MCP 协议启动时客户端会先发 initialize,服务器回 capabilities。手动模拟这个流程:
echo '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1}' | npx -y @executeautomation/playwright-mcp-server如果服务器正常,会返回一段 JSON,里面有result和capabilities字段。如果没有任何输出,或者直接报错退出,说明握手失败,Claude Code 那边自然也是 Connection closed。
Windows 的 cmd 里 echo 单引号不认,用 PowerShell:
'{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1}' | npx -y @executeautomation/playwright-mcp-server第三步,确认 Claude Code 侧能连上。启动 Claude Code 时加--debug:
claude --debugdebug 模式会打印 MCP Server 的启动过程、stderr 输出、握手细节。如果连上了,你能看到类似MCP server playwright connected的日志。如果还是报-32000,日志里会显示子进程的退出码和 stderr,这是定位问题的关键信息。
第四步,在 Claude Code 会话里用/mcp命令查看状态:
/mcp它会列出已连接的 MCP Server 和各自注册的工具。如果服务器连上了但工具列表是空的,说明 MCP Server 的tools/list响应有问题,那是服务器实现的事,不是连接问题。
验证通过的标准是:手动跑能等 stdin、initialize 能返回 JSON、Claude Code debug 日志显示 connected、/mcp能看到工具。四个都过,才算真正修好。任何一步卡住,就停在那一步排查,别往下走。
5. 常见报错对照排查:401、local proxy failed、reading choices
排查过程中会遇到几种典型报错,这里逐个对照。先说明,这些报错有的属于模型接入层,有的属于 MCP 层,得分清楚,不然会修错地方。
401 Unauthorized:这个跟 MCP 无关,是模型 API 的鉴权失败。出现它说明 Claude Code 连模型这一步就没过。检查ANTHROPIC_API_KEY是否设置正确、有没有多余空格、Base URL 是不是https://taotoken.net/api。如果 Key 是从 TaoToken 控制台复制的,确认没复制到多余字符。改完环境变量要重开终端或重新 source,不然不生效。
local proxy failed:这个通常出现在你配了本地代理或中转地址,但代理没起来或地址写错。如果你用 TaoToken 的 API 地址,确认写的是https://taotoken.net/api,不要写成带端口或带额外路径的形式。这个报错和 MCP 的-32000是两回事,别混在一起修。
reading choices 相关报错:这类报错一般出现在模型返回体解析阶段,说明请求发出去了、也收到响应了,但响应格式不符合预期。常见于 Base URL 指向了一个不兼容 Anthropic 格式的端点。确认你用的是兼容 Anthropic Messages API 的地址。TaoToken 的 API 是兼容的,直接填https://taotoken.net/api即可。
MCP error -32000: Connection closed:回到本篇主题。对照下面这个表定位:
| 现象 | 可能原因 | 处理 |
|---|---|---|
| Windows 上直接写 npx | 未用 cmd /c 包装 | 改 command 为 cmd,args 加 /c npx |
| 手动跑 MCP Server 秒退 | 依赖缺失或 Node 版本低 | 全局安装依赖,升级 Node 到 18+ |
| Playwright MCP 启动即崩 | 浏览器二进制未装 | 跑 npx playwright install |
| 启动慢后报错 | 默认超时不够 | settings.json 加 timeout 60000 |
| 只有某个 Server 报错 | 该 Server 自身问题 | 单独手动测试该 Server |
| 长时间会话后断开 | 进程被系统回收 | 配 restartOnCrash,定期重启会话 |
OAuth 相关报错:有些远程 MCP Server 走 OAuth 鉴权,本地 stdio 模式下一般用不到。如果你配的是远程 MCP 且报 OAuth 失败,检查 token 是否过期、回调地址是否配对。这类问题跟 stdio 的-32000不是一回事,但排查思路一样:先确认鉴权链路通不通。
排查时有个原则:一次只改一个变量。别同时改配置、升 Node、装依赖,那样即使修好了也不知道是哪个起的作用。改一处,重启 Claude Code,看报错变没变。变了就说明方向对,没变就换下一个。
另外,claude --debug的日志会写到~/.claude/logs/下,文件名带 mcp 前缀。日志里搜ENOENT是命令路径找不到,搜EACCES是权限问题,搜timeout是启动超时,搜Module not found是依赖缺失。这几个关键词能快速缩小范围。
6. 修好之后:把 MCP 接入稳定跑起来
配置修好、验证通过之后,还有几件事能让 MCP 接入更稳。第一,把timeout统一加上,别省这一行。MCP Server 启动涉及进程 fork、依赖加载、协议握手,给 60 秒缓冲很合理。第二,能用 node 直接路径就别用 npx,npx 每次启动都要解析包、检查版本,慢且容易受网络影响。第三,Playwright 这类带浏览器的 MCP,浏览器二进制装一次就行,但换 Node 版本或重装系统后要重装。
如果你还没配 TaoToken 的 Key,去控制台生成一个,接入文档里有各语言的示例。模型对话页面可以先试跑确认模型可用,再填进 Claude Code。长期用 Claude Code 做编码和 Agent 任务的话,Coding Plan 比按量更划算,适合高频调用。
最后留一个我踩过的坑:改完 settings.json 一定要完全退出 Claude Code 再重开,光在会话里重启 MCP 有时不读新配置。Windows 上还要注意路径里的反斜杠,JSON 里要写成双反斜杠\\,或者干脆用正斜杠/,Node 在 Windows 上也认。把这些细节处理好,-32000基本就不会再找上门了。