Connecting MCP Servers to Claude Agent SDK - A Practical Guide
Connecting MCP Servers to Claude Agent SDK - A Practical Guide
One of the things that makes the Claude Agent SDK genuinely useful for building production agents is MCP support. The Model Context Protocol lets your agent connect to external tools and data sources without you having to write custom tool implementations for every integration. Need your agent to query a database? There's probably an MCP server for that. GitHub? Slack? Filesystem access? Same story.
I've been building agents with the Claude Agent SDK across several client projects, and MCP is consistently where agents go from interesting demos to actually useful systems. An agent that can only think is limited. An agent that can think and act on real systems through MCP servers starts solving real problems.
The Claude Agent SDK MCP documentation covers the technical reference. Here's what I've learned about using it effectively.
What MCP Actually Is
MCP - the Model Context Protocol - is an open standard for connecting AI agents to external tools. Think of it like a USB port for AI agents. Your agent understands the MCP protocol, and any tool that speaks MCP can plug in. The agent discovers what tools are available, understands their inputs and outputs, and calls them as needed.
The practical upside is that you don't build integrations from scratch. The MCP ecosystem has servers for GitHub, Slack, databases, file systems, web browsing, and dozens of other services. You configure the connection, tell your agent which tools it can use, and the agent figures out when and how to call them.
The Claude Agent SDK supports MCP natively. You pass server configurations when creating your agent, specify which tools are allowed, and the SDK handles the connection lifecycle - starting servers, discovering tools, managing the protocol, and shutting things down cleanly.
A Quick Working Example
Let me show what this looks like in practice before we get into the details. Here's an agent that connects to a documentation MCP server and uses it to answer questions:
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "What are hooks in Claude Code?",
options: {
mcpServers: {
"claude-code-docs": {
type: "http",
url: "https://code.claude.com/docs/mcp"
}
},
allowedTools: ["mcp__claude-code-docs__*"]
}
})) {
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}
That's a working agent with external tool access in about 15 lines. The agent connects to the documentation server, discovers its available tools, searches for information about hooks, and returns the answer. No custom tool code needed.
The Python equivalent is just as clean:
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
async def main():
options = ClaudeAgentOptions(
mcp_servers={
"claude-code-docs": {
"type": "http",
"url": "https://code.claude.com/docs/mcp",
}
},
allowed_tools=["mcp__claude-code-docs__*"],
)
async for message in query(
prompt="What are hooks in Claude Code?",
options=options,
):
if isinstance(message, ResultMessage) and message.subtype == "success":
print(message.result)
asyncio.run(main())
Transport Types - Choosing the Right Connection
MCP servers communicate with your agent using different transport protocols. Which one you use depends on where the server runs.
stdio is for local processes. The MCP server runs on the same machine as your agent, communicating through standard input and output. This is what you use for most open-source MCP servers that you install via npm. You specify a command to run and any arguments:
mcpServers: {
github: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-github"],
env: {
GITHUB_TOKEN: process.env.GITHUB_TOKEN
}
}
}
The SDK starts the process, manages the communication, and shuts it down when the agent finishes. You can pass environment variables through the env field, which is how most servers receive credentials.
HTTP and SSE are for remote servers. If the MCP server is hosted somewhere on the internet, you connect via URL:
mcpServers: {
"remote-api": {
type: "sse",
url: "https://api.example.com/mcp/sse",
headers: {
Authorization: `Bearer ${process.env.API_TOKEN}`
}
}
}
Use HTTP for servers that support the newer streamable HTTP transport. Use SSE (Server-Sent Events) for servers that use the older streaming protocol. Check the server's documentation to see which it supports.
SDK MCP servers run directly inside your application. This is for when you're building your own tools in code rather than connecting to external servers. Useful when you want tight integration with your application's internal state.
How do you know which transport to use? Simple rule of thumb: if the server's documentation gives you a command to run (like npx @modelcontextprotocol/server-github), use stdio. If it gives you a URL, use HTTP or SSE.
Tool Permissions - Getting This Right
Here's something that trips people up. MCP tools require explicit permission before the agent can use them. Just connecting to an MCP server doesn't mean the agent can call its tools. You need to specify which tools are allowed via the allowedTools configuration.
MCP tools follow a naming convention: mcp__<server-name>__<tool-name>. So a GitHub server named "github" with a list_issues tool becomes mcp__github__list_issues.
You can be as specific or broad as you want:
allowedTools: [
"mcp__github__*", // All tools from the github server
"mcp__db__query", // Only the query tool from the db server
"mcp__slack__send_message" // Only send_message from the slack server
]
The wildcard (*) is convenient during development but think about whether you want it in production. Allowing mcp__github__* means the agent can create issues, close PRs, push code - everything the GitHub MCP server can do. If your agent only needs to read issues, restrict it to mcp__github__list_issues and mcp__github__get_issue.
One thing worth knowing: the SDK's permissionMode: "acceptEdits" does NOT auto-approve MCP tools. It only auto-approves file edits and filesystem commands. And permissionMode: "bypassPermissions" does approve MCP tools but also removes all other safety checks, which is more than you want. Use allowedTools with explicit wildcards instead - it gives you exactly the MCP access you need without disabling other protections.
Configuration via .mcp.json
If you don't want to configure MCP servers in code, you can use a .mcp.json file at your project root. The SDK picks it up automatically:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/project"]
},
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_TOKEN": "${GITHUB_TOKEN}"
}
}
}
}
Notice the ${GITHUB_TOKEN} syntax - you can reference environment variables in the config file. This keeps secrets out of your config while still being explicit about what the server needs.
This approach works well for team projects. Commit the .mcp.json to your repo so everyone gets the same MCP server configuration. Each developer sets the environment variables locally.
Discovering Available Tools
When you connect to an MCP server, how do you know what tools it offers? You can check the server's documentation, obviously. But you can also inspect the tools programmatically by checking the system init message:
for await (const message of query({ prompt: "...", options })) {
if (message.type === "system" && message.subtype === "init") {
console.log("Available MCP tools:", message.mcp_servers);
}
}
This is useful during development when you're exploring a new MCP server and want to see exactly what it provides before deciding which tools to allow.
Patterns That Work in Production
After building several agent systems that use MCP extensively, here are the patterns I keep coming back to.
Principle of least privilege for tool access. Start with no tools allowed and add them one at a time as needed. It's tempting to wildcard everything during development and tighten it later. You won't tighten it later. Be specific from the start.
Separate read and write servers when possible. If you're connecting to a system where the agent needs to both read and write data, consider whether you can use separate MCP configurations - one for read operations and one for write operations. This lets you grant read access broadly while being more restrictive about writes.
Test MCP connections independently. Before hooking an MCP server into your agent, verify it works on its own. Most MCP servers have some way to test the connection - use it. Finding out your GitHub token has expired during a demo is not ideal.
Handle MCP failures gracefully. MCP servers can fail. The network can drop. A local process can crash. Your agent should handle these failures rather than crashing. The SDK provides error information when MCP calls fail - use it to give the agent enough context to work around the failure or ask the user for help.
Environment variables for all credentials. Never hardcode tokens or secrets in your MCP configuration. Use environment variables with the env field for stdio servers and the ${VAR} syntax in .mcp.json files.
When MCP Makes Sense (and When It Doesn't)
MCP is excellent when you need your agent to interact with established services that already have MCP servers. GitHub, Slack, PostgreSQL, filesystem access, web search - the ecosystem covers a lot of common needs.
MCP is less appropriate when you need very tight integration with custom internal systems. If your agent needs to call a proprietary internal API with complex authentication, session management, and domain-specific error handling, building a custom tool in code gives you more control than trying to force it through an MCP server.
The overhead of MCP is low, but it's not zero. Each server connection is a process or network connection. For agents that only need one or two simple tools, building those tools directly might be simpler than configuring MCP.
At Team 400, we build AI agent systems for Australian organisations using the Claude Agent SDK and other frameworks. MCP is one of the patterns we use heavily, particularly for agents that need to integrate with existing enterprise tools. If you're building agents that need to connect to your organisation's systems, our AI development team can help you design and build the right architecture. And for organisations exploring AI strategy more broadly, our AI consulting practice can help you figure out where agents and MCP fit into your technology stack.
For the full technical reference on MCP in the Claude Agent SDK, see the official documentation.