Skip to content

Commit 6bc6727

Browse files
Implement unified timeout mechanism for stdio client cleanup
Changes from PR #555 by @cristipufu: - Remove Windows-specific terminate_windows_process function - Apply uniform 2-second timeout mechanism across all platforms: - Try process.terminate() first (SIGTERM on Unix, similar on Windows) - Wait up to 2 seconds for graceful termination - If timeout occurs, force process.kill() (SIGKILL equivalent) This ensures consistent behavior between Windows and Unix systems when cleaning up stdio client processes, preventing hanging when MCP servers don't respond to SIGTERM. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 9be413a commit 6bc6727

File tree

2 files changed

+6
-27
lines changed

2 files changed

+6
-27
lines changed

src/mcp/client/stdio/__init__.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
from .win32 import (
1717
create_windows_process,
1818
get_windows_executable_command,
19-
terminate_windows_process,
2019
)
2120

2221
# Environment variables to inherit by default
@@ -180,13 +179,12 @@ async def stdin_writer():
180179
finally:
181180
# Clean up process to prevent any dangling orphaned processes
182181
try:
183-
if sys.platform == "win32":
184-
await terminate_windows_process(process)
185-
else:
186-
process.terminate()
187-
except ProcessLookupError:
188-
# Process already exited, which is fine
189-
pass
182+
process.terminate()
183+
with anyio.fail_after(2.0):
184+
await process.wait()
185+
except TimeoutError:
186+
# Force kill if it doesn't terminate
187+
process.kill()
190188
await read_stream.aclose()
191189
await write_stream.aclose()
192190
await read_stream_writer.aclose()

src/mcp/client/stdio/win32.py

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -161,22 +161,3 @@ async def create_windows_process(
161161
return FallbackProcess(popen_obj)
162162

163163

164-
async def terminate_windows_process(process: Process | FallbackProcess):
165-
"""
166-
Terminate a Windows process.
167-
168-
Note: On Windows, terminating a process with process.terminate() doesn't
169-
always guarantee immediate process termination.
170-
So we give it 2s to exit, or we call process.kill()
171-
which sends a SIGKILL equivalent signal.
172-
173-
Args:
174-
process: The process to terminate
175-
"""
176-
try:
177-
process.terminate()
178-
with anyio.fail_after(2.0):
179-
await process.wait()
180-
except TimeoutError:
181-
# Force kill if it doesn't terminate
182-
process.kill()

0 commit comments

Comments
 (0)