このガイドは、Agents SDK v0.20.0 での MCP SDK v2 ↗ アップグレードを扱います。サーバーを @modelcontextprotocol/server へ移す方法、セッション依存の機能が必要なときだけ一時的なレガシーレーンを使う方法、MCP クライアントの更新方法を説明します。
次の表で移行経路を選びます。
| 現在のサーバー | 移行経路 |
|---|---|
| セッション依存のない SDK v1 サーバー | サーバー定義を SDK v2 ファクトリへ移し、そのファクトリを createMcpHandler に渡します。 |
| セッション依存のある SDK v1 サーバー | SDK v2 ルートを追加します。依存を置き換えるあいだだけ、一時的なレガシーレーンに createLegacyMcpHandler を残します。 |
レガシーのステートフル機能を使わない McpAgent |
SDK v2 ファクトリと createMcpHandler へ直接移行します。 |
レガシーのステートフル機能を使う McpAgent |
ステートレス相当を設計し、ステートレスレーンとレガシーレーンを並行提供し、レガシーレーンを排出します。 |
Agents SDK v0.20.0 は、次の API を非推奨にします。
- SDK v1 サーバーを
createMcpHandlerに渡すこと。サーバーを SDK v2 ファクトリへ移します。セッション依存の動作には、一時的な橋渡しとしてだけcreateLegacyMcpHandlerを使います。このオーバーロードは次のメジャーバージョンで削除予定です。 McpAgent。非推奨で、機能は凍結されています。できるだけ早く移行してください。削除バージョンは未発表です。MCPClientManager.callTool(params, resultSchema, options)とwithX402Client(...).callTool(confirm, params, resultSchema, options)。代わりにcallTool(params, options)またはcallTool(confirm, params, options)を使います。削除バージョンは未発表です。
experimental_createMcpHandler はすでに非推奨で、次のメジャーバージョンで削除予定のままです。その SDK v1 サーバーを SDK v2 ファクトリへ移します。移行中は、一時的なセッション依存レーンにだけ createLegacyMcpHandler を使います。
アプリケーションがインポートする世代の MCP パッケージだけをインストールします。v2 のバージョンは固定してください。
ステートレスサーバーの場合:
npm i agents @modelcontextprotocol/server@2.0.0 zodyarn add agents @modelcontextprotocol/server@2.0.0 zodpnpm add agents @modelcontextprotocol/server@2.0.0 zodbun add agents @modelcontextprotocol/server@2.0.0 zod一時的なレガシーレーンの場合:
npm i agents @modelcontextprotocol/sdk@1.30.0 zodyarn add agents @modelcontextprotocol/sdk@1.30.0 zodpnpm add agents @modelcontextprotocol/sdk@1.30.0 zodbun add agents @modelcontextprotocol/sdk@1.30.0 zodMCP サーバーへ接続する Agent の場合:
npm i agents @modelcontextprotocol/client@2.0.0yarn add agents @modelcontextprotocol/client@2.0.0pnpm add agents @modelcontextprotocol/client@2.0.0bun add agents @modelcontextprotocol/client@2.0.0パッケージマネージャーのピア依存関係の指示に従ってください。正確な MCP バージョンは、それらをサポートする Agents リリースと合わせて更新します。
サーバーがいま SDK v1 をインポートしている、という理由だけで v1 を残さないでください。エンドポイントが次のセッション依存機能のいずれかに依存する場合を除き、SDK v2 ファクトリへ直接移します。
- プロトコルセッション、または渡された
WorkerTransport - トランスポートストレージ、またはイベント再生
- スタンドアロンの GET ストリーム
- プッシュされる elicitation、sampling、roots リクエスト
- HTTP
DELETEによるセッション削除
エンドポイントがこれらの機能を使う場合は、先にステートレスルートをデプロイします。セッション依存を置き換えるあいだだけ SDK v1 ルートを残します。リクエストの振り分けは isLegacyRequest() で行います。手順は ステートレスレーンとレガシーレーンを並行運用する を参照してください。
McpAgent を使わない SDK v1 エンドポイントでは、その一時的なレガシー分岐にだけ createLegacyMcpHandler を使います。クライアントが移行し、既存セッションが排出されたら削除します。
ステートレスの createMcpHandler はファクトリを受け取ります。ファクトリは @modelcontextprotocol/server の McpServer または Server を返します。
-
サーバー登録の変更は、上流の TypeScript SDK v2 移行ガイド ↗ に従います。
-
サーバーを
@modelcontextprotocol/serverからインポートします。 -
サーバーの構築と登録をファクトリへ移します。
-
Worker オブジェクトのデフォルトエクスポートは残します。その
fetch()内でファクトリをcreateMcpHandlerに渡し、返ってきた呼び出し可能オブジェクトをこれまでどおり呼び出します。より低レベルのリクエスト統合にだけ、ハンドラーのfetch(request, options?)メソッドを使います。 -
Agents ハンドラーが返す呼び出し可能オブジェクトをデフォルトエクスポートしないでください。Wrangler は関数のデフォルトエクスポートを
WorkerEntrypointクラスとして解釈します。 -
SDK v1 のトランスポートとセッションオプションを削除します。
-
ステートレスクライアントとレガシークライアントの両方でエンドポイントをテストします。
import { McpServer } from "@modelcontextprotocol/server";
import { createMcpHandler } from "agents/mcp/server";
import { z } from "zod";
function createServer() {
const server = new McpServer({
name: "example-server",
version: "1.0.0",
});
server.registerTool(
"hello",
{
description: "Return a greeting",
inputSchema: { name: z.string().optional() },
},
async ({ name }) => ({
content: [{ type: "text", text: `Hello, ${name ?? "World"}!` }],
}),
);
return server;
}
export default {
fetch(request, env, ctx) {
return createMcpHandler(createServer)(request, env, ctx);
},
};import { McpServer } from "@modelcontextprotocol/server";
import { createMcpHandler } from "agents/mcp/server";
import { z } from "zod";
function createServer() {
const server = new McpServer({
name: "example-server",
version: "1.0.0",
});
server.registerTool(
"hello",
{
description: "Return a greeting",
inputSchema: { name: z.string().optional() },
},
async ({ name }) => ({
content: [{ type: "text", text: `Hello, ${name ?? "World"}!` }],
}),
);
return server;
}
export default {
fetch(request, env, ctx) {
return createMcpHandler(createServer)(request, env, ctx);
},
} satisfies ExportedHandler;Worker のエントリポイントはオブジェクトのままです。変わるのはハンドラーの呼び出しだけです。
// SDK v1: pass a fresh constructed server.
return createMcpHandler(createServer())(request, env, ctx);
// SDK v2: pass the factory itself.
return createMcpHandler(createServer)(request, env, ctx);これを export default createMcpHandler(createServer) に簡略化しないでください。Agents ハンドラーは、別のハンドラー内で合成するために呼び出し可能ですが、Wrangler は関数のデフォルトエクスポートをすべて WorkerEntrypoint クラスとして扱います。
SDK v2 ハンドラーは、MCP リクエストごとにサーバーを 1 つ作成します。並行する Worker リクエストが、接続済みのサーバーインスタンスを共有することはありません。
Agents ラッパーは route、corsOptions、allowedHostnames、allowedOriginHostnames、authContext を追加します。対応する SDK v2 オプションは、上流ハンドラーへそのまま渡します。
よく使うオプションは次のとおりです。
| オプション | 動作 |
|---|---|
route |
正確なリクエストパスを設定します。デフォルトは /mcp です。 |
legacy |
デフォルトではレガシー互換を使います。ステートレス専用エンドポイントでは "reject" にします。 |
responseMode |
自動、JSON、SSE のいずれかの応答処理を選びます。 |
allowedHostnames |
Host ヘッダーを特定のホスト名に制限します。 |
allowedOriginHostnames |
ブラウザーの Origin を制限します。信頼できるミドルウェアが検証する場合は "*" も受け付けます。 |
corsOptions |
CORS 応答ヘッダーを制御します。削除するには false を設定します。 |
onerror |
応答を変えずにハンドラーエラーを報告します。 |
maxSubscriptions、keepAliveMs |
subscriptions/listen の配信を設定します。 |
ステートレスハンドラーは、次の SDK v1 オプションを拒否します。
transportstoragesessionIdGeneratoronsessioninitializedとonsessionclosedenableJsonResponseeventStoreallowedHostsとallowedOriginsenableDnsRebindingProtectionretryInterval
enableJsonResponse: true の代わりに responseMode: "json" を使います。JSON モードは、最終結果より前に出た通知を落とします。
Workers ラッパーは、存在する Origin をすべて検証します。不正、不透明、非 HTTP の Origin は 403 で拒否します。
デフォルトの許可リストには、localhost 系の Origin と、エンドポイントの workers.dev ホスト名が含まれます。具体的な corsOptions.origin も、そのホスト名を自動で追加します。ハンドラーは localhost と workers.dev エンドポイントに、対応する Host チェックを適用します。
ワイルドカード CORS のカスタムドメインでは、Host と Origin の制限を両方とも明示します。
export default {
fetch(request, env, ctx) {
return createMcpHandler(createServer, {
allowedHostnames: ["mcp.example.com"],
allowedOriginHostnames: ["app.example.com"],
corsOptions: { origin: "https://app.example.com" },
})(request, env, ctx);
},
};export default {
fetch(request, env, ctx) {
return createMcpHandler(createServer, {
allowedHostnames: ["mcp.example.com"],
allowedOriginHostnames: ["app.example.com"],
corsOptions: { origin: "https://app.example.com" },
})(request, env, ctx);
},
} satisfies ExportedHandler;allowedOriginHostnames: "*" は、信頼できるミドルウェアがハンドラー呼び出し前に Origin を検証する場合にだけ設定します。この値はハンドラーの Origin チェックをオフにします。MCP HTTP サーバーは、ブラウザーの Origin を検証する必要があります。
CORS ヘッダーはリクエストを認証しません。エンドポイントは OAuth または別の認証層で保護します。
ハンドラーは request.url から信頼できる Host 許可リストを推論しません。デプロイが任意の Host 値を受け付ける場合は、ハンドラーを呼ぶ前に検証します。Cloudflare Workers 外のローカルサーバーでは、上流 SDK の Host と Origin 検証の案内に従ってください。
デフォルトの legacy: "stateless" 設定は、通常のレガシーツール、リソース、プロンプトに対応します。このレーンは SDK v2 のウェブ標準トランスポートを使います。WorkerTransport はインポートせず、完全なセッション依存トランスポートでもありません。
フォールバックには次の制限があります。
- 各 POST は新しいサーバーとトランスポートを受け取ります。
- HTTP GET と DELETE は
405を返します。 - MCP セッション ID もプロトコルセッション状態も永続化しません。
- プッシュされる sampling、elicitation、roots リクエストは即座に失敗します。
- スタンドアロンストリーム、イベント再生、セッション削除は使えません。
- 公開済みの実験的タスクは、このフォールバックではサポートされません。
これらの機能を移行しているあいだは、影響を受けるレガシークライアントを、一時的な createLegacyMcpHandler または McpAgent レーンへ振り分けます。
移行中、McpAgent は SDK v1 サーバーのままです。レガシールート内のサーバーインポートを @modelcontextprotocol/server に変えないでください。
サーバーが MCP セッション状態、RPC、プッシュされるサーバーからクライアントへのリクエスト、スタンドアロンストリーム、イベント再生に依存しない場合は、ツールを SDK v2 ファクトリへ移し、createMcpHandler で提供します。
サーバーがレガシーのステートフル機能を使う場合は、ステートレス相当を設計してデプロイするあいだ、既存の McpAgent ルートを残します。
| レガシー経路上のステートフル機能 | ステートレス経路での設計 |
|---|---|
| MCP セッションをキーにしたアプリケーションデータ | Durable Object、D1、KV、R2 など、明示的なアプリケーション境界の裏にデータを置きます。アドレス指定は MCP セッション ID ではなく、認証済みのサーバー発行ハンドルで行います。 |
| 複数ステップの対話状態 | 完全性保護された requestState を input_required と一緒に返します。認証済みユーザー、元のメソッドとパラメーター、有効期限に結び付けます。 |
| プッシュされる elicitation、sampling、roots | inputRequired(...) を返します。クライアントが埋め込みリクエストを満たし、元の操作を再試行します。 |
| スタンドアロンの list-change ストリーム | 変更は subscriptions/listen で公開します。ストリームが終わったら、クライアントはサブスクリプションを開き直します。 |
| セッション再生またはトランスポート復旧 | 各ステートレスリクエストを独立して復旧できるようにします。業務進捗は MCP トランスポートではなく、アプリケーションストレージに永続化します。 |
Agent から McpAgent への RPC |
プロトコルセッション依存を、明示的なアプリケーション RPC または HTTP 境界に置き換え、ステートレス MCP ツールは別に公開します。 |
ステートレス実装ができても、すぐレガシールートを削除しないでください。クライアントが移行し、既存セッションが排出されるまで、両方のレーンを提供します。
1 つの URL で、ステートレスリクエストを SDK v2 へ、レガシーリクエストを既存のセッション依存サーバーへ振り分けられます。
import { isLegacyRequest } from "@modelcontextprotocol/server";
import { createMcpHandler } from "agents/mcp/server";
const stateless = createMcpHandler(createStatelessServer, {
route: "/mcp",
legacy: "reject",
});
const legacy = MyMcpAgent.serve("/mcp");
export default {
async fetch(request, env, ctx) {
if (await isLegacyRequest(request)) {
return legacy.fetch(request, env, ctx);
}
return stateless(request, env, ctx);
},
};import { isLegacyRequest } from "@modelcontextprotocol/server";
import { createMcpHandler } from "agents/mcp/server";
const stateless = createMcpHandler(createStatelessServer, {
route: "/mcp",
legacy: "reject",
});
const legacy = MyMcpAgent.serve("/mcp");
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext) {
if (await isLegacyRequest(request)) {
return legacy.fetch(request, env, ctx);
}
return stateless(request, env, ctx);
},
} satisfies ExportedHandler<Env>;ステートレスハンドラーでは legacy: "reject" を維持します。そうしないと、レガシー互換レーンが先にリクエストを消費し、セッション依存ルートへ届きません。
クライアントを移す前に、両方のルートをデプロイします。レガシーレーンを監視し、既存セッションを排出させます。どのクライアントも依存しなくなってから、レガシールートとそのプロトコル専用 Durable Object バインディングを削除します。Durable Object の移行設定は、別のデプロイ手順として扱います。
Agents は内部で @modelcontextprotocol/client を使うようになりました。既存の addMcpServer 呼び出しは、プロトコル世代を自動で交渉します。
ステートレス経路のサーバーは server/discover を使います。レガシーの Streamable HTTP、SSE、RPC サーバーでは、Agents は initialize にフォールバックします。
クライアント API の変更は次のとおりです。
- 推奨シグネチャは
callTool(params, options)です。 callTool(params, resultSchema, options)は残っていますが、非推奨です。- MCP クライアントの型は
@modelcontextprotocol/clientから来ます。 - 必須のステートレス HTTP ヘッダーは SDK が処理します。
- リスト変更は、交渉したレーンに応じて、ステートレスサブスクリプションまたはレガシー通知を使います。
ステートレス経路のツール、プロンプト、リソースは、複数往復リクエスト(MRTR)で input_required を返せます。SDK は設定済みの elicitation ハンドラーを呼び、元の操作を再試行します。元の callTool、getPrompt、readResource の Promise は pending のままです。
各再試行に含まれるのは、直前の入力ラウンドへの応答だけです。それより前の応答はすべて含まれません。クライアントは最新の不透明な requestState もエコーします。後続ラウンドが必要とする信頼できる中間値は、完全性保護された requestState に封入します。inputResponses がラウンドをまたいで蓄積することは期待しないでください。
2 ラウンドのツールフローは ステートレス elicitation の例 ↗ を参照してください。
export class MyAgent extends Agent {
onStart() {
this.mcp.configureElicitationHandlers({
form: async (request, serverId, signal) => {
return collectInput(request, serverId, signal);
},
url: async (request, serverId, signal) => {
return openExternalFlow(request, serverId, signal);
},
});
}
}export class MyAgent extends Agent<Env> {
onStart() {
this.mcp.configureElicitationHandlers({
form: async (request, serverId, signal) => {
return collectInput(request, serverId, signal);
},
url: async (request, serverId, signal) => {
return openExternalFlow(request, serverId, signal);
},
});
}
}ハンドラーと進行中の呼び出しはメモリに残ります。ハイバネーション、isolate の再起動、トランスポート喪失、接続の再構築は、稼働中の対話呼び出しを拒否します。接続が復旧してから操作を再試行します。
手動で扱う requestState は、信頼できない入力として扱います。認証済みユーザーと操作に結び付け、完全性を保護し、短い有効期限を設定します。
カスタムの AgentMcpOAuthProvider は、v2 の OAuthClientProvider 契約を実装する必要があります。
- OAuth 型は
@modelcontextprotocol/clientからインポートします。 StoredOAuthClientInformationとStoredOAuthTokensを保存します。- 資格情報上の SDK issuer スタンプを維持します。
- ブラウザーリダイレクトをまたいで
OAuthDiscoveryStateを永続化します。 invalidateCredentialsで"discovery"を受け付けます。- 認可 issuer が異なる場合は、資格情報を分けて保持します。
SDK v2 はデフォルトで OAuth メタデータの issuer を検証します。メタデータの不一致が既知の、信頼できるレガシーサーバーでは skipIssuerMetadataValidation: true を使えます。これは OAuth の mix-up 保護を弱めるため、一般的なフォールバックにはしないでください。
MCP のステートレスモデルは、トランスポートとライフサイクルを変えます。
| 領域 | 以前の動作 | 新しい動作 |
|---|---|---|
| 起動 | initialize ハンドシェイク |
ハンドシェイクなし。クライアントにとって server/discover は任意 |
| リクエストメタデータ | 接続スコープの交渉 | 各リクエストにバージョン、クライアント能力、識別メタデータ |
| セッション | 任意の Mcp-Session-Id |
プロトコルセッションなし |
| サーバー入力リクエスト | サーバーが JSON-RPC リクエストを送る | サーバーは input_required を返す。クライアントが元の操作を再試行する |
| 変更通知 | スタンドアロン GET ストリームと list-change 通知 | SSE 応答付きの subscriptions/listen POST |
| ストリーム復旧 | Last-Event-ID で設定済みストリームを再開できる |
Listen ストリームは失敗後に開き直す。Last-Event-ID 再生はない |
カスタムトランスポート、プロキシ、ゲートウェイは、ドラフトのリクエストヘッダーを保持する必要があります。
MCP-Protocol-VersionMcp-Method- ツール、プロンプト、リソース操作向けの
Mcp-Name - 宣言された
Mcp-Param-*ツールヘッダー
Agents が使う正確な SDK バージョンは、MCP 2026-07-28 改訂を実装します。clientInfo を任意にし、サーバー識別を結果の _meta に置きます。高レベルの SDK API を使い、各プロトコル改訂をサポートする Agents リリースと合わせて MCP パッケージを更新します。生のステートレス結果には resultType が必要です。
ドラフトは Roots、Sampling、Logging、旧 HTTP+SSE トランスポート、Dynamic Client Registration を非推奨にします。非推奨期間中、レガシー互換のため型は残ります。公開済みの実験的タスクメソッドは io.modelcontextprotocol/tasks 拡張になります。Agents SDK v0.20.0 はこの拡張を追加しません。
次の統合は、このリリースでも SDK v1 サーバー出力を維持します。
- 現行 Code Mode の
codeMcpServerとopenApiMcpServerヘルパー - サーバー側の
withX402ヘルパー - SDK v1 の
McpServerをインポートする既存の OpenAI Apps 例
これらの統合が SDK v2 サーバーを出すまでは、出力を一時的な createLegacyMcpHandler ルートの後ろに隔離します。Code Mode の MCP コネクターと withX402Client は、どちらのクライアント世代も受け付けます。
-
各エンドポイントを、セッション依存の有無で分類します。
-
Agents リリースが要求する MCP SDK バージョンを固定します。
-
ステートレスにできるサーバー定義を、それぞれ SDK v2 ファクトリへ移します。
-
一時的なレガシーレーンがまだ必要なエンドポイントの横に、ステートレスハンドラーを追加します。
-
ステートレスとレガシーのリクエストを
isLegacyRequest()で振り分けます。 -
ステートレスクライアントとレガシークライアントを、それぞれ独立してテストします。
-
必須 HTTP ヘッダーを、すべてのプロキシとゲートウェイ経由でテストします。
-
クリーンなログイン後と、Durable Object ハイバネーション後の OAuth をテストします。
-
キャンセル、複数の入力ラウンド、トランスポート喪失をテストします。
-
有効な Origin を確認し、無効な Origin は
403で拒否します。 -
既存セッションが排出されたあとでのみ、レガシールートを削除します。
v0.20.0 より前の Agents リリースが保存した HTTP セッション ID には、交渉済みプロトコルバージョンが含まれません。アップグレード後のクライアントは、それらの ID を捨て、危険な再開リクエストを送らずに再接続します。古いリモートセッションに紐づく進行中の作業は再開しません。
API の詳細は createMcpHandler と McpClient を参照してください。