The full upstream README, mirrored here for reference. Install config, tool schemas, adoption signals, and an original overview live on the DNS MCP Server listing page.
Real-time DNS security analysis for AI assistants via MCP. Gives your assistant the ability to investigate domains the way a practitioner would — DNSSEC chain validation, email authentication posture, and registration intelligence — without leaving your chat session.
Built by a cybersecurity professional for SOC investigation workflows. Not a toy — the same queries you would run at the command line, accessible through any MCP-compatible assistant in real time.
dns-mcp is a Streamable HTTP MCP server with OAuth via Pocket
ID. Tool implementations are thin wrappers around the
dns_tool Python library, which
owns all DNS logic. The server itself is ~430 lines of code: auth bootstrap,
tool registration, and prompt loading.
Three benefits over the previous stdio-only architecture:
whoami.dns_tool is published independently and reusable. The
same code powers a CLI, this MCP server, and (eventually) a REST API.The old stdio architecture lives at server.py.legacy for porting reference.
The remote branch (mcp-shim Go bridge) is deprecated.
dns-mcp 2.0.0 currently exposes 19 tools. Ten additional tools from the
1.x stdio architecture are pending port into dns_tool — see
Open work.
| Tool | Description |
|---|---|
ping | Server uptime, current timestamp, dns_tool version + commit hash |
whoami | Authenticated user identity from JWT claims |
| Tool | Description |
|---|---|
dns_query | Standard DNS lookup over DoH — 20 record types (A, AAAA, MX, TXT, NS, SOA, CNAME, PTR, SRV, CAA, DNSKEY, DS, RRSIG, NSEC, NSEC3, TLSA, SSHFP, HTTPS, SVCB, NAPTR) |
dnssec_validate | Full DNSSEC chain walk from IANA root trust anchor down to target. Real cryptographic validation at every zone cut. Returns structured verdict + per-zone findings + event transcript |
nsec_info | NSEC / NSEC3 denial-of-existence analysis — zone walkability assessment, NSEC3 hash parameters, opt-out detection |
| Tool | Description |
|---|---|
check_spf | SPF record parsing with recursive include resolution (RFC 7208 10-lookup limit) |
check_dmarc | DMARC policy retrieval with organizational domain fallback |
check_dkim | DKIM public key record verification for a selector + domain pair |
enumerate_dkim_selectors | Probe a domain for DKIM keys at well-known selector names; returns the selectors that resolve |
check_dane | DANE TLSA records for all MX hosts of a domain |
check_tlsa | Standalone TLSA record lookup at _<port>._<proto>.<host> |
| Tool | Description |
|---|---|
check_rbl | IP reputation against 8 DNS-based RBLs (Spamhaus ZEN, SpamCop, UCEProtect L1/L2, Mailspike, PSBL, Barracuda, SORBS) |
check_dbl | Domain reputation against DNS-based Domain Block Lists (Spamhaus DBL, URIBL, SURBL) |
cymru_asn | ASN lookup via Team Cymru DNS service — BGP prefix, org, country |
check_fast_flux | Fast-flux detection — repeated A/AAAA queries to identify rotating IPs and short TTLs |
detect_hijacking | Test a recursive resolver for tampering — NXDOMAIN wildcards, DNSSEC handling, identity |
| Tool | Description |
|---|---|
rdap_lookup | Domain registration data via RDAP (modern WHOIS replacement) |
| Tool | Description |
|---|---|
session_stats | Per-tool call statistics for the current process — count, error_count, mean_ms, max_ms, first/last_called timestamps; plus session uptime and total call count. Module-level state (resets on container restart). Backed by dns_mcp/tracking.py. |
reset_stats | Clear all tool-call statistics and restart the session clock. |
Downstream consumers (e.g. ~/projects/yahoo batch forensics) call
session_stats as the final tool in each investigation to record which
DNS tools were consulted; an empty stats dict indicates a "cold read"
where the analyst LLM produced a verdict without DNS verification.
All 19 tools use Pydantic Field for parameter descriptors. The LLM sees:
Literal[...] enums for record types and protocols (no string-guessing)Constraints are advertised in the tool descriptor JSON Schema and enforced at
the MCP boundary by FastMCP — invalid input is rejected before dns_tool is
called. See src/dns_mcp/server.py for the type alias definitions.
Four analyst prompt templates ship with the server. Any MCP-compatible client that supports prompts can list and invoke them.
| Prompt | What it does |
|---|---|
email_security_audit | SPF, DKIM, DMARC, MTA-STS, BIMI — graded A through F with prioritized recommendations |
dnssec_chain_audit | Full DNSSEC chain-of-trust audit from IANA root down to target |
soc_email_forensics | Forensic phishing analysis of a raw email — TRUSTABLE / SUSPICIOUS / PHISHING / FURTHER ANALYSIS REQUIRED |
nist_800_81r3_audit | Domain security posture audit aligned with NIST SP 800-81r3 |
Prompt invocation requires client-side UI support. Claude Code surfaces them
as /mcp__dns-mcp__<prompt_name>. Claude.ai web exposes prompts via the
slash-command picker. Use tools ad-hoc in clients that do not support prompts.
Ask your assistant: "Check the email security posture of example.com"
The assistant calls check_spf, check_dmarc, check_dane in sequence and
returns a complete analysis:
No copy-pasting dig commands. No tab-switching. One question.
Mint an admin API key in Pocket ID's UI: Settings → API Keys → Create new
key. Name it dns-mcp so you can revoke just this service if needed. Copy
the key value (it is shown once).
The image installs dns_tool as a versioned dependency (URL-pinned in
pyproject.toml); make build is also available for direct development.
The container listens on port 8000 (HTTP). Front it with TLS termination:
If you use mclose/gateway (the Caddy +
DNS-01 setup that serves dns-mcp.lab.deflationhollow.net), drop a
conf.d/dns-mcp.conf matching the existing pattern.
Add https://dns-mcp.example.com/mcp as a connector in your MCP client. The
OAuth flow runs once on first connect — Claude.ai redirects to Pocket ID, you
authenticate, the server creates a DCR client on your Pocket ID instance, and
returns a JWT. Subsequent tool calls send that JWT as a bearer token; the
server verifies against Pocket ID JWKS.
Eleven tools from the 1.x stdio architecture are not yet ported into
dns_tool and are therefore not registered in 2.0.0:
check_caa (with CNAME chain tracing and wildcard delegation detection)check_zone_transfer (AXFR enumeration)check_bimi, check_mta_sts, check_smtp_tlsrptcheck_ct_logs (Certificate Transparency log enumeration via crt.sh)timestamp_converter, reverse_dnsenumerate_dkim_selectors, dns_dig_style, dns_query_dotReference implementations live in server.py.legacy. Each port involves
moving the function into the appropriate dns_tool module
(dns_tool.email, dns_tool.intel, etc.), adding tests on the library
side, and registering a one-line wrapper in src/dns_mcp/server.py.
| Command | What it does |
|---|---|
make build | Rebuild the Docker image |
make rebuild | Full clean build, no cache |
make lint | pre-commit run --all-files (ruff check + format) |
make import-check | Build image, run create_server() inside, assert tools register |
make shell | Interactive shell inside the container |
make deploy | Push to GitHub + VPS post-receive hook |
make logs | Tail container logs |
make status | Container status |
dns_tool (dnspython internally), RDAP via
requestsField constraints enforced at MCP boundary — invalid input
rejected before reaching dns_toolclaude, uid 1000)MIT