MCP server for programmatic Cloudflare API token management.
cd workers/cloudflare-token-manager
pnpm installYou need a "bootstrap" token with permission to create other tokens:
- Go to Cloudflare Dashboard
- Create Token → Create Custom Token
- Name:
Token Manager Bootstrap - Permissions: User → API Tokens → Edit
- (Recommended) Add IP restrictions and expiration
- Create Token and copy the value
# Bootstrap token for creating other tokens
pnpm exec wrangler secret put CLOUDFLARE_BOOTSTRAP_TOKEN
# API key for MCP authentication
openssl rand -base64 32 # Generate a key
pnpm exec wrangler secret put MCP_API_KEYexport CLOUDFLARE_API_TOKEN=$(grep CLOUDFLARE_API_TOKEN ../../.env.local | cut -d'=' -f2)
pnpm exec wrangler deployAdd the MCP server using the CLI:
# Add remote MCP server with authentication header
claude mcp add cloudflare-tokens \
--transport http \
--url "https://cloudflare-token-manager.<subdomain>.workers.dev/mcp" \
--header "X-API-Key: your-mcp-api-key"
or
claude mcp add cloudflare-tokens \
--transport http \
--url "https://cloudflare-token-manager.<subdomain>.workers.dev/mcp" \
--header "X-API-Key: $MCP_API_KEY"
# Verify it was added
claude mcp list
# Remove if needed
claude mcp remove cloudflare-tokensFor local development:
claude mcp add cloudflare-tokens-dev \
--transport http \
--url "http://localhost:8787/mcp" \
--header "X-API-Key: test-key"Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or ~/.config/claude/claude_desktop_config.json (Linux):
{
"mcpServers": {
"cloudflare-tokens": {
"url": "https://cloudflare-token-manager.<subdomain>.workers.dev/mcp",
"headers": {
"X-API-Key": "your-mcp-api-key"
}
}
}
}{
"mcpServers": {
"cloudflare-tokens": {
"command": "npx",
"args": [
"mcp-remote",
"https://cloudflare-token-manager.<subdomain>.workers.dev/mcp",
"--header",
"X-API-Key: your-mcp-api-key"
]
}
}
}| Tool | Description |
|---|---|
list_permission_groups |
List all available permission groups |
list_templates |
List preset token templates |
get_template |
Get template details with resolved permissions |
list_tokens |
List user or account tokens |
get_token |
Get token details |
create_token |
Create token from template or custom permissions |
revoke_token |
Delete/revoke a token |
verify_token |
Check if a token is valid |
rotate_token |
Create new token with same permissions |
list_accounts |
List accessible Cloudflare accounts |
get_account |
Get account details |
| Template | Description |
|---|---|
full_access |
All account and zone permissions |
workers_deploy |
Workers, KV, R2, D1, Queues, Vectorize |
pages_deploy |
Cloudflare Pages only |
dns_only |
DNS record management |
dns_read |
DNS read-only |
cache_purge |
Cache purge only |
analytics_read |
Analytics read-only |
api_tokens_manage |
Create/manage API tokens |
zero_trust_admin |
Zero Trust settings |
waf_admin |
WAF rules |
curl -X POST https://cloudflare-token-manager.<account>.workers.dev/mcp \
-H "X-API-Key: your-key" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "create_token",
"arguments": {
"type": "user",
"name": "CI/CD Full Access",
"template": "full_access",
"expiresIn": "90d"
}
}
}'curl -X POST https://cloudflare-token-manager.<account>.workers.dev/mcp \
-H "X-API-Key: your-key" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "create_token",
"arguments": {
"type": "account",
"accountId": "your-account-id",
"name": "Workers Deploy",
"template": "workers_deploy",
"expiresIn": "30d",
"ipAllow": ["192.0.2.0/24"]
}
}
}'curl -X POST https://cloudflare-token-manager.<account>.workers.dev/mcp \
-H "X-API-Key: your-key" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_permission_groups",
"arguments": {
"filter": "workers"
}
}
}'curl -X POST https://cloudflare-token-manager.<account>.workers.dev/mcp \
-H "X-API-Key: your-key" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "rotate_token",
"arguments": {
"type": "user",
"tokenId": "abc123...",
"revokeOld": true,
"newName": "CI/CD Token v2"
}
}
}'| Endpoint | Method | Description |
|---|---|---|
/mcp |
POST | MCP JSON-RPC endpoint |
/health |
GET | Health check (verifies bootstrap token) |
/templates |
GET | List available token templates (public) |
All responses include:
X-Correlation-ID- Request tracking ID for debugging
Rate-limited responses (HTTP 429) include:
X-RateLimit-Remaining- Requests remaining in windowX-RateLimit-Reset- Unix timestamp when window resets
-
Bootstrap Token Security: The bootstrap token can create tokens with any permissions. Protect it carefully:
- Use IP restrictions
- Set short TTL
- Monitor usage via Cloudflare audit logs
-
Permission Escalation: Cloudflare prevents creating tokens with more permissions than the bootstrap token has.
-
Account Restrictions: Set
ALLOWED_ACCOUNT_IDSenvironment variable to restrict which accounts can be managed. -
Token Secrets: Token secrets are only shown once on creation. The MCP response includes a warning about this.
-
Rate Limiting: Token creation/revocation/rotation is rate-limited per client IP (default: 10/minute). Returns HTTP 429 when exceeded.
-
Audit Logging: Enable structured audit logs for compliance.
-
Input Validation: All tool arguments are validated against JSON schemas using Zod. IP CIDR ranges are validated before being sent to Cloudflare.
-
Timing-Safe Auth: API key comparison uses constant-time comparison to prevent timing attacks.
| Variable | Description | Default |
|---|---|---|
ALLOWED_ACCOUNT_IDS |
Comma-separated account IDs to restrict access | (none - all allowed) |
RATE_LIMIT_PER_MINUTE |
Max token operations per IP per minute | 10 |
ENABLE_AUDIT_LOG |
Set to "true" to enable structured audit logging |
false |
When ENABLE_AUDIT_LOG=true, operations are logged as structured JSON:
{
"level": "info",
"type": "audit",
"timestamp": "2024-01-15T10:30:00.000Z",
"operation": "create_token",
"tokenType": "user",
"tokenName": "CI/CD Token",
"success": true,
"clientIp": "192.0.2.1"
}View logs in Cloudflare Dashboard → Workers → Logs, or use wrangler tail.
pnpm dev # Start local server on port 8787Test locally:
curl -X POST http://localhost:8787/mcp \
-H "X-API-Key: test-key" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'pnpm test # Run all tests
pnpm test:watch # Run tests in watch modeTest suite includes 124 tests covering:
- Error categorization and handling
- Expiration parsing and validation
- Rate limiting (KV and in-memory fallback)
- Tool schema definitions
- Request tracing and correlation IDs
- Input validation and schema conversion