stdio_server: text a tool prints still reaches the client, because sys.stdout is flushed after fd 1 is restored
Les mainteneurs répondent en général sous 1 jour
Personne n'a encore pris cette issue.
Évaluation
- Difficulté
- 2/5
- Temps estimé
- 1-3 heures
- Accessibilité débutants
- 76/100
- Type d'issue
- Bug
- Clarté
- Clairement spécifiée
- Activité
- Active
- Stack technique
- python
- Domaine
- backend-api-design
Piste de recherche
Commencez par lire l’implémentation de stdio_server() et suivre où fd 1 est redirigé et restauré ; l’issue ne précise aucun fichier ni test. Reproduisez le cas signalé avec un outil qui appelle print() alors que stdout est redirigé vers un pipe, puis vérifiez que le texte en attente est envoyé vers stderr avant la restauration de fd 1 et qu’il n’apparaît pas comme un message JSON-RPC.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Description
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.
- Langage dominant
- Python
- Étoiles
- 24.7k
- Forks
- 4.1k
- Merge moyen
- 9 h 45 min
- PR mergées (30 j)
- 16
Préparer son environnement
- Aucun Dockerfile ni fichier Docker Compose
- Propose un modèle de pull request
- Lire le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de modelcontextprotocol/python-sdk
-
bug v2
Difficulté 2/5 1-3 heures Accessibilité débutants 76/100
modelcontextprotocol/python-sdk#3811 · 1 commentaire ·
Les mainteneurs répondent en général sous 1 jour
-
bug v2
Difficulté 2/5 1-3 heures Accessibilité débutants 79/100
modelcontextprotocol/python-sdk#3810 · 1 commentaire ·
Les mainteneurs répondent en général sous 1 jour
-
bug v1 v2
Difficulté 2/5 1-3 heures Accessibilité débutants 79/100
modelcontextprotocol/python-sdk#3781 · 2 commentaires ·
Les mainteneurs répondent en général sous 1 jour
-
[Bug]: Inconsistent structured output wrapping and opt-out for typing.Dict and typing sequence generics in func_metadataPeut-être à nouveau libre Une pull request pour cette issue a été fermée sans être fusionnée. Ouvertebug v1 v2
Difficulté 2/5 1-3 heures Accessibilité débutants 82/100
modelcontextprotocol/python-sdk#3771 · 3 commentaires ·
Les mainteneurs répondent en général sous 1 jour
-
bug v2
Difficulté 2/5 1-3 heures Accessibilité débutants 68/100
modelcontextprotocol/python-sdk#3769 · 2 commentaires ·
Les mainteneurs répondent en général sous 1 jour
Toutes les issues de modelcontextprotocol/python-sdk
Issues similaires
-
Difficulté 2/5 1-3 heures Accessibilité débutants 78/100
fritzprix/libr-agent#2612 ·
Les mainteneurs répondent en général sous 1 jour
-
needs-triage presubmit-gate
Difficulté 2/5 1-3 heures Accessibilité débutants 76/100
gke-labs/kube-agents#5001 ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 84/100
simonw/sqlite-utils#928 ·
Les mainteneurs répondent en général sous 3 jours
-
colorado
Difficulté 2/5 1-3 heures Accessibilité débutants 72/100
freelawproject/juriscraper#2405 ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 66/100
cline/mcp-marketplace#3576 ·