utilities
Windows-specific functionality for stdio transport operations.
rebind_std_handle_to_fd
rebind_std_handle_to_fd(fd: int) -> None
Points the Win32 standard-handle slot for fd 0, 1, or 2 at fd's current OS handle.
os.dup2 updates only the C runtime's descriptor table; anything that resolves GetStdHandle — subprocess standard-handle inheritance, native code — reads the Win32 slot, so after retargeting a standard descriptor the slot must be repointed too.
Raises:
| Type | Description |
|---|---|
OSError
|
The slot could not be set; callers treat descriptor rearrangement as best-effort and fall back on failure. |
Source code in src/mcp/os/win32/utilities.py
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | |
get_windows_executable_command
Resolves the command to a Windows executable path.
Tries the bare name first, then the common script extensions (.cmd, .bat, .exe, .ps1).
Source code in src/mcp/os/win32/utilities.py
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | |
FallbackProcess
Async wrapper around subprocess.Popen for SelectorEventLoop.
Windows event loops without async subprocess support get this Popen-backed fallback, with anyio file streams wrapping the pipes.
Source code in src/mcp/os/win32/utilities.py
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | |
wait
async
wait() -> int
Waits for exit by polling the Popen.
A thread blocked in Popen.wait() cannot be cancelled by anyio, which would defeat every timeout placed around this call.
Source code in src/mcp/os/win32/utilities.py
101 102 103 104 105 106 107 108 109 | |
terminate
terminate() -> None
Terminates the subprocess.
Source code in src/mcp/os/win32/utilities.py
111 112 113 | |
kill
kill() -> None
Kills the subprocess (on Windows the same hard kill as terminate).
Source code in src/mcp/os/win32/utilities.py
115 116 117 | |
returncode
property
returncode: int | None
The exit code, or None while the process is still running.
Polls the Popen so death is observable without anyone calling wait().
create_windows_process
async
create_windows_process(
command: str,
args: list[str],
env: dict[str, str] | None = None,
errlog: TextIO | None = stderr,
cwd: Path | str | None = None,
) -> Process | FallbackProcess
Creates a subprocess with Job Object support for tree termination.
Spawns via anyio's open_process; event loops without async subprocess support (notably the SelectorEventLoop) raise NotImplementedError, in which case the spawn falls back to a Popen-backed FallbackProcess. Either way the process is then assigned to a Job Object so its children can be terminated with it; children spawned before the assignment completes are not captured (see the inline note below).
Returns:
| Type | Description |
|---|---|
Process | FallbackProcess
|
Process | FallbackProcess: The spawned process with async stdin/stdout streams. |
Source code in src/mcp/os/win32/utilities.py
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | |
close_process_job
close_process_job(
process: Process | FallbackProcess,
) -> None
Closes the process's Job Object handle, if it still has one.
KILL_ON_JOB_CLOSE makes the close also kill any members still alive, deterministically rather than at GC time; a deliberate divergence from POSIX, where a graceful server's children are left alive.
Source code in src/mcp/os/win32/utilities.py
250 251 252 253 254 255 256 257 258 259 260 261 262 | |
terminate_windows_process_tree
async
terminate_windows_process_tree(
process: Process | FallbackProcess,
) -> None
Terminates the process's job, or just the process if it has no job.
Job termination is an immediate hard kill of every member. Windows has no tree-wide SIGTERM; the stdin-close grace period is the server's chance to exit cleanly.
Source code in src/mcp/os/win32/utilities.py
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 | |