Use when working with Anthropic Claude Agent SDK. Provides architecture guidance, implementation patterns, best practices, and common pitfalls.
Claude Agent SDK
Overview
The Claude Agent SDK enables building autonomous AI agents with Claude through a feedback loop architecture. Available for Python (3.10+) and TypeScript (Node 18+).
Rule: Use tools for repeatable operations, bash for exploration, code generation when you need structured output that can be validated.
Quick Start Patterns
Python: Basic Query
from claude_agent_sdk import query
result = await query(
model="claude-sonnet-4-5",
system_prompt="You are a helpful coding assistant.",
user_message="List files in current directory",
working_dir=".",
)
print(result.final_message)
TypeScript: Session Management
import { ClaudeSdkClient } from'@anthropic-ai/agent-sdk';
const client = newClaudeSdkClient({ apiKey: process.env.ANTHROPIC_API_KEY });
const result = await client.query({
model: 'claude-sonnet-4-5',
systemPrompt: 'You are a helpful coding assistant.',
userMessage: 'List files in current directory',
workingDir: '.',
});
console.log(result.finalMessage);
Key Components
1. Custom Tools (SDK MCP Servers)
In-process tools with no subprocess overhead. Primary building block for agents.
Python:
from claude_agent_sdk.mcp import tool, create_sdk_mcp_server
@tool(
name="calculator",
description="Perform calculations",
input_schema={"expression": str}
)asyncdefcalculator(args):
result = eval(args["expression"]) # Use safe eval in productionreturn {"content": [{"type": "text", "text": str(result)}]}
server = create_sdk_mcp_server(name="math", tools=[calculator])
Symptom: stdio/SSE MCP servers timeout
Solution: Verify server is executable and logs are accessible:
# Check server stderr in context.mcp_server_logsasyncdefdebug_hook(input_data, tool_use_id, context):
print(context.mcp_server_logs.get("server_name"))
Language-Specific Considerations
Python vs TypeScript
Aspect
Python
TypeScript
Runtime
anyio.run(main)
Native async/await
Min Version
Python 3.10+
Node.js 18+
Type Safety
Type hints optional
Strict types with Zod
Hook Fields
async_, continue_
async, continue
CLI
Bundled (no install)
Separate install needed
Tool Validation
Dict-based schemas
Zod schemas
TypeScript Advantages
Linting provides extra feedback layer for generated code
Stronger type safety catches errors earlier
Better IDE integration
Python Advantages
Simpler setup for data science workflows
Direct integration with ML/data tools
More concise for scripting tasks
Decision Frameworks
When to Use Claude Agent SDK
✅ Use when:
Building autonomous agents that need computer access
Iterative workflows with verification loops
Multi-step tasks requiring context and tool use
Custom tool integration requirements
Need for permission control and safety
❌ Don't use when:
Simple API calls sufficient (use Messages API)
No tool/computer access needed
Purely conversational applications
Real-time streaming responses critical
Tool vs Bash vs Code Generation
Use Custom Tools when:
Operation repeats frequently
Need structured input/output validation
Want prominent placement in agent context
Require error handling and retry logic
Use Bash when:
One-off exploration or debugging
System operations (git, file management)
Flexible scripting without formal structure
Use Code Generation when:
Need structured, reusable output
Can validate with linting/compilation
Building components or modules
TypeScript preferred for feedback quality
SDK MCP vs External MCP
Use SDK MCP (in-process) when:
Building custom tools for your agent
Performance matters (no subprocess overhead)
Need shared state with main process
Debugging tool logic
Use External MCP (stdio/SSE) when:
Integrating third-party services
Tool needs isolation
Using pre-built MCP servers
Cross-language tool requirements
Session Management
Resuming Sessions
Python:
# First run
result1 = await query(user_message="Create a file", working_dir=".")
# Resume with new message
result2 = await query(
user_message="Now modify it",
working_dir=".",
session_id=result1.session_id
)
# Fork for different approach
result_fork = await query(
user_message="Try different implementation",
session_id=original_result.session_id,
fork_session=True
)
import tempfile
import os
asyncdeftest_file_operations():
with tempfile.TemporaryDirectory() as tmpdir:
result = await query(
user_message="Create test.txt with content 'hello'",
working_dir=tmpdir,
permission_mode="bypassPermissions"
)
assert os.path.exists(f"{tmpdir}/test.txt")