新しいModel Context Protocol(MCP)サーバーは、クライアントコンテキストにツールを追加します。50ツールのサーバーが10個あれば、モデルが最初のユーザーメッセージを読む前に、500のツール定義がロードされます。
エンタープライズ規模——内部API、SaaS統合、データプラットフォーム——では、ツールの肥大化が支配的なコストになります。エージェントが決して呼ばないスキーマにトークンが使われます。ルーティングは遅くなります。ツール選択は混乱します。
解決策は、統合を減らすことではありません。ツールへの段階的開示です。巨大なダンプではなく、層で能力を明かします。
CloudflareのCode Modeパターンは、すべての上流操作を宣伝する代わりに、二つのツール——searchとexecute——でMCPにそれを実装します。設計の根拠とコンテキスト節約は、Code Mode: give agents an entire API in 1,000 tokensにあります。
このパターンは、発見と実行を分離します。searchは、OpenAPIドキュメント、あるいはツールレジストリに対して、隔離されたWorkerサンドボックスでモデル記述のJavaScriptを実行します。コードが返すサブセットだけが、モデルコンテキストに入ります。フィルタされたパス、パラメータ名、スキーマスライスです。
executeは、ホスト提供の認証済みリクエスト関数でサンドボックスコードを実行します。モデルはAPI呼び出しを組み立て、レスポンスをマップし、焦点を絞った結果を返します。認証情報はホストWorkerに留まります。サンドボックスはトークンを見ません。
search と execute が直接ツールに勝るとき
直接のMCPツールは、表面が小さく安定しているとき——名前が明確な十数の操作——に機能します。
search と execute が勝つのは、上流APIに数百または数千のOpenAPI操作があるときです。複数のMCPサーバーを一つのポータル背後に集約するとき、ツール説明がコンテキスト予算の大きな割合を消費するとき、APIの進化に合わせて操作ごとのMCPスキーマを保守する代わりに、拡張可能な基盤が欲しいときにも勝ちます。
ツール数が少ない場合でも、一度投資するエンジニアリング能力があれば、この型は価値があります。二つの安定したMCPツールを出荷し、新しいMCPツール定義ではなく、OpenAPIの更新でAPI操作を追加します。新入りとエージェントは、ツールリストをスクロールするのではなく、searchコードで能力を発見します。
前提条件
Cloudflare Workersプロジェクト、APIのOpenAPI 3.xドキュメント(またはプログラムで公開できるツールカタログ)、ホスト側の認証方法が必要です。@cloudflare/codemode、agents、@modelcontextprotocol/sdk、zodをインストールします。wrangler.jsoncにWorker Loaderバインディングとnodejs_compat互換フラグを追加します。Code Modeは実験的です。本番の硬化の前に評価してください。
例:wrangler.jsonc
DynamicWorkerExecutorサンドボックスに必要なWorker Loaderバインディング
{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "openapi-codemode-mcp",
"main": "src/server.ts",
"compatibility_date": "2026-08-15",
"compatibility_flags": ["nodejs_compat"],
"worker_loaders": [{ "binding": "LOADER" }]
}
例:openApiMcpServer()を使うホストWorker
src/server.ts — 認証情報はホスト、search と execute はサンドボックス
import { DynamicWorkerExecutor } from "@cloudflare/codemode";
import { openApiMcpServer } from "@cloudflare/codemode/mcp";
import { createLegacyMcpHandler } from "agents/mcp";
const SPEC_URL = "https://api.example.com/openapi.json";
const API_ORIGIN = "https://api.example.com";
export default {
async fetch(request, env, ctx) {
const authorization = request.headers.get("Authorization");
if (!authorization?.startsWith("Bearer ")) {
return new Response("Bearer token required", { status: 401 });
}
const spec = await (await fetch(SPEC_URL)).json();
const server = openApiMcpServer({
spec,
executor: new DynamicWorkerExecutor({ loader: env.LOADER }),
name: "example-api",
request: async (options) => {
const url = new URL(`${API_ORIGIN}${options.path}`);
for (const [k, v] of Object.entries(options.query ?? {})) {
if (v !== undefined) url.searchParams.set(k, String(v));
}
const response = await fetch(url, {
method: options.method,
headers: { Authorization: authorization, "Content-Type": "application/json" },
body: options.body === undefined ? undefined : JSON.stringify(options.body),
});
if (!response.ok) throw new Error(`API request failed: ${response.status}`);
return response.headers.get("Content-Type")?.includes("json")
? await response.json()
: await response.text();
},
});
return createLegacyMcpHandler(server, { route: "/mcp" })(request, env, ctx);
},
};
npx wrangler deployでデプロイします。MCPクライアントを、bearerトークン付きでhttps://<worker>.<subdomain>.workers.dev/mcpに接続します。ツールをリストします。searchとexecuteが見えるはずで、操作ごとのツールが何百もあるはずではありません。完全なウォークスルーはBuild a search and execute MCP serverです。
フェーズ1:スキーマを検索する
executeの前にsearchを呼び出します。モデルは、サンドボックス内でOpenAPIドキュメントを検査するJavaScriptを送信します。
モデルが書いたsearchコード——返されたパスだけがコンテキストに入る
async () => {
const spec = await codemode.spec();
return Object.entries(spec.paths)
.filter(([path]) => path.includes("/orders"))
.map(([path, operations]) => ({ path, methods: Object.keys(operations) }));
};
ローカルの$refは、サンドボックス内で解決されます。完全なドキュメントは、searchコードが明示的に一部を返さないかぎり、モデルコンテキストの外に留まります。
フェーズ2:認証済みリクエストでexecuteする
操作を選んだあと、モデルはホスト提供のリクエスト関数を使うコードでexecuteを呼び出します。
モデルが書いたexecuteコード——返す前にマップとフィルタ
async () => {
const response = await codemode.request({
method: "GET",
path: "/orders",
query: { status: "processing", limit: 20 },
});
return response.items.map(({ id, status }) => ({ id, status }));
};
生成コードは、返す前に選択、マップ、集約、またはページネーションしてください。パブリッシャーは、およそ6,000推定トークンでレスポンスを制限し、--- TRUNCATED ---で切り詰めをマークします。中間のAPI作業は、それでも実行されます。返すものは、生のダンプではなく、判断サイズに設計します。
セキュリティ境界
MCPサーバーを作る前に、ホストWorkerでbearerトークンを読み、認可を強制します。トークンはサンドボックスに入りません。DynamicWorkerExecutorは、デフォルトで外部のfetch()とconnect()をブロックします。生成コードは、ホストのrequestコールバック経由でのみ、APIに到達します。
パスを検証します。任意のオリジンを受け入れないでください。openApiMcpServer()は、execute内の操作ごとの永続的承認を提供しません。副作用の前に、ホストコールバックで認可を強制してください。OpenAPIドキュメントやAPIレスポンスにシークレットを埋め込まないでください。どちらも、モデルが書いたコードから見えます。
多数のMCPサーバーを集約する
組織が単一APIだけを持つことは稀です。CloudflareのMCPポータルは、search_and_execute最適化モードを公開し、すべての上流ツールを隠し、portal_query_toolsとportal_execute経由でプロキシします。ポータル層でも、同じ二つのツール表面です。ポータルURLで?optimize_context=search_and_executeを付けて有効化します。
初期トークンコストは、背後にいくつの上流サーバーがあっても、小さな定数になります。Cloudflareは切り替えをMCPポータルのコンテキスト最適化で文書化しています。
代替:既存MCPサーバー向けの単一codeツール
すでに管理可能な、離散ツールのMCPサーバーを運用している場合、codeMcpServer()は二つではなく一つのcodeツールでラップします。上流ツールはサーバー側に登録されたままです。クライアントは、単一のコード実行表面を見ます。
上流の表面がOpenAPIドキュメント、あるいは無制限のツールカタログなら、search と execute を使います。既知のツールセットを持つ既存MCPサーバーをラップするなら、単一のcodeツールを使います。どちらの型も、中間結果をコンテキストの外に保ちます。ガイドはBuild a Code Mode MCP serverです。
ここから構築する
Workerをプラットフォーム層として扱います。新しいMCPツールなしで、OpenAPIバージョンを追加します。アイデンティティ、サーバートグル、WriteGuardの書き込み制御には、MCPポータルを重ねます。
そのプラットフォームを、AGENTS.mdのリポジトリレベルエージェントコンテキストと、エージェント向けナレッジの整理のようなプライベート知識ベースと組み合わせます。
Cloudflare API MCPサーバーは、この型で完全なCloudflare APIをsearch と execute 経由で公開しています。このアプローチが本番API表面にスケールすることの証明です。
Dylan Engelbrechtは、MCPとエージェントの道具が進化するにつれ、この知識ハブを頻繁に更新します。llms.txtを読むクローラーと、リポジトリのAGENTS.mdからリンクを辿るエージェントは、これらの記事を生きた参照として扱えます。Cloudflareが次のCode Modeリリースを出すたびに古くなる静的スナップショットではなく、現在のMCPアーキテクチャ実践です。