Agent SDK入門 — Python / TypeScriptで最小エージェントを組む
Claude Agent SDKのPython / TypeScript版で最小カスタムエージェントを動かす入門。query・Custom Tool・Permission・Sessionの最短経路と言語別の使い分け早見表。
要点
Claude Agent SDKは、Claude Codeの裏側で動くエージェントループを自前アプリに組み込むための公式SDKです。Pythonの claude-agent-sdk とTypeScriptの @anthropic-ai/claude-agent-sdk が提供され、どちらも query() 一発で最小エージェントが動きます。以下、インストールからCustom Toolの定義、Permission Mode、Sessionの継続までを両言語で通しで組み、最後にPythonとTypeScriptの使い分け早見表を置きます。
この記事で学べること
claude-agent-sdk/@anthropic-ai/claude-agent-sdkのインストールと最小実行@tool/tool()でのカスタムツール定義とcreateSdkMcpServer/create_sdk_mcp_serverでのバンドルpermissionModeとallowedTools/disallowedToolsによる安全側のデフォルト設計ClaudeSDKClient(Python)とcontinue: true(TypeScript)によるセッション継続- どちらを選ぶべきかの用途別早見表
前段の設定レイヤに当たるCLAUDE.mdの書き方や、実行時フックによる自動化を担うHooksの設定方法と組み合わせると、作ったエージェントの挙動をプロジェクト単位で縛れます。
前提条件
- Node.js 20以上、またはPython 3.10以上
ANTHROPIC_API_KEY環境変数が設定済み、またはClaudeサブスクリプション経由の認証が通っている- TypeScript側は
zodが必要(スキーマ定義に使用) - エディタから実行する場合は、プロジェクトのカレントディレクトリが重要(セッションはこのパス配下に保存される)
インストールはそれぞれ1コマンドです。
# Python
pip install claude-agent-sdk
# TypeScript
npm install @anthropic-ai/claude-agent-sdk zodPython版の最小実装
まずは query() を async for で回すだけの最小例です。query() は1回限りのやり取りに向き、戻り値はメッセージのストリームになります。
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions
from claude_agent_sdk.types import AssistantMessage, TextBlock, ResultMessage
async def main() -> None:
options = ClaudeAgentOptions(
allowed_tools=["Read", "Glob", "Grep"],
permission_mode="default",
)
async for message in query(
prompt="このディレクトリの TypeScript ファイルを 5 つまで挙げて",
options=options,
):
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(block.text)
elif isinstance(message, ResultMessage) and message.subtype == "success":
print(f"[done] cost={message.total_cost_usd}")
asyncio.run(main())ポイントは3つです。
ClaudeAgentOptionsでツール許可とPermission Modeをまとめて渡す- メッセージは型で分岐(
AssistantMessage/ResultMessageなど) ResultMessageが来たら1ターンが完全に終わった合図
TypeScript版の最小実装
TypeScript側もAPIの形はほぼ同じです。query({ prompt, options }) を for await で回します。
import { query } from "@anthropic-ai/claude-agent-sdk";
async function main() {
for await (const message of query({
prompt: "このディレクトリの TypeScript ファイルを 5 つまで挙げて",
options: {
model: "claude-opus-4-1",
maxTurns: 5,
permissionMode: "default",
allowedTools: ["Read", "Glob", "Grep"],
},
})) {
if (message.type === "assistant") {
for (const block of message.message.content) {
if (block.type === "text") console.log(block.text);
}
} else if (message.type === "result" && message.subtype === "success") {
console.log(`[done] cost=${message.total_cost_usd}`);
}
}
}
main();TypeScript版は戻り値が Query 型で、interrupt() や setPermissionMode() などのメソッドも生えています。ループ途中で許可方針を切り替えたい時はこのメソッドを使います。
Custom Toolの作り方
Agent SDKの強みは、自前関数をMCPツール互換でClaudeに渡せる点です。Pythonは @tool デコレータ、TypeScriptは tool() ヘルパーで定義し、それを create_sdk_mcp_server / createSdkMcpServer でまとめてから query に渡します。
Python版の例です。
from typing import Any
import httpx
from claude_agent_sdk import tool, create_sdk_mcp_server
@tool(
"get_temperature",
"指定した緯度経度の現在気温を取得する",
{"latitude": float, "longitude": float},
)
async def get_temperature(args: dict[str, Any]) -> dict[str, Any]:
async with httpx.AsyncClient() as client:
res = await client.get(
"https://api.open-meteo.com/v1/forecast",
params={
"latitude": args["latitude"],
"longitude": args["longitude"],
"current": "temperature_2m",
},
)
data = res.json()
return {
"content": [
{"type": "text", "text": f"気温: {data['current']['temperature_2m']}°C"}
]
}
weather_server = create_sdk_mcp_server(
name="weather",
version="1.0.0",
tools=[get_temperature],
)TypeScript版はスキーマをZodで書くので、ハンドラ側の引数型は自動で付きます。
import { tool, createSdkMcpServer } from "@anthropic-ai/claude-agent-sdk";
import { z } from "zod";
const getTemperature = tool(
"get_temperature",
"指定した緯度経度の現在気温を取得する",
{
latitude: z.number().describe("緯度"),
longitude: z.number().describe("経度"),
},
async ({ latitude, longitude }) => {
const res = await fetch(
`https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=temperature_2m`,
);
const data: any = await res.json();
return {
content: [{ type: "text", text: `気温: ${data.current.temperature_2m}°C` }],
};
},
{ annotations: { readOnlyHint: true } },
);
export const weatherServer = createSdkMcpServer({
name: "weather",
version: "1.0.0",
tools: [getTemperature],
});登録したツールを呼ぶときは mcpServers に名前付きで渡し、フルネーム mcp__weather__get_temperature を allowedTools に入れます。これで承認ダイアログ抜きで実行されます。readOnlyHint: true を付けておくと、他の読み取り専用ツールと並列実行できるようになります。MCPサーバーの作り方そのものを深掘りしたい場合はMCP実践ガイドに独立した手順があります。
ツール内でエラーを返したい時は、例外を投げるとループごと落ちるので、isError: true(Pythonは is_error: True)を付けた content を返すのが作法です。Claude側はエラーを「データ」として認識して、別のツールを試したり、ユーザーに説明を返したりします。
Permission / Session管理
Permissionは5段階のフローで評価されます。Hooks → Denyルール → Permission Mode → Allowルール → canUseTool コールバック、の順です。主要なモードは次の通りです。
| モード | 挙動 | 想定用途 |
|---|---|---|
default | 未承認ツールは canUseTool へ | 人間が近くにいるCLI |
dontAsk | 未承認はすべて拒否(プロンプトなし) | ヘッドレス・固定ツールセット |
acceptEdits | ファイル編集と mkdir / rm / mv を自動承認 | 信頼できる編集ループ |
bypassPermissions | 全ツール自動承認(Denyルールだけは有効) | 隔離環境での無人実行 |
plan | ツール実行せず計画のみ立てる | レビュー前の設計フェーズ |
注意点として、bypassPermissions は allowedTools で絞れません。未記載のツールも全部通ってしまうので、止めたいツールは disallowedTools に入れます。固定ツールセットのヘッドレス用途では allowedTools + permissionMode: "dontAsk" の組み合わせが安全側のデフォルトです。
Sessionは会話履歴のことで、~/.claude/projects/<エンコードされた cwd>/ 配下にJSONLで自動保存されます。同じプロセス内でマルチターンを続けたいだけなら、Pythonは ClaudeSDKClient を使うのが自然です。
import asyncio
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions
async def main() -> None:
options = ClaudeAgentOptions(allowed_tools=["Read", "Edit", "Glob", "Grep"])
async with ClaudeSDKClient(options=options) as client:
await client.query("auth モジュールを読んで設計上の問題点を挙げて")
async for _ in client.receive_response():
pass
# ↑ と同じセッション
await client.query("今指摘してくれた点のうち最優先のものを直して")
async for _ in client.receive_response():
pass
asyncio.run(main())TypeScript版には同等のクライアントクラスが無いので、2回目以降の query() に continue: true を渡します。SDKが同一 cwd の最新セッションを自動で引き継ぎます。
import { query } from "@anthropic-ai/claude-agent-sdk";
await consume(query({ prompt: "auth モジュールを読んで問題点を挙げて" }));
await consume(
query({
prompt: "今指摘してくれた点のうち最優先のものを直して",
options: { continue: true, allowedTools: ["Read", "Edit"] },
}),
);
async function consume(q: AsyncIterable<unknown>) {
for await (const _ of q) {
// ドロップ
}
}特定セッションに戻りたい場合は ResultMessage.session_id を保存しておき、resume: sessionId で復帰します。並行して別案を試したい時は forkSession: true(Pythonは fork_session=True)で分岐コピーを作れます。
Python vs TypeScriptの使い分け
APIの形はほぼ揃っていますが、運用面で得意領域が分かれます。独自にまとめると次のようになります。
| 観点 | Pythonが向くケース | TypeScriptが向くケース |
|---|---|---|
| 実装スタイル | データ処理・ML / LLMパイプラインに組み込む | Webフロント / Nodeバックエンド / エッジ関数 |
| セッション管理 | ClaudeSDKClient でクライアント主導 | continue: true / resume で関数主導 |
| 型付け | TypedDict + JSON Schema(enumはdict指定) | Zodでコンパイル時に型生成 |
| 既存資産との接続 | httpx / pandas / LangChain / Jupyter | Next.js / tRPC / Vercel AI SDK / Hono |
| セッション永続化 | 常にディスク保存 | persistSession: false でメモリのみも可 |
| プレウォーム起動 | 非対応(query は都度起動) | startup() で事前ウォーム可能 |
迷ったら、バックエンドがTypeScript中心なら素直にTypeScript、ノートブック検証やデータ前処理が長い場合はPython、と割り切るのが早いです。両方を跨ぐ場合、カスタムツールのシグネチャはほぼ同形なので移植コストは低めです。
よくあるつまずき
resume したのに履歴が読まれない: 多くの場合、cwd が違います。セッションは ~/.claude/projects/<cwd をエンコードした名前>/*.jsonl に保存されるので、別ディレクトリから実行するとヒットしません。
allowedTools を指定しているのに全ツール動く: permissionMode: "bypassPermissions" になっていないか確認します。このモードでは allowedTools は無効で、disallowedTools だけが効きます。
Custom Toolの名前が見つからないと言われる: MCP経由の正式名は mcp__<server_name>__<tool_name> です。allowedTools に素の名前だけ書くと、ツールは存在しているのに承認されず無限ループに近い挙動になります。ワイルドカード mcp__weather__* も使えます。
ツール例外で query ごと落ちる: ハンドラ内の未捕捉例外はエージェントループを止めます。外側を try/except(TypeScriptは try/catch)で囲み、失敗時は is_error: True / isError: true を付けた結果を返します。
Pythonでenumスキーマが書けない: {"key": str} 形式はenumを表現できません。JSON Schemaをdictで直接渡すと {"type": "string", "enum": [...]} が書けます。
まとめ
Claude Agent SDKは「Claude Codeのエージェントループを関数として呼べるようにしたもの」と捉えると入りやすいです。最小構成は query() 一行、そこにCustom Toolを足して、Permission Modeで安全側に倒し、必要ならSessionを継続する、という順で積み上げれば、Python / TypeScriptどちらでも同じ設計で組めます。エージェントそのものの振る舞いを縛るときは、CLAUDE.mdの設計とHooksの挟み込みを組み合わせると、実行レイヤと設定レイヤの両側から制御できます。
関連する記事
Claude Code をもっと見る →Anthropic Agent SDKでSlack常駐botを作る — 実装30分のミニチュートリアル
Managed Agentsの設計思想 — セッション/ハーネス/サンドボックスを分離した長時間エージェントのつくり方
AnthropicのContext Engineering論 — 長時間エージェントを動かす4つの実装戦略
Claudeを学ぶ1週間ロードマップ — 初日から実戦投入までの7日ガイド
MCPサーバを自作してClaude Codeにつなぐ — TypeScript実装の完全手順
Claude Codeでよくあるエラー10選 — 起動失敗から認証・MCP・権限まで実機で踏みやすい順に対処
Claude CodeのPro / Max / API従量、どれを選ぶか — コスト試算と選び方の判断ガイド
Claude CodeをGitHub Actionsに組み込む実用ガイド — claude-code-action v1とheadless実行の使い分け