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.
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.
| Client | File on Windows | Top-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 scope | mcpServers |
| Cursor | %USERPROFILE%\.cursor\mcp.json, or .cursor\mcp.json in a project | mcpServers |
| VS Code | .vscode\mcp.json; the user file via MCP: Open User Configuration | servers |
| Visual Studio | %USERPROFILE%\.mcp.json, then the solution folder | servers |
| Codex | %USERPROFILE%\.codex\config.toml | [mcp_servers.name] |
| Gemini CLI | %USERPROFILE%\.gemini\settings.json | mcpServers |
| Zed | %APPDATA%\Zed\settings.json | context_servers |
| Devin Desktop (formerly Windsurf) | %APPDATA%\devin\mcp_config.json, legacy Cascade agent | mcpServers |
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.
- 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.
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"]
}
}
}- 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 pathPowerShell: 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 CurrentUserNone 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"]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.
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" }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 see | Why | Fix |
|---|---|---|
| spawn npx ENOENT | No shell, so npx.cmd is never tried; or a PATH from before the install | cmd /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 disabled | The execution policy is Restricted | npx.cmd, or RemoteSigned for CurrentUser |
| python opens the Microsoft Store | An app execution alias | Enable the "Python (default)" alias, or use py |
| Bad escaped character in JSON | A single backslash in a path | \\ or /, and watch for C:\tools |
| An error with ${APPDATA} in a path | The server expects it expanded | "APPDATA": "C:\\Users\\you\\AppData\\Roaming\\" in env |
| Connects, then disconnects | Non-protocol output on stdout: a profile, AutoRun, a banner | pwsh -NoProfile, cmd /d; servers log to stderr |
| Claude Desktop ignores a correct config | It may be reading the package’s private copy | Check both folders; keep one file |
| A token is empty inside the server | SDK clients pass only allow-listed variables; WSL needs WSLENV | Put it in env; add WSLENV for wsl.exe |
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.