Claude Media
Claude Agent SDK入門 — Python / TypeScriptで最小エージェントを組む

Claude Agent SDK入門 — Python / TypeScriptで最小エージェントを組む

Claude Agent SDKのPython / TypeScript版で最小エージェントを動かす入門。インストールから権限設計・カスタムツール・セッション管理、2026年6月開始のサブスク専用クレジットまで現行APIで解説。

Claude Agent SDKとは

Claude Agent SDKとは、Claude Codeを動かしているエージェントループ(ツール実行・コンテキスト管理・権限制御)を、ライブラリとして自分のアプリケーションに組み込むための公式SDKです。Pythonの claude-agent-sdk とTypeScriptの @anthropic-ai/claude-agent-sdk が提供され、どちらも query() を1回呼ぶだけで、ファイル読み取り・コマンド実行・コード編集まで自律的にこなす最小エージェントが動きます。

最大の特徴は、ツール実行を自前で実装しなくてよい点です。Read / Write / Edit / Bash / Glob / Grep / WebSearch / WebFetchといったClaude Code譲りの組み込みツールが最初から使えるため、Anthropic Client SDK(素のAPIクライアント)のように「stop_reasontool_use の間ループを回して結果を返す」コードを書く必要がありません。隣接する選択肢との位置付けは次の通りです。

観点Client SDKAgent SDKManaged Agents
ツールループClient SDK自前で実装Agent SDKSDKが内蔵Managed AgentsAnthropic側が実行
実行場所Client SDK自分のプロセスAgent SDK自分のプロセスManaged Agentsホスト型サンドボックス
提供形態Client SDKAPIクライアントAgent SDKPython / TSライブラリManaged AgentsREST API
向く用途Client SDK単発の生成・分類Agent SDK自社インフラ上のエージェントManaged Agentsサンドボックス運用を持ちたくない本番

以下、インストールと認証、Python / TypeScript両方の最小実装、カスタムツール、権限設計、セッション管理までを通しで組み、最後に両言語の使い分け早見表とよくあるつまずきを置きます。Claude Code本体の全体像から入りたい場合はClaude Code完全ガイドが前提整理に向いています。

前提条件と認証方式

ANTHROPIC_API_KEY が設定済みなら、インストール後すぐに動きます。前提は次の4点だけです。

  • Pythonは3.10以上(pipNo matching distribution found を返す場合はインタープリタが古い)
  • TypeScript版はNode.js環境と、スキーマ定義用の zod
  • TypeScript版はプラットフォーム別のClaude Codeネイティブバイナリを依存として同梱するため、Claude Code本体の別途インストールは不要
  • セッションは実行時のカレントディレクトリ単位で保存されるため、どこで実行するかが後から効いてくる(詳細は後述)
# Python
pip install claude-agent-sdk
 
# TypeScript
npm install @anthropic-ai/claude-agent-sdk zod

認証はAPIキーが基本です。Console(platform.claude.com)で発行したキーを環境変数 ANTHROPIC_API_KEY に設定します。クラウド経由の認証も一通り揃っており、Amazon Bedrockは CLAUDE_CODE_USE_BEDROCK=1、Google Vertex AIは CLAUDE_CODE_USE_VERTEX=1、Microsoft Foundryは CLAUDE_CODE_USE_FOUNDRY=1 を設定した上で各クラウドの資格情報を構成する方式です。

サブスクリプション利用は専用クレジット制へ(2026年6月15日〜)

2026年6月15日から、Agent SDKと claude -p(Claude Codeの非対話モード)の利用は、サブスクリプションプランでは対話利用と別枠の「Agent SDK月次クレジット」から消費されます。これまで対話利用の上限と混ざっていたSDK経由の消費が分離されるため、「スクリプトを回したら対話分の枠が消えた」という事故がなくなる一方、SDK側には明確な月次上限が付きます。

プランAgent SDK月次クレジット
ProAgent SDK月次クレジット$20
Max 5xAgent SDK月次クレジット$100
Max 20xAgent SDK月次クレジット$200
Team StandardAgent SDK月次クレジット$20
Team PremiumAgent SDK月次クレジット$100
Enterprise(従量課金)Agent SDK月次クレジット$20
Enterprise PremiumシートAgent SDK月次クレジット$200

クレジットを使い切った後の挙動は設定次第で分かれます。usage credits(従量課金)を有効にしていればAPI標準レートでの課金に切り替わり、無効なら次の請求サイクルでクレジットがリセットされるまでAgent SDKのリクエストは停止します。未使用分の翌サイクルへの繰り越しはありません。CI等で常時動かす設計なら、最初からAPIキー課金で見積もる方が読みやすいです。

Python版の最小実装

まずは query()async for で回すだけの最小例です。query() は呼ぶたびに新しいセッションを作る一発実行型で、戻り値はメッセージの非同期ストリームになります。

agent_minimal.py
import asyncio
from claude_agent_sdk import (
    query,
    ClaudeAgentOptions,
    AssistantMessage,
    TextBlock,
    ResultMessage,
)
 
async def main() -> None:
    options = ClaudeAgentOptions(
        allowed_tools=["Read", "Glob", "Grep"],
        permission_mode="default",
        max_turns=5,
    )
 
    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 でツールの事前承認(allowed_tools)とPermission Modeをまとめて渡す
  • メッセージは型で分岐する(AssistantMessage / ResultMessage など)
  • ResultMessage が来たら1回の実行が完全に終わった合図。total_cost_usd(コスト概算)や session_id もここから取れる

コスト上限を先に切りたい場合は max_budget_usd を渡せます。概算コストが指定額に達すると実行が止まり、ResultMessage.subtypeerror_max_budget_usd になります。

TypeScript版の最小実装

TypeScript側もAPIの形はほぼ同じで、query({ prompt, options })for await で回します。モデルは "sonnet" / "opus" / "haiku" などのエイリアスか、フルのモデルIDで指定できます。

agent-minimal.ts
import { query } from "@anthropic-ai/claude-agent-sdk";
 
async function main() {
  for await (const message of query({
    prompt: "このディレクトリの TypeScript ファイルを 5 つまで挙げて",
    options: {
      model: "sonnet",
      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()(許可方針の動的切り替え)、setModel()(モデル切り替え)はストリーミング入力モードでの利用が前提、rewindFiles()(ファイルチェックポイントへの巻き戻し)は enableFileCheckpointing: true を有効にした場合に使えます。初回起動を速くしたい常駐プロセスでは、startup() でCLIサブプロセスを事前にウォームアップしておく選択肢もあります。

カスタムツールの作り方(プロセス内MCPサーバー)

Agent SDKの強みは、自前の関数をMCP(Model Context Protocol)ツールとしてClaudeに渡せる点です。Pythonは @tool デコレータ、TypeScriptは tool() ヘルパーで定義し、create_sdk_mcp_server / createSdkMcpServer でまとめてから query に渡します。このMCPサーバーは別プロセスではなく、アプリケーションのプロセス内で動きます。

Python版の例です。スキーマは {"latitude": float} のような型のdictで書くと、SDKがJSON Schemaへ変換してくれます。

weather_tool.py
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で書くため、ハンドラ側の引数型が自動で付きます。.describe() を付けるとフィールド説明としてClaudeに渡り、.default() を付けたパラメータは省略可能になります。

weather-tool.ts
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}&current=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 に名前付きで渡します。mcpServers のキーがそのままサーバー名になり、ツールの正式名は mcp__weather__get_temperature の形式です。この名前を allowedTools に入れておくと、承認の問い合わせなしで実行されます。同じサーバーのツールをまとめて許可するワイルドカード mcp__weather__* も使えます。readOnlyHint: true を付けたツールは、他の読み取り専用ツールと並列実行の対象になります(ただしアノテーションはメタデータであって強制ではありません)。MCPサーバーそのものの作り方と外部サーバー接続はMCP実践ガイドに独立した手順があります。

ツール内でエラーを返すときの作法も決まっています。未捕捉の例外を投げるとエージェントループごと停止して query 自体が失敗するため、ハンドラ内で捕捉し、isError: true(Pythonは is_error: True)を付けた content を返します。こうするとClaudeはエラーを「データ」として受け取り、リトライ・別ツールの試行・ユーザーへの説明に進めます。

なお、機械可読なJSONを返す structuredContent はTypeScriptのプロセス内サーバーで使えますが、Pythonの @tool デコレータは contentis_error しか転送しません。Pythonで構造化データを返したい場合は、スタンドアロンのMCPサーバーとして立てる形になります。

権限制御の設計(Permission)

ツールの実行可否は6段階の固定順で評価されます。Hooks → Denyルール → Askルール → Permission Mode → Allowルール → canUseTool コールバック、の順です。HookやDenyルールが先に評価されるため、bypassPermissions でもDenyルールとAskルールは効きます。主要なモードは次の通りです。

モード挙動想定用途
default挙動自動承認なし。未解決は canUseTool想定用途人間が近くにいる対話アプリ
dontAsk挙動事前承認以外はすべて拒否(問い合わせなし)想定用途ヘッドレス・固定ツールセット
acceptEdits挙動ファイル編集とファイル系コマンドを自動承認想定用途信頼できる編集ループ
bypassPermissions挙動全ツール自動承認(Deny / Ask / Hookは有効)想定用途隔離環境での無人実行
plan挙動編集せず計画のみ。編集要求は必ず問い合わせ想定用途レビュー前の設計フェーズ
auto(TypeScriptのみ)挙動モデル分類器が承認 / 拒否を判定想定用途問い合わせを減らしたい対話運用

設計上の急所は allowedTools の意味です。これは「利用可能なツールの制限」ではなく「事前承認リスト」で、載っていないツールもClaudeからは見えており、Permission Modeと canUseTool に流れていきます。ツール自体を使わせたくない場合は、組み込みツールを絞る tools オプションを使うか、disallowedTools に素のツール名(例: "Bash")を書いてコンテキストから除去します。disallowedTools"Bash(rm *)" のようなスコープ付きルールも書け、この場合Bash自体は残しつつ rm 系の呼び出しだけを全モードで拒否します。

bypassPermissionsallowedTools で絞れません。未記載のツールもモード評価の段階で全部承認されるため、allowed_tools=["Read"] と併用しても BashWrite は通ります。止めたいツールは disallowedTools に入れます。固定ツールセットのヘッドレス用途では、allowedTools + permissionMode: "dontAsk" の組み合わせが「許可した分だけ動き、それ以外は静かに拒否」という安全側のデフォルトです。

acceptEdits が自動承認するのは、Edit / Writeによるファイル編集と、mkdir / touch / rm / rmdir / mv / cp / sed のファイル系コマンドです。いずれも作業ディレクトリ(と additionalDirectories)の内側に限られ、外側のパスは通常通り問い合わせになります。実行時に挙動へ割り込みたい場合はHooksコールバック(PreToolUse / PostToolUse など)も併用できます。Hooksの考え方はClaude Code本体と共通なので、Hooksの設定方法が下地になります。

セッションの継続・再開・分岐

セッションは会話履歴のことで、~/.claude/projects/<エンコードされたcwd>/ 配下にJSONLとして自動保存されます(CLAUDE_CONFIG_DIR を設定している場合はその配下)。エンコード規則は「絶対パスの英数字以外をすべて - に置換」で、/Users/me/proj なら -Users-me-proj です。同じプロセス内でマルチターンを続けるだけなら、Pythonは ClaudeSDKClient が一番素直です。

session_python.py
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が同一ディレクトリの最新セッションを自動で引き継ぐ方式です。

session-ts.ts
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(またはinitの SystemMessage)を保存しておき、resume にそのIDを渡します。error_max_turnserror_max_budget_usd で止まった実行を、上限を引き上げて続きから再開する、という使い方が典型です。並行して別案を試したいときは forkSession: true(Pythonは fork_session=True)で履歴のコピーから分岐でき、元のセッションは無傷のまま残ります。

ディスクに何も残したくないステートレス用途では、TypeScript版だけ persistSession: false でメモリのみの実行にできます(Python版は常にディスク保存)。過去セッションの列挙・読み出し・改名・タグ付けには listSessions() / getSessionMessages() / renameSession() / tagSession()(Pythonはスネークケースの同名関数)が用意されており、独自のセッションピッカーや掃除処理を組めます。なお、TypeScript版に実験実装されていたV2セッションAPI(createSession())は0.3.142で削除済みで、現行は query() + セッションオプションに一本化されています。

PythonとTypeScriptの使い分け早見表

APIの形はほぼ揃っており、カスタムツールのシグネチャも同形なので移植コストは低めです。運用面の差は次の通りです。

観点PythonTypeScript
マルチターンPythonClaudeSDKClient でクライアント主導TypeScriptcontinue: true / resume で関数主導
スキーマ定義Python型dict + JSON Schema(enumはJSON Schema必須)TypeScriptZodでコンパイル時に型生成
セッション永続化Python常にディスク保存TypeScriptpersistSession: false でメモリのみ可
起動の事前ウォームPython非対応TypeScriptstartup() で可能
構造化ツール結果Pythonプロセス内では structuredContent 非転送TypeScriptstructuredContent 対応
既存資産との接続Pythonデータ処理 / ML / Jupyter系TypeScriptNext.js / Node / エッジ関数系

迷ったら、バックエンドがTypeScript中心なら素直にTypeScript、ノートブック検証やデータ前処理が長いならPython、という割り切りで十分です。複数エージェントの並列化や agents オプションによるサブエージェント定義はどちらの言語でも使えるので、その設計論はサブエージェント並列パターンが参考になります。実戦寄りの題材としては、TypeScript版でSlack常駐botを組むAgent SDKミニチュートリアルがあります。

よくあるつまずき

resume したのに履歴が読まれない: ほとんどの場合 cwd の不一致です。セッションは ~/.claude/projects/<cwdをエンコードした名前>/*.jsonl に保存されるため、別ディレクトリから実行すると新規セッションが始まります。別ホストで再開したい場合は、このJSONLファイルを同じパスに移すか、必要な結論だけをアプリ側の状態として持ち回ります。

Claude Codeと同じ挙動にならない: SDKのシステムプロンプトはデフォルトで最小限です。Claude Code本体と同じ振る舞いが欲しければ、systemPrompt: { type: "preset", preset: "claude_code" } を明示します。逆に、ホスト環境の ~/.claude やプロジェクトの .claude/ 設定(CLAUDE.mdやSkills)はデフォルトで読み込まれるため、本番でホスト設定から隔離したい場合は settingSources: [](Pythonは setting_sources=[])を渡します。プロジェクト設定として何を書くかはCLAUDE.mdの書き方が使えます。

allowedTools に書いていないツールまで動く: allowedTools は事前承認リストであり、ツールの存在自体は制限しません。使わせたくないツールは tools オプションで絞るか、disallowedTools に素の名前を書いてコンテキストから外します。

bypassPermissionsallowedTools が効かない: 仕様通りの挙動です。このモードはAllowルールより後の段階で全承認するため、絞り込みは disallowedTools で行います。

カスタムツールの名前が見つからない: 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を表現できません。{"type": "string", "enum": [...]} を含むJSON Schemaのdictを直接渡します。

よくある質問

Claude Agent SDKは無料で使えますか

SDK自体は無料ですが、実行にはモデル利用分の費用がかかります。APIキー経由ならトークン従量課金、サブスクリプション経由なら2026年6月15日以降はプラン付属のAgent SDK月次クレジット(Pro $20 / Max 5x $100 / Max 20x $200)から消費されます。

Claude Code本体を別途インストールする必要はありますか

TypeScript版は不要です。プラットフォーム別のClaude Codeネイティブバイナリが任意依存(optional dependency)として同梱されます。同梱バイナリをスキップした構成では、別途インストールした claude バイナリのパスを pathToClaudeCodeExecutable で指定できます。

Claude Code SDKとClaude Agent SDKは別物ですか

同じものです。以前「Claude Code SDK」として提供されていたものが「Claude Agent SDK」に改名されました。パッケージ名も claude-agent-sdk(Python)/ @anthropic-ai/claude-agent-sdk(TypeScript)に統一されています。

作ったエージェントを自社サービスとして提供できますか

可能です。利用はAnthropicのCommercial Termsに従います。ブランディングには制約があり、「Claude Agent」「Powered by Claude」という表現は使えますが、「Claude Code」を名乗ることや、Claude Code風のビジュアルを模倣することは認められていません。エンドユーザーへのclaude.aiログイン提供も事前承認なしには不可です。

どのモデルで動きますか

model オプションで指定します。"sonnet" / "opus" / "haiku" などのエイリアスか、フルのモデルIDを渡せます。未指定の場合はCLI側のデフォルトモデルが使われます。TypeScript版は実行中でも setModel() で切り替え可能です。

まとめ

Claude Agent SDKは「Claude Codeのエージェントループを関数として呼べるようにしたもの」と捉えると入りやすいです。最小構成は query() 一行、そこにカスタムツールを足し、allowedTools + dontAsk やDenyルールで権限を安全側に倒し、必要に応じてセッションを継続・分岐する、という順で積み上げれば、Python / TypeScriptどちらでも同じ設計で組めます。2026年6月15日からはサブスクリプションでの利用枠が専用クレジットに分離されるため、常時運用するエージェントはAPIキー課金前提でコストを見積もり、max_budget_usd で実行単位の上限も切っておくと運用が読みやすくなります。エージェントの振る舞いをプロジェクト単位で縛るときは、CLAUDE.mdによる設定レイヤとHooksによる実行レイヤを組み合わせる構成が有効です。

この記事を共有:XはてブLinkedIn