Alpha-Vorschau von langchain.mcp – ein First-Party-Adapter, der jeden MCP-Server in LangChain-Tools verwandelt, die Sie direkt an create_agent übergeben können.
Die Verbindungsabwicklung übernimmt FastMCP, sodass dessen Client-Funktionen unverändert zur Verfügung stehen, statt hinter einer schmaleren Schnittstelle neu implementiert zu werden.
pip install "langchain[mcp]==1.4.0a2"
Verbinden
MCPAdapter akzeptiert jedes Ziel, das fastmcp.Client annimmt – der Transport wird automatisch erkannt, sodass es einen einzigen Einstiegspunkt gibt statt einen pro Protokoll.
from langchain.agents import create_agent
from langchain.mcp import MCPAdapter
async with MCPAdapter("https://example.com/mcp") as adapter:
agent = create_agent("anthropic:claude-sonnet-5", await adapter.get_tools())
result = await agent.ainvoke({"messages": [{"role": "user", "content": "..."}]})
Gültige Ziele: eine URL, ein lokaler Skriptpfad (gestartet über stdio), ein In-Process-FastMCP-Server, eine Konfiguration, die mehrere Server gleichzeitig benennt, oder ein selbst erstellter fastmcp.Client.
Die von get_tools() zurückgegebenen Tools halten den Client des Adapters, sodass sie nach dem Verlassen des Kontexts weiterhin aufrufbar bleiben – der async with-Block begrenzt die Erkennung, nicht die Lebensdauer der Tools.
Authentifizierung, Caching, Timeouts – Client erstellen
MCPAdapter nimmt zwei Argumente entgegen: das Ziel und elicitation. Alles andere, was FastMCP unterstützt, wird auf einem fastmcp.Client konfiguriert, den Sie selbst erstellen und als Ziel übergeben. Dies ist das Muster, das Sie verwenden sollten, wenn Sie mehr als eine einfache Verbindung benötigen:
from fastmcp.client import Client
from langchain.mcp import MCPAdapter
client = Client(
"https://example.com/mcp",
auth="oauth", # or a bearer token string, or any httpx auth
cache=True, # opt-in response caching
timeout=30,
)
async with MCPAdapter(client) as adapter:
tools = await adapter.get_tools()
Auth akzeptiert "oauth", um den OAuth-Flow auszuführen, eine Token-Zeichenkette für Bearer-Authentifizierung oder eine httpx.Auth-Instanz für alles Individuelle – siehe die Auth-Dokumentation von FastMCP. Server-spezifische Header und Authentifizierung können auch in einer Multi-Server-Konfiguration festgelegt werden (siehe unten).
Caching ist opt-in und standardmäßig deaktiviert: cache=True aktiviert es mit Standardwerten und berücksichtigt die eigenen ttlMs– und cacheScope-Hinweise des Servers; eine CacheConfig passt es individuell an. Der Cache ist pro Client und im Arbeitsspeicher.
Alles andere auf fastmcp.Client – timeout, log_handler, progress_handler, message_handler, roots, sampling_handler – funktioniert auf die gleiche Weise. Der Adapter reicht Ihren Client unverändert durch, sodass das Verhalten von FastMCP weder neu implementiert noch eingeschränkt wird.
Eine Einschränkung: Bei elicitation="interrupt" klont der Adapter Ihren Client, um einen von Ihnen gesetzten Callback nicht zu überschreiben. Die Konfiguration (Auth, Cache-Einstellungen, Handler) wird auf den Klon übertragen; zwischengespeicherte Einträge jedoch nicht, da der Klon einen eigenen Speicher erhält.
adapter.client legt den zugrunde liegenden Client für Prompts, Ressourcen und alles andere offen, was der Adapter nicht umschließt.
Mehrere Server
Richten Sie den Adapter auf eine Konfiguration, und er verteilt sich über eine einzige Verbindung auf jeden Server und präsentiert Ihrem Agenten eine einzige Tool-Liste.
config = {
"mcpServers": {
"weather": {"url": "https://weather.example.com/mcp"},
"calendar": {
"url": "https://calendar.example.com/mcp",
"headers": {"Authorization": "Bearer ..."},
},
}
}
async with MCPAdapter(config) as adapter:
agent = create_agent("anthropic:claude-sonnet-5", await adapter.get_tools())
Bei mehr als einem Server werden die Tools nach Servernamen benannt – etwa weather_get_forecast, calendar_create_event – sodass Kollisionen zwischen Servern ausgeschlossen sind. Bei genau einem Server verbindet sich der Adapter direkt, und die Namen bleiben ohne Präfix. Jeder Eintrag akzeptiert eigene headers, auth, transport und timeout, sodass Server mit unterschiedlichen Anmeldedaten in einem Agenten zusammenwirken können. Ein lokaler Server verwendet command/args statt url und wird über stdio gestartet. Die Konfiguration folgt dem MCP-JSON-Schema von FastMCP, sodass eine bereits anderweitig verwendete Konfiguration hier unverändert funktioniert.
Alte und neue Protokollserver nebeneinander
MCP hat sich vom initialize-Handshake zu server/discover weiterentwickelt, und in freier Wildbahn existieren Server auf beiden Seiten dieser Linie. FastMCP handelt die Ära pro Verbindung aus, sodass der Adapter beide erreicht, ohne dass Sie eine auswählen müssen:
# handshake-era server over SSE
legacy = MCPAdapter("https://legacy.example.com/sse")
# modern-era server over streamable HTTP
modern = MCPAdapter("https://modern.example.com/mcp")
Getrennte Adapter verhandeln unabhängig voneinander und können gleichzeitig laufen, jeder in seiner eigenen Ära. Dies wird durch Integrationstests abgedeckt, die jeweils einen Server jeder Ära starten und beide aufrufen.
Die eine wichtige Regel: Eine Multi-Server-Konfiguration legt eine einzige Ära offen, daher bestimmt das älteste Backend die Ära für die gesamte Flotte. Das Einmischen eines Servers aus der Handshake-Ära in eine Konfiguration zieht die modernen Backends zurück in die Handshake-Ära – sie funktionieren weiterhin, aber ära-spezifische Funktionen gehen verloren. Behalten Sie einen Legacy-Server in seinem eigenen Adapter, wenn Sie die anderen auf dem modernen Protokoll belassen möchten:
async with (
MCPAdapter({"mcpServers": {...modern servers...}}) as modern,
MCPAdapter("https://legacy.example.com/sse") as legacy,
):
tools = await modern.get_tools() + await legacy.get_tools()
Ergebnisse
Jedes Tool ist asynchron. Ein MCP-Tool, das ausgeführt wird und einen Fehler meldet, kommt als ToolMessage mit status="error" zurück und trägt den Fehlertext des Servers, sodass der Agent sich selbst korrigieren und es erneut versuchen kann. Transportfehler und nicht konvertierbare Inhalte führen stattdessen zu einer Exception – ein Modell kann darauf nicht reagieren.
Strukturierte Ausgabe wird über das Artefakt der Tool-Nachricht mitgeliefert:
from langchain.mcp import MCPToolArtifact
artifact: MCPToolArtifact | None = tool_message.artifact # None when there is no structured content
artifact["structured_content"]
Elicitation – Server, die während des Aufrufs Fragen stellen
Einige MCP-Tools benötigen Eingaben, bevor sie abgeschlossen werden können. Wenn Sie sich dafür entscheiden, erscheint die Anfrage als LangGraph-interrupt(), sodass der Mensch, der ohnehin die Arbeit des Agenten überprüft, auch dem Server antwortet.
adapter = MCPAdapter(target, elicitation="interrupt")
Die Fähigkeit ist opt-in statt Standard, weil ihre Deklaration ein Versprechen über die Leitung darstellt: Ein Agent ohne Zugang zu einem Menschen kann sie nicht einhalten. Wenn nichts festgelegt ist, wird nichts deklariert, und ein Server, dessen Tool eine Antwort erfordert, lehnt den Aufruf ab, anstatt ohne eine zu laufen.
Der Lauf stoppt mit einer typisierten Nutzlast und wird mit einer Antwort pro Anfrageschlüssel fortgesetzt:
from langgraph.types import Command
result = await agent.ainvoke({"messages": [...]}, config)
[pause] = result["__interrupt__"]
pause.value["type"] # "mcp_elicitation"
pause.value["tool_name"] # the tool that is waiting
pause.value["requests"] # each question, in the order to ask them
answer = {"responses": {key: {"action": "accept", "content": {"guests": 4}}}}
result = await agent.ainvoke(Command(resume=answer), config)
Anfragen spezifizieren sich über mode: Eine "form"-Anfrage enthält ein requested_schema, das die Antwort erfüllen muss, eine "url"-Anfrage enthält eine Adresse, die der Mensch besuchen soll. Antworten spezifizieren sich über action – "accept" (mit content), "decline" (Frage überspringen, Aufruf fortsetzen) oder "cancel" (Tool-Aufruf abbrechen). Erfordert einen Checkpointer, wie jeder Interrupt.
Sampling und Roots werden nicht über Interrupts beantwortet; überlassen Sie diese den eigenen Handlern Ihres Clients.
Die Typen für Handler – MCPElicitationInterrupt, MCPElicitationRequest, MCPElicitationResponse, MCPElicitationResume und der Diskriminator ELICITATION_INTERRUPT_TYPE – befinden sich in langchain.mcp.elicitation.
Weiterführende Informationen
- FastMCP-Client-Dokumentation – Authentifizierung, Caching, Transporte und Handler-Konfiguration
- Client-Transporte – was jeder Zieltyp ableitet
- Elicitation – die zugrunde liegende Protokollfunktion
Dies ist eine Alpha-Version: Die Schnittstelle kann sich vor der finalen Version 1.4.0 noch ändern. Feedback zur API-Gestaltung ist genau das, wonach wir suchen.



