Skip to content

fix: make pywin32 imports soft to support server-only Windows installs#2241

Open
herakles-dev wants to merge 1 commit intomodelcontextprotocol:mainfrom
herakles-dev:fix/pywin32-soft-import
Open

fix: make pywin32 imports soft to support server-only Windows installs#2241
herakles-dev wants to merge 1 commit intomodelcontextprotocol:mainfrom
herakles-dev:fix/pywin32-soft-import

Conversation

@herakles-dev
Copy link

Problem

pywin32>=311 is a Windows dependency used exclusively for Job Object support in mcp.client.stdio. However, because mcp/__init__.py eagerly imports from .client.stdio import StdioServerParameters, stdio_client, the pywin32 modules in mcp/os/win32/utilities.py are loaded unconditionally on Windows — even for server-only users who never use the stdio client.

This causes two issues:

  1. Installation failures: The pywin32 wheel contains Windows DLLs that antivirus software (e.g., Windows Defender) locks during extraction, causing uv cache cleanup to fail with OS error 32 (file in use). This blocks server-only deployments entirely.

  2. Unnecessary dependency: Pure MCP servers should not require pywin32 at all, since Job Objects are only relevant for client-side subprocess management.

This blocks downstream projects like ha-mcp on Windows (tracked in homeassistant-ai/ha-mcp#672).

Solution

Wrap the pywin32 imports in src/mcp/os/win32/utilities.py with try/except ImportError, falling back to None when the package is not installed.

All downstream functions that use these modules — _create_job_object(), _maybe_assign_process_to_job(), and terminate_windows_process_tree() — already null-check them before use, so the graceful degradation path is fully covered with no behavior change for users who have pywin32 installed.

Change

 if sys.platform == "win32":
-    import pywintypes
-    import win32api
-    import win32con
-    import win32job
+    try:
+        import pywintypes
+        import win32api
+        import win32con
+        import win32job
+    except ImportError:
+        pywintypes = None
+        win32api = None
+        win32con = None
+        win32job = None

Fixes #2233

Wrap pywin32 imports in try/except ImportError so that server-only
Windows users are not forced to install pywin32. The package is only
needed for Job Object support in mcp.client.stdio, but the eager
import in mcp/__init__.py pulls it in for all users.

All downstream functions (_create_job_object, _maybe_assign_process_to_job,
terminate_windows_process_tree) already null-check these modules before
use, so graceful degradation is fully covered.

Fixes server-only deployments that fail with pywin32 installation errors
when antivirus software locks extracted DLLs during uv cache cleanup.

Github-Issue: modelcontextprotocol#2233
Reported-by: Nikhil Suresh
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pywin32 installation fails on Windows — hard dep only needed for client stdio, but pulled in for all users via eager import in __init__.py

1 participant