cloudflare-mcp
by LesterAJohn
README.md
# cloudflare-mcp
Cloudflare MCP server built from a reusable MCP architecture with:
- Vault-backed persistent multi-user Cloudflare credentials
- Postgres-backed persistent per-user configuration
- MCP admin key protection for mutating tools
- Dedicated Cloudflare tools plus full API coverage through a generic request tool
- Query suggestion and schema discovery tools for safer LLM workflows
This solution uses Vault-backed multi-user Cloudflare credentials and Postgres-backed per-user configuration as first-class persistence layers.
## Solution Guarantees
- All user credentials are multi-user and scoped by user ID in Vault.
- All secrets are persisted in Vault.
- All non-secret configuration is persisted in Postgres.
- Mutating tools support admin-gate enforcement via `MCP_ADMIN_AUTH_KEY`.
- API coverage is full through `cloudflare_api_request` (`method + path + query + body`) against Cloudflare API v4.
## Architecture
Runtime flow:
1. `src/index.js` (stdio) or `src/http/index.js` (HTTP) loads env, Postgres, Vault.
2. `src/config/env.js` validates Cloudflare, Vault, Postgres, and transport config.
3. `src/services/configStore.js` persists user config in Postgres table `<app>_config`.
4. `src/services/vault.js` persists user secrets and HTTP auth token indexes in Vault KV.
5. `src/services/targetService.js` is the Cloudflare client with Vault token resolution and API calls.
6. `src/mcp/server.js` registers Cloudflare MCP tools and wraps auth/error handling.
7. `src/http/server.js` exposes MCP over HTTP with auth, rate limit, allowlists, and access logs.
## Data Model
Vault per-user Cloudflare token path:
- `<APP_NAME>/users/<normalized-user-id>/cloudflare/tokens`
Vault token payload shape:
```json
{
"userId": "team-a",
"activeTokenId": "primary",
"tokens": {
"primary": {
"tokenId": "primary",
"tokenType": "api_token",
"apiToken": "<secret>",
"active": true,
"notes": "prod",
"createdAt": "2026-07-29T00:00:00.000Z",
"updatedAt": "2026-07-29T00:00:00.000Z"
}
}
}
```
Postgres config scope:
- Table: `<APP_NAME>_config`
- PK: `(user_id, key)`
- Common keys:
- `cloudflare.default.accountId`
- `cloudflare.default.zoneId`
- `cloudflare.default.tokenId`
## Environment
Copy `.env.example` to `.env` and set values.
Required runtime groups:
- Postgres: `POSTGRES_HOST`, `POSTGRES_PORT`, `POSTGRES_DB`, `POSTGRES_USER`, `POSTGRES_PASSWORD`
- Vault: `VAULT_ADDR`, `VAULT_TOKEN`, `VAULT_KV_MOUNT` (+ optional agent config)
- Cloudflare: `CLOUDFLARE_API_BASE_URL`, `CLOUDFLARE_API_TIMEOUT_MS`, `CLOUDFLARE_API_DOCS_INDEX_URL`
- MCP auth gate: `MCP_ADMIN_AUTH_KEY` (optional but recommended)
## Run
Install and run stdio:
```bash
npm ci
npm run start:stdio
```
Run HTTP transport:
```bash
npm run start:http
```
Run both:
```bash
npm run start:both
```
Run tests:
```bash
npm test
```
## Docker
Local full stack (app + Postgres + Vault):
```bash
docker compose up -d
```
External Services Mode (app only, external Vault/Postgres):
```bash
docker compose -f docker-compose.external.yml up -d
```
## Tool Catalog
Common response envelope (success):
```json
{
"ok": true,
"status": 200,
"data": {}
}
```
Common error envelope (`isError=true`):
```json
{
"ok": false,
"status": 401,
"error": "Unauthorized: invalid authorizationKey for mutating operation"
}
```
### cloudflare_connection_info
- Use when: you need runtime metadata and auth/scope state.
- Do not use when: you need actual Cloudflare resource data.
- Classification: read-only, low risk.
- Required permissions: none.
- Environment behavior: returns current app/user scope defaults and service connection info.
- Parameters: none.
- Response shape: `{ server, service }`.
- Common failures: unexpected runtime metadata serialization errors.
- Prerequisite tools: none.
- Follow-up tools: `cloudflare_scope_info`, `cloudflare_verify_token`.
- Example:
```json
{"name":"cloudflare_connection_info","arguments":{}}
```
### cloudflare_scope_info
- Use when: you need exact Vault/Postgres scope details for a user.
- Do not use when: you only need API data.
- Classification: read-only, low risk.
- Required permissions: none.
- Environment behavior: defaults `userId` to `MCP_CONFIG_DEFAULT_USER_ID`.
- Parameters:
- `userId?: string`
- Response shape: `{ appName, userId, postgres, vault }`.
- Common failures: normalization/path construction errors.
- Prerequisite tools: `cloudflare_connection_info`.
- Follow-up tools: token/config tools.
- Example:
```json
{"name":"cloudflare_scope_info","arguments":{"userId":"team-a"}}
```
### cloudflare_schema_discovery
- Use when: you need API operation discovery and docs links.
- Do not use when: path/method are already known.
- Classification: read-only, low risk.
- Required permissions: outbound network to docs URL.
- Environment behavior: loads from `CLOUDFLARE_API_DOCS_INDEX_URL`, with caching.
- Parameters:
- `categoryFilter?: string`
- `actionFilter?: string`
- `limit?: integer(1..1000)`
- `forceRefresh?: boolean`
- Response shape: `{ totalOperations, filteredOperations, operations[] }`.
- Common failures: docs fetch unavailable; markdown structure changes.
- Prerequisite tools: `cloudflare_connection_info`.
- Follow-up tools: `cloudflare_query_suggestion`, `cloudflare_api_request`.
- Safety warnings: discovery only, no mutations.
- Example:
```json
{"name":"cloudflare_schema_discovery","arguments":{"categoryFilter":"Zones","limit":25}}
```
### cloudflare_query_suggestion
- Use when: you want tool sequencing and safer invocation hints.
- Do not use when: you are already executing a known workflow.
- Classification: advisory/read-only, low risk.
- Required permissions: none.
- Environment behavior: infers mutating behavior from method/operation type and reports admin-key requirement.
- Parameters:
- `intent?: string`
- `operationType?: discover|read|mutate|token|config|dns`
- `method?: string`
- `path?: string`
- `includeExamples?: boolean`
- `includeToolSchemas?: boolean`
- Response shape: `{ summary, recommendedOrder, safetyChecks, toolSchemas?, examples? }`.
- Common failures: recommendation logic failures.
- Prerequisite tools: none.
- Follow-up tools: whichever sequence is returned.
- Example:
```json
{"name":"cloudflare_query_suggestion","arguments":{"intent":"rotate token and patch dns","operationType":"mutate"}}
```
### cloudflare_token_list
- Use when: you need token metadata for a user.
- Do not use when: you need to create/rotate credentials.
- Classification: read-only, medium risk (metadata exposure).
- Required permissions: none.
- Environment behavior: reads user-scoped Vault path.
- Parameters:
- `userId?: string`
- Response shape: `{ userId, activeTokenId, tokens[] }` (secret values redacted).
- Common failures: Vault read errors.
- Prerequisite tools: `cloudflare_scope_info`.
- Follow-up tools: `cloudflare_token_set_active`, `cloudflare_verify_token`.
- Example:
```json
{"name":"cloudflare_token_list","arguments":{"userId":"default"}}
```
### cloudflare_token_upsert
- Use when: you need to create or rotate Cloudflare credentials for a user.
- Do not use when: you only need metadata read.
- Classification: mutating, high risk.
- Required permissions/prerequisites:
- If `MCP_ADMIN_AUTH_KEY` is set, `authorizationKey` must match.
- `tokenType=api_token`: requires `apiToken`.
- `tokenType=global_api_key`: requires `apiKey` and `email`.
- Environment behavior: writes to user-scoped Vault path; optional active-token switch.
- Parameters:
- `userId?: string`
- `tokenId?: string` (defaults to `primary`)
- `tokenType?: api_token|global_api_key`
- `apiToken?: string`
- `apiKey?: string`
- `email?: string`
- `setActive?: boolean` (default `true`)
- `notes?: string`
- `authorizationKey?: string`
- Response shape: `{ userId, activeTokenId, token(metadata) }`.
- Common failures: admin auth mismatch, missing required token fields, Vault write failures.
- Prerequisite tools: `cloudflare_scope_info`.
- Follow-up tools: `cloudflare_token_list`, `cloudflare_verify_token`.
- Safety warnings: changes live credentials for API execution.
- Example:
```json
{
"name":"cloudflare_token_upsert",
"arguments":{
"userId":"team-a",
"tokenId":"primary",
"tokenType":"api_token",
"apiToken":"<token>",
"setActive":true,
"authorizationKey":"<admin-key-if-required>"
}
}
```
### cloudflare_token_set_active
- Use when: multiple tokens exist and you need to switch active token.
- Do not use when: token is missing; create it first.
- Classification: mutating, high risk.
- Required permissions: admin key when configured.
- Parameters:
- `userId?: string`
- `tokenId: string`
- `authorizationKey?: string`
- Response shape: `{ userId, activeTokenId }`.
- Common failures: token not found, Vault write failure, auth mismatch.
### cloudflare_token_delete
- Use when: decommissioning a user token.
- Do not use when: uncertain if token is in active use.
- Classification: mutating, high risk.
- Required permissions: admin key when configured.
- Parameters:
- `userId?: string`
- `tokenId: string`
- `authorizationKey?: string`
- Response shape: `{ deleted, userId, tokenId, activeTokenId? }`.
- Common failures: Vault write failure; auth mismatch.
- Safety warnings: irreversible token removal.
### cloudflare_config_list
- Use when: you need all or prefixed config rows in Postgres.
- Do not use when: you need one key only.
- Classification: read-only, low risk.
- Required permissions: none.
- Parameters:
- `userId?: string`
- `prefix?: string`
- Response shape: `{ userId, configs[] }`.
### cloudflare_config_get
- Use when: you need one config value.
- Do not use when: you need bulk config listing.
- Classification: read-only, low risk.
- Required permissions: none.
- Parameters:
- `userId?: string`
- `key: string`
- Response shape: `row|null`.
### cloudflare_config_set
- Use when: setting default account/zone/token or custom config.
- Do not use when: no persisted config change is needed.
- Classification: mutating, medium risk.
- Required permissions: admin key when configured.
- Parameters:
- `userId?: string`
- `key: string`
- `value: any JSON`
- `authorizationKey?: string`
- Response shape: upserted row.
### cloudflare_config_delete
- Use when: removing obsolete config keys.
- Do not use when: key may still be required for production defaults.
- Classification: mutating, medium risk.
- Required permissions: admin key when configured.
- Parameters:
- `userId?: string`
- `key: string`
- `authorizationKey?: string`
- Response shape: `{ deleted: boolean }`.
### cloudflare_verify_token
- Use when: validate selected credential health before operations.
- Do not use when: token validity is already confirmed in current workflow.
- Classification: read-only, low risk.
- Required permissions: valid Cloudflare token in Vault for selected scope.
- Parameters:
- `userId?: string`
- `tokenId?: string`
- Response shape: proxied `/user/tokens/verify` payload.
- Common failures: missing/invalid token, Cloudflare auth errors.
### cloudflare_list_accounts
- Use when: discover accessible accounts.
- Do not use when: account ID already known and not needed.
- Classification: read-only, low risk.
- Parameters:
- `userId?: string`
- `tokenId?: string`
- `page?: integer`
- `perPage?: integer`
### cloudflare_list_zones
- Use when: discover zones, optionally per account/name.
- Do not use when: exact zone ID already known and no listing required.
- Classification: read-only, low risk.
- Parameters:
- `userId?: string`
- `tokenId?: string`
- `accountId?: string`
- `name?: string`
- `page?: integer`
- `perPage?: integer`
### cloudflare_list_dns_records
- Use when: review DNS records before mutating operations.
- Do not use when: only direct create/update/delete is needed and target IDs are verified.
- Classification: read-only, medium risk.
- Parameters:
- `userId?: string`
- `tokenId?: string`
- `zoneId?: string` (falls back to `cloudflare.default.zoneId`)
- `type?: string`
- `name?: string`
- `page?: integer`
- `perPage?: integer`
### cloudflare_create_dns_record
- Use when: adding a DNS record.
- Do not use when: uncertain about current zone state; list first.
- Classification: mutating, high risk.
- Required permissions: admin key when configured.
- Parameters:
- `userId?: string`
- `tokenId?: string`
- `zoneId?: string`
- `record: object` (Cloudflare DNS record create payload)
- `authorizationKey?: string`
- Safety warnings: writes production DNS.
### cloudflare_update_dns_record
- Use when: patching/replacing an existing record.
- Do not use when: record ID is not validated.
- Classification: mutating, high risk.
- Required permissions: admin key when configured.
- Parameters:
- `userId?: string`
- `tokenId?: string`
- `zoneId?: string`
- `dnsRecordId: string`
- `record: object`
- `replace?: boolean` (`false` = PATCH, `true` = PUT)
- `authorizationKey?: string`
### cloudflare_delete_dns_record
- Use when: deleting DNS records intentionally.
- Do not use when: rollback plan is missing.
- Classification: mutating, high risk.
- Required permissions: admin key when configured.
- Parameters:
- `userId?: string`
- `tokenId?: string`
- `zoneId?: string`
- `dnsRecordId: string`
- `authorizationKey?: string`
- Safety warnings: destructive and irreversible.
### cloudflare_api_request
- Use when: any Cloudflare endpoint access is needed, including APIs without dedicated tools.
- Do not use when: dedicated tools already cover the operation and are safer.
- Classification: read-only or mutating depending on `method`; variable risk.
- Required permissions/prerequisites:
- Active user-scoped Vault token.
- If mutating (`POST|PUT|PATCH|DELETE`) and `MCP_ADMIN_AUTH_KEY` is set, `authorizationKey` is required.
- Environment behavior:
- Normalizes path to Cloudflare v4 route under `/client/v4`.
- Resolves default token from user config and active token state.
- Parameters:
- `method: string`
- `path: string`
- `query?: object<string, string|number|boolean>`
- `body?: json`
- `headers?: object<string,string>`
- `userId?: string`
- `tokenId?: string`
- `authorizationKey?: string`
- Expected response shape:
- `{ method, path, url, status, tokenId, userId, data }`
- Common failure conditions:
- Missing token in Vault
- Invalid Cloudflare credentials
- Cloudflare API 4xx/5xx
- Admin auth key mismatch for mutating operations
- Recommended prerequisite tools:
- `cloudflare_verify_token`
- `cloudflare_schema_discovery`
- Recommended follow-up tools:
- `cloudflare_config_set` (to persist defaults)
- `cloudflare_query_suggestion` (for workflow refinement)
- Safety warnings:
- Mutating calls can alter/delete production resources.
- Short valid invocation examples:
```json
{"name":"cloudflare_api_request","arguments":{"method":"GET","path":"/zones","userId":"default"}}
```
```json
{"name":"cloudflare_api_request","arguments":{"method":"PATCH","path":"/zones/<zone>/settings/cache_level","body":{"value":"aggressive"},"authorizationKey":"<admin-key-if-required>"}}
```
## Suggested Playbooks
1. Bootstrap new user credentials
- `cloudflare_scope_info`
- `cloudflare_token_upsert`
- `cloudflare_verify_token`
2. Configure user defaults
- `cloudflare_config_set` (`cloudflare.default.accountId`)
- `cloudflare_config_set` (`cloudflare.default.zoneId`)
- `cloudflare_config_set` (`cloudflare.default.tokenId`)
3. Safe DNS mutation
- `cloudflare_list_dns_records`
- `cloudflare_create_dns_record` or `cloudflare_update_dns_record` or `cloudflare_delete_dns_record`
4. Full API call flow
- `cloudflare_schema_discovery`
- `cloudflare_query_suggestion`
- `cloudflare_api_request`
## License
MIT. See `LICENSE`.
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues