Pourquoi deux transports MCP — stdio et HTTP
Un serveur MCP fait une chose : exposer des outils invocables Ă un client
agentique, en dialoguant en JSON-RPC 2.0. Cette mécanique d'appel est indépendante
du canal par lequel les messages circulent. Ce canal — le transport — peut
prendre deux formes : un sous-processus local piloté par le client (stdio) ou
un service réseau interrogé à distance (HTTP).
Cette pièce explique pourquoi les deux coexistent, ce que chacun coûte et rapporte, et sur quels critères trancher. Elle ne décrit pas comment les configurer : pour la recette côté client, voir le guide Brancher un client agentique ; pour le contrat exact du serveur (points d'entrée, handshake, codes d'erreur), voir la référence Serveur MCP.
Une distinction : le protocole n'est pas le transport
MCP définit ce qui est échangé — un handshake d'initialisation, un catalogue d'outils, des appels d'outils, des réponses. Il ne définit pas par où ces messages transitent. La même conversation JSON-RPC peut donc voyager sur deux tuyaux différents sans que la logique métier du serveur change d'une ligne.
C'est cette séparation qui rend le double support peu coûteux : le serveur écrit sa logique une fois, et deux adaptateurs de transport la branchent sur deux canaux. Le choix du transport n'est pas un choix de fonctionnalité — les mêmes outils sont exposés dans les deux cas — mais un choix de topologie de déploiement et de modèle de menace.
stdio — le serveur vit dans la machine du client
En stdio, le client lance lui-mĂŞme le serveur comme un sous-processus enfant et
lui parle sur l'entrée/sortie standard : une requête écrite sur stdin, une réponse
lue sur stdout, un message JSON par ligne.
Ce que ce modèle apporte :
- Aucune surface réseau. Il n'y a ni port ouvert, ni écoute, ni requête qui sort de la machine. Rien à exposer, donc rien à attaquer depuis le réseau. Pour une charge de travail confidentielle ou une machine sans connectivité vers un serveur distant, c'est un argument de sécurité fort.
- Le secret reste local. Le token d'authentification est passé dans l'environnement du sous-processus, transmis d'un parent à son enfant sur la même machine. Il ne traverse aucun lien réseau.
- Le cycle de vie est trivial. Le serveur naît quand le client le démarre et meurt quand le client s'arrête. Pas de service à superviser, à redémarrer, à surveiller.
- Idéal en développement. On itère sur le code du serveur et le client relance le sous-processus ; pas de déploiement dans la boucle.
Ce qu'il coûte :
- Couplé à la machine. Le binaire du serveur — et donc tout son environnement d'exécution, ses dépendances, sa base de données, son cœur de recherche — doit tourner là où tourne le client. Un serveur qui a besoin d'une infrastructure lourde n'est pas raisonnablement déployable sur chaque poste.
- Mono-client par nature. Chaque client démarre son sous-processus. Il n'y a pas de service partagé : rien n'est mutualisé entre plusieurs utilisateurs ou plusieurs postes.
- Fragile au canal. Puisque le protocole s'appuie sur
stdout, tout ce qui pollue la sortie standard casse le dialogue. Les journaux doivent impérativement partir sur la sortie d'erreur, et les fins de ligne parasites (par exempleCRLFsur certaines plateformes) suffisent à corrompre le parsing. Le transport le plus simple a ses propres pièges, purement mécaniques.
HTTP — le serveur est un service que l'on interroge
En HTTP, le serveur est un service déployé que le client contacte par le réseau.
Le client n'a plus rien à lancer : il envoie ses messages JSON-RPC à un point d'entrée
et reçoit les réponses ; un canal en flux (SSE) permet au serveur de pousser des
messages quand c'est nécessaire.
Ce que ce modèle apporte :
- Accessible à distance. Le serveur peut vivre là où est son infrastructure — proche de sa base de données et de son cœur de recherche — et être consommé depuis n'importe quel poste, n'importe quel répertoire de travail, sans rien installer localement.
- Multi-clients par construction. Un seul service répond à plusieurs clients. Cela autorise la mutualisation : un déploiement, plusieurs consommateurs, et une logique de locataires/périmètres appliquée côté serveur.
- Indépendant de l'environnement local. Le client n'a pas besoin des dépendances du serveur ; il n'a besoin que d'un accès réseau et d'un token.
Ce qu'il coûte — et c'est le cœur de l'arbitrage :
- Il expose une surface réseau. Dès qu'un service écoute, il devient une cible.
L'authentification n'est plus une commodité locale mais une frontière défensive :
chaque appel doit présenter un jeton, transporté cette fois dans un en-tête de la
requête, c'est-à -dire sur le réseau. Ce déplacement du secret hors de la machine
est précisément ce que
stdioévitait. Il impose des exigences que le local n'avait pas : chiffrement du transport, jeton révocable, refus explicite et distinct selon que le jeton manque ou n'est plus valide. - Le handshake devient un état à gérer. En local, une conversation = un sous-processus, et l'état de session est implicite. Sur le réseau, plusieurs clients partagent le même service : le serveur doit savoir à quelle conversation rattacher chaque message. D'où une notion de session et une phase d'initialisation à respecter — un appel d'outil émis avant la fin du handshake est légitimement rejeté. Cette statefulness est le prix du partage. (Le détail du handshake et des identifiants de session est dans la référence.)
- Plus de pièces Ă opĂ©rer. Un service rĂ©seau se dĂ©ploie, se supervise, se met Ă
jour, se protège. Ce que
stdioobtenait gratuitement — naître et mourir avec le client — devient une responsabilité d'exploitation.
Le même serveur, deux modèles de menace
Le point à retenir n'est pas qu'un transport serait « plus sûr » que l'autre dans l'absolu, mais qu'ils déplacent le risque à des endroits différents :
- En
stdio, le secret et l'exécution restent dans le périmètre de confiance de la machine du client. Il n'y a pas de réseau à défendre ; la sécurité repose sur la machine elle-même. - En
HTTP, le secret franchit le réseau et le service est atteignable de l'extérieur. La sécurité repose alors sur l'authentification, le confinement des périmètres d'accès et la discipline d'exploitation du service.
Le serveur applique par ailleurs les mêmes garde-fous au-dessus du transport, quel qu'il soit : vérification du jeton, périmètres d'accès (scopes), quotas, journal d'audit, confinement des chemins de fichiers lisibles. Ces protections ne dépendent pas du canal — elles s'appliquent identiquement aux deux. Le transport ne change que d'où vient l'appelant et par où voyage le secret.
Comment trancher
Le critère décisif est simple : où vit le serveur par rapport au client ?
- Le serveur tourne sur la machine du client — développement, poste isolé, charge
confidentielle, absence de connectivité vers un service distant :
stdio. On gagne la simplicité et l'absence de surface réseau, on accepte le couplage à la machine et le mono-client. - Le serveur est déployé ailleurs et sert plusieurs consommateurs — cas par défaut
d'un composant partagé et multi-locataire :
HTTP. On gagne l'accès distant et la mutualisation, on accepte d'exposer et de défendre une surface réseau.
Il n'y a pas de transport supérieur : il y a une topologie, et un modèle de menace qui en découle. Supporter les deux, c'est refuser de figer ce choix dans le composant — et laisser chaque déploiement le trancher selon sa situation.
Pour aller plus loin
- Serveur MCP — référence — points d'entrée, handshake, authentification, codes d'erreur : le contrat exact des deux transports.
- Brancher un client agentique — la recette de configuration côté client, transport par transport.
- Un cœur, trois surfaces — où se situe la surface MCP dans la stratégie IA d'ensemble.