Editorial

Research guide · MCP · Windows · stdio · 14 September 2026

MCP Windows WinError 193: fix .ps1 stdio server spawn failures

If an MCP stdio server starts normally on macOS or Linux but fails on Windows with WinError 193, not a valid Win32 application, or a nearby FileNotFoundError, inspect the launcher before you debug MCP protocol messages. A current Python SDK report shows a narrow Windows path where command discovery can resolve a PowerShell .ps1 wrapper and the spawn layer then attempts to execute that script directly.

Published 14 September 2026 · sources checked 14 September 2026

WinError 193

Searchable Windows symptom

.ps1

Problematic resolved launcher type

stdio

Affected MCP transport path

PowerShell -File

Controlled workaround shape

The useful distinction

Command resolution can succeed while process creation still fails

The MCP Python SDK normalizes stdio commands on Windows before spawning the child process. Current source calls a Windows-specific get_windows_executable_command() helper and then passes the resolved command into the platform process-creation path.

Issue #3496, opened 13 September 2026 against the current 2.x line, reports that the resolver can locate .ps1 files alongside executable launcher types. The problem is the next boundary: Windows does not treat a PowerShell script as a native executable that CreateProcess can launch directly. The report reproduces WinError 193 or FileNotFoundError, while explicitly invoking PowerShell with -File succeeds.

That means this symptom is a launcher/process-boundary failure before it is an MCP handshake, JSON-RPC, authorization or tool-schema failure. If no child process starts, changing initialize, capabilities or tool definitions cannot repair it.

Error map

Use the executable type to choose the next test

Observed symptomWhat to inspect next
WinError 193 / not a valid Win32 applicationCheck whether the resolved MCP command ends in .ps1 and is being handed directly to CreateProcess.
FileNotFoundError after a bare command resolves on WindowsInspect the resolved launcher path, PATHEXT behavior and whether the result is a PowerShell wrapper rather than a native executable.
The same script works from PowerShell but fails from MCP stdioReproduce by launching the script explicitly through powershell.exe or pwsh with -File while keeping the MCP server arguments unchanged.

Diagnosis

Seven checks before changing your MCP server

  1. 1. Capture the exact exception. Distinguish WinError 193, FileNotFoundError, permission failures and later JSON-RPC disconnects. They do not share one cause.
  2. 2. Resolve the configured command yourself. On the failing machine, determine the concrete path for the command in the same environment the MCP host receives. Do not assume a bare name maps to .exe or .cmd.
  3. 3. Inspect the suffix. If the resolved file is .ps1, this current SDK report is relevant. If it is a native executable, continue with a different process-start diagnosis.
  4. 4. Test the script outside MCP. Invoke the same script through an explicit PowerShell executable with the same working directory and arguments. Keep secrets out of the command line and logs.
  5. 5. Make the interpreter explicit. Configure stdio to launch powershell.exe or pwsh and pass -NoProfile, -NonInteractive, -File, the script path and server arguments as separate array elements.
  6. 6. Avoid a blanket shell workaround. Do not switch every MCP launch to a shell string merely to make one wrapper executable. Explicit interpreter plus structured arguments preserves a narrower quoting and injection surface.
  7. 7. Pin and re-test after SDK changes. The upstream issue is open. Treat the workaround as version-scoped and verify the actual resolved command after upgrading rather than keeping a permanent compatibility layer by habit.

Safe configuration shape

Launch the interpreter, not the script

The exact configuration syntax depends on your MCP host, but the process boundary should look like this: the executable is PowerShell and the script is an argument. Keep values as separate arguments instead of interpolating a shell command string.

command: "powershell.exe"

args: [

  "-NoProfile",

  "-NonInteractive",

  "-File",

  "C:\\path\\to\\server.ps1"

]

If your environment standardizes on PowerShell 7, use the explicit pwsh executable instead. Do not copy -ExecutionPolicy Bypass into a production policy by default; the upstream reproduction uses it to demonstrate process launch, not as a universal security recommendation.

What not to infer

Three tempting fixes are too broad

“MCP stdio is broken on Windows”

No. The current report is specifically about a command that resolves to a PowerShell script and then crosses a native process-spawn boundary.

“Enable shell execution everywhere”

No. That changes parsing and security semantics. Prefer an explicit interpreter and argument vector for the one launcher that needs it.

“The server handshake is wrong”

Not when process creation fails first. Confirm the child process actually starts before changing initialize, capabilities, auth or tool schemas.

Sources

Primary evidence

Continue the implementation path