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 symptom | What to inspect next |
|---|---|
WinError 193 / not a valid Win32 application | Check whether the resolved MCP command ends in .ps1 and is being handed directly to CreateProcess. |
FileNotFoundError after a bare command resolves on Windows | Inspect 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 stdio | Reproduce 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. Capture the exact exception. Distinguish
WinError 193,FileNotFoundError, permission failures and later JSON-RPC disconnects. They do not share one cause. - 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
.exeor.cmd. - 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. 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. Make the interpreter explicit. Configure stdio to launch
powershell.exeorpwshand pass-NoProfile,-NonInteractive,-File, the script path and server arguments as separate array elements. - 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. 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
- MCP Python SDK issue #3496 — open 13 September 2026 report reproducing direct
.ps1spawn failure on Windows with MCP Python SDK 2.2.0. - MCP Python SDK stdio client source — current source shows Windows command normalization feeding the platform-specific process creation path.
Continue the implementation path
Verify an MCP server before connecting
Separate endpoint, transport, auth and tool-surface checks before trusting a discovered server.
Diagnose incomplete Streamable HTTP responses
If your child process starts but HTTP transport fails later, move to the response-lifecycle boundary instead.
Migrate to MCP 2026-07-28
Check current protocol-version and stateless request semantics separately from local process launch.
Inspect zFinia machine APIs
Machine-readable services for agents and operators working across the machine economy.