cf-mcp
# cf-mcp
Read-only Cloudflare MCP server for SOC investigation agents (companion to
`sumologic-mcp`, `flare-mcp`, `mcp-virustotal`).
Exposes:
- **Discovery** — accounts, zones
- **Rulesets & WAF** — custom rules, rate-limit rules, managed rulesets
- **Bot Management** — config, Super Bot Fight Mode
- **Analytics (GraphQL)** — firewall events, HTTP requests, bot events, baseline traffic diff
- **Cloudflare One / Zero Trust** — Access apps & policies, Gateway rules, WARP devices, IdPs
- **Logpush** — job metadata
- **Helpers** — dashboard URL builder, wirefilter validator
**v1 is strictly read-only.** Every non-GET HTTP request is refused at the
client layer when `CF_READ_ONLY=true` (default).
## Install
```bash
uv sync
```
## Configure
Store your Cloudflare API token in the OS credential store (Windows Credential
Manager / macOS Keychain / Linux Secret Service):
```bash
uv run cf-mcp-setup
```
Alternatively, set the `CF_API_TOKEN` environment variable in your MCP client
config — useful on headless Linux hosts where no keyring backend is available.
### Required token scopes
Create an API token at https://dash.cloudflare.com/profile/api-tokens with at
least these read permissions:
- Zone Read
- Zone WAF Read
- Account Rulesets Read
- Account Settings Read
- Bot Management Read
- Analytics Read (Account + Zone)
- Logs Read
- Access: Apps Read, Access: Policies Read
- Zero Trust: Gateway Read
### Optional env vars
- `CF_ACCOUNT_ID` — default account ID for account-scoped tools.
- `CF_ZONE_ALLOWLIST` — comma-separated zone names; zone-scoped tools refuse
zones not in the list, even if the token has broader access.
- `CF_READ_ONLY` — defaults to `true`; set `false` only if a future v1.5 ships
mutating tools and you've reviewed them.
## MCP client config
### Claude Desktop (`claude_desktop_config.json`)
```json
{
"mcpServers": {
"cloudflare": {
"command": "uv",
"args": ["run", "--project", "/path/to/cf-mcp", "cf-mcp"],
"env": {
"CF_ACCOUNT_ID": "<your-account-id>",
"CF_ZONE_ALLOWLIST": "example.com,example.net"
}
}
}
}
```
## Development
```bash
uv sync
uv run ruff check src tests
uv run mypy --strict src
uv run pytest tests/unit
CF_LIVE_TEST=true uv run pytest tests/integration
```
## Architecture notes
- **One async httpx client per process**, shared across all tool calls.
- **No retry on 429** — the agent decides; `retry_after_s` is
surfaced in the error envelope. **Retry 502/503/504** with exponential
backoff + jitter, max 3 attempts, ~10s total budget.
- **No internal rate-limit accountant** — Cloudflare's edge and the agent are
the only governors. REST quota is 1200/5min; GraphQL is a separate 300/5min.
- **No cache in v1** — the `cache_meta` envelope field is reserved for v1.5.
- **Compact-mode by default** — GraphQL tools return only dimensions + counts.
Detail drill-down via `verbose=true` on `cf_query_firewall_events_raw` and
`cf_query_http_requests_raw`.
- **Hard ~20K-token response ceiling** — exceeding tools return
`response_too_large` with a hint, never silent truncation.
## Response envelope
```json
{
"data": {...},
"next_cursor": "v1.<base64>",
"cache_meta": {"hit": false, "age_s": 0, "ttl_s": 0},
"api_endpoint_called": "POST /graphql",
"correlation_id": "uuid",
"error": null
}
```
On error, `data` is `null` and `error` has:
```json
{
"code": "rate_limited|auth|not_found|validation|upstream|response_too_large|read_only_violation|zone_not_allowed",
"http_status": 429,
"cf_errors": [{"code": 10000, "message": "..."}],
"retry_after_s": 30,
"hint": "narrow the time range or reduce limit"
}
```
TDQS
Scored across 32 tools
Most tools have clear, distinct purposes. However, some overlaps exist: cf_list_custom_rules is a convenience wrapper for cf_get_entrypoint_ruleset's custom WAF phase, and cf_list_super_bot_fight_mode_config is a subset of cf_get_bot_management_config. These could cause minor confusion but are well-documented.
All tools follow the 'cf_[verb]_[noun]' pattern with snake_case (e.g., cf_get_zone, cf_list_zones). One outlier is cf_baseline_traffic_diff, where 'baseline' is used as a noun rather than a verb, breaking the pattern. Overall, naming is mostly consistent.
32 tools is excessive for a typical MCP server, which ideally has 3-15. While the Cloudflare API is broad, many tools are convenience wrappers (e.g., cf_list_custom_rules) or very specific (cf_baseline_traffic_diff). The count feels bloated and could benefit from consolidation.
The tool set is entirely read-only, lacking any create, update, or delete operations. For a general Cloudflare interface, this is a severe gap. Even for a diagnostic-focused server, essential actions like blocking IPs or modifying rules are missing. The presence of validation and URL-building tools doesn't compensate.