From 86176c58f78306edb100c9c5db4291cc03505057 Mon Sep 17 00:00:00 2001 From: Zeheng Huang <153708448+hunjaiboy@users.noreply.github.com> Date: Mon, 1 Jun 2026 14:21:45 -0700 Subject: [PATCH] Fix stdio server newline translation on Windows --- src/mcp/server/stdio.py | 4 ++-- tests/server/test_stdio.py | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/mcp/server/stdio.py b/src/mcp/server/stdio.py index 5c1459dff6..b66c0a5224 100644 --- a/src/mcp/server/stdio.py +++ b/src/mcp/server/stdio.py @@ -39,9 +39,9 @@ async def stdio_server(stdin: anyio.AsyncFile[str] | None = None, stdout: anyio. # python is platform-dependent (Windows is particularly problematic), so we # re-wrap the underlying binary stream to ensure UTF-8. if not stdin: - stdin = anyio.wrap_file(TextIOWrapper(sys.stdin.buffer, encoding="utf-8", errors="replace")) + stdin = anyio.wrap_file(TextIOWrapper(sys.stdin.buffer, encoding="utf-8", errors="replace", newline="")) if not stdout: - stdout = anyio.wrap_file(TextIOWrapper(sys.stdout.buffer, encoding="utf-8")) + stdout = anyio.wrap_file(TextIOWrapper(sys.stdout.buffer, encoding="utf-8", newline="")) read_stream_writer, read_stream = create_context_streams[SessionMessage | Exception](0) write_stream, write_stream_reader = create_context_streams[SessionMessage](0) diff --git a/tests/server/test_stdio.py b/tests/server/test_stdio.py index 677a993567..06a4e0edb4 100644 --- a/tests/server/test_stdio.py +++ b/tests/server/test_stdio.py @@ -63,6 +63,29 @@ async def test_stdio_server(): assert received_responses[1] == JSONRPCResponse(jsonrpc="2.0", id=4, result={}) +@pytest.mark.anyio +async def test_stdio_server_uses_lf_newlines_with_default_stdout(monkeypatch: pytest.MonkeyPatch): + class UnclosableBytesIO(io.BytesIO): + def close(self) -> None: + pass + + raw_stdout = UnclosableBytesIO() + monkeypatch.setattr(sys, "stdin", TextIOWrapper(io.BytesIO(b""), encoding="utf-8")) + monkeypatch.setattr(sys, "stdout", TextIOWrapper(raw_stdout, encoding="utf-8")) + + response = JSONRPCRequest(jsonrpc="2.0", id=3, method="ping") + + with anyio.fail_after(5): + async with stdio_server() as (read_stream, write_stream): + await read_stream.aclose() + async with write_stream: # pragma: no branch + await write_stream.send(SessionMessage(response)) + + raw_bytes = raw_stdout.getvalue() + assert raw_bytes.endswith(b"\n") + assert b"\r\n" not in raw_bytes + + @pytest.mark.anyio async def test_stdio_server_invalid_utf8(monkeypatch: pytest.MonkeyPatch): """Non-UTF-8 bytes on stdin must not crash the server.