Python SDK for programmatically interacting with Claude Code, enabling AI-powered automation workflows with support for bidirectional conversations, custom in-process tools, hooks, and fine-grained permission control
—
—
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
—
The risk profile of this skill
This plugin was archived by the owner on Jun 3, 2026
Reason: Retiring all tiles created prior to the transition to plugin support
Configure Model Context Protocol (MCP) servers to extend Claude with custom tools. The SDK supports four server types: in-process SDK servers, subprocess stdio servers, Server-Sent Events (SSE) servers, and HTTP servers.
Union type for all MCP server configurations.
McpServerConfig = (
McpStdioServerConfig | McpSSEServerConfig |
McpHttpServerConfig | McpSdkServerConfig
)Server Types:
McpStdioServerConfig: Subprocess server via stdin/stdoutMcpSSEServerConfig: Server-Sent Events serverMcpHttpServerConfig: HTTP-based serverMcpSdkServerConfig: In-process SDK server (recommended)Subprocess-based MCP server via stdin/stdout communication.
class McpStdioServerConfig(TypedDict):
"""Subprocess MCP server via stdio."""
type: NotRequired[Literal["stdio"]]
command: str
args: NotRequired[list[str]]
env: NotRequired[dict[str, str]]Fields:
type (Literal["stdio"], optional): Server type. Optional for backwards compatibility; defaults to "stdio" if not specified.
command (str): Command to execute. Can be an executable name (resolved via PATH) or absolute path.
args (list[str], optional): Command-line arguments for the command.
env (dict[str, str], optional): Environment variables for the subprocess.
Usage Example:
from claude_agent_sdk import ClaudeAgentOptions
# Simple stdio server
options = ClaudeAgentOptions(
mcp_servers={
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
}
}
)
# With explicit type
options = ClaudeAgentOptions(
mcp_servers={
"filesystem": {
"type": "stdio",
"command": "mcp-server-filesystem",
"args": ["/home/user/data"]
}
}
)
# With environment variables
options = ClaudeAgentOptions(
mcp_servers={
"custom": {
"command": "python",
"args": ["-m", "my_mcp_server"],
"env": {
"LOG_LEVEL": "debug",
"API_KEY": "secret"
}
}
}
)Server-Sent Events MCP server configuration.
class McpSSEServerConfig(TypedDict):
"""MCP server via Server-Sent Events."""
type: Literal["sse"]
url: str
headers: NotRequired[dict[str, str]]Fields:
type (Literal["sse"]): Server type, must be "sse".
url (str): Server URL endpoint for SSE connection.
headers (dict[str, str], optional): HTTP headers to include in requests (e.g., authentication).
Usage Example:
from claude_agent_sdk import ClaudeAgentOptions
# Basic SSE server
options = ClaudeAgentOptions(
mcp_servers={
"weather": {
"type": "sse",
"url": "http://localhost:3000/sse"
}
}
)
# With authentication
options = ClaudeAgentOptions(
mcp_servers={
"api": {
"type": "sse",
"url": "https://api.example.com/mcp/sse",
"headers": {
"Authorization": "Bearer secret-token",
"X-Client-Version": "1.0"
}
}
}
)HTTP-based MCP server configuration.
class McpHttpServerConfig(TypedDict):
"""MCP server via HTTP."""
type: Literal["http"]
url: str
headers: NotRequired[dict[str, str]]Fields:
type (Literal["http"]): Server type, must be "http".
url (str): Server URL endpoint for HTTP requests.
headers (dict[str, str], optional): HTTP headers to include in requests (e.g., authentication).
Usage Example:
from claude_agent_sdk import ClaudeAgentOptions
# Basic HTTP server
options = ClaudeAgentOptions(
mcp_servers={
"data": {
"type": "http",
"url": "http://localhost:8080/mcp"
}
}
)
# With authentication and custom headers
options = ClaudeAgentOptions(
mcp_servers={
"api": {
"type": "http",
"url": "https://api.example.com/mcp",
"headers": {
"Authorization": "Bearer secret-token",
"Content-Type": "application/json",
"X-API-Version": "2.0"
}
}
}
)In-process SDK MCP server configuration.
class McpSdkServerConfig(TypedDict):
"""In-process SDK MCP server."""
type: Literal["sdk"]
name: str
instance: McpServerFields:
type (Literal["sdk"]): Server type, must be "sdk".
name (str): Server name for identification.
instance (McpServer): Server instance created by create_sdk_mcp_server().
Usage Example:
from claude_agent_sdk import (
ClaudeAgentOptions, create_sdk_mcp_server, tool
)
# Create tools
@tool("greet", "Greet user", {"name": str})
async def greet(args):
return {"content": [{"type": "text", "text": f"Hello, {args['name']}!"}]}
# Create SDK server
my_server = create_sdk_mcp_server(
name="greeting",
version="1.0.0",
tools=[greet]
)
# Use in options
options = ClaudeAgentOptions(
mcp_servers={"greet": my_server},
allowed_tools=["greet"]
)Note: SDK servers are created using create_sdk_mcp_server() which returns a properly formatted McpSdkServerConfig. See Custom Tools for detailed documentation.
from claude_agent_sdk import (
ClaudeAgentOptions, create_sdk_mcp_server, tool
)
# SDK server (in-process)
@tool("calculate", "Perform calculation", {"expression": str})
async def calculate(args):
result = eval(args["expression"])
return {"content": [{"type": "text", "text": str(result)}]}
calc_server = create_sdk_mcp_server("calculator", tools=[calculate])
# Configuration with all server types
options = ClaudeAgentOptions(
mcp_servers={
# In-process SDK server
"calc": calc_server,
# Subprocess stdio server
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
},
# SSE server
"weather": {
"type": "sse",
"url": "http://localhost:3000/sse",
"headers": {"Authorization": "Bearer token"}
},
# HTTP server
"api": {
"type": "http",
"url": "https://api.example.com/mcp",
"headers": {"X-API-Key": "secret"}
}
},
allowed_tools=["calculate", "read_file", "get_weather", "api_call"]
)from claude_agent_sdk import ClaudeAgentOptions
import os
# Development configuration - local servers
dev_servers = {
"database": {
"type": "http",
"url": "http://localhost:8080/mcp"
},
"cache": {
"type": "http",
"url": "http://localhost:6379/mcp"
}
}
# Production configuration - authenticated remote servers
prod_servers = {
"database": {
"type": "http",
"url": "https://db.example.com/mcp",
"headers": {
"Authorization": f"Bearer {os.environ['DB_TOKEN']}",
"X-Environment": "production"
}
},
"cache": {
"type": "http",
"url": "https://cache.example.com/mcp",
"headers": {
"Authorization": f"Bearer {os.environ['CACHE_TOKEN']}"
}
}
}
# Select based on environment
is_production = os.environ.get("ENV") == "production"
servers = prod_servers if is_production else dev_servers
options = ClaudeAgentOptions(mcp_servers=servers)from claude_agent_sdk import ClaudeAgentOptions
from pathlib import Path
# Single directory access
options = ClaudeAgentOptions(
mcp_servers={
"fs": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/home/user/project"
]
}
},
allowed_tools=["read_file", "write_file", "list_directory"]
)
# Multiple directory access
project_root = Path("/home/user/project")
options = ClaudeAgentOptions(
mcp_servers={
"project_fs": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
str(project_root / "src"),
str(project_root / "tests")
]
}
}
)from claude_agent_sdk import ClaudeAgentOptions
import os
options = ClaudeAgentOptions(
mcp_servers={
"postgres": {
"command": "mcp-server-postgres",
"env": {
"DATABASE_URL": os.environ["DATABASE_URL"],
"PGUSER": os.environ["PGUSER"],
"PGPASSWORD": os.environ["PGPASSWORD"],
"PGDATABASE": "myapp"
}
}
},
allowed_tools=["query_db", "execute_sql"]
)from claude_agent_sdk import ClaudeAgentOptions, create_sdk_mcp_server, tool
import httpx
class APIClient:
def __init__(self, base_url: str, api_key: str):
self.base_url = base_url
self.api_key = api_key
async def get(self, endpoint: str):
async with httpx.AsyncClient() as client:
response = await client.get(
f"{self.base_url}{endpoint}",
headers={"Authorization": f"Bearer {self.api_key}"}
)
return response.json()
# Create API client
api = APIClient("https://api.example.com", "secret-key")
# Define tool
@tool("api_get", "Fetch from API", {"endpoint": str})
async def api_get(args):
data = await api.get(args["endpoint"])
return {"content": [{"type": "text", "text": str(data)}]}
# Create server
api_server = create_sdk_mcp_server("api", tools=[api_get])
options = ClaudeAgentOptions(
mcp_servers={"api": api_server},
allowed_tools=["api_get"]
)from claude_agent_sdk import ClaudeAgentOptions
# GitHub API server
github_server = {
"type": "http",
"url": "https://mcp-github.example.com",
"headers": {
"Authorization": f"token {os.environ['GITHUB_TOKEN']}",
"Accept": "application/vnd.github.v3+json"
}
}
# Slack API server
slack_server = {
"type": "sse",
"url": "https://mcp-slack.example.com/sse",
"headers": {
"Authorization": f"Bearer {os.environ['SLACK_TOKEN']}"
}
}
# Jira API server
jira_server = {
"command": "mcp-server-jira",
"env": {
"JIRA_URL": os.environ["JIRA_URL"],
"JIRA_USERNAME": os.environ["JIRA_USERNAME"],
"JIRA_API_TOKEN": os.environ["JIRA_API_TOKEN"]
}
}
options = ClaudeAgentOptions(
mcp_servers={
"github": github_server,
"slack": slack_server,
"jira": jira_server
}
)from claude_agent_sdk import ClaudeAgentOptions
# Run custom Python MCP server as subprocess
options = ClaudeAgentOptions(
mcp_servers={
"custom": {
"command": "python",
"args": ["-m", "my_package.mcp_server"],
"env": {
"LOG_LEVEL": "info",
"CONFIG_PATH": "/etc/myapp/config.json"
}
}
}
)Load MCP server configurations from a file:
from claude_agent_sdk import ClaudeAgentOptions
from pathlib import Path
# Load from JSON file
options = ClaudeAgentOptions(
mcp_servers="/path/to/mcp-config.json"
)
# Load from YAML file
options = ClaudeAgentOptions(
mcp_servers=Path("/path/to/mcp-config.yaml")
)Example config file (JSON):
{
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
},
"weather": {
"type": "sse",
"url": "http://localhost:3000/sse"
},
"database": {
"type": "http",
"url": "http://localhost:8080/mcp",
"headers": {
"Authorization": "Bearer token"
}
}
}| Feature | SDK | Stdio | SSE | HTTP |
|---|---|---|---|---|
| Process | In-process | Subprocess | Remote | Remote |
| Performance | Fastest | Fast | Medium | Medium |
| Deployment | Simple | Simple | Complex | Complex |
| Debugging | Easy | Medium | Hard | Hard |
| State Access | Direct | None | None | None |
| Language | Python | Any | Any | Any |
| IPC Overhead | None | Low | Medium | Medium |
Recommendations:
Prefer SDK Servers: Use in-process SDK servers when possible for best performance
Secure Authentication: Always use headers for authentication with remote servers
Environment Variables: Use environment variables for secrets, not hardcoded values
Error Handling: MCP servers should handle errors gracefully and return error content
Server Naming: Use descriptive server names (e.g., "github_api", not "server1")
Tool Whitelisting: Always specify allowed_tools to control which tools Claude can use
Local Development: Use local servers for development, authenticated remote servers for production
Monitoring: Log MCP server requests and responses for debugging
Timeouts: Configure timeouts for remote server requests
Documentation: Document available tools and their parameters for team members
# Add stderr callback to debug server issues
def handle_stderr(line: str):
print(f"MCP Server stderr: {line}")
options = ClaudeAgentOptions(
mcp_servers={"server": server_config},
stderr=handle_stderr
)Ensure the server command is executable and paths are accessible:
import os
import stat
# Make server script executable
server_path = "/path/to/server"
os.chmod(server_path, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP)Validate environment variables before use:
required_vars = ["API_KEY", "DATABASE_URL"]
missing = [var for var in required_vars if var not in os.environ]
if missing:
raise ValueError(f"Missing environment variables: {missing}")from claude_agent_sdk import ClaudeAgentOptions
def get_mcp_servers(environment: str) -> dict:
"""Get MCP server config based on environment."""
if environment == "production":
return {
"api": {
"type": "http",
"url": "https://api.prod.example.com/mcp",
"headers": {"Authorization": f"Bearer {os.environ['PROD_TOKEN']}"}
}
}
else:
return {
"api": {
"type": "http",
"url": "http://localhost:8080/mcp"
}
}
options = ClaudeAgentOptions(
mcp_servers=get_mcp_servers(os.environ.get("ENV", "dev"))
)servers = {}
# Load filesystem server if available
if shutil.which("npx"):
servers["fs"] = {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
}
# Load custom server if module exists
try:
import my_mcp_server
servers["custom"] = create_sdk_mcp_server(
"custom",
tools=my_mcp_server.get_tools()
)
except ImportError:
pass
options = ClaudeAgentOptions(mcp_servers=servers)docs