6. MCP in agent frameworks¶
Intermediate · 11 min read
You rarely write the host loop from page 4 by hand in production. Every major agent framework can load MCP tools and treat them like its own. The pattern is always the same:
- Describe how to reach each server (a command for stdio, a URL for HTTP).
- The framework connects, lists the tools and converts them into its own tool type.
- Your agent uses them like any other tool.
Adapters move fast
Checked with langchain-mcp-adapters 0.3, openai-agents 0.24 and mcp 2.3 in October 2026. These adapters
still depend on mcp 1.x, so install them in their own environment, separate from servers built on mcp 2.x.
That's fine because MCP is a wire protocol: a 1.x client talks to a 2.x server through the older initialize
handshake, which 2.x servers still support. All the outputs below are from 1.x clients calling the 2.x server
from page 3.
6.1 LangChain and LangGraph¶
langchain-mcp-adapters connects to one or more servers and returns ordinary LangChain tools:
# no-run — pip install langchain-mcp-adapters langchain langgraph
import asyncio
from langchain_mcp_adapters.client import MultiServerMCPClient
client = MultiServerMCPClient({
"orders": {"command": "python", "args": ["/abs/path/orders_server.py"], "transport": "stdio"},
"docs": {"url": "https://mcp.example.com/mcp", "transport": "http",
"headers": {"Authorization": "Bearer ..."}},
})
async def main():
tools = await client.get_tools() # LangChain BaseTool objects, one per MCP tool
print([t.name for t in tools])
status = next(t for t in tools if t.name == "get_order_status")
print(await status.ainvoke({"order_id": "A100"}))
asyncio.run(main())
['get_order_status', 'refund_order']
[{'type': 'text', 'text': '{\n "order_id": "A100",\n "status": "shipped",\n "eta": "Friday"\n}', 'id': 'lc_0dce8450-eaa3-4361-91a7-b3a9934cb5dd'}]
Hand them to an agent exactly like the tools in LangChain:
# no-run — needs ANTHROPIC_API_KEY
from langchain.agents import create_agent
agent = create_agent(
model="anthropic:claude-opus-5-5",
tools=tools,
system_prompt="You are a support assistant. Use tools; never guess order details.",
)
result = await agent.ainvoke({"messages": [{"role": "user", "content": "Where is order A100?"}]})
print(result["messages"][-1].content)
Useful options on MultiServerMCPClient:
| Option | What it does |
|---|---|
tool_name_prefix=True |
Names tools orders_get_order_status, avoiding clashes between servers |
handle_tool_errors=True (default) |
An isError result goes back to the model as an error ToolMessage so it can retry, instead of crashing the run |
tool_interceptors=[...] |
Hook every call: add headers, log, block, or rewrite arguments |
client.session("orders") + load_mcp_tools(session) |
Keep one session open for many calls. By default each tool call opens a fresh connection, which is slow for stdio servers |
Since the tools are plain LangChain tools, everything from Agents in LangGraph
applies: put them in a ToolNode, add guard nodes, add interrupt() before destructive ones.
6.2 OpenAI Agents SDK¶
The OpenAI Agents SDK takes MCP servers directly on the agent:
# no-run — pip install openai-agents ; the run needs OPENAI_API_KEY
import asyncio
from agents import Agent, Runner
from agents.mcp import MCPServerStdio, MCPServerStreamableHttp, create_static_tool_filter
async def main():
async with MCPServerStdio(
name="orders",
params={"command": "python", "args": ["/abs/path/orders_server.py"]},
cache_tools_list=True, # don't re-list tools every turn
tool_filter=create_static_tool_filter(allowed_tool_names=["get_order_status"]),
) as orders:
print([t.name for t in await orders.list_tools()])
agent = Agent(name="Support", instructions="Answer order questions with tools.", mcp_servers=[orders])
result = await Runner.run(agent, "Where is order A100?")
print(result.final_output)
asyncio.run(main())
tool_filter is least privilege at the framework level: this agent can look orders up but can't see
refund_order at all. For remote servers use MCPServerStreamableHttp(params={"url": ..., "headers": {...}}), and
the require_approval option lets you mark tools that need a human "yes" before they run.
6.3 The Claude API's MCP connector¶
For remote servers you don't need a client at all: the Claude API can connect to an MCP server itself during a request. You pass the server and a toolset that points at it:
# no-run — needs ANTHROPIC_API_KEY; pip install anthropic
import anthropic
client = anthropic.Anthropic()
response = client.beta.messages.create(
model="claude-opus-5-5",
max_tokens=16000,
betas=["mcp-client-2025-11-20"],
mcp_servers=[{
"type": "url",
"url": "https://mcp.example.com/mcp",
"name": "orders",
"authorization_token": "<oauth access token for this server>",
}],
tools=[{"type": "mcp_toolset", "mcp_server_name": "orders"}], # both halves are required
messages=[{"role": "user", "content": "Where is order A100?"}],
)
for block in response.content:
print(block.type) # mcp_tool_use and mcp_tool_result blocks appear inline, then the text answer
| Use the connector when | Use your own client (page 4) when |
|---|---|
| The server is reachable on the public internet over HTTPS | The server is local (stdio) or on a private network |
| You only need its tools | You need resources, prompts or elicitation |
| You're happy for Anthropic's servers to call it | You want to approve, log or modify each call yourself |
The Anthropic Python SDK also has helpers that convert MCP tools from your own client session for its tool
runner (pip install "anthropic[mcp]"), which covers the right-hand column.
6.4 Claude Code, Cursor and other coding agents¶
Coding agents are MCP hosts too, and MCP is how teams give them company context: the issue tracker, the internal docs, staging databases, feature flags.
claude mcp add orders -- python /abs/path/orders_server.py # local server
claude mcp add --transport http sentry https://mcp.sentry.dev/mcp # remote server (OAuth login on first use)
claude mcp add --scope project orders -- python orders_server.py # saved in .mcp.json, shared via git
A project-scoped .mcp.json checked into the repo means every developer's agent gets the same tools. Treat it like
code: review changes to it, because adding a server gives it a place in every developer's agent.
6.5 Choosing how to connect¶
| Situation | Approach |
|---|---|
| Already on LangChain / LangGraph | langchain-mcp-adapters |
| Already on the OpenAI Agents SDK | MCPServerStdio / MCPServerStreamableHttp on the Agent |
| Claude API, public remote server, tools only | The MCP connector (mcp_servers + mcp_toolset) |
| Need full control (approvals, logging, resources, elicitation) | Your own mcp.Client loop (page 4) |
| Developers' coding agents | Claude Code / Cursor config, project-scoped and reviewed |
Interview questions¶
How do you use MCP tools in a LangGraph agent?
Use langchain-mcp-adapters: create a MultiServerMCPClient with each server's command or URL, call
get_tools() to get LangChain tools, and pass them to create_agent or a ToolNode. Keep a session open for
repeated calls, prefix tool names if servers overlap, and keep handle_tool_errors on so tool failures go back
to the model.
Can an MCP client on an old SDK talk to a server on a new SDK?
Yes, usually. MCP is a wire protocol with version negotiation: a client on the handshake era sends initialize,
and a new server that still supports those versions answers it. A new client probes server/discover and falls
back to initialize for old servers. Problems only appear when one side has dropped every version the other
supports.
When would you use the Claude API's MCP connector instead of your own MCP client?
When the server is a public HTTPS endpoint and you only need its tools: Claude calls it directly, so there's no client code. Use your own client when the server is local or private, when you need resources, prompts or elicitation, or when you want to approve, log or change each call before it runs.
How do you limit what an agent can do with an MCP server that has 40 tools?
Filter tools on the client (an allow-list such as the OpenAI Agents SDK's tool_filter, or only passing some
LangChain tools to the agent), require approval for write tools, and use credentials or OAuth scopes that only
permit what the agent needs. Filtering also improves tool-selection accuracy and saves prompt tokens.
Practice¶
- Load the page 3 server with
langchain-mcp-adapterswithtool_name_prefix=Trueand print the names. - Add
require_approval={"refund_order": "always"}to the OpenAI Agents example and read what happens when the agent tries a refund. - Decide which approach from 6.5 fits a project you're working on, and why.
Next: 7. Security and production Back to: MCP overview · Notes overview