How to Use Claude Agent SDK: 12 Steps, 100 Min [2026]

Anthropic’s Claude Agent SDK turns the same agent loop that powers Claude Code into a library you can drop into your own Python or TypeScript application. Instead of writing a tool-calling loop from scratch against the raw Claude API, you get file access, shell commands, web search, permission handling, and multi-agent orchestration out of the box. As of August 2026, the Python package claude-agent-sdk sits at version 0.2.139 on PyPI and the TypeScript package @anthropic-ai/claude-agent-sdk is at version 0.3.233 on npm, both under active weekly releases.

This tutorial walks through installing the Claude Agent SDK, writing your first agent, choosing between Claude Opus 4.8, Sonnet 4.6, and Haiku 4.5, locking down permissions, wiring in custom tools through an in-process MCP server, adding safety hooks, delegating to subagents, and shipping a complete working project: a repo audit agent that reads a codebase, searches it, and produces a structured report. Budget about 100 minutes if you’re following every step, less if you skip straight to the project.

Google · Preferred Sources

Don't miss new tech stories on Google

Add Tech Insider once in the Google app and our stories appear in your news suggestions.

Add Now

What Is the Claude Agent SDK?

The Claude Agent SDK is Anthropic’s official Python and TypeScript library that exposes the agent loop, tool execution, context management, and permission system that run Claude Code, packaged as an API you call from your own process. Anthropic originally shipped this as the Claude Code SDK and renamed it to Claude Agent SDK once the harness was generalized past coding tasks, according to Anthropic’s own announcement. The pitch is simple: you stop reimplementing the same read-file, run-command, search-web, edit-code loop every time you build an agent, and instead call query() or spin up a ClaudeSDKClient and let the SDK manage it.

Agents built with the SDK can read and write files, run shell commands, search and fetch the web, and call custom tools you define, all inside a permission system that decides what gets auto-approved, what gets asked, and what gets blocked outright. Apple’s Xcode now ships with Claude Agent SDK support baked in, using the same harness that runs Claude Code, which is the most concrete evidence yet that the SDK has moved past hobby projects into shipped developer tools. Anthropic also launched Claude Managed Agents in April 2026 as a hosted alternative: instead of running the harness yourself, Anthropic runs the sandbox and you integrate over REST. The Agent SDK remains the self-hosted option for teams that want the agent loop running inside their own infrastructure.

The core loop the SDK implements — gather context, take an action, verify the result, repeat — is the same loop Claude Code runs on every coding task, which is why agents built with the SDK inherit behaviors that took Anthropic years of Claude Code usage to tune: knowing when to re-read a file after an edit, when to run a test suite before declaring a task done, and when to stop and ask instead of guessing. That inherited judgment is the actual value proposition over hand-rolling a tool loop against the raw Messages API — you’re not just getting a thinner wrapper around tool calls, you’re getting the accumulated behavior tuning from a production coding agent used by millions of developers.

Claude Agent SDK vs Claude Code CLI vs MCP: How They Differ

People searching for a Claude Agent SDK tutorial usually arrive confused about how it relates to two other things with overlapping names: the Claude Code CLI and the Model Context Protocol. They solve different problems and you’ll likely use more than one together.

Claude Code CLI is the command-line tool developers install globally with npm install -g @anthropic-ai/claude-code to use Claude interactively inside a terminal. The Agent SDK is the programmable version of that same harness: instead of a human typing prompts into a terminal, your application calls the SDK directly and handles the responses in code. When you install the Python Agent SDK package, the Claude Code CLI binary gets bundled automatically, so the two share the same underlying engine even though they’re used differently.

The Model Context Protocol is a separate, open specification for exposing tools and data sources to any compatible AI client, not just Claude. An MCP server describes a set of tools; an MCP client (which can be Claude Desktop, Claude Code, or your own Agent SDK app) connects to it and calls those tools. The Agent SDK can act as an MCP client, connecting to external MCP servers, and it can also host its own in-process MCP server for custom tools without running a separate process. If you already built an MCP server for another project, check our guide on how to set up MCP servers before wiring it into an Agent SDK app.

LayerWhat It IsWho Uses ItTypical Entry Point
Claude Code CLIInteractive terminal tool for coding with ClaudeIndividual developersnpm install -g @anthropic-ai/claude-code
Claude Agent SDKProgrammable library exposing the same agent loopDevelopers embedding agents in appspip install claude-agent-sdk
Model Context ProtocolOpen protocol for exposing tools/data to any AI clientTool authors, integration buildersAny MCP-compatible server framework
Claude Managed AgentsAnthropic-hosted version of the same harnessTeams that don’t want to run infraREST API, launched April 2026

Prerequisites: What You Need Before You Start

Check these before you install anything. The Claude Agent SDK is picky about Python and Node versions, and skipping this step is the single most common reason a first install fails.

RequirementMinimum VersionCheck CommandNotes
Python3.10+python3 --versionRequired for the Python SDK; 3.11+ recommended for async performance
Node.js18+node --versionNeeded even for Python projects, since the CLI binary runs on Node
Python SDK packageclaude-agent-sdk 0.2.139pip show claude-agent-sdkCurrent version on PyPI as of August 2026
TypeScript SDK package@anthropic-ai/claude-agent-sdk 0.3.233npm list @anthropic-ai/claude-agent-sdkCurrent version on npm as of August 2026
Anthropic API keyAny active keyN/APay-as-you-go billing tied to your Anthropic Console account

You’ll also want a terminal, a code editor, and roughly $5-10 of API credit sitting in your Anthropic Console account if you plan to run every example in this tutorial including the full project at the end. None of the examples here require GPU access, Docker, or a cloud account: everything runs locally against the Anthropic API.

Step 1: Create Your Anthropic API Key

Sign in to the Anthropic Console, open the API Keys section, and generate a new key. Store it as an environment variable rather than hardcoding it into any script, since the SDK reads it automatically from ANTHROPIC_API_KEY.

# macOS/Linux
export ANTHROPIC_API_KEY="sk-ant-your-key-here"

# Or store it in a .env file and load it with python-dotenv
echo 'ANTHROPIC_API_KEY=sk-ant-your-key-here' > .env

If you already use the Claude API for other projects, this is the same key. Our Claude API tutorial covers raw API calls without the agent loop if you want to compare the two approaches side by side before committing to the SDK.

Step 2: Install Python, Node.js, and the SDK Packages

Install the Python package inside a virtual environment so it doesn’t collide with other projects’ dependencies. If you’re building the TypeScript version instead, skip to the npm block.

# Python setup
python3 -m venv venv
source venv/bin/activate        # Windows: venv\Scripts\activate
pip install claude-agent-sdk
pip install python-dotenv        # optional, for .env loading

# Verify the install
python3 -c "import claude_agent_sdk; print(claude_agent_sdk.__file__)"

You can confirm you’re on the current release by checking the claude-agent-sdk project page on PyPI directly — it lists the exact version history alongside release dates, which is useful if a tutorial you’re following references a method that doesn’t exist in your installed version yet.

# TypeScript/Node.js setup
mkdir claude-agent-project && cd claude-agent-project
npm init -y
npm pkg set type=module
npm install @anthropic-ai/claude-agent-sdk
npm install --save-dev tsx typescript @types/node

Installing the Python package pulls in the Claude Code CLI binary automatically, so you don’t need a separate global install unless you also want the interactive terminal tool. If pip install fails with a build error, it’s almost always the Python version check — confirm python3 --version reports 3.10 or higher before filing a bug.

Step 3: Write Your First Agent With query()

The query() function is the simplest entry point in the Claude Agent SDK. You pass a prompt and an options object, and you get back an async stream of messages as Claude reasons and, if you’ve enabled tools, calls them. There’s no session state to manage: every call to query() starts fresh.

import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions

async def main():
    options = ClaudeAgentOptions(
        system_prompt="You are an expert Python developer",
        permission_mode="acceptEdits",
    )

    async for message in query(prompt="Create a Python web server", options=options):
        print(message)

asyncio.run(main())

Run that script and you’ll see a stream of message objects print to your terminal: text blocks as Claude reasons, tool-use blocks when it decides to write a file, and a final result message with token usage. This is the pattern used across nearly every Claude Agent SDK tutorial you’ll find, because it’s the fastest way to confirm your install and API key both work before adding complexity. The full field-by-field reference for every option on ClaudeAgentOptions lives in Anthropic’s official Python SDK documentation, which is worth bookmarking since the options object grows as you move through the rest of this tutorial.

One detail that trips up developers coming from raw API usage: message objects here aren’t plain dictionaries, they’re typed classes like SystemMessage, AssistantMessage, UserMessage, and ResultMessage. Pattern-matching on isinstance(), as the examples throughout this tutorial do, is the idiomatic way to branch your handling logic instead of poking around in dictionary keys that may or may not exist depending on the message type.

Output Example

SystemMessage(subtype='init', data={'model': 'claude-sonnet-4-6', 'cwd': '/home/user/project'})
AssistantMessage(content=[TextBlock(text="I'll create a simple Python web server using Flask...")])
AssistantMessage(content=[ToolUseBlock(name='Write', input={'file_path': 'server.py', 'content': '...'})])
UserMessage(content=[ToolResultBlock(content='File created successfully')])
AssistantMessage(content=[TextBlock(text="Done. I created server.py with a basic Flask app...")])
ResultMessage(subtype='success', total_cost_usd=0.0142, num_turns=3, duration_ms=8421)

Step 4: Choose a Model — Opus 4.8 vs Sonnet 4.6 vs Haiku 4.5

The Claude Agent SDK doesn’t lock you into one model. You set it through the model field on ClaudeAgentOptions, and you can even override the model per subagent, which matters once you start delegating work in Step 9. As of August 2026, Anthropic’s current lineup is Claude Opus 4.8, Sonnet 4.6, and Haiku 4.5, and pricing published on Anthropic’s pricing page breaks down like this:

ModelInput (per MTok)Output (per MTok)Prompt Cache WritePrompt Cache ReadBest For
Claude Opus 4.8$5.00$25.00$6.25$0.50Complex multi-step agents, code review, planning
Claude Sonnet 4.6$3.00$15.00$3.75$0.30Default agent workhorse, balanced cost/quality
Claude Haiku 4.5$1.00$5.00$1.25$0.10High-volume subagents, simple lookups, fast loops

Prompt caching matters more with agent loops than with one-shot chat, because every turn resends the system prompt, tool definitions, and prior conversation. A cache read on Haiku 4.5 costs $0.10 per million tokens versus $1.00 for a fresh read, a 10x difference that adds up fast once an agent runs a dozen tool calls in a single task. Note also that Anthropic prices US-only inference at a 1.1x premium over standard pricing for workloads that must stay in-region, and batch processing (for non-interactive workloads) runs at roughly half the price shown above.

For most agents built with the SDK, Sonnet 4.6 is the practical default: cheap enough to run long tool-calling loops, capable enough to plan multi-step tasks without constant hand-holding. Reserve Opus 4.8 for the reasoning-heavy subagent in a multi-agent pipeline (see Step 9) and drop to Haiku 4.5 for narrow, repetitive subtasks like classifying a file or summarizing a single search result. Full, current pricing including batch and prompt-caching rates for every published model is always available on Anthropic’s official pricing page, which is worth checking before you commit a cost estimate to a client or a budget line, since per-token rates do shift as new model generations ship.

Step 5: Control Tool Access With Permission Modes

An agent that can run shell commands and edit files is only as safe as the permission system wrapped around it. The Claude Agent SDK’s Python reference documents six permission mode values on ClaudeAgentOptions.permission_mode:

ModeBehaviorWhen To Use
defaultStandard permission prompts for risky actionsLocal development, first-time testing
acceptEditsAuto-accepts file edits, still prompts elsewhereTrusted codebases, rapid iteration
planExplores and reasons without editing anythingRead-only audits, dry runs before a real edit pass
dontAskDenies anything not explicitly pre-approvedUnattended batch jobs where surprises are unacceptable
bypassPermissionsSkips permission checks entirelyFully sandboxed containers only — never on a real filesystem
autoA model classifier approves or denies each callSemi-trusted environments needing judgment calls
from claude_agent_sdk import ClaudeAgentOptions

# Read-only audit: the agent can look but not touch
audit_options = ClaudeAgentOptions(
    permission_mode="plan",
    allowed_tools=["Read", "Grep", "Glob"],
)

# Restrict tools directly for extra safety on top of the permission mode
options = ClaudeAgentOptions(
    permission_mode="acceptEdits",
    allowed_tools=["Read", "Write", "Edit", "Grep", "Glob"],
    disallowed_tools=["Bash"],   # no shell access at all
    cwd="/path/to/your/project",
)

bypassPermissions is tempting during development because it stops interrupting you, but treat it as a container-only setting. Running it against a real filesystem with shell access enabled means Claude can execute any command the SDK’s underlying process is allowed to run, with nothing standing between a bad instruction and rm -rf.

Step 6: Hold Multi-Turn Conversations With ClaudeSDKClient

query() is stateless — every call starts a new conversation. For an agent that needs to remember earlier turns, like a chatbot or an interactive debugging session, use ClaudeSDKClient instead. It also unlocks hooks, which query() alone does not support.

import asyncio
from claude_agent_sdk import ClaudeSDKClient, AssistantMessage, TextBlock

async def main():
    async with ClaudeSDKClient() as client:
        await client.query("What's the capital of France?")
        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}")

        # Follow-up in the same session — context is retained
        await client.query("What's the population of that city?")
        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}")

asyncio.run(main())

You can also switch permission modes mid-session by calling client.set_permission_mode(), which is useful when an agent starts in plan mode to scope out a task, then flips to acceptEdits once you’ve reviewed its plan and want it to actually make changes.

Step 7: Add Custom Tools With an In-Process MCP Server

Beyond the built-in tools — Read, Write, Edit, Glob, Grep, Bash, WebSearch, WebFetch, and AskUserQuestion — you’ll usually need domain-specific tools: hit an internal API, query a database, call a calculator. The SDK lets you define these as an in-process MCP server without running a separate process, using the @tool decorator and create_sdk_mcp_server().

from claude_agent_sdk import tool, create_sdk_mcp_server, ClaudeAgentOptions, query

@tool("add", "Add two numbers", {"a": float, "b": float})
async def add(args):
    return {"content": [{"type": "text", "text": f"Sum: {args['a'] + args['b']}"}]}

@tool("multiply", "Multiply two numbers", {"a": float, "b": float})
async def multiply(args):
    return {"content": [{"type": "text", "text": f"Product: {args['a'] * args['b']}"}]}

calculator = create_sdk_mcp_server(
    name="calculator",
    version="2.0.0",
    tools=[add, multiply],
)

options = ClaudeAgentOptions(
    mcp_servers={"calc": calculator},
    allowed_tools=["mcp__calc__add", "mcp__calc__multiply"],
)

async for message in query(prompt="What is 5 + 3?", options=options):
    print(message)

Notice the tool naming convention: mcp__<server_name>__<tool_name>. That prefix is how the permission system and the model distinguish your custom tools from built-ins and from tools exposed by other MCP servers you’ve connected. If you’ve already built a standalone MCP server for a different client, you can point mcp_servers at it over stdio or HTTP instead of defining tools in-process — the SDK supports both patterns.

Step 8: Block Dangerous Commands With Hooks

Hooks intercept events in the agent loop and let you allow, deny, or modify what happens next. They require ClaudeSDKClient — the stateless query() function doesn’t support them. The full set of hook events includes PreToolUse, PostToolUse, PostToolUseFailure, UserPromptSubmit, Stop, SubagentStop, PreCompact, Notification, SubagentStart, and PermissionRequest.

from claude_agent_sdk import ClaudeAgentOptions, query

async def main():
    def pre_tool_use_hook(context):
        # Intercept every tool call before it executes
        if context.tool_name == "Bash" and "rm" in context.input.get("command", ""):
            return {"behavior": "deny"}
        return {"behavior": "allow"}

    options = ClaudeAgentOptions(
        hooks={
            "pre-tool-use": [
                {"type": "sync", "handler": pre_tool_use_hook}
            ]
        }
    )

    async for message in query(prompt="List files", options=options):
        print(message)

This is the layer that separates a toy demo from something you’d trust with write access to a real repository. A PreToolUse hook checking for destructive shell patterns, combined with disallowed_tools and a scoped-down cwd, gives you three independent layers of defense instead of relying on the model’s judgment alone.

Step 9: Delegate Work to Subagents

Subagents are separate agent instances your main agent can spawn for focused subtasks. They’re useful for context isolation — a subagent doesn’t inherit the parent’s entire conversation history — as well as for running work in parallel, applying specialized instructions, or restricting which tools a given subtask can touch. You define them through the agents field on ClaudeAgentOptions, using AgentDefinition.

from claude_agent_sdk import AgentDefinition, ClaudeAgentOptions, query

options = ClaudeAgentOptions(
    agents={
        "code-reviewer": AgentDefinition(
            description="Reviews code changes",
            prompt="You are a code reviewer. Report issues in the diff.",
            tools=["Read", "Grep"],
            model="opus",       # override the model for this subagent only
            max_turns=5,
            permission_mode="plan",
        )
    }
)

A common production pattern: run the main agent loop on Sonnet 4.6 for cost, but define a code-reviewer subagent pinned to Opus 4.8 for the step that actually needs deeper reasoning, and a summarizer subagent pinned to Haiku 4.5 for cheap, repetitive text condensing. Each subagent gets its own max_turns ceiling too, so a runaway loop in one subtask can’t burn through your entire budget.

Step 10: Build the Complete Project — A Repo Audit Agent

Here’s a full working project that ties every concept above together: an agent that reads a local codebase, greps for common issues (bare except blocks, hardcoded secrets, TODO comments), and writes a structured Markdown report. It runs read-only by default using plan mode, uses a Haiku 4.5 subagent to summarize findings cheaply, and logs the total cost of the run.

Project Structure

repo-audit-agent/
├── .env                  # ANTHROPIC_API_KEY=sk-ant-...
├── venv/
├── requirements.txt      # claude-agent-sdk, python-dotenv
└── audit.py              # the agent itself

Full Code: audit.py

import asyncio
import os
import sys
from dotenv import load_dotenv
from claude_agent_sdk import (
    query,
    ClaudeAgentOptions,
    AgentDefinition,
    AssistantMessage,
    TextBlock,
    ResultMessage,
)

load_dotenv()

def build_options(target_dir: str) -> ClaudeAgentOptions:
    return ClaudeAgentOptions(
        system_prompt=(
            "You are a senior code auditor. Scan the target repository for "
            "bare except blocks, hardcoded secrets or API keys, TODO/FIXME "
            "comments, and files over 500 lines. Use the summarizer subagent "
            "to condense findings from any file over 200 lines before "
            "including them in your report. Write the final report to "
            "audit_report.md in Markdown with a table of findings."
        ),
        cwd=target_dir,
        model="claude-sonnet-4-6",
        permission_mode="plan",
        allowed_tools=["Read", "Grep", "Glob", "Write"],
        max_turns=25,
        agents={
            "summarizer": AgentDefinition(
                description="Condenses long file findings into 2-3 sentences",
                prompt="Summarize the security or quality issue in 2-3 sentences. Be specific about line numbers.",
                tools=["Read"],
                model="claude-haiku-4-5-20251001",
                max_turns=3,
            )
        },
    )

async def run_audit(target_dir: str):
    options = build_options(target_dir)
    total_cost = 0.0

    async for message in query(prompt=f"Audit the codebase at {target_dir}", options=options):
        if isinstance(message, AssistantMessage):
            for block in message.content:
                if isinstance(block, TextBlock):
                    print(block.text)
        elif isinstance(message, ResultMessage):
            total_cost = message.total_cost_usd
            print(f"\n--- Run complete in {message.num_turns} turns ---")

    print(f"Total cost: ${total_cost:.4f}")
    print("Report written to audit_report.md")

if __name__ == "__main__":
    target = sys.argv[1] if len(sys.argv) > 1 else "."
    asyncio.run(run_audit(os.path.abspath(target)))

Running It and Sample Output

$ pip install claude-agent-sdk python-dotenv
$ python3 audit.py ./my-flask-app

I'll scan the repository for the issues you specified...
Found 3 bare except blocks in app/routes.py (lines 45, 112, 203)
Found 1 potential hardcoded secret in config.py (line 12)
Delegating summary of app/models.py (312 lines) to summarizer subagent...
Found 7 TODO comments across 4 files
Writing report to audit_report.md...

--- Run complete in 14 turns ---
Total cost: $0.0387
Report written to audit_report.md

Because permission_mode is set to plan and Bash isn’t in allowed_tools, this agent physically cannot modify or delete anything in the target repository, no matter what a prompt injection buried in a source file tries to convince it to do. That’s the pattern worth copying for any agent that touches code you didn’t write yourself.

Step 11: Ship a TypeScript Version

If your stack is Node instead of Python, the API maps closely. The TypeScript package is @anthropic-ai/claude-agent-sdk, currently at version 0.3.233 on npm, and it exposes the same query() function with a nearly identical options object.

import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({
  prompt: "List three capabilities of the Claude Agent SDK.",
  options: {
    permissionMode: "plan",
    allowedTools: ["Read", "Grep", "Glob"],
    model: "claude-sonnet-4-6",
  },
})) {
  console.log(message);
}

The TypeScript SDK also supports streaming input — passing an async iterable instead of a static string as the prompt — which is the pattern to reach for if you’re building a chat UI where the user can type follow-ups while the agent is still working on the first request. Anthropic maintains the TypeScript package’s source and issue tracker on GitHub at anthropics/claude-agent-sdk-typescript, which is the fastest place to check whether a bug you’ve hit is already known before you spend an afternoon debugging your own code.

import { query } from "@anthropic-ai/claude-agent-sdk";

const streamInput = async function* () {
  yield { type: "text", text: "First prompt" };
  yield { type: "text", text: "Follow-up prompt" };
};

for await (const message of query({ prompt: streamInput() })) {
  console.log(message);
}

Step 12: Deploy, Monitor, and Control Cost in Production

A script that runs once on your laptop is different from an agent running unattended in production. Before you deploy, wire in three things: a hard max_turns ceiling on every agent and subagent so a reasoning loop can’t run forever, a logging hook on PostToolUse that writes every tool call to your observability stack, and a cost check against ResultMessage.total_cost_usd after every run so a misbehaving prompt can’t silently rack up a five-figure API bill overnight. Run agents that touch the filesystem or shell inside a container or VM, not on a host with access to anything you’d mind losing, and default new deployments to dontAsk or a tightly scoped allowed_tools list rather than bypassPermissions.

Common Pitfalls When Building With the Claude Agent SDK

  • Using bypassPermissions outside a sandbox. It’s the fastest way to stop permission prompts during development, and also the fastest way to give a hallucinated tool call full shell access to your real machine. Keep it inside disposable containers only.
  • Reaching for hooks with query() instead of ClaudeSDKClient. Hooks silently do nothing under query() — they require ClaudeSDKClient. If your PreToolUse hook never fires, this is almost always why.
  • Forgetting the mcp__server__tool naming convention. Custom tools registered through create_sdk_mcp_server() won’t be callable unless you list them in allowed_tools using the full mcp__<server>__<tool> prefix, not just the bare tool name.
  • Running every subagent on Opus 4.8 by default. At $25 per million output tokens, an audit or summarization subagent that could run on Haiku 4.5 for a fifth of the cost adds up fast across hundreds of runs. Set model per-agent deliberately.
  • No max_turns ceiling. An agent stuck in a retry loop against a flaky tool will keep calling it turn after turn unless you cap max_turns on both the main agent and every subagent definition.
  • Skipping the .env load order. If you call load_dotenv() after importing claude_agent_sdk and the SDK reads the API key at import time in your framework, the key can end up empty. Load environment variables before any SDK import.

Troubleshooting: Errors You’ll Hit and How to Fix Them

  • “ANTHROPIC_API_KEY not set” on startup. Confirm the variable is exported in your current shell session with echo $ANTHROPIC_API_KEY, or that load_dotenv() runs before you construct any SDK objects.
  • ImportError on claude_agent_sdk after a clean install. You’re almost certainly running Python under 3.10. Run python3 --version and recreate your virtual environment with a supported interpreter.
  • Tool calls silently fail with no error message. Check that the tool name is actually in allowed_tools — a mismatch between what you registered and what you allowed fails quietly rather than raising.
  • Hooks never trigger. You’re using query() instead of ClaudeSDKClient. Switch to the client class, since hooks require the stateful session.
  • Rate limit errors (429) mid-run. Long agent loops with many tool calls can burn through your requests-per-minute limit fast. Add exponential backoff around your query() or client calls, or request a rate limit increase in the Anthropic Console if this happens regularly in production.
  • Permission denied on Bash tool calls. Under default or dontAsk mode, shell commands need explicit approval or a pre-approved allowlist. Either switch modes for testing or add the specific command pattern to your approval logic.
  • MCP server tools not appearing in the tool list. Double-check the server is actually registered under mcp_servers with a matching key, and that your @tool decorator’s input schema is a valid dict of field names to types — a malformed schema causes the tool to be silently dropped from the available set.
  • Node.js version errors when installing the TypeScript package. The SDK requires Node 18+; older LTS versions will fail on ESM import syntax. Run node --version and upgrade via nvm if needed.
  • Unexpectedly high API costs after a run. Check whether prompt caching is actually hitting — a system prompt or tool definition that changes slightly between calls invalidates the cache and forces a full-price read every time. Keep static content, like tool schemas, byte-for-byte identical across calls.
  • Subagent doesn’t use the model you specified. Confirm the model field is set inside the specific AgentDefinition, not just on the parent ClaudeAgentOptions — the parent’s model setting does not automatically cascade to every subagent alias.

Advanced Tips for Production-Grade Claude Agents

Once the basics are working, a few patterns separate a demo from something you’d trust running unattended. First, treat plan mode as a first-class production feature, not just a testing convenience: have the agent produce a plan, log or surface it for human review, then re-invoke with acceptEdits only after approval. Second, batch non-interactive workloads through Anthropic’s batch processing tier for roughly half the standard per-token price when the task doesn’t need a live response. Third, chain subagents deliberately by cost tier — cheap Haiku 4.5 pass for triage and filtering, Sonnet 4.6 for the bulk of the work, Opus 4.8 reserved for the specific step that needs the deepest reasoning — rather than running the entire pipeline on one model.

Fourth, use PostToolUse and PostToolUseFailure hooks to build a full audit trail of every action an agent took, independent of whatever the model reports in its own final summary — this is what makes an incident review possible after something goes wrong. Fifth, if you’re comparing the SDK against building directly on OpenAI’s equivalent tooling, our OpenAI Agents SDK tutorial walks the same territory from the other side, and it’s worth prototyping both before locking in an architecture, since switching cost patterns differ meaningfully between the two ecosystems once you’re running dozens of subagent calls per task.

What Your Agent Will Actually Cost

Cost in an agent loop scales with turns, not just output length, because every turn resends context. A simple single-file audit running 10-15 turns on Sonnet 4.6 typically lands under $0.05 per run once prompt caching is working correctly, based on the pricing shown in Step 4. The same task on Opus 4.8 without caching can run 5-8x higher, which is exactly why the subagent cost-tiering pattern in the advanced tips section matters at any real scale — a difference that’s invisible on one test run and very visible on ten thousand.

Developer adoption data backs up why this cost discipline matters: Stack Overflow’s 2025 Developer Survey found that 31% of developers are currently using AI agents, while 17% plan to use them, and among developers who have used agents at work, 69% agree they’ve increased productivity. That same survey also found that 52% of developers either don’t use AI agents or prefer simpler AI tools, and 38% say they have no plans to adopt agents at all — a reminder that agent adoption is real but far from universal, and that the added complexity of a full agent loop (versus a simple chat completion) needs to earn its keep on a given task rather than being reached for by default.

That split matters when you’re deciding whether a project even needs the Agent SDK. A task that’s genuinely one-shot — summarize this document, classify this ticket — is usually cheaper and simpler as a direct API call with no tool loop at all. The SDK earns its cost and complexity on tasks that need multiple rounds of file access, command execution, or tool calls chained together, where the alternative is writing and maintaining that orchestration logic yourself.

Frequently Asked Questions

Is the Claude Agent SDK free to use?

The SDK packages themselves — claude-agent-sdk on PyPI and @anthropic-ai/claude-agent-sdk on npm — are free and open source. You pay standard Anthropic API rates for the underlying model calls, starting at $1 per million input tokens on Haiku 4.5.

What’s the difference between the Claude Agent SDK and Claude Code?

Claude Code is the interactive CLI tool you run in a terminal. The Agent SDK is the programmable library version of the same underlying harness, meant to be embedded inside your own application rather than used directly by a human.

Can I use the Claude Agent SDK with Amazon Bedrock or Google Vertex AI?

The officially documented authentication path is a direct Anthropic API key via ANTHROPIC_API_KEY. Check Anthropic’s current documentation before assuming Bedrock or Vertex AI credentials work as a drop-in substitute, since support and configuration details can change between SDK releases.

Does the Claude Agent SDK support languages other than Python and TypeScript?

Anthropic officially maintains and publishes Python and TypeScript/Node.js packages. Community wrappers exist for other ecosystems, but they aren’t Anthropic-maintained, so expect a lag before new SDK features reach them.

How is the Claude Agent SDK different from Claude Managed Agents?

The Agent SDK runs the harness inside your own infrastructure — you manage the process, the sandbox, and the deployment. Claude Managed Agents, launched in April 2026, is Anthropic’s hosted alternative where Anthropic runs the sandbox and you integrate over REST instead of self-hosting.

Which Claude model should I use for a Claude Agent SDK project?

Sonnet 4.6 is the practical default for most agent loops, balancing cost and reasoning quality at $3/$15 per million input/output tokens. Reserve Opus 4.8 for subagents doing the heaviest reasoning, and use Haiku 4.5 for cheap, high-volume subtasks.

Can an agent built with the SDK edit files without my approval?

Only if you set permission_mode to acceptEdits or bypassPermissions. The default and plan modes require explicit approval or block edits entirely, which is why testing new agents in plan mode first is standard practice.

Do I need to run a separate MCP server to add custom tools?

No. The SDK supports in-process MCP servers through create_sdk_mcp_server() and the @tool decorator, so you can define custom tools inside the same script without spinning up a separate MCP process. You can still connect to external, standalone MCP servers if you have them.

Related Coverage

Sofia Lindström

Sofia Lindström

Editor-in-Chief

Sofia Lindström is the Editor-in-Chief at Tech Insider, where she leads editorial strategy and oversees coverage across AI, cybersecurity, and enterprise technology. With over a decade in Swedish tech journalism, she previously served as technology editor at Dagens Industri and covered the Nordic startup ecosystem for Breakit. Sofia holds an MSc in Media Technology from KTH Royal Institute of Technology and is a frequent speaker at Web Summit and Slush. She is passionate about making complex technology accessible to business leaders.

View all articles