Chapitre 3 — Primitives du serveur : exposer le contexte et les capacités
Troisième billet de la tournée chapitre par chapitre de LLM Primer IV : Concevoir la cognition de l'IA avec MCP. Le chapitre où l'on apprend ce qu'un serveur MCP peut réellement dire — trois noms, trois cycles de vie, trois modèles d'erreur — et pourquoi la discipline de choisir le bon décide si un serveur se met à l'échelle ou s'accrète.
Pourquoi ce chapitre existe
Un protocole ne vaut que par ce qu'il vous permet de dire. Le Chapitre 2 a bâti le modèle mental d'hôte, client, serveur, et a vu une session prendre vie par la négociation des capacités. Une fois la poignée de main terminée et chacun sachant ce que l'autre peut faire, qu'y a-t-il concrètement sur la table ? MCP répond par trois noms : Ressources, Prompts et Outils. Ils se ressemblent superficiellement — chacun est une chose nommée, décrite par un schéma, que le serveur peut produire ou exécuter — mais ils correspondent à trois intentions distinctes. Les Ressources sont de l'état en lecture. Les Prompts sont un échafaudage réutilisable. Les Outils sont des actions d'écriture. Le chapitre parcourt chacun à son tour : schéma, cycle de vie, modèle d'erreur, et les endroits où les ingénieurs se trompent.
3.1 Ressources : données contextuelles en lecture seule
Une ressource, c'est de la donnée que le serveur peut tendre au modèle comme contexte. Le mot qui définit, c'est lecture seule. Une ressource ne modifie pas le monde ; elle le décrit. Si une lecture provoque un changement d'état ailleurs — une ligne de journal d'audit, un compteur incrémenté, un webhook déclenché — ce n'est pas une ressource, c'est un outil déguisé. Tracer cette ligne nettement est la première discipline de la conception de serveur MCP.
Chaque ressource a un URI stable dans un schéma que le serveur choisit (file://, postgres://, linear://issue/ENG-1234), plus des métadonnées : nom, description facultative, type MIME, taille facultative. Aucun de ces champs n'est décoratif. Une ressource sans description est une ressource que le modèle ne peut pas évaluer. Le cycle de vie est simple : resources/list pour énumérer, resources/read pour récupérer. Il n'y a pas de resources/write — si le serveur veut des écritures, il doit exposer un outil. L'asymétrie maintient la frontière de confiance visible.
Deux patrons rendent les ressources praticables à l'échelle. Les URI templates laissent le serveur exposer un endpoint de lecture paramétré (db://orders/{order_id}) au lieu d'énumérer des millions de lignes. Les abonnements permettent à l'hôte d'enregistrer son intérêt pour un URI et de recevoir notifications/resources/updated quand la donnée sous-jacente change — l'alternative étant de sonder à la cadence du LLM, ce qui est gaspilleur des deux côtés. L'écueil à éviter est de déverser chaque objet interne sur la liste des ressources au début de session : une liste de trois mille ressources mange des dizaines de milliers de tokens avant que l'utilisateur n'ait tapé quoi que ce soit. Exposez un sommet sélectionné plus des templates, et laissez le modèle fouiller la longue queue.
3.2 Prompts : modèles et workflows réutilisables
Les prompts en MCP n'ont rien à voir avec le prompt système d'un LLM. Ce sont des modèles réutilisables, définis par le serveur, qu'un utilisateur — ou un hôte au nom d'un utilisateur — peut invoquer pour ouvrir une interaction particulière. Un prompt est plus proche d'une commande slash que d'une personnalité. L'idée est de laisser un serveur livrer des patrons d'interaction connus pour fonctionner, à côté des outils et ressources qu'il expose, pour que l'humain au clavier n'ait pas à se rappeler comment formuler la demande.
Un prompt a un nom, une description facultative, et une liste d'arguments. L'hôte appelle prompts/list pour découvrir, puis prompts/get pour développer un prompt en une séquence de messages que l'hôte peut introduire dans sa boucle de modèle. Le prompt peut référencer des ressources par URI, auquel cas l'hôte les incorpore avant d'envoyer. Le serveur scénarise les tours d'ouverture ; le modèle prend la suite.
La distinction entre prompts et messages système compte. Un utilisateur qui invoque /review_pr voit, dans son journal de conversation, l'assistant commencer à travailler sur une revue — il comprend ce qui a démarré, il peut interrompre, il peut auditer. Si le serveur ajoutait à la place silencieusement des instructions au prompt système de l'hôte, l'utilisateur n'aurait aucune idée de pourquoi l'assistant se comporterait soudain différemment. Les prompts sont un échafaudage visible par l'utilisateur ; les prompts système sont le cadrage de l'hôte. Il ne faut pas confondre les deux. La discipline : tout contenu de prompt que l'utilisateur n'approuverait pas s'il était montré explicitement est un défaut.
3.3 Outils : actions, sorties structurées, idempotence
Les Outils sont là où MCP devient intéressant et dangereux à parts égales. Les ressources sont en lecture ; les prompts sont des échafaudages ; les outils sont en écriture — ils créent des lignes, envoient des messages, déploient des services, débitent des cartes. Chaque outil a un nom, une description, et un schéma d'entrée en JSON Schema. La description est le champ le plus important de toute la surface MCP, parce que c'est le texte que le modèle utilise pour décider d'appeler l'outil, quand l'appeler et avec quels arguments. Un outil dont la description dit « envoie un e-mail » est un outil que le modèle ira chercher dès qu'une intention en forme d'e-mail apparaît. Un outil dont la description dit « envoie un e-mail transactionnel via la plateforme marketing, uniquement aux adresses de clients vérifiés ; pas pour de la correspondance personnelle » est un outil que le modèle utilise plus discriminément.
Le modèle d'erreur a deux canaux. Une erreur de protocole (arguments mal formés, outil inconnu) renvoie une erreur JSON-RPC et constitue un échec de cadrage. Une erreur d'outil (destinataire rejeté, disque plein) renvoie une réponse réussie avec isError: true et un bloc de contenu expliquant ce qui s'est passé. La distinction compte : le modèle doit voir les erreurs d'outil et s'adapter ; l'hôte doit voir les erreurs de protocole et récupérer le transport. Les confondre prive le modèle de l'information dont il a besoin.
MCP moderne soutient un champ structuredContent à côté du tableau de contenu en prose, conforme à un outputSchema déclaré. L'effet cumulé sur une trace longue est réel : des sorties d'outils courtes et structurées laissent au modèle de la marge pour le raisonnement véritable ; des sorties en prose longues mangent le budget de contexte. Deux disciplines de plus méritent d'être nommées. Minimalité : douze outils bien décrits battent soixante dans presque tous les benchmarks ; exposez find_users avec un filtre structuré plutôt que list_users, get_user, search_users, count_users. Idempotence : les tempêtes de retries sont inévitables ; un outil qui accepte une clé d'idempotence ou utilise un schéma d'identifiant déterministe transforme une coupure réseau en no-op plutôt qu'en incident d'intégrité de données.
3.4 Composition : comment les trois primitives coopèrent
Les primitives sont le plus utiles quand elles travaillent ensemble. Un serveur bien conçu expose typiquement un peu de chaque : quelques prompts pour amorcer des interactions courantes, un petit ensemble d'outils pour les actions qui comptent, et un ensemble possiblement vaste de ressources qui fournissent le contexte. Un serveur de support client peut exposer profils clients et historique de tickets comme ressources, reply_to_ticket et escalate_ticket comme outils, et /triage_ticket comme prompt qui charge les bonnes ressources et demande au modèle de classer. Les prompts amorcent ; les ressources remplissent la situation ; les outils changent le monde.
La tentation, une fois qu'on voit la flexibilité des primitives, est de tout faire passer par une seule. Vous pouvez faire passer des ressources pour des outils en lecture seule, des outils pour des prompts qui poussent le modèle à émettre des commandes, des prompts pour des ressources contenant des instructions. Chaque substitution compresse l'espace de conception et perd quelque chose. Les ressources camouflées en outils ne peuvent ni être mises en cache, ni être abonnées, ni être incorporées dans le développement d'un prompt. Les outils camouflés en prompts ne peuvent être autorisés au point d'appel et n'ont pas de canal de sortie structurée. Les primitives ne sont pas arbitraires ; elles sont factorisées pour que l'hôte sache comment traiter chacune en sécurité. Honorer la factorisation fait partie du contrat du protocole.
Ce que prépare le Chapitre 3
Vous avez parcouru le côté serveur du marché. Un serveur expose des Ressources, des Prompts et des Outils, chacun avec son schéma, son cycle de vie et son modèle d'erreur. La discipline consiste à choisir la bonne primitive pour chaque chose que le serveur peut faire, à les nommer et les décrire avec soin, et à résister à la surcharge. Mais MCP n'est pas à sens unique. Un hôte peut aussi exposer des capacités en retour vers le serveur — et c'est là que vivent les choix de conception les plus intéressants et les plus sensibles à la sécurité du protocole.
Prochaine étape — Chapitre 4 : Primitives du client — Sampling, Roots, Elicitation. La surface inverse — ce que l'hôte rend au serveur — et les implications de sécurité de chaque capacité prêtée à travers la frontière de confiance.