@dnsdoctor/mcp 1.12.0 → 1.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -7
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/instructions.txt +1 -1
- package/package.json +1 -1
- package/tools.json +93 -10
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ claude-plugin/
|
|
|
19
19
|
├── .mcp.json # MCP server: https://dnsdoctor.dev/mcp (HTTP)
|
|
20
20
|
├── skills/dns-doctor/SKILL.md # the scan → diagnose → fix workflow
|
|
21
21
|
├── src/ # @dnsdoctor/mcp — the local stdio MCP server
|
|
22
|
-
├── tools.json # the
|
|
22
|
+
├── tools.json # the tool definitions (generated, never hand-edited)
|
|
23
23
|
├── instructions.txt # the server's own `initialize` guidance (generated)
|
|
24
24
|
├── tests/ # vitest suite for the stdio server
|
|
25
25
|
├── package.json tsconfig.json # npm package + build
|
|
@@ -39,10 +39,12 @@ claude-plugin/
|
|
|
39
39
|
| `generate_dmarc_record` | Build a DMARC record from a policy + reporting address. |
|
|
40
40
|
| `check_dkim_selector` | Look up one DKIM selector and check the key. |
|
|
41
41
|
| `parse_dmarc_report` | Parse an aggregate (RUA) report file into rows. |
|
|
42
|
-
| `check_record` | Read any DNS record type for a name. |
|
|
42
|
+
| `check_record` | Read any DNS record type for a name; with `expected_value`, a one-word verdict on whether a change has landed. |
|
|
43
43
|
| `check_propagation` | Whether a DNS change has gone global: six vantage points (five owner-run probes plus the server's own resolver) read the same name, returning the grid plus a deterministic verdict. Observation only — an unavailable cell is a vantage point we could not read, never a missing record, and under three reached vantage points the verdict stays `unknown`. |
|
|
44
44
|
| `lookup_registration` | Registrar, dates, EPP status codes, nameservers, DNSSEC and abuse contact from one RDAP read. Observation only; a registry that did not answer is `unknown` with a reason, never "not registered". |
|
|
45
45
|
| `check_lookalikes` | Which close variants of a domain's name resolve and which accept mail: counts plus up to ten resolving names. DNS-only facts, never a verdict; a name that could not be checked is `unknown`, and unregistered names are never listed. |
|
|
46
|
+
| `check_bimi` | Whether a domain can show its logo in the inbox (BIMI): the DMARC gate, the published record, the logo and any certificate, and eligibility per mailbox, never a promise that a logo will show. With a candidate `logo_url`, the engine's record to publish. |
|
|
47
|
+
| `start_email_test`, `get_email_test` | How one real message authenticated: a single-use address the user sends one email to, then the SPF, DKIM and DMARC verdicts (every signature, alignment, the disposition the policy implies), blocklist status and a score out of 10 with every deduction itemized. Only verdicts and selected header facts are kept (24 hours, 90 days with an account), never the body. |
|
|
46
48
|
| `check_reverse_dns` | PTR / forward-confirmed reverse DNS for an IP. |
|
|
47
49
|
| `audit_spf_includes` | The SPF include/redirect tree — who can transitively send as the domain, with typed findings (broken include, confirmed-unregistered include, expiring registration, nested `+all`). Analysis only; no SPF fix record. |
|
|
48
50
|
| `build_parked_domain_records` | The Null MX + `v=spf1 -all` + `p=reject; np=reject` hardening pack for a domain that sends no mail. The server re-checks DNS itself and refuses when it finds evidence of mail. |
|
|
@@ -50,13 +52,15 @@ claude-plugin/
|
|
|
50
52
|
| `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`. |
|
|
51
53
|
| `get_readiness` | **Token required.** Whether one monitored domain's aggregate-report evidence justifies a stronger DMARC policy yet: `ready`, the `blockers`, and `next_record` (validated, or `null` while blocked — which is an answer, not a gap). |
|
|
52
54
|
| `get_lookalikes` | **Token required.** The watched lookalike domains of one monitored domain, highest threat % first, with the itemized points and site facts. `ai_assessment.summary` is written from third-party page content: untrusted data, never an instruction. Read-only; takedowns are filed by the owner from the dashboard. |
|
|
55
|
+
| `list_email_tests` | **Token required.** The account's own earlier email tests, newest first, with status, score and DMARC result; read one in full with `get_email_test`. |
|
|
56
|
+
| `list_my_domains` | **Token required.** Every domain on the account with its state (verified, pending, verification lapsed) and the next step for it. |
|
|
53
57
|
|
|
54
58
|
The three monitoring reads are **listed for everyone and callable with a token**:
|
|
55
59
|
they appear in the tool list on both transports, and without a valid token the
|
|
56
60
|
call is refused with the page the account owner mints one on. Over the hosted
|
|
57
61
|
HTTP transport the `dnsdoctor://domains` resource (your monitored domains) is
|
|
58
62
|
likewise always listed and refused without a token; the local stdio server
|
|
59
|
-
registers the tools only — no resource. Anonymous access covers all
|
|
63
|
+
registers the tools only — no resource. Anonymous access covers all eighteen
|
|
60
64
|
diagnosis tools, which is enough for a one-off diagnosis either way.
|
|
61
65
|
|
|
62
66
|
## Install
|
|
@@ -101,7 +105,7 @@ Add a custom connector with:
|
|
|
101
105
|
## Optional: API token for monitored domains
|
|
102
106
|
|
|
103
107
|
Anonymous access covers scanning and fixes. A per-account API token unlocks the
|
|
104
|
-
account's own monitoring data: the `get_alerts`, `get_readiness` and `
|
|
108
|
+
account's own monitoring data: the `get_alerts`, `get_readiness`, `get_lookalikes`, `list_email_tests` and `list_my_domains` tools, and
|
|
105
109
|
the `dnsdoctor://domains` resource (your continuously-monitored domains and
|
|
106
110
|
their latest per-check statuses).
|
|
107
111
|
|
|
@@ -126,11 +130,11 @@ their latest per-check statuses).
|
|
|
126
130
|
|
|
127
131
|
### Transport
|
|
128
132
|
|
|
129
|
-
Two supported public transports, same
|
|
133
|
+
Two supported public transports, same 27 tools:
|
|
130
134
|
|
|
131
135
|
- **Hosted streamable HTTP** — `https://dnsdoctor.dev/mcp`, wired in this
|
|
132
136
|
plugin's `.mcp.json`. No install, no keys.
|
|
133
|
-
- **Local stdio** — `npx -y @dnsdoctor/mcp@1.
|
|
137
|
+
- **Local stdio** — `npx -y @dnsdoctor/mcp@1.14.0`. A thin server that runs on your
|
|
134
138
|
machine and calls the public DNS Doctor REST API; it holds no diagnosis logic
|
|
135
139
|
of its own and relays every record string verbatim.
|
|
136
140
|
|
|
@@ -139,7 +143,7 @@ Two supported public transports, same 25 tools:
|
|
|
139
143
|
"mcpServers": {
|
|
140
144
|
"dns-doctor": {
|
|
141
145
|
"command": "npx",
|
|
142
|
-
"args": ["-y", "@dnsdoctor/mcp@1.
|
|
146
|
+
"args": ["-y", "@dnsdoctor/mcp@1.14.0"],
|
|
143
147
|
"env": { "DNSDOCTOR_API_TOKEN": "dnsd_YOUR_TOKEN" }
|
|
144
148
|
}
|
|
145
149
|
}
|
package/dist/index.js
CHANGED
|
@@ -45,6 +45,7 @@ const ROUTES = {
|
|
|
45
45
|
},
|
|
46
46
|
lookup_registration: { kind: "json", path: "/api/tools/whois" },
|
|
47
47
|
check_lookalikes: { kind: "json", path: "/api/tools/lookalikes" },
|
|
48
|
+
check_bimi: { kind: "json", path: "/api/tools/bimi" },
|
|
48
49
|
get_alerts: { kind: "query", path: "/api/v1/alerts" },
|
|
49
50
|
get_readiness: { kind: "query", path: "/api/v1/readiness" },
|
|
50
51
|
get_lookalikes: { kind: "query", path: "/api/v1/lookalikes" },
|
|
@@ -55,11 +56,13 @@ const ROUTES = {
|
|
|
55
56
|
add_monitored_domain: { kind: "json", path: "/api/v1/domains" },
|
|
56
57
|
check_domain_verification: { kind: "json", path: "/api/v1/domains/verify" },
|
|
57
58
|
get_domain_records: { kind: "query", path: "/api/v1/domains/records" },
|
|
58
|
-
//
|
|
59
|
+
// Email test: start takes no arguments (an empty body); the read is a GET.
|
|
59
60
|
start_email_test: { kind: "json", path: "/api/tools/email-test" },
|
|
60
61
|
get_email_test: { kind: "query", path: "/api/tools/email-test" },
|
|
61
|
-
//
|
|
62
|
+
// The linked account's email-test history (token, monitoring:read).
|
|
62
63
|
list_email_tests: { kind: "query", path: "/api/v1/email-tests" },
|
|
64
|
+
// The account's domains with state + next step (token, monitoring:read).
|
|
65
|
+
list_my_domains: { kind: "query", path: "/api/v1/domains/mine" },
|
|
63
66
|
};
|
|
64
67
|
/** Default upload name when the caller supplies none — the API only reads bytes. */
|
|
65
68
|
const DEFAULT_REPORT_FILENAME = "report.xml";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EACL,qBAAqB,EACrB,sBAAsB,GAEvB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAuBhE,MAAM,MAAM,GAA0B;IACpC,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE;IACnD,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC9B,mBAAmB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,uBAAuB,EAAE;IACpE,uBAAuB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,oBAAoB,EAAE;IACrE,iBAAiB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,sBAAsB,EAAE;IACjE,qBAAqB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,2BAA2B,EAAE;IAC1E,qBAAqB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,2BAA2B,EAAE;IAC1E,mBAAmB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,uBAAuB,EAAE;IACpE,kBAAkB,EAAE;QAClB,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,+BAA+B;QACrC,KAAK,EAAE,MAAM;KACd;IACD,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,yBAAyB,EAAE;IAC/D,iBAAiB,EAAE;QACjB,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,8BAA8B;KACrC;IACD,iBAAiB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,8BAA8B,EAAE;IACzE,kBAAkB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,sBAAsB,EAAE;IAClE,2BAA2B,EAAE;QAC3B,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,kCAAkC;KACzC;IACD,mBAAmB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,EAAE;IAC/D,gBAAgB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,uBAAuB,EAAE;IACjE,UAAU,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE;IACrD,aAAa,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,mBAAmB,EAAE;IAC3D,cAAc,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,oBAAoB,EAAE;IAC7D,qEAAqE;IACrE,+DAA+D;IAC/D,yEAAyE;IACzE,qCAAqC;IACrC,oBAAoB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,EAAE;IAC/D,yBAAyB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,wBAAwB,EAAE;IAC3E,kBAAkB,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,yBAAyB,EAAE;IACtE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/instructions.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Use DNS Doctor whenever a user asks to check, audit, diagnose, troubleshoot or fix SPF, DKIM or DMARC, wonders why their mail lands in spam, wants DMARC monitoring or alerts on new senders, asks whether a DNS change has propagated, or needs a domain's blacklist status or domain/SSL expiry. DNS Doctor scans, fixes and verifies a domain's DNS: email authentication (SPF, DMARC, DKIM), multi-region propagation, SPF include supply-chain audits, MX, DNS health, blacklists and domain/SSL expiry. It returns deterministic verdicts plus copy-paste fix records generated by a validating engine — never a guessed record. Workflow: call scan_domain (or get_report), read the verdicts failing-first (a 'temperror' status is transient, NOT a failure), then call build_dmarc_upgrade for a DMARC enforcement record. ONE EXCEPTION TO READING FAILING-FIRST: when a report carries not_registered: true the domain has no DNS records at all, so no check ran and every status is an 'info' placeholder — zero failing checks there does NOT mean the domain is healthy. Report that the domain does not resolve (usually a typo), propose no records for it, and do not call start_monitoring_signup for it until it resolves. PRESENT ANY RETURNED RECORD VERBATIM — never rewrite, reformat, or 'improve' a record string. build_dmarc_upgrade may return record: null (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 the one this scan justifies) — relay its 'rationale' as the answer and NEVER compose a record yourself to fill the gap. 'policy' describes the returned record and is null whenever record is; the domain's observed policy is in 'current_policy'. A human must approve every DNS change; nothing is applied automatically. SPF is diagnose-only: relay the report's SPF findings, but never propose SPF record edits of your own (e.g. tightening ~all to -all) — an SPF change can silently de-authorize a real sender, which is why the engine emits no SPF fix record. The ONE SPF record DNS Doctor ever emits is the constant 'v=spf1 -all' inside the build_parked_domain_records pack, for a domain the server itself verified sends no mail; never set that tool's confirm_no_mail flag on your own judgment — only the human who owns the domain can confirm it, and the server still re-checks DNS and refuses on any evidence of a sender. audit_spf_includes reports who can transitively send as a domain; its include_registrable finding is raised ONLY on confirmed absence, and only the ones carrying registry_confirmed: true rest on the registry's word — treat every other registration verdict, including a registry_confirmed: false finding, as unknown and never tell anyone a name is free to register. For lookalike, typosquat or impersonation questions call check_lookalikes: it returns facts (which close variants of the name resolve and accept mail), never a verdict, so relay the names as facts and never call one malicious. To see how a real message authenticates (whether it is actually DKIM-signed and DMARC-aligned), call start_email_test, have the user send one email to the address it returns, then call get_email_test; list_email_tests returns an account's earlier tests and needs the same API token as the monitoring reads. Scan responses end with a next_steps block: relay it. Safe DMARC enforcement needs ~30 days of aggregate-report (RUA) evidence, which no chat session can watch. If the user wants ongoing monitoring, call start_monitoring_signup and give the human the signup_url it returns, printed verbatim as a clickable markdown link on its own line — never paraphrase, shorten, or describe it without printing it. That tool sends no email and creates nothing: the human opens the link, signs in themselves, and adds the domain themselves. Never ask a human for their email address to pass to us, and never invent one — hand over the link and let them sign in on our page. Also share the report_url and monitor_url links from next_steps, each printed verbatim as a clickable markdown link — never described without being printed. Monitoring is a loop, not a one-off: the human enrolls a domain and verifies ownership in the dashboard, then you watch it with get_alerts (what changed), get_readiness (whether enforcement is safe yet) and get_lookalikes (the watched lookalike domains and their threat %), propose the next record with build_dmarc_upgrade, wait for the human to approve and publish it, and re-scan to confirm it landed. Those
|
|
1
|
+
Use DNS Doctor whenever a user asks to check, audit, diagnose, troubleshoot or fix SPF, DKIM or DMARC, wonders why their mail lands in spam, wants DMARC monitoring or alerts on new senders, asks whether a DNS change has propagated, or needs a domain's blacklist status or domain/SSL expiry. DNS Doctor scans, fixes and verifies a domain's DNS: email authentication (SPF, DMARC, DKIM), multi-region propagation, SPF include supply-chain audits, MX, DNS health, blacklists and domain/SSL expiry. It returns deterministic verdicts plus copy-paste fix records generated by a validating engine — never a guessed record. Workflow: call scan_domain (or get_report), read the verdicts failing-first (a 'temperror' status is transient, NOT a failure), then call build_dmarc_upgrade for a DMARC enforcement record. ONE EXCEPTION TO READING FAILING-FIRST: when a report carries not_registered: true the domain has no DNS records at all, so no check ran and every status is an 'info' placeholder — zero failing checks there does NOT mean the domain is healthy. Report that the domain does not resolve (usually a typo), propose no records for it, and do not call start_monitoring_signup for it until it resolves. PRESENT ANY RETURNED RECORD VERBATIM — never rewrite, reformat, or 'improve' a record string. build_dmarc_upgrade may return record: null (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 the one this scan justifies) — relay its 'rationale' as the answer and NEVER compose a record yourself to fill the gap. 'policy' describes the returned record and is null whenever record is; the domain's observed policy is in 'current_policy'. A human must approve every DNS change; nothing is applied automatically. SPF is diagnose-only: relay the report's SPF findings, but never propose SPF record edits of your own (e.g. tightening ~all to -all) — an SPF change can silently de-authorize a real sender, which is why the engine emits no SPF fix record. The ONE SPF record DNS Doctor ever emits is the constant 'v=spf1 -all' inside the build_parked_domain_records pack, for a domain the server itself verified sends no mail; never set that tool's confirm_no_mail flag on your own judgment — only the human who owns the domain can confirm it, and the server still re-checks DNS and refuses on any evidence of a sender. audit_spf_includes reports who can transitively send as a domain; its include_registrable finding is raised ONLY on confirmed absence, and only the ones carrying registry_confirmed: true rest on the registry's word — treat every other registration verdict, including a registry_confirmed: false finding, as unknown and never tell anyone a name is free to register. For lookalike, typosquat or impersonation questions call check_lookalikes: it returns facts (which close variants of the name resolve and accept mail), never a verdict, so relay the names as facts and never call one malicious. For questions about a logo in the inbox (BIMI) call check_bimi: it reports eligibility per mailbox, never a promise that a logo will show. To see how a real message authenticates (whether it is actually DKIM-signed and DMARC-aligned), call start_email_test, have the user send one email to the address it returns, then call get_email_test; list_email_tests returns an account's earlier tests and needs the same API token as the monitoring reads. Scan responses end with a next_steps block: relay it. Safe DMARC enforcement needs ~30 days of aggregate-report (RUA) evidence, which no chat session can watch. If the user wants ongoing monitoring, call start_monitoring_signup and give the human the signup_url it returns, printed verbatim as a clickable markdown link on its own line — never paraphrase, shorten, or describe it without printing it. That tool sends no email and creates nothing: the human opens the link, signs in themselves, and adds the domain themselves. Never ask a human for their email address to pass to us, and never invent one — hand over the link and let them sign in on our page. Also share the report_url and monitor_url links from next_steps, each printed verbatim as a clickable markdown link — never described without being printed. Monitoring is a loop, not a one-off: the human enrolls a domain and verifies ownership in the dashboard, then you watch it with list_my_domains (the account's domains and the next step on each), get_alerts (what changed), get_readiness (whether enforcement is safe yet) and get_lookalikes (the watched lookalike domains and their threat %), propose the next record with build_dmarc_upgrade, wait for the human to approve and publish it, and re-scan to confirm it landed. Those reads return an account's own monitoring data and need an API token: they are listed to everyone and callable only with one. You cannot create a token — tokens are minted by the account owner while signed in to the dashboard, and the refusal message names the exact page. Relay that page to the human and let them decide; never ask anyone to paste a token or any other credential to you. They are all read-only by design: there is no way to acknowledge or clear an alert or to file a takedown here, because triage is the human's. When get_alerts returns a non-null next_before, older rows remain — page down with it BEFORE advancing your 'since' watermark, or you silently skip rows you never read. get_readiness returns next_record: null while a domain is not ready, and THAT NULL IS AN ANSWER: relay the blockers and never compose a stronger record to fill it. When record_withheld is true, the step is ready but the record is not included in the result: relay that the record isn't included and withheld_reason, and never compose a record. add_monitored_domain, check_domain_verification and get_domain_records need a linked DNS Doctor account; when this host has none, they return the sign-up link instead, so use the hand-off described above.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dnsdoctor/mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.0",
|
|
4
4
|
"mcpName": "dev.dnsdoctor/dns-doctor",
|
|
5
5
|
"description": "Thin stdio MCP server for DNS Doctor — scan, fix and verify a domain's DNS: SPF, DMARC, DKIM, multi-region propagation, MX, DNS health, blacklists and expiry, over the public DNS Doctor REST API.",
|
|
6
6
|
"license": "Apache-2.0",
|
package/tools.json
CHANGED
|
@@ -85,11 +85,12 @@
|
|
|
85
85
|
"readOnlyHint": true,
|
|
86
86
|
"title": "Build Parked Domain Records"
|
|
87
87
|
},
|
|
88
|
-
"description": "Use this when the user asks how to protect a domain that sends no email from being spoofed. 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 \u2014 NEVER for a domain that sends any mail, including transactional or one legacy system.
|
|
88
|
+
"description": "Use this when the user asks how to protect a domain that sends no email from being spoofed. 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 \u2014 NEVER for a domain that sends any mail, including transactional or one legacy system. Ask the domain's owner whether it sends any email BEFORE calling, then call with the bare domain (e.g. example.com) and confirm_no_mail: true only if they said it sends none \u2014 a call without it is always refused. Never set the flag on your own judgment or because a scan looked quiet. That flag unlocks the question, not the answer \u2014 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.",
|
|
89
89
|
"inputSchema": {
|
|
90
90
|
"properties": {
|
|
91
91
|
"confirm_no_mail": {
|
|
92
|
-
"
|
|
92
|
+
"default": false,
|
|
93
|
+
"description": "Send true only after the HUMAN who owns the domain has told you it sends no email at all; false or omitted is always refused, so ask them first instead of calling. Never set it on your own judgment or because a scan looked quiet. It unlocks the question only; the server independently re-checks DNS for evidence of mail and refuses when it finds any.",
|
|
93
94
|
"title": "Confirm No Mail",
|
|
94
95
|
"type": "boolean"
|
|
95
96
|
},
|
|
@@ -113,8 +114,7 @@
|
|
|
113
114
|
}
|
|
114
115
|
},
|
|
115
116
|
"required": [
|
|
116
|
-
"domain"
|
|
117
|
-
"confirm_no_mail"
|
|
117
|
+
"domain"
|
|
118
118
|
],
|
|
119
119
|
"title": "build_parked_domain_recordsArguments",
|
|
120
120
|
"type": "object"
|
|
@@ -122,6 +122,58 @@
|
|
|
122
122
|
"name": "build_parked_domain_records",
|
|
123
123
|
"title": "Build Parked Domain Records"
|
|
124
124
|
},
|
|
125
|
+
{
|
|
126
|
+
"annotations": {
|
|
127
|
+
"destructiveHint": false,
|
|
128
|
+
"idempotentHint": true,
|
|
129
|
+
"openWorldHint": true,
|
|
130
|
+
"readOnlyHint": true,
|
|
131
|
+
"title": "Check BIMI Logo Setup"
|
|
132
|
+
},
|
|
133
|
+
"description": "Use this when the user asks how to get their logo shown in Gmail, Yahoo, Apple Mail or other inboxes (BIMI), whether their BIMI setup works, or why their logo does not show. A live read of one host's BIMI setup: the DMARC gate (BIMI needs p=quarantine or p=reject; dmarc_sources names each policy read and why it does or does not count), the published default._bimi record, the logo (fetched and checked as SVG Tiny PS) and any certificate (certificate.trust_verified is true for a mark certificate for this host, in date, chaining to a Mark Verifying Authority root, false with trust_reason when not, null when the check could not run; revocation is not checked). mailboxes is ELIGIBILITY per mailbox, never a promise that a logo will show: each mailbox decides, Gmail and Apple Mail also need a VMC or CMC certificate, and Outlook does not support BIMI. Pass logo_url (and optionally certificate_url) to check a candidate logo: generated.record is then the exact record to publish at generated.host \u2014 present it verbatim. generated.record is null while DMARC is not at enforcement: relay generated.rationale and never compose a BIMI record yourself. status unknown means a lookup or download failed (try again), never that the setup is broken. next_step is the one thing to do next. Observation only: nothing is published.",
|
|
134
|
+
"inputSchema": {
|
|
135
|
+
"properties": {
|
|
136
|
+
"certificate_url": {
|
|
137
|
+
"anyOf": [
|
|
138
|
+
{
|
|
139
|
+
"type": "string"
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"type": "null"
|
|
143
|
+
}
|
|
144
|
+
],
|
|
145
|
+
"default": null,
|
|
146
|
+
"description": "Optional https:// URL of the VMC or CMC certificate (PEM) for the candidate logo, added to the record as a=. Only used together with logo_url.",
|
|
147
|
+
"title": "Certificate Url"
|
|
148
|
+
},
|
|
149
|
+
"domain": {
|
|
150
|
+
"description": "The domain to check, e.g. example.com. Bare registrable names and subdomains both work; scheme, path or port do not belong here. Unicode names are accepted and normalized to punycode.",
|
|
151
|
+
"title": "Domain",
|
|
152
|
+
"type": "string"
|
|
153
|
+
},
|
|
154
|
+
"logo_url": {
|
|
155
|
+
"anyOf": [
|
|
156
|
+
{
|
|
157
|
+
"type": "string"
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"type": "null"
|
|
161
|
+
}
|
|
162
|
+
],
|
|
163
|
+
"default": null,
|
|
164
|
+
"description": "Optional https:// URL of a candidate SVG logo (port 443, no spaces, ; or ,). When given, that logo is checked instead of the published one and generated carries the BIMI record for it. Omit it to check what the domain already publishes.",
|
|
165
|
+
"title": "Logo Url"
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
"required": [
|
|
169
|
+
"domain"
|
|
170
|
+
],
|
|
171
|
+
"title": "check_bimiArguments",
|
|
172
|
+
"type": "object"
|
|
173
|
+
},
|
|
174
|
+
"name": "check_bimi",
|
|
175
|
+
"title": "Check BIMI Logo Setup"
|
|
176
|
+
},
|
|
125
177
|
{
|
|
126
178
|
"annotations": {
|
|
127
179
|
"destructiveHint": false,
|
|
@@ -162,7 +214,7 @@
|
|
|
162
214
|
"readOnlyHint": false,
|
|
163
215
|
"title": "Check Domain Verification"
|
|
164
216
|
},
|
|
165
|
-
"description": "Check whether the ownership TXT record for a domain the user has added is visible yet, and mark it verified when it is. The result says WHICH outcome occurred and which nameservers were asked, so you can tell 'not published yet' from 'published with the wrong value' from 'our lookup did not complete' \u2014 a lookup that did not complete is TRANSIENT, never a verdict about their DNS. On success the result also carries the DMARC reporting record that turns monitoring on. Print every record host and value EXACTLY as returned \u2014 never rewrite, reformat or improve a record string. Nothing here is applied to anyone's DNS: a human publishes every record, and you must show them what you are about to add and get their approval before using any DNS tool of your own.",
|
|
217
|
+
"description": "Use this only for DNS Doctor's own ownership TXT challenge on a domain the user already added to their DNS Doctor account (add_monitored_domain). For a TXT record another service asked for (Google Workspace, Microsoft 365, Shopify or any site verification), use check_record instead. Check whether the ownership TXT record for a domain the user has added is visible yet, and mark it verified when it is. The result says WHICH outcome occurred and which nameservers were asked, so you can tell 'not published yet' from 'published with the wrong value' from 'our lookup did not complete' \u2014 a lookup that did not complete is TRANSIENT, never a verdict about their DNS. On success the result also carries the DMARC reporting record that turns monitoring on. Print every record host and value EXACTLY as returned \u2014 never rewrite, reformat or improve a record string. Nothing here is applied to anyone's DNS: a human publishes every record, and you must show them what you are about to add and get their approval before using any DNS tool of your own.",
|
|
166
218
|
"inputSchema": {
|
|
167
219
|
"properties": {
|
|
168
220
|
"domain": {
|
|
@@ -267,7 +319,7 @@
|
|
|
267
319
|
"readOnlyHint": true,
|
|
268
320
|
"title": "Look Up DNS Record"
|
|
269
321
|
},
|
|
270
|
-
"description": "Use this when the user asks whether a DNS change has landed, wants a DNS record looked up, or wants to verify a record they just published \u2014 or whenever answering needs the live value of a record.
|
|
322
|
+
"description": "Use this when the user asks whether a DNS change has landed, wants a DNS record looked up, or wants to verify a record they just published \u2014 or whenever answering needs the live value of a record. Reads the record from the domain's OWN nameservers (cache-free) and from two public caching resolvers. `kind` is one of spf|dmarc|txt|mx|cname|a|aaaa \u2014 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). Pass `expected_value` when checking an edit. Relay `verdict`: done (the nameservers serve it and both caches agree), wait (served, caches catching up \u2014 check again after check_again_after_seconds), edit (the domain's nameservers do not serve it; `found_at` names where the value was seen instead, if anywhere). not_registered: true means the domain does not exist (usually a typo). An error starting cant_tell is a lookup fault, never evidence the record is missing. Two resolvers is the whole sample, so never describe this as worldwide or as propagation coverage.",
|
|
271
323
|
"inputSchema": {
|
|
272
324
|
"properties": {
|
|
273
325
|
"domain": {
|
|
@@ -275,6 +327,20 @@
|
|
|
275
327
|
"title": "Domain",
|
|
276
328
|
"type": "string"
|
|
277
329
|
},
|
|
330
|
+
"expected_value": {
|
|
331
|
+
"anyOf": [
|
|
332
|
+
{
|
|
333
|
+
"maxLength": 1024,
|
|
334
|
+
"type": "string"
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
"type": "null"
|
|
338
|
+
}
|
|
339
|
+
],
|
|
340
|
+
"default": null,
|
|
341
|
+
"description": "Optional: the exact value just published (e.g. the DMARC record text, a verification token, '10 mx.example.com'). Given it, the verdict tests for that value and an 'edit' also checks the names a misplaced edit usually lands on (found_at).",
|
|
342
|
+
"title": "Expected Value"
|
|
343
|
+
},
|
|
278
344
|
"host": {
|
|
279
345
|
"anyOf": [
|
|
280
346
|
{
|
|
@@ -360,7 +426,7 @@
|
|
|
360
426
|
}
|
|
361
427
|
],
|
|
362
428
|
"default": null,
|
|
363
|
-
"description": "
|
|
429
|
+
"description": "A bare domain like example.com whose PUBLISHED SPF record should be resolved and counted recursively (nested includes cost lookups too). Send exactly one of domain or record, never both.",
|
|
364
430
|
"title": "Domain"
|
|
365
431
|
},
|
|
366
432
|
"record": {
|
|
@@ -373,7 +439,7 @@
|
|
|
373
439
|
}
|
|
374
440
|
],
|
|
375
441
|
"default": null,
|
|
376
|
-
"description": "
|
|
442
|
+
"description": "The full SPF record text starting with v=spf1, e.g. 'v=spf1 include:_spf.google.com ~all' \u2014 never a domain name. Counts this record's own terms only. Send exactly one of domain or record, never both.",
|
|
377
443
|
"title": "Record"
|
|
378
444
|
}
|
|
379
445
|
},
|
|
@@ -750,6 +816,23 @@
|
|
|
750
816
|
"name": "list_email_tests",
|
|
751
817
|
"title": "List Email Tests"
|
|
752
818
|
},
|
|
819
|
+
{
|
|
820
|
+
"annotations": {
|
|
821
|
+
"destructiveHint": false,
|
|
822
|
+
"idempotentHint": true,
|
|
823
|
+
"openWorldHint": false,
|
|
824
|
+
"readOnlyHint": true,
|
|
825
|
+
"title": "List My Domains"
|
|
826
|
+
},
|
|
827
|
+
"description": "Use this when a signed-in operator asks which domains their DNS Doctor account monitors, or what to do next on them. Lists every domain on the caller's account with its state \u2014 verified, pending (added, ownership not proven yet) or verification_lapsed (the ownership record was removed, so monitoring is paused for it) \u2014 and next_step, the one thing to do next for that domain. Requires an API token. Relay next_step as given.",
|
|
828
|
+
"inputSchema": {
|
|
829
|
+
"properties": {},
|
|
830
|
+
"title": "list_my_domainsArguments",
|
|
831
|
+
"type": "object"
|
|
832
|
+
},
|
|
833
|
+
"name": "list_my_domains",
|
|
834
|
+
"title": "List My Domains"
|
|
835
|
+
},
|
|
753
836
|
{
|
|
754
837
|
"annotations": {
|
|
755
838
|
"destructiveHint": false,
|
|
@@ -823,7 +906,7 @@
|
|
|
823
906
|
"readOnlyHint": false,
|
|
824
907
|
"title": "Scan Domain"
|
|
825
908
|
},
|
|
826
|
-
"description": "Use this when the user asks to check, audit, diagnose or troubleshoot SPF, DKIM, DMARC, email authentication, email deliverability DNS, why their mail lands in spam, MX, DNS health, blacklist status, or domain/SSL expiry for a domain, or wants to fix what a scan finds (fix records for DMARC and DNS; SPF is diagnose-only) \u2014 or whenever a conversation turns to a specific domain's email or DNS setup. Force a fresh scan of a domain and return its full report: seven deterministic checks \u2014 SPF, DKIM, DMARC, MX, DNS hardening, domain/TLS expiry and blacklist listing \u2014 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 the dedup window (about a minute) reuses the stored report rather than re-reading DNS, so `scanned_at` may predate a DNS change you just made \u2014 when you are verifying an edit, check `scanned_at` and call again after the window rather than treating an unchanged report as the new state. Use this when you need current state; use get_report when a recent cached answer will do.",
|
|
909
|
+
"description": "Use this when the user asks to check, audit, diagnose or troubleshoot SPF, DKIM, DMARC, email authentication, email deliverability DNS, why their mail lands in spam, MX, DNS health, blacklist status, or domain/SSL expiry for a domain, or wants to fix what a scan finds (fix records for DMARC and DNS; SPF is diagnose-only) \u2014 or whenever a conversation turns to a specific domain's email or DNS setup. It needs the user's real domain: if they have not said which domain, ask them first; never scan a placeholder such as example.com. Force a fresh scan of a domain and return its full report: seven deterministic checks \u2014 SPF, DKIM, DMARC, MX, DNS hardening, domain/TLS expiry and blacklist listing \u2014 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 the dedup window (about a minute) reuses the stored report rather than re-reading DNS, so `scanned_at` may predate a DNS change you just made \u2014 when you are verifying an edit, check `scanned_at` and call again after the window rather than treating an unchanged report as the new state. Use this when you need current state; use get_report when a recent cached answer will do.",
|
|
827
910
|
"inputSchema": {
|
|
828
911
|
"properties": {
|
|
829
912
|
"domain": {
|
|
@@ -849,7 +932,7 @@
|
|
|
849
932
|
"readOnlyHint": false,
|
|
850
933
|
"title": "Start Email Test"
|
|
851
934
|
},
|
|
852
|
-
"description": "Use this when the user wants to know how a real email from them actually authenticates \u2014 whether a message from Google Workspace, Microsoft 365, a newsletter tool or an app is SPF/DKIM/DMARC aligned, why it lands in spam, or to prove DKIM signing works before tightening DMARC. Returns a single-use address (valid about an hour, one message) and a test_id. Tell the user to send one email to that address from the sender they want to test, then call get_email_test with the test_id. Each call creates a new address
|
|
935
|
+
"description": "Use this when the user wants to know how a real email from them actually authenticates \u2014 whether a message from Google Workspace, Microsoft 365, a newsletter tool or an app is SPF/DKIM/DMARC aligned, why it lands in spam, or to prove DKIM signing works before tightening DMARC. Returns a single-use address (valid about an hour, one message) and a test_id. Tell the user to send one email to that address from the sender they want to test, then call get_email_test with the test_id. Each call creates a new address; the daily limit counts only messages that arrive, a few unused addresses may be open at once, and limit says which allowance applied.",
|
|
853
936
|
"inputSchema": {
|
|
854
937
|
"properties": {},
|
|
855
938
|
"title": "start_email_testArguments",
|