Fix VS Code MCP server stdio launches on macOS when Node / pnpm is managed via nvm or fnm.
When you launch VS Code from a GUI (Dock, Spotlight, Finder), it starts as a process whose environment is inherited from launchd — not from your interactive shell. That means none of the PATH modifications that live in ~/.zshrc, ~/.bash_profile, or similar files are applied.
Tools like nvm and fnm work by injecting themselves into your shell session at login:
# typical ~/.zshrc entry for nvm
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"This writes the active Node version's bin/ directory (e.g. ~/.nvm/versions/node/v22.19.0/bin) onto PATH. When VS Code opens a regular terminal it sources your rc file and everything works. But when VS Code spawns an MCP server as a child stdio process it does not source any shell config — the binary is just exec()'d directly.
The result: pnpm (and even node) are not found, and every stdio MCP server fails to start with a cryptic spawn pnpm ENOENT or command not found error.
- macOS intentionally keeps GUI-launched application environments minimal for security and reproducibility reasons.
- VS Code does not source shell profiles when spawning non-terminal child processes (only the integrated terminal does this via a shell login trick).
- npm-managed global tools (like
pnpm dlx) rely on aPATH-resident binary, so there is no stable "default" location to hard-code. - The absolute path of the
pnpmbinary changes every time you switch Node versions with nvm/fnm (e.g.~/.nvm/versions/node/v20.x.x/bin/pnpm→~/.nvm/versions/node/v22.x.x/bin/pnpm).
This is a well-documented pain point across the community:
- microsoft/vscode#70248 — "Terminal: shell integration should source shell profile"
- Dozens of GitHub issues across MCP server repos where users report
spawn pnpm ENOENTon macOS with nvm - The VS Code docs for MCP servers note that you may need to ensure runtimes are on PATH, but don't provide a concrete fix for version-manager users
Because the path is version-specific and changes over time, a one-time hardcode is not enough. The right fix is a script that reads your current nvm/fnm state, resolves the real absolute path, and writes it directly into mcp.json — then you re-run it whenever you switch Node versions.
mcp-mac-setup does exactly this:
- Detects your Node version manager (fnm, nvm, or
PNPM_HOMEfallback). - Resolves the absolute path to the active
pnpmbinary and itsbin/directory. - Rewrites every
stdioserver entry in~/.../Code/User/mcp.jsonso that:commandis the absolute path topnpmenv.PATHis a hardcoded string containing the activebin/directory first
pnpm dlx @kylebrodeur/mcp-mac-setupThen reload VS Code:
Cmd+Shift+P → Developer: Reload Window
All stdio MCP servers in your user-level mcp.json are updated. HTTP/SSE servers are left untouched.
# fix all stdio servers
pnpm dlx @kylebrodeur/mcp-mac-setup
# fix a single server
pnpm dlx @kylebrodeur/mcp-mac-setup --server playwrightpnpm add -g @kylebrodeur/mcp-mac-setup
# then run any time you switch Node versions
mcp-mac-setupgit clone https://github.com/kylebrodeur/mcp-mac-setup.git
cd mcp-mac-setup
node scripts/resolve-pnpm.js| Flag | Description |
|---|---|
| (none) | Update all stdio servers in the user-level mcp.json |
--server <name> |
Update a single named server only |
--target <path> |
Write to a custom file instead of the default mcp.json |
--workspace <path> |
Also read server definitions from a workspace mcp.json |
--install-task |
Install a VS Code tasks.json entry into the current project |
--task-dir <path> |
Combined with --install-task: target a specific .vscode/ directory |
Instead of running the CLI manually, you can install a VS Code task into any project:
# adds a task to your current project's .vscode/tasks.json
pnpm dlx @kylebrodeur/mcp-mac-setup --install-taskThen run it with Cmd+Shift+P → Tasks: Run Task → Fix MCP pnpm path.
The task will also be offered for projects that clone this repo directly (see .vscode/tasks.json).
Re-run mcp-mac-setup after:
- Upgrading your Node version with
nvm use/fnm use - Reinstalling pnpm (e.g. via
corepack enable pnpm) - Any change that moves the
pnpmbinary to a new absolute path
~/.nvm/versions/node/v22.19.0/bin/
├── node ← resolved by reading ~/.nvm/alias/default
└── pnpm ← written into mcp.json as the absolute command
┌─────────────────────────────────────┐
│ ~/.../Code/User/mcp.json (before) │
│ "command": "pnpm" │ ← not found in GUI PATH
└─────────────────────────────────────┘
│ mcp-mac-setup
▼
┌──────────────────────────────────────────────────────────┐
│ ~/.../Code/User/mcp.json (after) │
│ "command": "/Users/you/.nvm/versions/node/v22.19.0/ │
│ bin/pnpm" │
│ "env": { "PATH": "/Users/you/.nvm/…/bin:~/Library/pnpm:│
│ /usr/local/bin:/usr/bin:/bin" } │
└──────────────────────────────────────────────────────────┘
Detection priority:
- fnm — checks
~/.local/share/fnm/aliases/default/bin/ - nvm — reads
~/.nvm/alias/defaultto get the active version - PNPM_HOME /
which pnpm— last-resort fallback (warns if used)
- macOS (Linux is supported but the PATH problem is less common there)
- Node ≥ 18
- nvm or fnm managing your Node installation (fallback works for other setups)
- VS Code with MCP server support (GitHub Copilot or Copilot Chat)
Issues and PRs welcome at github.com/kylebrodeur/mcp-mac-setup.