DNS MCP server — DMARC, SPF and DKIM tools for AI agents
DNS Doctor is a DNS MCP server: it gives an AI agent the same diagnosis this site runs — SPF, DMARC, DKIM, MX, blacklists, domain/SSL expiry, plus general DNS record checks — with fix records generated by a validating engine, never composed by the model. If you're looking for a DMARC MCP server, an SPF MCP tool, or a DKIM check your agent can call, this is that: one server, fifteen tools. This page covers every way to connect and what the tools will and won't do.
Try it in your browser first
No install needed: the Glama listing
has a Try in Browser button that starts a sandbox instance in their MCP Inspector —
you can call scan_domain or check_record against a real domain and read the raw tool
results before wiring anything into your agent.
Connect the hosted DNS MCP server
The server runs at https://dnsdoctor.dev/mcp (streamable HTTP). Anonymous access includes
all thirteen diagnosis tools — no account, no key. The two monitoring reads (get_alerts,
get_readiness) are listed for everyone and need an API token, because they return one
account's own data.
Claude Code — one command, via the plugin (bundles a skill that teaches the scan → diagnose → fix workflow):
/plugin marketplace add dnsdoctor/claude-plugin
Any other MCP client — point it at the URL. The generic config shape:
{
"mcpServers": {
"dns-doctor": {
"type": "http",
"url": "https://dnsdoctor.dev/mcp"
}
}
}
Run the MCP server locally (npm)
Some setups prefer a local process to a remote endpoint. The same fifteen tools ship as
@dnsdoctor/mcp — a small open-source
stdio server (TypeScript, source on GitHub)
whose tool definitions are pinned to the hosted server, so the two can never drift.
{
"mcpServers": {
"dns-doctor": {
"command": "npx",
"args": ["-y", "@dnsdoctor/mcp"]
}
}
}
The local server calls DNS Doctor's public REST API for each tool — your agent talks to a process on your machine, and the diagnosis runs on the same engine either way.
The DMARC, SPF, DKIM and DNS tools
| Tool | What it answers |
|---|---|
scan_domain / get_report | The full seven-check report — fresh scan, or the stored report if one exists. |
build_dmarc_upgrade | A validated next-step DMARC record. The safety gate (whether p=reject is justified) is decided server-side from evidence, never asserted by the caller. |
count_spf_lookups | SPF validation plus the 10-lookup cost against RFC 7208, with the offending mechanisms named. |
validate_dmarc_record / generate_dmarc_record | Check a pasted DMARC record tag by tag, or build one from scratch — re-validated before it is returned. |
check_dkim_selector | The published key at one specific DKIM selector. |
parse_dmarc_report | One DMARC aggregate (RUA) report parsed into readable per-source stats. Nothing is stored. |
check_record | Did a DNS change land? Reads the record from the domain's own nameservers and two public resolvers, and reports whether they agree. |
check_reverse_dns | Forward-confirmed reverse DNS for a sending IP. |
audit_spf_includes | Who can transitively send as the domain. Walks the whole include/redirect tree and reports broken includes, an include target whose registrable domain is confirmed unregistered (anyone could register it and become an authorized sender), targets expiring within 30 days, a +all nested anywhere, and the total IPv4 addresses the record authorizes. Diagnose-only — no SPF fix record. |
build_parked_domain_records | The three-record hardening pack for a domain that sends no mail (Null MX, v=spf1 -all, p=reject; np=reject). The caller's confirmation unlocks the question, not the answer: the server re-verifies non-sending from DNS and refuses if it finds any evidence of mail — or any transient lookup failure, because this output ends in -all. |
start_monitoring_signup | A signup link the agent hands the domain's owner. It sends no email and creates nothing — signing in is the human's own action. |
get_alerts | Token required. The account's monitoring alert log, newest first. Read-only: no acknowledge, no delete. Page down with before until next_before is null before advancing since. |
get_readiness | Token required. Whether one monitored domain's evidence justifies a stronger DMARC policy yet — ready, the blockers, and next_record (validated, or null while blocked, which is an answer rather than a gap). |
The rules your agent follows
The tools ship with a packaged DNS skill that teaches the safe
workflow: records presented verbatim (never rewritten by the model), SPF diagnose-only,
a human approving every DNS change, temperror treated as retry rather than a verdict,
and DMARC enforcement gated on evidence. The full ruleset — and why each rule exists —
is on the skill page; the scoring logic itself is on
/methodology.
API tokens (optional)
The diagnosis tools above work anonymously. A dnsd_ API token raises rate limits and
unlocks the account's own monitoring data — the get_alerts and get_readiness tools and
the monitored-domains resource — and it is created by the account owner, signed in,
under dashboard Settings. An agent can't create one, and shouldn't ask you to paste
one into a conversation.
Where the token goes depends on the transport. On the hosted HTTP endpoint it travels
as a request header, so add a headers block to the server entry in your MCP config:
{
"mcpServers": {
"dns-doctor": {
"type": "http",
"url": "https://dnsdoctor.dev/mcp",
"headers": { "Authorization": "Bearer ${DNSDOCTOR_API_TOKEN}" }
}
}
}
On the stdio client (npx -y @dnsdoctor/mcp) it is read from the environment instead —
set DNSDOCTOR_API_TOKEN in that server's env. Either way, export the value from your
shell rather than writing it into the file, and never commit it.
Prefer plain HTTP?
The same engine is exposed as a REST API — the schema lives at
/api/v1/openapi.json, and the full machine
contract (endpoints, the fix-verify loop, rate limits) is written for agents at
/llms-full.txt.
Operate monitoring, over MCP or REST
The diagnosis tools above cover one conversation. Getting that domain to DMARC
enforcement is a job that runs for weeks — roughly 30 days of aggregate (RUA) report
evidence proving every legitimate sender is aligned, then a stepped policy upgrade. With a
dnsd_ API token, an agent can carry that job rather than hand it off and forget it:
- Hand off the signup.
start_monitoring_signup(orPOST /api/v1/signup-url) returns a link for the human who owns the domain. They open it and sign in themselves — nothing is created on their behalf, and no email is sent. - They verify ownership with a TXT record, and monitoring starts. The account owner creates the API token, signed in, under dashboard Settings.
- Poll
get_alerts(orGET /api/v1/alerts— same core, same answers) for what changed — new sending sources, records that disappeared, alignment regressions.sinceis an inclusivecreated_atfloor, so store the newest timestamp you have seen and pass it back; dedupe onid. When the response carries a non-nullnext_before, older rows are still waiting: page down withbeforeuntil it isnullbefore you advancesince, or the rows you did not receive are gone for good. - Poll
get_readiness(orGET /api/v1/readiness) for whether enforcement is justified yet:ready, theblockersstill in the way, the window's message volume, andnext_record— the validated next-step DMARC record, ornullwhile blocked. - Propose, never publish. Present
next_record(orPOST /api/v1/dmarc-upgrade's record) verbatim. The domain owner approves and applies it.check_recordconfirms it landed.
Two things are worth stating plainly. The alert feed is larger than the alert email: at an enforcing policy, routine aligned new sources are routed to the dashboard and never mailed, so an agent watching a mailbox sees a quieter picture than the log holds — that is why these reads exist. And both are read-only, over MCP and REST alike: there is no acknowledge and no delete. Acking is the owner's own triage on their dashboard, and an agent clearing rows on their behalf would silence something a human never saw.
Check SPF, DMARC, DKIM, MX, DNS and expiry in one free scan — with the exact record to paste in to fix each problem.