# Building Agents with the Claude Agent SDK

> A working tutorial for the Claude Agent SDK in TypeScript and Python — query(), tool permissions, custom in-process MCP tools, subagents, hooks, and auth.

The Claude Agent SDK is Claude Code as a library: npm install @anthropic-ai/claude-agent-sdk or pip install claude-agent-sdk, call query() with a prompt and options, and you get the full agent loop — file tools, command execution, permissions, MCP, subagents, hooks — streaming back as messages. It's the production path from 'Claude Code works for this' to 'this is a product.'

At some point "Claude Code handles this perfectly in my terminal" wants to become "this runs in my product / pipeline / Slack bot." The **Claude Agent SDK** is that path: the same engine — agent loop, built-in tools, permissions, MCP, subagents, hooks — as a TypeScript/Python library. You stop driving the agent and start shipping it.

## First agent in ten lines

**TypeScript:**

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

for await (const message of query({
  prompt: "Find and fix the bug in auth.ts",
  options: { allowedTools: ["Read", "Edit", "Bash"] },
})) {
  if ("result" in message) console.log(message.result);
}
```

**Python:**

```python
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions

async def main():
    async for message in query(
        prompt="Find and fix the bug in auth.py",
        options=ClaudeAgentOptions(allowed_tools=["Read", "Edit", "Bash"]),
    ):
        if hasattr(message, "result"):
            print(message.result)

asyncio.run(main())
```

Install with `npm install @anthropic-ai/claude-agent-sdk` (the package bundles the agent binary) or `pip install claude-agent-sdk` (Python 3.10+), export `ANTHROPIC_API_KEY`, and that code **runs the full loop**: the model plans, calls tools, reads their results, edits files, runs commands, and iterates — streaming every step back as messages you can render, log, or gate.

## The options that matter

`query()` takes one options object; these carry most real applications:

| Option | What it does |
| --- | --- |
| `allowedTools` / `disallowedTools` | The permission boundary — grant exactly what the task needs |
| `permissionMode` | `default`, `acceptEdits`, `plan`, `bypassPermissions` — same dial as Claude Code |
| `maxTurns` | Circuit breaker for runaway loops |
| `model` | Pin the model per agent |
| `systemPrompt` | Replace or extend the agent's instructions |
| `mcpServers` | External *and* in-process tool servers (below) |
| `agents` | Subagent definitions the lead agent can delegate to |
| `hooks` | Deterministic callbacks around the loop (below) |

Treat `allowedTools` + `maxTurns` as non-optional in production — they're the difference between an agent and an unbounded process with your credentials. The [permission semantics](/guides/configuration/claude-code-settings-permissions) are identical to Claude Code's.

## Custom tools without a server process

The SDK's best trick: your application functions become agent tools via **in-process MCP** — no separate server to deploy.

```typescript
import { query, tool, createSdkMcpServer } from "@anthropic-ai/claude-agent-sdk";
import { z } from "zod";

const lookupOrder = tool(
  "lookup_order",
  "Look up an order by ID in our database",
  { orderId: z.string() },
  async ({ orderId }) => ({
    content: [{ type: "text", text: JSON.stringify(await db.orders.find(orderId)) }],
  })
);

const server = createSdkMcpServer({ name: "shop-tools", version: "1.0.0", tools: [lookupOrder] });

for await (const message of query({
  prompt: "Why did order #4127 fail to ship?",
  options: {
    mcpServers: { "shop-tools": { type: "sdk", name: "shop-tools", instance: server.instance } },
    allowedTools: ["mcp__shop-tools__lookup_order"],
  },
})) { /* ... */ }
```

Inputs are schema-validated before your handler runs, and the tool participates in permissions under its `mcp__server__tool` name. External MCP servers (the [same ecosystem Claude Code uses](/guides/mcp/claude-code-mcp-setup)) plug into the same `mcpServers` option.

## Subagents and hooks: the patterns port over

Everything you've learned composing Claude Code carries into the SDK. **Subagents** keep big tasks coherent — define specialists and let the lead delegate:

```typescript
options: {
  allowedTools: ["Read", "Glob", "Grep", "Agent"],
  agents: {
    "code-reviewer": {
      description: "Expert code reviewer",
      prompt: "Analyze code quality and suggest improvements.",
      tools: ["Read", "Glob", "Grep"],
    },
  },
}
```

**Hooks** add the deterministic layer — a `PreToolUse` hook that blocks writes outside a sandbox directory, a `PostToolUse` hook that logs every command for audit. In the SDK they're plain callbacks in `options.hooks`, same events and semantics as [Claude Code hooks](/guides/configuration/claude-code-hooks).

## Production notes

- **Auth:** `ANTHROPIC_API_KEY` for the Claude API; `CLAUDE_CODE_USE_BEDROCK=1` or `CLAUDE_CODE_USE_VERTEX=1` to run on AWS/GCP with their credential chains. Consumer claude.ai logins aren't a thing here — this is the API surface.
- **Billing:** API usage is per-token. If your team is on Claude subscription plans, note that Anthropic announced a separate monthly Agent SDK credit for SDK and `claude -p` usage (planned for June 15, 2026) but **paused** it before it took effect — for now that usage still meters against your normal plan limits, so check the current policy before you budget.
- **Where it sits in the landscape:** against [LangGraph, CrewAI, and the OpenAI Agents SDK](/guides/concepts/agent-frameworks-2026), the Claude Agent SDK's pitch is the *harness*: you inherit a battle-tested tool-execution loop, permission system, and context management instead of assembling them. The trade is the same as [Claude Code's](/tools/claude-code) — it runs Anthropic's models, tuned for them.

Start with the smallest version of your agent that does real work — one `query()`, three tools, `maxTurns: 10` — and grow it the way you'd grow a Claude Code workflow: add a custom tool when the model needs your data, a subagent when one context stops being enough, a hook when a rule must hold every time. For making the result *reliable*, the [production tool-calling guide](/guides/concepts/production-tool-calling) and the [agent-reliability-reviewer](/agents/meta-orchestration/agent-reliability-reviewer) pick up where this tutorial ends.

---

_Source: https://agentscamp.com/guides/advanced/claude-agent-sdk-tutorial — Guide on AgentsCamp._
