-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Description
Describe the bug
The mcp.client.stdio.stdio_client (and its underlying subprocess creation mechanisms) encounters an AttributeError when running in an environment where sys.stderr has been replaced by a custom logger object that does not implement the fileno() method. This prevents the successful launch of MCP tools via the stdio transport in such environments.
The error occurs because anyio.open_process (called by mcp) attempts to use a stderr object that is incompatible with the requirements of subprocess.Popen when a file descriptor is expected.
To Reproduce
- Set up an environment where sys.stderr is globally replaced with a file-like object that handles logging but does not have a fileno() method. (This is common in managed platforms like Databricks).
- Attempt to use the mcp.client.stdio.stdio_client (e.g., via langchain-mcp-adapters) to connect to and launch an MCP tool/server using the stdio transport.
- The process creation will fail when anyio.open_process (or underlying asyncio.create_subprocess_exec / subprocess.Popen) attempts to access stderr.fileno().
Expected behavior
The mcp.client.stdio.stdio_client should successfully launch the subprocess for the MCP tool. It should handle environments with custom sys.stderr implementations by:
Explicitly passing stderr=subprocess.PIPE (or its asyncio equivalent) to anyio.open_process if it intends to read/log the subprocess's stderr.
Or explicitly passing stderr=subprocess.DEVNULL if the subprocess's stderr is not needed. This would prevent reliance on the inherited sys.stderr object's compatibility with fileno().
Impact:
This bug prevents the use of mcp tools over stdio transport in common managed Python environments (like Databricks Serving Endpoints and potentially other PaaS/FaaS platforms) that customize sys.stderr for integrated logging.
Suggested Solution/Investigation Point:
Review the mcp.client.stdio.init._create_platform_compatible_process (and stdio_client) function. When calling anyio.open_process, ensure that the stderr argument is explicitly set to a compatible value (e.g., asyncio.subprocess.PIPE or asyncio.subprocess.DEVNULL) rather than implicitly inheriting sys.stderr or passing an object that might not have fileno().