Maintenant que notre serveur MCP fonctionne, il est temps de construire le côté client. Le client est ce qui permet à notre application de communiquer avec le serveur MCP et d'accéder à ses fonctionnalités.
Comprendre l'architecture du client
Avant de plonger dans le code, clarifions un point important concernant les projets MCP. Normalement, vous implémenteriez soit un client MCP, soit un serveur MCP - pas les deux. Nous construisons les deux dans ce projet simplement pour que vous puissiez voir comment ils fonctionnent ensemble.

Le client MCP se compose de deux composants principaux :
- Client MCP - Une classe personnalisée que nous créons pour faciliter l'utilisation de la session
- Session client - La connexion réelle au serveur (fait partie du SDK Python MCP)

La session client nécessite un nettoyage des ressources une fois que nous en avons terminé avec elle, c'est pourquoi nous l'encapsulons dans notre classe personnalisée. Cela gère automatiquement la gestion des connexions et le nettoyage.
Comment le client s'intègre dans notre application
Vous vous souvenez du flux de notre application ? Notre code CLI doit interagir avec Claude de deux manières clés :

Le client permet ces deux interactions en exposant les fonctionnalités du serveur à notre base de code.
Implémenter les fonctions client principales
Nous devons implémenter deux fonctions essentielles : list_tools et call_tool.
Fonction List Tools
Cette fonction récupère tous les outils disponibles depuis le serveur :
async def list_tools(self) -> list[types.Tool]:
result = await self.session().list_tools()
return result.toolsC'est simple - nous accédons à notre session (la connexion au serveur MCP), appelons la fonction intégrée list_tools, et renvoyons les outils à partir du résultat.
Fonction Call Tool
Cette fonction exécute un outil spécifique 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)Nous transmettons le nom de l'outil et les paramètres d'entrée (fournis par Claude) au serveur et renvoyons le résultat.
Tester le client
Pour vérifier que notre implémentation fonctionne, nous pouvons la tester directement. Le fichier client inclut un harnais de test qui se connecte au serveur MCP et exécute des commandes contre celui-ci. Faites-lui appeler list_tools() et afficher le résultat :
async with MCPClient(
command="uv", args=["run", "mcp_server.py"]
) as client:
result = await client.list_tools()
print(result)L'exécution de uv run mcp_client.py devrait renvoyer une liste des outils disponibles avec leurs descriptions et schémas d'entrée. Vous devriez voir des outils comme read_doc_contents et edit_document que nous avons définis dans notre serveur.
Test de bout en bout
Maintenant que le client et le serveur fonctionnent tous les deux, nous pouvons tester le flux complet. L'exécution de notre application principale et la question posée à Claude « Quel est le contenu du document report.pdf ? » devrait :
- Envoyer la liste des outils disponibles à Claude
- Claude décide d'utiliser l'outil
read_doc_contents - Notre client appelle l'outil sur le serveur
- Le serveur renvoie le contenu du document
- Claude répond avec l'information
Le client agit comme le pont entre le code de votre application et le serveur MCP, facilitant l'accès aux fonctionnalités du serveur sans avoir à gérer directement les détails de connexion de bas niveau.