CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-claude-agent-sdk

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

Quality

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

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

Overview
Eval results
Files

mcp-server-configuration.mddocs/

MCP Server Configuration

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.

Capabilities

MCP Server Config Union

Union type for all MCP server configurations.

McpServerConfig = (
    McpStdioServerConfig | McpSSEServerConfig |
    McpHttpServerConfig | McpSdkServerConfig
)

Server Types:

  • McpStdioServerConfig: Subprocess server via stdin/stdout
  • McpSSEServerConfig: Server-Sent Events server
  • McpHttpServerConfig: HTTP-based server
  • McpSdkServerConfig: In-process SDK server (recommended)

Stdio Server Configuration

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"
            }
        }
    }
)

SSE Server Configuration

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 Server Configuration

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"
            }
        }
    }
)

SDK Server Configuration

In-process SDK MCP server configuration.

class McpSdkServerConfig(TypedDict):
    """In-process SDK MCP server."""

    type: Literal["sdk"]
    name: str
    instance: McpServer

Fields:

  • 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.

Complete Examples

Multiple Server Types

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"]
)

Development vs Production Configuration

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)

Filesystem Server Configuration

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")
            ]
        }
    }
)

Database Server Configuration

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"]
)

API Integration Server

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"]
)

External Service Integration

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
    }
)

Custom Python MCP 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"
            }
        }
    }
)

MCP Config File

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"
    }
  }
}

Server Type Comparison

FeatureSDKStdioSSEHTTP
ProcessIn-processSubprocessRemoteRemote
PerformanceFastestFastMediumMedium
DeploymentSimpleSimpleComplexComplex
DebuggingEasyMediumHardHard
State AccessDirectNoneNoneNone
LanguagePythonAnyAnyAny
IPC OverheadNoneLowMediumMedium

Recommendations:

  • SDK servers: Best for Python tools with direct access to application state
  • Stdio servers: Good for local tools in any language
  • SSE servers: Good for streaming updates and real-time data
  • HTTP servers: Good for existing HTTP APIs and microservices

Best Practices

  1. Prefer SDK Servers: Use in-process SDK servers when possible for best performance

  2. Secure Authentication: Always use headers for authentication with remote servers

  3. Environment Variables: Use environment variables for secrets, not hardcoded values

  4. Error Handling: MCP servers should handle errors gracefully and return error content

  5. Server Naming: Use descriptive server names (e.g., "github_api", not "server1")

  6. Tool Whitelisting: Always specify allowed_tools to control which tools Claude can use

  7. Local Development: Use local servers for development, authenticated remote servers for production

  8. Monitoring: Log MCP server requests and responses for debugging

  9. Timeouts: Configure timeouts for remote server requests

  10. Documentation: Document available tools and their parameters for team members

Troubleshooting

Server Connection Issues

# 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
)

Permission Denied

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)

Environment Variable Issues

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}")

Advanced Configuration

Dynamic Server Configuration

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"))
)

Conditional Server Loading

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

agent-definitions.md

agents.md

client.md

configuration-options.md

content-blocks.md

core-query-interface.md

custom-tools.md

error-handling.md

errors.md

hook-system.md

hooks.md

index.md

mcp-config.md

mcp-server-configuration.md

messages-and-content.md

messages.md

options.md

permission-control.md

permissions.md

query.md

transport.md

COMPLETION_SUMMARY.md

tile.json