cloudflare-mcp is a token-efficient Model Context Protocol (MCP) server that exposes the entire Cloudflare API (~2,500 endpoints) using Cloudflare's Code Mode pattern. Instead of registering thousands of MCP tools, it uses just two tools (search and execute) that let agents write JavaScript to query the OpenAPI spec and call APIs — fitting all 2,500 endpoints into ~1,000 tokens.
Production URL: mcp.cloudflare.com
When modifying MCP or OAuth functionality, always check the latest published MCP specification:
- Specification: https://modelcontextprotocol.io/specification/2025-11-25
- Authorization section: https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization
cloudflare-mcp/
├── src/
│ ├── index.ts # Worker entry point & OAuth/Hono routing
│ ├── server.ts # MCP server setup & tool registration
│ ├── executor.ts # Code executor (Worker Loader API)
│ ├── spec-processor.ts # OpenAPI spec fetching & $ref resolution
│ ├── truncate.ts # Response truncation (~6K token limit)
│ ├── metrics.ts # Analytics Engine metrics (session_start/tool_call)
│ ├── auth/
│ │ ├── types.ts # Auth props schemas (Zod discriminated union)
│ │ ├── api-token-mode.ts # Direct Cloudflare API token support
│ │ ├── cloudflare-auth.ts # PKCE & OAuth utilities
│ │ ├── oauth-handler.ts # OAuth authorization flow
│ │ ├── scopes.ts # OAuth scope definitions (120+ scopes)
│ │ └── workers-oauth-utils.ts # OAuth provider helpers
├── tests/ # Vitest suite (top-level, mirrors src/)
│ ├── index.test.ts
│ ├── auth/
│ ├── executor.test.ts
│ ├── spec-processor.test.ts
│ ├── truncate.test.ts
│ └── e2e/ # End-to-end tests (real worker via exports.default.fetch)
│ └── tool-call.test.ts
├── scripts/
│ └── seed-r2.ts # Seed OpenAPI spec to R2 bucket
├── .github/workflows/
│ ├── ci.yml # PR validation
│ └── bonk.yml # AI code review
├── wrangler.jsonc # Workers config (dev/staging/prod)
├── .oxfmtrc.json # oxfmt formatter config
└── README.md
npm install # Install dependenciesNode 22+ required.
| Command | What it does |
|---|---|
npm run dev |
Start local dev server (wrangler dev) |
npm run deploy |
Deploy to staging |
npm run deploy:prod |
Deploy to production |
npm run types |
Generate worker type definitions |
npm run typecheck |
TypeScript type checking (no emit) |
npm run lint |
Lint with oxlint |
npm run format |
Format with oxfmt |
npm run format:check |
Check formatting without modifying |
npm run test |
Run vitest test suite |
npm run test:watch |
Run vitest in watch mode |
npm run check |
Run all checks (format, lint, typecheck, test) |
npm run seed:staging |
Seed OpenAPI spec to staging R2 |
npm run seed:prod |
Seed OpenAPI spec to production R2 |
- Strict mode enabled
- Target: ES2022, Module: ESNext
- Runtime validation with Zod for auth props and external data
- oxfmt for formatting: single quotes, no semicolons, no trailing commas
- oxlint for linting
- Run
npm run formatbefore committing
PascalCasefor classes, interfaces, types, enumscamelCasefor functions, methods, variablesSCREAMING_SNAKE_CASEfor constants
The core innovation: instead of 2,500 MCP tools (~244K tokens), two tools handle everything:
searchtool — Agents write JavaScript to query the pre-resolved OpenAPI spec (all$refs inlined). Runs in an isolated worker with no network access.executetool — Agents write JavaScript usingcloudflare.request()to call discovered endpoints. Runs in an isolated worker with outbound restricted to Cloudflare API URLs only.
Code execution uses Cloudflare's Worker Loader API to dynamically create isolated worker instances. The API token is passed via props (never enters user code isolate). A globalOutbound service restricts network access.
Two modes via Zod discriminated union (AuthProps):
- OAuth mode (default): Uses
@cloudflare/workers-oauth-providerwith PKCE. Supports both account-scoped and user-scoped tokens. - API token mode: Direct Cloudflare API tokens bypass OAuth. Detection: OAuth tokens have 3 colon-separated parts; API tokens don't.
Max 76 OAuth scopes enforced (Cloudflare server limitation).
- Fetched from GitHub daily (scheduled handler, cron
0 0 * * *) - All
$refreferences resolved inline before storage - Products and minimal operation metadata extracted
- Stored in R2 bucket (
SPEC_BUCKET) asspec.json,products.json, and the precomputednon-codemode-tools.jsonartifact - The non-Code-Mode artifact contains protocol-ready JSON Schemas plus minimal request-routing metadata. Low-level MCP handlers serve
tools/listdirectly and lazily validate/dispatch only the requestedtools/calloperation with Zod; no per-endpoint SDK tools are registered src/isolate-cache.tscaches all three artifacts for one hour in warm isolates; non-Code-Mode falls back to deriving its artifact fromspec.jsonduring rollout
Responses capped at ~6,000 tokens (~24KB). Truncation notice included with original size to prompt agents to write more specific queries.
Tool usage is tracked via the MCP_METRICS Analytics Engine binding into the shared mcp-metrics-{dev,staging,production} dataset — the same dataset used by the per-product Cloudflare MCP servers (cloudflare/mcp-server-cloudflare), so this server shows up alongside them under server name cloudflare-api.
src/metrics.tsmirrors the upstream@repo/mcp-observabilityschema. The blob/double layout is positional and must not change:index1= event type,blob1/blob2= server name/version (reserved),blob3= userId,blob4= toolName/errorMessage,double1= errorCode.attachMetrics()insrc/server.tswraps Code-ModeregisterToolcalls; the lazy non-Code-Mode dispatcher records the sametool_callevents directly.auth_userevents are emitted from the OAuth handler.- No
session_start: unlike the Durable-Object-backed servers, this server is stateless (a freshMcpServerper request), sooninitializedfires on a different request thaninitializeand can never see client info. Client identity comes from the HTTPUser-Agentheader (visible in zone HTTP analytics) instead. - The tracker is tolerant of a missing binding (no-op in tests/local dev) and swallows write errors so metrics can never break a tool call.
- Query via the Analytics Engine SQL API:
SELECT ... FROM 'mcp-metrics-production' WHERE blob1='cloudflare-api' AND index1='tool_call'.
- API tokens never enter user code isolates — passed via worker props
globalOutboundservice restricts execute tool to Cloudflare API URLs only- Search tool runs with no network access
- OAuth uses PKCE (RFC 7636) for secure authorization
- Cookie encryption for OAuth sessions (
MCP_COOKIE_ENCRYPTION_KEY)
Tests live in the top-level tests/ directory (mirroring src/) and use vitest with @cloudflare/vitest-pool-workers.
npm run test # Single run
npm run test:watch # Watch modeUnit/integration coverage areas:
- Scheduled handler (spec fetching & processing)
- Auth token detection and parsing
- Auth props building and validation
- Spec processor ($ref resolution, product extraction)
- Response truncation
- Metrics event mapping & path normalization
End-to-end (tests/e2e/):
Drives the real worker via exports.default.fetch() (from cloudflare:workers), the
pattern from the Cloudflare vitest recipes.
A full JSON-RPC tools/call for execute runs real code inside a Worker Loader
isolate and is forwarded through the real GlobalOutbound proxy. The only mock
is outbound fetch(), declared with MSW (server.use(http.get(...))) — see
tests/e2e/msw-server.ts and tests/e2e/msw-setup.ts. MSW intercepts both the
auth-guard /user+/accounts probes and the GlobalOutbound-forwarded API call.
Everything else — auth, MCP transport, tool dispatch, Worker Loader — is the real
code path.
The test stack is vitest 4 + @cloudflare/vitest-pool-workers 0.16 using the
cloudflareTest() Vite plugin (required for MSW's msw/node to load under
workerd). Note: storage isolation is per test file (not per test), so tests
sharing real bindings (e.g. OAUTH_KV) must clear state in afterEach.
CI runs on every PR:
npm ci— Clean installnpm run format:check— oxfmt formatting checknpm run lint— oxlintnpm run typecheck— TypeScript type checkingnpm run test— Vitest test suite
All checks must pass before merge.
Mention /bonk or @ask-bonk in PR comments to get AI-powered code review and suggestions. Bonk can analyze code, suggest fixes, and even auto-commit improvements.
Always:
- Run
npm run checkbefore considering work done - Add tests for new functionality
- Consider security implications — this handles API tokens and OAuth flows
- Use Zod for runtime validation of external data
Ask first:
- Adding new dependencies
- Changing authentication flows or token handling
- Modifying the OpenAPI spec processing pipeline
- Changing deployment configuration or bindings
Never:
- Hardcode secrets or API keys
- Allow user code to access API tokens directly
- Bypass
globalOutboundnetwork restrictions - Force push to main
Update this file when:
- Adding new modules or significant features
- Changing project structure
- Modifying build/test tooling
- Adding new code patterns or conventions
- Changing contribution workflows