活用事例一覧へ
2026年7月27日開発・エンジニアリング検証時期:2026年4月

MCPサーバーをCloudflare Workersでリモート化する|プラットフォーム選定の4つの軸【AI活用検証vol.119】

MCPサーバーをCloudflare Workersでリモート化する|プラットフォーム選定の4つの軸【AI活用検証vol.119】

ローカルMCPサーバーは1ファイルで動く手軽さがある一方、「自分のPC上でしか動かない」という構造的な制約を持っています。

この検証では、MCPサーバーをCloudflare Workersへ移し、どこからでも・誰でもGoogle広告データを分析できる状態を作りました。

本記事は3回シリーズの最終回です。第1回で認証設定、第2回でローカルMCPサーバーの構築を扱いました。

この検証の概要

検証時期

2026年4月5日

やりたかったこと

ローカルMCPの制約(PC依存・チーム共有不可・Web版から使えない)を解消する

構成

TypeScript + Hono + @hono/mcp / Cloudflare Workers

依存パッケージ

4つだけ(hono / @modelcontextprotocol/sdk / @hono/mcp / zod)

認証

JWT Bearer Token(有効期限2週間)

コスト

無料枠内(10万リクエスト/日)

結論:ローカルとリモートの違いは通信方式

ローカルMCP:
  Claude Desktop → (stdio) → ローカルプロセス → Google Ads API
  ※ 同じPCでしか使えない

リモートMCP:
  Claude Desktop / Web版Claude / Cursor → (HTTP) → クラウドサーバー → Google Ads API
  ※ どこからでもアクセス可能

ローカル版はstdio(標準入出力)でプロセス間通信を行うため、同じマシン上でしか動きません。リモート版はHTTP経由のため、インターネットに接続できるあらゆるクライアントから使えます。

MCPプロトコルが定義するトランスポートはstdioとStreamable HTTP(SSE)の2つで、リモートMCPは後者を使います。

プラットフォーム選定:4つの判断軸

3つの候補を比較しました。

要件

Cloudflare Workers

Vercel

Render

SSEストリーミング

△(時間制限)

コールドスタート

ほぼなし

あり

大きい

無料枠

10万req/日

100GB-hrs/月

750hrs/月(スリープあり)

エコシステム

Hono最適化

Next.js向き

汎用

決め手①:実行時間制限

MCPセッションではツール呼び出しを含む対話が続くため、ストリーミング接続が維持される時間が最大の分岐点になります。

Vercelは Hobbyプラン10秒 / Proプラン60秒の実行時間制限があり、この制限を超えることは十分にありえます。

決め手②:コールドスタート

MCPクライアントが接続する瞬間のレスポンス速度は、体験に直結します。

Renderの無料プランはスリープ復帰に10〜30秒かかり、MCPの接続タイムアウトに引っかかる可能性があります。Workersはエッジ実行のためコールドスタートがほぼゼロです。

決め手③:コスト

MCPサーバーの利用パターンは「1日に数十〜数百リクエスト」程度です。Workers無料枠の10万リクエスト/日は、個人〜小規模チームなら全く問題になりません。

決め手④:エコシステム

技術選定で見逃せない点です。

  • Honoの作者はCloudflare所属。Workers上での動作が最も安定している
  • @hono/mcp が提供する StreamableHTTPTransport はWorkers前提で設計されている
  • 依存パッケージは4つだけで、Workersのバンドルサイズ制限とも好相性

ステートレス設計は制約ではなく健全性

app.all('/mcp', async (c) => {
  // リクエストごとにMCPサーバーとトランスポートを作成
  const mcpServer = createMcpServer(c.env);
  const transport = new StreamableHTTPTransport();
  await mcpServer.connect(transport);
  return transport.handleRequest(c);
});

Cloudflare Workersはリクエストごとに独立した実行コンテキストを持ち、グローバル状態を共有しません。つまりステートレスに設計せざるを得ない制約があります。

ただしこれは一見すると制約ですが、実際にはアーキテクチャの健全性を担保してくれます。

常時起動するサーバーでは、インスタンスの生存管理やメモリリークへの配慮が必要です。Workersならそもそもその心配がありません。

認証:なぜJWTか

リモートMCPサーバーは公開エンドポイントになるため、認証が必須です。

方式

評価

API Key

JWTのほうが安全——有効期限を設定でき、ペイロードに任意の情報を含められる

JWT

採用

OAuth2

認可サーバーが必要で、個人〜小規模チームには過剰

さらに二重チェックを入れています。

app.use('/mcp', async (c, next) => {
  const jwtMiddleware = jwt({ secret: c.env.JWT_SECRET });
  await jwtMiddleware(c, next);

  // ソルトの一致チェック(二重チェック)
  const payload = c.get('jwtPayload');
  if (payload.salt !== c.env.JWT_SALT) {
    return c.json({ error: 'Unauthorized' }, 401);
  }
});

JWT署名の検証に加え、ペイロード内の salt をサーバー側の環境変数と照合します。トークンは2週間で期限切れになる設定です。

Workers環境の制約が理解を深める

実装上、最も学びのあった部分です。

ローカル版はPythonのライブラリがOAuthトークンを自動管理していました。しかしWorkers環境ではNode.jsネイティブのモジュールが使えないため、fetch APIでOAuthトークンを直接更新する必要があります。

async getAccessToken(): Promise<string> {
  const response = await fetch('https://oauth2.googleapis.com/token', {
    method: 'POST',
    body: new URLSearchParams({
      client_id: this.env.GOOGLE_ADS_CLIENT_ID,
      client_secret: this.env.GOOGLE_ADS_CLIENT_SECRET,
      refresh_token: this.env.GOOGLE_ADS_REFRESH_TOKEN,
      grant_type: 'refresh_token'
    })
  });
  // アクセストークンをキャッシュ(有効期限5分前に更新)
}

ライブラリが隠蔽していたOAuth2のトークン更新フローを自前で実装することで、仕組みが明確になりました。制約が理解を促した例です。

ローカル版との比較

観点

ローカル版

リモート版

言語

Python

TypeScript

フレームワーク

FastMCP

Hono + @hono/mcp

通信方式

stdio

Streamable HTTP/SSE

クライアント認証

なし(ローカルのため不要)

JWT Bearer Token

API Version

v19

v23

ツール数

14

9

チーム共有

不可

可能

Web版Claude

非対応

対応

コスト

無料(自分のPC)

無料(Workers無料枠)

ツール数が減っている理由は明確です。ローカルファイルシステムに依存するツール(画像ダウンロード等)を除外したためです。リモートサーバーにはファイルシステムがないので、構造的に不要になります。

デプロイ手順

1. シークレット設定

wrangler secret put GOOGLE_ADS_DEVELOPER_TOKEN
wrangler secret put GOOGLE_ADS_CLIENT_ID
wrangler secret put GOOGLE_ADS_CLIENT_SECRET
wrangler secret put GOOGLE_ADS_REFRESH_TOKEN
wrangler secret put JWT_SECRET
wrangler secret put JWT_SALT

wrangler secret put はCLIから対話形式で値を入力でき、ダッシュボードを開く必要がありません。コード上では c.env.GOOGLE_ADS_CLIENT_ID でアクセスできます。

2. デプロイ

npm run deploy

これだけです。数秒で完了します。

3. JWTトークン生成 → 4. 接続

{
  "mcpServers": {
    "google-ads": {
      "command": "mcp-remote",
      "args": [
        "https://your-worker-url/mcp",
        "--header",
        "Authorization: Bearer your-jwt-token"
      ]
    }
  }
}

mcp-remote はリモートMCPサーバーへの接続を仲介するプロキシツールです。Claude Desktopのstdioトランスポートと、リモートサーバーのStreamable HTTPトランスポートの間を橋渡しします。

運用Tips

  • wrangler tail で本番環境のログをリアルタイムに確認できる——デバッグ時に重宝する
  • ヘルスチェックGET / でサーバー情報とツール一覧をJSONで返却
  • JWTトークンは2週間で期限切れ。定期的な再生成が必要
  • check_token_validity ツールで、MCPクライアントから直接トークンの有効性を確認できる——「トークンの状態確認して」と聞くだけ

シリーズ全体で得られたもの

内容

キーポイント

第1回

認証セットアップ

OAuth2クライアント作成、Developer Token取得、テストMCC構築

第2回

ローカルMCPサーバー構築

1ファイルで実装、Claude Desktopから即利用可能

第3回

リモートMCPサーバー構築

どこからでもアクセス可能、Web版Claude対応

今後の展望としては、Durable Objectsを活用したセッション管理(現在はステートレスだが、セッションを維持できれば対話の文脈を跨いだ分析が可能になる)、書き込み系ツールの段階的な追加、他のMCPクライアントからの接続検証を挙げています。

よくある質問

なぜCloudflare Workersを選んだのですか?

SSEストリーミング対応・コールドスタートの短さ・コスト・Honoエコシステムとの親和性の4点です。特にMCPセッションは対話が続くため、実行時間制限のあるプラットフォームは不利になります。

リモート化すると何ができるようになりますか?

PCを起動していなくても使え、チームで共有でき、Web版のClaudeからも接続できます。ローカル版はstdioのため同じマシン上でしか動きません。

認証はどうしていますか?

JWT Bearer Tokenです。公開エンドポイントになるため必須になります。署名検証に加えてペイロード内のsaltを環境変数と照合する二重チェックを入れ、有効期限は2週間にしています。

ツール数がローカル版より少ないのはなぜですか?

ローカルファイルシステムに依存するツールを除外したためです。リモートサーバーにはファイルシステムがないため、画像ダウンロードのようなツールは構造的に不要になります。

まとめ

  • ローカルとリモートの違いは通信方式(stdio vs Streamable HTTP/SSE)
  • プラットフォーム選定の軸はSSE対応・コールドスタート・コスト・エコシステム
  • MCPセッションは対話が続くため、実行時間制限が最大の分岐点になる
  • ステートレス設計は制約だが、生存管理やメモリリークの心配がなくなる
  • 公開エンドポイントになるため認証は必須。JWT + salt の二重チェック
  • Workers環境の制約が、ライブラリに隠蔽されていたOAuth2の仕組みの理解を促した
  • リモート化でファイルシステム依存のツールは構造的に不要になる

ローカルで動くものをそのままクラウドに移すことはできません。実行環境の制約に合わせて構成を組み替える過程で、仕組みの理解が深まります。

株式会社AI棒では、こうしたAI活用の検証を日々行い、企業の広告運用・マーケティング業務へのAI導入を支援しています。ご相談はお問い合わせフォームから、継続的な伴走支援についてはAI参謀をご覧ください。

関連する検証事例

© 株式会社AI棒 All Rights Reserved.