Connecting the Claude Agent SDK to MCP Servers
The Model Context Protocol (MCP) is a standard way for an agent to call tools that live outside the SDK itself, on a local process or a remote server.
Search across all documentation pages
The Model Context Protocol (MCP) is a standard way for an agent to call tools that live outside the SDK itself, on a local process or a remote server.
The Claude Agent SDK has first-class MCP client support: you register a server, stdio for a local process or HTTP for a remote one, and its tools become callable by the tool-use loop the same way built-in tools are.
Built-in tools cover file editing, bash, and the web; MCP is how you extend the loop to anything else, a database, an internal API, a ticketing system, a third-party SaaS product.
A stdio MCP server runs as a subprocess on the same machine as your agent and communicates over standard input/output.
An HTTP MCP server runs remotely and communicates over HTTP, useful when the tool lives on infrastructure you don't control directly or want to share across multiple agents.
This page covers registering both kinds of server and how their tools interact with the rest of the loop once connected.
Quick-reference recipe card - copy-paste ready.
from claude_agent_sdk import query, AgentOptions, McpServerConfig
options = AgentOptions(
allowed_tools=["file_edit"],
mcp_servers=[
McpServerConfig(
name="internal-search",
transport="stdio",
command=["python", "-m", "internal_search_mcp"],
),
McpServerConfig(
name="ticketing",
transport="http",
url="https://mcp.internal.example.com/ticketing",
),
],
)
async for message in query(
prompt="Find related past incidents and open a ticket summarizing this bug.",
options=options,
):
print(message)When to reach for this:
import asyncio
from claude_agent_sdk import query, AgentOptions, McpServerConfig
async def triage_incident(incident_description: str) -> None:
options = AgentOptions(
allowed_tools=["file_edit"],
mcp_servers=[
McpServerConfig(
name="logs",
transport="stdio",
command=["node", "logs-mcp-server.js"],
# stdio servers inherit no special network access by default;
# they only do what the local process is built to do.
),
McpServerConfig(
name="pagerduty",
transport="http",
url="https://mcp.example.com/pagerduty",
headers={"Authorization": "Bearer ${PAGERDUTY_MCP_TOKEN}"},
),
],
# MCP tools are scoped through allowed_tools like anything else;
# naming them explicitly here keeps this agent from calling every
# tool either server happens to expose.
allowed_mcp_tools=["logs.search", "pagerduty.create_incident"],
)
prompt = (
f"An incident was reported: {incident_description}. Search recent logs "
"for related errors, then create a PagerDuty incident summarizing what "
"you found, only if you find a genuine match."
)
async for message in query(prompt=prompt, options=options):
if message.get("type") == "text":
print(message["text"], end="", flush=True)
elif message.get("type") == "tool_call":
print(f"\n[tool call: {message['tool_name']}]")
asyncio.run(triage_incident("Checkout API returning 500s intermittently since 14:02 UTC"))What this demonstrates:
allowed_mcp_tools) instead of exposing every tool a server happens to offer.mcp_servers tells the SDK how to reach it (a subprocess command for stdio, a URL and headers for HTTP) and to fetch its tool definitions at startup.allowed_tools/allowed_mcp_tools control which of the server's exposed tools the loop can actually call, the same layered scoping model used for built-in tools.| Transport | Runs Where | Good For | Consideration |
|---|---|---|---|
| stdio | Local subprocess, same machine as the agent | Local file access, local dev tools, no network hop needed | Process lifecycle tied to the agent run |
| HTTP | Remote server | Shared infrastructure, systems already exposed as a service | Needs its own auth, network reliability becomes a factor |
# stdio servers should be started with an explicit, minimal command -
# avoid relying on ambient PATH resolution that might differ between
# your dev machine and a deployment environment.
McpServerConfig(
name="internal-search",
transport="stdio",
command=["python3", "/opt/mcp-servers/internal_search/main.py"],
)| Parameter | Type | Description |
|---|---|---|
name | str | Identifier used to reference this server's tools |
transport | str | "stdio" or "http" |
command | list[str] | Subprocess command, stdio only |
url | str | Server endpoint, HTTP only |
headers | dict | Auth or other headers sent with HTTP requests |
allowed_mcp_tools | list[str] | Fine-grained allowlist of specific tools across registered servers |
allowed_mcp_tools to name exactly which tools this agent can call.headers or command. Committing an API token directly into AgentOptions risks leaking it through logs or version control. Fix: read secrets from environment variables at call time, not literal strings in code.query() calls. A stdio server's process lifecycle is generally tied to the run that started it. Fix: don't rely on stdio server state persisting between unrelated runs; use an HTTP server if you need a long-lived shared process.| Alternative | Use When | Don't Use When |
|---|---|---|
| Built-in tools only | The task fits entirely within file/bash/web capabilities | The task needs a specific external system MCP can reach |
| Custom tool wired directly into your app | You need one very specific, tightly coupled integration and won't reuse it elsewhere | You want the same tool reusable across multiple agents or projects |
| A subagent that itself uses MCP tools | The MCP-backed work is a self-contained subtask worth isolating | The MCP call is a small, one-off step in a larger flow |
Yes, MCP tools are scoped through the same allowlist mechanism (often via a dedicated allowed_mcp_tools list), so you control exactly which registered tools the loop can call.
Yes, mcp_servers accepts a list and can mix stdio and HTTP servers together in a single agent configuration.
At startup, the SDK fetches each registered server's tool definitions (names, descriptions, argument schemas) and adds them to the loop's available tool set, the same way built-in tool definitions are presented.
Calls to that server's tools fail, and that failure feeds back into the loop as an observation the model has to reason about, the same as any other failed tool call.
Only if a suitable one doesn't already exist for the system you need; MCP is a protocol, so servers built by third parties or your own team both work as long as they speak it.
Yes, mcp_servers and allowed_mcp_tools are set per AgentOptions, so a subagent's own options can register a different (or narrower) set than its parent's.
The SDK passes along whatever headers you configure; the actual authentication scheme (bearer token, API key, etc.) is defined by the server and supplied through headers on your registration.
If an MCP tool performs a destructive or irreversible action, yes; checkpoint configuration (checkpoint_tools) applies to MCP tools the same way it applies to built-in ones.
It can, in principle, since MCP tools are just named tools with schemas. Be deliberate about scoping if you register a server whose tools might conflict or overlap in purpose with a built-in tool.
Stack versions: Written against the Claude model lineup current as of ~June 2026 - Claude Fable 5, Claude Opus 4.8, Claude Sonnet 5 (the default), and Claude Haiku 4.5 - and the Claude Agent SDK (latest release, Python and TypeScript). Model names, SDK versions, and pricing move quickly - verify current specifics at platform.claude.com/docs before relying on them.
Reviewed by Chris St. John·Last updated Jul 16, 2026