ローカル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_SALTwrangler 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参謀をご覧ください。
