Engineering 27 Sep 2026 · 5 min read

MCP on Windows: set up MCP servers on Windows 11 without the usual errors

The protocol is the same on Windows. The plumbing is not: a config file that can live in two places, an npx that is really npx.cmd, and a JSON parser that reads C:\tools as a tab.

MR mcprush team · The people who run the gateway

MCP on Windows breaks in five places: the wrong config file, a launcher the client cannot start, a backslash, something writing to stdout, or a server on the wrong side of WSL. Each one has a fix below.

Where each client keeps its MCP config on Windows

On Windows, ~ means %USERPROFILE% and %APPDATA% is the Roaming folder beneath it. Entry shapes are in where every MCP client keeps its config.

ClientFile on WindowsTop-level key
Claude Desktop%APPDATA%\Claude\claude_desktop_config.json (Settings → Developer → Edit Config)mcpServers
Claude Code%USERPROFILE%\.claude.json; .mcp.json in the repository for project scopemcpServers
Cursor%USERPROFILE%\.cursor\mcp.json, or .cursor\mcp.json in a projectmcpServers
VS Code.vscode\mcp.json; the user file via MCP: Open User Configurationservers
Visual Studio%USERPROFILE%\.mcp.json, then the solution folderservers
Codex%USERPROFILE%\.codex\config.toml[mcp_servers.name]
Gemini CLI%USERPROFILE%\.gemini\settings.jsonmcpServers
Zed%APPDATA%\Zed\settings.jsoncontext_servers
Devin Desktop (formerly Windsurf)%APPDATA%\devin\mcp_config.json, legacy Cascade agentmcpServers
Claude Desktop reads its file only at launch: quit it fully after an edit.

Claude Desktop is a packaged app, and it may read another file

Claude Desktop installs on Windows as an MSIX package, the format Store apps use. When Windows virtualizes a packaged app, files the app creates under AppData land in a private folder under %LOCALAPPDATA%\Packages, and Windows opens that copy first. If Claude Desktop created its own config, a file you write by hand in %APPDATA%\Claude may never be read. Which folders Claude opts out of this is not documented, so check.

Microsoft’s order for a packaged app: its private copy first, the real AppData file only when there is none.Microsoft’s order for a packaged app: its private copy first, the real AppData file only when there is none.
Microsoft’s order for a packaged app: its private copy first, the real AppData file only when there is none.
  • Look in both folders: %LOCALAPPDATA%\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Roaming\Claude\ and %APPDATA%\Claude\. If both hold a config, keep one.
  • On a managed laptop, isLocalDevMcpEnabled set to false under HKLM\SOFTWARE\Policies\Claude stops every local server, whatever the file says.
  • Or skip the file. Desktop Extensions (.mcpb) run on the Node.js built into Claude Desktop, so a Node server needs neither PATH nor npx.

Why npx and uvx fail with spawn ENOENT on Windows

On Windows, npx is not an executable. npm ships it as npx.cmd and npx.ps1, and Node’s documentation says .cmd files "are not executable on their own without a terminal". A client that spawns through Node without a shell ignores PATHEXT, finds no executable called npx, and fails with spawn npx ENOENT. Point it at npx.cmd directly and, since Node’s April 2024 security release, it fails with EINVAL.

The same server, started two ways. Only the second reaches node.exe.The same server, started two ways. Only the second reaches node.exe.
The same server, started two ways. Only the second reaches node.exe.

Clients built on the official SDKs avoid it: the TypeScript SDK spawns through cross-spawn, and the Python SDK tries .cmd, .bat, .exe and .ps1 after the bare name. Claude Code’s documentation says npx and uvx on PATH work as-is. For a client that still fails, wrap the command in cmd, as Node’s documentation advises:

{ "mcpServers": { "filesystem": { "command": "cmd", "args": ["/d", "/c", "npx", "-y", "@modelcontextprotocol/server-filesystem", "C:\\Users\\you\\Documents"] } } }
/c runs the rest of the line and exits, so /d comes first: it skips registry AutoRun commands, whose output would land on stdout.
  • Restart after installing Node or uv. A process inherits its parent’s environment, so a client that was already open keeps the old PATH.
  • Or use a full path to a real .exe. where.exe uvx prints it (in PowerShell, plain where means Where-Object); uv’s standalone installer puts uvx.exe in %USERPROFILE%\.local\bin. npx has no .exe: its full path is npx.cmd, which still needs cmd /d /c.

Backslashes: the JSON mistake that sometimes parses

JSON allows only a few backslash escapes. "C:\Users\you" contains an invalid one, so the parse fails with Bad escaped character in JSON and none of the file’s servers load. "C:\tools\node" is worse: \t and \n are valid, so it parses into a tab and a newline, and the server gets a path that does not exist.

"C:\Users\you\Documents" fails: \U is not an escape "C:\tools\node" parses, as a tab and a newline "C:\\Users\\you\\Documents" correct "C:/Users/you/Documents" correct where Windows resolves the path
Double every backslash, as the MCP guide’s own Windows example does, and keep every path absolute.

PowerShell: the execution policy and the stdout rule

In PowerShell, npx can resolve to npx.ps1, which the execution policy blocks: "running scripts is disabled on this system". On Windows clients the effective policy is Restricted unless a scope sets another. Type npx.cmd, or allow local scripts for your account, no administrator needed:

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Group Policy overrides it, and Microsoft is plain that the policy is not a security boundary.

None of this affects a client that spawns npx.cmd or cmd. It matters for servers written as PowerShell scripts, which should start so that only the script reaches stdout:

"command": "pwsh", "args": ["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File", "C:\\mcp\\server.ps1"]
-NoProfile keeps profile output off the protocol stream, -NonInteractive makes a prompt an error instead of a hang, and -File goes last.

Or use a ready-made one: Powershell (PowerShell plus SSH and WinRM), Pwsh Exec (exit code, stdout, stderr) or Windows Admin (services, Event Viewer, Task Scheduler). They run commands as you, so read what an install can reach first.

WSL or native: run the server where its files are

Run the server where its data and tools are. PowerShell, the AD module, Office and desktop automation stay native. An Excel MCP server that drives desktop Excel needs Windows itself. Linux toolchains and repositories inside a distribution go in WSL 2, because Windows reaches those files through a network filesystem that is slow and breaks file watching. Claude Code’s sandbox needs WSL 2; VS Code’s MCP server sandboxing is not available on Windows.

Two ways across. The stdio route needs two settings the HTTP route does not.Two ways across. The stdio route needs two settings the HTTP route does not.
Two ways across. The stdio route needs two settings the HTTP route does not.

A Windows client can start a Linux server through wsl.exe, with two catches: variables in env reach Linux only if WSLENV lists them, and -e runs the command without a shell, so a node from a version manager in .bashrc may be missing from PATH.

"command": "wsl.exe", "args": ["-d", "Ubuntu", "-e", "/usr/bin/npx", "-y", "@you/issues-mcp"], "env": { "ISSUES_TOKEN": "…", "WSLENV": "ISSUES_TOKEN/u" }
Works as written with a Node installed from the distribution’s packages, in /usr/bin. npx runs through /usr/bin/env node, so with nvm or another version manager put that node’s absolute path first and the npx-cli.js path after it. A path under /mnt/c is Windows’ npx, not Linux’s. /u passes the variable only when WSL starts from Windows.

The cleaner crossing is HTTP: run the server in WSL on Streamable HTTP and give the Windows client http://localhost:<port>/mcp, which WSL’s default NAT mode allows (the transports guide covers the trade). Wsl Exec and Wsl Filesystem go the other way: commands and files inside WSL for a Windows client.

What Windows 11 adds: the On-device Agent Registry

Windows 11 has MCP support of its own, in public preview: an On-device Agent Registry where agents discover servers, odr.exe to list and register them, and connectors for File Explorer and Settings. Registered servers can run contained, under a separate agent account with no access to your files unless granted. It needs build 26220.7262 or later, and an administrator to turn on Settings → System → AI Components → Experimental agentic features. A host has to call the registry, so Claude Desktop, Cursor and Claude Code still start the servers in their own files.

MCP and on-premises Active Directory: PowerShell and WinRM

For Entra ID, Microsoft’s own read-only server is covered in MCP servers for SQL Server, Azure and Active Directory.

On-premises Active Directory has no dedicated MCP server we would recommend. It is reached through the Active Directory module for PowerShell (RSAT, on Pro and Enterprise but not Home) or over WinRM with a server such as Powershell, whose winrm_exec tool runs commands on a remote Windows host. Either way the server can do whatever its account can, so give that account only the rights the job needs. For audits, see the Active Directory vulnerability assessment skill.

Errors, causes and fixes

What you seeWhyFix
spawn npx ENOENTNo shell, so npx.cmd is never tried; or a PATH from before the installcmd /d /c npx …, or the full path of a real .exe such as uvx.exe; restart the client
npx.ps1 cannot be loaded because running scripts is disabledThe execution policy is Restrictednpx.cmd, or RemoteSigned for CurrentUser
python opens the Microsoft StoreAn app execution aliasEnable the "Python (default)" alias, or use py
Bad escaped character in JSONA single backslash in a path\\ or /, and watch for C:\tools
An error with ${APPDATA} in a pathThe server expects it expanded"APPDATA": "C:\\Users\\you\\AppData\\Roaming\\" in env
Connects, then disconnectsNon-protocol output on stdout: a profile, AutoRun, a bannerpwsh -NoProfile, cmd /d; servers log to stderr
Claude Desktop ignores a correct configIt may be reading the package’s private copyCheck both folders; keep one file
A token is empty inside the serverSDK clients pass only allow-listed variables; WSL needs WSLENVPut it in env; add WSLENV for wsl.exe
Each server’s stderr is in %APPDATA%\Claude\logs\mcp-server-NAME.log, or in the same logs folder under %LOCALAPPDATA%\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Roaming\Claude\ on a packaged install. In PowerShell, Get-Content "$env:APPDATA\Claude\logs\mcp.log" -Tail 20 -Wait follows the main log.

Past these, a server behaves on Windows as anywhere else. Search the catalogue for windows, powershell or active directory. Windows is the computer-use server, and its README warns it runs with full system access.