KBCodeKB

Fix MCP Servers Not Working with NVM/npx (ENOENT/-32000) in Claude Desktop, Cursor, and Cline

When using NVM (Node Version Manager), MCP servers fail to connect from GUI applications like Claude Desktop, Cursor, and Cline. The root cause is that GUI apps spawn child processes via spawn() with shell: false, so NVM's shell functions (which resolve node/npx) are unavailable. Symptoms include silent connection failures, 'Client Closed', ENOENT errors, and -32000 'Connection closed'. This affects all major Node version managers (nvm, fnm, Volta, n, nodenv, proto, mise) across macOS, Windows, and Linux. Seven verified workarounds are provided — from simple PATH injection to full version manager migration — ordered by complexity. 91 comments and 182 reactions on the official modelcontextprotocol/servers repo confirm this is a widespread issue affecting thousands of MCP users.

Symptoms

  • MCP servers silently fail to connect in Claude Desktop, showing no tools in the UI — check ~/Library/Logs/Claude/mcp-server-*.log on macOS
  • Spawn node ENOENT error in MCP server logs: 'Error: spawn node ENOENT' with errno: -2 and syscall: 'spawn node'
  • MCP error -32000: Connection closed when configuring servers with npx command in claude_desktop_config.json
  • 'Client Closed' error in Cursor MCP configuration (~/.cursor/mcp.log) despite npx commands working in terminal
  • MCP server starts (logs show 'Server started and connected successfully') but tools never appear in client UI
  • npx returns 'ERROR: You must supply a command' when invoked from GUI app context — indicates PATH resolution failure
  • npm ERR! Invalid dependency type requested: alias — caused by incompatible npm version from old NVM Node install

Error signatures

spawn node ENOENT
MCP error -32000: Connection closed
Client Closed
Error: Cannot find module
EPIPE
npm ERR! Invalid dependency type requested: alias
ENOENT at Process.ChildProcess._handle.onexit
spawn /Users/.../node ENOENT

Possible causes

  • GUI applications (Electron-based) spawn child processes with shell: false, so NVM's shell function that resolves node/npx is completely bypassed — npx is not found on PATH
  • Claude Desktop picks the lowest (oldest) Node version from ~/.nvm/versions/node/ directory instead of the active/default version — observed via which-node diagnostic MCP server technique
  • The PATH environment variable in GUI-launched processes doesn't include NVM's version-specific bin directory (e.g., ~/.nvm/versions/node/v22.11.0/bin) — confirmed by env-injection workaround fixing the issue
  • NVM installs node/npx as shell functions in ~/.zshrc or ~/.bashrc, which are only sourced by interactive shell sessions, not by Node's child_process.spawn() with default options
  • Multiple Node versions installed via NVM cause CLI tools to resolve to an incompatible version (e.g., v12 picked when MCP server requires >= 18, or npm from v12 rejecting 'alias' dependency type)
  • npx in a bundled/Electron environment also requires /bin on PATH for shell commands (sh, which, etc.) it invokes internally — providing only node's bin directory is insufficient

Solutions

Remove Old Node Versions (Quick Diagnostic Solver)

risk: lowgithubpending_review

Claude Desktop and other Electron apps sometimes pick the lowest (oldest) Node version from the ~/.nvm/versions/node/ directory instead of the active one. Removing unused old versions forces resolution to the remaining compatible version. This is a quick diagnostic step — not a permanent fix.

  1. List all installed Node versions: `nvm list`
  2. Identify old/unused versions (e.g., v12, v14, v16 when using v22)
  3. Remove old versions: `nvm uninstall <version>`
  4. Restart Claude Desktop and verify MCP servers connect

Commands

nvm list  # shows all installed versions with 'default' marked
# Identify which versions to remove (keep only compatible ones >=18):
nvm list | grep -E 'v1[0-7]\.'  # find old versions
nvm uninstall 12.22.0
nvm uninstall 14.21.0
# Verify remaining versions:
ls ~/.nvm/versions/node/

Risks

  • Destructive — removes Node versions that other projects may depend on via .nvmrc files
  • Temporary fix only; issue may recur when new versions are installed and Claude picks the wrong one again
  • Better used as a diagnostic: if removing old versions fixes it, you've confirmed the root cause and should implement one of the permanent solutions above

Verification

  • Run `ls ~/.nvm/versions/node/` → expect only compatible Node versions remain (e.g., v22.14.0 only)
  • Restart client after cleanup, tail logs: `tail -f ~/Library/Logs/Claude/mcp-server-*.log` → expect 'Server started and connected successfully' for all configured MCP servers with no ENOENT errors
  • If issue persists after removing old versions, the problem is not version selection — proceed to the env.PATH or wrapper script solutions
0 verified0 failed

Global Install + Absolute Node Path (Most Robust, Bypasses npx Entirely)

risk: lowgithubpending_review

Install the MCP server package globally via npm, then use the absolute path to both the Node binary and the globally installed server's entry point (dist/index.js). This completely bypasses npx, NVM resolution, and PATH issues. Recommended for production/stable setups.

  1. Install the MCP server globally: `npm install -g <package>@latest`
  2. Find your Node binary path: `which node` or `nvm which node`
  3. Find the globally installed server entry point: use `npm root -g` then append `/package-name/dist/index.js`
  4. Use absolute paths for both command and args in your MCP config

Commands

npm install -g @modelcontextprotocol/server-filesystem
# Find node binary path:
which node  # or: nvm which node
# Find global module entry point:
npm root -g  # e.g., /Users/user/.nvm/versions/node/v22.11.0/lib/node_modules
ls $(npm root -g)/@modelcontextprotocol/server-filesystem/dist/index.js  # verify exists
# One-liner to generate the path:
echo $(npm root -g)/@modelcontextprotocol/server-filesystem/dist/index.js

Config examples

// macOS with NVM
{
  "mcpServers": {
    "puppeteer": {
      "command": "/Users/username/.nvm/versions/node/v22.11.0/bin/node",
      "args": [
        "/Users/username/.nvm/versions/node/v22.11.0/lib/node_modules/@modelcontextprotocol/server-puppeteer/dist/index.js"
      ]
    }
  }
}
// Windows with nvm-windows (nvm4w) — 2026 verified fix
{
  "mcpServers": {
    "memory": {
      "command": "C:\\nvm4w\\nodejs\\node.exe",
      "args": [
        "C:/Users/USERNAME/AppData/Roaming/npm/node_modules/@modelcontextprotocol/server-memory/dist/index.js"
      ]
    }
  }
}

Risks

  • Global installs require manual updates (`npm update -g <package>`) when new versions are released
  • Path must be updated when Node version changes (the version number is in the path)
  • Some MCP servers have entry points at different locations — check package.json 'main' field if dist/index.js doesn't exist

Verification

  • Run the full command manually: `/Users/user/.nvm/versions/node/v22.11.0/bin/node /Users/user/.nvm/versions/node/v22.11.0/lib/node_modules/@modelcontextprotocol/server-puppeteer/dist/index.js` → expect server initialization log output
  • Verify global install: `npm list -g --depth=0 | grep modelcontextprotocol` → expect package listed with version number
  • Restart client, tail logs: `tail -f ~/Library/Logs/Claude/mcp-server-puppeteer.log` → expect 'Server started and connected successfully'
  • Test functionality: ask Claude to 'take a screenshot of example.com' (for puppeteer) → expect MCP tool executes successfully
0 verified0 failed

Bash -c with nvm use (Source NVM Before Running npx, Version-Pinned)

risk: lowgithubpending_review

Use bash -c to first source nvm.sh and explicitly set the Node version with nvm use before running npx. This properly loads the NVM environment and allows specifying the exact Node version — useful when different MCP servers need different Node versions.

  1. Set command to 'bash' in your MCP config
  2. Use args: ['-c', 'source $HOME/.nvm/nvm.sh && nvm use --silent <version> && npx -y <package>']
  3. Test the full command manually first
  4. Restart the MCP client

Commands

# Verify nvm.sh exists:
ls $NVM_DIR/nvm.sh || ls $HOME/.nvm/nvm.sh
# Test the command manually:
bash -c 'source $HOME/.nvm/nvm.sh && nvm use --silent 22 && npx -y @modelcontextprotocol/server-filesystem ~/Desktop'
# For fnm equivalent:
bash -c 'export PATH="$HOME/.local/share/fnm/aliases/default/bin:$PATH" && npx -y @modelcontextprotocol/server-filesystem ~/Desktop'

Config examples

// NVM with explicit version pinning
{
  "mcpServers": {
    "desktop-commander": {
      "command": "bash",
      "args": [
        "-c",
        "source $HOME/.nvm/nvm.sh && nvm use --silent 23 && npx -y @wonderwhy-er/desktop-commander"
      ]
    },
    "filesystem": {
      "command": "bash",
      "args": [
        "-c",
        "export PATH=/Users/user/.nvm/versions/node/v22.14.0/bin:$PATH && npx -y @modelcontextprotocol/server-filesystem /Users/user/Code"
      ]
    }
  }
}
// Windows with nvm-windows (use cmd /c):
{
  "mcpServers": {
    "playwright": {
      "command": "cmd",
      "args": ["/c", "npx -y @playwright/mcp@latest"]
    }
  }
}

Risks

  • Slightly slower startup (200-500ms) due to sourcing nvm.sh on each connection — negligible in practice
  • Bash must be available (standard on macOS/Linux; on Windows use Git Bash or WSL)

Verification

  • Run the full bash -c command manually in terminal → expect MCP server outputs startup log 'Secure MCP Filesystem Server running on stdio' without npm errors
  • Check client MCP logs: `tail -20 ~/Library/Logs/Claude/mcp-server-desktop-commander.log` → expect 'Server started and connected successfully' and no ENOENT or EPIPE errors
  • In Claude Desktop, ask Claude to 'list files in the allowed directory' → expect MCP tool call succeeds and returns directory listing
0 verified0 failed

Wrapper Script for npx with NVM Environment (npx-for-claude, Survives Version Changes)

risk: lowgithubpending_review

Create a shell script at /usr/local/bin that sources your shell profile or sets up NVM's PATH before executing npx. This survives Node version changes by auto-detecting the latest version. Works with nvm, fnm, and Volta.

  1. Create file /usr/local/bin/npx-for-claude with your preferred approach (explicit PATH, auto-detect latest, or source .zshrc)
  2. Make it executable with chmod +x
  3. Use 'npx-for-claude' as the command in your MCP config
  4. Verify the script works by running it from terminal first

Commands

# Auto-detect latest NVM version (recommended — survives version changes):
cat > /usr/local/bin/npx-for-claude << 'SCRIPT_EOF'
#!/usr/bin/env bash
NODE_VERSIONS_DIR="$HOME/.nvm/versions/node"
LATEST_NODE_VERSION=$(ls -v "$NODE_VERSIONS_DIR" 2>/dev/null | grep "^v" | sort -V | tail -n 1)
if [ -n "$LATEST_NODE_VERSION" ]; then
  export PATH="$NODE_VERSIONS_DIR/$LATEST_NODE_VERSION/bin:$PATH"
fi
exec npx "$@"
SCRIPT_EOF
chmod +x /usr/local/bin/npx-for-claude
# For fnm wrapper:
cat > /usr/local/bin/npx-for-claude << 'EOF'
#!/usr/bin/env bash
fnm exec --using=default npx "$@"
EOF
chmod +x /usr/local/bin/npx-for-claude
# Verify the script:
/usr/local/bin/npx-for-claude --version

Config examples

// Use npx-for-claude wrapper (works with all npx-based MCP servers)
{
  "mcpServers": {
    "filesystem": {
      "command": "npx-for-claude",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/dir"]
    },
    "brave-search": {
      "command": "npx-for-claude",
      "args": ["-y", "@modelcontextprotocol/server-brave-search"],
      "env": {
        "BRAVE_API_KEY": "your-key-here"
      }
    }
  }
}
// zsh users — source .zshrc variant
cat > /usr/local/bin/npx-for-claude << 'EOF'
#!/bin/zsh
source ~/.zshrc 2>/dev/null
exec npx "$@"
EOF
chmod +x /usr/local/bin/npx-for-claude

Risks

  • Script at /usr/local/bin may require sudo on some systems — use `sudo tee` instead of `cat >`
  • The 'source ~/.zshrc' variant may be slow if .zshrc initializes large frameworks (oh-my-zsh, etc.) — prefer the explicit PATH version for performance

Verification

  • Run `/usr/local/bin/npx-for-claude -y @modelcontextprotocol/server-filesystem ~/Desktop` → expect server startup message 'Secure MCP Filesystem Server running on stdio'
  • Run `which npx-for-claude` → expect `/usr/local/bin/npx-for-claude`
  • Restart client and tail logs: `tail -f ~/Library/Logs/Claude/mcp-server-filesystem.log` → expect 'Server started and connected successfully' and tool listing output
  • After restart, verify tools: click hammer icon → expect MCP tools listed and functional
0 verified0 failed

Use Absolute Path to npx in Version Manager Directory (Simplest No-Config Change)

risk: lowgithubpending_review

Bypass NVM's shell function entirely by using the absolute path to the npx binary inside the NVM versions directory. This works identically for fnm, Volta, n, nodenv, and proto.

  1. Find your active Node version: run `node -v`
  2. Locate the npx binary: `ls ~/.nvm/versions/node/$(node -v)/bin/npx`
  3. Replace 'npx' in your MCP config command with the absolute path
  4. Restart your MCP client

Commands

node -v  # e.g., v22.14.0
ls ~/.nvm/versions/node/v22.14.0/bin/npx  # confirm npx exists
# For fnm:
ls ~/.local/share/fnm/node-versions/v22.14.0/installation/bin/npx
# For Volta:
volta which node  # get full path
# For n:
which npx  # /usr/local/bin/npx (n installs to /usr/local)

Config examples

// NVM on macOS
{
  "mcpServers": {
    "filesystem": {
      "command": "/Users/username/.nvm/versions/node/v22.14.0/bin/npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/username/Desktop"
      ]
    }
  }
}
// fnm on macOS
{
  "mcpServers": {
    "filesystem": {
      "command": "/Users/username/.local/share/fnm/node-versions/v22.14.0/installation/bin/npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path"]
    }
  }
}
// Volta on macOS
{
  "mcpServers": {
    "figma-mcp": {
      "command": "/Users/username/.volta/bin/npx",
      "args": ["-y", "figma-mcp"]
    }
  }
}
// nvm-windows (nvm4w)
{
  "mcpServers": {
    "memory": {
      "command": "C:\\nvm4w\\nodejs\\npx.cmd",
      "args": ["-y", "@modelcontextprotocol/server-memory"]
    }
  }
}

Risks

  • Path breaks when Node version changes via nvm use — must update config after version upgrade
  • For fnm, verify path with `fnm exec --using=default which npx` to get the correct binary path

Verification

  • Run the absolute npx path manually: `/Users/username/.nvm/versions/node/v22.14.0/bin/npx -y @modelcontextprotocol/server-filesystem ~/Desktop` → expect server logs 'Secure MCP Filesystem Server running on stdio'
  • Restart Claude Desktop and tail logs: `tail -f ~/Library/Logs/Claude/mcp-server-filesystem.log` → expect 'Server started and connected successfully' with no ENOENT/-32000 lines
  • Verify tools appear: In Claude Desktop, look for MCP tools (hammer icon) → expect filesystem tools listed with correct names (read_file, write_file, etc.)
  • Test a tool: ask Claude to 'list the files on my Desktop' → expect MCP tool invocation succeeds and returns file listing
0 verified0 failed

Set env.PATH in MCP Server Config (Inject Node Binary Path — Quickest Fix)

risk: lowgithubpending_review

Pass the correct PATH environment variable in the MCP server configuration so spawned processes can find node and npx. This is a one-line config addition that works immediately — no scripts, no global installs. Also works for fnm, Volta, nodenv, and proto.

  1. Find your NVM node bin directory: run `echo $HOME/.nvm/versions/node/$(node -v)/bin`
  2. Add an 'env' block with PATH including that directory + /bin to your MCP server config
  3. Keep command as 'npx' — the env injection handles resolution
  4. Restart your MCP client and verify tools appear

Commands

# Find active node version's bin directory
echo $HOME/.nvm/versions/node/$(node -v)/bin
# For fnm:
dirname $(fnm exec --using=default which npx)
# For nodenv:
echo $HOME/.nodenv/versions/$(nodenv version | cut -d' ' -f1)/bin
# For proto:
ls $HOME/.proto/tools/node/ && echo $HOME/.proto/tools/node/$(ls $HOME/.proto/tools/node/ | tail -1)/bin

Config examples

// NVM on macOS
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/user/Desktop"],
      "env": {
        "PATH": "/Users/user/.nvm/versions/node/v22.14.0/bin:/usr/local/bin:/usr/bin:/bin"
      }
    },
    "playwright": {
      "command": "npx",
      "args": ["@playwright/mcp@latest"],
      "env": {
        "PATH": "/Users/user/.nvm/versions/node/v20.10.0/bin:/bin"
      }
    }
  }
}
// Proto version manager on macOS
{
  "mcpServers": {
    "memory": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-memory"],
      "env": {
        "PATH": "/Users/foo/.proto/tools/node/23.9.0/bin:/bin"
      }
    }
  }
}
// nvm-windows (nvm4w) — use semicolons for Windows PATH
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "C:\\Users\\user\\Desktop"],
      "env": {
        "PATH": "C:\\nvm4w\\nodejs;C:\\Windows\\System32;C:\\Windows"
      }
    }
  }
}

Risks

  • PATH must include /bin (not just node's bin) because npx internally invokes sh, which, and other shell utilities
  • Version number in PATH needs updating when Node is upgraded — set a reminder or use the symlink approach for automatic resolution

Verification

  • Run `npx -y @modelcontextprotocol/server-filesystem ~/Desktop` in terminal → expect output containing 'Secure MCP Filesystem Server running' or similar startup message
  • Add env.PATH to config, restart client, check logs: `tail -f ~/Library/Logs/Claude/mcp-server-filesystem.log` → expect 'Server started and connected successfully' without ENOENT or -32000 errors
  • In Claude Desktop, verify tools: click the tools (hammer) icon → expect filesystem tools (read_file, write_file, list_directory, etc.) listed and clickable
  • Run diagnostic: configure a 'which-node' MCP server with 'command: node, args: [-v]' → check logs to confirm correct Node version is used
0 verified0 failed

Switch to mise Version Manager (Architectural Solution)

risk: lowgithubpending_review

mise (modern replacement for asdf/nvm) works correctly with GUI-spawned processes because it uses shims rather than shell functions. Migrating from NVM to mise eliminates the root cause entirely. The `mise exec` command provides explicit version pinning for each MCP server.

  1. Install mise: `brew install mise` on macOS or `curl https://mise.run | sh` on Linux
  2. Install Node: `mise use node@22` (or @lts)
  3. Configure MCP servers to use mise exec for version-pinned execution
  4. Launch Claude Desktop from terminal: `open -a Claude` so it inherits mise environment

Commands

brew install mise  # macOS
# Or Linux:
curl https://mise.run | sh
mise use node@lts
# Verify mise can run npx:
mise exec node@lts -- npx --version
# Launch Claude from terminal (macOS):
open -a Claude

Config examples

// mise exec approach — version-pinned per server
{
  "mcpServers": {
    "filesystem": {
      "command": "mise",
      "args": [
        "exec", "node@latest", "--",
        "npx", "-y", "@modelcontextprotocol/server-filesystem",
        "/Users/user/Desktop"
      ]
    },
    "context7": {
      "command": "mise",
      "args": [
        "exec", "node@latest", "--",
        "npx", "-y", "@upstash/context7-mcp"
      ]
    }
  }
}
// mise with uv for Python-based MCP servers
{
  "mcpServers": {
    "git": {
      "command": "mise",
      "args": ["exec", "uv@latest", "--", "uvx", "mcp-server-git"]
    }
  }
}

Risks

  • Requires installing and learning a new version manager (migration effort)
  • Existing NVM-specific project configs (.nvmrc) need conversion to .mise.toml or .tool-versions
  • Must launch Claude Desktop from terminal (`open -a Claude`) for mise environment to be inherited by GUI app

Verification

  • Run `mise exec node@latest -- npx -y @modelcontextprotocol/server-filesystem ~/Desktop` → expect server starts and logs 'Secure MCP Filesystem Server running on stdio'
  • Launch Claude from terminal: `open -a Claude` then check MCP logs → expect 'Server started and connected successfully' without errors
  • Verify mise is active: `mise doctor` → expect all checks pass with green checkmarks
0 verified0 failed

Agent JSON

Canonical machine-readable representation of this issue:

{
  "issue_id": "c1d69658-cba8-41e7-ae37-de6ba1d335cc",
  "slug": "fix-mcp-servers-not-working-with-nvm-npx-enoent-32000-in-claude-desktop-cursor-and-cline-w9iusc",
  "verification_status": "unverified",
  "canonical_json": "https://codekb.dev/v1/issues/fix-mcp-servers-not-working-with-nvm-npx-enoent-32000-in-claude-desktop-cursor-and-cline-w9iusc"
}
← Back to all issuesPowered by CodeKB