Root Cause
execute_command() in service.py uses subprocess.run() with capture_output=True. This creates inheritable stdout/stderr pipe handles. When pip, npm, or other tools spawn grandchild processes, those grandchildren inherit the write end of the pipe. The direct child (PowerShell) exits, but grandchildren keep the pipe open — so communicate() blocks forever waiting for EOF. Result: 4+ minute MCP timeout on any subprocess-spawning command.
The existing stdin=subprocess.DEVNULL partial fix (v0.7.0) closes stdin but does NOT fix the stdout/stderr pipe deadlock.
Confirmed Affected Commands
pip --version, pip list, pip install
-
-
-
-
-
python -c "import subprocess; subprocess.run([...])"
-
-
-
-
- Any multi-line script with loops or multiple commands
Confirmed Working Commands (not affected)
echo, python --version, node --version, arduino-cli version
The Fix
Replace subprocess.run(capture_output=True) with subprocess.Popen() writing to temp files, then proc.wait(). This waits only for the direct child (PowerShell), not grandchildren. Temp files are never inherited across process boundaries.
import tempfile as _tempfile
_fd_out, _out_path = _tempfile.mkstemp(suffix="_out.txt", prefix="wmcp_")
_fd_err, _err_path = _tempfile.mkstemp(suffix="_err.txt", prefix="wmcp_")
try:
with os.fdopen(_fd_out, "wb") as _fout, os.fdopen(_fd_err, "wb") as _ferr:
proc = subprocess.Popen(
args,
stdin=subprocess.DEVNULL,
stdout=_fout,
stderr=_ferr,
cwd=os.path.expanduser(path="~"),
env=env,
creationflags=subprocess.CREATE_NO_WINDOW,
)
try:
returncode = proc.wait(timeout=timeout)
except subprocess.TimeoutExpired:
proc.kill()
proc.wait()
return ("Command execution timed out", 1)
with open(_out_path, "rb") as f:
stdout = f.read().decode("utf-8", errors="replace")
with open(_err_path, "rb") as f:
stderr = f.read().decode("utf-8", errors="replace")
return (stdout or stderr, returncode)
finally:
for _p in (_out_path, _err_path):
try:
os.unlink(_p)
except Exception:
pass
Verified Fix
Applied this patch locally to service.py in the Claude Desktop extension. After restarting Claude Desktop:
pip --version → instant response ✅
-
pip list → instant response ✅
-
-
npm --version → instant response ✅
-
-
-
python -m pip --version → instant response ✅
Environment
- Windows 11 AMD64
-
- Claude Desktop v1.1.8629.0 (MSIX install)
-
-
- windows-mcp v0.7.0 (Claude Desktop built-in extension)
-
-
-
- Python 3.13.12 (venv), Python 3.14.3 (uv system)
Root Cause
execute_command()inservice.pyusessubprocess.run()withcapture_output=True. This creates inheritable stdout/stderr pipe handles. When pip, npm, or other tools spawn grandchild processes, those grandchildren inherit the write end of the pipe. The direct child (PowerShell) exits, but grandchildren keep the pipe open — socommunicate()blocks forever waiting for EOF. Result: 4+ minute MCP timeout on any subprocess-spawning command.The existing
stdin=subprocess.DEVNULLpartial fix (v0.7.0) closes stdin but does NOT fix the stdout/stderr pipe deadlock.Confirmed Affected Commands
pip --version,pip list,pip installnpm --versionpython -m pip --versionpython -c "import subprocess; subprocess.run([...])"Confirmed Working Commands (not affected)
echo,python --version,node --version,arduino-cli versionThe Fix
Replace
subprocess.run(capture_output=True)withsubprocess.Popen()writing to temp files, thenproc.wait(). This waits only for the direct child (PowerShell), not grandchildren. Temp files are never inherited across process boundaries.Verified Fix
Applied this patch locally to
service.pyin the Claude Desktop extension. After restarting Claude Desktop:pip --version→ instant response ✅pip list→ instant response ✅npm --version→ instant response ✅python -m pip --version→ instant response ✅Environment