MCP 配置为什么手动跑没问题、客户端一起就挂?工作目录和环境变量两个坑

2026-08-08

配 MCP 时最让人怀疑人生的一种情况是:

你把配置里那条命令复制到终端里跑,一切正常;让客户端去拉,就是起不来。

于是你开始怀疑配置文件写错了、怀疑客户端有 bug、怀疑自己眼花。实际上,官方调试文档里明确写了两个原因,任何一个都能造成这种现象。

一、坑一:工作目录可能是未定义的

官方原话说得很直接:客户端启动 stdio 服务时,服务的工作目录可能是未定义的——在 macOS 上可能就是 /,因为客户端本身可能是从任何地方被启动的。

你在终端里手动跑的时候,工作目录是你当前所在的目录

这个差别的后果是:所有相对路径的含义都变了。

你写的 ./data,手动跑时指向你项目里的 data 目录,客户端拉起来时可能指向文件系统根目录下的 data——那个大概率不存在。

官方给的正确写法

配置和 .env 里一律用绝对路径。 官方给的正例:

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/username/data"
      ]
    }
  }
}

而不是 ./data 这样的相对写法。

command 本身也建议用绝对路径。 官方在讲启动失败的「路径问题」时给的建议就是:试试给 command 用绝对路径。

为什么 command 也要绝对路径

因为 command 的解析依赖 PATH 环境变量——而这正好引出第二个坑。

二、坑二:环境变量只继承一个有限子集

官方说明:通过 stdio 启动的 MCP 服务,只会自动继承一部分环境变量,具体是哪些跟平台有关。

这句话的杀伤力很大,因为它意味着:

  • 你 shell 里 export 的 API key,服务端进程可能读不到
  • 你在 .zshrc 里配的 PATH可能没完整传下去
  • 你用 nvm、pyenv 这类版本管理工具设置的环境,可能整个不生效

于是服务端进程要么找不到命令(command 解析失败),要么起来了但初始化时因为缺 key 而抛错退出。

这两种表现在客户端侧看到的都是「连接关闭」或者「进程提前退出」,完全看不出跟环境变量有关。

官方给的做法

在配置里显式写 env 键:

{
  "mcpServers": {
    "myserver": {
      "command": "mcp-server-myapp",
      "env": {
        "MYAPP_API_KEY": "some_key"
      }
    }
  }
}

需要什么就显式写什么,别指望继承。

三、一个真实案例:npx 找不到

modelcontextprotocol/servers 仓库的 issue #1097(已关闭)标题是:

GitHub MCP Server Fails to Start: 'npx' Command Error and Connection Closed (-32000)

报错编号是 -32000 连接关闭,真因是 npx 这个命令在那个环境下跑不通。

这正是上面两个坑叠加的典型结果:npx 通常靠 PATH 找到,而 PATH 可能没完整传给服务端进程。你在终端里能跑 npx,是因为你的 shell 配置生效了;客户端拉起来的进程不一定有那份配置。

同一个仓库的 issue #891(已关闭)标题更直白:Fix 'Client Closed' Error by Correcting npm Config——也是 npm 配置层面导致的启动失败。

两条 issue 指向同一个教训:客户端报的是连接层的现象,真因在进程启动层。

四、自查方法:模拟客户端的环境

既然问题是「你的终端环境 ≠ 客户端拉起来的环境」,那自查的关键就是尽量模拟后者

第一,用绝对路径跑一遍。

把配置里的 command 换成绝对路径试试。先找到它在哪:

which npx

(Windows:where npx

然后用那个完整路径去跑。如果绝对路径能跑通、命令名跑不通,那就锁定是 PATH 的问题。

第二,在一个干净的环境里跑。

尽量去掉你 shell 的个性化配置,看还能不能跑。能跑,说明不依赖你的 shell 配置;不能跑,说明依赖,那就要在 env 里补齐。

第三,从一个不相干的目录跑。

cd / 然后用绝对路径跑那条命令。这最接近客户端的处境(工作目录未定义、可能是根目录)。跑通了,说明不依赖工作目录。

这三条做完,基本能覆盖本文说的两个坑。

五、官方对启动失败的三分类

官方调试文档把启动失败归成三类,排查时可以照着对:

1. 路径问题

  • 服务端可执行文件路径不对
  • 缺必需的文件
  • 权限问题
  • 建议给 command 用绝对路径

2. 配置错误

  • JSON 语法错误
  • 缺必填字段
  • 类型不匹配

3. 环境问题

  • 缺环境变量
  • 变量值不对
  • 权限限制

第 2 类最容易自查——JSON 语法错误可以直接用工具验。如果你的系统上有 python:

python -m json.tool 你的配置文件路径 > /dev/null && echo OK

输出 OK 就是合法 JSON。这一步花几秒,能排除掉一整类问题。

六、一条排查路径

  1. 验 JSON 合法性(几秒钟,先排除掉配置错误这一类)
  2. 把所有相对路径改成绝对路径——包括 command 和参数里的路径
  3. 需要的环境变量显式写进 env,别指望继承
  4. 在干净环境 + 不相干目录下手动跑一遍那条命令,模拟客户端的处境
  5. 完全退出客户端再打开(Claude Desktop 只关窗口不算)
  6. 看日志(macOS ~/Library/Logs/Claude,Windows %APPDATA%\Claude\logs),确认服务端进程有没有启动记录
  7. 还不行就用 MCP Inspector 单独测,把客户端这一层摘出去

前三步能解决掉大多数「手动跑没问题、客户端起不来」的情况。

七、几条能一次性避开的习惯

  • 配置里永远写绝对路径,无一例外。省下的是每次换机器、换目录都要重排一遍的时间
  • 需要的环境变量都写进 env,哪怕你确定 shell 里有——显式写一遍的成本是几秒,靠继承出问题的排查成本是几十分钟
  • 改完配置随手验一下 JSON
  • 写配置时就假设「工作目录是根目录、环境变量什么都没有」,按这个前提写出来的配置最稳

八、版本管理工具是重灾区

用 nvm、fnm、pyenv、rbenv 这类版本管理工具的人,撞上本文这两个坑的概率特别高。值得单独说。

这类工具的工作方式,基本都是在你的 shell 配置里注入一段初始化脚本,运行时改写 PATH,把当前选中的版本指到前面。

问题在于:那段初始化脚本只在你的交互式 shell 里跑。 客户端拉起 MCP 服务端进程时,走的不是你的交互式 shell——于是:

  • nodepython 可能指向系统自带的老版本
  • 或者干脆找不到
  • 你用 npm install -g 装的包,装在版本管理工具管理的目录下,那个目录不在服务端进程的 PATH

表现就是:你在终端里 node -v 显示 20.x,服务端进程那边可能是 12.x 或者根本没有。

排查方法:

which node
which npx

拿到的是不是版本管理工具目录下的路径?如果是,那就把那个绝对路径写进配置,别依赖 PATH 解析。

配置里可以直接写完整路径:

{
  "mcpServers": {
    "myserver": {
      "command": "/绝对路径/到/node",
      "args": ["/绝对路径/到/server.js"]
    }
  }
}

代价是换 Node 版本时要改配置——但比每次都排查半天强。

九、写配置时的一个心法

把本文的两个坑合起来,可以总结成一句写配置时的假设:

假设服务端进程启动时,工作目录是根目录,环境变量近乎为空。

按这个假设写出来的配置,具备两个性质:

  • 所有路径都是绝对的,不依赖工作目录
  • 需要的环境变量都显式声明,不依赖继承

这样的配置在你的机器上能跑,在同事的机器上、在换了客户端之后、在换了目录之后,也大概率能跑。

反过来,靠继承和相对路径写出来的配置,能不能跑取决于运气——取决于那台机器的 shell 怎么配的、客户端从哪启动的。它在你这里能跑,恰恰是最误导人的信号。

十、总结

  • 「手动跑没问题、客户端起不来」的两个官方原因:工作目录可能未定义(macOS 上可能是 /)、环境变量只继承有限子集
  • 配置和 .env 里一律用绝对路径command 本身也建议用绝对路径。
  • 需要的环境变量显式写进配置的 env
  • issue #1097 那条 -32000 Connection closed 的真因是 npx 跑不通——客户端报连接层现象,真因在启动层
  • 自查靠模拟客户端环境:绝对路径 + 干净环境 + 不相干目录。
  • 官方的启动失败三分类:路径问题、配置错误、环境问题。其中 JSON 语法可以几秒钟验掉。

本文所引官方内容来自 Model Context Protocol 官方调试文档,issue 编号来自 modelcontextprotocol/servers 仓库,核对日 2026-08-08。

相关阅读

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。