modelcontextprotocol / modelcontextprotocol/python-sdk

Windows: TextIOWrapper in stdio_server() emits CRLF instead of LF, corrupting newline-delimited JSON messages

Đang mở Phù hợp với người mới
#2,433 9 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

bug fix proposed P2 ready for work
Ngôn ngữ chính
Python
Star
24.3k
Fork
4k
Merge trung bình
1 ngày 1 giờ
Pull request đã merge (30 ngày)
31

Mô tả

Summary

mcp/server/stdio.py creates TextIOWrapper(sys.stdout.buffer, encoding="utf-8") without specifying newline="". On Windows, the default newline=None causes \n\r\n translation, so every JSON-RPC message written to stdout ends with \r\n instead of \n.

The MCP spec uses newline-delimited JSON with \n as the delimiter. Emitting \r\n is a protocol-level impurity.

Affected file

mcp/server/stdio.py lines 46–49

# Current (buggy on Windows)
if not stdin:
    stdin = anyio.wrap_file(TextIOWrapper(sys.stdin.buffer, encoding="utf-8"))
if not stdout:
    stdout = anyio.wrap_file(TextIOWrapper(sys.stdout.buffer, encoding="utf-8"))

Reproduction

On Windows, spawn a Python subprocess that uses this code and read the raw bytes:

import subprocess, sys

script = r'''
import sys
from io import TextIOWrapper
stdout = TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
stdout.write('{"jsonrpc":"2.0","result":"ok"}\n')
stdout.flush()
'''

proc = subprocess.Popen([sys.executable, "-c", script], stdout=subprocess.PIPE)
out, _ = proc.communicate(timeout=5)
print(repr(out))
# Output on Windows: b'{"jsonrpc":"2.0","result":"ok"}\r\n'
# Output on Linux:   b'{"jsonrpc":"2.0","result":"ok"}\n'

Verified on:

  • OS: Windows 11 Pro (10.0.26200)
  • Python: 3.11
  • mcp: 1.26.0

Why this matters

While the current JS MCP SDK client (StdioClientTransport) strips trailing \r via .replace(/\r$/, "") before parsing, this is a server-side bug that:

  1. Violates the NDJSON wire format (which specifies LF-only line endings)
  2. Creates an asymmetry: the Python stdio_client sends bare \n, but the Python stdio_server responds with \r\n
  3. Could break any MCP client that does a strict split("\n") and then fails to JSON.parse the line with a trailing \r

The comment on line 43 even acknowledges: "Encoding of stdin/stdout as text streams on python is platform-dependent (Windows is particularly problematic)" — but the fix applied (re-wrap to ensure UTF-8) doesn't also fix the newline translation mode.

Fix

Add newline="" to both TextIOWrapper calls. newline="" disables translation while still operating in text mode:

if not stdin:
    stdin = anyio.wrap_file(TextIOWrapper(sys.stdin.buffer, encoding="utf-8", newline=""))
if not stdout:
    stdout = anyio.wrap_file(TextIOWrapper(sys.stdout.buffer, encoding="utf-8", newline=""))

With this fix:

# newline="" result:
buf = io.BytesIO()
wrapper = TextIOWrapper(buf, encoding="utf-8", newline="")
wrapper.write('{"jsonrpc":"2.0","result":"ok"}\n')
wrapper.flush()
repr(buf.getvalue())
# b'{"jsonrpc":"2.0","result":"ok"}\n'  ← correct on all platforms

The same fix should be applied to the stdin wrapper so that incoming messages with bare \n are not translated either (avoiding any future issues if a client sends strict LF).

Context

This was discovered while debugging Windows MCP tool timeouts with mem0-mcp-selfhosted. The eager-init approach fixed the actual timeout, but this CRLF emission was identified as a secondary protocol-level issue during investigation.

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Hướng nghiên cứu

Bắt đầu trong src/mcp/server/stdio.py tại các lệnh gọi TextIOWrapper quanh dòng 46–49, sau đó tái hiện đầu ra thô của subprocess trên Windows. Hoàn tất khi cả stdin và stdout đều giữ nguyên các byte LF thuần cho JSON được phân cách bằng dòng mới trên mọi nền tảng.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
python
Lĩnh vực
backend-api-design
Loại issue
Lỗi
Độ khó
1/5
Thời gian dự kiến
Dưới một giờ
Mức độ hoạt động
Sôi nổi
Độ rõ ràng
Đặc tả rõ ràng
Mức phù hợp với người mới
88/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.