Cloudflare Agents SDK は、AI エージェント 1 体を 1 つの Durable Object(状態を持つ小さなサーバー)として動かす TypeScript の SDK です。Agent クラスを継承するだけで、状態の保存、SQLite、WebSocket でのリアルタイム同期、予約実行が使えます1。この記事では、2026 年 10 月時点の最新版 agents 0.26.0 で最小のエージェントを手で書き、wrangler dev で「状態が残る」「RPC で呼べる」「予約した処理が動く」ことを実際に確かめた手順を紹介します。後半では、LLM や MCP ツールを持たせる方法と、2026 年に増えた Think・Code Mode・PiHarness の使い分け、料金の注意点をまとめます。
Cloudflare Agents SDK は、npm の agents パッケージとして配布されている、状態を持つ AI エージェントのための SDK です。公式ドキュメントは「永続メモリ、リアルタイムの WebSocket 接続、スケジュールされたタスクを持つ、状態のある AI エージェントを作る」ものと説明しています1。ソースは GitHub の cloudflare/agents で公開されています。
仕組みの中心は Durable Objects です。エージェントのクラス 1 つが Durable Object のクラス 1 つに対応し、/agents/{クラス名}/{インスタンス名} の URL ごとに別のインスタンスが立ちます。インスタンスごとに専用の SQLite があるので、ユーザーごと・会話ごとに状態を分けられます。
ブラウザや Node.js のクライアントが Worker の routeAgentRequest を通って、名前ごとに分かれたエージェント(Durable Object)につながり、その中で状態・SQLite・予約実行・LLM 呼び出しを扱う流れ図: 筆者作成
Agents SDK を使うと、次のものを自分で作らずに済みます。
| 機能 | API | 中身 |
|---|
| 状態の保存と同期 | initialState / this.setState() | SQLite に保存し、つながっているクライアントへ自動で配る |
| RPC | @callable() | クライアントから WebSocket 越しにメソッドを呼ぶ |
| SQL | this.sql`...` | インスタンス専用の SQLite に直接クエリ |
| 予約実行 | this.schedule() / scheduleEvery() | 秒数・日時・cron で自分のメソッドを後から呼ぶ |
| HTTP | onRequest() | 普通の HTTP リクエストにも答える |
| チャット | AIChatAgent(@cloudflare/ai-chat) | メッセージの保存・ストリーミング・再接続時の再開 |
| MCP | this.addMcpServer() / createMcpHandler() | MCP サーバーへの接続、MCP サーバーの公開 |
「AI エージェント」と言っても、LLM を呼ぶ部分は Vercel の AI SDK や Workers AI など好きなものを使えます。Agents SDK が受け持つのは、エージェントがどこに住み、何を覚え、いつ動くかという土台です。
2026 年の Agents SDK は、ほぼ毎月マイナーバージョンが上がるほど速く変わっています。npm の公開履歴を数えると、2026 年 1 月から 10 月 2 日までに 77 回のリリースがあり、そのうち 23 回がマイナーバージョンの更新でした。0.4.0(2 月 9 日)から始まり、10 月 2 日に 0.26.0 になっています2。
npm の agents パッケージの月別リリース数(2026 年)データを表で見る
npm の agents パッケージの月別リリース数(2026 年)| 月 | 全リリース(パッチ含む)(回) | x.y.0 のリリース(回) |
|---|
| 1月 | 3 | 0 |
|---|
| 2月 | 9 | 3 |
|---|
| 3月 | 18 | 2 |
|---|
| 4月 | 15 | 4 |
|---|
| 5月 | 8 | 1 |
|---|
| 6月 | 13 | 4 |
|---|
| 7月 | 5 | 3 |
|---|
| 8月 | 2 | 2 |
|---|
| 9月 | 2 | 2 |
|---|
| 10月 | 2 | 2 |
|---|
出典: 筆者集計(元データ: npm registry の agents パッケージの公開日時。10 月は 10/2 まで。2026-10-05 取得)
中でも大きな更新は次の 3 つです。
| 時期 | 版 | 内容 |
|---|
| 2026-07-27 | 0.20.0 | MCP の新仕様 2026-07-28 に対応。Workers が MCP のセッションや Durable Object なしでツールを提供できるようになり、McpAgent は非推奨・機能凍結に3 |
| 2026-08〜09 | 0.22.0〜0.24.0 | Agent が Cloudflare の DurableObject を直接継承する形に整理。スケジューラ・キュー・状態・WebSocket が「Lifecycle capability」という部品に分かれた4 |
| 2026-10-02 | 0.25.0 / 0.26.0 | Pi Durable ハーネスを動かす PiHarness(ベータ)を追加5 |
関心も伸びています。Google トレンド(日本・過去 90 日、2026-10-05 取得)の相対値で、「Cloudflare Workers」は直近 4 週の平均が 2.0、その前の 8 週の平均が 0.8 でした。値は小さいものの上向きです。
いちばん早いのは公式のスターターテンプレートです。チャット画面、Workers AI のモデル、ツール呼び出し、承認つきツール、予約実行、MCP サーバーの接続までが最初から入っています6。
npm create cloudflare@latest -- agents-starter --template cloudflare/agents-starter
cd agents-starter
npm run dev
2026 年 10 月 5 日に create-cloudflare 2.73.2 で作ると、途中で「AI コーディングツールが Cloudflare の API を理解しやすくなるよう AGENTS.md を追加するか」を聞かれました。Claude Code や Codex で開発を続けるなら追加しておくと便利です。
できあがるファイルのうち、エージェントの本体は src/server.ts の 1 ファイルです。
| ファイル | 役割 |
|---|
src/server.ts | AIChatAgent を継承した ChatAgent。モデル呼び出しとツール定義 |
src/app.tsx | useAgentChat を使ったチャット画面(React) |
wrangler.jsonc | Durable Object のバインディング、SQLite のマイグレーション、Workers AI |
作った直後のプロジェクトで npx tsc --noEmit と npx vite build を実行し、どちらもエラーなく通ることを確かめました。
注意点が 2 つあります。1 つ目に、このテンプレートの package.json は "agents": "^0.17.4" です。0.x の ^ は 0.17.x の範囲しか入れないため、最新の 0.26 は入りません。2 つ目に、既定のモデル @cf/moonshotai/kimi-k2.7-code は、Workers Paid プランか AI Gateway のプリペイドクレジットが必要なモデルです7。wrangler.jsonc の Workers AI も "remote": true なので、npm run dev でチャットを動かすには Cloudflare へのログインが要ります。
テンプレートは機能が多く、どこが Agents SDK の役目なのか分かりにくいので、ここでは LLM を使わない最小のエージェントを手で書きます。ToDo を覚えるエージェントで、Cloudflare のアカウントがなくてもローカルで全部動きます。
前提は Node.js 24.6.0、agents 0.26.0、wrangler 4.147.0、TypeScript 7.0.2 です(2026 年 10 月 5 日に筆者が確認)。
mkdir todo-agent && cd todo-agent
npm init -y
npm pkg set type=module
npm i agents@0.26.0
npm i -D wrangler typescript @types/node
エージェントのクラスごとに、Durable Object のバインディングと SQLite のマイグレーションが 1 つずつ要ります6。
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "todo-agent",
"main": "src/server.ts",
"compatibility_date": "2026-10-01",
"compatibility_flags": ["nodejs_compat"],
"durable_objects": {
"bindings": [{ "name": "TodoAgent", "class_name": "TodoAgent" }]
},
"migrations": [{ "tag": "v1", "new_sqlite_classes": ["TodoAgent"] }]
}
書いたら npx wrangler types env.d.ts で Env の型を作ります。
src/server.ts です。状態(ToDo の配列)、RPC(追加・完了)、予約実行、SQL、HTTP をひととおり使っています。
import { Agent, callable, routeAgentRequest } from "agents";
type Todo = { id: string; title: string; done: boolean };
export type TodoState = { todos: Todo[]; updatedAt: string | null };
export class TodoAgent extends Agent<Env, TodoState> {
initialState: TodoState = { todos: [], updatedAt: null };
@callable()
add(title: string) {
const todo = { id: crypto.randomUUID(), title, done: false };
this.setState({
todos: [...this.state.todos, todo],
updatedAt: new Date().toISOString()
});
return todo;
}
@callable()
complete(id: string) {
this.setState({
todos: this.state.todos.map((t) => (t.id === id ? { ...t, done: true } : t)),
updatedAt: new Date().toISOString()
});
}
@callable()
async remindLater(seconds = 60) {
const s = await this.schedule(seconds, "remind", { at: new Date().toISOString() });
return s.id;
}
onStart() {
this.sql`CREATE TABLE IF NOT EXISTS reminders (at TEXT, open INTEGER)`;
}
async remind(payload: { at: string }) {
const open = this.state.todos.filter((t) => !t.done).length;
this.sql`INSERT INTO reminders (at, open) VALUES (${payload.at}, ${open})`;
}
async onRequest(_request: Request) {
const reminders = this.sql<{ at: string; open: number }>`SELECT * FROM reminders`;
return Response.json({ ...this.state, reminders });
}
}
export default {
async fetch(request: Request, env: Env) {
return (
(await routeAgentRequest(request, env)) ??
new Response("Not found", { status: 404 })
);
}
} satisfies ExportedHandler<Env>;
routeAgentRequest が URL を見て、TodoAgent クラスを /agents/todo-agent/... に振り分けます。クラス名はケバブケースに変わる点に注意してください。
tsconfig.json は strict で types に ./env.d.ts を入れた最小の構成です。experimentalDecorators は入れません。@callable() は TC39 標準のデコレーターで動くため、古い形式のデコレーターを有効にすると壊れます。この状態で npx tsc --noEmit と npx wrangler deploy --dry-run が通りました。
npx wrangler dev --port 8799
クライアントは agents/client の AgentClient を使います。ブラウザでも Node.js でも同じように書けます(React なら agents/react の useAgent)。
import { AgentClient } from "agents/client";
const agent = new AgentClient({
agent: "TodoAgent",
name: process.argv[2] ?? "kohei",
host: "localhost:8799",
onStateUpdate: (state) => console.log("state:", state.todos.length, "件")
});
const todo = await agent.call("add", ["記事の図を作る"]);
console.log("added:", todo.title);
await agent.call("complete", [todo.id]);
const id = await agent.call("remindLater", [5]);
console.log("scheduled:", id);
agent.close();
node client.mjs demo で demo という名前のインスタンスを呼び、6 秒待ってから curl で中身を見た実際の出力が次の GIF です。
node client.mjs demo で ToDo を追加・完了して 5 秒後の予約を入れ、curl で状態と予約実行の記録、別名インスタンスが空であることを確かめるターミナル2026-10-05 に筆者の環境で実行した出力
出力から分かることは 3 つです。
setState のたびに onStateUpdate が呼ばれ、クライアントに状態が届いています(state: 1 件)
- 5 秒後に
remind() が動き、SQLite の reminders に 1 行入っています。Durable Object のアラームで動くので、クライアントが切れていても実行されます
- 名前が違う
other のインスタンスは空です。名前ごとに状態が分かれています
さらに wrangler dev を止めて起動し直しても、kohei インスタンスの ToDo はそのまま返ってきました。ローカルでも状態は .wrangler/state の SQLite に保存されています。
本番に出すときは npx wrangler deploy です(この記事ではデプロイしていません)。インスタンスはアクセスされた時点で作られるので、事前にユーザー数ぶん用意する必要はありません。公式ドキュメントは「数千万のインスタンスまでスケールする」と説明しています1。
Workers 自体の作り方やデプロイの基本は「Claude Code で Cloudflare Workers アプリを作る全手順」で詳しく扱っています。
最小のエージェントに LLM を足すときは、用途に合わせて土台のクラスを選びます。2026 年 10 月時点の選択肢は次の 4 つです。
| クラス | パッケージ | 向いている用途 | 状態 |
|---|
Agent | agents | LLM を自分で呼ぶ。チャット以外(バッチ、Webhook、メール) | 安定 |
AIChatAgent | @cloudflare/ai-chat | チャット UI。メッセージ保存とストリーミングの再開が要る | 安定 |
Think | @cloudflare/think | getModel() だけ書けばよい、決め打ちのチャットエージェント | 実験的 |
PiHarness | agents/harness/pi | Pi Durable ハーネスで長く動くエージェント | ベータ5 |
テンプレートの ChatAgent は AIChatAgent を使い、onChatMessage() の中で AI SDK の streamText() を呼んでいます。ツールは AI SDK の tool() で定義し、needsApproval を付けると実行前に人の承認を求められます。
MCP サーバーのツールを使わせるには、エージェントの中で this.addMcpServer(名前, URL) を呼び、this.mcp.getAITools() をツール一覧に混ぜるだけです。0.20.0 からは、相手が MCP 2026-07-28 に対応しているかを server/discover で確かめ、未対応なら従来の initialize の手順に戻ります3。既存の addMcpServer の呼び出しを書き換える必要はありません。
自分で MCP サーバーを公開する側の話は「Cloudflare Workers にリモート MCP サーバーをデプロイする」にまとめました。
ツールが増えてきたら Code Mode も候補です。@cloudflare/codemode を使うと、モデルがツールを 1 つずつ呼ぶ代わりに、ツールを組み合わせるコードを書き、それを隔離された Worker で実行します8。Cloudflare 自身の MCP サーバーがこの方式でトークンを減らしている話は「Cloudflare の MCP サーバー(Code Mode)を Claude Code につなぐ」で扱っています。
Agents SDK は変化が速いので、AI コーディングツールの学習データが古いまま書かせると、存在しない API や非推奨の書き方が出てきます。Cloudflare は対策として、Agents SDK の書き方をまとめたスキルを cloudflare/skills で公開しています9。Claude Code ではプラグインとして入れられます。
/plugin marketplace add cloudflare/skills
/plugin install cloudflare@cloudflare
このプラグインには agents-sdk・durable-objects・wrangler などのスキルと、Cloudflare の MCP サーバーが含まれます。agents-sdk スキルは「学習済みの知識より公式ドキュメントを優先して調べる」よう指示し、機能ごとの公式ページの一覧を持っています。筆者がこの記事を書いたときも、このスキルの一覧から状態・予約実行・Code Mode のページをたどりました。
Claude Code に任せるときは、次の順で頼むと手戻りが少なくなります。
wrangler.jsonc のバインディングとマイグレーションを先に決めさせる
Agent クラスを書かせ、npx wrangler types → npx tsc --noEmit を通させる
wrangler dev を起動し、curl かクライアントのスクリプトで状態・RPC・予約実行を確かめさせる
スキル全般の作り方は「Claude Code のスキル(Skills)の作り方」を参照してください。
tsconfig.json で experimentalDecorators: true にすると @callable() が動きません。Vite を使う構成では、テンプレートのように agents/vite のプラグインを vite.config.ts に入れます。このプラグインがデコレーターの変換を受け持ちます(Vite 標準の Oxc はまだ変換できないため)。
一度デプロイした migrations の tag を書き換えてはいけません。クラスを増やしたら v2 のように新しいタグを足します。クラスごとに、バインディングとマイグレーションが 1 つずつ要ります。
agents はまだ 0.x です。マイナーバージョンの更新で動きが変わることがあります。たとえば 0.25.0 では、newUniqueId() や idFromString() で作った ID のまま非同期の RPC を呼ぶと、最初の呼び出しが失敗するようになりました。エージェントは名前で指定する必要があります4。更新は 1 マイナーずつ、GitHub の CHANGELOG を見ながら進めると安全です。
MCP サーバーを作る McpAgent は 0.20.0 で非推奨・機能凍結になりました3。新しく作るなら createMcpHandler() です。
Agents SDK 自体は無料のライブラリです。費用は Durable Objects(と使えば Workers AI)にかかります。2026 年 10 月時点の Durable Objects(SQLite)の料金は次のとおりです10。
| 項目 | Workers Free | Workers Paid |
|---|
| リクエスト | 10 万/日 | 月 100 万まで込み、以降 100 万あたり $0.15 |
| 実行時間 | 1 万 3,000 GB 秒/日 | 月 40 万 GB 秒まで込み、以降 100 万 GB 秒あたり $12.50 |
| 読んだ行 | 500 万/日 | 月 250 億まで込み、以降 100 万行あたり $0.001 |
| 書いた行 | 10 万/日 | 月 5,000 万まで込み、以降 100 万行あたり $1.00 |
| 保存量 | 合計 5 GB | 月 5 GB まで込み、以降 1 GB-月あたり $0.20 |
受け取る WebSocket のメッセージは 20 件で 1 リクエストとして数えます。また、休止(hibernation)できる状態のオブジェクトは、つながったまま待っている間の実行時間がかかりません10。Workers AI は 1 日 1 万 Neurons まで無料で、それを超えると 1,000 Neurons あたり $0.011 です7。LLM の費用の管理は「Workers AI と AI Gateway で LLM の費用を管理する」で扱っています。
- Cloudflare Agents SDK は、エージェント 1 体を 1 つの Durable Object として動かし、状態・SQLite・WebSocket・予約実行を最初から持たせる SDK
- 最小構成は
Agent の継承、wrangler.jsonc のバインディングとマイグレーション、routeAgentRequest の 3 点。アカウントなしで wrangler dev だけで試せる
- チャットなら
AIChatAgent、手早く作るなら実験的な Think、長く動かすなら PiHarness(ベータ)
- 2026 年は MCP 2026-07-28 対応(0.20.0)など変更が多い。バージョンを固定し、CHANGELOG を読んで 1 つずつ上げる
次は、この記事の TodoAgent に AIChatAgent を組み合わせて、ToDo を会話で操作できるエージェントにしてみてください。
SDK 自体は MIT ライセンスで無料です。動かす Durable Objects には Workers Free でも 1 日 10 万リクエストなどの無料枠があり、小さな試作なら無料枠で動きます10。ただしテンプレートの既定モデル kimi-k2.7-code は有料プランか AI Gateway のクレジットが必要です7。
Agents SDK の Agent は Durable Object そのものです(0.22.0 から DurableObject を直接継承)4。違いは、状態の同期、@callable の RPC、予約実行、URL での振り分け、React のフックを自分で作らずに済む点です。
使えます。LLM の呼び出しは AI SDK などに任せる設計なので、onChatMessage() の中で使うプロバイダーを替えるだけです。テンプレートは Workers AI を使いますが、特定のモデルに縛られていません。
できます。agents/mcp/server の createMcpHandler() に、@modelcontextprotocol/server の McpServer を返す関数を渡します。0.20.0 から MCP 2026-07-28 のステートレスな形で提供でき、従来のクライアントとも互換があります3。
インスタンスごとの Durable Object の SQLite に保存されます。setState() の状態も this.sql で作ったテーブルも同じ SQLite に入り、ローカルの wrangler dev では .wrangler/state に保存されます。