Build Production-Grade AI Agents with the Claude Agent SDK

Vibe Tools Expert Team
Published
Updated

Build Production-Grade AI Agents with the Claude Agent SDK

If you've been working with AI, you know that the future isn't just about chatbots—it's about building truly autonomous systems that can handle complex, multi-step tasks, interact with files, and execute code.

That’s where Anthropic’s official Python and TypeScript toolkit, the Claude Agent SDK, comes in. Formerly known as the Claude Code SDK, this framework provides all the necessary building blocks for creating production-grade AI agents. It brings the powerful agentic capabilities of Claude Code—including context management, rich tooling, error handling, and advanced permissions—directly into your applications.

Ready to give your AI agents the digital equivalent of a computer on a desk? Let's walk through how to start building with the Claude Agent SDK!


I. Getting Started: Installation and Prerequisites

To leverage the full power of the Claude Agent SDK, follow these simple setup steps.

1. Prerequisites and Installation

The Python Claude Agent SDK requires a few key components:

  • Python 3.10+.
  • Node.js.
  • Claude Code CLI (2.0.0+): You need to install the underlying engine via NPM (npm install -g @anthropic-ai/claude-code).
  • Install the SDK: The Python package name has been updated to claude-agent-sdk (from claude-code-sdk).
# Install the Claude Agent SDK Python package
pip install claude-agent-sdk

# Set your API Key
export ANTHROPIC_API_KEY="your-key-here"

You can obtain your Claude API key from the Claude Console.


II. Core Usage: Choosing Your Interaction Mode

The Claude Agent SDK offers two primary ways to interact with Claude Agent, depending on whether you need session memory:

Mode 1: Single-Call Queries (query())

The query() function is ideal for one-off tasks or questions that do not require remembering previous context. It creates a new session for every interaction, returns an async iterator suitable for processing streaming responses, and automatically manages the connection lifecycle.

Code Detail: Basic Streaming Query

This example shows the minimal usage of the Claude Agent SDK to receive streaming output:

import anyio
from claude_agent_sdk import query, AssistantMessage, TextBlock

async def basic_query_example():
    # query() returns an AsyncIterator[Message]
    async for message in query(prompt="Hello Claude, what is the capital of France?"):
        # Check if the message is from the Assistant
        if isinstance(message, AssistantMessage):
            for block in message.content:
                # Extract and print the text response
                if isinstance(block, TextBlock):
                    print(block.text, end="")
    print()

if __name__ == "__main__":
    anyio.run(basic_query_example)

Mode 2: Continuous Conversation (ClaudeSDKClient)

For applications requiring memory, complex interactive dialogues, or advanced features like custom tools and hooks, the Claude Agent SDK recommends using ClaudeSDKClient. This class maintains session continuity across multiple query() calls.

Key Features of ClaudeSDKClient:

  • Session Continuity: Claude remembers previous messages and context.
  • Supports Advanced Features: Enables custom tools and hooks.
  • Interruption: Allows stopping a running agent mid-execution (client.interrupt()).
  • Explicit Lifecycle: You manually control the connection and disconnection, often using an asynchronous context manager.

Code Detail: Persistent Conversation with ClaudeSDKClient

import asyncio
from claude_agent_sdk import ClaudeSDKClient, AssistantMessage, TextBlock

async def continuous_conversation_example():
    # Use context manager for automatic connection management
    async with ClaudeSDKClient() as client:
        # First query: sets the context
        await client.query("What is the largest mammal on Earth?")
        async for message in client.receive_response():
            # Process response...
            pass

        # Second query: Claude remembers the previous context
        await client.query("Tell me one interesting fact about that animal.")
        async for message in client.receive_response():
            if isinstance(message, AssistantMessage):
                for block in message.content:
                    if isinstance(block, TextBlock):
                        print(f"Claude: {block.text}")

if __name__ == "__main__":
    asyncio.run(continuous_conversation_example())


III. Advanced Development Details: Customizing Your Claude Agent SDK

The real power of the Claude Agent SDK lies in its configuration capabilities using the ClaudeAgentOptions data class, enabling fine-grained control over tools, permissions, and behavior.

1. Configuring Autonomy and Permissions (ClaudeAgentOptions)

ClaudeAgentOptions allows you to set the agent's system prompt, define allowed tools, and specify the working directory (cwd).

Code Detail: Enabling Built-in Tools and Setting Permissions

The Claude Agent SDK is built on the agent framework that powers Claude Code, which includes powerful built-in tools like Read, Write, and Bash for file operations and command execution.

from claude_agent_sdk import query, ClaudeAgentOptions
import asyncio

async def options_with_tools():
    options = ClaudeAgentOptions(
        # Set the agent's persona
        system_prompt="You are an expert Python developer",
        # Allow the agent to use core capabilities
        allowed_tools=["Read", "Write", "Bash"],
        # Use 'acceptEdits' mode to automatically approve file modifications, useful for automation
        permission_mode='acceptEdits',
        # Set the current working directory
        cwd="/home/user/project"
    )

    async for message in query(
        prompt="Create a Python script named 'hello.py' that prints 'Hello World'",
        options=options
    ):
        # The agent will use the 'Write' tool, automatically accepted by the permission_mode
        pass

if __name__ == "__main__":
    asyncio.run(options_with_tools())

2. Defining Custom Tools (In-Process SDK MCP Servers)

One of the most powerful features of the Claude Agent SDK is the ability to expose your own Python functions as callable tools, known as in-process SDK MCP servers. This eliminates the overhead of inter-process communication (IPC) required by external Model Context Protocol (MCP) servers, simplifying deployment and improving performance.

Code Detail: Creating and Integrating a Custom Tool

  1. Define the Tool: Use the @tool decorator to specify the tool's name, description, and input schema.
  2. Create the Server: Use create_sdk_mcp_server() to wrap the tool function.
  3. Configure Options: Include the resulting McpSdkServerConfig in ClaudeAgentOptions.mcp_servers. Note the required naming convention for allowed_tools: mcp__<server_name>__<tool_name>.
from claude_agent_sdk import tool, create_sdk_mcp_server, ClaudeAgentOptions, ClaudeSDKClient
from typing import Any
import asyncio

# 1. Define the tool with type-safe input schema
@tool("calculate", "Execute a mathematical expression", {"expression": str})
async def calculate(args: dict[str, Any]) -> dict[str, Any]:
    try:
        result = eval(args["expression"], {"__builtins__": {}}) # Example logic
        return {"content": [{"type": "text", "text": f"Result: {result}"}]}
    except Exception as e:
        return {"content": [{"type": "text", "text": f"Error: {str(e)}"}], "is_error": True}

# 2. Create an in-process SDK MCP server
my_server = create_sdk_mcp_server(
    name="utilities",
    version="1.0.0",
    tools=[calculate]
)

async def custom_tool_session():
    # 3. Configure ClaudeAgentOptions
    options = ClaudeAgentOptions(
        mcp_servers={"utils": my_server},
        # Allow Claude to use the tool using the MCP naming convention
        allowed_tools=["mcp__utils__calculate"]
    )

    async with ClaudeSDKClient(options=options) as client:
        await client.query("What is 123 multiplied by 456?")
        async for message in client.receive_response():
            # Claude will decide to use the 'calculate' tool
            # ... print response ...
            pass

if __name__ == "__main__":
    asyncio.run(custom_tool_session())

3. Enhancing Safety and Observability with Hooks

Hooks are deterministic callback functions that are executed at specific points during the agent's operation cycle (e.g., before or after a tool is used, or when a user prompt is submitted). They are critical for implementing safety checks, logging, or modifying inputs.

Code Detail: Blocking Dangerous Operations with Hooks (PreToolUse)

This example demonstrates how to use the PreToolUse hook to deny a potentially destructive Bash command:

from claude_agent_sdk import ClaudeAgentOptions, ClaudeSDKClient, HookMatcher
from typing import Any
import asyncio

async def check_bash_command(input_data: dict[str, Any], tool_use_id: str | None, context: Any) -> dict[str, Any]:
    tool_name = input_data.get('tool_name', '')
    if tool_name == "Bash":
        command = input_data['tool_input'].get('command', '')
        # Check for a dangerous pattern
        if 'rm -rf /' in command:
            print("[SECURITY HOOK] Dangerous command blocked!")
            return {
                'hookSpecificOutput': {
                    'hookEventName': 'PreToolUse',
                    # Deny the operation
                    'permissionDecision': 'deny',
                    'permissionDecisionReason': 'Dangerous command blocked'
                }
            }
    return {}

async def hooks_example():
    options = ClaudeAgentOptions(
        allowed_tools=["Bash"],
        hooks={
            # Apply hook before any tool use
            'PreToolUse': [
                # Use HookMatcher to specifically target the 'Bash' tool
                HookMatcher(matcher='Bash', hooks=[check_bash_command])
            ]
        }
    )

    async with ClaudeSDKClient(options=options) as client:
        # Agent attempts to run the dangerous command
        await client.query("Run a bash command that removes all files recursively.")
        # The hook will intercept and block the Bash tool use
        async for message in client.receive_response():
            print(message)

if __name__ == "__main__":
    asyncio.run(hooks_example())


IV. Conclusion: Why the Claude Agent SDK is Production-Ready

The Claude Agent SDK isn't just another agent framework; it’s an infrastructure for building robust, professional autonomous systems.

It directly addresses the challenges faced when deploying agents to production environments:

  1. Autonomy and Persistence: It enables agents to operate independently for long durations (Claude Sonnet 4.5 can run autonomously for over 30 hours). The SDK handles persistent state management and session continuity.
  2. Context Management: It includes automatic context compaction and management to prevent token limits from being hit, a necessary feature for long-running workflows.
  3. Security and Control: Features like allowed_tools, permission_mode, and powerful Hooks ensure you have fine-grained control over what your agent can and cannot do, preventing the agent from performing dangerous actions.
  4. Flexible Tooling: Through the use of MCP and in-process SDK MCP servers, you can seamlessly integrate custom Python functions as high-performance tools, extending the agent's capabilities without complex subprocess management.

If your goal is to transition from simple prototypes to complex, reliable, SRE/DevOps, or Financial Services agents that integrate deeply with your system, the Claude Agent SDK provides the foundation to get work done. Happy building!

Blog

Latest from the blog

New research, comparisons, and workflow tips from the Vibe Coding Tools team.

The Coding Beast Has Arrived: Your Complete Guide to Claude Sonnet 4.5

Explore Claude Sonnet 4.5's record-breaking coding performance, new agent tools, usage limits, and expert tips for getting started today.

Vibe Tools Expert Team
Read article
Unlocking the Browser Context: Chrome DevTools MCP for AI Coding Agents

See how Chrome DevTools MCP ends blind programming by giving AI coding agents real-time debugging insight across the browser.

Vibe Tools Expert Team
Read article
Serena MCP: Detailed User Guide (Installation, Configuration, and Practical Usage)

Step-by-step tutorial for installing Serena MCP, configuring Claude Desktop, and building practical workflows with uv.

Vibe Tools Expert Team
Read article