Skip to content

非公式本サイトは非公式の日本語ドキュメントであり、Cloudflare 公式サイトではありません。最新情報はdevelopers.cloudflare.comをご確認ください。

トランスポート

最終更新 Markdown で表示Agent セットアップ

Model Context Protocol(MCP)仕様は、クライアントとサーバー間の通信向けに、次の 2 つの標準 トランスポート機構 を定義しています。

  1. stdio — 標準入力と標準出力での通信です。ローカル MCP 接続向けです。
  2. Streamable HTTP — リモート MCP 接続の標準トランスポートです。2025 年 3 月に 導入 されました。双方向メッセージングに、単一の HTTP エンドポイントを使います。

Agents SDK で構築した MCP サーバーは、Streamable HTTP トランスポートの処理に createMcpHandler を使います。

リモート MCP トランスポートを実装する

createMcpHandler で、Streamable HTTP トランスポートを扱う MCP サーバーを作成します。新規 MCP サーバーでは、この方法を推奨します。

すばやく始める

「Cloudflare にデプロイ」ボタンで、リモート MCP サーバーを作成できます。

Workers にデプロイ

リモート MCP サーバー(認証なし)

createMcpHandler で MCP サーバーを作成します。GitHub の完全な例 を参照してください。

import { createMcpHandler } from "agents/mcp/server";
import { McpServer } from "@modelcontextprotocol/server";
import { z } from "zod";

function createServer() {
	const server = new McpServer({
		name: "My MCP Server",
		version: "1.0.0",
	});

	server.registerTool(
		"hello",
		{
			description: "Returns a greeting message",
			inputSchema: { name: z.string().optional() },
		},
		async ({ name }) => {
			return {
				content: [{ text: `Hello, ${name ?? "World"}!`, type: "text" }],
			};
		},
	);

	return server;
}

export default {
	fetch(request, env, ctx) {
		return createMcpHandler(createServer)(request, env, ctx);
	},
};
import { createMcpHandler } from "agents/mcp/server";
import { McpServer } from "@modelcontextprotocol/server";
import { z } from "zod";

function createServer() {
	const server = new McpServer({
		name: "My MCP Server",
		version: "1.0.0",
	});

	server.registerTool(
		"hello",
		{
			description: "Returns a greeting message",
			inputSchema: { name: z.string().optional() },
		},
		async ({ name }) => {
			return {
				content: [{ text: `Hello, ${name ?? "World"}!`, type: "text" }],
			};
		},
	);

	return server;
}

export default {
	fetch(request, env, ctx) {
		return createMcpHandler(createServer)(request, env, ctx);
	},
} satisfies ExportedHandler;

認証付き MCP サーバー

MCP サーバーが Workers OAuth Provider ライブラリで認証と認可を実装している場合は、apiRouteapiHandler を指定して createMcpHandler を使います。GitHub の完全な例 を参照してください。

export default new OAuthProvider({
	apiRoute: "/mcp",
	apiHandler: createMcpHandler(createServer),
	// ... other OAuth configuration
});
export default new OAuthProvider({
	apiRoute: "/mcp",
	apiHandler: createMcpHandler(createServer),
	// ... other OAuth configuration
});

プロトコルセッションが必要なサーバー

MCP のステートレス経路には、プロトコルレベルのセッションはありません。アプリケーションは、別のストレージ境界の向こうに、耐久性のある業務データを置けます。

レガシーセッションの移行中は、既存サーバーが、新しいステートレスルートの横に、WorkerTransport または McpAgent ルート付きの一時的な createLegacyMcpHandler を残せます。これらの API は、トランスポート状態、イベントの再送、プッシュ型 elicitation、sampling、roots リクエストをサポートします。McpAgent は非推奨で、機能は凍結されています。

クライアントを移す前にステートレスルートを追加し、既存セッションが排出されるまで両方のレーンを維持します。段階的な移行は MCP SDK v2 へ移行する を参照してください。既存のストリーム動作は McpAgent: ストリームの再開可能性 を参照してください。

RPC トランスポート

RPC トランスポートは、MCP サーバーとエージェントの両方が Cloudflare 上で動く内部アプリケーション向けです。同じ Worker 内でも動かせます。公開インターネットを経由せず、Cloudflare の RPC バインディング 上で JSON-RPC メッセージを直接送ります。

  • 高速 — ネットワークオーバーヘッドがなく、Durable Objects 間の直接的な関数呼び出しです
  • 単純 — HTTP エンドポイントも接続管理も不要です
  • 内部専用 — 同じ Worker 内でエージェントが MCP サーバーを呼び出す用途に適します

RPC トランスポートは認証をサポートしません。OAuth が必要な外部接続には、Streamable HTTP を使います。

RPC で既存の McpAgent に Agent を接続する

1. MCP サーバーを定義する

公開したいツールを持つ McpAgent を作成します。

import { McpAgent } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";

export class MyMCP extends McpAgent {
	server = new McpServer({ name: "MyMCP", version: "1.0.0" });
	initialState = { counter: 0 };

	async init() {
		this.server.tool(
			"add",
			"Add to the counter",
			{ amount: z.number() },
			async ({ amount }) => {
				this.setState({ counter: this.state.counter + amount });
				return {
					content: [
						{
							type: "text",
							text: `Added ${amount}, total is now ${this.state.counter}`,
						},
					],
				};
			},
		);
	}
}
import { McpAgent } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";

type State = { counter: number };

export class MyMCP extends McpAgent<Env, State> {
	server = new McpServer({ name: "MyMCP", version: "1.0.0" });
	initialState: State = { counter: 0 };

	async init() {
		this.server.tool(
			"add",
			"Add to the counter",
			{ amount: z.number() },
			async ({ amount }) => {
				this.setState({ counter: this.state.counter + amount });
				return {
					content: [
						{
							type: "text",
							text: `Added ${amount}, total is now ${this.state.counter}`,
						},
					],
				};
			},
		);
	}
}

2. Agent を MCP サーバーに接続する

AgentonStart() で、Durable Object バインディングを渡して addMcpServer() を呼び出します。

import { AIChatAgent } from "@cloudflare/ai-chat";

export class Chat extends AIChatAgent {
	async onStart() {
		// Pass the DO namespace binding directly
		await this.addMcpServer("my-mcp", this.env.MyMCP);
	}

	async onChatMessage(onFinish) {
		const allTools = this.mcp.getAITools();

		const result = streamText({
			model,
			tools: allTools,
			// ...
		});

		return createUIMessageStreamResponse({ stream: result });
	}
}
import { AIChatAgent } from "@cloudflare/ai-chat";

export class Chat extends AIChatAgent<Env> {
	async onStart(): Promise<void> {
		// Pass the DO namespace binding directly
		await this.addMcpServer("my-mcp", this.env.MyMCP);
	}

	async onChatMessage(onFinish) {
		const allTools = this.mcp.getAITools();

		const result = streamText({
			model,
			tools: allTools,
			// ...
		});

		return createUIMessageStreamResponse({ stream: result });
	}
}

RPC 接続は、HTTP 接続と同様に、Durable Object のハイバネーション後に自動で復元されます。バインディング名と props はストレージに永続化されるため、追加コードなしで接続を再確立できます。

RPC トランスポートでは、すでにアクティブな接続がある名前で addMcpServer を呼ぶと、重複を作らず既存接続を返します。HTTP トランスポートでは、サーバー名と URL の両方で重複排除します(詳細は MCP Client API を参照)。そのため onStart() から呼んでも安全です。

3. Durable Object バインディングを設定する

wrangler.jsonc で、両方の Durable Objects のバインディングを定義します。

{
	"durable_objects": {
		"bindings": [
			{ "name": "Chat", "class_name": "Chat" },
			{ "name": "MyMCP", "class_name": "MyMCP" },
		],
	},
	"migrations": [
		{
			"new_sqlite_classes": ["MyMCP", "Chat"],
			"tag": "v1",
		},
	],
}

4. Worker の fetch ハンドラーを設定する

リクエストを Chat エージェントへルーティングします。

import { routeAgentRequest } from "agents";

export default {
	async fetch(request, env, ctx) {
		const url = new URL(request.url);

		// Optionally expose the MCP server via HTTP as well
		if (url.pathname.startsWith("/mcp")) {
			return MyMCP.serve("/mcp").fetch(request, env, ctx);
		}

		const response = await routeAgentRequest(request, env);
		if (response) return response;

		return new Response("Not found", { status: 404 });
	},
};
import { routeAgentRequest } from "agents";

export default {
	async fetch(request: Request, env: Env, ctx: ExecutionContext) {
		const url = new URL(request.url);

		// Optionally expose the MCP server via HTTP as well
		if (url.pathname.startsWith("/mcp")) {
			return MyMCP.serve("/mcp").fetch(request, env, ctx);
		}

		const response = await routeAgentRequest(request, env);
		if (response) return response;

		return new Response("Not found", { status: 404 });
	},
} satisfies ExportedHandler<Env>;

MCP サーバーへ props を渡す

RPC トランスポートには OAuth フローがないため、ユーザーコンテキストを props として直接渡せます。

await this.addMcpServer("my-mcp", this.env.MyMCP, {
	props: { userId: "user-123", role: "admin" },
});
await this.addMcpServer("my-mcp", this.env.MyMCP, {
	props: { userId: "user-123", role: "admin" },
});

McpAgent 側では、次のように props にアクセスできます。

export class MyMCP extends McpAgent {
	async init() {
		this.server.tool("whoami", "Get current user info", {}, async () => {
			const userId = this.props?.userId || "anonymous";
			const role = this.props?.role || "guest";

			return {
				content: [{ type: "text", text: `User ID: ${userId}, Role: ${role}` }],
			};
		});
	}
}
export class MyMCP extends McpAgent<
	Env,
	State,
	{ userId?: string; role?: string }
> {
	async init() {
		this.server.tool("whoami", "Get current user info", {}, async () => {
			const userId = this.props?.userId || "anonymous";
			const role = this.props?.role || "guest";

			return {
				content: [{ type: "text", text: `User ID: ${userId}, Role: ${role}` }],
			};
		});
	}
}

props は型安全です(TypeScript が McpAgent のジェネリックから Props 型を抽出します)。永続的で(Durable Object ストレージに保存されます)、ツール呼び出しの前にすぐ使えます。

RPC トランスポートのサーバータイムアウトを設定する

RPC トランスポートは、ツール応答を待つタイムアウトを設定できます。デフォルトでは、サーバーはツールハンドラーの応答を 60 秒 待ちます。McpAgentgetRpcTransportOptions() をオーバーライドすると、変更できます。

export class MyMCP extends McpAgent {
	server = new McpServer({ name: "MyMCP", version: "1.0.0" });

	getRpcTransportOptions() {
		return { timeout: 120000 }; // 2 minutes
	}

	async init() {
		this.server.tool(
			"long-running-task",
			"A tool that takes a while",
			{ input: z.string() },
			async ({ input }) => {
				await longRunningOperation(input);
				return {
					content: [{ type: "text", text: "Task completed" }],
				};
			},
		);
	}
}
export class MyMCP extends McpAgent<Env, State> {
	server = new McpServer({ name: "MyMCP", version: "1.0.0" });

	protected getRpcTransportOptions() {
		return { timeout: 120000 }; // 2 minutes
	}

	async init() {
		this.server.tool(
			"long-running-task",
			"A tool that takes a while",
			{ input: z.string() },
			async ({ input }) => {
				await longRunningOperation(input);
				return {
					content: [{ type: "text", text: "Task completed" }],
				};
			},
		);
	}
}

トランスポートを選ぶ

トランスポート 使う場面 利点 欠点
Streamable HTTP 外部 MCP サーバー、本番アプリ 標準プロトコル、セキュア、認証をサポート わずかなネットワークオーバーヘッド
RPC Cloudflare 上の内部エージェント 最速で、セットアップが最も単純 認証なし、Durable Object バインディングのみ
SSE 古いクライアントとの互換性 後方互換 非推奨。Streamable HTTP を使います

McpAgent から移行する

エンドポイントがレガシーのステートフル機能を使っていない場合は、@modelcontextprotocol/server のステートレスサーバーファクトリへ直接移行し、createMcpHandler に渡します。

MCP セッション状態、RPC、サーバーからクライアントへのプッシュリクエスト、スタンドアロンストリーム、再送に依存している場合は、まずステートレスな同等機能を設計します。たとえば、業務状態を明示的なアプリケーションストレージへ移し、プッシュ型の入力リクエストをステートレス elicitation に置き換えます。クライアントが移行し、既存セッションが排出されるまで、ステートレスレーンとレガシーレーンを並行提供します。

機能対応、デュアル時代のルーティング、ロールアウト手順は MCP SDK v2 へ移行する を参照してください。

MCP クライアントでテストする

リモート接続をサポートする MCP クライアントで MCP サーバーをテストできます。ローカル接続だけをサポートする MCP クライアントを、リモート MCP サーバーで動かすアダプター mcp-remote も使えます。

Claude Desktop、Cursor、Windsurf、その他の MCP クライアントからリモート MCP サーバーへ接続する手順は、このガイド に従ってください。

役に立ちましたか?