Skip to main content
DNZ is an MCP server: Claude, Cursor, VS Code and other assistants that speak the Model Context Protocol can look up zones and records, explain why a name answers the way it does, read the query log, statistics, threats and the audit log and, if you allow it, change records. Ask things like “why doesn’t app.example.com resolve from 10.0.4.7?”, “audit example.com” or “point staging at 192.0.2.40”. It is off until a superadmin turns it on. Then there are two ways to connect:
  • A URL, https://<your DNZ>/mcp (Streamable HTTP). The assistant signs in with OAuth on its first connection: you log in to DNZ as usual (two-factor included), see which app asks, and pick read only or read and change. Or it sends an API token as the bearer token.
  • A command, dnz mcp (stdio), for assistants that start a program. It uses the session from dnz login or an API token, like every other dnz command, and is read only unless started with --allow-writes.
Either way every tool goes through DNZ’s HTTP API as you (or as the token): you see what your roles let you see, change approval applies, and history and the audit log show the change as made through MCP, e.g. alice via Claude.

Turn it on

The /mcp endpoint is off until a superadmin turns it on: nothing answers there and no app can sign in. Turn it on under Settings → Integrations → AI assistants → Turn on, or:
It takes effect at once, on every server of a cluster, without a restart. dnz settings mcp off (or Turn off) shuts it again, and also shuts out the apps already signed in until it’s back on; their grants stay, so they work again when it is. To have it on from the first start, set DNZ_MCP=true (or mcp = true under [http] in the config file); a switch made in the dashboard or the CLI wins over that. dnz mcp with an API token works either way: it is a client of the API like any other dnz command.

Connect

Settings → Integrations → AI assistants in the dashboard has the URL for your server and these steps with copy buttons.

Claude (claude.ai, Claude Desktop)

  1. Settings → Connectors → Add custom connector.
  2. Name it DNZ and paste https://dns.example.com/mcp.
  3. Connect, log in to DNZ if asked, choose the access and Allow.
claude.ai connects from Anthropic’s servers, so the URL must be reachable from the internet over HTTPS. For a DNZ that is only on your network, use Claude Desktop with the dnz mcp command below.

Claude Code

Then run /mcp in Claude Code and choose dnz → Authenticate.

Cursor

~/.cursor/mcp.json (or .cursor/mcp.json in a project):

VS Code

.vscode/mcp.json, or MCP: Add Server… → HTTP:

With an API token instead of signing in

Any client that lets you set headers can skip OAuth: create a token under Settings → API tokens (API tokens) and send Authorization: Bearer dnz_…. The token’s permissions and zones decide what the tools may read and change. With Claude Code:

As a command (stdio)

Install the dnz binary where the assistant runs (it doesn’t have to be the DNZ server), then either sign in once with dnz login --server https://dns.example.com, or give it an API token:
Leave out --allow-writes for read only. That’s claude_desktop_config.json for Claude Desktop, and the same shape for Cursor; for Claude Code:
This is also how to connect a DNZ that runs without the web UI (DNZ_UI=false), where signing in with OAuth isn’t possible.

Tools

Tools that list something long take page (from 1) and limit (rows per page, at most 200), and answer with total, page and per_page next to the list, so the assistant can tell there is more and ask for the next page. ✎ marks the tools that change DNS or what visitors see. They are only offered with read and change access (OAuth), --allow-writes (stdio) or an API token. A change that needs approval isn’t made: the tool answers with the change request’s number instead. No tool approves changes, deletes zones, rolls back or restores a route version. Each zone is also a resource, dnz://zone/<name>, with its zone file. And there are three prompts (slash commands in clients that show them): audit_zone, troubleshoot_name and recent_changes.

What an OAuth sign-in may do

The token an assistant gets acts as the user who allowed it, with their divisions and roles, and:
  • Read only reads what that user can read in the API, except accounts, sessions, users, two-factor, OAuth apps, API tokens and division members, DNS update keys, backups, settings, notification providers, Cloudflare connections, ACME credentials, the server’s system and setup pages, the cluster, and the private CA’s keys (a certificate’s private key and the CA’s export). Proxies, routes, upstreams, middlewares, route groups, maintenance windows and the rest are readable. It may also make the calls that only look: a live capture, planning a proxy’s YAML (never applying it), checking a route’s rules and looking an upstream’s DNS name up (nothing saved).
  • Read and change also creates, changes and deletes records, creates zones and changes a zone’s settings (typo help), clears the DNS cache and a proxy’s cache, sets, switches and removes status pages, edits a route (its upload limits, redirect, web application firewall and rules, group), edits several routes at once (batch edit and Set status page), saves the route groups, and creates and changes scheduled maintenance windows, upstreams and middlewares. DNZ still refuses an assistant passwords and sign-in on routes and middlewares. Nothing else: no zone deletion, no rollbacks, no approvals, no settings, no applying a proxy’s YAML, no new or deleted routes, and no deleting or merging maintenance windows, upstreams or middlewares.
Access tokens last an hour; the assistant renews them with a refresh token that lasts 30 days from its last use and is replaced every time. Account → Connected apps (your name in the top bar) lists the apps you allowed, with their access and last use, and signs them out; so does dnz mcp apps / dnz mcp revoke <id> (CLI). Changing your password, a superadmin resetting it, or the account being switched off signs every app out.

How it works

  • Discovery: an unauthenticated request to /mcp gets 401 with WWW-Authenticate: Bearer resource_metadata=… pointing at /.well-known/oauth-protected-resource/mcp (RFC 9728), which names this server as the authorization server; /.well-known/oauth-authorization-server (RFC 8414) has the endpoints.
  • Registration: clients register themselves at /oauth/register (RFC 7591) as public clients (no secret). Redirect URIs must be https://, http:// on localhost / 127.0.0.1 / [::1] (any port), or an app’s own scheme (cursor://…). Apps nobody approved are forgotten after a day.
  • Authorization: /oauth/authorize checks the request and sends you to the consent page at /oauth/consent; PKCE with S256 is required, codes last five minutes and work once. Scopes are dnz:read and dnz:write.
  • Tokens: /oauth/token (authorization code and refresh token grants), /oauth/revoke (RFC 7009). Access tokens start with dnzo_, refresh tokens with dnzr_; only their SHA-256 is stored.
  • MCP: POST /mcp takes one JSON-RPC message (or a batch) and answers with JSON; no sessions and no server-sent stream (GET is 405). Protocol revisions 2025-11-25, 2025-06-18, 2025-03-26 and 2024-11-05. The tools call the API over this machine’s loopback with your token; the audit log still shows the assistant’s own address.
  • The metadata uses the scheme and host the request came in on, so put DNZ behind your TLS proxy (or give it a certificate) and connect with that address. Most clients refuse to sign in over plain HTTP except on localhost.