MCP pour les agents LangGraph, niveau par niveau : serveurs, transports et le pont d’adaptation
MCP pour les agents LangGraph, niveau par niveau : rôles hôte, client et serveur, un serveur FastMCP, transports stdio vs HTTP, langchain-mcp-adapters et pièges à éviter.
Sources: MCP for LangGraph Developers: From Basics to Production
Les prérequis sont simples : une connaissance de la structure d’un projet LangGraph et de l’idée d’une fonction décorée avec @tool. Le Model Context Protocol constitue une nouvelle infrastructure, et non une nouvelle façon de penser les graphes ; par conséquent, l’explication commence par zéro concernant le MCP lui-même et ne reprend pas LangGraph que lorsque le concept est bien maîtrisé.
Le problème de l’échelle avec des outils classiques
Un outil dans LangGraph commence généralement comme ceci :
@tool
def search_web(query: str) -> str:
"""Search the web for current information."""
return f"Search results for: {query}"
Cela fonctionne tant que l’échelle n’est pas un problème. Supposons que cinq agents travaillant sur cinq projets aient tous besoin d’un outil permettant de « rechercher dans la base de données de l’entreprise ». Avec le modèle décrit ci-dessus, le même outil serait écrit cinq fois, dans cinq bases de code, éventuellement dans cinq langages différents. Chaque modification du schéma entraîne donc cinq modifications correspondantes. Partager cet outil avec un collègue qui développe un type d’application IA différent, peut-être même pas utilisant LangGraph, échoue complètement, car cette fonction @tool fait partie du monde Python de LangChain.
Cette difficulté est appelée le problème d’intégration N×M. N outils (bases de données, API, systèmes de fichiers) doivent être connectés à M applications IA (un agent LangGraph, un agent personnalisé d’un collègue, Claude Desktop, un assistant d’IDE). En l’absence d’un standard commun, cela entraîne N×M intégrations sur mesure.
Le Model Context Protocol (MCP) constitue une norme ouverte et universelle permettant de relier les applications d’IA à des outils et des données. Un outil développé une fois en tant que serveur MCP peut être utilisé par n’importe quelle application compatible avec MCP, qu’il s’agisse d’un agent LangGraph, de Claude Desktop, de Cursor ou d’un agent personnalisé, sans nécessiter de code d’intégration spécifique. La comparaison habituelle est celle d’un port USB-C : une norme de connecteur unique, avec n’importe quel appareil compatible à chaque extrémité.
Le parcours allant de « qu’est-ce que le MCP ? » à un serveur de niveau production connecté à un véritable agent LangGraph passe par cinq étapes, chacune ajoutant une idée supplémentaire.
Niveau 1 : qu’est-ce que le MCP ?
Commencez par une image avant tout code. Un concierge d’hôtel ne sait pas personnellement comment réserver un restaurant, appeler un taxi ou acheter des billets de théâtre. Le concierge garde une liste de services locaux de confiance, chacun étant un spécialiste. Lorsqu’un client souhaite une réservation pour le dîner, le concierge utilise une ligne dédiée vers le service de réservation, formule la demande dans un format compris des deux parties et transmet la réponse.
MCP représente cette ligne standard ainsi que ce format de demande standard. L’application d’IA fait office de concierge. Un serveur MCP est un service spécialisé tel qu’un service de réservation de restaurants, une compagnie de taxis ou une billetterie. MCP lui-même constitue le langage commun et le schéma de connexion, permettant ainsi à tout concierge de communiquer avec n’importe quel service sans avoir à apprendre comment chacun gère sa propre centrale téléphonique.
Les trois rôles
Chaque système MCP compte exactement trois participants, et tout le reste s’appuie sur eux.
- Hôte. L’application d’IA que l’utilisateur final utilise réellement : ici un agent LangGraph, ailleurs Claude Desktop, Cursor ou VS Code avec un copilote. C’est lui qui gère la conversation, décide quand un outil est nécessaire et affiche les résultats.
- Client. Il se trouve à l’intérieur de l’hôte, et chaque client entretient une connexion un-à-un dédiée avec un seul serveur. Un hôte connecté à trois serveurs exécute donc trois clients en interne. Ce mapping un-à-un constitue une mesure de sécurité volontaire, afin qu’un client destiné au serveur de système de fichiers ne fasse pas accidentellement fuir des données vers le serveur de base de données.
Le format de communication : JSON-RPC 2.0
Les messages échangés entre le client et le serveur utilisent JSON-RPC 2.0, un format simple et bien établi comprenant trois types de messages.
Une demande demande l’exécution d’une action et inclut un id unique afin que la réponse puisse être associée à cette demande :
{"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": "search_db", "arguments": {"query": "Q3 revenue"}}}
Une réponse répond à une demande. Elle contient soit un résultat en cas de succès, soit une erreur en cas d’échec, avec le même id que la demande :
{"jsonrpc": "2.0", "id": 1, "result": {"content": [{"type": "text", "text": "Q3 revenue was $4.2M"}]}}
Une notification est un message unidirectionnel qui ne nécessite pas de réponse, par exemple pour annoncer que la liste des outils disponibles a changé.
Le JSON-RPC brut est rarement écrit à la main, car les SDK s’en chargent. Néanmoins, en connaissant son fonctionnement de base, on comprend mieux beaucoup de concepts ultérieurs, tout comme connaître HTTP permet à quelqu’un de devenir un meilleur développeur REST, même s’il n’écrit jamais de requêtes HTTP brutes.
Niveau 2 : les trois primitives
Un serveur propose ses fonctionnalités au moyen de trois types précis de primitives, et presque toutes les décisions de conception lors de sa création relèvent d’un choix parmi celles-ci.
Outils sont des actions que le modèle peut effectuer. Un outil correspond à une fonction que le LLM peut décider d’appeler lors de son raisonnement, tout comme une fonction décorée dans LangGraph classique. La différence réside dans son emplacement : il se trouve à l’intérieur d’un serveur MCP et non dans le codebase de LangGraph, étant découvert et appelé via le protocole. Il faut recourir à un outil chaque fois qu’une action doit être réalisée : un calcul, une requête de base de données, l’envoi d’un e-mail ou la modification d’un fichier.
Ressources fournissent un contexte en lecture seule. L’application peut récupérer une ressource pour fournir au modèle des informations de fond, sans que le modèle n’ait besoin de décider de l’appeler comme il le ferait avec un outil. Les ressources sont identifiées par URI, de la même manière qu’une page web est identifiée par URL. Utilisez-les pour du matériel en lecture seule, tel qu’un fichier de configuration, un document ou une liste de sources de données que le modèle pourrait vouloir connaître avant de choisir ce à rechercher.
Les prompts sont des modèles réutilisables. Un prompt est une structure pré-écrite qui déclenche un flux de travail spécifique pour un utilisateur ou l’hôte. Contrairement aux outils, les prompts sont généralement invoqués par l’utilisateur et non par le modèle, ce qui les fait ressembler à des commandes avec des barres obliques. Ils conviennent à des tâches courantes et répétitives telles que « résumer ce document » ou « vérifier ce code pour y détecter des problèmes de sécurité », où des instructions cohérentes et bien conçues valent mieux que de laisser l’expression au bon vouloir de l’utilisateur.
Lorsque vous n’êtes pas sûr duquel utiliser, demandez-vous si l’action modifie quelque chose ou ne fournit que des informations. S’il s’agit de créer, mettre à jour, supprimer, envoyer ou exécuter, c’est un outil. S’il s’agit de données en lecture seule que le modèle peut utiliser en arrière-plan, c’est une ressource. S’il s’agit d’un modèle d’instruction que l’utilisateur déclenche explicitement, c’est un prompt.
Niveau 3 : un premier serveur avec FastMCP
FastMCP est le framework Python dominant pour la création de serveurs MCP. Il transforme l’ensemble des mécanismes complexes du protocole (gestion des requêtes, génération de schémas, cycle de vie) en quelques décorateurs, dans le même esprit que @tool pour les fonctions LangChain. Installation :
pip install fastmcp
Un serveur complet avec une seule outil tient dans un petit fichier :
# ── math_server.py ───────────────────────────────────────────
from fastmcp import FastMCP
# Create the server - this object is the container for everything below
mcp = FastMCP(name="Math Server")
@mcp.tool
def add(a: int, b: int) -> int:
"""Add two numbers together."""
return a + b
@mcp.tool
def multiply(a: int, b: int) -> int:
"""Multiply two numbers together."""
return a * b
if __name__ == "__main__":
mcp.run() # Defaults to stdio transport
C’est un serveur MCP valide et fonctionnel. FastMCP lit les indications de type de la fonction pour générer le schéma d’entrée et lit la documentation pour produire la description que voit le LLM. La même règle que pour les outils ordinaires s’applique, mais avec des enjeux plus importants : une documentation vague laisse le modèle indécis quant au moment de faire appel à l’outil, et cette ambiguïté affecte désormais toutes les applications qui se connectent, et non plus un seul agent.
Pour ajouter une ressource, il faut utiliser un décorateur avec une URI de choix :
# ── Adding to math_server.py ─────────────────────────────────
@mcp.resource("config://server-info")
def server_info() -> dict:
"""Provides metadata about this server's capabilities."""
return {"version": "1.0", "operations": ["add", "multiply"]}
Lorsqu’un client demande config://server-info, FastMCP appelle la fonction et renvoie le résultat. Elle ne s’exécute qu’à la demande, ce qui constitue une évaluation différée ; ainsi, rien n’est calculé que le modèle n’utilisera jamais.
Parfois, une ressource doit dépendre d’un argument, comme un enregistrement spécifique et non un bloc de configuration fixe :
@mcp.resource("history://{operation_id}")
def get_calculation(operation_id: str) -> dict:
"""Retrieve a past calculation by its ID."""
# In a real server, this would look up a database record
return {"id": operation_id, "result": "..."}
Le marqueur {operation_id} dans l’URI en fait un modèle de ressource. Une demande vers history://abc123 amène FastMCP à extraire abc123 et à le transmettre automatiquement à la fonction.
Une instruction est définie de la même manière :
@mcp.prompt
def explain_calculation(operation: str, result: str) -> str:
"""Generate a request to explain a calculation in plain English."""
return f"Explain how the operation '{operation}' produced the result '{result}', in simple terms a beginner could follow."
Pour exécuter le serveur :
python math_server.py
Avant de connecter une application d’IA réelle, vérifiez-la à l’aide du MCP Inspector, un outil de débogage basé sur le navigateur fourni avec l’écosystème. Il liste les outils, les exécute manuellement et inspecte les ressources sans l’intervention d’un LLM :
fastmcp dev math_server.py
Cela ouvre une interface web locale, généralement à http://127.0.0.1:6274, permettant de naviguer parmi les outils, d’entrer des arguments de test et d’observer les messages JSON-RPC qui vont et viennent. Testez d’abord ici. Un outil défectueux est beaucoup plus difficile à déboguer en analysant le comportement d’appel des outils par un LLM que directement dans l’Inspecteur.
Niveau 4 : transports
Jusqu’à présent, le serveur fonctionnait avec le transport par défaut. Ce choix est important car il détermine la manière dont un agent LangGraph se connectera.
Considérez le transport comme le câble physique et JSON-RPC comme le langage transmis par ce câble. L’anglais fonctionne aussi bien par téléphone que par radio : un langage, deux câbles. Les serveurs MCP utilisent toujours JSON-RPC 2.0, quel que soit le transport, mais les octets se déplacent différemment.
stdio, pour les outils locaux
C’est la valeur par défaut, et c’est ce que fait mcp.run() lorsqu’il est appelé sans arguments :
if __name__ == "__main__":
mcp.run() # stdio is the default
Avec stdio (entrée et sortie standard), l’hôte lance le serveur en tant que sous-processus et communique avec lui en écrivant dans son stdin et en lisant son stdout. Aucun réseau n’est impliqué : il s’agit d’une communication processus-à-processus sur une seule machine. Cela convient à un serveur qui s’exécute à côté de l’hôte, comme un outil de système de fichiers, un exécuteur de scripts local ou une utilité personnelle, et c’est la configuration la plus simple ainsi que la plus courante pour le développement.
Une contrainte est particulièrement importante. Avec stdio, le stdout du serveur est réservé exclusivement aux messages de protocole, de sorte qu’une ligne de débogage contenant un print() endommage le flux. Le journalage doit donc se faire via stderr.
HTTP streamable, pour les outils distants
Pour un serveur réseau, indiquez explicitement le transport à utiliser :
if __name__ == "__main__":
mcp.run(transport="streamable-http", host="0.0.0.0", port=8000)
Ici, le serveur fonctionne en tant que service web autonome. Les clients se connectent via le réseau par des requêtes HTTP POST, avec éventuellement des Server-Sent Events pour recevoir les réponses en flux continu. Cela rend le serveur véritablement distant : il peut être hébergé sur une autre machine, dans le cloud ou derrière un équilibreur de charge, et servir plusieurs applications simultanément. L’utilisez lorsque le serveur doit être partagé au sein d’une équipe, déployé de manière centralisée, ou être accessible depuis des machines différentes, y compris un agent LangGraph fonctionnant sur un serveur et communiquant avec un serveur MCP permettant d’accéder à une base de données ailleurs.
Règle générale : stdio pour un outil local, destiné à un seul utilisateur et à une configuration simple, typique du développement et de l’usage personnel ; Streamable HTTP pour un outil partagé, destiné à de nombreux utilisateurs ou applications, nécessitant un déploiement en production et des mécanismes d’authentification. C’est précisément le choix à définir pour chaque serveur dans la configuration LangGraph suivante.
Niveau 5 : connexion à LangGraph
Le pont est un paquet nommé langchain-mcp-adapters, géré par l’équipe LangChain afin de rendre les outils MCP utilisables à l’intérieur des agents LangGraph. Il fait pour MCP ce que le décorateur @tool faisait pour les fonctions ordinaires : il transforme un outil MCP externe en un objet BaseTool qui peut être directement intégré dans un ToolNode LangGraph sans nécessiter de traitement particulier au sein du graphe. Une fois converti, l’agent ne sait ni ne se soucie du fait qu’un outil provienne d’un serveur MCP ou ait été écrit localement.
Installez-le avec :
pip install langchain-mcp-adapters langgraph "langchain[openai]"
L’objet central est MultiServerMCPClient, qui peut se connecter à plusieurs serveurs MCP en même temps et mixer librement les transports :
# ── MODULE 1 (extended): MCP CLIENT CONFIGURATION ───────────
from langchain_mcp_adapters.client import MultiServerMCPClient
client = MultiServerMCPClient({
# A local server, launched as a subprocess via stdio
"math": {
"command": "python",
"args": ["/absolute/path/to/math_server.py"],
"transport": "stdio",
},
# A remote server, already running, connected over HTTP
"company_data": {
"url": "http://localhost:8000/mcp",
"transport": "http",
},
})
Chaque entrée du dictionnaire correspond à un serveur. La clé ("math" ou "company_data") n’est qu’une étiquette qui permet d’organiser internement les outils provenant de serveurs différents. L’entrée reflète la décision de transport : les serveurs stdio prennent une commande et des arguments, tandis que les serveurs HTTP prennent une URL.
Le chargement des outils nécessite une seule appel :
# This single call discovers every tool, on every configured server,
# and converts each one into a LangChain-compatible BaseTool
tools = await client.get_tools()
print([t.name for t in tools])
# ['add', 'multiply', 'search_company_db', ...]
C’est là toute l’intégration. client.get_tools() envoie la requête MCP tools/list à chaque serveur configuré, récupère les schémas retournés et les enveloppe chacun dans un objet outil qui, du point de vue du graphe, est indiscernable d’une fonction @tool écrite manuellement.
Le reste de la configuration est identique à celui de n’importe quel agent LangGraph. MCP modifie simplement l’origine des outils sans changer la manière dont le graphe est construit. Un modèle complet :
# ============================================================
# LANGGRAPH + MCP AGENT — COMPLETE TEMPLATE
# Extends: Part 1 (core structure)
# ============================================================
# ── MODULE 1: IMPORTS & CONFIGURATION ───────────────────────
import asyncio
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain.chat_models import init_chat_model
from langchain_core.messages import HumanMessage
from langgraph.graph import StateGraph, MessagesState, START, END
from langgraph.prebuilt import ToolNode, tools_condition
from langgraph.checkpoint.memory import MemorySaver
llm = init_chat_model("openai:gpt-4o")
client = MultiServerMCPClient({
"math": {
"command": "python",
"args": ["./math_server.py"],
"transport": "stdio",
},
"company_data": {
"url": "http://localhost:8000/mcp",
"transport": "http",
},
})
# ── MODULE 2: STATE ──────────────────────────────────────────
class State(MessagesState):
pass
# ── MODULE 4: NODES ──────────────────────────────────────────
# (Module 3, Tools, is now sourced from MCP rather than defined here)
def make_agent_node(llm_with_tools):
"""Factory pattern: tools are loaded asynchronously, so the node
closure is built after the async tool-loading step completes."""
def agent_node(state: State) -> dict:
response = llm_with_tools.invoke(state["messages"])
return {"messages": [response]}
return agent_node
# ── MODULE 6: GRAPH ASSEMBLY (inside an async function) ──────
async def build_graph():
tools = await client.get_tools()
llm_with_tools = llm.bind_tools(tools)
graph_builder = StateGraph(State)
graph_builder.add_node("agent", make_agent_node(llm_with_tools))
graph_builder.add_node("tools", ToolNode(tools))
graph_builder.add_edge(START, "agent")
graph_builder.add_conditional_edges("agent", tools_condition)
graph_builder.add_edge("tools", "agent")
return graph_builder.compile(checkpointer=MemorySaver())
# ── MODULE 7: ENTRYPOINT ──────────────────────────────────────
async def main():
graph = await build_graph()
config = {"configurable": {"thread_id": "session-001"}}
response = await graph.ainvoke(
{"messages": [HumanMessage(content="What's (3 + 5) times 12?")]},
config=config
)
print(response["messages"][-1].content)
if __name__ == "__main__":
asyncio.run(main())
Tout devient asynchrone
MCP introduit un seul véritable ajustement. La communication est intrinsèquement asynchrone, car chaque appel à une outil représente un aller-retour réseau ou de sous-processus, même via stdio. Par conséquent, client.get_tools() doit être attendu, la construction du graphe se trouve généralement dans une fonction async def, et le graphe compilé est invoqué avec ainvoke et non invoke. Tout le reste, StateGraph, MessagesState, tools_condition et MemorySaver, reste inchangé.
Le routeur prédéfini à nouveau
Le routage disparaît presque complètement de ce modèle. Au lieu d’un routeur personnalisé, il utilise tools_condition, le routeur prêt à l’emploi : si le dernier message contient des appels à des outils, on se rend à "tools", sinon on termine. Le routeur ne peut pas distinguer les outils MCP des outils écrits manuellement, car tous deux sont des objets BaseTool au moment où le graphe les perçoit.
Niveau 6 : considérations de production
Quelques éléments séparent une démonstration fonctionnelle d’un système pouvant être déployé, et ce sont eux qui se posent le plus fréquemment dans des configurations réelles de MCP et de LangGraph.
Gardez la connexion au client active. MultiServerMCPClient est par défaut sans état : chaque appel à l’outil ouvre une nouvelle connexion, l’exécute puis la ferme. Cela convient pour une seule requête. Dans le cas d’une application qui sert de nombreux utilisateurs, ouvrir un sous-processus ou une connexion HTTP à chaque appel entraîne une latence réelle. En production, ouvrez le client une seule fois au démarrage du processus et réutilisez-le tout au long de la durée de vie de l’application :
# Hold the connection open across the application's lifetime,
# rather than opening/closing per request
async with MultiServerMCPClient({...}) as client:
tools = await client.get_tools()
graph = await build_graph_with(tools)
# ... serve many requests using this same graph ...
Évitez l’usage de stdio dans un serveur web. Stdio a été conçu pour des cas locaux, à un seul utilisateur, sur la même machine, comme un application de bureau qui lance un outil d’assistance. Lorsqu’un agent LangGraph est déployé en tant que service web destiné à de nombreux utilisateurs, les serveurs stdio deviennent un fardeau : des sous-processus sont créés à chaque demande, sans moyen naturel de partager l’état ou d’élargir les capacités. Pour tout déploiement côté serveur, préférez Streamable HTTP, et demandez-vous honnêtement s’un processus MCP distinct est vraiment nécessaire. Il existe des cas où une simple fonction @tool appelant directement une bibliothèque interne est supérieure, tant par simplicité que par vitesse, à l’usage du protocole supplémentaire.
Apportez une approbation humaine pour les outils sensibles. Les outils MCP deviennent des outils ordinaires une fois qu’ils sont intégrés au graphe, ce qui signifie que tous les schémas existants s’appliquent. Si un serveur expose des informations sensibles, comme l’envoi d’e-mails, la modification d’une base de données ou des dépenses financières, enveloppez cette action avec la même étape d’examen interrupt() utilisée pour toute autre appel d’outil. MCP assure la découverte et la standardisation, mais ne garantit pas la sécurité par défaut. Cela reste la responsabilité du développeur.
Les serveurs ne peuvent pas voir l’état du graphe. Les serveurs MCP s’exécutent en tant que processus distincts. Ils ne peuvent pas accéder à l’state de LangGraph, au checkpointer ou à tout objet Python en mémoire. Lorsqu’une requête nécessite une personnalisation, par exemple avec une préférence utilisateur enregistrée, la valeur doit être transmise explicitement en tant qu’argument de l’outil, ou fournie via des intercepteurs, un mécanisme avancé offert par langchain-mcp-adapters qui permet d’inspecter et de modifier une requête avant qu’elle ne soit envoyée, en utilisant le contexte de exécution du graphe. Transmettre des valeurs en tant qu’arguments suffit pour la plupart des agents et est bien plus simple.
Niveau 7 : MCP dans un système multi-agents
MCP s’intègre au pattern du superviseur. Plusieurs agents spécialisés obtiennent chacun leurs outils depuis leur propre serveur dédié :
# ── Specialist agents, each pulling tools from a DIFFERENT MCP server ──
async def build_multi_agent_system():
client = MultiServerMCPClient({
"research": {"url": "http://localhost:8001/mcp", "transport": "http"},
"code": {"url": "http://localhost:8002/mcp", "transport": "http"},
})
research_tools = await client.get_tools(server_name="research")
code_tools = await client.get_tools(server_name="code")
researcher_llm = llm.bind_tools(research_tools)
coder_llm = llm.bind_tools(code_tools)
# From here, wire researcher_node, coder_node, and a supervisor_node
# exactly as shown in Part 4 - the rest of the supervisor pattern
# is completely unchanged.
...
MCP ne propose pas une architecture concurrente ici. Un spécialiste pris en charge par un serveur MCP est structurellement identique à celui géré par des outils manuels : le superviseur dirige les communications de la même manière et les spécialistes envoient leurs rapports de la même façon. MCP ne modifie que l’emplacement des définitions des outils et le nombre d’applications pouvant les réutiliser.
Référence rapide
- Architecture. L’hôte est l’application d’IA à laquelle l’utilisateur interagit (ici l’agent LangGraph). L’client se trouve dans l’hôte, un par serveur connecté, et gère une session un-à-un. Le serveur est le programme autonome qui expose des outils, des ressources et des instructions, sans savoir quel hôte est connecté. JSON-RPC 2.0 est le format de message utilisé pour toutes les échanges : demandes, réponses et notifications.
- Primitifs. Tool est une action exécutable que le modèle choisit d’appeler, construite avec
@mcp.tool. Resource sont des données en lecture seule accessibles via un URI, contrôlées par l’application ou l’utilisateur, construites avec@mcp.resource("uri://..."). Prompt est un modèle d’instruction réutilisable invoqué par l’utilisateur, construit avec@mcp.prompt. - FastMCP.
FastMCP(name="...")crée le serveur, le conteneur qui englobe tout.@mcp.toolexpose une fonction, en lisant les indications de type pour le schéma ainsi que la documentation pour la description.@mcp.resource("scheme://{param}")déclare des données en lecture seule,{param}servant à créer un modèle.@mcp.promptdéclare un modèle.mcp.run()lance le serveur, par défaut sur stdio, ou avectransport="streamable-http"pour une utilisation en réseau.fastmcp dev server.pyouvre l’Inspecteur pour des tests sans LLM. - Transports.
stdioest basé sur des sous-processus et fonctionne de manière locale, le hôte lançant le serveur, et les sorties de débogage ne doivent jamais être envoyées vers stdout.streamable-httpest réseau, prend en charge de nombreux hôtes simultanés et constitue la solution par défaut en environnement de production pour les serveurs partagés. - Intégration avec LangGraph.
MultiServerMCPClient({...}), provenant delangchain_mcp_adapters.client, se connecte à un ou plusieurs serveurs utilisant différents types de transports au sein d’un même dictionnaire.await client.get_tools()découvre chaque outil et le convertit enBaseTool.tools_conditionest le routage prédéfini et fonctionne de manière identique pour les outils écrits manuellement et ceux provenant de MCP. Tout est asynchrone :get_tools(), la construction du graphe etainvokenécessitent tous l’instructionawait.
Le MCP est-il nécessaire ici ?
- Un outil, un agent, une base de code unique. Aucun MCP n’est nécessaire. Une fonction simple
@toolest plus élégante et ne comporte aucun surcoût lié à un protocole. - Un outil réutilisé entre différents agents ou projets, ou partagé avec des collègues utilisant d’autres frameworks. Créez-le en tant que serveur MCP. C’est là la valeur principale.
- Vous souhaitez utiliser des centaines de serveurs communautaires existants (GitHub, Slack, Postgres, Google Drive, Stripe et bien d’autres) à la place de codes d’intégration écrits manuellement. Connectez-vous via
MultiServerMCPClientet évitez d’écrire ces codes d’intégration, ce qui représente souvent l’économie de temps la plus importante offerte par MCP. - Un outil situé sur une machine différente de l’agent, ou partagé par plusieurs hôtes en même temps. Utilisez Streamable HTTP en tant que service indépendant.
Un standard, pas un remplaçant
Apprendre un nouveau protocole suscite l’inquiétude qu’il remplace ce qui est déjà connu. MCP ne fait pas cela. Il laisse intactes les outils, les nœuds et les graphes de LangGraph. Ce qui change, c’est l’origine des outils et le nombre d’applications qui peuvent les partager. Une fois qu’un outil MCP atteint le ToolNode, il se comporte comme n’importe quel outil écrit manuellement, est approuvé par les mêmes schémas interrupt() et s’intègre aux mêmes architectures de supervision.
La progression suivait un modèle en escalier : concepts et rôles, les trois primitives, un serveur opérationnel, le choix du transport, le pont LangGraph, le renforcement pour le environnement de production et la composition avec des systèmes multi-agents. Chaque étape ajoutait une idée à une base stable. Associé à une structure graphique canonique, à une gestion de la mémoire, à une sécurité grâce à l’intervention humaine, à l’orchestration et à la récupération multi-agents, cela couvre la plupart des besoins d’une application LangGraph sérieuse destinée à la production, et MCP est ce qui permet aux outils de s’étendre au-delà d’une seule base de code.
Lectures complémentaires
- Notes pratiques : Pourquoi personne ne parle de LangChain, LangGraph ou AutoAgent — Guide pas à pas des Notes pratiques : Pourquoi personne ne parle de LangChain, LangGraph ou AutoAgent : contrats, vérifications et emplacements de code prêts à l’emploi pour les équipes qui utilisent ce modèle.
- ReAct dans LangGraph : De boucle manuelle à ToolNode et StateGraph — Créez un agent ReAct à deux reprises : d’abord en utilisant une boucle asynchrone manuelle, puis avec ToolNode, tools_condition et StateGraph de LangGraph qui gèrent automatiquement les appels en chaîne aux outils.