modelcontextprotocol / modelcontextprotocol/python-sdk

stdio_client crashes on malformed UTF-8 from child stdout instead of surfacing parse error

Ouverte
#2,454 3 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

bug fix proposed P2 ready for work
Langage dominant
Python
Étoiles
24.3k
Forks
4k
Merge moyen
1 j 1 h
PR mergées (30 j)
31

Description

Summary

mcp.client.stdio.stdio_client() crashes when the spawned child process writes invalid UTF-8 bytes to stdout.

The transport currently decodes child stdout with encoding_error_handler="strict", so malformed bytes raise during TextReceiveStream(...) iteration. That exception escapes the decoding loop and brings down the transport task group instead of surfacing the bad line as an in-stream parse error.

Why this looks like a bug

The SDK already hardened the server side for the analogous case in PR #2302 (fix: handle non-UTF-8 bytes in stdio server stdin). That change explicitly preferred:

  • replace invalid bytes with U+FFFD,
  • let JSON validation fail on the malformed line, and
  • keep the transport alive so subsequent valid messages can still be processed.

The client side still behaves asymmetrically today. A buggy or non-compliant child server can kill the Python client transport with a single malformed line even if the next line is valid JSON-RPC.

That seems inconsistent with the current stdio robustness direction.

Reproduction

A minimal child process that writes one malformed line and then one valid JSON-RPC line:

import sys
import time

sys.stdout.buffer.write(b"\xff\xfe\n")
sys.stdout.buffer.write(b'{"jsonrpc":"2.0","id":1,"method":"ping"}\n')
sys.stdout.buffer.flush()
time.sleep(0.2)

With current stdio_client(...) defaults, the transport raises ExceptionGroup instead of continuing.

Expected behavior

The malformed line should be surfaced as an in-stream parse / validation error, and the next valid JSON-RPC line should still be received.

Observed behavior

The transport task group fails before the valid follow-up message is delivered.

Proposed fix

Match the server-side approach from PR #2302:

  1. default StdioServerParameters.encoding_error_handler to "replace"
  2. continue treating malformed decoded lines as JSON validation failures
  3. keep the background stdio tasks resilient during early subprocess shutdown / abrupt close

Validation

I reproduced this locally against current main and verified that a minimal patch plus a regression test fixes it.

A focused regression test in tests/client/test_stdio.py can assert:

  • first item from the read stream is an Exception
  • second item is the valid SessionMessage

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

Commencez dans mcp.client.stdio.stdio_client() et tests/client/test_stdio.py ; examinez comment le décodage de TextReceiveStream et l’itération du flux de lecture gèrent les erreurs d’encodage. Ajoutez la régression malformé-puis-valide décrite dans l’issue, puis exécutez le test ciblé pour vérifier que le premier élément est une Exception, que le second est une SessionMessage valide et que le transport reste actif.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
python
Domaine
backend, testing
Type d'issue
Bug
Difficulté
3/5
Temps estimé
1-2 jours
Activité
Calme
Clarté
Clairement spécifiée
Accessibilité débutants
78/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.