Real-time DNS security analysis — DNSSEC, email auth, and RDAP. Built for SOC investigations.
Real-time DNS security analysis — DNSSEC, email auth, and RDAP. Built for SOC investigations.
DNS MCP Server · v1.3.2
mclose
DNS MCP Server
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'd run at the command line, accessible
through any MCP-compatible assistant in real time.
Tools
DNS Tools
| Tool | Description |
|---|---|
dns_query |
Standard DNS lookups (A, AAAA, MX, TXT, NS, SOA, CNAME, PTR, SRV, DNSKEY, DS, TLSA, CAA, SSHFP, RRSIG, CDS, CDNSKEY, HTTPS, SVCB, NAPTR) |
dns_dig_style |
Detailed dig-style output with DNSSEC flags (DO flag set) — same 20 record types |
dns_query_dot |
DNS over TLS (DoT) query — TLS session info, EDNS pseudosection, DNSSEC flags |
dns_dnssec_validate |
Chain-of-trust validation like delv +vtrace |
nsec_info |
NSEC/NSEC3 denial-of-existence analysis and zone walkability assessment |
reverse_dns |
PTR lookup + forward-confirmed rDNS (FCrDNS) verification — essential for mail server identity |
timestamp_converter |
Convert between ISO, epoch, and human-readable timestamps |
detect_hijacking |
Test a resolver for DNS hijacking/tampering (NXDOMAIN probe, known record, DNSSEC, identity) |
Email Security Tools
| 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_selector |
DKIM public key record verification for a selector+domain pair |
check_bimi |
BIMI record and VMC (Verified Mark Certificate) check |
check_mta_sts |
MTA-STS DNS record + HTTPS policy file fetch (mode, MX patterns, max_age) |
check_smtp_tlsrpt |
SMTP TLS Reporting record check |
check_dane |
DANE TLSA record check with DNSSEC validation for a domain's MX hosts |
check_tlsa |
Standalone TLSA record lookup for any hostname, port, and protocol |
rdap_lookup |
Domain registration data via RDAP (modern WHOIS replacement) |
check_rbl |
IP reputation check against 8 DNS-based RBLs (Spamhaus ZEN, SpamCop, UCEProtect L1/L2, Mailspike, PSBL, Barracuda, SORBS) |
Utility
| Tool | Description |
|---|---|
ping |
Health check — returns pong with timestamp |
server_info |
Show resolver config: dnspython version, nameservers, EDNS settings |
quine |
Returns the source code of this server |
session_stats |
Per-tool call counts, error rates, and latency for this container session |
reset_stats |
Reset session stats and clock without restarting the container |
Analyst Prompts
The server ships with three analyst prompt templates. Any MCP-compatible client
can list and invoke them — no Claude-specific configuration required.
| Prompt | What it does |
|---|---|
email_security_audit |
Domain 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 the IANA root trust anchor down to the target domain |
soc_email_forensics |
Forensic phishing analysis of a raw email (.eml or pasted headers) — returns TRUSTABLE / SUSPICIOUS / PHISHING / FURTHER ANALYSIS REQUIRED |
Prompts set the analyst context and tool-use strategy for the session. The LLM
runs the appropriate tools in sequence and synthesizes a structured report.
Client support note: MCP prompt invocation requires client-side UI support.
Claude Code CLI supports prompts via slash commands (see Quick Start §4).
Claude Desktop currently exposes MCP tools only — prompts are registered but
not reachable from the UI. Use tools ad-hoc in Desktop, or describe the
analysis you want and the model will apply the same workflow.
Example
Ask your assistant: "Check the email security posture of deflationhollow.net"
The assistant calls check_spf, check_dmarc, check_dane, check_mta_sts,
and check_bimi in sequence and returns a complete analysis:
✅ SPF: Hard fail (-all), delegated to ForwardEmail, 5 lookups (under RFC limit)
✅ DMARC: p=reject, pct=100 — full enforcement, aggregate reporting configured
⚠️ DANE: TLSA records present but unverifiable — DNSSEC not enabled on zone
⚠️ MTA-STS: Not configured — no TLS enforcement policy published
⚠️ BIMI: Not configured
Overall: B+ — Strong fundamentals, three actionable gaps identified.
No copy-pasting dig commands. No tab-switching. One question.
Quick Start
Prerequisites
- Docker
1. Build
git clone https://github.com/mclose/dns-mcp.git
cd dns-mcp
make build
2. Connect
Any MCP client that supports stdio transport works. The server config block
is the same across all clients — see Client Support for
client-specific setup instructions and config file locations.
The --dns 9.9.9.9 flag ensures DNSSEC-correct resolution regardless of the
host's DNS configuration.
3. Verify
make test # unit tests inside container
./test-mcp-stdio.sh # end-to-end stdio test
4. Start an analysis
Once connected, just ask:
"Check the email security posture of deflationhollow.net"
"Audit the DNSSEC chain for dnssec.works"
"Is this email headers trustworthy?" (paste raw headers)
Clients that support MCP prompts can also invoke the structured analyst
workflows directly — see Client Support for details.
Client Support
All clients use the same server block. The command and args are identical
everywhere — only the config file location and prompt invocation differ.
{
"mcpServers": {
"dns-mcp": {
"command": "docker",
"args": ["run", "--rm", "-i", "--dns", "9.9.9.9", "dns-mcp", "python", "server.py"]
}
}
}
Claude Desktop
Prompts: Not supported — Desktop exposes MCP tools only. Use ad-hoc questions.
Config file:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json - Linux:
~/.config/Claude/claude_desktop_config.json
Claude Code CLI
Prompts: Full support via / slash commands.
Add the server with one command (adds to local project config):
claude mcp add dns-mcp -- docker run --rm -i --dns 9.9.9.9 dns-mcp python server.py
Or add --scope user to make it available across all projects. Invoke prompts
by typing / in the chat — the three analyst prompts appear as:
/mcp__dns-mcp__email_security_audit
/mcp__dns-mcp__dnssec_chain_audit
/mcp__dns-mcp__soc_email_forensics
Type /mcp__dns-mcp__ and tab-complete to see all three.
Gemini CLI
Prompts: Supported (Gemini CLI implements the full MCP spec).
Add the server with one command:
gemini mcp add dns-mcp -- docker run --rm -i --dns 9.9.9.9 dns-mcp python server.py
Or add manually to ~/.gemini/settings.json (user scope) or
.gemini/settings.json (project scope) using the same JSON block above.
Cursor
Prompts: Verify with your installed version — Cursor MCP support is active
and evolving. Config location: consult Cursor MCP docs.
Add the JSON block above to your Cursor MCP config file.
VS Code (GitHub Copilot / Continue / Cline)
Prompts: Depends on the extension — check extension documentation.
Config location varies by extension. The JSON block above is the standard
stdio format; consult your extension's MCP setup guide for the exact file path.
Zed
Prompts: Check current Zed release notes — MCP support is active.
Config location: consult Zed MCP docs.
Windsurf
Prompts: Check current Windsurf release notes.
Config location: consult Windsurf MCP documentation.
Note on prompt support: MCP prompts require explicit client-side UI
(a slash command picker or equivalent). Not all clients have implemented
this yet. When prompts aren't available, ask ad-hoc — the tools work the
same way and the model applies the same workflow.
Architecture
MCP Client (e.g. Claude Desktop)
|
| (spawns per-session)
v
docker run --rm -i dns-mcp python server.py
|
| stdin/stdout (MCP stdio transport)
v
FastMCP server (server.py)
| - All 23 tools
| - dnspython for DNS queries
| - requests for RDAP only
No network ports. No auth tokens. No proxy. The MCP client manages the
container lifecycle — one container per session, cleaned up on exit.
Day-to-Day
| Command | What it does |
|---|---|
make build |
Build the Docker image (uses layer cache) |
make rebuild |
Full clean build, no cache — use when something feels off |
make test |
Run unit tests inside the container |
make shell |
Interactive shell inside the container |
./test-mcp-stdio.sh |
End-to-end stdio protocol test |
Testing
Unit tests — tool logic, input validation, error handling:
make test # runs pytest inside container
End-to-end stdio — full MCP protocol over stdin/stdout:
./test-mcp-stdio.sh
Security
- No shell execution — all DNS via dnspython, RDAP via requests
- Strict domain validation (regex allowlist)
- IP address validation (ipaddress module)
- Query type allowlist
- Non-root container user (
claude, uid 1000) - SPF recursion limit enforced (RFC 7208)
- RDAP: input validated before HTTP request, 10s timeout, max 3 redirects
File Structure
dns-mcp/
├── server.py # FastMCP server (23 tools, stdio transport)
├── Dockerfile # Single-stage Alpine image
├── docker-compose.yml # Build target
├── Makefile # build/test/shell
├── requirements.txt # Python dependencies
├── test-mcp-stdio.sh # End-to-end stdio test
└── tests/
└── test_tools.py # pytest unit tests
Contributing
pip install pre-commit
pre-commit install
That's it. On every commit, ruff will lint and auto-fix staged Python files.
The full test suite (pytest + stdio e2e) runs in CI on every push and pull request.
Remote / HTTP Transport
The remote branch contains the HTTP Streamable transport version of this
server, including a Flask auth proxy sidecar, bearer token authentication,
fail2ban integration, and instructions for exposing the server via an HTTPS
reverse proxy. See that branch if you need network-accessible deployment.
License
MIT