mcp server
dns-doctor
Scan and fix email auth (SPF, DMARC, DKIM, MX, blacklists, expiry) + DNS checks. Validated fixes.
Description as published by the maintainer. Source
- version 1.4.0
- active
active — Most recent push to the repository was 2026-08-04.
What this server can do
15 functions, named and described by the server itself. Parameter names are shown because they say more about what a function does than its name usually does.
audit_spf_includes(domain)- Audit a domain's SPF supply chain: walks every include and redirect it delegates to, and reports who can transitively send as it. Returns the resolved tree, per-node lookup attribution, the total authorized IPv4 address count, and typed findings — include_broken (a target that no longer publishes SPF, a PermError today), include_registrable (a delegated-to domain that does not exist, so a stranger who registers it becomes an authorized sender), include_expiring (registration lapsing within 30 days), pass_all_nested (a +all deep in the chain) and spf_record_unusable (the audited domain's OWN record is missing or does not parse, so there is no chain to walk). A domain we could not verify is reported as unverified and NEVER as available — never tell anyone a name is free on this tool's say-so unless the finding is include_registrable AND carries registry_confirmed: true. A registry_confirmed: false finding rests on DNS alone, which cannot tell an unsold name from one in redemption or on clientHold: report the mechanism as broken and the takeover risk as possible, but never as an available domain. Findings are risk analysis, not instructions: no SPF fix record exists here or anywhere else in DNS Doctor, because dropping a mechanism can silently de-authorize a real sender — relay the findings and let the domain's owner decide. Use count_spf_lookups instead when the question is only the 10-lookup limit. Required: domain.
build_dmarc_upgrade(domain)- Return a validated DMARC enforcement-upgrade record for a domain. The alignment gate (whether p=reject is safe) is derived server-side from a scan — a caller can never assert alignment. `record` is null when there is no honest upgrade to offer (the domain does not exist; the DMARC lookup itself hit NXDOMAIN while the existence probe did not resolve; the DMARC lookup temp-failed; or the domain already applies a policy at least as strong as this scan justifies): relay `rationale` and never compose a record to fill the gap. A returned record also carries np=reject (the DMARCbis tag covering non-existent subdomains, which can have no legitimate aligned mail) unless the domain already publishes an np tag, which is preserved as-is. Present a returned record verbatim; a human must approve before publishing. Required: domain.
build_parked_domain_records(domain, rua_email, confirm_no_mail)- Build the three-record hardening pack that makes a NON-SENDING domain unusable for spoofing: a Null MX, a hard-fail SPF record, and a p=reject; np=reject DMARC record. For parked, redirect and brand-defensive domains only — NEVER for a domain that sends any mail, including transactional or one legacy system. Do NOT set confirm_no_mail on your own judgment or because a scan looked quiet: only the human who owns the domain can confirm it sends nothing, so ask them first. That flag unlocks the question, not the answer — the server re-checks DNS itself (existence, MX, SPF, DKIM selectors) and returns records: null with a rationale when it finds evidence of mail; relay that rationale rather than retrying. A lookup failure is reported as a failure, never as a pack. Publishing is the human's decision: present the records verbatim, in the order given, and let them approve each one. Required: domain, confirm_no_mail.
check_dkim_selector(domain, selector)- Check ONE specific DKIM selector on a domain — the exact selector the sending platform uses (e.g. `google`, `s1`), which a full scan's common-selector sweep may miss. Returns the verdict, its explanation, and the published key record when one resolves. No fix record is returned: a DKIM key is generated by the sending platform, so the fix is always to publish what that platform gives the owner. Required: domain, selector.
check_record(host, kind, domain)- Check whether a DNS change has landed: reads the record from the domain's OWN nameservers (cache-free) and from two public caching resolvers, and reports whether they agree. `kind` is one of spf|dmarc|txt|mx|cname|a|aaaa — pass the kind, not a query name: `dmarc` reads TXT at _dmarc.<domain> and `spf` reads apex TXT, each filtered to the matching record. `host` prepends a label (txt, cname, a and aaaa only). Empty values mean the record is genuinely absent. When in_sync is false, max_wait_seconds is the largest remaining cached TTL — the wait before those resolvers refresh. This samples two resolvers, so never describe it as worldwide or as propagation coverage. Required: domain, kind.
check_reverse_dns(ip)- Check one sending IP's forward-confirmed reverse DNS (FCrDNS): reads the IP's PTR record, then resolves that hostname back and reports whether it returns to the same IP. `verdict` is confirmed (the pair agrees — what receivers want to see), ptr_missing (the IP publishes no reverse record), or mismatch (a PTR that does not resolve back). A PTR on its own proves nothing, because the IP's operator writes its own reverse zone — only the forward confirmation is evidence, so never report a bare PTR as verified. The fix is always made by whoever controls the IP (the hosting or mail provider), never in the sending domain's own DNS. Pass a public IPv4 or IPv6 address. Required: ip.
count_spf_lookups(domain, record)- Validate an SPF record and count what it costs. Returns `record_valid` (the record parses as RFC 7208 SPF), `findings` (per-term diagnostics), `has_pass_all` (a `+all` that authorizes the whole internet to send as this domain), `multiple_all` (more than one `all`, which makes everything after the first unreachable), the parsed `terms`, and the lookup count against the limit of 10 with `over_limit`/`near_limit` and the `offending_mechanisms` that push it over. Pass EXACTLY ONE of `domain` (resolves the published record and counts recursively through nested includes) or `record` (parses a pasted record, its own terms only). This is the SPF validator — there is no separate one. Diagnose-only: no SPF fix record is ever returned, because removing a mechanism can silently de-authorize a real sender — relay the findings and let the domain's owner decide what to drop.
generate_dmarc_record(policy, rua_email, strict_alignment, subdomain_policy)- Build a DMARC record from scratch for a domain that has none, using a validating engine — never compose one yourself. `policy` is none|quarantine|reject; optional `rua_email` (aggregate-report destination), `subdomain_policy`, and `strict_alignment`. Every generated record carries np=reject — the DMARCbis tag for non-existent subdomains, which can have no legitimate aligned mail — independently of the p= you choose. The generated record is re-validated before it is returned. Present it verbatim; a human must approve before publishing. Required: policy.
get_alerts(type, limit, since, before, domain)- Read the monitoring alert log for the domains the caller's account monitors, newest first. Requires an API token. Each row carries id, domain, type, check, summary, a deterministic detail map, created_at, email_sent_at, acknowledged_at and delivery_class — a 'dashboard_only' row was deliberately kept out of the digest mail, so an agent watching only the inbox would never see it; this log is the complete picture. PAGE DOWN BEFORE ADVANCING `since`: next_before is non-null exactly when older rows remain, and a caller that ignores it, takes a full page and moves its watermark to the newest row it saw drops every row it did not receive. `since` is an INCLUSIVE floor, so rows repeat rather than go missing — de-duplicate on id. READ-ONLY by decision: there is no ack and no delete here, because acknowledging an alert is the human's own triage on their dashboard and an agent that acks on their behalf silences a row they have never seen. Report what the log says and let them clear it.
get_readiness(domain)- Read the DMARC enforcement-readiness verdict for ONE domain the caller's account monitors, computed from its aggregate (RUA) report window. Requires an API token. Returns whether the domain is ready to step its policy up, the blockers that say why it is not, the window the verdict rests on, and next_record — the validated record for the next step, generated by the engine and null while blocked. THAT NULL IS AN ANSWER: relay the blockers and never compose a stronger record to fill the gap. Present a returned record verbatim; a human must approve it before it is published. Use this before proposing enforcement — a scan can show a domain's current policy, but only this evidence window can say whether tightening it would start rejecting real mail. Required: domain.
get_report(domain)- Return the stored report for a domain, scanning once only if none exists yet — the cheap read, and the right default for a first look. Returns the same seven-check report as scan_domain (SPF, DKIM, DMARC, MX, DNS hardening, domain/TLS expiry, blacklist; each with a status, the observed record and any fixengine fix_record), including `scanned_at` so you can judge staleness yourself. Prefer scan_domain when you specifically need state re-read right now — for example after a DNS change. Required: domain.
parse_dmarc_report(filename, content_base64)- Parse ONE DMARC aggregate (RUA) report into readable per-source aggregates: who sent mail as the domain, how much, and what share was SPF/DKIM aligned. Pass the file's bytes base64-encoded in `content_base64` (XML, .gz or .zip; up to 2 MiB decoded) with an optional `filename`. Nothing is stored — the report is parsed and discarded. Required: content_base64.
scan_domain(domain)- Force a fresh scan of a domain and return its full report: seven deterministic checks — SPF, DKIM, DMARC, MX, DNS hardening, domain/TLS expiry and blacklist listing — each with a status (pass/warn/fail/info/temperror), the observed record, and a fixengine-generated fix_record where one exists. Explanations are cache-first. A repeat scan of the same domain within a minute reuses the stored report. Use this when you need current state; use get_report when a recent cached answer will do. Required: domain.
start_monitoring_signup(domain)- Return a sign-up link to give to the HUMAN who owns a domain, so they can start monitoring it themselves. Nothing is created and no email is sent by this call: the returned signup_url opens a page that explains monitoring and asks them to sign in with their own email address; the domain is carried over to their dashboard, already filled in, only after that, and monitoring itself starts once they prove ownership with a TXT record. Hand them the URL and relay `message` — never sign in on their behalf. Required: domain.
validate_dmarc_record(record)- Validate a pasted DMARC record: parsed tags, level'd findings, and whether it is valid. No DNS lookup — pass the record string itself. `upgrade_record` previews a stronger policy and is capped at p=quarantine: a pasted record carries no alignment evidence, so p=reject needs a full scan (use build_dmarc_upgrade). Present any returned record verbatim. Required: record.
Last successful function declaration observed on . Source: https://dnsdoctor.dev/mcp. We list what the server declared; we do not call any of these functions.
Endpoint status observed on . Source: https://dnsdoctor.dev/mcp.
Signals
These are separate measurements of different things. They are deliberately not combined into one score, because a popularity number that mixes website traffic with saves and stars cannot be checked or acted on.
| Signal | Value | What it measures | Window | Observed | Source |
|---|---|---|---|---|---|
| GitHub stars | 2 | Number of GitHub accounts that bookmarked this repository since it was created. It is a bookmark count, not installs, not active users and not quality. | cumulative, all time | GitHub | |
| Last commit | 2026-08-04 | Date of the most recent push to any branch. This is the strongest cheap indicator of whether the project is still maintained. | point in time | GitHub | |
| Open issues | 0 | Open issues plus open pull requests, as GitHub counts them together. A high number can mean an active project or an abandoned one. | as of fetch | GitHub | |
| Package downloads | 342 downloads | Package downloads from the npm registry in this window. Includes continuous integration runs, mirrors and automated installs, so it overstates the number of human users. | 2026-07-30 to 2026-08-05 | npm | |
| Latest published version | 1.4.0 | Latest version string the maintainer published to the registry. | as of fetch | Model Context Protocol | |
| Registry record last updated | 2026-08-04 | When the registry record was last updated by its maintainer. | point in time | Model Context Protocol | |
| License | Apache-2.0 | Licence GitHub detected in the repository. Detection can be wrong; the LICENSE file is authoritative. | as of fetch | GitHub | |
| First listed in the MCP Registry | 2026-08-04 | Date this server was first published to the official MCP Registry. Not a usage or quality measure. | point in time | Model Context Protocol | |
| repository status | active | The repository exists on GitHub and is not archived. This says nothing about how recently it was worked on. | as of fetch | GitHub | |
| mcp tools declared | 15 tools | Number of functions the server itself declared when asked to list them. This is what the server offers an agent, not a measure of how well any of them work. | as of probe | dnsdoctor.dev | |
| mcp endpoint status | ok | The server listed 15 functions when asked. | as of probe | dnsdoctor.dev |
Where to get it
Related, by what their authors tagged them
-
com.blackveilsecurity/dns
— last commit 2026-08-06, shares dkim, dmarc, email-security
DNS and email security scanner with 80 MCP tools for SPF, DMARC, DNSSEC, SSL, and brand audits.
-
io.github.dmarc-examiner/mcp
— last commit 2026-08-04, shares dkim, dmarc, email-security
Read your own DMARC aggregate and forensic reports: sources, alignment, alerts, CSV export.
-
io.github.Davison-Francis/deliveriq-mcp
— last commit 2026-05-02, shares dkim, dmarc, spf
Email deliverability for AI agents. 12 tools: verify, DNSBL, DMARC, spam-trap, finder.
-
DMARKOFF — DMARC, SPF & DKIM Analytics
— last commit 2026-04-30, shares dmarc, email-security, spf
DMARC analytics for AI assistants — domain health, SPF/DKIM records, compliance stats, anomalies.
-
ContrastAPI
— last commit 2026-08-04, shares email-security
55 tools, 7 Resources, Sigma rules, email SPF/DMARC, MITRE, CVE/KEV, risk_score. No key.
These share tags the maintainers applied themselves, such as dkim, dmarc, email-security, spf. Common tags like "mcp" or "ai" are ignored for this: agreeing with six hundred other projects is not a similarity.
This is not a recommendation and not a test result. It is a map of what the authors said their work is about.
How the author describes it
Topics the maintainer set on GitHub: claude, dkim, dmarc, email-security, mcp, spf.
This record as data
Every field on this page, with its source and observation date, is in the catalog JSON. Fetch the whole kind at once instead of parsing this HTML.
GET /api/v1/entries/mcp_server.json