From 838d50495f15713be8825615a6e713a3e2f3105d Mon Sep 17 00:00:00 2001 From: teknium1 <127238744+teknium1@users.noreply.github.com> Date: Tue, 7 Jul 2026 14:11:59 -0700 Subject: [PATCH] fix(mcp): guard POSIX-only kill primitives in stdio watchdog for the Windows footgun linter signal.SIGKILL / os.killpg don't exist on Windows. The watchdog is only spawned on POSIX (wrap site gates on os.name), but guard via getattr with a plain terminate/kill fallback so an accidental Windows import can't AttributeError. --- tools/mcp_stdio_watchdog.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/tools/mcp_stdio_watchdog.py b/tools/mcp_stdio_watchdog.py index 17e6fb4c41c91..18c710402d9d5 100644 --- a/tools/mcp_stdio_watchdog.py +++ b/tools/mcp_stdio_watchdog.py @@ -86,14 +86,29 @@ def _is_orphaned(original_ppid: int, parent_create_time: float, getppid=os.getpp def _terminate_process_group(proc: subprocess.Popen) -> None: - """Best-effort SIGTERM-then-SIGKILL of the child's process group.""" + """Best-effort SIGTERM-then-SIGKILL of the child's process group. + + This module only ever runs on POSIX (the wrap site in tools/mcp_tool.py + gates on ``os.name == "posix"``), but guard the POSIX-only primitives + anyway so an accidental Windows import/execute degrades to a plain + child kill instead of AttributeError. + """ + killpg = getattr(os, "killpg", None) + if killpg is None: # windows-footgun: ok — non-POSIX fallback + try: + proc.terminate() + proc.wait(timeout=_TERM_GRACE_S) + except (OSError, subprocess.TimeoutExpired): + proc.kill() + return try: pgid = os.getpgid(proc.pid) except (ProcessLookupError, OSError): return - for sig in (signal.SIGTERM, signal.SIGKILL): + sigkill = getattr(signal, "SIGKILL", signal.SIGTERM) + for sig in (signal.SIGTERM, sigkill): try: - os.killpg(pgid, sig) + killpg(pgid, sig) except (ProcessLookupError, PermissionError, OSError): return try: