インストール

pip install claude-agent-sdk

query()ClaudeSDKClient の選択

Python SDK は Claude Code とやり取りする2つの方法を提供します:

簡単な比較

機能query()ClaudeSDKClient
セッション毎回新しいセッションを作成同じセッションを再利用
会話単一の交換同じコンテキストで複数の交換
接続自動的に管理手動制御
ストリーミング入力✅ サポート✅ サポート
割り込み❌ サポートなし✅ サポート
フック❌ サポートなし✅ サポート
カスタムツール❌ サポートなし✅ サポート
チャット継続❌ 毎回新しいセッション✅ 会話を維持
使用例一回限りのタスク継続的な会話

query() を使用する場合(毎回新しいセッション)

最適な用途:
  • 会話履歴が不要な一回限りの質問
  • 以前の交換からのコンテキストを必要としない独立したタスク
  • シンプルな自動化スクリプト
  • 毎回新しい開始が必要な場合

ClaudeSDKClient を使用する場合(継続的な会話)

最適な用途:
  • 会話の継続 - Claude にコンテキストを記憶させる必要がある場合
  • フォローアップ質問 - 以前の応答に基づいて構築する場合
  • インタラクティブアプリケーション - チャットインターフェース、REPL
  • 応答駆動ロジック - 次のアクションが Claude の応答に依存する場合
  • セッション制御 - 会話のライフサイクルを明示的に管理する場合

関数

query()

Claude Code との各やり取りで新しいセッションを作成します。メッセージが到着するとそれらを yield する非同期イテレータを返します。query() への各呼び出しは、以前のやり取りの記憶なしに新しく開始します。
async def query(
    *,
    prompt: str | AsyncIterable[dict[str, Any]],
    options: ClaudeAgentOptions | None = None
) -> AsyncIterator[Message]

パラメータ

パラメータ説明
promptstr | AsyncIterable[dict]文字列またはストリーミングモード用の非同期イテラブルとしての入力プロンプト
optionsClaudeAgentOptions | Noneオプションの設定オブジェクト(None の場合は ClaudeAgentOptions() がデフォルト)

戻り値

会話からのメッセージを yield する AsyncIterator[Message] を返します。

例 - オプション付き


import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions

async def main():
    options = ClaudeAgentOptions(
        system_prompt="あなたは専門の Python 開発者です",
        permission_mode='acceptEdits',
        cwd="/home/user/project"
    )

    async for message in query(
        prompt="Python ウェブサーバーを作成してください",
        options=options
    ):
        print(message)


asyncio.run(main())

tool()

型安全性を持つ MCP ツールを定義するためのデコレータ。
def tool(
    name: str,
    description: str,
    input_schema: type | dict[str, Any]
) -> Callable[[Callable[[Any], Awaitable[dict[str, Any]]]], SdkMcpTool[Any]]

パラメータ

パラメータ説明
namestrツールの一意識別子
descriptionstrツールが何をするかの人間が読める説明
input_schematype | dict[str, Any]ツールの入力パラメータを定義するスキーマ(下記参照)

入力スキーマオプション

  1. シンプルな型マッピング(推奨):
    {"text": str, "count": int, "enabled": bool}
    
  2. JSON スキーマ形式(複雑な検証用):
    {
        "type": "object",
        "properties": {
            "text": {"type": "string"},
            "count": {"type": "integer", "minimum": 0}
        },
        "required": ["text"]
    }
    

戻り値

ツール実装をラップして SdkMcpTool インスタンスを返すデコレータ関数。

from claude_agent_sdk import tool
from typing import Any

@tool("greet", "ユーザーに挨拶する", {"name": str})
async def greet(args: dict[str, Any]) -> dict[str, Any]:
    return {
        "content": [{
            "type": "text",
            "text": f"こんにちは、{args['name']}さん!"
        }]
    }

create_sdk_mcp_server()

Python アプリケーション内で実行されるインプロセス MCP サーバーを作成します。
def create_sdk_mcp_server(
    name: str,
    version: str = "1.0.0",
    tools: list[SdkMcpTool[Any]] | None = None
) -> McpSdkServerConfig

パラメータ

パラメータデフォルト説明
namestr-サーバーの一意識別子
versionstr"1.0.0"サーバーバージョン文字列
toolslist[SdkMcpTool[Any]] | NoneNone@tool デコレータで作成されたツール関数のリスト

戻り値

ClaudeAgentOptions.mcp_servers に渡すことができる McpSdkServerConfig オブジェクトを返します。

from claude_agent_sdk import tool, create_sdk_mcp_server

@tool("add", "2つの数値を足す", {"a": float, "b": float})
async def add(args):
    return {
        "content": [{
            "type": "text",
            "text": f"合計: {args['a'] + args['b']}"
        }]
    }

@tool("multiply", "2つの数値を掛ける", {"a": float, "b": float})
async def multiply(args):
    return {
        "content": [{
            "type": "text",
            "text": f"積: {args['a'] * args['b']}"
        }]
    }

calculator = create_sdk_mcp_server(
    name="calculator",
    version="2.0.0",
    tools=[add, multiply]  # デコレートされた関数を渡す
)

# Claude で使用
options = ClaudeAgentOptions(
    mcp_servers={"calc": calculator},
    allowed_tools=["mcp__calc__add", "mcp__calc__multiply"]
)

クラス

ClaudeSDKClient

複数の交換にわたって会話セッションを維持します。 これは TypeScript SDK の query() 関数が内部でどのように動作するかの Python 版です - 会話を継続できるクライアントオブジェクトを作成します。

主な機能

  • セッション継続性: 複数の query() 呼び出しにわたって会話コンテキストを維持
  • 同じ会話: Claude はセッション内の以前のメッセージを記憶
  • 割り込みサポート: Claude の実行中に停止可能
  • 明示的ライフサイクル: セッションの開始と終了を制御
  • 応答駆動フロー: 応答に反応してフォローアップを送信可能
  • カスタムツールとフック: カスタムツール(@tool デコレータで作成)とフックをサポート
class ClaudeSDKClient:
    def __init__(self, options: ClaudeAgentOptions | None = None)
    async def connect(self, prompt: str | AsyncIterable[dict] | None = None) -> None
    async def query(self, prompt: str | AsyncIterable[dict], session_id: str = "default") -> None
    async def receive_messages(self) -> AsyncIterator[Message]
    async def receive_response(self) -> AsyncIterator[Message]
    async def interrupt(self) -> None
    async def disconnect(self) -> None

メソッド

メソッド説明
__init__(options)オプションの設定でクライアントを初期化
connect(prompt)オプションの初期プロンプトまたはメッセージストリームで Claude に接続
query(prompt, session_id)ストリーミングモードで新しいリクエストを送信
receive_messages()Claude からのすべてのメッセージを非同期イテレータとして受信
receive_response()ResultMessage を含むまでのメッセージを受信
interrupt()割り込み信号を送信(ストリーミングモードでのみ動作)
disconnect()Claude から切断

コンテキストマネージャーサポート

クライアントは自動接続管理のための非同期コンテキストマネージャーとして使用できます:
async with ClaudeSDKClient() as client:
    await client.query("こんにちは Claude")
    async for message in client.receive_response():
        print(message)
重要: メッセージを反復処理する際は、早期終了のために break を使用することは避けてください。これは asyncio のクリーンアップ問題を引き起こす可能性があります。代わりに、反復を自然に完了させるか、必要なものを見つけたときを追跡するフラグを使用してください。

例 - 会話の継続

import asyncio
from claude_agent_sdk import ClaudeSDKClient, AssistantMessage, TextBlock, ResultMessage

async def main():
    async with ClaudeSDKClient() as client:
        # 最初の質問
        await client.query("フランスの首都は何ですか?")
        
        # 応答を処理
        async for message in client.receive_response():
            if isinstance(message, AssistantMessage):
                for block in message.content:
                    if isinstance(block, TextBlock):
                        print(f"Claude: {block.text}")
        
        # フォローアップ質問 - Claude は以前のコンテキストを記憶している
        await client.query("その都市の人口は何人ですか?")
        
        async for message in client.receive_response():
            if isinstance(message, AssistantMessage):
                for block in message.content:
                    if isinstance(block, TextBlock):
                        print(f"Claude: {block.text}")
        
        # もう一つのフォローアップ - まだ同じ会話内
        await client.query("そこにある有名なランドマークは何ですか?")
        
        async for message in client.receive_response():
            if isinstance(message, AssistantMessage):
                for block in message.content:
                    if isinstance(block, TextBlock):
                        print(f"Claude: {block.text}")

asyncio.run(main())

例 - ClaudeSDKClient でのストリーミング入力

import asyncio
from claude_agent_sdk import ClaudeSDKClient

async def message_stream():
    """メッセージを動的に生成します。"""
    yield {"type": "text", "text": "以下のデータを分析してください:"}
    await asyncio.sleep(0.5)
    yield {"type": "text", "text": "温度: 25°C"}
    await asyncio.sleep(0.5)
    yield {"type": "text", "text": "湿度: 60%"}
    await asyncio.sleep(0.5)
    yield {"type": "text", "text": "どのようなパターンが見えますか?"}

async def main():
    async with ClaudeSDKClient() as client:
        # Claude に入力をストリーミング
        await client.query(message_stream())
        
        # 応答を処理
        async for message in client.receive_response():
            print(message)
        
        # 同じセッションでフォローアップ
        await client.query("これらの測定値について心配すべきでしょうか?")
        
        async for message in client.receive_response():
            print(message)

asyncio.run(main())

例 - 割り込みの使用

import asyncio
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions

async def interruptible_task():
    options = ClaudeAgentOptions(
        allowed_tools=["Bash"],
        permission_mode="acceptEdits"
    )
    
    async with ClaudeSDKClient(options=options) as client:
        # 長時間実行されるタスクを開始
        await client.query("1から100まで数えてください、ゆっくりと")
        
        # しばらく実行させる
        await asyncio.sleep(2)
        
        # タスクを割り込み
        await client.interrupt()
        print("タスクが割り込まれました!")
        
        # 新しいコマンドを送信
        await client.query("代わりに挨拶だけしてください")
        
        async for message in client.receive_response():
            # 新しい応答を処理
            pass

asyncio.run(interruptible_task())

例 - 高度な権限制御

from claude_agent_sdk import (
    ClaudeSDKClient,
    ClaudeAgentOptions
)

async def custom_permission_handler(
    tool_name: str,
    input_data: dict,
    context: dict
):
    """ツール権限のカスタムロジック。"""

    # システムディレクトリへの書き込みをブロック
    if tool_name == "Write" and input_data.get("file_path", "").startswith("/system/"):
        return {
            "behavior": "deny",
            "message": "システムディレクトリへの書き込みは許可されていません",
            "interrupt": True
        }

    # 機密ファイル操作をリダイレクト
    if tool_name in ["Write", "Edit"] and "config" in input_data.get("file_path", ""):
        safe_path = f"./sandbox/{input_data['file_path']}"
        return {
            "behavior": "allow",
            "updatedInput": {**input_data, "file_path": safe_path}
        }

    # その他はすべて許可
    return {
        "behavior": "allow",
        "updatedInput": input_data
    }

async def main():
    options = ClaudeAgentOptions(
        can_use_tool=custom_permission_handler,
        allowed_tools=["Read", "Write", "Edit"]
    )
    
    async with ClaudeSDKClient(options=options) as client:
        await client.query("システム設定ファイルを更新してください")
        
        async for message in client.receive_response():
            # 代わりにサンドボックスパスを使用
            print(message)

asyncio.run(main())

SdkMcpTool

@tool デコレータで作成された SDK MCP ツールの定義。
@dataclass
class SdkMcpTool(Generic[T]):
    name: str
    description: str
    input_schema: type[T] | dict[str, Any]
    handler: Callable[[T], Awaitable[dict[str, Any]]]
プロパティ説明
namestrツールの一意識別子
descriptionstr人間が読める説明
input_schematype[T] | dict[str, Any]入力検証のスキーマ
handlerCallable[[T], Awaitable[dict[str, Any]]]ツール実行を処理する非同期関数

ClaudeAgentOptions

Claude Code クエリの設定データクラス。
@dataclass
class ClaudeAgentOptions:
    allowed_tools: list[str] = field(default_factory=list)
    max_thinking_tokens: int = 8000
    system_prompt: str | None = None
    mcp_servers: dict[str, McpServerConfig] | str | Path = field(default_factory=dict)
    permission_mode: PermissionMode | None = None
    continue_conversation: bool = False
    resume: str | None = None
    fork_session: bool = False
    max_turns: int | None = None
    disallowed_tools: list[str] = field(default_factory=list)
    model: str | None = None
    permission_prompt_tool_name: str | None = None
    cwd: str | Path | None = None
    settings: str | None = None
    add_dirs: list[str | Path] = field(default_factory=list)
    env: dict[str, str] = field(default_factory=dict)
    extra_args: dict[str, str | None] = field(default_factory=dict)
プロパティデフォルト説明
allowed_toolslist[str][]許可されたツール名のリスト
max_thinking_tokensint8000思考プロセスの最大トークン数
system_promptstr | NoneNoneシステムプロンプト設定。カスタムプロンプトには文字列を渡すか、Claude Code のシステムプロンプトにはプリセット形式を使用
mcp_serversdict[str, McpServerConfig] | str | Path{}MCP サーバー設定または設定ファイルへのパス
permission_modePermissionMode | NoneNoneツール使用の権限モード
continue_conversationboolFalse最新の会話を継続
resumestr | NoneNone再開するセッション ID
fork_sessionboolFalseresume で再開する際、元のセッションを継続する代わりに新しいセッション ID にフォーク
max_turnsint | NoneNone最大会話ターン数
disallowed_toolslist[str][]禁止されたツール名のリスト
modelstr | NoneNone使用する Claude モデル
permission_prompt_tool_namestr | NoneNone権限プロンプト用の MCP ツール名
cwdstr | Path | NoneNone現在の作業ディレクトリ
settingsstr | NoneNone設定ファイルへのパス
add_dirslist[str | Path][]Claude がアクセスできる追加ディレクトリ
extra_argsdict[str, str | None]{}CLI に直接渡す追加の CLI 引数
can_use_toolCanUseTool | NoneNoneツール権限コールバック関数
hooksdict[HookEvent, list[HookMatcher]] | NoneNoneイベントをインターセプトするためのフック設定
agentsdict[str, AgentDefinition] | NoneNoneプログラム的に定義されたサブエージェント
setting_sourceslist[SettingSource] | NoneNone(設定なし)SDK がどのファイルシステム設定を読み込むかを制御。省略時は設定を読み込まない

SettingSource

SDK がファイルシステムベースの設定ソースから設定を読み込む際の制御。
SettingSource = Literal["user", "project", "local"]
説明場所
"user"グローバルユーザー設定~/.claude/settings.json
"project"共有プロジェクト設定(バージョン管理対象).claude/settings.json
"local"ローカルプロジェクト設定(gitignore対象).claude/settings.local.json

デフォルト動作

setting_sources省略または**Noneの場合、SDK はファイルシステム設定を読み込みません**。これにより SDK アプリケーションの分離が提供されます。

setting_sources を使用する理由

すべてのファイルシステム設定を読み込む(レガシー動作):
# SDK v0.0.x のようにすべての設定を読み込む
from claude_agent_sdk import query, ClaudeAgentOptions

async for message in query(
    prompt="このコードを分析してください",
    options=ClaudeAgentOptions(
        setting_sources=["user", "project", "local"]  # すべての設定を読み込む
    )
):
    print(message)
特定の設定ソースのみを読み込む:
# プロジェクト設定のみを読み込み、ユーザーとローカルを無視
async for message in query(
    prompt="CI チェックを実行",
    options=ClaudeAgentOptions(
        setting_sources=["project"]  # .claude/settings.json のみ
    )
):
    print(message)
テストと CI 環境:
# ローカル設定を除外して CI で一貫した動作を保証
async for message in query(
    prompt="テストを実行",
    options=ClaudeAgentOptions(
        setting_sources=["project"],  # チーム共有設定のみ
        permission_mode="bypassPermissions"
    )
):
    print(message)
SDK のみのアプリケーション:
# すべてをプログラム的に定義(デフォルト動作)
# ファイルシステム依存なし - setting_sources はデフォルトで None
async for message in query(
    prompt="この PR をレビュー",
    options=ClaudeAgentOptions(
        # setting_sources=None がデフォルト、指定不要
        agents={ /* ... */ },
        mcp_servers={ /* ... */ },
        allowed_tools=["Read", "Grep", "Glob"]
    )
):
    print(message)

設定の優先順位

複数のソースが読み込まれる場合、設定はこの優先順位でマージされます(高い順):
  1. ローカル設定(.claude/settings.local.json
  2. プロジェクト設定(.claude/settings.json
  3. ユーザー設定(~/.claude/settings.json
プログラム的オプション(agentsallowed_tools など)は常にファイルシステム設定を上書きします。

AgentDefinition

プログラム的に定義されたサブエージェントの設定。
@dataclass
class AgentDefinition:
    description: str
    prompt: str
    tools: list[str] | None = None
    model: Literal["sonnet", "opus", "haiku", "inherit"] | None = None
フィールド必須説明
descriptionはいこのエージェントをいつ使用するかの自然言語説明
toolsいいえ許可されたツール名の配列。省略時はすべてのツールを継承
promptはいエージェントのシステムプロンプト
modelいいえこのエージェントのモデル上書き。省略時はメインモデルを使用

PermissionMode

ツール実行を制御するための権限モード。
PermissionMode = Literal[
    "default",           # 標準権限動作
    "acceptEdits",       # ファイル編集を自動承認
    "plan",              # 計画モード - 実行なし
    "bypassPermissions"  # すべての権限チェックをバイパス(注意して使用)
]

McpSdkServerConfig

create_sdk_mcp_server() で作成された SDK MCP サーバーの設定。
class McpSdkServerConfig(TypedDict):
    type: Literal["sdk"]
    name: str
    instance: Any  # MCP サーバーインスタンス

McpServerConfig

MCP サーバー設定のユニオン型。
McpServerConfig = McpStdioServerConfig | McpSSEServerConfig | McpHttpServerConfig | McpSdkServerConfig

McpStdioServerConfig

class McpStdioServerConfig(TypedDict):
    type: NotRequired[Literal["stdio"]]  # 後方互換性のためオプション
    command: str
    args: NotRequired[list[str]]
    env: NotRequired[dict[str, str]]

McpSSEServerConfig

class McpSSEServerConfig(TypedDict):
    type: Literal["sse"]
    url: str
    headers: NotRequired[dict[str, str]]

McpHttpServerConfig

class McpHttpServerConfig(TypedDict):
    type: Literal["http"]
    url: str
    headers: NotRequired[dict[str, str]]

メッセージ型

Message

すべての可能なメッセージのユニオン型。
Message = UserMessage | AssistantMessage | SystemMessage | ResultMessage

UserMessage

ユーザー入力メッセージ。
@dataclass
class UserMessage:
    content: str | list[ContentBlock]

AssistantMessage

コンテンツブロックを持つアシスタント応答メッセージ。
@dataclass
class AssistantMessage:
    content: list[ContentBlock]
    model: str

SystemMessage

メタデータを持つシステムメッセージ。
@dataclass
class SystemMessage:
    subtype: str
    data: dict[str, Any]

ResultMessage

コストと使用情報を持つ最終結果メッセージ。
@dataclass
class ResultMessage:
    subtype: str
    duration_ms: int
    duration_api_ms: int
    is_error: bool
    num_turns: int
    session_id: str
    total_cost_usd: float | None = None
    usage: dict[str, Any] | None = None
    result: str | None = None

コンテンツブロック型

ContentBlock

すべてのコンテンツブロックのユニオン型。
ContentBlock = TextBlock | ThinkingBlock | ToolUseBlock | ToolResultBlock

TextBlock

テキストコンテンツブロック。
@dataclass
class TextBlock:
    text: str

ThinkingBlock

思考コンテンツブロック(思考機能を持つモデル用)。
@dataclass
class ThinkingBlock:
    thinking: str
    signature: str

ToolUseBlock

ツール使用リクエストブロック。
@dataclass
class ToolUseBlock:
    id: str
    name: str
    input: dict[str, Any]

ToolResultBlock

ツール実行結果ブロック。
@dataclass
class ToolResultBlock:
    tool_use_id: str
    content: str | list[dict[str, Any]] | None = None
    is_error: bool | None = None

エラー型

ClaudeSDKError

すべての SDK エラーのベース例外クラス。
class ClaudeSDKError(Exception):
    """Claude SDK のベースエラー。"""

CLINotFoundError

Claude Code CLI がインストールされていないか見つからない場合に発生。
class CLINotFoundError(CLIConnectionError):
    def __init__(self, message: str = "Claude Code not found", cli_path: str | None = None):
        """
        Args:
            message: エラーメッセージ(デフォルト: "Claude Code not found")
            cli_path: 見つからなかった CLI へのオプションパス
        """

CLIConnectionError

Claude Code への接続が失敗した場合に発生。
class CLIConnectionError(ClaudeSDKError):
    """Claude Code への接続に失敗しました。"""

ProcessError

Claude Code プロセスが失敗した場合に発生。
class ProcessError(ClaudeSDKError):
    def __init__(self, message: str, exit_code: int | None = None, stderr: str | None = None):
        self.exit_code = exit_code
        self.stderr = stderr

CLIJSONDecodeError

JSON パースが失敗した場合に発生。
class CLIJSONDecodeError(ClaudeSDKError):
    def __init__(self, line: str, original_error: Exception):
        """
        Args:
            line: パースに失敗した行
            original_error: 元の JSON デコード例外
        """
        self.line = line
        self.original_error = original_error

フック型

HookEvent

サポートされるフックイベント型。セットアップの制限により、Python SDK は SessionStart、SessionEnd、Notification フックをサポートしていません。
HookEvent = Literal[
    "PreToolUse",      # ツール実行前に呼び出し
    "PostToolUse",     # ツール実行後に呼び出し
    "UserPromptSubmit", # ユーザーがプロンプトを送信時に呼び出し
    "Stop",            # 実行停止時に呼び出し
    "SubagentStop",    # サブエージェント停止時に呼び出し
    "PreCompact"       # メッセージ圧縮前に呼び出し
]

HookCallback

フックコールバック関数の型定義。
HookCallback = Callable[
    [dict[str, Any], str | None, HookContext],
    Awaitable[dict[str, Any]]
]
パラメータ:
  • input_data: フック固有の入力データ(フックドキュメント参照)
  • tool_use_id: オプションのツール使用識別子(ツール関連フック用)
  • context: 追加情報を持つフックコンテキスト
以下を含む辞書を返します:
  • decision: アクションをブロックするには "block"
  • systemMessage: トランスクリプトに追加するシステムメッセージ
  • hookSpecificOutput: フック固有の出力データ

HookContext

フックコールバックに渡されるコンテキスト情報。
@dataclass
class HookContext:
    signal: Any | None = None  # 将来: 中止シグナルサポート

HookMatcher

特定のイベントやツールにフックをマッチングするための設定。
@dataclass
class HookMatcher:
    matcher: str | None = None        # マッチするツール名またはパターン(例:"Bash"、"Write|Edit")
    hooks: list[HookCallback] = field(default_factory=list)  # 実行するコールバックのリスト

フック使用例

from claude_agent_sdk import query, ClaudeAgentOptions, HookMatcher, HookContext
from typing import Any

async def validate_bash_command(
    input_data: dict[str, Any],
    tool_use_id: str | None,
    context: HookContext
) -> dict[str, Any]:
    """危険な bash コマンドを検証し、潜在的にブロックします。"""
    if input_data['tool_name'] == 'Bash':
        command = input_data['tool_input'].get('command', '')
        if 'rm -rf /' in command:
            return {
                'hookSpecificOutput': {
                    'hookEventName': 'PreToolUse',
                    'permissionDecision': 'deny',
                    'permissionDecisionReason': '危険なコマンドがブロックされました'
                }
            }
    return {}

async def log_tool_use(
    input_data: dict[str, Any],
    tool_use_id: str | None,
    context: HookContext
) -> dict[str, Any]:
    """監査のためにすべてのツール使用をログに記録します。"""
    print(f"使用されたツール: {input_data.get('tool_name')}")
    return {}

options = ClaudeAgentOptions(
    hooks={
        'PreToolUse': [
            HookMatcher(matcher='Bash', hooks=[validate_bash_command]),
            HookMatcher(hooks=[log_tool_use])  # すべてのツールに適用
        ],
        'PostToolUse': [
            HookMatcher(hooks=[log_tool_use])
        ]
    }
)

async for message in query(
    prompt="このコードベースを分析してください",
    options=options
):
    print(message)

ツール入力/出力型

すべての組み込み Claude Code ツールの入力/出力スキーマのドキュメント。Python SDK はこれらを型としてエクスポートしませんが、メッセージ内のツール入力と出力の構造を表します。

Task

ツール名: Task 入力:
{
    "description": str,      # タスクの短い(3-5語)説明
    "prompt": str,           # エージェントが実行するタスク
    "subagent_type": str     # 使用する専門エージェントの種類
}
出力:
{
    "result": str,                    # サブエージェントからの最終結果
    "usage": dict | None,             # トークン使用統計
    "total_cost_usd": float | None,  # USD での総コスト
    "duration_ms": int | None         # 実行時間(ミリ秒)
}

Bash

ツール名: Bash 入力:
{
    "command": str,                  # 実行するコマンド
    "timeout": int | None,           # オプションのタイムアウト(ミリ秒、最大600000)
    "description": str | None,       # 明確で簡潔な説明(5-10語)
    "run_in_background": bool | None # バックグラウンドで実行するには true に設定
}
出力:
{
    "output": str,              # stdout と stderr の結合出力
    "exitCode": int,            # コマンドの終了コード
    "killed": bool | None,      # タイムアウトによりコマンドが強制終了されたかどうか
    "shellId": str | None       # バックグラウンドプロセス用のシェル ID
}

Edit

ツール名: Edit 入力:
{
    "file_path": str,           # 変更するファイルの絶対パス
    "old_string": str,          # 置換する文字列
    "new_string": str,          # 置換後の文字列
    "replace_all": bool | None  # すべての出現を置換(デフォルト False)
}
出力:
{
    "message": str,      # 確認メッセージ
    "replacements": int, # 実行された置換数
    "file_path": str     # 編集されたファイルパス
}

MultiEdit

ツール名: MultiEdit 入力:
{
    "file_path": str,     # 変更するファイルの絶対パス
    "edits": [            # 編集操作の配列
        {
            "old_string": str,          # 置換する文字列
            "new_string": str,          # 置換後の文字列
            "replace_all": bool | None  # すべての出現を置換
        }
    ]
}
出力:
{
    "message": str,       # 成功メッセージ
    "edits_applied": int, # 適用された編集の総数
    "file_path": str      # 編集されたファイルパス
}

Read

ツール名: Read 入力:
{
    "file_path": str,       # 読み取るファイルの絶対パス
    "offset": int | None,   # 読み取りを開始する行番号
    "limit": int | None     # 読み取る行数
}
出力(テキストファイル):
{
    "content": str,         # 行番号付きのファイル内容
    "total_lines": int,     # ファイルの総行数
    "lines_returned": int   # 実際に返された行数
}
出力(画像):
{
    "image": str,       # Base64 エンコードされた画像データ
    "mime_type": str,   # 画像の MIME タイプ
    "file_size": int    # ファイルサイズ(バイト)
}

Write

ツール名: Write 入力:
{
    "file_path": str,  # 書き込むファイルの絶対パス
    "content": str     # ファイルに書き込む内容
}
出力:
{
    "message": str,        # 成功メッセージ
    "bytes_written": int,  # 書き込まれたバイト数
    "file_path": str       # 書き込まれたファイルパス
}

Glob

ツール名: Glob 入力:
{
    "pattern": str,       # ファイルにマッチする glob パターン
    "path": str | None    # 検索するディレクトリ(デフォルトは cwd)
}
出力:
{
    "matches": list[str],  # マッチするファイルパスの配列
    "count": int,          # 見つかったマッチ数
    "search_path": str     # 使用された検索ディレクトリ
}

Grep

ツール名: Grep 入力:
{
    "pattern": str,                    # 正規表現パターン
    "path": str | None,                # 検索するファイルまたはディレクトリ
    "glob": str | None,                # ファイルをフィルタする glob パターン
    "type": str | None,                # 検索するファイルタイプ
    "output_mode": str | None,         # "content"、"files_with_matches"、または "count"
    "-i": bool | None,                 # 大文字小文字を区別しない検索
    "-n": bool | None,                 # 行番号を表示
    "-B": int | None,                  # 各マッチの前に表示する行数
    "-A": int | None,                  # 各マッチの後に表示する行数
    "-C": int | None,                  # 前後に表示する行数
    "head_limit": int | None,          # 出力を最初の N 行/エントリに制限
    "multiline": bool | None           # マルチラインモードを有効化
}
出力(content モード):
{
    "matches": [
        {
            "file": str,
            "line_number": int | None,
            "line": str,
            "before_context": list[str] | None,
            "after_context": list[str] | None
        }
    ],
    "total_matches": int
}
出力(files_with_matches モード):
{
    "files": list[str],  # マッチを含むファイル
    "count": int         # マッチを含むファイル数
}

NotebookEdit

ツール名: NotebookEdit 入力:
{
    "notebook_path": str,                     # Jupyter ノートブックへの絶対パス
    "cell_id": str | None,                    # 編集するセルの ID
    "new_source": str,                        # セルの新しいソース
    "cell_type": "code" | "markdown" | None,  # セルのタイプ
    
    "edit_mode": "replace" | "insert" | "delete" | None  # 編集操作タイプ
}
出力:
{
    "message": str, # 成功メッセージ
    "edit_type": "replaced" | "inserted" | "deleted",  # 実行された編集のタイプ
    "cell_id": str | None,                       # 影響を受けたセル ID
    "total_cells": int                           # 編集後のノートブックの総セル数
}

WebFetch

ツール名: WebFetch 入力:
{
    "url": str,     # コンテンツを取得する URL
    "prompt": str   # 取得したコンテンツに対して実行するプロンプト
}
出力:
{
    "response": str,           # プロンプトに対する AI モデルの応答
    "url": str,                # 取得された URL
    "final_url": str | None,   # リダイレクト後の最終 URL
    "status_code": int | None  # HTTP ステータスコード
}

WebSearch

ツール名: WebSearch 入力:
{
    "query": str,                        # 使用する検索クエリ
    "allowed_domains": list[str] | None, # これらのドメインからの結果のみを含める
    "blocked_domains": list[str] | None  # これらのドメインからの結果を含めない
}
出力:
{
    "results": [
        {
            "title": str,
            "url": str,
            "snippet": str,
            "metadata": dict | None
        }
    ],
    "total_results": int,
    "query": str
}

TodoWrite

ツール名: TodoWrite 入力:
{
    "todos": [
        {
            "content": str, # タスクの説明
            "status": "pending" | "in_progress" | "completed",  # タスクのステータス
            "activeForm": str                            # 説明のアクティブフォーム
        }
    ]
}
出力:
{
    "message": str,  # 成功メッセージ
    "stats": {
        "total": int,
        "pending": int,
        "in_progress": int,
        "completed": int
    }
}

BashOutput

ツール名: BashOutput 入力:
{
    "bash_id": str,       # バックグラウンドシェルの ID
    "filter": str | None  # 出力行をフィルタするオプションの正規表現
}
出力:
{
    "output": str, # 最後のチェック以降の新しい出力
    "status": "running" | "completed" | "failed",       # 現在のシェルステータス
    "exitCode": int | None # 完了時の終了コード
}

KillBash

ツール名: KillBash 入力:
{
    "shell_id": str  # 強制終了するバックグラウンドシェルの ID
}
出力:
{
    "message": str,  # 成功メッセージ
    "shell_id": str  # 強制終了されたシェルの ID
}

ExitPlanMode

ツール名: ExitPlanMode 入力:
{
    "plan": str  # ユーザーが承認のために実行する計画
}
出力:
{
    "message": str,          # 確認メッセージ
    "approved": bool | None  # ユーザーが計画を承認したかどうか
}

ListMcpResources

ツール名: ListMcpResources 入力:
{
    "server": str | None  # リソースをフィルタするオプションのサーバー名
}
出力:
{
    "resources": [
        {
            "uri": str,
            "name": str,
            "description": str | None,
            "mimeType": str | None,
            "server": str
        }
    ],
    "total": int
}

ReadMcpResource

ツール名: ReadMcpResource 入力:
{
    "server": str,  # MCP サーバー名
    "uri": str      # 読み取るリソース URI
}
出力:
{
    "contents": [
        {
            "uri": str,
            "mimeType": str | None,
            "text": str | None,
            "blob": str | None
        }
    ],
    "server": str
}

ClaudeSDKClient での高度な機能

継続的な会話インターフェースの構築

from claude_agent_sdk import ClaudeSDKClient, ClaudeCodeOptions, AssistantMessage, TextBlock
import asyncio

class ConversationSession:
    """Claude との単一の会話セッションを維持します。"""
    
    def __init__(self, options: ClaudeCodeOptions = None):
        self.client = ClaudeSDKClient(options)
        self.turn_count = 0
    
    async def start(self):
        await self.client.connect()
        print("会話セッションを開始します。Claude はコンテキストを記憶します。")
        print("コマンド: 'exit' で終了、'interrupt' で現在のタスクを停止、'new' で新しいセッション")
        
        while True:
            user_input = input(f"\n[ターン {self.turn_count + 1}] あなた: ")
            
            if user_input.lower() == 'exit':
                break
            elif user_input.lower() == 'interrupt':
                await self.client.interrupt()
                print("タスクが割り込まれました!")
                continue
            elif user_input.lower() == 'new':
                # 新しいセッションのために切断して再接続
                await self.client.disconnect()
                await self.client.connect()
                self.turn_count = 0
                print("新しい会話セッションを開始しました(以前のコンテキストはクリアされました)")
                continue
            
            # メッセージを送信 - Claude はこのセッションの以前のすべてのメッセージを記憶
            await self.client.query(user_input)
            self.turn_count += 1
            
            # 応答を処理
            print(f"[ターン {self.turn_count}] Claude: ", end="")
            async for message in self.client.receive_response():
                if isinstance(message, AssistantMessage):
                    for block in message.content:
                        if isinstance(block, TextBlock):
                            print(block.text, end="")
            print()  # 応答後の改行
        
        await self.client.disconnect()
        print(f"会話が {self.turn_count} ターン後に終了しました。")

async def main():
    options = ClaudeCodeOptions(
        allowed_tools=["Read", "Write", "Bash"],
        permission_mode="acceptEdits"
    )
    session = ConversationSession(options)
    await session.start()

# 会話例:
# ターン 1 - あなた: "hello.py というファイルを作成してください"
# ターン 1 - Claude: "hello.py ファイルを作成します..."
# ターン 2 - あなた: "そのファイルには何が入っていますか?"  
# ターン 2 - Claude: "先ほど作成した hello.py ファイルには..." (記憶している!)
# ターン 3 - あなた: "それに main 関数を追加してください"
# ターン 3 - Claude: "hello.py に main 関数を追加します..." (どのファイルかを知っている!)

asyncio.run(main())

動作変更のためのフックの使用

from claude_agent_sdk import (
    ClaudeSDKClient,
    ClaudeAgentOptions,
    HookMatcher,
    HookContext
)
import asyncio
from typing import Any

async def pre_tool_logger(
    input_data: dict[str, Any],
    tool_use_id: str | None,
    context: HookContext
) -> dict[str, Any]:
    """実行前にすべてのツール使用をログに記録します。"""
    tool_name = input_data.get('tool_name', 'unknown')
    print(f"[PRE-TOOL] 使用予定: {tool_name}")

    # ここでツール実行を変更またはブロックできます
    if tool_name == "Bash" and "rm -rf" in str(input_data.get('tool_input', {})):
        return {
            'hookSpecificOutput': {
                'hookEventName': 'PreToolUse',
                'permissionDecision': 'deny',
                'permissionDecisionReason': '危険なコマンドがブロックされました'
            }
        }
    return {}

async def post_tool_logger(
    input_data: dict[str, Any],
    tool_use_id: str | None,
    context: HookContext
) -> dict[str, Any]:
    """ツール実行後に結果をログに記録します。"""
    tool_name = input_data.get('tool_name', 'unknown')
    print(f"[POST-TOOL] 完了: {tool_name}")
    return {}

async def user_prompt_modifier(
    input_data: dict[str, Any],
    tool_use_id: str | None,
    context: HookContext
) -> dict[str, Any]:
    """ユーザープロンプトにコンテキストを追加します。"""
    original_prompt = input_data.get('prompt', '')

    # すべてのプロンプトにタイムスタンプを追加
    from datetime import datetime
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

    return {
        'hookSpecificOutput': {
            'hookEventName': 'UserPromptSubmit',
            'updatedPrompt': f"[{timestamp}] {original_prompt}"
        }
    }

async def main():
    options = ClaudeAgentOptions(
        hooks={
            'PreToolUse': [
                HookMatcher(hooks=[pre_tool_logger]),
                HookMatcher(matcher='Bash', hooks=[pre_tool_logger])
            ],
            'PostToolUse': [
                HookMatcher(hooks=[post_tool_logger])
            ],
            'UserPromptSubmit': [
                HookMatcher(hooks=[user_prompt_modifier])
            ]
        },
        allowed_tools=["Read", "Write", "Bash"]
    )
    
    async with ClaudeSDKClient(options=options) as client:
        await client.query("現在のディレクトリのファイルをリストしてください")
        
        async for message in client.receive_response():
            # フックが自動的にツール使用をログに記録
            pass

asyncio.run(main())

リアルタイム進捗監視

from claude_agent_sdk import (
    ClaudeSDKClient,
    ClaudeAgentOptions,
    AssistantMessage,
    ToolUseBlock,
    ToolResultBlock,
    TextBlock
)
import asyncio

async def monitor_progress():
    options = ClaudeAgentOptions(
        allowed_tools=["Write", "Bash"],
        permission_mode="acceptEdits"
    )
    
    async with ClaudeSDKClient(options=options) as client:
        await client.query(
            "異なるソートアルゴリズムで5つの Python ファイルを作成してください"
        )
        
        # リアルタイムで進捗を監視
        files_created = []
        async for message in client.receive_messages():
            if isinstance(message, AssistantMessage):
                for block in message.content:
                    if isinstance(block, ToolUseBlock):
                        if block.name == "Write":
                            file_path = block.input.get("file_path", "")
                            print(f"🔨 作成中: {file_path}")
                    elif isinstance(block, ToolResultBlock):
                        print(f"✅ ツール実行完了")
                    elif isinstance(block, TextBlock):
                        print(f"💭 Claude の発言: {block.text[:100]}...")
            
            # 最終結果を受信したかチェック
            if hasattr(message, 'subtype') and message.subtype in ['success', 'error']:
                print(f"\n🎯 タスク完了!")
                break

asyncio.run(monitor_progress())

使用例

基本的なファイル操作(query を使用)

from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage, ToolUseBlock
import asyncio

async def create_project():
    options = ClaudeAgentOptions(
        allowed_tools=["Read", "Write", "Bash"],
        permission_mode='acceptEdits',
        cwd="/home/user/project"
    )
    
    async for message in query(
        prompt="setup.py を含む Python プロジェクト構造を作成してください",
        options=options
    ):
        if isinstance(message, AssistantMessage):
            for block in message.content:
                if isinstance(block, ToolUseBlock):
                    print(f"ツールを使用: {block.name}")

asyncio.run(create_project())

エラーハンドリング

from claude_agent_sdk import (
    query,
    CLINotFoundError,
    ProcessError,
    CLIJSONDecodeError
)

try:
    async for message in query(prompt="こんにちは"):
        print(message)
except CLINotFoundError:
    print("Claude Code をインストールしてください: npm install -g @anthropic-ai/claude-code")
except ProcessError as e:
    print(f"プロセスが終了コード {e.exit_code} で失敗しました")
except CLIJSONDecodeError as e:
    print(f"応答のパースに失敗しました: {e}")

クライアントでのストリーミングモード

from claude_agent_sdk import ClaudeSDKClient
import asyncio

async def interactive_session():
    async with ClaudeSDKClient() as client:
        # 初期メッセージを送信
        await client.query("天気はどうですか?")
        
        # 応答を処理
        async for msg in client.receive_response():
            print(msg)
        
        # フォローアップを送信
        await client.query("それについてもっと教えてください")
        
        # フォローアップ応答を処理
        async for msg in client.receive_response():
            print(msg)

asyncio.run(interactive_session())

ClaudeSDKClient でのカスタムツールの使用

from claude_agent_sdk import (
    ClaudeSDKClient,
    ClaudeAgentOptions,
    tool,
    create_sdk_mcp_server,
    AssistantMessage,
    TextBlock
)
import asyncio
from typing import Any

# @tool デコレータでカスタムツールを定義
@tool("calculate", "数学計算を実行", {"expression": str})
async def calculate(args: dict[str, Any]) -> dict[str, Any]:
    try:
        result = eval(args["expression"], {"__builtins__": {}})
        return {
            "content": [{
                "type": "text",
                "text": f"結果: {result}"
            }]
        }
    except Exception as e:
        return {
            "content": [{
                "type": "text",
                "text": f"エラー: {str(e)}"
            }],
            "is_error": True
        }

@tool("get_time", "現在時刻を取得", {})
async def get_time(args: dict[str, Any]) -> dict[str, Any]:
    from datetime import datetime
    current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    return {
        "content": [{
            "type": "text",
            "text": f"現在時刻: {current_time}"
        }]
    }

async def main():
    # カスタムツールで SDK MCP サーバーを作成
    my_server = create_sdk_mcp_server(
        name="utilities",
        version="1.0.0",
        tools=[calculate, get_time]
    )

    # サーバーでオプションを設定
    options = ClaudeAgentOptions(
        mcp_servers={"utils": my_server},
        allowed_tools=[
            "mcp__utils__calculate",
            "mcp__utils__get_time"
        ]
    )
    
    # インタラクティブなツール使用のために ClaudeSDKClient を使用
    async with ClaudeSDKClient(options=options) as client:
        await client.query("123 × 456 は何ですか?")
        
        # 計算応答を処理
        async for message in client.receive_response():
            if isinstance(message, AssistantMessage):
                for block in message.content:
                    if isinstance(block, TextBlock):
                        print(f"計算: {block.text}")
        
        # 時刻クエリでフォローアップ
        await client.query("今何時ですか?")
        
        async for message in client.receive_response():
            if isinstance(message, AssistantMessage):
                for block in message.content:
                    if isinstance(block, TextBlock):
                        print(f"時刻: {block.text}")

asyncio.run(main())

関連項目