---
title: "MCPサーバーをCloudflare Workersでリモート化する｜プラットフォーム選定の4つの軸"
excerpt: "ローカルMCPの「PCが起動していないと使えない」制約を、Cloudflare Workersへの移行で解消しました。MCPセッションは対話が続くため実行時間制限が最大の分岐点になります。ステートレス設計・JWT二重チェック・ファイルシステム依存ツールの除外という判断をまとめています。"
author: "AI活編集部"
author_username: ai-katsu-editorial
published_at: 2026-04-05T00:00:00+00:00
verified_at: 2026-04-05T00:00:00+00:00
tools: ["Google Ads", "MCP", "Cloudflare"]
tasks: ["開発・エンジニアリング", "ツール検証"]
domain: "マーケティング"
canonical_url: https://ai-katsu.jp/articles/google-ads-mcp-remote-server
---
# MCPサーバーをCloudflare Workersでリモート化する｜プラットフォーム選定の4つの軸

ローカル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導入を支援しています。ご相談は[お問い合わせフォーム](/contact)から、継続的な伴走支援については[AI参謀](/ai-sanbo)をご覧ください。
