fix: pipe stderr asynchronously to support Jupyter notebook environments#2786
Open
michaelxer wants to merge 2 commits into
Open
fix: pipe stderr asynchronously to support Jupyter notebook environments#2786michaelxer wants to merge 2 commits into
michaelxer wants to merge 2 commits into
Conversation
In Jupyter notebook environments, sys.stderr cannot reliably be used as a subprocess file descriptor. This causes stdio_client to fail when trying to start MCP servers from within Jupyter notebooks. Changes: - Always pipe stderr (subprocess.PIPE) instead of passing sys.stderr directly to the subprocess - Add async stderr_reader task that reads stderr output and forwards it to the errlog stream (or ANSI-colored print output in Jupyter) - Add _is_jupyter_notebook() helper to detect Jupyter environments via isinstance check against ZMQInteractiveShell - Remove errlog parameter from _create_platform_compatible_process and create_windows_process since stderr is now always piped - Update win32 utilities to always use subprocess.PIPE for stderr Fixes modelcontextprotocol#156
Three tests to cover the _is_jupyter_notebook() and stderr_reader() Jupyter-specific branches introduced in the stderr piping fix: - _is_jupyter_notebook returns False without ipykernel - _is_jupyter_notebook returns True with mocked Jupyter shell - stderr_reader writes ANSI-colored output when in Jupyter Fixes 100% coverage requirement for src/mcp/client/stdio.py.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes stderr handling in
stdio_clientto work correctly in Jupyter notebook environments by always piping stderr and reading it asynchronously, rather than passingsys.stderrdirectly as a subprocess file descriptor.Fixes #156
Problem
In Jupyter notebook environments,
sys.stderris not a regular file descriptor — it's a rich text widget that cannot be passed tosubprocess.Popenoranyio.open_process. This causesstdio_clientto fail with an error when trying to start MCP servers from within Jupyter notebooks.Solution
Instead of forwarding
sys.stderr(or a customerrlogstream) directly to the subprocess, we now:subprocess.PIPE) — both on Unix and Windowsstderr_readertask that runs alongsidestdout_readerandstdin_writer_is_jupyter_notebook()which usesisinstance(get_ipython(), ZMQInteractiveShell)to check for ZMQ-based IPython kernelsprint()in Jupyter, plain text via theerrlogstream elsewhereChanges
src/mcp/client/stdio.py:_is_jupyter_notebook()helper functionstderr_reader()async task instdio_client()errlogparameter from_create_platform_compatible_process()stderr=subprocess.PIPEin process creationsrc/mcp/os/win32/utilities.py:errlogparameter usage, always usestderr=subprocess.PIPEtests/issues/test_1027_win_unreachable_cleanup.py:_create_platform_compatible_process()to match new signature (removederrlogarg)Testing