Cloudflare WorkersでRemote MCPを安全に運用する設計ガイド
Cloudflare Workers上のRemote MCPを、現行createMcpHandler、OAuth、権限、レート制限、監査ログ、停止条件まで含めて段階的に設計します。
- 情報確認
- 参考リンク
- 7件
- 更新性
- 定期更新
- 読了目安
- 約8分
仕様・料金・提供範囲が変わりやすいテーマは、公開日・更新日・情報確認日を分けて管理します。 導入前には必ず記事末尾の一次情報と公式ドキュメントで最新状況を確認してください。
結論
Cloudflare WorkersでRemote MCPを作るなら、2026年8月13日時点の新規実装は**ステートレスな createMcpHandler()**を基準にします。ただし、ハンドラーを置いて公開URLを得るだけでは運用可能とはいえません。OAuthによる本人確認、ツール単位の権限、利用者単位のレート制限、機密値を除外した構造化ログ、異常時の停止条件を一つのリリースゲートとして設計します。
この記事は公式仕様とCloudflare公式Docsを基にした設計ガイドです。特定のWorkersアカウントへ実際にデプロイし、すべてのプラン・SDK組み合わせで動作確認した結果ではありません。パッケージ版、利用可能な機能、上限、料金は、実装時点の公式Docsと自分のアカウントで再確認してください。
この記事の対象読者
- ローカルMCPをチームや顧客向けのRemote MCPへ移したい開発者
- Cloudflare WorkersとAgents SDKで新規MCPサーバーを作る人
- OAuthを入れたが、ツール権限・レート制限・監査ログまで設計できていない人
- 本番投入の可否と、問題発生時に止める条件を明文化したい運用担当者
トランスポート自体をまだ決めていない場合は、stdioとStreamable HTTPの選び方から確認してください。
現行の実装方式を選ぶ
CloudflareのRemote MCPガイドは、2026年7月時点で次の境界を示しています。
| 方式 | 状態 | 新規実装での判断 |
|---|---|---|
createMcpHandler() | ステートレス、現行MCP向け | 第一候補 |
createLegacyMcpHandler() | 旧WorkerTransport経路向け | 移行期間だけ使う |
McpAgent | 非推奨・機能固定 | 新規では使わない |
| Raw SDK transport | 実装者が輸送層を所有 | 独自要件が明確な場合だけ |
公式のMCP handler APIでは、createMcpHandler はリクエストごとに新しいMCPサーバーを生成するファクトリーを受け取ります。依存版は記事の固定値をコピーせず、インストールしている agents が要求するMCPパッケージの正確な版へ合わせます。
import { McpServer } from '@modelcontextprotocol/server';import { createMcpHandler } from 'agents/mcp/server';
function createServer() { const server = new McpServer({ name: 'team-tools', version: '1.0.0' });
// registerToolで、最初は読み取り専用ツールだけを登録する return server;}
const handler = createMcpHandler(createServer, { // modern専用endpoint。旧クライアントは期限付きの別経路へ分離する legacy: 'reject', // 実際の許可OriginとCORSも環境ごとに明示する});
export default { fetch(request, env, ctx) { return handler(request, env, ctx); },} satisfies ExportedHandler;このコードは構造を示す骨組みです。legacy: 'reject' はmodern専用endpointの境界を明示します。既定の legacy: 'stateless' で互換性を残す場合は、対象クライアント、廃止日、legacy成功率を別に記録してください。認証、権限判定、環境型、例外処理を省略しているため、そのまま本番へ出してはいけません。
公開レベルを判断する表
| 扱うもの | 認証 | 権限 | レート制限 | リリース判断 |
|---|---|---|---|---|
| 公開情報の低コスト検索 | 条件次第 | 読み取り専用 | 必須 | 小規模ベータから |
| 個人・顧客データの参照 | 必須 | 利用者・テナント分離 | 必須 | 認可テスト後のみ |
| 外部サービスへの書き込み | 必須 | ツール別スコープ | 厳しめ | 人間確認を加える |
| 削除・公開・購入・課金 | 必須 | 最小権限+再確認 | 必須 | 初期公開から除外を推奨 |
| 管理者操作 | 必須 | 管理者専用、既定非表示 | 必須 | 独立経路を検討 |
最初の公開範囲は「利用価値」ではなく「失敗時の損失」で決めます。読み取り専用で十分な価値を確認してから、書き込みツールを一つずつ追加します。AIエージェントの秘密情報保護も、環境変数とログの境界を決める際に使えます。
OAuthはログインとツール権限を分ける
CloudflareのAuthorization解説は、認証と認可を別の問題として扱っています。ログインに成功しただけでは、すべてのMCPツールを実行できる根拠になりません。
設計は次の順序で行います。
- 誰がログインできるかを決める
read:documents、write:issuesのようにツールへ対応するスコープを定義する- 同意画面に、クライアント名、要求スコープ、対象リソースを表示する
- ツール登録時またはツール実行時にスコープを強制する
- テナントID・ユーザーIDを、クライアントからの任意入力ではなく検証済み認証コンテキストから得る
- トークン失効、ユーザー無効化、権限変更が反映されることを試す
CloudflareのWorkers OAuth Provider Libraryを使う選択肢には、Cloudflare Access、第三者OAuth、既存の認証サービス、独自フローがあります。どれを選んでも、同意とツール権限の最終責任はアプリケーション側に残ります。
第三者OAuthへプロキシする場合は、CloudflareのMCPセキュリティガイドが示すように、上流へ転送する前に自前の同意画面とCSRF対策が必要です。保存済み同意を攻撃者のクライアントに誤用される「confused deputy」を防ぐため、state、安全なCookie、リダイレクトURI、発行者を結び付けて検証します。
レート制限は過負荷防止として使う
Workers Rate Limiting bindingは、Worker内の任意の位置で利用者やリソース別の制限をかけられます。MCPでは、検証済みの主体IDとツール名を組み合わせたキーが扱いやすい設計です。
const key = `${verifiedTenantId}:${verifiedUserId}:${toolName}`;const { success } = await env.MCP_RATE_LIMITER.limit({ key });
if (!success) { return new Response('rate limit exceeded', { status: 429 });}ただし、これは概念例です。verifiedTenantId、verifiedUserId、toolName は信頼できる認証コンテキストと検証済みMCPメタデータから作り、外部入力をそのまま信用しません。
また、Cloudflare公式Docsは、このAPIのカウンターがCloudflareロケーション単位で、許容的・結果整合的であり、正確な会計システム向けではないと明記しています。そのため役割を分けます。
- Rate Limiting binding: バースト、誤ループ、上流API過負荷の緩和
- 永続的なクォータ管理: 課金、厳密な日次上限、契約上限
- 観測: 429件数、主体別・ツール別拒否率、上流エラー率
IPアドレスだけをキーにすると、モバイル回線やプロキシを共有する正当な利用者をまとめて止める可能性があります。可能なら検証済みユーザーID、テナントID、クライアントIDを使います。
Workers Logsを監査可能な形にする
Workers Logsの公式Docsでは、Wrangler設定でobservabilityを有効にし、JSONの構造化ログを使うことが推奨されています。ただし「ログを有効化した」だけでは監査ログになりません。
推奨するイベント項目は次の通りです。
| 項目 | 例 | 注意 |
|---|---|---|
request_id | ランダムな相関ID | 応答にも返すなら形式を固定 |
actor_id | ハッシュ化または不透明ID | メールアドレスを直接入れない |
tenant_id | 不透明ID | テナント越境の調査に使う |
client_id | OAuthクライアントID | 生トークンは入れない |
scopes | 許可済みスコープ名 | 権限判断の証跡にする |
tool_name | 呼び出したツール | 引数全文とは分離する |
decision | allow / deny | 拒否理由を定型化する |
status | success / error / cancelled | HTTPコードも別項目にする |
duration_ms | 処理時間 | 上流遅延の検知に使う |
release_id | デプロイ版 | ロールバック判断に使う |
記録しないものも明文化します。
- OAuthアクセストークン、更新トークン、Cookie、APIキー
authInfo.token、authInfo.extra.props- ツール引数・結果の全文
- 個人情報や顧客文書の本文
- 例外オブジェクト内に混入した秘密値
サンプリングを使う場合でも、拒否、認可エラー、書き込み操作、重大エラーを追跡できる設計にします。保存期間、閲覧権限、削除手順も監査要件に含めてください。
段階的な実装手順
1. ローカルで読み取り専用ツールを作る
createMcpHandler と対応MCPパッケージの版を公式Docsで固定し、外部副作用のないツールを一つだけ登録します。不正入力、タイムアウト、キャンセルもテストします。
2. 認証なしの公開を前提にしない
将来個人データや書き込みを扱うなら、最初からOAuthの主体IDとスコープをツール層へ渡せる構造にします。認証なしの試験エンドポイントは、公開情報・低コスト・読み取り専用に限定し、期間と呼び出し上限を決めます。
3. ツール単位の権限テストを書く
少なくとも、未認証、期限切れトークン、正しい利用者でスコープ不足、別テナント、管理者、失効後を試します。ツール一覧から見せない方式と、実行時に拒否する方式のどちらでも、サーバー側の強制を省略しません。
4. レート制限と上流保護を入れる
主体×ツールの制限、全体の緊急上限、上流APIタイムアウト、同時実行上限を分けます。429と上流エラーをダッシュボードで追えるようにします。
5. 構造化ログとアラートを入れる
秘密値除外テストを行い、認可拒否急増、5xx、429、レイテンシ、書き込み件数を観測します。エージェントのサンドボックス運用と同様に、許可境界と証跡を実行環境の外側にも持たせます。
6. 限定利用者でステージングする
本番データを使わず、テスト用テナントと最小スコープで接続します。旧クライアントが必要ならmodernとlegacyを別経路・別メトリクスにします。
7. 停止訓練をしてから公開する
対象ツールの無効化、ルート停止、直前版へのロールバック、OAuthクライアント失効、上流資格情報のローテーションを実際に手順化します。
即時停止する条件
次のいずれかを検知したら、新規リリースを止め、影響するツールまたはMCPルートを無効化します。
- ログや応答にトークン、秘密値、顧客データが出た
- 未認証またはスコープ不足でツールを実行できた
- 別テナントのデータを参照・変更できた
- 同意していない書き込み、削除、公開、課金が行われた
- 429、5xx、上流タイムアウトが定めた閾値を超えた
- 主体、ツール、結果、リリース版をログから追えない
- OAuth発行者、リダイレクトURI、CSRF検証に不整合がある
- ロールバックまたは資格情報失効の手順が機能しない
閾値の数値は利用量、上流APIの契約、SLOによって変わるため、この記事では一律値を断定しません。平常時のベースラインを計測し、絶対値と増加率の両方で決めます。
公開前チェックリスト
- 新規実装が
createMcpHandlerと対応SDK版を使っている - legacy経路が必要なら期限・対象・監視を分離した
- Origin、CORS、許可メソッドを明示した
- ログインとツール権限を別々に検証した
- 同意画面にクライアント、スコープ、対象を表示した
- 主体×ツールのレート制限と全体上限を設けた
- 厳密な課金・クォータをRate Limiting bindingへ任せていない
- 構造化ログからトークンと機密本文を除外した
- 未認証、スコープ不足、テナント越境、失効をテストした
- ツール停止、ルート停止、ロールバックを実行できる
よくある質問
認証なしのRemote MCPを公開してもよいですか?
公開情報を返す低コストの読み取り専用ツールに限定し、悪用時の上限と停止手順を持つ場合は選択肢になります。個人データ、社内情報、書き込み、課金を扱うツールは、OAuthとツール単位の権限を先に実装してください。
CloudflareのRate Limiting bindingだけで厳密な利用量課金をできますか?
できません。公式Docsではロケーション単位で、許容的かつ結果整合的な仕組みであり、正確な会計用途には使わないよう説明されています。過負荷防止に使い、課金や厳密なクォータは別の整合性を持つ仕組みで管理します。
Workers Logsを有効にすれば監査ログは完成ですか?
ログ保存基盤が使えるだけで、監査項目や機密値の除外はアプリ側の設計です。主体の不透明ID(opaque ID)、クライアントID、スコープ、ツール名、結果、所要時間を構造化し、raw token、秘密値、機密引数・結果は残さないでください。
まとめ
Cloudflare WorkersはRemote MCPの公開基盤を用意できますが、本番品質はURLを発行した後の設計で決まります。新規サーバーはステートレスな createMcpHandler を基準にし、OAuthのログインとツール権限を分離します。Rate Limiting bindingは過負荷防止に使い、厳密な会計とは分けます。Workers Logsには監査に必要な最小項目だけを構造化して残します。
そして、認可逸脱、秘密値漏えい、テナント越境、追跡不能が起きた時に止められなければ、まだ公開可能な設計ではありません。読み取り専用の限定公開から始め、停止訓練を通過した機能だけを段階的に広げてください。
一次情報
一次情報・参考リンク
- Cloudflare Agents docs: Build a Remote MCP server https://developers.cloudflare.com/agents/model-context-protocol/guides/remote-mcp-server/
- Cloudflare Agents docs: MCP handler APIs https://developers.cloudflare.com/agents/model-context-protocol/apis/handler-api/
- Cloudflare Agents docs: MCP Authorization https://developers.cloudflare.com/agents/model-context-protocol/protocol/authorization/
- Cloudflare Agents docs: Securing MCP servers https://developers.cloudflare.com/agents/model-context-protocol/guides/securing-mcp-server/
- Cloudflare Workers docs: Rate Limiting binding https://developers.cloudflare.com/workers/runtime-apis/bindings/rate-limit/
- Cloudflare Workers docs: Workers Logs https://developers.cloudflare.com/workers/observability/logs/workers-logs/
- Model Context Protocol Specification 2026-07-28: Authorization https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization
関連して読む
- · 参考リンク 3件
2026-05-27 朝のIT・AIニュース3本
今日のIT・AIニュースから、MCPセキュリティ、AI検索、AIコーディングの3点を選び、開発者・サイト運用者目線で確認点を整理します。
- · 参考リンク 4件
MCPとSmolVM: AIエージェント実行基盤の役割分担
MCPが外部システム接続を標準化し、SmolVMが生成コードの実行を隔離する。AIエージェント基盤を接続レイヤーと実行レイヤーに分けて整理します。
- · 参考リンク 5件
e-Gov法令XMLをMCP向けJSONへ変換する:条・項・号と出典を壊さない設計
e-Gov法令APIのXMLを、AIが引用しやすいMCPレスポンスへ変換する設計を解説。条・項・号の順序、施行時点、改正履歴、原文参照を失わない型と実装手順を示します。