Implémenter un client
Mis à jour le 29 juillet 2026
Notre serveur MCP fonctionne et l’inspecteur nous l’a confirmé. Il est maintenant temps de construire l’autre moitié du dispositif : le côté client, qui permet à notre code applicatif de communiquer avec le serveur MCP et d’accéder à ses fonctionnalités. C’est la pièce qui manquait pour que notre CLI puisse enfin parler à Claude en connaissant les outils disponibles.
Deux objets, deux rôles
Un mot d’abord sur ce que vous êtes en train de faire. Dans la plupart des projets réels, vous implémenterez soit un client MCP, soit un serveur MCP — rarement les deux. Nous construisons ici les deux côtés parce que c’est le meilleur moyen de voir ce qui circule entre eux, mais ne prenez pas cette symétrie pour une obligation.
Le client MCP se compose de deux éléments. Le premier, que nous appellerons MCP Client, est une classe personnalisée que nous créons nous-mêmes pour faciliter l’utilisation de la session. Le second, la Client Session, est la connexion réelle au serveur, fournie par le SDK MCP Python. Pourquoi ne pas utiliser directement la session du SDK ? Parce qu’elle nécessite une gestion soigneuse des ressources : une connexion ouverte doit être refermée proprement, y compris quand une exception survient au milieu d’un appel. En l’encapsulant dans notre propre classe, nous obtenons un objet qui prend ce nettoyage en charge automatiquement, et le reste du code applicatif n’a plus à y penser.
Lister les outils disponibles
Deux fonctions suffisent pour couvrir le cycle de vie d’un outil, et elles reprennent exactement les deux paires de messages vues dans la première partie du cours. La première, list_tools(), récupère tous les outils que le serveur MCP expose :
async def list_tools(self) -> list[types.Tool]:
result = await self.session().list_tools()
return result.tools
Le corps est volontairement minimal : on accède à la session, c’est-à-dire à la connexion au serveur, on appelle la méthode list_tools() intégrée au SDK, et on retourne le champ tools du résultat. Toute la mécanique du protocole — sérialisation du message, envoi sur stdio, attente de la réponse — se déroule à l’intérieur de cet unique await.
Exécuter un outil
La seconde fonction déclenche l’exécution d’un outil précis sur le serveur :
async def call_tool(
self, tool_name: str, tool_input: dict
) -> types.CallToolResult | None:
return await self.session().call_tool(tool_name, tool_input)
On transmet le nom de l’outil et ses paramètres d’entrée, puis on retourne le résultat. Le point important est l’origine de ces deux arguments : ils ne viennent pas de vous, ils viennent de Claude. Le modèle a choisi l’outil et rempli ses paramètres, votre code se contente de transporter cette décision jusqu’au serveur.
Vérifier que la connexion tient
Le fichier client inclut un harnais de test simple, que vous pouvez lancer directement sans passer par l’application complète :
uv run mcp_client.py
Cette commande connecte votre serveur MCP et affiche les outils disponibles. Vous devriez y retrouver les définitions écrites à la leçon précédente, avec leurs descriptions et leurs schémas d’entrée — la preuve que les annotations Pydantic ont bien été traduites en schéma exploitable par le modèle.
Faire tourner la chaîne complète
Les deux fonctions étant en place, testez le flux de bout en bout :
uv run main.py
Posez une question comme « Quel est le contenu du document rapport.pdf ? » et observez la réponse. En coulisses, la séquence se déroule ainsi :
1. Votre application utilise le client pour obtenir les outils disponibles
2. Ces outils sont envoyés à Claude avec votre question
3. Claude décide d'utiliser l'outil read_doc_contents
4. Votre application utilise le client pour exécuter cet outil
5. Le résultat est retourné à Claude, qui vous répond
Retenez la répartition des rôles que cette séquence met en évidence : le client agit comme pont entre votre logique applicative et les fonctionnalités du serveur MCP. Il rend facile l’intégration d’outils puissants dans vos workflows IA, sans que vous ayez à gérer les détails du protocole de communication. Dans les prochaines leçons, nous enrichirons cette architecture avec les deux primitives restantes : les ressources, puis les prompts.