MCP is cross-platform in principle. In practice, the same claude_desktop_config.json pasted from a blog post behaves differently on Windows, macOS and Linux because of PATH resolution, path escaping and permission models. Here are the platform-specific gotchas that eat an afternoon if you don't know about them.
Config file location
| OS | Path |
|---|---|
| macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
| Linux | ~/.config/Claude/claude_desktop_config.json |
Easiest: Claude Desktop → Settings → Developer → Edit Config. Opens the right file on every platform.
macOS: the PATH problem
Most annoying macOS gotcha. When Claude Desktop launches from the Dock it does not source your ~/.zshrc, which is where nvm, Homebrew and most Node tooling advertise themselves. Result: npx is "not found" even though it works perfectly in Terminal.
Three fixes, least invasive first:
- Symlink Node into a standard location:
sudo ln -sf $(which node) /usr/local/bin/node sudo ln -sf $(which npx) /usr/local/bin/npx - Use an absolute command in the config:
"command": "/Users/you/.nvm/versions/node/v22.0.0/bin/npx" - Install Node via Homebrew (
brew install node) which lands it in/opt/homebrew/bin— on the default PATH.
Windows: path escaping and spaces
Windows paths contain backslashes and often spaces. JSON requires double-escaping backslashes; omitting the escape silently breaks the path.
// Wrong - will break
"args": ["-y", "@mcp/server", "C:\Users\Me\Documents"]
// Right
"args": ["-y", "@mcp/server", "C:\\Users\\Me\\Documents"]
// Also right (forward slashes work in JSON)
"args": ["-y", "@mcp/server", "C:/Users/Me/Documents"]
Spaces in paths (C:\Program Files) must stay inside a single argument, not split across elements.
Windows: PowerShell vs CMD execution
Claude Desktop on Windows launches MCP servers through cmd.exe, not PowerShell. This matters if your install command uses PowerShell-specific syntax. Also: npx on Windows is a .cmd wrapper. If it's missing from PATH, install via nodejs.org rather than a Node version manager.
WSL: the double-layer trap
If you run Claude Desktop in Windows and your dev environment in WSL2, you have two Node installations. MCP servers installed in WSL are not visible to Claude Desktop on Windows.
Three options:
- Install Node on Windows too. Configure the config to use Windows
npx. - Run the MCP server as a remote (HTTP+SSE) inside WSL, point Claude at
http://localhost:3000/sse. See our deploy guide. - Run Claude Desktop inside WSL with an X-server (overkill for most).
Linux: permissions and AppImage
Linux Claude Desktop ships as an AppImage, which has its own quirks:
- Must be marked executable (
chmod +x Claude-Desktop.AppImage) before launch. - MCP config path is
~/.config/Claude/regardless of launcher. - AppImages run in a sandbox — some distros (Fedora with SELinux) block subprocess spawn. Check
journalctl -fwhile launching.
Cross-platform checklist
If you plan to ship an MCP server for users on multiple platforms, test:
- Paths with spaces (Windows "Program Files", macOS "Application Support")
- Unicode paths (Cyrillic / Japanese filenames)
- Very long paths (Windows 260-char default limit, hits easily with nvm)
- Case-sensitive filesystems (Linux yes, macOS usually no, Windows no)
Docker: the great equaliser
The cleanest way to ship an MCP server that "just works" across platforms: distribute as a Docker image. Every gotcha above goes away because the server runs in a Linux container regardless of host OS.
"github": {
"command": "docker",
"args": ["run", "-i", "--rm", "ghcr.io/github/github-mcp-server"]
}
Docker Desktop runs on all three, command-line is identical. Only downside: +2-3 seconds of container spin-up per invocation.