8 min de lecture

Les processus MCP orphelins peuvent encore laisser du travail derrière eux

Les processus MCP orphelins demandent plus qu'une commande kill. Trouvez les serveurs stdio obsolètes, révoquez leur autorité et reliez leurs derniers appels à la session propriétaire.

Les processus MCP orphelins peuvent encore laisser du travail derrière eux

Un plantage du client ne vous dit pas si son serveur MCP s'est arrêté. Il vous dit seulement qu'un processus est mort, ou du moins qu'il ne répond plus. La distinction compte, car stdio est un transport, pas un interrupteur qui arrête le travail déjà passé d'un processus à un autre.

J'ai vu des équipes traiter un amas d'anciens processus auxiliaires comme un simple problème de ménage, puis découvrir que l'un d'eux détenait encore un jeton cloud, une socket de contrôle SSH ou une file de tâches que personne n'avait reliée à l'exécution ayant échoué. La commande de nettoyage était simple. Reconstituer l'identité de la personne ou du système ayant autorisé la dernière action était la partie oubliée.

La bonne réponse comporte trois tâches distinctes : identifier précisément le processus restant, déterminer s'il possède encore un moyen d'agir et conserver l'enregistrement qui relie ses derniers appels à la session qui les possédait. Faites-le dans cet ordre. Tuer le processus en premier peut faire disparaître le problème, mais aussi effacer les meilleures preuves de ce qui s'est passé.

Un processus sans parent est un indice, pas un verdict

Un processus orphelin est un enfant dont le parent initial s'est terminé et dont le parent au niveau du système d'exploitation a changé, souvent pour devenir le PID 1. C'est une information utile, mais ce n'est pas la définition d'un serveur MCP dangereux. Les superviseurs de processus, les shells, les IDE et les services de lancement peuvent réattribuer des processus enfants sains dans le cadre d'un fonctionnement normal.

Pour un serveur MCP stdio, posez une question plus précise : ce processus appartient-il encore à une connexion client active, ou a-t-il survécu après la disparition du client qui possédait ses entrées et sorties standard ? La réponse combine l'ascendance du processus, les descripteurs ouverts, le temps écoulé et un relevé d'activité.

La documentation du Model Context Protocol décrit stdio comme une intégration locale lancée sous forme de processus. Le client démarre une commande et échange du JSON-RPC délimité par des retours à la ligne via l'entrée et la sortie standard du serveur. Cette conception donne à un serveur correctement écrit un signal de fin simple : lorsque son entrée atteint EOF, le client a disparu.

EOF prouve que le transport est rompu ou fermé. Il ne prouve pas que chaque processus de travail, processus enfant, connexion réseau, minuteur ou tâche distante s'est arrêté. Un serveur peut recevoir un appel d'outil, commencer le travail, puis perdre le client avant de produire une réponse JSON-RPC. Si le gestionnaire a lancé un sous-processus ou envoyé une requête à un système distant, ce travail peut avoir sa propre durée de vie.

C'est ici que deux échecs différents sont souvent confondus :

  • Un orphelin du système d'exploitation a perdu son parent initial ou s'est détaché de l'arbre de processus attendu.
  • Un orphelin logique a perdu la session qui donnait un sens à son travail, même si son PID parent semble encore normal.

Le premier peut gaspiller de la mémoire ou garder un port ouvert. Le second peut provoquer une modification externe indésirable. Vous devez examiner les deux.

Un processus dont le PPID vaut 1, dont le temps écoulé est ancien et qui n'a pas d'entrée standard ouverte est suspect. Un processus encore attaché à un terminal actif peut aussi être dangereux si son client propriétaire est silencieusement bloqué et qu'il possède un identifiant ou une connexion réutilisable. À l'inverse, un processus qui reste actif après un plantage peut être inoffensif s'il ne possède aucune autorité et ne peut atteindre aucun canal d'action.

Ne construisez pas une règle disant « PPID 1 signifie qu'il faut tuer le processus ». Créez un relevé indiquant pourquoi ce processus existe, quelle exécution l'a créé, ce qu'il peut encore atteindre et ce que vous en avez fait.

Commencez par un inventaire des processus que vous pouvez justifier

Prenez un instantané avant d'envoyer le moindre signal. Vous ne pourrez pas récupérer une ligne de commande, un groupe de processus ou un descripteur ouvert après avoir terminé le processus, et la réutilisation des PID transforme rapidement des notes vagues en suppositions.

Sur macOS, commencez par la vue complète plutôt que par une ligne unique astucieuse qui filtrerait les preuves dont vous avez besoin :

ps -axo user,pid,ppid,pgid,stat,etime,command

Cherchez les commandes démarrées par votre client MCP. Il peut s'agir d'un binaire serveur direct, d'un interpréteur comme node ou python, d'un lanceur de paquet, d'un auxiliaire SSH ou du shim sp mcp. Copiez les lignes pertinentes dans une note d'incident avant de réduire la recherche.

Les champs répondent à des questions différentes :

  • pid identifie le processus uniquement pour cette inspection.
  • ppid indique si son parent immédiat existe encore.
  • pgid identifie le groupe de processus et révèle souvent les auxiliaires frères lancés ensemble.
  • stat peut montrer un processus en veille, arrêté ou bloqué dans un état impossible à interrompre.
  • etime indique si une exécution supposée récente est là depuis des heures ou des jours.
  • command est souvent le dernier relevé conservé du fichier exécutable et des arguments utilisés au lancement.

Examinez ensuite directement chaque candidat. Remplacez le PID par sa valeur réelle et enregistrez la sortie avec un horodatage dans votre relevé d'incident.

ps -o pid=,ppid=,pgid=,stat=,etime=,user=,command= -p 48271
lsof -nP -p 48271

La première commande fournit une fiche d'identité compacte. La seconde indique ce que le processus garde ouvert. Portez une attention particulière aux descripteurs 0, 1 et 2. Un serveur stdio normal possède généralement une extrémité de lecture pour stdin et des extrémités d'écriture pour stdout et stderr. Si stdin a atteint EOF, le processus peut encore afficher un descripteur de tube. Ne déduisez donc pas que le processus est actif uniquement parce que ce descripteur est présent. Cherchez une vue plus large : processus pair, terminaux, fichiers ordinaires, sockets Unix, connexions TCP et processus enfants.

lsof peut aussi révéler une erreur que les listes de processus dissimulent. Supposons que le parent du serveur ait disparu, mais que le serveur possède encore une connexion TCP établie vers une API interne. Cela ne prouve pas qu'il peut envoyer une nouvelle requête, mais vous disposez d'une capacité concrète à examiner. S'il possède une socket de contrôle SSH ou une socket Unix locale reliée à un assistant d'identification, considérez cela comme une piste, pas comme une raison de supposer qu'il est inoffensif.

Vérifiez le groupe de processus avant d'agir :

ps -axo pid,ppid,pgid,stat,etime,command | awk '$3 == 48271 || $2 == 48271'

Cet exemple suppose que 48271 est l'identifiant du groupe observé. Adaptez-le à la valeur réelle. La sortie peut montrer un wrapper, un serveur et un processus enfant auxiliaire qu'un simple kill appliqué à un seul PID laisserait actifs. Elle peut aussi prouver qu'il ne reste aucun processus frère et qu'il est plus facile à isoler.

Évitez un raccourci courant : chercher uniquement node, python ou npx et tuer toutes les correspondances. Ces noms désignent des environnements d'exécution, pas des identités. Un nettoyage trop large peut interrompre une extension d'éditeur, un test local, une tâche de compilation ou une automatisation sans rapport. Comparez la ligne de commande complète avec la configuration attendue du serveur, puis examinez son parent et son groupe.

Si votre client enregistre la commande du serveur au lancement, placez cette commande à côté du relevé de session. Une enquête ultérieure passera ainsi d'une recherche imprécise par nom de processus à une comparaison directe.

Le tube stdio ne définit pas la limite de l'action

Un serveur stdio correctement écrit doit cesser d'accepter des requêtes lorsque stdin se ferme. Il doit annuler le travail qui n'a pas commencé, fermer son transport et quitter après avoir effectué les opérations de nettoyage limitées dans le temps. Le guide officiel du SDK MCP TypeScript souligne le même point dans sa section sur l'arrêt : fermer un transport ne vide pas automatiquement les gestionnaires d'outils en cours avant la fin du processus.

Cette dernière précision mérite plus d'attention. Lorsqu'un client plante, un gestionnaire d'outil peut se trouver dans plusieurs états :

  1. Il n'a pas commencé le travail externe et peut être annulé proprement.
  2. Il a envoyé une requête, mais n'a pas reçu de réponse.
  3. Il a terminé la modification distante, mais a perdu le chemin de réponse avant de pouvoir signaler le succès.
  4. Il a lancé un processus enfant local ou une tâche distante qui survit au gestionnaire.
  5. Il est bloqué en attente d'une dépendance externe et peut reprendre plus tard.

Seul le premier état peut être décrit sans risque comme « rien ne s'est passé ». Les quatre autres exigent des relevés situés en dehors du processus client mort.

Prenons un exemple concret. Un serveur reçoit un appel d'outil qui déploie une compilation. Il écrit la requête dans une API de compilation distante, puis le client plante pendant que l'API la traite. Le serveur voit que son tube stdout est rompu. S'il quitte immédiatement, la compilation peut continuer. S'il réessaie sans mécanisme d'idempotence, il peut en lancer une seconde. S'il reste actif avec un identifiant à longue durée de vie, il peut interroger l'API, réessayer ou lancer du travail de suivi après la disparition du client d'origine.

Le problème n'est pas que le serveur soit resté actif. Le problème est de traiter la fermeture du transport comme une conclusion complète sur l'autorisation, l'annulation et l'état distant.

Pour chaque canal d'action, définissez explicitement la limite :

  • Quel événement empêche l'arrivée de nouvelles tâches dans le serveur ?
  • Quel identifiant permet d'interroger ou d'annuler le travail déjà envoyé ?
  • L'opération distante prend-elle en charge l'idempotence ou un jeton de requête ?
  • Quel processus conserve encore l'identifiant après la disparition du client ?
  • Où le résultat final est-il enregistré si la réponse JSON-RPC ne peut pas être livrée ?

Si vous ne pouvez pas répondre à ces questions pour un outil à fort impact, ne le considérez pas comme sûr simplement parce qu'il utilise stdio.

La même règle s'applique à SSH. Une commande qui ressemble à une commande interactive peut avoir démarré un processus en arrière-plan sur l'hôte distant. La fermeture du client local peut fermer le canal local tandis qu'une commande distante détachée de son shell continue. Un serveur a besoin d'une conception qui rende le travail distant observable et annulable, pas d'une confiance aveugle dans la déconnexion du terminal.

Prouvez si le processus restant peut encore agir

L'existence d'un processus ne constitue pas une autorité. Vous devez tester le chemin d'action sans déclencher une véritable action.

Commencez par identifier l'emplacement de l'autorité. Un serveur qui lit un jeton API dans son propre environnement présente un profil de risque différent de celui qui demande à un courtier séparé d'effectuer chaque action. Un serveur qui possède une clé privée SSH dans un fichier présente un profil différent de celui qui délègue l'action à un assistant local de courte durée. Notez la réponse pour le serveur examiné.

Examinez ensuite ce que le processus garde ouvert et ce qu'il peut encore atteindre. lsof fournit un point de départ, mais ne révèle pas tous les identifiants en mémoire ni toutes les sessions authentifiées. Complétez-le avec vos propres journaux d'actions et, lorsque c'est possible, avec la piste d'audit du système externe.

Une séquence d'enquête utile ressemble à ceci :

  1. Enregistrez le PID candidat, la commande, le PPID, le groupe de processus et les sockets réseau ou Unix ouverts.
  2. Trouvez la dernière action externe liée à ce processus ou à sa session.
  3. Vérifiez si une nouvelle action a eu lieu après l'heure du plantage du client.
  4. Révoquez ou désactivez le chemin d'autorisation du processus.
  5. Observez si le processus tente une autre action et si la passerelle la refuse.

Ne faites pas un test en demandant au serveur orphelin d'effectuer une écriture qui semble inoffensive. De nombreux systèmes ne possèdent aucune écriture réellement inoffensive. Un appel de test peut modifier des limites de débit, créer du bruit dans les audits, faire tourner un état ou déclencher une automatisation. Préférez un point de terminaison de santé ou d'identité en lecture seule si votre conception en prévoit un. Mieux encore, validez le refus depuis la passerelle ou le courtier d'identifiants après la révocation.

Il faut distinguer deux choses : un processus qui dispose encore d'un accès réseau n'est pas forcément capable d'agir, et un processus sans connexion réseau visible peut encore être capable d'agir plus tard. La résolution DNS, un proxy, un assistant local, un minuteur en file d'attente ou un processus enfant peuvent rouvrir le chemin. C'est pourquoi le test de révocation compte davantage qu'un instantané des sockets.

Si le serveur détient directement un secret réutilisable, votre périmètre de nettoyage doit inclure sa rotation ou sa révocation. Tuer le processus supprime une copie de la mémoire, mais ne change pas ce qu'un attaquant, une image mémoire du processus ou un service distant peut faire avec le même secret. Les équipes évitent souvent la rotation parce qu'elle demande du travail. C'est compréhensible, mais ce n'est pas un argument de sécurité.

Un modèle avec passerelle change l'enquête. Le serveur peut survivre comme processus non fiable et ne plus pouvoir effectuer d'appel protégé, parce qu'il ne possède jamais l'identifiant et n'a plus de session active approuvée. Sallyport conserve les secrets API et SSH dans son coffre chiffré et exécute lui-même l'action. L'agent ne reçoit donc ni le secret en clair ni une valeur de remplacement. Cela réduit les dommages qu'un processus stdio égaré peut causer, mais vous devez tout de même révoquer une exécution suspecte au lieu de supposer qu'un plantage l'a fait automatiquement.

La règle pratique est simple : après la révocation de la session ou du chemin d'action, tout appel protégé doit être refusé et ce refus doit être enregistré. Si vous ne pouvez pas le démontrer, vous n'avez pas confirmé le confinement.

Enregistrez les derniers appels avant que le nettoyage ne modifie l'histoire

Garder les secrets hors des processus auxiliaires
Sallyport conserve les secrets API et SSH dans son coffre chiffré, jamais dans le processus de l'agent.

Un relevé d'incident a besoin d'identifiants stables, pas d'un récit reconstitué de mémoire. Un PID est temporaire et peut être réutilisé. Une commande peut changer après une mise à jour. Un identifiant de session et un relevé d'audit résistant aux altérations offrent un point d'ancrage bien meilleur.

Créez au minimum une ligne par processus suspect avec les champs suivants :

Observed at:
Client process PID and command:
MCP server PID and command:
Parent PID and process group:
Session identifier:
Authorization state:
Last successful action time:
Last attempted action time:
Action target and operation:
Result or remote job identifier:
Revocation time and operator:
Termination signal and exit result:
Follow-up required:

Le couple le plus important est l'identifiant de session et la dernière action tentée. De nombreuses équipes n'enregistrent que les appels réussis, ce qui masque le moment le plus révélateur d'une enquête après un plantage : la requête qui a quitté la machine locale sans jamais recevoir de résultat.

Conservez trois horodatages distincts. Notez le moment où le client est devenu indisponible, celui où la dernière action connue du serveur a commencé et celui où vous avez révoqué l'autorité. Avec un seul « moment de l'incident », vous ne pouvez pas savoir si un appel a eu lieu avant le plantage, pendant une période incertaine ou après le confinement qui aurait dû être effectif.

Conservez aussi la cible de l'action. « Appel d'une API cloud » ne suffit pas. Indiquez le compte ou la catégorie du point de terminaison, la méthode ou la catégorie de commande SSH et tout identifiant de requête ou de tâche permettant à un opérateur de rechercher l'opération dans le service distant. Évitez de stocker des corps de requête sensibles dans une note d'incident générale. Vous devez disposer de suffisamment d'informations pour rapprocher l'effet produit, pas d'une seconde copie de chaque secret et de chaque donnée client.

Pour une passerelle qui possède des journaux distincts de sessions et d'activités, utilisez les deux. Le relevé de session indique qui a lancé le processus de l'agent et si cette exécution reste autorisée. Le relevé d'activité indique quels appels individuels ont eu lieu et dans quel ordre. Ce sont deux questions différentes. Les fusionner dans un seul flux d'événements général rend chacune plus difficile à résoudre sous pression.

Sallyport produit ces deux journaux à partir d'un journal d'audit chiffré et chaîné par hachage. Après avoir capturé les entrées de session et d'activité pertinentes, lancez la vérification d'intégrité hors ligne :

sp audit verify

Enregistrez le résultat exact de la commande avec le relevé d'incident. La vérification ne décide pas si l'action était autorisée ou judicieuse. Elle indique si la chaîne d'audit sur laquelle vous vous appuyez est toujours valide, sans nécessiter d'accès au coffre. Cette séparation est utile lorsque la personne qui examine l'incident ne doit pas recevoir d'identifiants uniquement pour vérifier l'historique.

N'attendez pas un incident de sécurité officiel pour vous exercer à cette tenue de registres. C'est lors d'une revue de plantage ordinaire que vous trouverez les identifiants de session manquants, les commandes ambiguës et les journaux qui n'existent que sur la machine morte. Corriger ces lacunes pendant un nettoyage calme coûte bien moins cher que de les découvrir après une écriture en production.

Révoquez l'autorité avant de terminer le processus

L'ordre le plus sûr est le suivant : révoquer, vérifier le refus, puis arrêter le processus. L'ordre inverse semble plus rapide, car le processus disparaît immédiatement, mais il peut laisser un enregistrement d'autorisation actif et compliquer les corrélations ultérieures.

Commencez par la révocation efficace la plus ciblée. Si le système suit l'autorisation par exécution d'agent, révoquez cette exécution. Si un identifiant unique a été exposé au serveur, désactivez-le ou faites-le tourner. Si une tâche distante possède un mécanisme d'annulation, annulez cette tâche séparément. Ce sont des actions différentes, car elles concernent des durées de vie différentes.

Ne supposez pas que la fin du serveur annule le travail distant. Un processus peut avoir disparu alors que sa requête reste en file d'attente. Ne supposez pas non plus qu'une annulation distante arrête le serveur. Le processus peut réessayer ou soumettre une autre requête s'il conserve son autorité. Le confinement exige que les côtés local et distant considèrent tous deux l'exécution comme terminée.

Une fois le chemin d'action révoqué, vérifiez l'état avec des preuves adaptées à votre configuration. Il peut s'agir d'un refus enregistré dans le journal d'activité de la passerelle, d'une requête authentifiée échouant vers un point de terminaison d'identité sans danger ou d'une entrée d'audit distante indiquant que le jeton a été désactivé. La méthode exacte varie. Le principe reste le même : prouvez qu'un processus survivant ne peut pas effectuer d'appel protégé.

Envoyez ensuite un signal de terminaison normal au PID identifié :

kill -TERM 48271
sleep 2
ps -p 48271 -o pid=,ppid=,stat=,etime=,command=

Si la dernière commande ne renvoie aucune ligne de processus, notez ce résultat. S'il reste actif, vérifiez s'il est en train de s'arrêter, bloqué dans une opération d'entrée-sortie ou s'il maintient un travail enfant en vie. Avant d'escalader, examinez à nouveau le groupe et les enfants. Vous devrez peut-être terminer séparément un auxiliaire connu, mais ne tuez pas aveuglément tout un groupe de processus sans avoir confirmé que chacun de ses membres appartient à la même exécution défaillante.

N'utilisez kill -KILL que lorsque la terminaison normale échoue et que vous avez préservé les preuves. SIGKILL ne laisse au processus aucune possibilité de fermer ses fichiers, d'annuler son travail, d'émettre un dernier journal ou de supprimer son état temporaire. C'est parfois le bon compromis. Appelez-le pour ce qu'il est : un confinement forcé qui peut laisser un nettoyage incomplet.

Le Moniteur d'activité de macOS peut aider lorsque la ligne de commande ne suffit pas. Apple documente une action Quitter normale et une action Forcer à quitter, et l'outil peut afficher les processus sous forme hiérarchique. Cette vue est utile pour confirmer les relations parent-enfant. Elle ne remplace pas le relevé d'incident, car une liste graphique ne conserve pas les preuves de session et d'action dont vous aurez besoin plus tard.

Faites de l'arrêt du serveur une exigence de conception

Séparer les sessions des actions
Sallyport enregistre séparément les exécutions et les appels, afin de distinguer la propriété du processus de l'historique des actions.

Les serveurs stdio doivent traiter la disparition du client comme un événement normal, et non comme un cas exceptionnel. Les plantages de clients font partie du fonctionnement habituel des logiciels. Les ordinateurs portables se mettent en veille, les terminaux se ferment, les IDE redémarrent, les mises à jour interrompent les processus et les agents peuvent s'arrêter après une erreur du modèle.

Un serveur doit disposer d'un chemin d'arrêt explicite avec quatre propriétés. Il cesse d'accepter de nouvelles requêtes lorsque l'entrée se ferme. Il suit chaque action démarrée avec un identifiant de corrélation. Il laisse au travail actif un délai limité pour s'annuler ou atteindre un état connu. Il quitte ensuite, au lieu de devenir accidentellement un service permanent en arrière-plan.

Ne confondez pas arrêt gracieux et attente infinie. Un serveur qui reçoit EOF et attend indéfiniment une API externe devient un orphelin mieux élevé. Fixez une limite au nettoyage, consignez ce qui reste irrésolu et quittez. Le travail non résolu doit rester consultable grâce à son identifiant de tâche externe ou à son relevé d'action.

La gestion des enfants compte tout autant. Si un outil lance un compilateur, un gestionnaire de paquets, un auxiliaire SSH, un pilote de navigateur ou un wrapper de commande, le serveur doit savoir si cet enfant doit mourir avec lui. Configurez délibérément les groupes de processus. Capturez les PID enfants. À l'arrêt, terminez uniquement les enfants appartenant à la requête, puis notez s'ils ont quitté le processus.

Évitez de mettre du travail en arrière-plan par l'intermédiaire d'un shell, sauf si le contrat de l'outil prévoit explicitement un travail durable. Une commande telle que some-command & crée une seconde durée de vie que votre serveur MCP peut ne pas observer. Si vous avez besoin d'un travail durable, envoyez-le à un système de tâches qui renvoie un identifiant, puis exposez des outils dédiés pour consulter son état et l'annuler. Un travail caché en arrière-plan n'est pas de la durabilité. C'est une lacune d'audit.

Utilisez l'idempotence lorsque le service distant la prend en charge. Attribuez à chaque écriture externe un identifiant de requête dérivé de la session et de l'appel d'outil, puis enregistrez cet identifiant avant d'envoyer la requête. Si le client plante après l'envoi, vous pouvez interroger le système distant au lieu de deviner s'il faut réessayer. Lorsqu'il ne prend pas l'idempotence en charge, documentez l'ambiguïté et exigez une décision d'opérateur avant de rejouer une écriture.

Un serveur doit aussi écrire ses diagnostics sur stderr, jamais sur stdout. Stdout est réservé au flux JSON-RPC MCP délimité par des retours à la ligne. Une ligne de débogage parasite peut corrompre le protocole, provoquer une défaillance du client et créer précisément le type de plantage que vous cherchez à nettoyer. Ce détail paraît insignifiant jusqu'au jour où un serveur de production affiche un avertissement de bibliothèque au démarrage.

Placez la propriété dans le relevé d'action, pas dans l'historique du shell

Retrouver les derniers appels protégés
Le journal Activity montre les appels HTTP et SSH individuels autour de la période du plantage.

L'historique du shell est pratique jusqu'à ce qu'il soit absent, tronqué, partagé ou écrit après la mort du processus. Le relevé d'action doit porter les informations de propriété pendant que le travail est en cours.

Pour chaque appel susceptible de toucher un système externe, joignez suffisamment de contexte pour répondre plus tard à quatre questions : quelle exécution d'agent l'a demandé, quel processus local l'a soumis, quelle décision d'autorisation l'a permis et quelle opération externe en a résulté. Si l'une de ces informations manque, un plantage du client laisse un trou que l'enquêteur doit combler par déduction.

Ne surchargez pas l'identité de signature du code pour répondre à toutes les questions de propriété. Elle indique qui a signé l'exécutable, ce qui aide à décider si un processus mérite une approbation. Elle n'identifie ni l'exécution individuelle, ni l'instruction qui a conduit à l'appel, ni la requête distante. Utilisez l'autorité de signature du code pour la confiance au début de la session, puis un identifiant de session et des relevés par appel pour la traçabilité opérationnelle.

Le même avertissement s'applique aux lignes de commande. Une commande peut indiquer que sp mcp ou un exécutable serveur a démarré. Elle ne peut pas dire de manière fiable quel appel d'outil était le dernier, si un utilisateur l'a approuvé ou si le système distant l'a accepté. Considérez la liste des processus comme une preuve secondaire, pas comme la source d'audit.

Lorsqu'un plantage se produit, corrélez les éléments dans cet ordre :

  1. Trouvez l'exécution de l'agent qui possédait le processus client au moment du plantage.
  2. Trouvez le processus serveur ou le groupe de processus lancé par cette exécution.
  3. Localisez les dernières entrées d'activité de cette exécution et comparez leurs horodatages avec l'instantané des processus.
  4. Rapprochez toute opération externe inachevée à l'aide de son identifiant de requête, de transaction ou de tâche.
  5. Enregistrez les événements de révocation et de terminaison à côté des derniers appels.

Cette séquence évite une erreur familière : trouver un PID obsolète, le tuer, puis attribuer plus tard son dernier appel API au mauvais agent parce que deux sessions utilisaient la même commande serveur. Les commandes se répètent. Les relevés de session ne devraient pas se répéter.

Si votre environnement ne permet pas encore cette corrélation, ajoutez-la avant d'accorder l'accès en écriture à des outils autonomes. Une expérimentation en lecture seule peut tolérer une observabilité imparfaite. Les modifications de production ne le peuvent pas.

Un exercice de plantage révèle les lacunes lorsque les enjeux sont faibles

Effectuez un exercice de plantage contrôlé pour chaque serveur MCP capable d'apporter des modifications externes. Faites-le dans un compte de test ou avec un chemin d'action en lecture seule et recueillez les preuves comme s'il s'agissait d'un incident réel.

Démarrez une session client normale et lancez une action avec un identifiant de corrélation connu. Pendant que le serveur est actif, terminez brutalement le client. Examinez ensuite le PID du serveur, son PPID et son groupe de processus, ses descripteurs ouverts et le journal d'action. Révoquez la session. Vérifiez qu'un appel protégé ultérieur est refusé. Enfin, terminez le serveur s'il n'est pas sorti après EOF et rapprochez l'action externe.

L'exercice doit produire des réponses, pas une simple étiquette de réussite ou d'échec. Vous devez savoir si la fermeture de stdin atteint le serveur, si des processus enfants persistent, si les tâches distantes disposent de mécanismes d'annulation, si vos journaux identifient le propriétaire et si la révocation modifie immédiatement le comportement.

Soyez attentif au moment du plantage. Un plantage qui survient avant la transmission de la requête se comporte différemment d'un plantage survenant après l'acceptation de la requête par le service distant. Répétez l'exercice à ces deux moments si le serveur fournit suffisamment d'instrumentation. La frontière difficile entre « envoyé » et « confirmé » est l'endroit où naissent les écritures en double et les fausses assurances.

Écrivez l'attente de nettoyage pour chaque serveur. Une bonne attente est précise : après la fermeture de l'entrée, le serveur cesse d'accepter les appels, quitte dans le délai configuré, ne laisse aucun processus auxiliaire dont il est propriétaire et crée une entrée d'activité pour chaque action externe démarrée. Une attente faible serait « le client s'en occupe normalement ». Le comportement normal n'est pas un contrôle.

Après quelques exercices, les processus obsolètes cessent d'être mystérieux. Ils deviennent un mode de défaillance défini, avec un instantané du processus, une trace de propriété, une action de révocation et une règle de nettoyage. C'est l'objectif. Le processus peut planter. Votre capacité à expliquer et à contenir ses derniers appels ne devrait pas disparaître.

FAQ

Qu'est-ce qu'un processus MCP orphelin ?

Il s'agit d'un processus de serveur MCP local qui survit au processus client ou à la connexion qui l'a lancé. Un processus dont le PPID vaut 1 est un indice utile, mais ce n'est pas une preuve en soi, car les lanceurs et les gestionnaires de services peuvent aussi réattribuer des processus enfants en bonne santé.

Un serveur MCP orphelin peut-il encore effectuer des appels API ?

Parfois. Si le serveur possède un jeton API, un identifiant SSH, une connexion authentifiée réutilisable ou un processus auxiliaire en arrière-plan, il peut encore modifier des systèmes externes après la disparition du client MCP. Un canal stdio fermé met fin à la conversation du protocole, mais n'annule pas le travail que le serveur a déjà transmis ailleurs.

Comment trouver les serveurs MCP obsolètes sur macOS ?

Commencez par relever l'identité du processus, le PID parent, le groupe de processus, le temps écoulé, la ligne de commande et les descripteurs ouverts. Comparez ensuite sa dernière action externe connue avec votre journal d'actions. Une simple liste de processus ne permet pas de savoir s'il dispose encore d'une autorité.

Dois-je tuer immédiatement un processus MCP orphelin ?

Utilisez d'abord un signal de terminaison normal, puis vérifiez que le PID a disparu et qu'aucun processus enfant ne reste actif. Force Quit ou SIGKILL ne doit être utilisé qu'après avoir recueilli les preuves et accepté qu'une opération en cours puisse s'arrêter au milieu.

Un identifiant de session MCP est-il la même chose qu'un PID ?

Non. Le PID identifie un processus du système d'exploitation, tandis qu'une session MCP identifie une exécution précise du protocole. Un même client peut créer plusieurs processus serveur et un processus survivant peut être détaché de la session qui l'avait initialement autorisé.

Comment empêcher les agents obsolètes de conserver des identifiants ?

La conception la plus sûre garde les identifiants hors de l'agent et du serveur stdio, puis exige un chemin d'autorisation actif pour chaque action. Un processus peut rester en mémoire, mais il ne peut pas faire grand-chose s'il ne peut ni récupérer un secret ni soumettre une action approuvée.

Que doit contenir le relevé d'un incident MCP ?

Notez le processus de l'agent, le PID du serveur, l'identifiant de session, l'heure de l'action, la cible, la méthode ou la commande, le résultat et la décision de terminaison. Recueillez ces informations avant le nettoyage, car les PID sont réutilisés et l'historique du terminal constitue un mauvais relevé d'incident.

L'approbation du client expire-t-elle lorsqu'un client MCP plante ?

Si l'approbation appartient à un processus d'agent toujours actif, elle peut rester valide jusqu'à la fin de ce processus ou jusqu'à la révocation de la session par un opérateur. Considérez le plantage du client comme une raison d'examiner la session, et non comme la preuve que tous les processus associés ont perdu leur autorisation.

Comment un serveur MCP stdio doit-il gérer les plantages du client ?

Fermez stdin, traitez EOF comme un événement d'arrêt, annulez le travail en attente, limitez la durée des requêtes et veillez à ce que les processus auxiliaires meurent avec leur parent. Le serveur doit aussi consigner l'identité de la requête avant de commencer une action externe, et non après son retour.

Comment Sallyport peut-il aider à examiner un client MCP qui a planté ?

Utilisez le journal des sessions pour trouver et révoquer l'exécution, puis le journal des activités pour exporter ou consigner les derniers appels avant et après le plantage. Exécutez sp audit verify sur les données d'audit conservées afin de vérifier que l'historique consulté n'a pas été modifié.

Sallyport

Sallyport exécute les appels d'API et les commandes SSH à la place de votre agent IA. Les clés restent dans un coffre-fort local sur votre Mac ; vous approuvez chaque exécution et chaque action est consignée dans un journal scellé.

© 2026 Sallyport · Open source sous Apache-2.0 · Oleg Sotnikov