fastmcp4-cf
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., "@fastmcp4-cfrun whoami to see which container responds"
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.
fastmcp4-cf
A Python MCP server on Cloudflare — FastMCP 4 speaking the MCP 2026-07-28 stateless protocol, on Cloudflare Containers behind a Worker.
Clone it, add tools, deploy.
Why this exists
MCP 2026-07-28 is the largest revision since the protocol launched. It removes
protocol-level sessions: no initialize handshake, no Mcp-Session-Id. Every
request carries its own protocol version and client identity in a _meta
envelope, so any instance can answer any request — which is what makes
round-robin load balancing and scale-to-zero possible at all.
This is a working place to watch that happen:
whoamireports which container answered, and who the server thinks you are. Call it repeatedly — the instance changes mid-conversation, nothing pinned.delete_notesis a guard tool: the multi-round-trip replacement forctx.elicit(), which now raises on modern connections. It also demonstrates per-caller authorization.probe.shspeaks the raw protocol over curl, so you can watch a tool call succeed with no handshake — impossible under 2025-11-25.CI boots the real container behind the real Worker and asserts all of it.
Tracks a beta.
fastmcp==4.0.0b1is the newest FastMCP 4 (no RC yet; stable is still 3.4.x) and pullspydantic 2.14.0a1. Pin your versions.
Related MCP server: Remote MCP Server on Cloudflare
Why Containers, not Workers
Workers run JS/TS on V8 isolates; Python there goes through Pyodide, which takes
only pure-Python and PyEmscripten wheels — and FastMCP's tree includes
pydantic-core, which is Rust. So Python MCP on Cloudflare means Containers,
which run an ordinary linux/amd64 image with FastMCP unmodified.
The tradeoff: containers are regional, started on demand in the nearest region — not per-PoP like Workers. Closer to Cloud Run than to edge. If you want true edge, you want TypeScript and Cloudflare's Agents SDK, not this.
Shape
request → src/index.ts (Worker) → Dockerfile → server.py (FastMCP 4)
routes + passes secrets inContainers are not standalone: a Worker receives every request and picks which instance handles it.
file | role |
| the MCP server — put your tools here |
|
|
| the Worker: routing, secrets, protocol-era handling |
| container, Durable Object binding, migration |
| smoke tool — raw 2026-07-28 over curl |
read before exposing this — authn/authz | |
gotchas that cost real time to find |
Prerequisites
Docker running — wrangler builds the image locally
Workers Paid plan — Containers are not on the free tier
Node 20+
Run locally
No Cloudflare account needed — the container runs in local Docker.
npm install
cp .dev.vars.example .dev.vars
python -c "import secrets; print(secrets.token_hex(32))" # paste into .dev.vars
npm run dev # ready on :8787Then, in another shell:
./probe.sh http://localhost:8787 server/discover
./probe.sh http://localhost:8787 tools/call whoami.dev.vars is local-dev config and deliberately holds no auth settings — you
cannot mint a Cloudflare Access token on localhost, so adding them makes every
local request 401. Deploy-time values live in .deploy.vars instead.
server/discover replaced the initialize handshake — it returns
supportedVersions, resultType, instructions, and cache hints. Call
whoami a few times and watch instance change: several containers answering
one client, no session between them.
Faster loop: no Docker, no Worker
wrangler dev rebuilds the image on every start, which is slow when you are
just iterating on tool code. To run the MCP server on its own — no container,
no Worker, no load balancing, but the same protocol:
python -m venv .venv && . .venv/bin/activate
pip install --pre -r requirements.txt
REQUEST_STATE_KEY=$(python -c "import secrets; print(secrets.token_hex(32))") \
PORT=9000 python server.py
./probe.sh http://localhost:9000 tools/call whoamiUse wrangler dev when you care about the Worker, the routing, or anything
Cloudflare-shaped; use this when you are writing tools.
The server asking a question back
delete_notes returns a question instead of blocking on one:
# Round 1 — the server asks. Note resultType: "input_required".
./probe.sh http://localhost:8787 tools/call delete_notes '{"folder":"notes"}'
# Round 2 — retry the SAME call with the answer and the state.
STATE=$(./probe.sh http://localhost:8787 tools/call delete_notes '{"folder":"notes"}' \
| python3 -c "import json,sys; print(json.load(sys.stdin)['result']['requestState'])")
./probe.sh http://localhost:8787 tools/call delete_notes '{"folder":"notes"}' \
'{"confirm":{"action":"accept","content":{"value":true}}}' "$STATE"The tool body runs from the top on both rounds — locals don't survive.
ctx.input_responses is None the first time, populated the second; anything
else that must carry over goes in request_state.
Deploy
npx wrangler login
npx wrangler secret put REQUEST_STATE_KEY # 32+ bytes of randomness
npm run deployFirst provisioning takes a few minutes. Then:
./probe.sh https://fastmcp4-cf.<your-subdomain>.workers.dev tools/call whoamiREQUEST_STATE_KEY seals the multi-round-trip request_state. Every instance
needs the same value — see NOTES.md for why the default breaks
under a load balancer. The server refuses to boot without it.
Adding your own tools
@mcp.tool
def my_tool(arg: str) -> str:
"""Docstring becomes the tool description the model reads."""
return f"got {arg}"Two constants are duplicated by necessity — keep them in sync:
port
8080:Dockerfile(EXPOSE),src/index.ts(defaultPort),server.pyinstance count:
src/index.ts(INSTANCES) andwrangler.jsonc(max_instances)
server.py runs with stateless_http=True, which is what lets both
protocol eras be load-balanced with no affinity. Turn it off and clients on the
old protocol break intermittently — see NOTES.md.
Authentication
Off by default — as cloned, anyone with the URL can call every tool, and the server says so on boot.
Cloudflare Access is wired up and needs no code: Access runs the OAuth flow
at the edge and forwards a signed JWT, which server.py verifies.
npx wrangler secret put ACCESS_TEAM_DOMAIN # yourteam.cloudflareaccess.com
npx wrangler secret put ACCESS_AUD # the application's AUD tag
npx wrangler secret put ADMIN_EMAILS # who may call gated tools
npm run deployVerified end to end on a plain workers.dev hostname — no custom domain needed.
Two dashboard settings will block you if missed; both are in
AUTH.md, along with per-caller tool visibility, service tokens
for CI, and the rules worth treating as non-negotiable.
Any other provider — Google, Auth0, WorkOS, Keycloak — swaps into build_auth().
Teardown
wrangler delete removes the Worker but leaves the container application and
the pushed image, which keeps costing storage:
npx wrangler delete
npx wrangler containers list && npx wrangler containers delete <ID>
npx wrangler containers images list && npx wrangler containers images delete <image>Delete the Access application separately in the Zero Trust dashboard.
probe.sh
A smoke tool, not a client library. It sends the required headers and _meta
envelope and supports multi-round-trip retries. Its requestState escaping
handles quotes only. For real client work use the
MCP Inspector.
License
MIT — see LICENSE.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Flicense-qualityCmaintenanceA Cloudflare Workers-based MCP server that enables deployment of custom tools accessible via the Model Context Protocol without authentication requirements.Last updated
- Flicense-qualityFmaintenanceA remote MCP server deployed on Cloudflare Workers with OAuth authentication, enabling secure tool calling over SSE.Last updated
- Flicense-qualityCmaintenanceA remote MCP server deployable on Cloudflare Workers without authentication, enabling custom tool definitions and connections via SSE to clients like Cloudflare AI Playground or Claude Desktop.Last updated
- Flicense-qualityCmaintenanceA remote MCP server deployed on Cloudflare Workers without authentication, enabling tool usage via SSE from clients like Cloudflare AI Playground and Claude Desktop.Last updated1
Related MCP Connectors
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
Cloudflare Workers MCP server: crypto-signal
Cloud-hosted MCP server for durable AI memory
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/tameernoor/fastmcp4-cf'
If you have feedback or need assistance with the MCP directory API, please join our Discord server