Repository navigation
pywin32 installation fails on Windows — hard dep only needed for client stdio, but pulled in for all users via eager import in __init__.py #2233
Description
Activity
I'd like to take this. The fix is straightforward — the
pywin32imports insrc/mcp/os/win32/utilities.py(lines 19-23) should be wrapped in atry/except ImportErrorso they degrade gracefully whenpywin32isn't installed:if sys.platform == "win32": try: import pywintypes import win32api import win32con import win32job except ImportError: pywintypes = None win32api = None win32con = None win32job = None
The downstream code (
_create_job_object,_maybe_assign_process_to_job,terminate_windows_process_tree) already null-checks these modules before use, so the graceful degradation path is fully covered.Will have a PR up shortly.
- added a commit that references this issue
on Mar 7, 2026 - added 2 commits that reference this issue
on Mar 13, 2026 - addedenhancementRequest for a new feature that's not currently supportedRequest for a new feature that's not currently supportedP2Moderate issues affecting some users, edge cases, potentially valuable featureModerate issues affecting some users, edge cases, potentially valuable featureneeds decisionIssue is actionable, needs maintainer decision on whether to implementIssue is actionable, needs maintainer decision on whether to implement
on Aug 14, 2026 Independent confirmation of the same root cause, from a different angle: this also completely blocks running under free-threaded CPython (3.14t) on Windows, not just installation flakiness under AV lock contention.
pywin32has nocp314twheel in any published release (checked against the full version history on PyPI, up to 312 as of this writing). Sincemcp/__init__.pyeagerly importsmcp.client.stdio→mcp.os.win32.utilities, which doesimport pywintypesetc. unconditionally at module level onsys.platform == "win32",import mcpitself fails on a free-threaded interpreter on Windows before any application code runs — there's no way to work around it short of stubbing the four modules locally (which is obviously not viable for a real deployment, since the actual Job Object functionality would then silently no-op).I hit this while experimenting with a free-threaded daemon architecture for an MCP server (to share memory across sessions without the GIL becoming the new serialization point). The fix @herakles-dev described above (soft-failing the import) would resolve this for us too, same as the AV case — the root cause is identical:
pywin32support should degrade gracefully rather than being a hard requirement for code paths (mcp.client.stdio's subprocess Job Object management) that a server-only, or otherwise stdio-client-free, deployment never touches.Given there's apparently no timeline for
pywin32to ever ship a free-threaded wheel (it hasn't kept pace with recent CPython ABI tags in general), this is likely to stay a hard blocker for the free-threaded + Windows combination indefinitely unless this import is made optional. Happy to test against a PR if one lands.pywin32is also the absolute kitchen sink of Windows stuff -- it ships Scintilla (text editor), OpenGL examples, a debugger.
It's the embodiment of dependency hell: it requires DLLs (e.g. MFC) that do not ship with Windows, with Python, or with pywin32 -- the user just has to have to them installed separately somehow!
It also requires DLLs that are not available on Windows Server Core.
Please drop the dependency on it.
Initial Checks
Description
pywin32>=311is a required Windows dependency used exclusively inmcp.client.stdio(Windows Job Objects for child process cleanup). However,mcp/__init__.pyeagerly importsfrom .client.stdio import StdioServerParameters, stdio_client, which causesmcp/os/win32/utilities.pyto unconditionally execute:This means
pywin32is a hard runtime requirement on Windows for all users — including those running a pure MCP server that never usesmcp.client.stdio.The
pywin32wheel contains a.datadirectory with Windows DLLs. On Windows, AV software (e.g. Windows Defender) locks newly-extracted DLLs beforeuvcan clean up its temp directory, causing installation to fail every time with:This blocks server-only deployments like ha-mcp entirely on Windows (tracked in homeassistant-ai/ha-mcp#672).
The null-checks already in
_create_job_object()and_maybe_assign_process_to_job()handlewin32job = Nonegracefully — so the only missing piece is allowing the import to fail softly:Or alternatively, lazily import
mcp.client.stdiofrommcp/__init__.pyso server-only users don't trigger this code path at all.Example Code
Python & MCP Python SDK
Python 3.13, MCP Python SDK 1.26.0 (latest)