Menu

AI

LangGraph MCP Tutorial: Use MCP Tools in a Graph and Expose Your Agent as an MCP Server

Load MCP tools into a LangGraph StateGraph with langchain.mcp and ToolNode, then expose your deployed graph to any MCP client through Agent Server's /mcp endpoint.

By: Irina ShvayaNovember 2, 2026

LangGraph MCP Tutorial: Use MCP Tools in a Graph and Expose Your Agent as an MCP Server

This tutorial is part of Build an MCP Server, within The MCP Guide. Want it built for you? See MCP development.

LangGraph meets MCP from two sides. Your graph can use tools from any MCP server, and a deployed graph can be an MCP tool that Claude, Cursor or another agent calls. This tutorial covers both.

For the first half you load MCP tools with LangChain's MCPAdapter and run them in a hand-built StateGraph with ToolNode. For the second half you expose a graph through the /mcp endpoint that LangChain's Agent Server adds automatically. Code was checked against the LangChain and LangGraph docs on 2 November 2026, with langgraph 1.2.19 and langchain 1.4.8 current on PyPI that day.

Key Takeaways

  • Load MCP tools with langchain.mcp.MCPAdapter (install langchain[mcp]); the old langchain-mcp-adapters package is no longer maintained.
  • MCP tools come back as normal LangChain tools, so ToolNode(tools) and model.bind_tools(tools) work unchanged.
  • Agent Server exposes every deployed graph as an MCP tool at /mcp over Streamable HTTP, and supports protocol revisions from 2024-11-05 through 2026-07-28.
  • Give exposed graphs small, typed input and output schemas; the default MessagesState is "too general for direct LLM exposure," per the docs.
  • The /mcp endpoint uses the same auth as the rest of the LangGraph API and rejects browser origins you have not allowed.

Prerequisites

  • Python 3.10 or later.
  • pip install "langchain[mcp]" langgraph plus the provider package for your chat model.
  • An MCP server to test with. The 20-line FastMCP notes server in our langchain-mcp-adapters tutorial works well and runs at http://localhost:8000/mcp.

If graphs, nodes and edges are new, LangChain's LangGraph quickstart builds the same loop with local tools first.

Part 1: Use MCP tools inside a LangGraph graph

Why not the old adapters?

Older LangGraph tutorials import MultiServerMCPClient from langchain_mcp_adapters. That repository now says it is "no longer actively maintained" and points to langchain[mcp]. The LangChain MCP docs describe the replacement, MCPAdapter, which "discovers a server's tools and adapts them into LangChain tools." It is in beta, so pin your versions.

Minimal working example

This graph has two nodes: a model node that decides whether to call a tool, and a ToolNode that runs it. It loops until the model stops asking for tools.

import asyncio
from typing import Literal

from langchain.chat_models import init_chat_model
from langchain.mcp import MCPAdapter
from langgraph.graph import END, START, MessagesState, StateGraph
from langgraph.prebuilt import ToolNode


async def main():
    async with MCPAdapter("http://localhost:8000/mcp") as adapter:
        tools = await adapter.list_tools()
        model = init_chat_model("claude-sonnet-5").bind_tools(tools)

        async def call_model(state: MessagesState):
            return {"messages": [await model.ainvoke(state["messages"])]}

        def route(state: MessagesState) -> Literal["tools", END]:
            return "tools" if state["messages"][-1].tool_calls else END

        builder = StateGraph(MessagesState)
        builder.add_node("model", call_model)
        builder.add_node("tools", ToolNode(tools))
        builder.add_edge(START, "model")
        builder.add_conditional_edges("model", route, ["tools", END])
        builder.add_edge("tools", "model")
        graph = builder.compile()

        result = await graph.ainvoke(
            {"messages": [{"role": "user", "content": "List my notes, then read the first one."}]}
        )
        print(result["messages"][-1].content)


asyncio.run(main())

What each piece does:

  • MCPAdapter(...) connects over Streamable HTTP because the target is an http URL. Pass a Path for a local stdio script, or an {"mcpServers": {...}} dict for several servers.
  • list_tools() returns LangChain tools. The docs say "the tools hold the client," so the graph keeps working inside the context.
  • ToolNode is LangGraph's prebuilt tool runner. The workflows and agents page says it "handles parallel tool execution, error handling, and state injection automatically."
  • ainvoke matters. MCP calls are network calls, so run the graph asynchronously.

Swap "claude-sonnet-5" for any chat model your LangChain install supports.

If you only need a standard agent loop

You may not need a custom graph at all. The LangChain MCP quickstart passes the same tools to create_agent, which builds a tool-calling loop for you. Write your own StateGraph when you need extra nodes, such as a human approval step before a write tool runs.

Add a human check before write tools

MCP servers can attach hints to tools. LangChain keeps them on tool.metadata["mcp"]["tool"]["annotations"], with keys such as read_only_hint and destructive_hint. The MCP tools page tells you to read this metadata defensively because every field is optional.

A simple pattern: split tools into a read-only list and a write list, and route write calls to a node that waits for approval. Treat the hints as hints. Our tool annotations guide explains why a malicious server could mislabel a tool.

Errors

A server result with isError=True becomes a ToolMessage with status="error", so the model sees the message and can try again. Transport or session failures raise an exception instead. Wrap the ainvoke call if your app must survive a server going down.

Test the server first

When a tool fails, find out which side is wrong. The MCP Inspector CLI calls the server with no model involved:

npx @modelcontextprotocol/inspector --cli http://localhost:8000/mcp --transport http --method tools/list

See our MCP Inspector lesson for tool calls and CI smoke tests.

Part 2: Expose your LangGraph agent as an MCP server

How it works

LangChain's Agent Server MCP page says Agent Server "implements MCP using the Streamable HTTP transport," which lets "LangGraph agents be exposed as MCP tools." The endpoint lives at /mcp. You do not write MCP code; deployed graphs appear as tools automatically.

Version details from that page:

  • Base requirement: langgraph-api>=0.2.3 and langgraph-sdk>=0.1.61.
  • Protocol revisions 2024-11-05 through 2026-07-28, plus the tool fields, session behavior and Origin check described there, need langgraph-api>=0.18.0.
  • If your dependencies pin an mcp version outside the range langgraph-api needs, Agent Server starts without the endpoint and logs MCP endpoint disabled: the installed MCP SDK is not supported.

Name and describe the tool

Each graph becomes one tool. The tool name is the agent's name, cleaned to allowed characters and cut to 128 characters. The description is the agent's description, or a generic fallback. Set both in langgraph.json:

{
    "graphs": {
        "my_agent": {
            "path": "./my_agent/agent.py:graph",
            "description": "Answers questions about our product docs. Input: a question."
        }
    },
    "env": ".env"
}

Agent Server marks these tools with readOnlyHint: false, destructiveHint: false, idempotentHint: false and openWorldHint: true. Clients that respect hints will treat your agent as something that can change state.

Keep the schema small

The docs warn that the default MessagesState "is too general for direct LLM exposure." Use explicit input and output schemas instead:

from langgraph.graph import StateGraph, START, END
from typing_extensions import TypedDict


class InputState(TypedDict):
    question: str


class OutputState(TypedDict):
    answer: str


class OverallState(InputState, OutputState):
    pass


def answer_node(state: InputState):
    return {"answer": "replace with real logic", "question": state["question"]}


builder = StateGraph(OverallState, input_schema=InputState, output_schema=OutputState)
builder.add_node(answer_node)
builder.add_edge(START, "answer_node")
builder.add_edge("answer_node", END)
graph = builder.compile()

An agent whose input schema cannot be generated is left out of the tool list, so check tools/list after each deploy.

Connect a client

The docs' local examples point at http://localhost:2024/mcp. Test it with the Inspector the same way as above, adding an Authorization or X-Api-Key header when you deploy. For a deployed LangSmith agent, the docs' Python example wraps a fastmcp StreamableHttpTransport with an X-Api-Key header and hands it to MCPAdapter, so one LangGraph agent can call another.

Sessions, auth and origins

  • No sessions. "Each /mcp request is independent," the endpoint answers with JSON, and it accepts only POST. That matches the stateless design of the 2026-07-28 spec.
  • Auth. /mcp "uses the same authentication as the rest of the LangGraph API." Add custom auth middleware if you need per-user identity.
  • Origins. Requests with an Origin header must come from an allowed origin. A wildcard * "does not allow any origin on this endpoint." Localhost origins are always allowed; others get HTTP 403.
  • Turn it off. Set disable_mcp to true in langgraph.json.

Pitfalls

  • Old imports. from langchain_mcp_adapters.client import MultiServerMCPClient belongs to the retired package.
  • Sync invoke. Calling graph.invoke with MCP tools in an async context causes confusing errors. Use ainvoke.
  • Too many tools. Every MCP tool you bind adds a description to every model call. Filter to what the graph needs; see too many MCP tools.
  • Pinned mcp package. A stale pin can silently disable Agent Server's /mcp endpoint. Check /info for "mcp": false under flags.

Next step

The free MCP course explains the protocol pieces these libraries hide. If you want a LangGraph agent and its MCP servers designed and secured for production, talk to our MCP development team.

More in the MCP Guide

Free tools: server.json Validator · MCP Error Code Lookup

Latest research: State of MCP: October 2026

Frequently asked questions

Do I need langchain-mcp-adapters for LangGraph?

No. Use langchain[mcp] and MCPAdapter. The adapters repository says it is no longer actively maintained, and LangChain publishes a migration guide.

Can a LangGraph agent call another LangGraph agent over MCP?

Yes. Deploy the second agent to Agent Server, then load its /mcp endpoint with MCPAdapter. It appears as one tool whose input is that agent's input schema.

Does the /mcp endpoint support SSE?

The page describes Streamable HTTP only, answered with JSON and POST requests. Clients that can only speak the deprecated SSE transport will need an update.

How do I stop a graph from being exposed?

Set disable_mcp to true in langgraph.json to turn off the whole endpoint. The docs do not describe a per-graph switch, so deploy graphs you want to keep private in a separate deployment with MCP disabled.

You Might Also like to Read

Get a FREE Website Audit

Enter your website and get a 20–30 page SEO, GEO, AEO & CRO audit within 24 hours. Completely free.

Don't have a site yet? Get in touch →

Ready to speak with a marketing expert?
Give us a call! (916) 866-7893

Websites Launched
1407
Websites Launched
Marketing Experts
29
Marketing Experts
Hours of Dedicated Work
204533
Hours of Dedicated Work
Irina S.Benjamin G.Jeanette M.David G.