stdio_client Fails with AttributeError: 'StreamToLogger' object has no attribute 'fileno' in Environments with Custom sys.stderr (e.g., Databricks)
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().