cloudflare-mcp-sample
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@cloudflare-mcp-samplesum the sales column"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
cloudflare-mcp-sample
Cloudflare Workers 上にステートレス方式の最小 MCP サーバを立てるサンプル。
agents パッケージの createMcpHandler を直に使い、テンプレート任せにしない構成にしてある。
ツールは疎通確認用の ping と、CSV の 1 列を合計する sum_csv_column の 2 本だけ。
動作確認済みバージョン
パッケージ | バージョン |
Node.js | 22.23.2 |
| 0.20.1 |
| 2.0.0(完全固定) |
| 4.4.3 |
| 4.123.0 |
TypeScript | 5.9.3 |
Node.js 22 以上が必須。
create-cloudflareもwranglerもengines: { node: ">=22.0.0" }を宣言していて、 Node 20 では警告ではなくWrangler requires at least Node.js v22.0.0.で停止する。
@modelcontextprotocol/serverにキャレット (^2.0.0) を付けないこと。agents@0.20.1のpeerDependenciesは"@modelcontextprotocol/server": "2.0.0"と完全一致で固定されている。 公式ドキュメントも "Use the exact MCP versions required by your installed Agents release." と書いている。
Related MCP server: remote-mcp-server-authless
セットアップ
npm installローカル実行
npm starthttp://127.0.0.1:8787/mcp で待ち受ける。
ドキュメントの手順には
8788と書かれているが、素の Worker をwrangler devで起動した場合は 8787 になる。 起動ログのReady on ...を必ず読むこと。
別ターミナルで MCP Inspector を起動して接続する。
npx @modelcontextprotocol/inspector@latestInspector に http://127.0.0.1:8787/mcp を入力 → Connect → List Tools。
CLI モードでも確認できる。
npx @modelcontextprotocol/inspector@latest --cli http://127.0.0.1:8787/mcp --transport http --method tools/list
/mcpをブラウザで直接開いても確認にはならない。MCP クライアントが話す JSON-RPC を、ブラウザは話さない。
デプロイ
npx wrangler@latest deploy稼働中のエンドポイント: https://cloudflare-mcp-sample.ma2no4413.workers.dev/mcp
npx @modelcontextprotocol/inspector@latest --cli \
https://cloudflare-mcp-sample.ma2no4413.workers.dev/mcp \
--transport http --method tools/list初回は workers.dev サブドメインの登録が要る。 未登録のままでも
wrangler deployはSuccess!を返し、警告 1 行を出すだけで成功したように見える。 しかし実際にアクセスすると DNS はワイルドカードで引けるのに TLS ハンドシェイクで落ちる (Windows ではSEC_E_ILLEGAL_MESSAGE)。ダッシュボードの Workers & Pages → Subdomain で登録し、 もう一度wrangler deployを実行すると URL が正しくなる。 証明書が行き渡るまで実測で約 75 秒かかった。サブドメインはアカウントに 1 つしか持てず、配下の全 Worker の URL に入る。 Worker 名と同じ文字列を選ぶと
foo.foo.workers.devになるので、ハンドル名にしておくのが無難。
Claude Code から使う
.mcp.json を同梱してあるので、clone してディレクトリを開けばそのまま接続できる。
{
"mcpServers": {
"cloudflare-mcp-sample": {
"type": "http",
"url": "https://cloudflare-mcp-sample.ma2no4413.workers.dev/mcp"
}
}
}初回のみ信頼の承認プロンプトが出る(project スコープの MCP サーバは無条件には読み込まれない)。
自分で建てたサーバに向ける場合は URL を書き換えるか、claude mcp add で入れ直す。
claude mcp add --transport http --scope project <name> https://<worker>.<subdomain>.workers.dev/mcp認証は付いていない。 URL を知っていれば誰でも叩ける。機微データを流さないこと。
ツール
ping
引数なし。サーバ名・バージョンとサーバ側の現在時刻 (UTC) を JSON で返す。
{
"server": "cloudflare-mcp-sample",
"version": "0.1.0",
"now": "2026-08-16T10:06:55.511Z"
}sum_csv_column
引数 | 型 | 説明 |
|
| ヘッダ行を含む CSV 文字列 |
|
| 合計したい列のヘッダ名 |
指定列を数値として合計する。数値化できない行(空欄・非数値)はスキップし、その件数も返す。
{ "column": "sales", "sum": 400, "counted": 3, "skipped": 2, "rows": 5 }列名が存在しない場合は isError: true と、実際のヘッダ一覧を返す。
CSV パースは外部ライブラリを使わない素朴な実装で、引用符付きフィールド ("a,b") には対応していない。
サンプルデータ
examples/store-sales.csv に、店舗別・月次売上を模した架空データを置いてある。
集計で現実に効いてくる「汚れ」を意図的に混ぜてある。
S004(休業)—salesもcustomersも空欄S006(POS 障害)—salesだけN/Aでcustomersは生きている
同じファイルでも、集計する列によってスキップ数が変わる。
列 |
|
|
|
|
| 6,054,200 | 6 | 2 | 8 |
| 2,161 | 7 | 1 | 8 |
sales の合計は 8 店舗中 6 店舗分でしかない。skipped を返さない設計だと、
これが「8 店舗の合計」として読まれる。 ツールの戻り値に信頼度の材料を含める理由がこれ。
引用符付きフィールドの壊れ方
store_id,store_name,sales
S001,"Shibuya, Tokyo",1284500
S002,"Shinjuku, Tokyo",1650000sum: 0, counted: 0, skipped: 2 が返る。引用符内のカンマで列がずれ、
sales の位置に Tokyo" が来て全行スキップされる。
間違った合計を返すのではなく skipped が全行に立つので、
戻り値だけで壊れていると分かる。素朴なパーサとしては悪くない壊れ方といえる。
なぜ McpAgent ではなく createMcpHandler なのか
McpAgent は deprecated かつ機能凍結されている。公式ドキュメントの
Handler API が
明示的に "McpAgent is deprecated and feature-frozen" と書いており、新規サーバは
createMcpHandler を使うことになっている。createLegacyMcpHandler はレガシー移行専用。
構造的な理由は状態の置き場所にある。
McpAgentは Durable Object にセッション状態を持たせる設計だった。接続ごとに DO インスタンスが立つ。createMcpHandlerはステートレス。リクエストごとにファクトリ関数からMcpServerを作って捨てる。 状態が要るなら D1 / KV / R2 / Durable Objects に明示的に置く。
状態を持たないサーバに DO を強制されないぶん、コールドスタートも課金も素直になる。 今回のような「引数を受け取って計算して返すだけ」のツールに、セッションは要らない。
agents/mcp/server の createMcpHandler は、実体は createStatelessMcpHandler の別名で、
MCP SDK 側の createMcpHandler を Workers 向けにラップしたもの。次のオプションを足している。
オプション | 既定値 | 内容 |
|
| この Worker が処理する pathname(完全一致) |
| — | CORS ヘッダ。 |
| localhost と | 受け付ける |
| 同上 | 受け付けるブラウザ |
| — |
|
これに加えて、SDK 側の legacy / onerror / responseMode / maxSubscriptions / keepAliveMs が渡せる。
実装上の落とし穴
1. ハンドラを default export に直接置かない
// NG: Wrangler が「関数の default export」を WorkerEntrypoint クラスとして解釈する
export default createMcpHandler(createServer);
// OK
export default {
fetch(request, env, ctx) {
return createMcpHandler(createServer)(request, env, ctx);
},
} satisfies ExportedHandler<Env>;NG 版で起きることを実際に確かめた。wrangler deploy --dry-run は通る。
バンドルは成功し Total Upload: 991.85 KiB まで表示される。落ちるのはランタイムの起動時。
X [ERROR] service core:user:cloudflare-mcp-sample:
Uncaught TypeError: Class extends value (request, _env, ctx) => serve(request, void 0, ctx)
is not a constructor or null
at wrapWorkerEntrypoint
X [ERROR] The Workers runtime failed to start.Wrangler は関数の default export を WorkerEntrypoint として extends しようとする。
関数はコンストラクタではないのでここで死ぬ。ビルドが通ったことは何の保証にもならない。
2. サーバインスタンスではなくファクトリを渡す
グローバルに 1 つ McpServer を作って使い回さない。createMcpHandler に渡すのは関数そのもので、
ハンドラがリクエストごとにサーバを生成する。
3. 引数なしツールでは inputSchema を「省略」する
inputSchema: {} を渡すと registerTool のオーバーロード解決が壊れ、
戻り値の type: "text" が string に広がって型エラーになる。空オブジェクトではなくキーごと消す。
4. import { createMcpHandler } の出どころが 2 つある
@modelcontextprotocol/server にも createMcpHandler が存在する。
Workers で使うのは agents/mcp/server の方(route / CORS / Host 検証を持つラッパ)。
エディタの自動インポートが SDK 側を選んでいないか確認すること。
所感 — CSV を引数で渡す方式の限界
sum_csv_column は本命(店舗別 CSV の横断集計)の最小プロトタイプとして書いた。
実際に動かして分かった限界を残しておく。
CSV 本体を引数で渡す設計は、そのままではスケールしない。 文字列がまるごとモデルのコンテキストを通るため、 数百 KB の実データを渡した時点でトークンを食い潰す。集計は「データを送る」のではなく 「データの置き場所を指す ID を送る」形にすべきで、本命は R2/D1 に置いたデータを
dataset_idで指す設計になる。Workers の CPU 10ms 制約を SQL に逃がす話とも整合する。skippedを返す設計は正解だった。 数値化できない行を黙って捨てると、モデルは合計値を無条件に信じる。 スキップ件数が返っていれば「5 行中 2 行落ちています」とモデル自身が但し書きを付けられる。 ツールの戻り値は「答え」だけでなく「答えの信頼度を判断する材料」を含めるべき。エラーは例外ではなく
isError: trueで返す。 列名が無いときに実際のヘッダ一覧を添えて返すと、 モデルはその場で列名を直して再実行できる。エラーメッセージがそのままリトライの入力になる。MCP Inspector の CLI は
--tool-argに改行を含む値を渡せない。 改行で引数が分割され、 ヘッダ行だけが届いてrows: 0が返る。複数行の値を試すときは Inspector の UI を使うか、fetchで JSON-RPC を直接叩くこと(CLI のパーサの制約であって、サーバ側の問題ではない)。
この先の拡張
Phase 1 は「往復が通ること」と「正しい API を使っていること」だけを成果物にしている。 以下は意図的に外してあるが、捨てたわけではなく順に足していく。
Phase 2 — 認証(OAuth 2.1)
@cloudflare/workers-oauth-provider で OAuth 2.1 のプロバイダ側を肩代わりさせ、
認証済みユーザの情報を createMcpHandler の authContext 経由でツールに渡す。
ツール内では getMcpAuthContext() から読む。
ここは公式に動く実例がまだ無い。authless のデモは
createMcpHandlerに移行済みだが、 OAuth のデモ (cloudflare/ai/demos/remote-mcp-github-oauth) はMcpAgent+ Durable Objects のままで、this.propsを使っている。 一方ドキュメントはgetMcpAuthContext()/context.http.authInfoを使えと書いている。 ライブラリが健在であることと、新しいハンドラに繋がることは別の話で、後者は未検証。
Phase 3 — データの置き場所(R2 / D1)
sum_csv_column で分かったとおり、CSV 本体を引数で渡す設計はスケールしない。
文字列がまるごとモデルのコンテキストを通るため、実データ規模でトークンが破綻する。
「データを送る」のではなく「データの置き場所を指す ID を送る」形に変える。
引数は
dataset_idとクエリ条件だけ。実体は R2 / D1 に置く集計はアプリ側でループを回さず D1 の SQL に寄せる(Workers の CPU 10ms 制約を設計で回避する)
describe_datasetのような「列とデータ型を返すツール」を用意する。 Phase 1 でエラー時に実ヘッダを返す設計が効いたのと同じ理屈で、 モデルに列名を推測させない
Phase 4 — 配布
@modelcontextprotocol/server の ./stdio エクスポートで stdio 版を同梱し、
ローカル実行と Workers ホスト版の二層構成にする。npm への公開もこの段階。
テスト / CI
Phase 1 では入れていない(スキャフォルドの vitest も削除した)。 ツールが 2 本で、検証が Inspector の往復で足りているうちは、 テストを置いても実際には守られない。Phase 3 で集計ロジックが SQL に移り、 「壊れたら気付けない」状態になった時点で入れる。
This server cannot be installed
Maintenance
Related MCP Servers
- Flicense-qualityCmaintenanceA deployable MCP server on Cloudflare Workers that allows you to create and expose custom tools to AI assistants without requiring authentication.
- Flicense-qualityBmaintenanceA remote MCP server deployed on Cloudflare Workers without authentication, allowing users to create custom tools and connect to MCP clients like Cloudflare AI Playground and Claude Desktop.
- Flicense-qualityCmaintenanceAn MCP server deployed on Cloudflare Workers with OAuth login, allowing remote invocation of tools like math operations from MCP-compatible clients.
- Flicense-qualityCmaintenanceDeploy a stateless remote MCP server on Cloudflare Workers without authentication, with custom tool support and compatibility for MCP clients.
Related MCP Connectors
Cloudflare Workers MCP server: crypto-signal
Cloudflare Workers MCP server: email-validator
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/ma2no4413/cloudflare-mcp-sample'
If you have feedback or need assistance with the MCP directory API, please join our Discord server