stdio_server: text a tool prints still reaches the client, because sys.stdout is flushed after fd 1 is restored
維護者通常 1 天內回覆
還沒有人認領這個 Issue。
評估
- 難度
- 2/5
- 預估耗時
- 1-3 小時
- 新手友好度
- 76/100
- Issue 類型
- 缺陷
- 描述清晰度
- 描述清楚
- 活躍度
- 活躍
- 技術堆疊
- python
研究方向
先閱讀 stdio_server() 的實作,並追蹤 fd 1 在哪裡被重新導向及還原;該 issue 沒有指出檔案或測試。使用一個在 stdout 透過管線連接時呼叫 print() 的工具重現回報的案例,接著檢查待輸出的文字是否在 fd 1 還原之前寫入 stderr,且沒有以 JSON-RPC 訊息的形式出現。
由索引模型根據 Issue 內容生成。
描述
Summary
Since #3117, stdio_server() points fd 1 at stderr while it serves, so that stray output from handlers misses the wire. Text written with print() still reaches the client. It goes into sys.stdout's own buffer, which is block-buffered when stdout is a pipe. That buffer is flushed when the interpreter exits, after stdio_server() has given fd 1 back to the client's pipe. The client then reads the text as a JSON-RPC message.
Reproduction
mcp 2.3.0, Python 3.13.16, macOS 26.3.
import asyncio
import sys
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from mcp.server.mcpserver import MCPServer
if sys.argv[1:] == ["server"]:
server = MCPServer("repro")
@server.tool()
def noisy() -> str:
print("stray output from a tool") # e.g. a library that prints
return "done"
server.run("stdio")
else:
async def main():
params = StdioServerParameters(command=sys.executable, args=[__file__, "server"])
async with stdio_client(params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
result = await session.call_tool("noisy", {})
print("result:", result.content[0].text)
asyncio.run(main())
Running python repro.py, the call succeeds, and the client also logs:
pydantic_core._pydantic_core.ValidationError: 1 validation error for union[JSONRPCRequest,JSONRPCNotification,JSONRPCResponse,JSONRPCError]
Invalid JSON: expected value at line 1 column 1 [type=json_invalid, input_value='stray output from a tool', input_type=str]
Cause
While fd 1 is diverted, the printed text never reaches it: it sits in sys.stdout's buffer. The buffer is written out at interpreter exit, when fd 1 is the protocol pipe again. Adding sys.stdout.flush() right after the print() in the tool removes the error, and the text appears on stderr, which confirms this.
Suggestion
Flush sys.stdout before restoring fd 1, so that pending text goes to the diversion. Making sys.stdout line-buffered while serving (sys.stdout.reconfigure(line_buffering=True)) would also send printed text to stderr when it is printed, rather than at exit.
As a workaround we call sys.stdout.reconfigure(line_buffering=True) before server.run("stdio") and flush after each tool.
- 主要語言
- Python
- 星號
- 24.7k
- 分支
- 4.1k
- 平均合併
- 9 小時 45 分鐘
- 30 天內合併 PR
- 16
環境準備
- 沒有 Dockerfile 或 Docker Compose 檔案
- 有 Pull Request 範本
- 閱讀貢獻指南
從這裡開始
- 先讀完整個 Issue,再讀專案的貢獻指南。
- 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
- Fork 儲存庫,在一個分支上完成修改。
- 送出 Pull Request,並在描述裡引用這個 Issue 編號。
modelcontextprotocol/python-sdk 的其他 Issue
-
bug v2
難度 2/5 1-3 小時 新手友好度 76/100
modelcontextprotocol/python-sdk#3811 · 1 則留言 ·
維護者通常 1 天內回覆
-
bug v2
難度 2/5 1-3 小時 新手友好度 79/100
modelcontextprotocol/python-sdk#3810 · 1 則留言 ·
維護者通常 1 天內回覆
-
bug v1 v2
難度 2/5 1-3 小時 新手友好度 79/100
modelcontextprotocol/python-sdk#3781 · 2 則留言 ·
維護者通常 1 天內回覆
-
[Bug]: Inconsistent structured output wrapping and opt-out for typing.Dict and typing sequence generics in func_metadata可能重新可做 關聯的 PR 已關閉且未合併。 未關閉bug v1 v2
難度 2/5 1-3 小時 新手友好度 82/100
modelcontextprotocol/python-sdk#3771 · 3 則留言 ·
維護者通常 1 天內回覆
-
bug v2
難度 2/5 1-3 小時 新手友好度 68/100
modelcontextprotocol/python-sdk#3769 · 2 則留言 ·
維護者通常 1 天內回覆
查看 modelcontextprotocol/python-sdk 的全部 Issue
相似的 Issue
-
documentation
難度 2/5 1-3 小時 新手友好度 76/100
awslabs/social-messaging-agent-runtime-toolkit#140 ·
維護者通常 1 天內回覆
-
subtask
難度 2/5 1-3 小時 新手友好度 72/100
fga-eps-mds/2026.2-MeasureSoftGram-DOC#187 ·
維護者通常 1 天內回覆
-
難度 2/5 1-3 小時 新手友好度 83/100
txn2/mcp-data-platform#2493 ·
維護者通常 1 天內回覆
-
bug
難度 2/5 1-3 小時 新手友好度 75/100
YO-WHATS-UP2/minigit#78 ·
維護者通常 3 天內回覆
-
documentation
難度 2/5 1-3 小時 新手友好度 78/100
liberation-data/drivine-python#432 ·
維護者通常 1 天內回覆