2026 : tamponnage stdio OpenClaw, arrêts JSON-RPC MCP et contre-pression de tube sur un Mac mini ProxyMac loué
Sur un ProxyMac Mac mini à Hong Kong, au Japon, en Corée, à Singapour ou aux États-Unis, OpenClaw enregistre souvent des serveurs MCP via stdio : la passerelle lance un processus enfant, parle JSON-RPC sur stdin/stdout et attend que chaque message arrive vite. La signature d’échec est d’un calme agaçant : le premier appel d’outil fonctionne, puis l’enfant cesse d’émettre alors que top montre du CPU au repos. Neuf fois sur dix ce n’est pas « de mauvais modèles », mais le tamponnage stdio plus la contre-pression de tube : l’enfant passe en mode entièrement tamponné par blocs car il ne voit plus de TTY ; des réponses partielles restent dans libc jusqu’à remplir un tampon. Le parent peut bloquer sur read() en attendant un délimiteur qui n’arrive jamais, ou l’enfant bloque sur write() car le parent n’a pas vidé le tube. Ce guide explique l’architecture, oppose tampon ligne vs bloc avec une matrice de symptômes, compare enveloppes PTY vs tubes bruts sous launchd, liste des atténuations pour Python (PYTHONUNBUFFERED=1, python -u), filtres POSIX (stdbuf -oL) et flux Node (garder stdout en mode flux), puis propose un triage en cinq étapes relié à déploiement MCP, redémarrage passerelle, dépannage déploiement et ulimits quand la cause réelle est la famine de descripteurs déguisée en « blocages ».
Architecture MCP stdio sur macOS (ce qui doit rester vrai)
Imaginez trois processus coopératifs : (A) la passerelle OpenClaw, (B) le binaire ou script serveur MCP, (C) des filtres optionnels (jq, runtimes). Tout participant qui bloque en écriture pendant qu’un autre attend la lecture pour la même dépendance circulaire crée un interblocage. Les transports stdio héritent aussi d’une discipline stderr : des bibliothèques bavardes qui crachent des barres de progression sur stderr peuvent remplir les tampons de tube du noyau si personne ne lit.
- Un message JSON par vidage est irréaliste — libc ne connaît pas les frontières JSON.
- Les grosses réponses exigent des lecteurs en flux ; si la passerelle tamponne toute la charge en RAM, vous ressentirez des « pauses » sans lien avec la sémantique MCP.
- launchd ne source pas vos rc de shell interactif — l’alignement d’environnement est manuel ; voir les motifs upgrade/rollback pour des redémarrages ordonnés après changement d’env.
Tampon ligne vs bloc (pourquoi le Terminal « marche »)
Beaucoup de CLI utilisent le tampon ligne quand isatty(stdout) est vrai, et le tampon bloc (souvent des multiples de 4–8 KiB) quand stdout est un tube. Sous un LaunchAgent sans interface, votre serveur MCP devient soudain écrivain de tube — les journaux « live » au Terminal sont groupés jusqu’à remplir le tampon. Ce délai ressemble à « le modèle s’est arrêté » alors que le LLM a fini il y a des secondes.
stdbuf -oL -eL uniquement pendant le triage — mesurez la latence avant de figer des enveloppes dans des plists de prod.
Matrice des symptômes MCP bloqué
| Signal | Plus probable qu’un bug MCP | Prouver / infirmer | Lien suivant |
|---|---|---|---|
| Premier RPC OK, le second bloque pour toujours | stdout tamponné par blocs | Même binaire sous script -q /dev/null (fumée PTY) | Cet article |
| CPU saturé, RAM plate | Boucle serrée sur fd vide | Échantillonner avec sample pid 5 -file /tmp/st.txt | Dépannage |
Too many open files | Ulimits, fan-out MCP | launchctl limit maxfiles vs limite souple du processus | Ulimits |
| Par intermittence après rotation des logs | Gestion SIGHUP / fds rouverts | Corréler horodatages avec newsyslog | Journaux |
Enveloppes PTY vs tubes bruts sous LaunchAgents
Des équipes enveloppent les serveurs MCP avec script, unbuffer ou des parents PTY maison pour que les enfants se croient interactifs. Compromis : les PTY ajoutent du CPU et du coût de copie mais retirent une classe de surprises de tampon. Les tubes bruts restent moins chers mais exigent un vidage discipliné dans l’enfant ou des cales stdbuf. Choisissez consciemment — mélanger les styles entre serveurs embrouille l’astreinte.
Atténuations toolchain (copier dans EnvironmentVariables du LaunchAgent)
Python : exporter PYTHONUNBUFFERED=1 ou appeler python3 -u ; pour les CLI packagées, préférer un point d’entrée qui invoque sys.stdout.reconfigure(line_buffering=True) sur les versions supportées. Node : consommez stdout en mode flux — les flux en pause sont un piège classique entre processus enfants. Go / Rust : videz explicitement après chaque trame JSON-RPC si vous contrôlez le code. Filtres shell : pensez à grep --line-buffered pour du tail via tubes en automatisation.
<key>EnvironmentVariables</key>
<dict>
<key>PYTHONUNBUFFERED</key>
<string>1</string>
<key>NODE_OPTIONS</key>
<string>--max-old-space-size=4096</string>
</dict>
Triage stdio en cinq étapes avant de réécrire l’agent
- Reproduire sous
sshen collant les mêmesProgramArgumentsdu plist dans un shell interactif — si ça marche soudain, vous avez un delta env/TTY. - Équivalent strace sur macOS :
sudo fs_usage -w -f filesys | grep mcpbrièvement pour voir des écritures bloquées (avec parcimonie en prod). - Séparer stderr vers un fichier rotatif pour que le spam de debug ne rivalise pas avec le JSON-RPC sur stdout.
- Test de trempage avec de grosses charges synthétiques après activation des atténuations.
- Choisir le transport : si stdio reste fragile, planifier du MCP HTTP selon le guide de déploiement.
FAQ
Augmenter le sysctl du tampon de tube règle-t-il le problème ? Dernier recours — la cause est souvent un rythme lecteur/écrivain désaccordé, pas seulement la taille du tampon.
Les serveurs MCP doivent-ils journaliser sur stdout ? Réservez stdout au JSON-RPC uniquement ; poussez les journaux humains vers stderr ou des fichiers structurés.
Apple Silicon change-t-il le tamponnage ? Non — le M4 vous fait juste toucher le bug plus vite, pas immuniser contre les défauts de libc.
Pourquoi le Mac mini ProxyMac est le bon endroit pour durcir le MCP stdio
Les mini Apple Silicon M4 en HK / JP / KR / SG / US offrent du métal toujours allumé pour rejouer chaque nuit les mêmes graphes stdio, accrocher de la capacité régionale à côté des API SaaS que vous appelez et garder des liens aide près du dépôt LaunchAgent. Quand des humains doivent valider des invites TCC, basculez sur VNC ; quand le réseau hésite, lisez IPv6 Happy Eyeballs SSH sur la même ligne de release.
Lancer OpenClaw sur du métal que vous pouvez stracer calmement
HK / JP / KR / SG / US · automatisation compatible stdio