Skip to content

Commit 33ab237

Browse files
Revert FallbackProcess to synchronous termination approach
This reverts the FallbackProcess termination logic to use synchronous wait in a thread rather than async polling. The previous async polling approach with anyio.sleep(0.1) may have been causing resource cleanup issues in Windows CI with Python 3.10. The synchronous approach: - Uses to_thread.run_sync() to wait for process termination - Removes the timeout-based termination attempt - Simplifies the wait() method to directly use popen.wait() This should resolve the unclosed transport warnings seen in CI tests.
1 parent a675bd5 commit 33ab237

File tree

1 file changed

+6
-19
lines changed

1 file changed

+6
-19
lines changed

src/mcp/client/stdio/win32.py

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from typing import BinaryIO, TextIO, cast
1010

1111
import anyio
12+
from anyio import to_thread
1213
from anyio.abc import Process
1314
from anyio.streams.file import FileReadStream, FileWriteStream
1415

@@ -74,18 +75,9 @@ async def __aexit__(
7475
exc_val: BaseException | None,
7576
exc_tb: object | None,
7677
) -> None:
77-
"""Clean up process and streams.
78-
79-
Attempts to terminate the process, but doesn't fail if termination
80-
is not possible (e.g., process already dead or being handled elsewhere).
81-
"""
82-
try:
83-
self.popen.terminate()
84-
with anyio.move_on_after(0.5):
85-
await self.wait()
86-
except (ProcessLookupError, OSError):
87-
# Process already dead or being handled elsewhere
88-
pass
78+
"""Terminate and wait on process exit inside a thread."""
79+
self.popen.terminate()
80+
await to_thread.run_sync(self.popen.wait)
8981

9082
# Close the file handles to prevent ResourceWarning
9183
if self.stdin:
@@ -100,13 +92,8 @@ async def __aexit__(
10092
self.stderr.close()
10193

10294
async def wait(self):
103-
"""
104-
Poll the process status instead of blocking wait
105-
This allows anyio timeouts to work properly
106-
"""
107-
while self.popen.poll() is None:
108-
await anyio.sleep(0.1)
109-
return self.popen.returncode
95+
"""Async wait for process completion."""
96+
return await to_thread.run_sync(self.popen.wait)
11097

11198
def terminate(self):
11299
"""Terminate the subprocess immediately."""

0 commit comments

Comments
 (0)