The
langchain.mcp namespace requires langchain[mcp]>=1.4.0 and is in beta. The API may change.MCPAdapter bridges MCP servers and LangChain agents: it discovers the tools a server advertises and adapts them into standard LangChain tools. Pass the tools from list_tools() to create_agent as you would any other LangChain tool.
This page covers what is specific to that bridge: identifying MCP tools, controlling their execution, handling their outputs, and responding when a server needs input during a call. For the runnable discovery-and-agent example, see the MCP quickstart.
Use MCP tools in an agent
Discover the server’s catalog withMCPAdapter.list_tools, then give the returned tools to create_agent. From the agent’s perspective, they behave like LangChain tools: the model chooses a tool, LangChain invokes it, and the resulting ToolMessage returns to the model.
Tool metadata
Each adapted tool may carry its MCP provenance under anmcp namespace on the LangChain tool’s metadata:
_meta, server identity, any combination of those, or none. annotations contains MCP hints such as read_only_hint and destructive_hint; _meta is opaque metadata supplied by the server; and server identifies the MCP implementation that advertised the tool.
Read optional metadata defensively, so a missing field returns a default rather than raising:
Handle tool outputs
MCP tool results become LangChain-native values: content the model can read, an artifact for structured output, and aToolMessage status that distinguishes a server-reported error from a transport failure.
Multimodal content
An MCP tool result arrives as LangChain content blocks. Image and file content convert into standardizedimage and file blocks alongside text, so a tool that returns a screenshot reaches the model as an image block:
Structured content
When a tool returns structured content, the adapter attaches it to theToolMessage as an artifact rather than folding it into the model-visible text. Read it off message.artifact:
MCPToolArtifact, whose structured_content field holds the tool result’s structuredContent.
Errors
An MCP tool result carries anisError flag. When a server reports isError=True, the adapter converts it into a ToolMessage with status="error" carrying the server’s own message, so the agent can read it and correct itself:
Human-in-the-loop
Reading annotations lets you gate a tool based on what the server declares about it, rather than hardcoding tool names. An MCP server can flag a tool as destructive with thedestructiveHint annotation, which MCPAdapter surfaces under metadata["mcp"]["tool"]["annotations"]["destructive_hint"].
Give an InterruptOnConfig a when predicate: a callable that receives the pending ToolCallRequest and returns whether that call needs approval. Read the destructive hint from metadata once at load time, then let the callable decide per call, so one config covers whatever destructive tools a server exposes without hardcoding tool names:
request.tool_call["args"], so a tool can run freely for safe inputs and pause only for risky ones, such as a delete_file call targeting a protected path. Combine both to gate a tool only when its type and its arguments warrant it.
For the full approval workflow, see Human-in-the-loop.
Server requests during tool execution
Most tools finish without asking the client for anything mid-call. When a server does need input,MCPAdapter answers elicitation automatically through a LangGraph interrupt.
Elicitation
Elicitation is the MCP mechanism for a server to request input in the middle of a tool call. When a server needs input, the request surfaces as a LangGraph interrupt so the person already reviewing the agent’s work answers it and the run resumes:- Elicitation is on by default. The adapter arms every client it builds to advertise the capability and drives the interrupt loop. A prebuilt client that already carries its own elicitation handler is honored instead of overridden.
- Resuming needs persistence. Attach a checkpointer so the interrupted run has somewhere to wait.
- Answers are keyed by the server’s request key. Resume with
Command(resume={"responses": {key: answer}}). Each answer’sactionisaccept(withcontentmatching the request’s schema),decline(answer refused, call continues), orcancel(the whole call is abandoned).
langchain.mcp.elicitation.
Only elicitation is answered this way. A server that instead asks for sampling (running an LLM completion) or roots (reachable local paths) raises NotImplementedError, because the modern, sessionless protocol has no live back-channel for those requests. See Sampling and roots.
Interrupt-driven elicitation answers a server that returns its request as an
InputRequiredResult (the modern protocol’s input-required round). A server that only pushes elicitation over a legacy handshake session cannot be answered this way.See also
- Content blocks
- Tools
- Human-in-the-loop
- FastMCP calling tools
- FastMCP client elicitation
- FastMCP server elicitation
- MCP elicitation specification
- MCP tool annotations
Connect these docs to Claude, VSCode, and more via MCP for real-time answers.

