Most people meet the Claude Agent SDK as a package name in someone else's repo and have no idea what it is. Is it the API client? Is it Claude Code? Is it a framework? The answer is none of those, and the confusion costs people time, because the SDK is a different tool from each of them.
I went through the official docs and both GitHub repos to write this. Everything below is checked against Anthropic's documentation on October 23, 2026, and the sources are listed at the end. If you want the wider landscape first, my AI agent frameworks comparison covers how the SDK sits next to LangGraph, the Vercel AI SDK and others.
What Is the Claude Agent SDK?
The Claude Agent SDK is a library, available for Python and TypeScript, that gives your own application the agent loop, built-in tools, permissions and context management that power Claude Code. You pass a prompt and options to query(), and it streams back messages while Claude reads files, runs commands and edits code on its own.
That is the whole idea. Claude Code is the product you use in a terminal. The Agent SDK is the same engine, exposed as a library, so you can embed it in a script, a backend service or a CI job. Anthropic's own phrasing is "Claude Code as a library."
The SDK used to be called the Claude Code SDK. The GitHub README for the TypeScript package says the Claude Code SDK is now the Claude Agent SDK and points to a migration guide for the breaking changes. If you find an old tutorial that imports @anthropic-ai/claude-code, that is the old package. The current ones are named below.
Claude Agent SDK vs the Messages API vs Claude Code
These are three different ways to put Claude to work, and they differ in who runs the loop. Anthropic's overview page compares the Agent SDK, the CLI, the Client SDK and Managed Agents. Here is the version I use when a teammate asks which one to reach for:
| Messages API (Client SDK) | Claude Agent SDK | Claude Code CLI | |
|---|---|---|---|
| What it is | Direct access to the Claude API from your code | Claude Code's agent as a library for Python and TypeScript | The terminal interface for daily interactive use |
| Who runs the tool loop | You, or the client SDK's beta tool runner | The SDK, using the Claude Code agent loop | Claude Code itself |
| Built-in tools | None. You define every tool | File read, write and edit, shell commands, web search and more | The same built-in tools |
| Permissions, sessions, hooks | You build them | Included | Included |
| Where it runs | Anywhere you can call the API | A process you operate | Your terminal, or non-interactively with claude -p |
| Best for | Chat, extraction, classification, custom agent loops | Embedding a coding-capable agent in your own app | Interactive development and one-off tasks |
A fourth option exists. Managed Agents is a hosted agent harness where Anthropic runs the loop in a managed cloud sandbox, configured through the Claude API. The Agent SDK is the opposite end: the agent runs in your process, on your machine or your servers.
One detail from the docs is worth knowing. The SDK is not a thin wrapper around HTTP calls. Both packages bundle a native Claude Code binary, and the SDK drives it. That is why you get Claude Code's exact behavior, and also why a few install setups need extra care (more on that in the install section).
How to Install the Claude Agent SDK
There are two packages, one per language. Both need an Anthropic API key.
| TypeScript | Python | |
|---|---|---|
| Package | @anthropic-ai/claude-agent-sdk | claude-agent-sdk |
| Install | npm install @anthropic-ai/claude-agent-sdk | pip install claude-agent-sdk or uv add claude-agent-sdk |
| Runtime | Node.js 18 or later | Python 3.10 or later |
| Version when I checked | 0.3.308 on npm | 0.2.172 on PyPI |
| Source | anthropics/claude-agent-sdk-typescript | anthropics/claude-agent-sdk-python |
Both are 0.x versions, so expect the API to keep moving. Pin the version in your lockfile and read the changelog in each repo before you upgrade.
For a new TypeScript project, the quickstart uses this setup:
mkdir my-agent
cd my-agent
npm init -y
npm pkg set type=module
npm install @anthropic-ai/claude-agent-sdk
npm install --save-dev tsxSetting "type": "module" lets the script use top-level await, and tsx runs TypeScript files directly. If your existing project uses CommonJS, name the script agent.mts instead.
Then set your key in the shell where the agent will run:
export ANTHROPIC_API_KEY=your-api-keyThe SDK reads the key from the process environment. It does not load .env files for you, so load them yourself with something like dotenv if that is where your key lives. The SDK also supports Amazon Bedrock (CLAUDE_CODE_USE_BEDROCK=1), Google Cloud (CLAUDE_CODE_USE_VERTEX=1) and Microsoft Foundry (CLAUDE_CODE_USE_FOUNDRY=1), each with its own cloud credentials.
Two install caveats from the docs. If pip installs the Python source distribution instead of a platform wheel (ARM64 Windows is the example given), no binary is bundled, and you need to install Claude Code natively so the SDK can find it on your PATH. On the TypeScript side, the binary arrives through npm optional dependencies, so npm ci --omit=optional leaves you without one. Reinstall without that flag, or point pathToClaudeCodeExecutable at a native install.
Build a Minimal Claude Agent in TypeScript
This is the quickstart agent. It reviews a file for crash bugs and fixes them. Create a utils.py with two obvious bugs first, since that is the file the agent will edit:
def calculate_average(numbers):
total = 0
for num in numbers:
total += num
return total / len(numbers)
def get_user_name(user):
return user["name"].upper()calculate_average([]) divides by zero and get_user_name(None) raises a TypeError. Now the agent, in agent.ts:
import { query } from "@anthropic-ai/claude-agent-sdk";
// Agentic loop: streams messages as Claude works
for await (const message of query({
prompt: "Review utils.py for bugs that would cause crashes. Fix any issues you find.",
options: {
allowedTools: ["Read", "Edit", "Glob"], // Auto-approve these tools
permissionMode: "acceptEdits" // Auto-approve file edits
}
})) {
// Print human-readable output
if (message.type === "assistant" && message.message?.content) {
for (const block of message.message.content) {
if ("text" in block) {
console.log(block.text); // Claude's reasoning
} else if ("name" in block) {
console.log(`Tool: ${block.name}`); // Tool being called
}
}
} else if (message.type === "result") {
console.log(`Done: ${message.subtype}`); // Final result
}
}Run it with npx tsx agent.ts. You should see the agent's reasoning and each tool it calls, ending with Done: success, and utils.py will have guards for the empty list and the null user.
Three things are happening in that file:
query()is the entry point. It returns an async iterator, and each iteration yields one message: Claude's reasoning, a tool call, a tool result or the final outcome.promptis the task. You do not tell Claude which tools to use. It picks them based on the task.optionsconfigures the agent. Here,allowedToolspre-approves three tools andpermissionMode: "acceptEdits"approves file edits.
The loop ends when Claude finishes the task or hits an error. The SDK handles orchestration, tool execution, context management and retries, so your code only consumes the stream. If you do not need live output, for example in a background job, you can collect all messages at once instead.
Build the Same Agent in Python
The Python version of the same quickstart agent uses ClaudeAgentOptions and the message classes:
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage, ResultMessage
async def main():
# Agentic loop: streams messages as Claude works
async for message in query(
prompt="Review utils.py for bugs that would cause crashes. Fix any issues you find.",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Edit", "Glob"], # Auto-approve these tools
permission_mode="acceptEdits", # Auto-approve file edits
),
):
# Print human-readable output
if isinstance(message, AssistantMessage):
for block in message.content:
if hasattr(block, "text"):
print(block.text) # Claude's reasoning
elif hasattr(block, "name"):
print(f"Tool: {block.name}") # Tool being called
elif isinstance(message, ResultMessage):
print(f"Done: {message.subtype}") # Final result
asyncio.run(main())Run it with python agent.py (or uv run agent.py). The shape matches the TypeScript one, with snake_case option names. For multi-turn conversations, bidirectional streaming, custom tools and hooks in Python, the repo also offers ClaudeSDKClient, which you use as an async context manager and talk to with client.query(...) followed by client.receive_response().
Tools and Permissions in the Claude Agent SDK
The built-in tools are the same ones Claude Code uses: reading, writing and editing files, running commands, searching and web access. The quickstart groups the common combinations like this:
| Tools | What the agent can do |
|---|---|
Read, Glob, Grep | Read-only analysis |
Read, Edit, Glob | Analyze and modify code |
Read, Edit, Bash, Glob, Grep | Full automation |
The part people get wrong is what allowedTools actually does. It is not an allowlist of which tools exist. It is a permission rule list: the tools you name are auto-approved. Any tool you leave out is still available to Claude, and a call to it that needs approval falls through to the permission mode and your canUseTool callback. To remove a tool from Claude's context entirely, put its bare name in disallowedTools. A scoped rule such as Bash(rm *) leaves Bash available but denies matching calls, in every mode.
The docs describe a fixed evaluation order for each tool request: hooks first, then deny rules, then ask rules, then the permission mode, then allow rules, and finally the canUseTool callback. A deny rule wins even in bypassPermissions mode.
The SDK supports six permission modes:
| Mode | What it does |
|---|---|
default | No mode-based auto-approvals. Calls that need approval and match no allow rule go to your canUseTool callback |
dontAsk | Denies anything that would prompt, without calling canUseTool |
acceptEdits | Auto-approves file edits and filesystem commands like mkdir, touch, rm, mv, cp and sed inside the working directory |
bypassPermissions | Tools run without prompts, apart from a few actions no mode auto-approves. Use with caution |
plan | Claude explores and plans without editing your source files |
auto | A classifier model reviews actions such as shell commands and network requests and allows or blocks each one |
For a locked-down read-only agent, the docs suggest pairing allowedTools with dontAsk:
const options = {
allowedTools: ["Read", "Glob", "Grep"],
permissionMode: "dontAsk"
};One warning from the docs deserves repeating. allowedTools does not constrain bypassPermissions. If you set allowedTools: ["Read"] with permissionMode: "bypassPermissions", every tool is still approved, including Bash, Write and Edit. If you need bypass mode but want specific tools blocked, use disallowedTools. I wrote up the wider least-privilege approach, including the --dangerously-skip-permissions flag in the CLI, in coding agent permissions and least privilege.
Also note that the SDK now starts in default mode unless you set a mode or your settings files do. In default mode with no way to approve, a tool call that needs approval is denied. If your first agent run reports denied tool calls, that is the usual reason, and the fix is an allow rule or a canUseTool callback, not bypass mode.
Add MCP Servers and Custom Tools
The SDK speaks the Model Context Protocol, so your agent can use any MCP server. You pass servers in the mcpServers option. The docs show stdio servers (a command to run), HTTP and SSE servers (a URL), and in-process SDK servers (tools defined in your own code). This example connects to the Claude Code docs MCP server over HTTP:
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "Use the docs MCP server to explain what hooks are in Claude Code",
options: {
mcpServers: {
"claude-code-docs": {
type: "http",
url: "https://code.claude.com/docs/mcp"
}
},
allowedTools: ["mcp__claude-code-docs__*"]
}
})) {
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}MCP tools are named mcp__<server-name>__<tool-name>, and they need explicit permission before Claude can call them. The wildcard in allowedTools grants every tool from one server and nothing else. The docs recommend this over broad permission modes: acceptEdits does not auto-approve MCP tools, and bypassPermissions approves them but also switches off most other safety prompts.
If you would rather write your own tools than run a separate server, define them with tool() and wrap them in createSdkMcpServer(). The server runs in-process inside your application. This is the docs' own example, trimmed to one tool:
import { tool, createSdkMcpServer, query } from "@anthropic-ai/claude-agent-sdk";
import { z } from "zod";
const getTemperature = tool(
"get_temperature",
"Get the current temperature at a location",
{
latitude: z.number().describe("Latitude coordinate"),
longitude: z.number().describe("Longitude coordinate")
},
async (args) => {
const response = await fetch(
`https://api.open-meteo.com/v1/forecast?latitude=${args.latitude}&longitude=${args.longitude}¤t=temperature_2m&temperature_unit=fahrenheit`
);
const data: any = await response.json();
return {
content: [{ type: "text", text: `Temperature: ${data.current.temperature_2m}°F` }]
};
}
);
const weatherServer = createSdkMcpServer({
name: "weather",
version: "1.0.0",
tools: [getTemperature]
});
for await (const message of query({
prompt: "What's the temperature in San Francisco?",
options: {
mcpServers: { weather: weatherServer },
allowedTools: ["mcp__weather__get_temperature"]
}
})) {
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}A tool has four parts: a name, a description Claude reads to decide when to call it, an input schema (a Zod schema in TypeScript) and an async handler that returns a content array. Return isError: true when something fails so Claude can react to it instead of treating an error as data. If you are building a standalone server rather than an in-process one, my guide to building an MCP server in TypeScript covers that path, and the same tool design rules apply to both.
Subagents in the Claude Agent SDK
Subagents are separate agent instances your main agent can spawn for a focused subtask. The docs list four reasons to use them: context isolation (only the subagent's final message returns to the parent), parallelization, specialized instructions, and tool restrictions.
You define them programmatically with the agents option, and Claude invokes them through the Agent tool, so Agent has to be reachable in your session. This version is trimmed from the docs:
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "Review the authentication module for security issues",
options: {
allowedTools: ["Read", "Grep", "Glob", "Agent"],
agents: {
"code-reviewer": {
description:
"Expert code review specialist. Use for quality, security, and maintainability reviews.",
prompt: "You are a code review specialist. Identify security vulnerabilities and suggest specific improvements.",
tools: ["Read", "Grep", "Glob"],
model: "sonnet"
}
}
}
})) {
if ("result" in message) console.log(message.result);
}description and prompt are required. tools, model and several other fields are optional. If you omit tools, the subagent inherits every tool available to subagents, so list them explicitly when you want a read-only reviewer. The description is what Claude uses to decide when to delegate, and if it keeps answering directly instead, name the subagent in your prompt.
Three details are easy to miss. A subagent starts with a fresh context: it does not see the parent's conversation, so put file paths and decisions in the prompt you hand it. A subagent runs in the parent's permission mode, and if the parent is in bypassPermissions, the subagent is too. And a subagent can spawn subagents of its own, so one prompt can grow into a tree. The docs describe three caps: CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH (default 3), CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS (default 20) and a maxBudgetUsd option (TypeScript) or max_budget_usd (Python) for spend. I would set a budget on any agent that can delegate. For the Claude Code side of this feature, see my subagents guide.
Hooks in the Claude Agent SDK
Hooks are callback functions that run your code at points in the agent lifecycle. They are the right place for checks that must run on every tool call, because hooks run before every other step in the permission flow, and a hook deny applies even in bypassPermissions mode.
This example blocks writes to .env files:
import { query, HookCallback, PreToolUseHookInput } from "@anthropic-ai/claude-agent-sdk";
const protectEnvFiles: HookCallback = async (input, toolUseID, { signal }) => {
const preInput = input as PreToolUseHookInput;
const toolInput = preInput.tool_input as Record<string, unknown>;
const filePath = toolInput?.file_path as string;
const fileName = filePath?.split("/").pop();
if (fileName?.toLowerCase() === ".env") {
return {
hookSpecificOutput: {
hookEventName: preInput.hook_event_name,
permissionDecision: "deny",
permissionDecisionReason: "Cannot modify .env files"
}
};
}
return {};
};
for await (const message of query({
prompt: "Create a .env file with the standard local development database configuration",
options: {
hooks: {
PreToolUse: [{ matcher: "Write|Edit", hooks: [protectEnvFiles] }]
}
}
})) {
if (message.type === "assistant" || message.type === "result") {
console.log(message);
}
}The matcher filters by tool name only, not by file path, which is why the path check lives inside the callback. Returning {} allows the operation. A PreToolUse hook can also rewrite a tool's input with updatedInput.
The same example shows a real limit. The Write|Edit matcher does not stop Claude from writing .env through a Bash command, because the hook never runs for that tool. The docs point to the sandbox configuration for blocking Bash writes.
Available events include PreToolUse, PostToolUse, PostToolUseFailure, UserPromptSubmit, Stop, SubagentStart, SubagentStop, PreCompact, PermissionRequest and Notification in both SDKs. Many others, including SessionStart and SessionEnd, are TypeScript only. If you also use shell command hooks in Claude Code, the hooks guide covers that side. SDK callbacks use the same JSON output format as those shell hooks.
When to Use the Agent SDK, the Messages API or claude -p
Here is how I decide, using the distinctions from the docs.
Use the Messages API (Client SDK) when you want the model to produce an answer, not take actions on a machine. Chat, extraction, classification, summaries, and tool use where you control the loop and the tools. You write the tool loop yourself, or use the client SDK's beta tool runner. You get full control and nothing you did not ask for.
Use the Agent SDK when the task is "go do this in a codebase or a file system." Reading files, editing them, running tests, searching the web, delegating to subagents, with permissions and sessions already built. You are embedding Claude Code's agent in a Python or TypeScript process that you operate.
Use claude -p when you want the same agent from a shell script or a CI step, or from a language that is not Python or TypeScript. The overview says to run the CLI as a subprocess with -p and --output-format json to drive the same agent loop from another language. A minimal call looks like this:
claude -p "Find and fix the bug in auth.py" --allowedTools "Read,Edit,Bash"The headless docs also document --output-format json for structured results with a session ID and cost, --json-schema for schema-conforming output, and --continue and --resume for multi-step conversations. For CI, they recommend --bare, which skips auto-discovery of hooks, skills, plugins, MCP servers and CLAUDE.md so every machine behaves the same. The docs say --bare will become the default for -p in a future release.
If you are driving this from Node or Python and need structured outputs, tool approval callbacks and native message objects, the SDK is the better fit. If you need a one-line command in a pipeline, claude -p is. And if you want Anthropic to host the agent, that is Managed Agents, a different product.
Licensing and Branding Rules
Two rules in the overview matter if you plan to ship a product on top of the SDK. Unless previously approved, Anthropic does not allow third-party developers to offer claude.ai login or rate limits in their products, including agents built on the SDK. Use API key authentication instead. And branding: you may call your agent "Claude Agent" in a menu, or "YourAgentName Powered by Claude," but not "Claude Code" or "Claude Code Agent," and your product should not look like Claude Code. Use of the SDK is governed by Anthropic's Commercial Terms of Service.
Frequently Asked
What is the Claude Agent SDK? It is a Python and TypeScript library that runs Claude Code's agent loop, built-in tools, permissions, sessions and hooks inside your own application. You call query() with a prompt and options, and it streams messages as Claude works on the task.
What is the difference between the Claude SDK and the Claude Agent SDK? "Claude SDK" is a loose term. Anthropic's Client SDK gives you direct access to the Claude API, and you write the tool loop yourself. The Agent SDK runs the Claude Code agent loop for you, with built-in tools. If you searched for "Claude SDK" to build an autonomous agent, you want the Agent SDK. If you want plain API calls, you want the Client SDK.
How do I install the Claude Agent SDK? For TypeScript, run npm install @anthropic-ai/claude-agent-sdk (Node.js 18 or later). For Python, run pip install claude-agent-sdk or uv add claude-agent-sdk (Python 3.10 or later). Then set ANTHROPIC_API_KEY in your environment.
Is the Claude Agent SDK the same as Claude Code? It is the same agent engine, packaged differently. Claude Code is the terminal product for interactive work. The SDK is a library that lets you run that agent from your own code. Both packages bundle a native Claude Code binary.
Was the Claude Code SDK renamed? Yes. The Claude Code SDK is now the Claude Agent SDK, and the official repos point to a migration guide for the breaking changes. Older tutorials may use the previous package name.
Do I need an API key? Yes. The quickstart uses an Anthropic API key from the Claude Console. Amazon Bedrock, Google Cloud and Microsoft Foundry are supported through environment variables and their own credentials. Anthropic does not allow third-party products to offer claude.ai login for SDK agents unless previously approved.
Can the Claude Agent SDK use MCP servers? Yes. Pass servers in mcpServers as stdio, HTTP or SSE servers, or build in-process tools with createSdkMcpServer(). Grant access with allowedTools, using the mcp__<server>__<tool> naming and a wildcard for a whole server.
Does allowedTools restrict which tools Claude can use? No. It pre-approves the tools you list. Unlisted tools stay available, and calls to them fall through to the permission mode. To remove a tool entirely, add its bare name to disallowedTools.
Can I run the Agent SDK from another language? Not as a native package. The docs say to run the CLI as a subprocess with claude -p and --output-format json to drive the same agent loop from other languages.
Sources: Anthropic's Agent SDK documentation on the overview, quickstart, permissions, MCP, custom tools, subagents, hooks and running Claude Code programmatically; the TypeScript and Python SDK repositories; package versions from npm and PyPI, all checked October 23, 2026.