From 7ae772a21aa59779f08054cbd4c07c569411aa60 Mon Sep 17 00:00:00 2001 From: Rudrendu Date: Thu, 9 Apr 2026 01:14:27 -0700 Subject: [PATCH] fix: allow integer file descriptors for errlog in stdio_client Github-Issue: #1806 --- src/mcp/client/stdio.py | 10 ++++++++-- src/mcp/os/win32/utilities.py | 7 +++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/mcp/client/stdio.py b/src/mcp/client/stdio.py index 3e03eef9ef..19aae0c462 100644 --- a/src/mcp/client/stdio.py +++ b/src/mcp/client/stdio.py @@ -112,10 +112,16 @@ class StdioServerParameters(BaseModel): @asynccontextmanager async def stdio_client( - server: StdioServerParameters, errlog: TextIO = sys.stderr + server: StdioServerParameters, errlog: TextIO | int = sys.stderr ) -> AsyncGenerator[TransportStreams, None]: """Spawns an MCP server subprocess and connects to it over stdin/stdout. + Args: + server: Parameters for the server process to spawn. + errlog: Where to send the server's stderr. Accepts a text stream + (e.g. ``sys.stderr``) or an integer file descriptor, including + ``subprocess.DEVNULL`` to discard stderr entirely. + Raises: OSError: If the server process cannot be spawned. ValueError: If the spawn parameters are invalid (embedded NUL bytes). @@ -329,7 +335,7 @@ async def _create_platform_compatible_process( command: str, args: list[str], env: dict[str, str] | None = None, - errlog: TextIO = sys.stderr, + errlog: TextIO | int = sys.stderr, cwd: Path | str | None = None, ) -> ServerProcess: """Spawns the server in its own kill scope. diff --git a/src/mcp/os/win32/utilities.py b/src/mcp/os/win32/utilities.py index 321fda8a66..88a06263bc 100644 --- a/src/mcp/os/win32/utilities.py +++ b/src/mcp/os/win32/utilities.py @@ -137,7 +137,7 @@ async def create_windows_process( command: str, args: list[str], env: dict[str, str] | None = None, - errlog: TextIO | None = sys.stderr, + errlog: TextIO | int | None = sys.stderr, cwd: Path | str | None = None, ) -> Process | FallbackProcess: """Creates a subprocess with Job Object support for tree termination. @@ -149,6 +149,9 @@ async def create_windows_process( with it; children spawned before the assignment completes are not captured (see the inline note below). + errlog accepts a text stream (e.g. ``sys.stderr``), an integer file + descriptor (e.g. ``subprocess.DEVNULL``), or ``None``. + Returns: Process | FallbackProcess: The spawned process with async stdin/stdout streams. """ @@ -177,7 +180,7 @@ async def _create_windows_fallback_process( command: str, args: list[str], env: dict[str, str] | None = None, - errlog: TextIO | None = sys.stderr, + errlog: TextIO | int | None = sys.stderr, cwd: Path | str | None = None, ) -> FallbackProcess: """Spawns via subprocess.Popen and wraps it in FallbackProcess."""