Kebanyakan tutorial "AI agent" masih nunjukin tiga baris yang manggil Anthropic Messages API langsung, parse blok tool_use manual, dan berharap shape JSON-nya cocok sama yang ada di docs. Itu jalan buat demo, lalu roboh begitu kamu tambah tool kedua, permission check, atau error path. Claude Agent SDK dibikin buat gap ini. SDK ini ngebungkus toolset Claude Code, agent loop, plumbing MCP server, dan protokol streaming jadi satu library Python, biar kamu fokus ke "agennya harus ngapain", bukan ngulang-ulang run loop.
Guide ini jalan dari pip install sampai agen kecil yang expose tool custom, intercept command bahaya pakai hook, dan streaming output balik ke terminal. Semuanya copy-paste. Package-nya claude-agent-sdk resmi di PyPI, sekarang versi 0.2.110 pas nulis ini. Statusnya 3 - Alpha, jadi pin versinya kalau kamu masukin ke production.
Prasyarat
- Python 3.10 atau lebih baru
- API key Anthropic, set sebagai
ANTHROPIC_API_KEYdi shell atau di file.env - Kira-kira 50MB disk buat SDK dan Claude Code CLI yang udah di-bundle
- Terminal buat paste command
Itu doang. SDK-nya nge-bundle Claude Code CLI, jadi nggak ada lagi yang perlu di-install atau di-download.
Step 1: Install SDK
python -m venv .venv
source .venv/bin/activate
pip install --upgrade claude-agent-sdk
Cek install-nya:
python -c "import claude_agent_sdk; print(claude_agent_sdk.__file__)"
Kalau import-nya ngeprint path di dalam virtualenv kamu, beres. Kalau dapat ModuleNotFoundError, kemungkinan shell kamu pake interpreter yang beda. Jalanin lagi source .venv/bin/activate dan coba ulang.
Step 2: Query One-Shot dengan query()
Entry point paling simpel itu query(). Dia async generator yang ngirim message setiap kali Claude ngehasilin sesuatu. Kamu nggak manage session, nggak handle tool loop, tinggal iterate.
import anyio
from claude_agent_sdk import query, AssistantMessage, TextBlock
async def main():
async for message in query(prompt="What is 2 + 2?"):
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(block.text)
anyio.run(main)
Jalanin:
python quickstart.py
Kamu bakal liat sesuatu kayak 4. Belum impressive, tapi bagian streaming-nya yang penting: query() ngebalikin tiap message begitu CLI ngeluarinnya, jadi kode yang sama yang ngeprint jawaban satu baris juga bakal ngeprint rencana refactor 200 baris token per token tanpa kode tambahan.
Step 3: Expose Tool Custom
Tool custom itu cuma fungsi Python yang di-decorate @tool, plus nama, deskripsi, dan JSON schema buat input-nya. SDK-nya ngewrap itu jadi MCP server in-process, dan ini jujur bagian paling bersih dari API-nya. Nggak ada subprocess, nggak ada plumbing stdio, nggak ada handshake JSON-RPC yang perlu di-debug.
import anyio
from claude_agent_sdk import (
tool,
create_sdk_mcp_server,
ClaudeAgentOptions,
ClaudeSDKClient,
)
@tool("sum", "Add two integers and return the result", {"a": int, "b": int})
async def sum_numbers(args):
return {
"content": [
{"type": "text", "text": str(args["a"] + args["b"])}
]
}
server = create_sdk_mcp_server(
name="math",
version="1.0.0",
tools=[sum_numbers],
)
options = ClaudeAgentOptions(
mcp_servers={"math": server},
allowed_tools=["mcp__math__sum"],
max_turns=3,
)
async def main():
async with ClaudeSDKClient(options=options) as client:
await client.query("Use the sum tool to compute 17 + 25.")
async for message in client.receive_response():
print(message)
anyio.run(main)
Tiga hal yang perlu diperhatiin:
- Nama tool muncul di list
allowed_toolsdengan prefixmcp__<server-name>__<tool-name>. Salah prefix, model nggak bakal bisa manggil tool-nya. allowed_toolsitu allowlist buat auto-approval, bukan daftar apa yang tersedia. Kalau mau beneran ngebuang tool dari conversation, pakedisallowed_tools. Panduan permissions punya urutan evaluasi lengkapnya.max_turnsngebatesin agent loop. Tanpa ini, model yang bingung bisa ngehabisin token manggil tool yang sama berulang-ulang.
Step 4: Block Command Bahaya dengan Hook
Hook itu bagian yang pengen banget aku tau dari awal. Hook bikin kode kamu jalan di dalam agent loop di titik yang udah ditentuin, dan bisa ngebalikin keputusan yang bakal dihormatin sama loop. Use case klasik: ngegah model jalanin rm -rf atau ngedit file di luar direktori project.
from claude_agent_sdk import (
ClaudeAgentOptions,
ClaudeSDKClient,
HookMatcher,
)
FORBIDDEN = ["rm -rf", "DROP TABLE", "mkfs"]
async def block_dangerous(input_data, tool_use_id, context):
if input_data["tool_name"] != "Bash":
return {}
command = input_data["tool_input"].get("command", "")
for pattern in FORBIDDEN:
if pattern in command:
return {
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": f"Refused: '{pattern}' is not allowed",
}
}
return {}
options = ClaudeAgentOptions(
allowed_tools=["Bash"],
hooks={
"PreToolUse": [
HookMatcher(matcher="Bash", hooks=[block_dangerous]),
],
},
)
async def main():
async with ClaudeSDKClient(options=options) as client:
await client.query("Delete everything in /tmp with rm -rf")
async for msg in client.receive_response():
print(msg)
anyio.run(main)
Waktu hook ngebalikin permissionDecision: "deny", agent loop nggak ngejalanin tool-nya. Model liat hasil penolakan dan harus nyari cara lain. Daftar lengkap event dan payload-nya ada di hooks guide.
Step 5: Handle Error Secara Eksplisit
SDK-nya nyertain typed error buat mode failure yang umum. Catch di tempat yang penting, biarin sisanya naik.
from claude_agent_sdk import (
query,
CLINotFoundError,
CLIConnectionError,
ProcessError,
CLIJSONDecodeError,
)
try:
async for message in query(prompt="Summarize README.md"):
print(message)
except CLINotFoundError:
print("Claude Code CLI missing. Reinstall the SDK.")
except CLIConnectionError:
print("CLI exited before producing output.")
except ProcessError as e:
print(f"CLI failed with exit code {e.exit_code}: {e}")
except CLIJSONDecodeError:
print("Could not parse a message from the CLI. Open an issue.")
CLINotFoundError yang paling sering aku temuin, biasanya abis upgrade SDK di satu venv terus jalanin dari venv yang lain. Cek path pakai which claude dan pastiin nunjuk ke dalam venv yang lagi aktif.
Kapan Pake SDK dan Kapan Manggil API Langsung
Pilih Claude Agent SDK kalau agen kamu perlu baca file, jalanin command shell, atau ngegabungin beberapa tool call. Loop, permission model, dan protokol streaming-nya udah jadi masalah yang solved dan kamu nggak mau nyelesainnya ulang.
Manggil Anthropic Messages API langsung kalau kamu lagi bikin chat surface tanpa tool use, lagi ngelakuin ekstraksi terstruktur satu-shot, atau jalanin batch offline di mana kamu mau kontrol eksplisit di tiap token. API-nya kasih full visibility; SDK-nya kasih loop dan tool dengan gratis.
Buat kerja autonomous yang lama, SDK-nya punya fitur settings isolation dan programmatic subagent API. Dua-duanya worth it dilihat setelah prototype pertama kamu jalan.
Jebakan yang Sering Kejadian
Lupa prefix mcp__<server>__<tool>. Tool-nya jalan, model bisa liat, terus nggak ada yang terjadi karena allowlist bilang "sum" tapi model manggil "mcp__math__sum". Cek prefix dulu kalau tool custom dianggurin.
Campur query() dan ClaudeSDKClient di script yang sama. query() nggak support tool custom atau hook. Kalau butuh salah satu, pindah ke ClaudeSDKClient dan pake await client.query() plus async for msg in client.receive_response().
Biarin agent loop jalan terus. Model yang bingung bisa ngehasilin biaya gede manggil tool yang sama yang fail di loop. Selalu set max_turns. Lima biasanya cukup buat satu pertanyaan, sepuluh buat task kecil, dua puluh buat refactor beneran.
Percaya sama hasil tool pertama. Agen itu bukan function call, dia loop. Tool yang ngebalikin sukses tapi bohong lebih parah dari yang error. Tambahin hook yang log setiap tool invocation dan satu lagi yang validasi shape hasilnya. Kamu bakal berterima kasih ke diri sendiri pertama kali ada yang diem-diem nakal.
Mau Lanjut ke Mana
- Claude Agent SDK overview — daftar kapabilitas lengkap dan catatan desain
- Panduan permissions —
allowed_tools,disallowed_tools, dan urutan evaluasinya - Referensi hooks — tiap event, tiap payload, lengkap sama contoh
- Repo GitHub — source, folder examples, dan changelog (SDK ini di jalur 0.2.x dan gerak cepet)