Skip to main content
Glama
README.md
# 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

B3.4/5.0

Scored across 32 tools

Disambiguation4/5

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.

Naming Consistency4/5

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.

Tool Count2/5

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.

Completeness2/5

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.

Maintenance

ActivityInactive
ResponsivenessNo issues