Skip to main content
Glama

cloudflare-dns-mcp

An MCP server that lets an LLM check, claim, release, and list subdomains under a root domain, backed by the Cloudflare DNS API. Runs over stdio (local, default) or streamable HTTP (remote, behind a bearer token).

Tools

  • check_subdomain_availability — check whether <subdomain>.<root_domain> already has a DNS record.

  • request_domain — claim <subdomain>.<root_domain> by creating an A record pointing at an IPv4 address. Fails if the subdomain is already taken.

  • release_subdomain — delete the DNS record for <subdomain>.<root_domain>, freeing it up again.

  • list_subdomains — list every record under <root_domain> currently registered.

Related MCP server: Cloudflare MCP Server

Setup

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

Copy .env.example to .env and fill in your Cloudflare credentials:

cp .env.example .env

Variable

Required

Description

CLOUDFLARE_API_TOKEN_DNS

yes

Cloudflare API token with Zone:DNS:Edit permission for the target zone.

CLOUDFLARE_ZONE_ID

yes

Zone ID of the domain in Cloudflare.

CLOUDFLARE_ROOT_DOMAIN

yes

Root domain that subdomains are created under, e.g. example.com.

CLOUDFLARE_API_BASE_URL

no

Overrides the Cloudflare API base URL. Defaults to https://api.cloudflare.com/client/v4.

Running

By default the server runs over stdio, meant to be launched by an MCP client rather than run standalone:

python main.py

To run it as a standalone remote server over streamable HTTP instead, set MCP_TRANSPORT=http plus a shared-secret MCP_HTTP_TOKEN (see .env.example):

MCP_TRANSPORT=http MCP_HTTP_HOST=0.0.0.0 MCP_HTTP_PORT=8000 MCP_HTTP_TOKEN=a-long-random-secret python main.py

MCP_HTTP_TOKEN is required in HTTP mode — the server refuses to start without it, since it can create and delete DNS records and must not be exposed unauthenticated. Every request needs Authorization: Bearer <token>; requests without it (or with the wrong token) get a 401. Put a reverse proxy with TLS in front of it if it's reachable from the public internet.

Claude Code

claude mcp add cloudflare-dns /path/to/.venv/bin/python /path/to/main.py \
  --env CLOUDFLARE_API_TOKEN_DNS=your-token \
  --env CLOUDFLARE_ZONE_ID=your-zone-id \
  --env CLOUDFLARE_ROOT_DOMAIN=example.com

Or add it by hand to .mcp.json (project scope) or ~/.claude.json (user scope):

{
  "mcpServers": {
    "cloudflare-dns": {
      "command": "/path/to/.venv/bin/python",
      "args": ["/path/to/main.py"],
      "env": {
        "CLOUDFLARE_API_TOKEN_DNS": "your-token",
        "CLOUDFLARE_ZONE_ID": "your-zone-id",
        "CLOUDFLARE_ROOT_DOMAIN": "example.com"
      }
    }
  }
}

If the server is running remotely over HTTP instead:

claude mcp add --transport http cloudflare-dns https://your-host/mcp \
  --header "Authorization: Bearer your-mcp-http-token"

or in .mcp.json:

{
  "mcpServers": {
    "cloudflare-dns": {
      "type": "http",
      "url": "https://your-host/mcp",
      "headers": {
        "Authorization": "Bearer your-mcp-http-token"
      }
    }
  }
}

opencode

Add to opencode.json (project) or ~/.config/opencode/opencode.json (global):

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "cloudflare-dns": {
      "type": "local",
      "command": ["/path/to/.venv/bin/python", "/path/to/main.py"],
      "enabled": true,
      "environment": {
        "CLOUDFLARE_API_TOKEN_DNS": "your-token",
        "CLOUDFLARE_ZONE_ID": "your-zone-id",
        "CLOUDFLARE_ROOT_DOMAIN": "example.com"
      }
    }
  }
}

If the server is running remotely over HTTP instead, use type: "remote":

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "cloudflare-dns": {
      "type": "remote",
      "url": "https://your-host/mcp",
      "enabled": true,
      "headers": {
        "Authorization": "Bearer your-mcp-http-token"
      }
    }
  }
}

Other MCP clients

Generic stdio client config:

{
  "mcpServers": {
    "cloudflare-dns": {
      "command": "/path/to/.venv/bin/python",
      "args": ["/path/to/main.py"],
      "env": {
        "CLOUDFLARE_API_TOKEN_DNS": "...",
        "CLOUDFLARE_ZONE_ID": "...",
        "CLOUDFLARE_ROOT_DOMAIN": "example.com"
      }
    }
  }
}

Generic streamable HTTP client config:

{
  "mcpServers": {
    "cloudflare-dns": {
      "type": "http",
      "url": "https://your-host/mcp",
      "headers": {
        "Authorization": "Bearer your-mcp-http-token"
      }
    }
  }
}

Security

Never commit your .env file — it contains a Cloudflare API token that can edit DNS records for your zone. .gitignore already excludes it; only .env.example (with placeholder values) is tracked.

If you run the HTTP transport, MCP_HTTP_TOKEN is the only thing standing between the internet and DNS write access to your zone — treat it like the Cloudflare token itself (long/random, not committed, rotated if it ever leaks), and put it behind TLS.

Related MCP Connectors

Related MCP Servers