What is the Claude Code SDK?
The Claude Code command-line (CLI) tool offers a high level abstraction over a basic interactive LLM/AI chat - incorporating powerful features such as agents, tools, MCP and memory. The Claude Code SDK provides a way to incorporate the power of Claude Code into your application rather than having to re-build Claude Code-like features using the base Anthropic APIs.
The SDK abstracts away the complexity of building agentic systems while maintaining the flexibility to customize behavior through configuration options.
Why use the SDK?
While it is possible to call the CLI as a subprocess, this approach has limitations. When running non-interactively, the Claude CLI only prints the final message, making it difficult to access intermediate steps, error details, or specific message types. Configuration of permissions rely on setting up a full Claude Code CLI working directory.
Using the Anthropic API directly gives you full control but requires implementing your own tool orchestration, context management, permission systems, and conversation handling. For simple chat applications this is fine, but for agentic workflows it becomes complex quickly.
Using the Claude Code SDK provides the agent abstraction layer with built-in tool support and context management, while giving you programmatic access to message streams, error handling, and configuration options.
The SDK approach is particularly valuable when you need Claude to interact with external systems (through MCP servers), perform complex multi-step tasks, or maintain conversation state across multiple interactions.
Core Concepts
Query vs ClaudeSDKClient
The SDK provides two ways to interact with Claude:
query() creates a fresh session for each call and returns an async iterator of messages. This is ideal for one-off tasks where you don’t need conversation history:
from claude_agent_sdk import query
async for message in query(prompt="Single prompt question"):
# Process messages as they arrive
pass
ClaudeSDKClient maintains conversation state across multiple exchanges, supports interrupts and hooks, and is better suited for interactive applications where Claude needs to remember previous context:
from claude_agent_sdk import ClaudeSDKClient, AssistantMessage, TextBlock
client = ClaudeSDKClient()
# First question - ask Claude to analyze data
response1 = await client.send_message("What are the top 3 products by sales?")
# Parse the response to extract product names
product_names = []
if isinstance(response1, AssistantMessage):
for block in response1.content:
if isinstance(block, TextBlock):
# Extract product names from the text response
# (In practice you might parse more carefully)
product_names = extract_product_names(block.text)
# Second question uses information from first response
response2 = await client.send_message(
f"Show me the monthly trend for {product_names[0]}"
)
Message Types
The SDK provides distinct message classes that make it easy to process different types of responses:
AssistantMessage- Contains response content blocks and model informationTextBlock- Plain text responses within messagesToolUseBlock- Represents tool invocation requestsResultMessage- Final response with execution metrics
This structured approach is much cleaner than parsing raw API responses.
Configuration Options
ClaudeAgentOptions allows fine-grained control over agent behavior:
from claude_agent_sdk import ClaudeAgentOptions
options = ClaudeAgentOptions(
cwd="/path/to/working/directory",
allowed_tools=["Bash", "Read", "Write"],
permission_mode="auto", # or "manual", "strict"
mcp_servers={
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest"]
}
}
)
This configuration controls which tools Claude can access, where it operates, and which external services (via MCP) it can connect to.
A Practical Example: Django Management Command
I’ve been building a Django application that uses the Claude Code SDK to automate product price checking. A management command runs on a schedule, queries Claude to check product availability and pricing across multiple websites, and stores the results in the database.
Here’s a simplified version of the core query function:
from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage, TextBlock
async def query_claude(prompt):
conversation_log = []
report_text = ''
# Configure Claude with MCP servers for browser automation
options = ClaudeAgentOptions(
cwd=CLAUDE_WORKING_DIR,
mcp_servers={
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest"]
},
"tracker-mcp": {
"command": "python",
"args": ["tracker-mcp-server.py"]
}
},
allowed_tools=[
"mcp__playwright__browser_navigate",
"mcp__playwright__browser_snapshot",
"mcp__tracker-mcp__query_data",
"mcp__tracker-mcp__insert_data"
]
)
# Collect all messages from Claude
async for message in query(prompt=prompt, options=options):
if isinstance(message, AssistantMessage):
message_text = ''
for block in message.content:
if isinstance(block, TextBlock):
message_text += block.text
if message_text:
conversation_log.append(message_text)
# Return both the full conversation and final message
return '\n\n--- MESSAGE ---\n'.join(conversation_log), conversation_log[-1]
The key points here:
- MCP Integration - Claude can use Playwright to navigate websites and a custom MCP server to query the application database
- Tool Restrictions - Only specific browser and database tools are allowed, preventing unwanted side effects
- Message Processing - All messages are collected for logging, while the final message contains the formatted report
- Error Handling - The full conversation log helps debug issues when things go wrong
Use Cases
The Claude Code SDK works well for:
- Scheduled automation tasks - Like the price checking example, where Claude performs complex multi-step operations on a schedule
- Data analysis pipelines - Claude can read files, run analysis, and generate reports with access to your application’s data through MCP servers
- Code generation and refactoring - Programmatically generate or update code within your application
- Interactive applications - Build chat interfaces or coding assistants that maintain conversation state
Configuration and Authentication
The SDK uses your Claude Code configuration from ~/.claude/, including your API key. This means usage counts against your Claude Code quota rather than requiring separate Anthropic API credits. The SDK respects your project-level configuration (from .claude/ in the working directory) but doesn’t automatically apply user-level memory features - those need to be configured at the project level if needed.
What’s Next
This article provides an overview of the Claude Code SDK and why you might want to use it. Future articles will dive deeper into specific topics:
- Building custom MCP servers for application-specific integrations
- Managing permissions and security in production environments
- Handling errors and rate limits gracefully
- Optimizing costs and context usage
- Testing applications that use the Claude Code SDK
The SDK makes it possible to build production-ready agentic applications with surprisingly little code.