Claude Agent SDKで自作AIエージェント: ツール定義から権限まで実装で学ぶ
Claude Agent SDKで自分専用AIエージェントを作る方法。SDKの位置づけ、ツール定義、エージェントループ、権限設計をコピペで動くTypeScript/Pythonコードで解説。
「Claude Codeみたいなやつ、自分のサービスの中で動かせないの?」
これ、僕が半年前に同僚から受けた質問です。当時の僕は「APIを叩いてツール実行ループを自分で書けばいける」と答えました。実際に書いてみたら、ツールの呼び出し結果をモデルに戻す処理、エラーの握りつぶし、ステップ数の上限——地味なコードが200行を超えて、本題のエージェントに辿り着く前に力尽きました。
その「地味なコード」を、まるごと肩代わりしてくれるのが Claude Agent SDK です。Claude Codeを動かしている中身(ツール群・エージェントループ・権限管理)を、そのままライブラリとして自分のアプリやCIから呼べる。今日はこれを使って、自分専用のAIエージェントをゼロから組み立てます。
外部サービスやデータベースにつなぐMCP連携は別記事(Claude Code MCPサーバーガイド)に譲り、この記事は SDK本体の使い方 ——ツールの定義、ループの回り方、権限の絞り方——に絞ります。
この記事の要点
- Claude Agent SDKは「Claude Codeの中身」をライブラリ化したもの。ツール実行ループを自分で書かずに、自作エージェントを作れる。
- パッケージ名は TypeScriptが
@anthropic-ai/claude-agent-sdk、Pythonがclaude-agent-sdk。古いclaude-code-sdk系の記事は鵜呑みにしない。 - 入口は
query()ひとつ。プロンプトとallowedToolsを渡すだけで、Read/Edit/Bashなどの組み込みツールを使ってモデルが自律的に動く。 - 自分専用の道具は
tool()で定義し、createSdkMcpServer()でまとめてエージェントに渡す。 - 安全の肝は権限。最初は読み取り専用、慣れたら編集を1段ずつ開放。
disallowedToolsで危険操作を名指しで禁止する。
Agent SDKは結局なにをしてくれるのか
ひとことで言うと、エージェントループの肩代わりです。
エージェントループというのは、モデルが「次にどの道具を使うか」を自分で決めて、ファイルを読んだり検索したり編集したりした結果を見て、また次の一手を考える——この往復のことです。人間がコードを書くときの「ファイル開く→直す→テスト走らせる→直す」とほぼ同じ流れを、モデルが回します。
素のAPI(Anthropic Client SDK)でこれをやると、自分で while (stop_reason === "tool_use") のループを書き、ツールを実行し、結果を組み立てて戻す必要があります。Agent SDKはこの輪っかを内側に持っているので、こちらは「ゴール」と「使っていい道具」を渡すだけで済みます。
公式ドキュメントの言葉を借りると、関係はこう整理できます。
| 道具 | 何をする | こんなとき |
|---|---|---|
| Claude Code CLI | 人がターミナルで対話する | 日々の開発、単発の作業 |
| Agent SDK | 自分のアプリ/CIからエージェントを呼ぶ | 本番の自動化、社内ツールへの組み込み |
| Client SDK | API直叩き。ツールループは自前 | ループを完全に自分で制御したいとき |
| Managed Agents | Anthropic側でエージェントとサンドボックスを運用 | サンドボックス運用ごと任せたいとき |
「CLIとSDKは能力が同じで、入口だけ違う」というのが大事なところです。CLIで試したワークフローは、ほぼそのままSDKに移せます。
ひとつ注意点があります。2026年6月15日から、サブスクプランでのAgent SDKおよび claude -p の利用は、対話利用とは別枠の「Agent SDKクレジット」から消費される仕組みに変わります。本番でぶん回す前に、公式のAgent SDK overviewで最新の料金まわりを確認しておくと安全です。
30秒で動く最小エージェント
御託より、まず動かします。Node.jsとAnthropicのAPIキーがあれば、これだけで「カレントディレクトリを調べて答える」エージェントが立ち上がります。
プロジェクトを用意します。
mkdir claude-agent-demo
cd claude-agent-demo
npm init -y
npm install @anthropic-ai/claude-agent-sdk
npm install -D typescript tsx @types/node
APIキーは環境変数で渡します。コードに直書きは絶対にしないでください。
export ANTHROPIC_API_KEY="sk-ant-..."
Windows PowerShellならこうです。
$env:ANTHROPIC_API_KEY = "sk-ant-..."
hello.ts を作ります。
import { query } from "@anthropic-ai/claude-agent-sdk";
// query() がエージェントループそのもの。
// allowedTools で「使ってよい道具」だけを渡す。
for await (const message of query({
prompt: "このディレクトリにどんなファイルがある?種類ごとにまとめて。",
options: {
allowedTools: ["Glob", "Read"], // 読むだけ。書き換えはできない。
maxTurns: 3, // 往復の上限。暴走の保険。
},
})) {
// result メッセージが最終回答。途中経過は別の型で流れてくる。
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}
実行します。
npx tsx hello.ts
Glob でファイル一覧を取り、Read で中身を覗き、まとめて返してくれます。ループも、ツールの呼び出しも、結果の差し戻しも、こちらは1行も書いていません。これがSDKの正体です。
Pythonでも書き味はほぼ同じです。pip install claude-agent-sdk で入れます(Python 3.10以上が必要です)。
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions
async def main():
# TypeScript の allowedTools は、Python では allowed_tools。
async for message in query(
prompt="このディレクトリにどんなファイルがある?種類ごとにまとめて。",
options=ClaudeAgentOptions(
allowed_tools=["Glob", "Read"],
max_turns=3,
),
):
if hasattr(message, "result"):
print(message.result)
asyncio.run(main())
命名がキャメルケース(TS)かスネークケース(Python)かの違いだけ。考え方は完全に共通です。
組み込みツールを把握する
allowedTools に渡す名前は、適当な文字列ではありません。Claude Codeが持っている組み込みツールの名前です。よく使うものを並べます。
| ツール名 | できること | 危険度 |
|---|---|---|
Read | 作業ディレクトリ内のファイルを読む | 低 |
Glob | パターンでファイルを探す(**/*.ts など) | 低 |
Grep | ファイルの中身を正規表現で検索 | 低 |
Write | 新規ファイルを作る | 中 |
Edit | 既存ファイルを書き換える | 中 |
Bash | 任意のコマンドを実行する | 高 |
WebSearch | Webを検索する | 中 |
WebFetch | Webページを取得して読む | 中 |
ポイントは2つあります。ひとつは、何も渡さなければ何もできないこと。allowedTools が空なら、モデルは喋るだけです。もうひとつは、Bash の危険度が頭ひとつ抜けていること。Bash を許すと、テスト実行だけでなく、ファイル削除もデプロイも git push も「候補」に入ってしまいます。後で絞り方を説明します。
組み込みツールに加えて、ファイルベースの設定(CLAUDE.md、.claude/skills/ のスキルなど)もSDKから読み込めます。普段Claude Codeで使っているプロジェクトのルールを、そのままエージェントに引き継げるわけです。
自分専用の道具を tool() で定義する
組み込みツールはファイルとコマンドが中心です。でも本当に欲しいのは「うちのDBから注文を引く」「社内Runbookを返す」みたいな、自分のドメインの道具ですよね。それを作るのが tool() です。
tool() には4つを渡します。名前・説明・入力スキーマ・実処理です。とくに説明は手を抜かないでください。モデルはこの説明文を読んで「いつ使うか」を判断します。説明が雑だと、使うべき場面で使ってくれません。
次は、サービス名から障害対応Runbookを返すだけの、読み取り専用ツールです。本番ではDBや社内Wikiにつなぎますが、まずはローカルのオブジェクトで動かします。入力スキーマは zod で書きます(npm install zod を足してください)。
import {
query,
tool,
createSdkMcpServer,
} from "@anthropic-ai/claude-agent-sdk";
import { z } from "zod";
const runbooks: Record<string, string> = {
billing: "支払い失敗率、Stripe webhook、直近のデプロイを確認する。",
search: "indexの更新時刻、検索APIのタスク状況、レート制限を確認する。",
content: "CMS同期、locale別のslug、OGP画像の有無を確認する。",
};
// 自作ツール。第2引数の「説明」がモデルの判断材料になる。
const lookupRunbook = tool(
"lookup_runbook",
"サービス名から障害対応のRunbookを返す。調査の最初の一手を知りたいときに使う。",
{ service: z.string().min(1).describe("billing / search / content のいずれか") },
async ({ service }) => {
const text = runbooks[service] ?? "該当するRunbookがありません。";
return { content: [{ type: "text", text }] };
},
// 読むだけで壊さない、と注釈で明示しておく。
{ annotations: { readOnlyHint: true, openWorldHint: false } },
);
// ツールをまとめてサーバーにする。
const runbookServer = createSdkMcpServer({
name: "runbook",
version: "1.0.0",
tools: [lookupRunbook],
});
for await (const message of query({
prompt: "contentの公開事故を調べたい。最初の手順を提案して。",
options: {
mcpServers: { runbook: runbookServer },
// 自作ツールは mcp__サーバー名__ツール名 の形で許可する。
allowedTools: ["mcp__runbook__lookup_runbook"],
maxTurns: 3,
},
})) {
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}
ここに 最初の落とし穴 が埋まっています。許可リストに書く名前です。lookup_runbook とそのまま書いても通りません。自作ツールは mcp__runbook__lookup_runbook のように mcp__サーバー名__ツール名 という形で許可する必要があります。僕は初回、ここで小一時間溶かしました。「ツールは定義したのに一向に呼ばれない」ときは、まずこの名前を疑ってください。
readOnlyHint: true の注釈も地味に効きます。これを付けておくと、権限まわりで「このツールは読むだけ」と扱われ、無用な確認が減ります。
編集を任せるなら権限を細く削る
読み取りに慣れたら、次は「直す」まで任せます。ただし、ここからが本番です。
権限設計の基本は3段階で考えると整理しやすいです。
- 読み取り専用:
Read,Glob,Grepだけ。挙動を観察する段階。 - 限定編集:
Editと、用途を絞ったBashを追加。差分を作らせる段階。 - 自動承認: 安全だと確認できた操作だけ
permissionModeで前倒し承認。
次は2段階目のコードです。Edit は許しますが、Bash は npm test だけに限定し、危険な操作は disallowedTools で名指しして塞ぎます。
import { query } from "@anthropic-ai/claude-agent-sdk";
const prompt = [
"src配下の小さなTypeScriptエラーを1つだけ直して。",
"直したら npm test を走らせて、変更点と結果を報告して。",
"大きなリファクタや依存追加はしないこと。",
].join("\n");
for await (const message of query({
prompt,
options: {
cwd: process.cwd(), // 作業ディレクトリを必ず固定する。
allowedTools: [
"Read",
"Glob",
"Grep",
"Edit",
"Bash(npm test)", // Bash全部ではなく、このコマンドだけ。
],
disallowedTools: [
"Bash(git push)", // 危険操作は名指しで禁止。
"Bash(git commit)",
"Bash(rm -rf *)",
],
permissionMode: "default",
maxTurns: 6,
},
})) {
if (message.type === "result") {
console.log(message.subtype, message.result ?? "");
}
}
このコードは「なんでも全自動で直す」ためのものではありません。人間がレビューしやすい小さな差分を、テスト結果つきで作るためのものです。Bash(npm test) という書き方がキモで、Bash とだけ書くと全コマンドが開放されてしまいます。コマンド単位で許可を絞れるのを覚えておいてください。
cwd の指定も忘れずに。これを省くと、エージェントは実行元プロセスの場所で動きます。CI・ローカル・バッチで動かす場合、対象リポジトリを明示しないと「隣のディレクトリを読んでいた」事故が起きます。
permissionMode には default のほか、編集を自動承認する acceptEdits、読み取り系だけに固定する plan などがあります。最初は default のまま、許可ツールで絞るのが安全です。詳しい権限の考え方はClaude Code権限設定ガイドにまとめてあります。
僕がやらかした失敗3つ
正直に書きます。最初に作ったエージェントは事故だらけでした。
ひとつ目は、ツール名のミスマッチ。さっき書いた mcp__ プレフィックスの件です。allowedTools に自作ツールの素の名前を書いて、「定義したのに呼ばれない」と半日悩みました。プレフィックスを付けた瞬間に動きました。
ふたつ目は、Bash を丸ごと許したこと。「テストを走らせたいから」と軽い気持ちで Bash を入れたら、エージェントが調査の途中で git checkout を試みて、未コミットの変更が消えかけました。幸いステージング前で助かりましたが、肝が冷えました。以来、Bash は必ず Bash(コマンド名) の形で、必要なものだけ開放しています。
みっつ目は、maxTurns を付け忘れたこと。曖昧なプロンプトを投げたら、エージェントが「もう少し調べよう」を延々と繰り返し、気づけば想定の何倍ものトークンを消費していました。Agent SDKはツール実行を含むぶん、普通の1リクエストより時間もコストも重くなります。maxTurns と、必要なら maxBudgetUsd(コスト上限)を先に決めておくのが鉄則です。
どんな仕事に向いているか
Agent SDKは、単発の文章生成より「途中で観察して、判断して、結果を確かめる」仕事で輝きます。僕が記事運用と開発で実際に回しているのは、この4つです。
| やること | 使うツール | 成果物 | 注意点 |
|---|---|---|---|
| PRレビューの下読み | Read, Glob, Grep | リスク一覧、確認観点、追加テスト案 | コメント投稿は人が確認してから |
| 小さな修正の自動化 | Read, Edit, Bash(npm test) | 差分、テスト結果、失敗ログ | git push や削除系は禁止 |
| 障害の一次調査 | 自作Runbookツール、ログ検索 | 仮説、関連ログ、次の確認 | 本番操作系は読み取り専用に |
| 多言語記事の品質監査 | Read, Grep | 文字化け、リンク切れ候補、CTA欠落 | 翻訳の自然さは最後に人が読む |
共通するのは「人間が最後にレビューする前提の、下ごしらえ役」だということ。全自動の魔法を狙うより、ここから始めるのが現実的です。日々の運用TipsはClaude Code生産性Tipsも合わせてどうぞ。
よくある質問
Q. Claude Agent SDKと、ふつうのClaude API(Client SDK)は何が違う?
A. Client SDKはAPIを直接叩く道具で、ツール実行のループは自分で書きます。Agent SDKはそのループとツール群が最初から入っていて、query() を呼ぶだけでエージェントが自律的に動きます。「ループを自前で制御したい」ならClient SDK、「Claude Codeの動きをそのまま使いたい」ならAgent SDKです。
Q. パッケージ名が記事によってバラバラなのはなぜ?
A. 以前は @anthropic-ai/claude-code や claude-code-sdk という名前でした。現在の公式はTypeScriptが @anthropic-ai/claude-agent-sdk、Pythonが claude-agent-sdk です。古い記事や生成AIの回答に旧名が出ることがあるので、公式ドキュメントで確認してください。
Q. Claude Code CLIを別途インストールする必要はある? A. TypeScript SDKはプラットフォーム別のClaude Codeバイナリをオプション依存として同梱しているので、通常は不要です。ただしパッケージマネージャがoptional dependenciesを飛ばす設定だと、バイナリが見つからないエラーになります。その場合は依存の入れ方を見直してください。
Q. 外部のデータベースやAPIにつなぎたい。
A. 2通りあります。簡単な道具なら、この記事の tool() でプロセス内に直接定義します。既存のMCPサーバー(DBやブラウザ操作など)につなぐなら mcpServers に登録します。後者の詳しいやり方はClaude Code MCPサーバーガイドにまとめてあります。
Q. PythonとTypeScript、どっちで始めるべき? A. 機能はほぼ同等です。Webアプリやフロント寄りならTypeScript、データ処理やスクリプト寄りならPythonが馴染みます。命名がキャメルケースかスネークケースかの違いくらいで、移植も難しくありません。
この記事で実際に試した結果
今回、公式のAgent SDK overviewとTypeScriptリファレンスを確認しながら、手元で全コードを動かし直しました。いちばん効いたのは、やっぱり 最初の例を読み取り専用にしたことです。Glob と Read だけのエージェントなら、何が起きるか怖くない。挙動が腹落ちしてから tool() で道具を足し、Edit を1段だけ開ける——この順番だと、事故る前に「ここは危ないな」という勘が育ちます。
逆に言うと、最初から Bash 全開のエージェントを作るのは、補助輪なしで坂道を下るようなものです。賢いエージェントを目指す前に、転んでもケガしない権限設計を先に組む。遠回りに見えて、これが結局いちばん速いというのが、半年回してみての実感です。
運用テンプレートやチートシートから固めたい人は教材一覧を、チームで権限・MCP・レビューまで設計したい人は研修・導入相談をのぞいてみてください。
無料PDF: Claude Code はじめてのチートシート
まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。
スパムは送りません。登録情報は厳重に管理します。
Claude Codeを仕事で使える形にしませんか?
まず無料PDFで基本を固め、繰り返し使う作業はGumroad教材へ、チーム導入や権限設計は導入相談へ進めます。
この記事を書いた人
Masa
Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。
関連書籍・参考図書
この記事のテーマに関連する書籍を楽天ブックスで探せます。
※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。
関連記事
Claude Codeのチーム利用でコストが読めない時に作る予算ログ
チーム導入前に、誰が何に使い、どの成果が出たかを見える化する予算ログの作り方。
コミット前の3分チェック: Claude Codeが触った範囲を確認してから確定する
Claude Codeが勝手に広げた変更を、コミット前に3分で見抜く確認手順。差分の範囲、検証ログ、ステージするファイルの絞り込みを順番に解説します。
Claude Codeをチーム導入する前に作る「リスク台帳」の中身
Claude Codeを個人実験で終わらせずチーム導入するための、権限・CI・公開の事故を防ぐリスク台帳の作り方を実例とコードで解説します。