Recall Module 10’s own complete, working client — discovering and calling a real server directly. This module does something genuinely more useful: wiring that same, real connection into an actual agent from your prior coursework, so an LLM decides when to use it, rather than your own code calling it directly.
The real, honest gap this module closes
flowchart LR
A["Module 10: you called<br/>call_tool() yourself"] --> B["This module: the LLM<br/>decides to call it"]
Recall your LangChain course’s own tool-calling discipline — a real agent reasons over available tools and decides, dynamically, whether to use one. Module 10’s client never did that; you called client.call_tool(...) directly, yourself. This module hands that real decision to an actual LLM.
Turning real MCP tools into real LangChain tools
Let’s connect a genuine, running MCP server directly to a LangChain agent.
We’ll discover the server’s real tools, then wrap each one as a genuine, real LangChain tool the agent can reason over.
from fastmcp import Client
from langchain.tools import StructuredTool
from langchain.chat_models import init_chat_model
from langchain.agents import create_agent
async def build_agent_from_mcp_server(server_path: str):
client = Client(server_path)
async with client:
mcp_tools = await client.list_tools() # real, live discovery, from Module 10
def make_langchain_tool(mcp_tool):
async def call_it(**kwargs):
async with Client(server_path) as c:
result = await c.call_tool(mcp_tool.name, kwargs) # a real, live MCP call
return result.data
return StructuredTool.from_function(
coroutine=call_it, name=mcp_tool.name, description=mcp_tool.description,
)
langchain_tools = [make_langchain_tool(t) for t in mcp_tools] # every real, discovered tool, wrapped
agent = create_agent(model=init_chat_model("openai:gpt-4o-mini"), tools=langchain_tools)
return agent
Recall Module 5’s own real MCP tool definitions — none of them changed at all. This function genuinely just translates each one into the shape your LangChain course’s own create_agent already knows how to use.
Connecting the same server to a LangGraph node
Recall your LangGraph course’s own real node functions — the exact same, real MCP connection slots in directly.
We’ll build a genuine LangGraph node whose entire job is calling a real, connected MCP tool.
from typing import TypedDict
from langgraph.graph import StateGraph, START, END
from fastmcp import Client
class State(TypedDict):
order_id: str
result: str
async def check_order_node(state: State) -> dict:
async with Client("support_server.py") as client: # the real server from Module 9
result = await client.call_tool("get_order_status", {"order_id": state["order_id"]})
return {"result": result.data}
builder = StateGraph(State)
builder.add_node("check_order", check_order_node)
builder.add_edge(START, "check_order")
builder.add_edge("check_order", END)
graph = builder.compile()
Notice this node is genuinely no different in shape from any node throughout your LangGraph course — recall Module 4’s own real definition, “a node is any callable taking state and returning an update.” It simply happens to call a real MCP server internally, instead of a plain Python function.
Connecting to LlamaIndex’s own real agent tools
Recall your LlamaIndex course’s own FunctionTool — the same real translation applies there too.
from llama_index.core.tools import FunctionTool
from fastmcp import Client
async def create_llamaindex_tool_from_mcp(server_path: str, tool_name: str, description: str):
async def call_it(**kwargs) -> str:
async with Client(server_path) as client:
result = await client.call_tool(tool_name, kwargs) # a real, live MCP call
return str(result.data)
return FunctionTool.from_defaults(async_fn=call_it, name=tool_name, description=description)
The real, deliberate pattern behind all three
Notice this module’s own real, repeated shape, regardless of which framework you’re connecting to.
flowchart TD
A[Real MCP Server] --> B[Discover real tools]
B --> C[Wrap each as the framework's native tool type]
C --> D[Hand to a real agent]
D --> E[LLM decides, dynamically, whether to call it]
MCP itself never changes — recall Module 1’s own real, deliberate goal, n+m instead of n×m. The real, one-time translation layer is what changes per framework; the actual MCP server, and everything it exposes, stays completely identical.
Common mistakes worth avoiding
Calling client.call_tool(...) directly inside your application logic, then calling this “agentic.” Recall this module’s own opening distinction — genuine agentic use means the LLM decides whether and when to call a tool; your own code calling it directly, even through MCP, is still just Module 10’s client pattern.
Opening a new, real connection on every single tool call, in a genuinely high-traffic application. Recall this module’s own example functions — each real call opens a fresh connection; a production system would genuinely want to reuse one, persistent connection instead, covered fully once this course reaches production architecture.
Assuming the translation layer needs to understand what a tool actually does. Recall this module’s own real functions — they’re genuinely generic, working identically regardless of which specific MCP tool is being wrapped, because they only ever pass through the real name, description, and arguments MCP already provides.
What you should take away from this module
- MCP tools become real, native tools in any framework through one, genuine, thin translation layer — the actual MCP server never needs to know or care which framework is calling it.
- A LangGraph node calling an MCP tool is genuinely no different in shape from any other node — it’s still just a callable, taking state and returning an update.
- The real, structural benefit is precisely Module 1’s own n+m goal — one real MCP server, usable by agents built on LangChain, LangGraph, or LlamaIndex, with no separate integration work for each.
Where this goes next
The next two modules cover practical, direct integration specifically with your own prior courses: MCP with LangChain and LangGraph, and MCP with LlamaIndex — going deeper than this module’s translation layer into genuine, real, idiomatic patterns each framework actually provides.
- Author
- TechByteByByte Editorial Team
- Reviewed by
- TechByteByByte Admin
- Published
- Last reviewed