Pro and Enterprise
DomainGuard MCP server
One endpoint that hands Claude your whole account and lets it act on it: add a domain by answering a few questions, see what is broken across your domains, what is holding a page back in search, where you rank on a map, and what to change. Claude also checks the scanner's work and tells us when it is wrong. This page is the complete reference plus the playbooks Claude follows.
Built on the Model Context Protocol, the open standard for connecting AI assistants to outside systems.
What this does
DomainGuard already checks your domains: DNS, SSL, SPF, DKIM, DMARC, HTTP headers, blacklists, vulnerabilities, uptime, on-page SEO, whole-site crawls, accessibility, local rankings, reviews, citations, backlinks, and how often AI answers cite you. The dashboard shows you the findings. The MCP server hands those same findings to Claude, so you can ask about them in plain language and get a specific edit list back.
With a read-only key it explains. Ask which certificate expires first, why invoices are landing in spam, what regressed since last month, or which of eleven sites share the same misconfiguration. With a write-capable key it also works: run the scan, check the rankings, pull the competitor gap, then compare the result against the baseline it took before you started.
One boundary worth stating plainly. We monitor your domains, we do not host them. Every tool here reports, records, or measures. Claude can tell you exactly what your DMARC record should say and why the one you have is failing — publishing it still happens at your DNS provider.
At a glance
- Endpoint
- /api/mcp
- Transport
- Streamable HTTP
- Auth
- Bearer nhm_…
- Tools
- 253 — 138 read, 115 write
- Local SEO actions
- 33, catalogued
- Sessions
- None — stateless
Setting it up
Fastest: two clicks in the dashboard
Open Settings, API & MCP access and click Connect an AI agent. Claude Code is already picked, so click Create key & copy setup. For Claude Code that copies one terminal command that adds the server and starts verifying your findings. Cursor, VS Code and Claude Desktop get a config snippet, and any other agent gets a prompt to paste into its chat. The key is read-only unless you tick otherwise, which is all verifying and reporting needs. Prefer to do it by hand? The steps are below.
1. Create an API key
In the dashboard, go to Settings, then API Keys. Pick the scopes the key should reach — domains, scans, SEO, accessibility, vulnerability, compliance, status — and copy the key when it is shown. It is shown once. On Enterprise you can also tick write access; leave it off for a key that should only ever read and report. Give each key an expiry if you have a date in mind.
2. Add the server
# Claude Code
claude mcp add --transport http --scope user domainguard https://nhmohio.com/api/mcp \
--header "Authorization: Bearer nhm_your_key_here"# Cursor: ~/.cursor/mcp.json
{
"mcpServers": {
"domainguard": {
"url": "https://nhmohio.com/api/mcp",
"headers": { "Authorization": "Bearer nhm_your_key_here" }
}
}
}# VS Code: .vscode/mcp.json (asks for the key once, keeps it out of the repo)
{
"inputs": [
{ "type": "promptString", "id": "domainguard-key", "description": "DomainGuard API key", "password": true }
],
"servers": {
"domainguard": {
"type": "http",
"url": "https://nhmohio.com/api/mcp",
"headers": { "Authorization": "Bearer ${input:domainguard-key}" }
}
}
}# Claude Desktop: claude_desktop_config.json, through the mcp-remote bridge (needs Node.js)
{
"mcpServers": {
"domainguard": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://nhmohio.com/api/mcp",
"--header", "Authorization:${DG_AUTH}"],
"env": { "DG_AUTH": "Bearer nhm_your_key_here" }
}
}
}# OpenAI Codex CLI: ~/.codex/config.toml (key in DOMAINGUARD_API_KEY)
[mcp_servers.domainguard]
url = "https://nhmohio.com/api/mcp"
bearer_token_env_var = "DOMAINGUARD_API_KEY"Any MCP client that supports a remote server over Streamable HTTP with a custom header works the same way, and one that only runs local servers can use the mcp-remote bridge above. There is no OAuth flow to complete and no event stream to open.
Keep the key to the job
Every tool a key reaches is described to the model before its first call, and that text stays in its context. A key with every scope and write is offered all 253 customer tools, roughly 55,000 tokens of descriptions. A key scoped to SEO and read only is offered 53. Give a reporting assistant no write access, and a local-SEO assistant just the seo and domains scopes.
| Key's scopes | Tools offered |
|---|---|
| seo, read only | 53 |
| seo + write | 94 |
| domains + write | 62 |
| vulnscan + write | 51 |
| every scope, read only | 138 |
| every scope + write | 253 |
3. Confirm it works
# Ask the server what this key can do
curl -s https://nhmohio.com/api/mcp \
-H "Authorization: Bearer nhm_your_key_here" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'The list that comes back is already filtered to the key's scopes and the account's plan, so it is the real answer to what this key can reach. If a tool you expected is missing, the key is missing a scope — mint a new one rather than rewording the prompt.
4. Ask it something
"Which of my domains have SSL certificates expiring in the next 30 days?"
"Why might email from my domain be going to spam?"
"Read the SEO results for every domain and give me one ranked fix list."
"Where do we drop out of the map pack for 'emergency plumber', and why?"
"Compare this month against last month and tell me what actually moved."
"Use the verify_findings prompt: check what DomainGuard found and report back."Plans, scopes, and what a key can reach
A key carries resource scopes, and optionally the write scope on top of them. Both are checked on every call, and the plan is re-read on every request — an account that moves from Enterprise to Pro loses write access on its next call rather than whenever someone remembers to rotate the key.
Free and Starter
No API or MCP access.
The endpoint answers 401.
Pro
Read access. 138 tools.
Everything that reads stored data, across every scope you grant.
Enterprise
Read and write. All 253 customer tools.
Adds the write scope: start scans, spend credits, change saved data.
| Scope | What it unlocks |
|---|---|
| domains | Inventory, history, DNS and registrar events, uptime, DMARC reporting |
| scans | Domain scans, security checkups, dark-web monitoring |
| seo | On-page SEO, whole-site audits, and the entire Local SEO suite |
| accessibility | Audit-grade WCAG 2.2 AA evaluations |
| vulnscan | Vulnerability scans, ports, components, ownership verification |
| compliance | PCI, HIPAA, and cyber-insurance control records |
| status | Third-party service status |
| write | Required on top of any of the above for anything that changes state |
Adding a domain is a conversation
You do not have to know what SPF is, what an exposure scan does, or which of nine setup steps matter. Tell Claude the domain. It asks a few plain questions — does this domain send email, is it a business that serves a place, which mailboxes to watch for breaches, is there an address at the domain we can send an ownership link to — and then makes one call that adds the domain and sets all of it up. Nothing in that call spends credits. Anything that does is quoted first.
1. plan_domain_onboarding
Returns where the account stands — plan, whether active scanning is already cleared, any saved business profile, credits and prices — and the ordered questions to ask, each with why it matters and what the answer becomes.
2. The questions, in your words
Claude confirms what is already known instead of re-asking, and can read the site's homepage (discover_local_seo_details) to pre-fill the business name, city, phone and phrases for you to correct.
3. onboard_domain, once
Adds the domain, starts the add-time checks you chose, records whether it sends mail, files it under a group, saves the business and phrases, sends the ownership link, watches the addresses — and returns the setup guide so Claude can say what is left.
# The write, with every answer collected
onboard_domain {
domain: "siffrin.org",
sends_email: true,
exposure_monitoring: false, // one exposure scan now, none after unless asked
group: "Clients",
ownership_email: "admin@siffrin.org", // one click verifies this domain for deep scans
local_business: {
business_name: "Siffrin",
location: "Canton, OH",
is_service_business: false,
keywords: ["tool repair canton", "pipe threader rental"]
}
}
→ steps: add_domain done · domain_settings done · local_business done · keywords 2 of 2 ·
ownership_email done
→ setup: first_scan running · alerts done · email_auth todo · ownership todo (link sent) · …Local search is the same shape. get_local_seo_quickstart says what is saved and the exact price of a first measurement; run_local_seo_quickstart saves the business and up to five phrases, confirms the city, then checks the map pack and the organic result for every phrase and reads the Google Business Profile: six credits a phrase plus five. Claude quotes that number and waits for a yes. In Claude Code the whole thing is /mcp__domainguard__onboard_domain and /mcp__domainguard__set_up_local_seo.
Your agent checks our work
Everything we tell you about a domain is a claim about the live world: this host runs WooCommerce 8.4.0, that CVE applies to it, the DMARC record says p=none. Every one of those can be checked from outside, and the server asks every connected agent to check them. get_verification_tasks hands it each claim with how we tested it and the read-only commands that reproduce the test: dig, curl, openssl, a service greeting. Nothing logs in and nothing tries an exploit. A version inside the published range is the whole proof.
The agent sends a verdict for each one with submit_verification_results: confirmed, incorrect (what is actually true and how it knows) or could not verify. Confirmations count as much as disputes. They give us a running accuracy figure for every way we test, and the worst one is the next thing we fix. A dispute files a report to a person and puts the finding back in the queue for a re-check. It never quietly changes your result. Problems we missed go in the same call.
It works on Pro and Enterprise with a read-only key, from the account's own keys only. The limits are 400 verdicts a day and one message to us per domain. The full method, the data sources and their licences are in How we test, and how to re-test it. You can reuse it commercially under CC BY 4.0. Mistakes that aren't on the task list still go through report_scanner_issue.
Prompts and resources the server carries
- onboard_domain
- the interview, start to finish
- set_up_local_seo
- profile, phrases, quote, first measurement
- verify_findings
- re-test every claim, send verdicts, report back
- review_domain
- read everything, verify, report, deliver fixes
- portfolio_triage
- one ranked list across every domain, spending nothing
- fix_email_deliverability
- SPF, DKIM, DMARC and the report stream, in order
- improve_local_seo
- the free brief turned into an ordered plan
- audit_domain
- one call: verdict, fixes ranked by risk, what isn't measured
- build_wisp
- a written information security plan by interview, as a Word document
Resources: domainguard://guide, domainguard://onboarding, domainguard://local-seo, domainguard://review, domainguard://verification, domainguard://wisp — the same text as this page's guide, readable through the protocol.
How to use it well
That many tools is enough that the order you call them in decides whether a session is useful or expensive. These are the rules we give Claude, and the sequences that actually produce a fix list.
Ten ground rules
Start with list_domains
Almost every tool takes a numeric domain_id, and that is where the ids come from. Never guess one.
Add a domain by interview
plan_domain_onboarding returns the questions to ask — does it send email, is it a local business, which addresses to watch for breaches — and onboard_domain applies the answers in one call without spending anything.
Verify, then report back
get_verification_tasks gives every claim with how we tested it and read-only commands to re-test it. Run them and send each verdict, confirmations too, with submit_verification_results. Other mistakes go to report_scanner_issue, then submit_scanner_review once per domain.
Read before you scan
get_checkup_history, get_seo_results, get_vuln_scan_latest and get_local_rank_history return data already collected — free, instant, and usually enough.
Know what spends
Anything named run_, start_, check_ or verify_ does real work. So do get_domain_email_security, discover_domain_subdomains and get_scan_ownership_verification, which perform live lookups.
Quote before spending
get_local_seo_credits for the balance, get_local_seo_catalog for what an action costs and requires. Say the cost before the first paid call of a session.
Fresh request_key every paid run
Eight to a hundred characters of letters, digits, dots, underscores, and hyphens. Reuse one only to retry the identical request.
Recover, do not re-run
After a timeout, get_local_seo_operation with the same key returns the saved or in-flight result. A new key charges again.
Poll asynchronous scans
start_vuln_scan, start_site_audit and start_accessibility_audit return an id immediately and finish in the background. Leave real time between polls.
Confirm deletions in words
delete_domain erases a domain's whole history and cannot be undone. Name the exact thing and get a yes.
Say who applies the fix
The registrar, the DNS provider, the CMS, or Google Business Profile. A finding without an owner is not a fix.
Never invent a number
Scores, positions, volumes and prices come from tool output. If a tool did not return it, say it is not measured.
Playbooks
Each one is a sequence that ends in something the user can act on. Every one of them opens with free reads.
Triage the whole portfolio
The first session on an account. Costs nothing — every call here reads data already collected.
list_domains ├─ get_domain_history → getting worse, or always been this way? └─ audit_domain → what is wrong, ranked, with the fix for each get_domain_events → anything hijack-shaped across the account get_downtime_events → was anything actually down
Report one ranked list across the portfolio, severity first and then by how many domains share the finding. Fixing the one misconfiguration that appears on nine sites beats fixing nine unrelated things, and that ordering is only visible when you read the whole account at once.
Make a page rank — the technical loop
The order matters. A page cannot rank if it cannot be crawled, cannot be trusted, or cannot be read.
get_seo_results → title, meta description, H1 and heading structure,
accessibility violations that also block crawling
get_checkup_history → HTTPS, redirects, response headers, exposed files
get_seo_history → has the score been moving, and in which direction
↓ hand the user a specific edit list, then wait for them to publish
run_seo_scan → re-score
get_seo_results → confirm the finding cleared
get_seo_history → confirm the number movedRead the SEO result for what it names, not for its score. A missing meta description, a title duplicated across a template, two H1s, a skipped heading level — each of those is a concrete edit with an owner. “Score is 71” is not. Batch the edits and scan once: free accounts get one manual scan a day.
Audit the whole site, not one page
A crawl of the sitemap or same-site links, checking every discovered page. Asynchronous — start, poll, read.
start_site_audit { domain_id, max_pages } → audit_id
get_site_audit_status { audit_id } → poll; minutes, not seconds
get_site_audit_results{ audit_id } → page-level findingsCluster before reporting. Three hundred crawled pages do not produce three hundred problems — they produce perhaps six template defects repeated three hundred times. Sort by pages affected multiplied by severity, name the template or page type where it can be inferred, and the fix list goes from unusable to a morning's work.
Get into the local map pack
The highest-leverage sequence for a business that serves a place. Set up once, then measure and diagnose.
Setup, once per domain
get_local_seo_profile → is there a profile at all?
save_local_seo_profile → business_name, location ("Akron, OH"),
is_service_business, radius_miles, and
street_address + phone if you will ever
want citation checks
add_local_keyword_target → phrases a customer would actually type,
up to 25 per domain
Measure
get_local_rank_history → free; is there recent data already?
get_local_seo_credits → check the balance before spending
check_local_ranks → live positions, local pack. For the organic
column too, or one phrase only, use
run_local_seo_action rank_check with
surfaces and keywords
run_geogrid_scan → where the ranking holds across the area
Diagnose
run_local_seo_action profile_health → what the profile is missing
run_local_seo_action citations → name/address/phone consistency
run_local_seo_action competitor_gap → who beats you, and on what
run_local_seo_action reviews → recent and unanswered reviewsHow to read a geogrid. A business ranks best at its own pin and decays outward. Strong at the centre and dead three miles out is a proximity problem — the answer is location-specific content and citations, not more keywords. Weak everywhere, including at the pin, is a profile or trust problem: go to profile health and citations first, because no amount of content fixes a profile Google does not trust.
A saved profile is the prerequisite for both rank checks and map scans. The service radius defaults to three miles and tops out at five hundred.
Find phrases worth targeting
Research before tracking, and a baseline before any work starts.
get_local_seo_catalog → inputs and cost
run_local_seo_action keyword_opportunities → local searches to consider
run_local_seo_action keyword_search_volume → is there real demand
run_local_seo_action keywords_for_site → what this domain already
associates with
run_local_seo_action keywords_related → adjacent phrases
run_local_seo_action keyword_trends → rising, or dying
↓
add_local_keyword_target → the survivors
check_local_ranks → the baseline, before anything changesTake the baseline before the user changes anything. Without it there is nothing to compare against in three months, and the work cannot be shown to have worked — which is usually the thing that decides whether it continues.
Beat a specific competitor
Three reads of the same rival from different angles, turned into three things to do this month.
run_local_seo_action competitor_gap → ranking, review, citation gap run_local_seo_action backlinks_gap → links they have, you do not run_local_seo_action local_authority → your own signals in one score
Convert the gap into three actions, not thirty. Link gaps are the slowest to close and the most durable once closed; review count and profile completeness are the fastest and the most visible to a searcher deciding between two names.
Be visible in AI answers
Increasingly the click never happens — the answer does. That is measurable, and it is a different surface from the ten blue links.
run_local_seo_action ai_visibility → how often answers surface this site run_local_seo_action serp_ai_mode → the AI answer, with references run_local_seo_action ai_mentions → which brands and sources get named run_local_seo_action ai_top_sources → what these systems rely on run_local_seo_action ai_top_pages → the pages they surface most run_local_seo_action ai_compare → you versus competitors, by phrase
The actionable output is almost always the cited sources, not the answer text. When the same three directories or publications are cited across every phrase in a category, being present and accurate on those three is the work — and it is work that pays off in ordinary search too.
Reputation and links
The two cheapest wins in local search, and the warmest outreach list that exists.
run_local_seo_action reviews → recent reviews, owner replies run_local_seo_action review_velocity → rate of arrival, not total run_local_seo_action multi_platform_reviews → beyond Google run_local_seo_action reputation_audit → quality, quantity, recency run_local_seo_action backlinks_summary → the link signals you have run_local_seo_action backlinks_gap → what competitors have run_local_seo_action brand_mentions → named, but not linked
Unanswered reviews are visible to searchers and free to fix. Unlinked brand mentions are the warmest outreach list there is — the site already decided to mention the business, so the ask is small.
Email that reaches the inbox
Not a ranking factor, but the fastest way to lose a customer who already found you — and the most common thing a monitored portfolio gets wrong.
get_domain_email_security { domain_id } → live SPF, DKIM, DMARC, MX,
MTA-STS, TLS-RPT
get_dmarc_setup_status { domain } → the authoritative checklist
get_dmarc_summary { domain } → 30-day volume and alignment
get_dmarc_diagnostics { domain } → ranked, with sender attributionRead the diagnostics before recommending a policy change. Moving a domain to p=reject while a legitimate sender is failing alignment stops that sender's mail on the next send. The diagnostics name which sender, which is the whole reason to look before you leap.
Security findings that are also search problems
Mixed content, an expired certificate, a blacklist entry, a compromised page. These belong in the SEO report, not a separate one.
audit_domain → ranked and de-duplicated; start here
get_checkup_history → the raw checkup rows behind it
run_domain_checkup { domain } → live, on any domain; the
exposed-file probe only on a
verified one
get_vuln_scan_latest → most recent completed scan
start_vuln_scan → quick | standard | port-scan |
deep | extreme
get_vuln_scan_results { scan_id } → poll for findings
Active scanning first needs proof of control:
get_scan_ownership_verification → creates or returns the challenge
↓ user publishes the DNS record or file
verify_scan_ownership → records the proofOwnership verification is not paperwork. Deep and extreme profiles send real traffic at a real server, and the proof is what separates scanning your own site from scanning someone else's.
Prove the work worked
Every engagement should end here, against the baseline taken at the start.
get_seo_history → score movement over the period get_local_rank_history → position per phrase, per check get_geogrid_scans → the map before, and the map after get_domain_history → everything else that changed get_uptime_snapshots + get_downtime_events → availability
Cite the dates, and say plainly where nothing moved. Positions move for reasons nobody controls; a report claiming every change was caused by the work is the one nobody believes twice.
Tool reference
All 262 tools: 144 that read stored data and 118 that change something, run a live lookup, or spend credits. 9 are operator-only, so a customer key can be offered at most 253. A key is only offered the subset its scopes and plan allow, so the list your client shows may be shorter than this one.
Fields marked ? are optional. Every tool runs through the same ownership checks as the dashboard, so a key reaches its own account and nothing else.
Domains, DNS, and deliverability
scope: domainsThe inventory and everything recorded about it. list_domains is the entry point to the whole server — its numeric ids are what the other tools take.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| list_domains | read | Inputs: detail? | Every domain on the account, one compact row each: health score, last scan and scan state, SSL and registration expiry, SEO score, vulnerabilities, paused checks. detail: true returns the full stored scans. Start here. |
| get_domain_history | read | Inputs: domain_id | Recorded results for one domain over time — when something regressed and by how much. |
| run_site_check | write | Inputs: domain_id | Load the homepage (three times, the middle run) and two more pages in a real browser as a phone on 4G. Queued; a few minutes. |
| list_site_checks | read | Inputs: domain_id, limit?, detail? | Site checks newest first, one short row each, with the six section scores and the homepage's phone speed metrics: the trend. |
| get_site_check | read | Inputs: check_id, detail? | One check's worst findings by section (speed, mobile, SEO, security, accessibility, errors), each with its cause and fix. |
| get_dns_change_events | read | Inputs: — | DNS changes across the account, so a new change can be told apart from a long-standing finding. |
| get_domain_events | read | Inputs: — | Hijack Guard events with severity and lifecycle: DNS, registrar, certificate, and hosting changes. |
| get_uptime_snapshots | read | Inputs: — | Recent uptime probe observations across the portfolio. |
| get_downtime_events | read | Inputs: — | Recorded outage windows and whether they recovered. |
| get_dmarc_summary | read | Inputs: domain_id or domain | Thirty-day aggregate report volume and alignment rate for one monitored domain. |
| get_dmarc_diagnostics | read | Inputs: domain_id or domain | Ranked deliverability diagnostics joining DNS, reports, and sender attribution. |
| get_dmarc_setup_status | read | Inputs: domain_id or domain | The authoritative SPF, DKIM, DMARC, report-arrival, and inbox-routing checklist. |
| add_domain | write | Inputs: domain | Start monitoring a new domain. Returns 403 once the plan's domain limit is reached. |
| update_domain | write | Inputs: domain_id, domain_group?, scan_client_id?, notes?, ignore_mail?, ignore_autoscan?, uptime_monitoring?, website_watch? | Change one domain's group, client, notes, or which checks it skips. Only the fields passed are changed. |
| delete_domain | destructive | Inputs: domain_id | Permanently removes the domain and its entire scan history. Re-adding does not recover it. |
| get_domain_email_security | write | Inputs: domain_id | Fresh SPF, DKIM, DMARC, MX, MTA-STS, and TLS-RPT evidence. Performs live DNS lookups, so it counts as a write. |
| discover_domain_subdomains | write | Inputs: domain_id | Passive subdomain discovery from certificate transparency and DNS. Does not probe the hosts it finds. |
Scans, checkups, and dark web
scope: scansSecurity checkups and breach monitoring. The stored history is almost always enough — reach for a live run only when something has just changed.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| get_checkup_history | read | Inputs: domain_id | The newest security checkup's failing and warning checks (passes counted) and the score trend of earlier ones. The raw list; audit_domain ranks and de-duplicates it. |
| get_dark_web_status | read | Inputs: — | Cached dark-web results with no upstream lookup: breaches per monitored address, and infostealer exposure: stealer logs in XposedOrNot's results for each address. |
| run_domain_scan | write | Inputs: domain_id | Domain health, security checkup, and single-page SEO in one pass. Does not run vulnerability, whole-site, dark-web, or audit-grade accessibility scans. |
| run_domain_checkup | write | Inputs: domain | A live checkup on any domain. The exposed-file probe runs only on a domain this account has verified. |
| run_dark_web_scan | write | Inputs: — | Refresh every monitored email address against the breach index. Spends the manual-scan allowance. |
SEO — one page and the whole site
scope: seoWhat a page says about itself, and what a crawl of every page finds. The site audit is asynchronous: start it, poll the status, then read the results.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| get_seo_results | read | Inputs: domain_id | The latest SEO and accessibility scan: page titles, meta descriptions, heading structure, and violations. |
| get_seo_history | read | Inputs: domain_id | SEO scores over time, so a change can be shown to have moved the number. |
| get_site_audit_status | read | Inputs: audit_id | Progress of a whole-site crawl. |
| get_site_audit_results | read | Inputs: audit_id | Page-level findings from a whole-site crawl. |
| get_seo_intent_conflicts | read | Inputs: domain_id, limit?, detail? | Which pages compete for one search, with the page to keep and the steps for the other. Read from the newest crawl; free. Worst 25 by default, with totals. |
| run_seo_scan | write | Inputs: domain_id | Re-score a site after publishing changes. Free accounts get one manual scan a day; a second returns 429. |
| start_site_audit | write | Inputs: domain_id, max_pages? | Crawl the sitemap or same-site links and check every discovered page. Returns an audit id immediately. |
IndexNow — tell search engines a page changed
scope: seoBing, Yandex, Seznam, Naver, Yep, the Internet Archive and Amazon take change notices over IndexNow. Google does not. The site serves a key file first; after that every URL sent, when its page changed and what each engine answered is on record.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| get_indexnow_status | read | Inputs: domain_id | Whether it is on, the key file to upload and whether it checked out per host, engines, auto-submit, last sitemap read and totals by engine. |
| list_indexnow_urls | read | Inputs: domain_id, engine?, result?, q?, limit?, offset? | Every URL sent: when the page changed, first and last sent, how often, and each engine's last answer. |
| list_indexnow_submissions | read | Inputs: domain_id, limit?, offset? | The send log, with each engine's HTTP status per send. |
| configure_indexnow | write | Inputs: domain_id, enabled?, engines?, auto_submit?, sitemap_url?, key?, key_location?, regenerate_key? | Turn IndexNow on (creates the key) or change engines, daily sitemap submission, the sitemap or the key. |
| verify_indexnow_key | write | Inputs: domain_id, host? | Fetch the key file from the site now, per host. |
| submit_urls_to_indexnow | write | Inputs: domain_id, urls, lastmod?, engines? | Send up to 1,000 changed URLs to each engine and record every answer. 10,000 a day per domain. |
| sync_sitemap_to_indexnow | write | Inputs: domain_id, sitemap_url?, dry_run? | Read the sitemap and send only what is new or has a newer lastmod. |
Google Search Console
scope: seoOnce the owner connects their Google account from the dashboard or the app (read-only access), these read Google's own numbers for their sites: clicks, impressions, click-through rate and average position, plus Google's indexing verdict for a page.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| list_search_console_sites | read | Inputs: refresh? | The Search Console properties on the connected Google account and the domain each one answers for. |
| get_search_console_performance | read | Inputs: domain_id, start_date?, end_date?, dimension?, limit?, refresh? | Totals, a daily series and the top queries or pages. Default is the 28 days ending three days ago. |
| inspect_url_index_status | read | Inputs: domain_id, url | Whether Google has indexed one page, why not, when it last crawled it and which canonical it chose. 2,000 a day per property. |
| get_search_console_opportunities | read | Inputs: domain_id, min_impressions?, limit? | Queries at average position 8-20 with impressions, and whether each is already a tracked keyword. |
Keyword gap
scope: seoThe searches a site's competitors show up for, set against every page on the site and what Search Console says it already ranks for. Each search gets one job: write a page, fix a page, merge two pages, or leave it. The ones worth paying for in Google Ads are grouped by the page an ad should land on. A run spends credits, so quote first.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| get_keyword_gap | read | Inputs: domain_id, bucket?, ads_only?, limit?, offset?, run_id? | The latest run: what to do per search, most important first, with volume, position, the page to rank and the competitors that rank. |
| quote_keyword_gap | read | Inputs: domain_id, shortlist? | What a run would read and its worst-case price, the balance, and which competitors it would use. |
| run_keyword_gap | write | Inputs: domain_id, approved_credits, request_key, shortlist? | Buy the competitor keyword lists and the shortlisted search pages, classify every search, store the rows. Charged for what returned data. |
| list_keyword_gap_runs | read | Inputs: domain_id | Earlier runs with their summaries, for month-to-month comparison. |
| get_keyword_gap_competitors | read | Inputs: domain_id | The saved competitors and suggestions from the site's own searches and the local scan. |
| add_keyword_gap_competitor | write | Inputs: domain_id, competitor, note? | Save a competitor domain. Five can be active at once. |
| set_keyword_gap_competitor | write | Inputs: competitor_id, status | Turn a saved competitor on or off. |
| remove_keyword_gap_competitor | write | Inputs: competitor_id | Delete a saved competitor. |
| update_keyword_gap_settings | write | Inputs: domain_id, frequency?, shortlist? | Run it on the 1st of each month, and how many search pages each run buys. |
Crawler access — can search engines and AI assistants read the site
scope: seoChatGPT, Claude and Perplexity take no URL submissions; they find pages with their own crawlers and the search indexes. These tools check robots.txt and the site's edge as each crawler, every day for domains with IndexNow on, and show every domain's setup at once.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| get_search_visibility_overview | read | Inputs: none | Every domain on the account: IndexNow on, key verified, last sitemap read and send, which crawlers are blocked, and what needs attention. |
| get_crawler_access | read | Inputs: domain_id | The latest check per crawler (Googlebot, Bingbot, OAI-SearchBot, Claude-SearchBot, GPTBot, ClaudeBot and more): robots.txt rule and edge answer. |
| check_crawler_access | write | Inputs: domain_id | Check now, store it, and name any search or AI crawler that lost access since the last check. |
| list_crawler_access_history | read | Inputs: domain_id, limit? | Earlier checks, newest first, to see when a crawler lost or regained access. |
Local SEO — rankings, maps, reviews, competitors
scope: seoThe suite behind local search. A saved business profile is the prerequisite for everything that measures a position, and the catalog is the authority on what each action needs and costs.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| get_local_seo_profile | read | Inputs: domain_id | The saved business profile: name, location, service radius, and targeting mode. |
| get_local_keyword_targets | read | Inputs: domain_id | The phrases currently tracked for this domain. |
| get_local_rank_history | read | Inputs: domain_id | Recorded positions for each tracked phrase on each past check. |
| get_geogrid_scans | read | Inputs: domain_id | Past map-grid scans showing where across the service area rankings hold and where they fall away. |
| get_local_seo_catalog | read | Inputs: — | All 33 catalogued actions with their exact inputs, prerequisites, price basis, and caching rules. Call this before running one. |
| get_local_seo_operation | read | Inputs: request_key | Recover a paid action after a timeout instead of paying for it twice. |
| get_local_seo_credits | read | Inputs: — | Remaining rank-check and map-scan credits on the account. |
| save_local_seo_profile | write | Inputs: domain_id, business_name, location, targeting?, radius_miles?, is_service_business?, street_address?, phone? | Create or update the business profile. Required before rank checks and map scans will run. |
| add_local_keyword_target | write | Inputs: domain_id, keyword, targeting? | Track a phrase. Up to 25 per domain; adding the same phrase twice does nothing. |
| delete_local_keyword_target | destructive | Inputs: keyword_id | Stop tracking a phrase. The rank history already recorded is kept. |
| get_rank_tracker | read | Inputs: domain_id | Whether the phrases are rank-checked on a schedule (off, daily, weekly), the cost per run and per month, and how the last run went. Free. |
| set_rank_tracker | write | Inputs: domain_id, cadence, surfaces? | Turn scheduled rank checks on (daily or weekly) or off. Each run costs two credits a phrase on the local pack and four on organic when it runs; a run the balance cannot cover is skipped uncharged. |
| check_local_ranks | write | Inputs: domain_id, request_key | Live positions for every tracked phrase, measuring the local pack. Costs two credits a phrase. |
| run_geogrid_scan | write | Inputs: domain_id, keyword, grid_size?, request_key | Check one phrase from many points across the service area on a 5×5, 7×7, or 9×9 grid. |
| run_local_seo_action | write | Inputs: action_id, request_key, input | Run any action from the catalog — reviews, citations, keyword research, competitor gap, backlinks, AI visibility, full audits. |
Accessibility
scope: accessibilityAudit-grade WCAG 2.2 AA evaluation in a real browser. Separate from the accessibility violations that come back with an ordinary SEO scan, and separately scoped so a key can have one without the other.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| quote_accessibility_audit | read | Inputs: domain_id | Cost, available credits, page cap, and whether an audit can start right now. |
| list_accessibility_audits | read | Inputs: domain_id?, limit? | Recent evaluations, optionally narrowed to one domain. |
| get_accessibility_audit | read | Inputs: audit_id | Pages, axe findings, WCAG rollups, manual-review coverage, and regression data for one audit. |
| start_accessibility_audit | write | Inputs: domain_id, request_key, max_pages?, viewport? | Queue a browser evaluation. Spends accessibility credits, so the request key matters. |
Vulnerability and exposure
scope: vulnscanActive scanning needs proof that the account controls the domain. Get the challenge, publish it, verify it, then scan.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| get_vuln_scan_latest | read | Inputs: domain_id | The most recent completed scan: findings worst first, informational readings counted, per-host tables left out unless detail is true. |
| get_vuln_scan_results | read | Inputs: scan_id | Findings for one scan by id. This is how you poll a scan you just started. |
| get_vuln_scan_history | read | Inputs: domain_id | The last twenty scans with status, profile, timing, and severity summary. |
| get_vulnerability_assets | read | Inputs: domain_id | Every public hostname discovered for a domain and the finding counts attached to each. |
| get_open_ports | read | Inputs: domain_id | Per-host port, service, banner, version, and risk observations. |
| list_lookalikes | read | Inputs: domain_id | Domains registered by other people to imitate yours, each with a risk band and the evidence behind it — plus how much of the variation space the scan actually covered. |
| get_lookalike_events | read | Inputs: domain_id | What changed about those impostors over time: one appearing, one gaining the ability to receive email, one becoming more dangerous. |
| run_lookalike_scan | write | Inputs: domain_id | Generate variations of a domain and check which are registered. Takes up to a minute; prefer the stored list unless a fresh check is wanted. |
| set_lookalike_verdict | write | Inputs: domain_id, lookalike, verdict? | Say what one impostor is so it stops being reported: ours, unrelated, or known. Omit the verdict to clear it. |
| get_observed_components | read | Inputs: — | The portfolio's technology inventory with version confidence where a version was actually observed. |
| get_scan_ownership_verification | write | Inputs: domain_id | Return the DNS, file, or email proof required before active scanning, creating a challenge if none exists. |
| verify_scan_ownership | write | Inputs: domain_id | Re-check the published proof and record verification when it is found. |
| start_vuln_scan | write | Inputs: domain_id, scan_type?, scan_profile?, target_hosts? | Quick through extreme, optionally limited to selected hosts. Returns a scan id; the scan runs in the background. |
Compliance evidence
scope: compliancePCI, HIPAA, and cyber-insurance controls. These records are audit evidence — notes should quote the account owner's own wording rather than paraphrase it.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| get_compliance_records | read | Inputs: — | The compliance checklist with each control's current status and notes. |
| update_compliance_item | write | Inputs: record_id, status, notes? | Set one control to unanswered, met, partial, not met, or n/a. "Not met" is a recorded gap, not a blank. Uses the record id, not the item id. |
| list_wisps | read | Inputs: — | The account's written information security plans (WISPs): draft or complete, progress, last built. |
| start_wisp | write | Inputs: title? | Start a WISP by interview. Returns the first questions to ask; DomainGuard holds the questionnaire and writes the document. |
| get_wisp_interview | read | Inputs: wisp_id, next? | A plan's progress, its saved answers, and the next questions to ask, each with why, options and a suggested value. |
| answer_wisp_questions | write | Inputs: wisp_id, answers | Save the user's answers by question id. Returns what was saved, what was refused and why, and the next questions. |
| build_wisp | write | Inputs: wisp_id | Write the finished plan as a Word document and return a 7-day download link plus the open items it records. |
| get_wisp_download_link | read | Inputs: wisp_id | A fresh 7-day download link for a plan that has been built. |
| delete_wisp | destructive | Inputs: wisp_id | Delete a plan and its answers. |
Uptime and dependencies
scope: statusThe live status of third-party providers — the fastest way to separate a problem with your site from an incident at your host.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| get_status_services | read | Inputs: detail? | Status across the whole provider catalogue: counts, and every vendor not operational with its affected components. |
Alerts
scope: domainsThe account's alert feed. Alerts are read through the domain tools; this is the one write against them.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| mark_alerts_read | write | Inputs: ids (optional) | Mark every open alert as read, or only the ids given. Read alerts cannot be reopened; the History log keeps the record. |
Tell us when we are wrong
scope: scansThe assistant reading these results is the best reviewer the scanner has. A false positive, a missed problem, a number that contradicts what it can verify — report it, and the operators get one message per domain review. Enterprise only; 30 reports a day.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| get_verification_tasks | read | Inputs: domain_id?, kind?, limit?, include_verified? | Every claim we make about a domain as a task: the claim, how we tested it, read-only commands that reproduce it (dig, curl, openssl, nc) and what to compare. Without domain_id, the domains with open counts. |
| submit_verification_results | read | Inputs: domain_id, agent?, results[], missed[] | Your verdict on each task: confirmed, incorrect or could_not_verify, with what you saw and how. A dispute files a report and queues a re-check. Records only, so a read-only key can send it. |
| report_scanner_issue | read | Inputs: domain_id, category, title, detail | One thing the scanner got wrong that is not a verification task: what it said, what is true, how you know, what to change. Records only; a read-only key can send it. |
| submit_scanner_review | read | Inputs: domain_id | Close the review and send it to the operators as one message. Call it once per domain, when you are done. |
Operator tools (administrator only)
scope: adminWhat the nightly fix routine reads. The admin scope is not one a customer key can carry: it is minted only from the administrator's own signed-in session and reaches only these tools.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| list_error_events | read | Inputs: days, source (optional) | The Worker's own error log, grouped by fingerprint with occurrence counts and the accounts affected, plus the newest raw rows. |
| get_self_check_status | read | Inputs: — | Every self-check invariant's last verdict, failing first, and when each cron scope last completed a pass. |
| list_scan_failures | read | Inputs: days (optional) | Domain scans, exposure scans, crawls and accessibility audits that did not finish, with their reason, plus exposure scans stuck for over two hours. |
| list_scanner_reports | read | Inputs: days, status (optional) | What customers' assistants reported wrong with the scanner, open ones first — the claim, the evidence, the suggested fix, who sent it. |
| get_verification_stats | read | Inputs: days? | Scanner accuracy from customers' agent verdicts: confirmed versus disputed per test method, and the recent disputes. Operator-only. |
| list_feature_requests | read | Inputs: status? | The feature-suggestion queue from the app, the dashboard and MCP: what was asked, by whom, its status, and a count per status. |
| update_feature_request | write | Inputs: suggestion_id, status, note? | Move a request to planned, building, shipped or declined, with the note the person reads in their feed. Shipped also pushes them. |
| domainguard_waitlist_launch_email | write | Inputs: action?, app_store_url? | The one launch email to the iPhone app waiting list: status, preview, a test copy to you, then send (50 every five minutes, nobody twice). |
| monthly_report_email | write | Inputs: action?, user_id?, month? | The monthly report email: status, a preview for any account, a test copy to you, and switching it on or off for one account. Off for everyone until switched on. |
Guided onboarding and setup
scope: domainsThe way in. plan_domain_onboarding returns the interview; onboard_domain applies the answers in one write without spending; the setup guide says what is left. add_domain still works for a bare add.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| plan_domain_onboarding | read | Inputs: domain? | Call this FIRST whenever the user wants to add or set up a domain. |
| onboard_domain | write | Inputs: domain, sends_email?, lookalikes?, subdomains?, vulnerabilities?, accessibility?, exposure_monitoring?, group?, notes?, scan_client_id?, local_business?, ownership_email?, dark_web_emails? | The one write that puts a domain on the account fully configured, from the answers plan_domain_onboarding told you to collect. |
| get_domain_setup_guide | read | Inputs: domain_id | The server-computed checklist for one domain: first scan, alerts, email authentication, DMARC reports, ownership proof, monitoring, local business, lookalikes, vulnerability scan, exposure monitoring — each done, todo, running, blocked by plan, skipped or not applicable, with how to finish it. |
| skip_domain_setup_step | write | Inputs: domain_id, step, skipped? | Record that a setup step does not apply to this domain (or un-skip it). Only optional steps can be skipped; the required ones cannot. |
| add_domains_bulk | write | Inputs: domains | Add up to 100 domains in one call. Returns which were added and which were skipped (already here, invalid). |
Account: alerts, settings, groups, clients
scope: domainsThe account-wide plumbing: the alert feed and history, alert and scan settings, group labels, and the client records a consultancy files domains under.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| list_alerts | read | Inputs: limit?, before? | The alert feed: every alert the account was sent, newest first, with the domain, event type, channel, and whether it has been read. Read it when the user asks "what have you told me about" or before mark_alerts_read. |
| get_alert_activity | read | Inputs: limit?, before? | The History log: alerts, scans, changes and events across the account merged into one timeline. Broader than list_alerts, which is only what was sent. |
| get_account_settings | read | Inputs: — | The account's alert and scanning settings: which alerts are on, how often domains are scanned, and the thresholds. Every alert lands in the alert feed and is pushed to the account's iPhone. Read before changing anything so you change only what the user asked. |
| update_account_settings | write | Inputs: scan_frequency?, notify_expiry_days?, notify_ssl_days?, security_threshold?, notify_expiry?, notify_ssl_expiry?, notify_dns_issues?, notify_security_issues?, notify_dns_record_changes?, notify_status_push?, notify_uptime_push?, notify_dmarc_alerts?, notify_new_subdomains?, notify_scan_complete?, notify_scan_results_email? | Change the account's alert and scan settings. Pass only the fields the user asked to change; everything else is kept. Alerts go to the alert feed and the account's iPhone; there is no alert email. notify_scan_results_email only emails the report of a scan the user started. |
| list_domain_groups | read | Inputs: — | The group labels used to organise the portfolio (clients, brands, regions) with how many domains sit in each. |
| create_domain_group | write | Inputs: name | Create an empty group label. Assigning domains to it is assign_domains_to_group; update_domain also takes a group name. |
| delete_domain_group | destructive | Inputs: group_id | Remove a group label. The domains in it are kept and become ungrouped. |
| rename_domain_group | write | Inputs: group_id, name | Give a group a new name. The domains in it stay in it. |
| assign_domains_to_group | write | Inputs: domain_ids, group_name? | Put up to 50 domains under one group name in a single call, creating the group if needed. Pass an empty group_name to ungroup them. |
| list_scan_clients | read | Inputs: — | Clients are the optional grouping a consultancy uses to hold domains and network targets per customer. Returns each with its id. |
| create_scan_client | write | Inputs: name | Create a client record to assign domains and IP targets to. Names are unique per account. |
| delete_scan_client | destructive | Inputs: client_id | Remove a client record. Domains and targets assigned to it are kept, unassigned. |
| suggest_feature | read | Inputs: title, details? | Send the DomainGuard team an idea for something the product should do. The user sees in Alerts when we plan it, build it, ship it or decline it. Read-only keys can send it; 10 a day. |
| list_my_feature_suggestions | read | Inputs: — | The account's own suggestions with their status and any note from us. Read it before suggesting the same thing twice. |
| list_support_conversations | read | Inputs: — | The account's support threads with NHM, newest first, with status. |
| get_support_conversation | read | Inputs: conversation_id | One support thread in full, including replies from NHM. |
| reply_to_support_conversation | write | Inputs: conversation_id, message | Add the user's message to an existing support thread. Opening a new thread needs the dashboard; say so if there is none. |
| update_support_conversation | write | Inputs: conversation_id, status?, archived? | Set a thread's status to open or closed, or archive/unarchive it. |
Hijack Guard: change events
scope: domainsDNS, registrar, certificate and hosting changes, per domain and account-wide, and the answer to each: ours (authorize), not ours (deny), or just moving it along.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| get_domain_hijack_events | read | Inputs: domain_id | Hijack Guard events for one domain: DNS, registrar, certificate and hosting changes with severity and lifecycle. get_domain_events is the account-wide view. |
| get_domain_event | read | Inputs: event_id | One Hijack Guard event in full: what changed, from what to what, when, and what has been done about it. |
| act_on_domain_event | write | Inputs: event_id, action | Move a Hijack Guard event through its lifecycle. authorize means "we made this change" and promotes it to the new baseline so it stops alerting; deny means "we did not" and keeps it flagged. |
Email: DMARC reports, senders, managed records
scope: domainsThe aggregate-report stream behind the DMARC score: who is sending as the domain, whether they align, the report address to publish, and the option to let DomainGuard publish and advance the records.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| list_dmarc_reports | read | Inputs: domain?, limit?, offset? | The aggregate reports received, newest first, optionally for one monitored domain. Each names the reporter, the window, the published policy and the message counts. |
| get_dmarc_senders | read | Inputs: domain, days? | Sender attribution from the aggregate reports: each sending source, its volume, and whether it passed SPF and DKIM alignment. The list to read before tightening a DMARC policy. |
| get_dmarc_inbox | read | Inputs: — | The rua= address DomainGuard receives aggregate reports at for this account, whether it is provisioned, and any delivery error. This is the address to put in the DMARC record. |
| rotate_dmarc_inbox | write | Inputs: — | Issue a new report address and retire the old one. Every domain's DMARC record then has to be updated, so confirm with the user; there is a cooldown between rotations. |
| get_managed_email_auth | read | Inputs: — | Which domains have delegated their DMARC or SPF record to DomainGuard to publish and maintain, and whether the delegation is live. |
| enable_managed_email_auth | write | Inputs: domain, service, source_record? | Start managing one record: returns the CNAME the user publishes (for DMARC) or takes the SPF record to flatten and serve. After they publish, check_managed_email_auth confirms it. |
| disable_managed_email_auth | write | Inputs: domain, service | End a delegation. The user must publish their own record again or the domain will have none. |
| check_managed_email_auth | write | Inputs: domain | Look up DNS to confirm the delegation CNAME is published and serving. A live lookup; call it after the user says they published. |
| set_managed_dmarc_policy | write | Inputs: domain, action | For a managed DMARC record: advance moves the policy one step towards reject (none → quarantine → reject) when the reports show every legitimate sender aligned; revert steps it back. |
Scan clearance and authorisation
scope: vulnscanBasic scans run on any domain. Deep scans need the domain verified, one domain at a time: a sign-in address at it counts, and otherwise the email link is the easiest proof. The operator queue covers a client's domain the account cannot prove, and approval for deep scans of any domain covers the rest.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| get_scan_clearance_status | read | Inputs: — | Account-wide view of ownership proof: which domains carry a current proof. A proof clears that domain only. |
| verify_scan_ownership_bulk | write | Inputs: domain_ids? | Re-check the published DNS or file proof for the domains given (or every domain when omitted) and record what is found. |
| request_ownership_email_link | write | Inputs: domain_id, address | The easiest ownership proof: send a one-click link to an address AT the domain (postmaster@, admin@, the owner's own mailbox — never a gmail or yahoo address). When they click it that domain is cleared for active scanning for 90 days. |
| request_ownership_instructions_email | write | Inputs: domain_id | Email the three ways to verify a domain (email link, DNS record, file) to the account's own verified sign-in address. Three a day. |
| request_scan_authorization | write | Inputs: domain_id, reason, contact_email? | For a domain the account cannot prove ownership of but is authorised to test (a client engagement), file a request with the reason and a contact; an operator approves or declines. Check get_scan_authorization for the answer. |
| get_scan_authorization | read | Inputs: domain_id | The latest operator authorisation for one domain and whether it is currently active. |
| list_scan_authorizations | read | Inputs: limit?, offset? | Every authorisation request the account has filed, newest first, with its status. |
Lookalike controls
scope: vulnscanTurning the watch on and off, the evidence pack for a filing, and how lookalike alerts are delivered.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| set_lookalike_watch | write | Inputs: domain_id, enabled | Continuous impostor-domain monitoring for one domain. Turning it on needs the plan capability; turning it off is always allowed. |
| get_lookalike_evidence | read | Inputs: domain_id, lookalike | Everything recorded about one lookalike domain — registration, DNS, mail capability, certificates, timeline — assembled for a registrar abuse report or a takedown filing. |
| act_on_lookalike_event | write | Inputs: event_id, action | Mark one lookalike change event as seen (acknowledge) or dealt with (resolve). Event ids come from get_lookalike_events. |
| get_lookalike_alert_settings | read | Inputs: — | Whether lookalike alerts are on. When they are, a lookalike that needs action lands in the alert feed and is pushed to the account's iPhone. |
| update_lookalike_alert_settings | write | Inputs: push | Turn lookalike alerts on or off. On means a feed entry and a push when a lookalike gains mail or turns into an active threat. |
Software, advisories, dismissals
scope: vulnscanWhat the portfolio runs on, by vendor and by product; the KEV and CVE alerts raised against it with an exposure verdict; the products the account chose to track; and the findings it has silenced with a reason.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| list_vuln_dismissals | read | Inputs: kind? | Findings, inventory readings and software alerts the account has permanently silenced, with the reason given. |
| dismiss_vuln_finding | write | Inputs: kind, target_key, reason, domain_id?, label?, note? | Silence one thing for good, with a reason: false_positive, accepted_risk, fixed or not_applicable. target_key is the finding's stable key from the scan result (what it IS, not its row id), so the dismissal survives re-scans. |
| restore_vuln_dismissal | write | Inputs: dismissal_id | Remove a dismissal so the finding, component or alert is reported again. Use the id from list_vuln_dismissals. |
| get_unreadable_versions | read | Inputs: — | Software a scan found on your hosts but could not read a version from (UniFi OS Server, firewalls), with any version you have entered. |
| declare_software_version | write | Inputs: host, product, version | Enter the version shown on the device's own settings page; its advisories are re-checked against it at once. A version a scan reads later replaces it. |
| remove_declared_software_version | write | Inputs: host, product | Withdraw a version entered by mistake; its advisories are re-judged at once. |
| recheck_host_software | write | Inputs: domain_id, host | "Check again" for one host after an update: re-read its software and versions and re-match advisories. Limited per host per day. |
| list_software_vendors | read | Inputs: — | The observed technology inventory rolled up by company: every vendor seen across the account's domains with component counts and open advisories. |
| get_software_vendor | read | Inputs: vendor | Every component, version and domain observed for one vendor, with its advisories. vendor is the vendorId from list_software_vendors. |
| get_vulnerability_feed | read | Inputs: — | The global feed of recently ingested vulnerabilities (CISA KEV and NVD), not filtered to this account. Use get_software_advisory_history for one product. |
| get_software_advisory_history | read | Inputs: product, vendor? | Every known advisory for one software product, matched the same way the alert ingest matches it. Use it when a component has no status feed: "CVEs and KEVs only". |
| get_software_overview | read | Inputs: — | One list of every application the account watches for advisories and every application a scan found running, with where each runs, the versions read and its open advisories by exposure verdict. |
| list_tracked_software | read | Inputs: — | The software products the account watches for new vulnerabilities, with alert preferences and open alert counts. |
| search_software_catalog | read | Inputs: q?, category? | Find a product to track by name or category. Returns slugs to pass to track_software. |
| get_software_catalog | read | Inputs: — | Every product in the catalog. Large; prefer search_software_catalog. |
| get_software_catalog_categories | read | Inputs: — | The categories the software catalog is organised by. |
| track_software | write | Inputs: app_name, app_slug?, vendor?, sources?, severity_filter? | Start watching one product for new KEV and CVE entries. Each new entry lands in the alert feed and as a push when it is found; severity_filter narrows what counts. |
| update_tracked_software | write | Inputs: app_id, is_active?, severity_filter?, sources? | Change which severities and feeds one tracked product alerts on, or pause it with is_active false. Only the fields passed change. |
| untrack_software | destructive | Inputs: app_id | Remove a tracked product and its alerts. Confirm the product name first. |
| watch_all_detected_software | write | Inputs: — | Free. Watch every product the scans found and nobody watches yet, in one call. |
| list_software_alerts | read | Inputs: status?, source?, limit?, offset? | KEV and CVE alerts raised for tracked and observed software, each with severity and an exposure verdict: confirmed (the vulnerable version was observed), possible, not_affected or unconfirmed. Lead with confirmed ones. |
| get_software_alert_summary | read | Inputs: — | Counts of unread, critical, KEV and confirmed-exposure software alerts, per tracked product and in total. |
| update_software_alert | write | Inputs: alert_id, alert_status | Set the status of one software alert. remediated records that the fix was applied; dismissed means it will not be. |
IP and network targets
scope: vulnscanDaily port scans of public IPs and small ranges the account owns or is authorised to test. Adding one records the attestation.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| list_ip_targets | read | Inputs: — | The IP addresses and CIDR ranges the account port-scans daily, with their client and last result. |
| add_ip_target | write | Inputs: target, attestation, label?, client_id?, daily_scan? | Start daily port scanning of a public IP or small CIDR. The user must confirm they own or are authorised to scan it; pass attestation true only after they say so in words. |
| update_ip_target | write | Inputs: target_id, client_id?, daily_scan? | Move a target to another client or turn its daily scan on or off. |
| delete_ip_target | destructive | Inputs: target_id | Stop scanning a target and remove it with its history. Confirm first. |
| list_ip_target_scans | read | Inputs: target_id | Past port scans of one target with the open ports and services seen each time. |
| scan_ip_target | write | Inputs: target_id | Run the port scan of one target immediately instead of waiting for the daily run. Sends traffic to the target. |
Dark web: addresses
scope: scansWhich addresses are watched in breach data, and one breach in detail. New hits land in the alert feed and are pushed to the app.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| get_dark_web_breach | read | Inputs: breach | Details of one breach (by breachID from get_dark_web_status): what was exposed, when, how many records, and which of your monitored addresses were in it. |
| add_dark_web_email | write | Inputs: email, cadence? | Watch one address in breach data. Only addresses at the account's own domains or its verified sign-in address; cadence weekly and daily need a paid plan. |
| remove_dark_web_email | destructive | Inputs: email_hash | Remove one monitored address by its hash, as get_dark_web_status lists it. |
Deep crawls, single-URL scoring, reports
scope: seoCrawl chosen pages rather than the whole site, score any public URL on demand, and send the branded report.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| get_seo_policy | read | Inputs: — | The account's SEO allowances: manual scans per day, crawl page caps, whether deep crawls and reports are on the plan. |
| list_manual_url_scans | read | Inputs: — | Past one-off SEO scans of individual URLs saved on the account. |
| fetch_sitemap | write | Inputs: domain | Read the sitemap of one monitored domain and return its URLs — the input for start_deep_seo_job. A live fetch of the site. |
| start_deep_seo_job | write | Inputs: domain_id, domain, pages, sitemap_url? | Crawl and score a list of specific pages on a monitored domain (from fetch_sitemap or the user). The plan caps how many; the response says if the list was trimmed. |
| list_deep_seo_jobs | read | Inputs: — | Every queued, running and finished deep crawl on the account with progress. |
| get_deep_seo_job | read | Inputs: job_id | Progress and status of one crawl job by id. |
| cancel_deep_seo_job | write | Inputs: job_id | Stop a queued or running crawl. Pages already scored are kept. |
| get_deep_seo_scans | read | Inputs: domain_id | The finished deep crawls for one domain with their scores and page counts. Each has a scan id for get_deep_seo_scan_pages. |
| get_deep_seo_scan_pages | read | Inputs: scan_id, detail? | Every page in one deep crawl with its scores, page signals and defects (warn and fail checks). |
| check_page_seo | write | Inputs: url, detail? | Fetch any public page and return its findings, not its HTML: scores, the problems worst first each with its page-specific fix (drafts marked as drafts, and where in the site builder to set it), passing checks named, robots.txt, sitemap and http-to-https redirect. A live fetch of that one page. Compact by default; detail: true for every check. |
| assess_website | write | Inputs: url, detail? | A quick combined read of any public URL: an overall score, category scores, the five most important findings, and the findings behind the SEO, accessibility, performance and best-practices scores (problems with fixes, passes named). A live fetch. detail: true for every check. |
| score_page_accessibility | write | Inputs: url, detail? | A quick static accessibility score of any public page with the problems worst first (element, drafted label or alt text, WCAG criterion) and passes named. Not audit grade — start_accessibility_audit is. detail: true for every check. |
| score_page_performance | write | Inputs: url | A quick performance read of any public page: weight, requests, render-blocking resources. A live fetch. |
| email_seo_report | write | Inputs: domain_id, to, note? | Send the branded PDF SEO report for one monitored domain to an address, with an optional note. Needs a completed SEO scan. |
| get_report_branding | read | Inputs: — | The white-label branding applied to emailed reports (company name, logo, accent colour, footer) and whether the plan allows changing it. |
| save_report_branding | write | Inputs: company_name?, logo_url?, accent_hex?, footer_text? | Set the white-label branding on emailed reports. Enterprise only. |
Local SEO setup: quick start, discovery, quotes
scope: seoThe short road into local search. Read the quick start, let discovery pre-fill the business from the homepage, confirm the city, quote, then one run takes the first local-pack and organic measurement.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| get_local_seo_quickstart | read | Inputs: domain_id | One read that shows where a domain stands in local search setup: the saved business (name, city, whether the city was confirmed), tracked phrases, suggested phrases from the homepage when nothing is saved yet, the newest local-pack and organic positions per phrase, the last Google Business Profile read, the credit balance, and the exact price of a run. |
| run_local_seo_quickstart | write | Inputs: domain_id, business_name, location, keywords, request_key | The whole first step in one call: saves the business name and city, saves up to 5 phrases, confirms the city against the gazetteer, then checks the local-pack AND organic position for every phrase and reads the Google Business Profile. |
| get_domain_schedule | read | Inputs: domain_id? | Free. Every automatic check for a domain, how often it runs, whether it is on, and when it last ran and runs next. Without domain_id, what would run on a domain about to be added. |
| autofill_local_seo | write | Inputs: domain_id, refresh? | Free. Does the free part of the local setup: reads the website, fills the blank business details, confirms the city and picks phrases, never over what the owner typed. Returns every value with where it came from and the paid steps (first report, weekly report) with their price. |
| get_local_autopilot | read | Inputs: domain_id | Free. The local setup as it stands: each business field with its source, tracked and suggested phrases, followed competitors, the schedule and the paid steps waiting for a yes. |
| preview_local_autopilot | write | Inputs: domain_id, refresh? | Free. Reads the business's own website (homepage plus contact, about, services and areas pages) and proposes the business details and phrases for a first scan, with the exact price. |
| run_local_autopilot | write | Inputs: domain_id, business_name, location, keywords, approved_credits, request_key, street_address?, phone?, grid_size?, grid_keyword?, frequency?, report_emails? | Saves the confirmed business and phrases, then runs the first full local scan: Maps top 20, the 3-pack and organic per phrase, the matched Google listing checked against the website, competitors and next steps. Emails the report. |
| get_local_seo_brief | read | Inputs: domain_id | Free. What to do next to rank better locally: Google profile fixes with the text to paste, a page for each phrase, on-page issues, why competitors are ahead, and the schedule. |
| quote_local_scan | read | Inputs: domain_id, grid_size?, grid_keyword? | Free. The price of a full local scan for the saved phrases, with or without a map grid. |
| run_local_scan | write | Inputs: domain_id, approved_credits, request_key, grid_size?, grid_keyword? | Runs a full local scan now and returns the report with the change since the last one. |
| list_local_scans | read | Inputs: domain_id | Free. Every local scan for a domain with its headline numbers, newest first. |
| get_local_scan | read | Inputs: scan_id | Free. One full local scan report. |
| email_local_scan | write | Inputs: scan_id | Sends a report again to the owner and the domain's saved recipients. |
| get_local_competitors | read | Inputs: domain_id | Free. Every business showing up for the domain's phrases, with positions, 3-pack count, rating, reviews and the owner's pins and hides. |
| add_local_competitor | write | Inputs: domain_id, name, website? | Free. Follow a competitor in every local report, matched to Google Maps by name or website. |
| remove_local_competitor | write | Inputs: competitor_id | Free. Stop following a competitor: one you added is deleted, one Google showed is hidden. |
| update_local_competitor | write | Inputs: competitor_id, pinned?, hidden? | Free. Pin a competitor to the top of every report, or hide one that is not a real competitor. |
| update_local_scan_settings | write | Inputs: domain_id, frequency?, email_reports?, report_emails?, scan_grid?, grid_size?, grid_keyword? | Free. Weekly or monthly scans, report email and recipients, and whether scheduled scans include a map grid. |
| set_local_listing | write | Inputs: domain_id, place_id, name? | Free. Pins the business's Google listing when a scan could not confirm it. |
| discover_local_seo_details | write | Inputs: domain_id | Read one monitored domain's public homepage and return candidate business name, city, street address, phone, whether it looks like a service-area business, and up to 12 candidate phrases — each with its source and a confidence. |
| verify_local_seo_location | write | Inputs: domain_id, location | Check a "City, ST" against the rank-data gazetteer before saving it, and get the resolved name or close matches. Free. |
| get_local_seo_access | read | Inputs: — | Says whether this account can use the Local SEO suite and on which plan. Check it before promising a rank check. |
| quote_local_ranks | read | Inputs: domain_id, keywords?, surfaces? | What check_local_ranks or a rank_check action would cost for this domain: per phrase per surface, against the current balance. Free. |
| quote_geogrid_scan | read | Inputs: domain_id, keyword, grid_size?, location? | What run_geogrid_scan would cost for one phrase and grid size, and whether the balance covers it. Free. |
| get_geogrid_entitlement | read | Inputs: domain_id | Free map scans remaining this period for a domain, and what more would cost. |
| quote_local_seo_endpoint | read | Inputs: domain_id, endpoint | The credit cost of one catalogued action before running it. endpoint is the key in its quote_endpoint, e.g. "localAudit". |
| search_locations | read | Inputs: q, state?, country?, limit? | Find the exact place name the rank data covers from a partial name; state may be "OH" or "Ohio". Use it when verify_local_seo_location or the quick start says the city was not found. |
| list_covered_locations | read | Inputs: prefix?, state?, country?, limit?, offset? | Page through the cities the rank data covers, optionally by state or name prefix. |
| get_local_keyword_ideas | read | Inputs: domain_id, limit? | Phrase ideas already gathered for a domain by earlier keyword research, without spending anything. |
| get_backlink_snapshots | read | Inputs: domain_id | Past backlink summaries recorded for a domain, so link growth can be shown over time without a new lookup. |
| get_local_seo_audit_history | read | Inputs: domain_id, kind? | Saved local, citation and reputation audits for a domain — reopening one is free. |
| list_local_seo_reports | read | Inputs: domain_id | Saved profile-health, reviews, AI-visibility, competitor-gap and citation reports for a domain. Reopening is free; the catalog actions refresh them. |
| quote_local_seo_report | read | Inputs: domain_id, type, refresh? | Whether a report of this type is already saved (free to reopen) and what a refresh would cost. |
Accessibility review and export
scope: accessibilityThe human half of an audit: record the manual WCAG judgements, close the audit, export the evidence pack.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| record_accessibility_manual_review | write | Inputs: audit_id, wcag_criterion, status, notes?, evidence_reference? | Record the human judgement on one WCAG criterion the automated audit cannot decide. Only after the automated checks finish. |
| complete_accessibility_audit | write | Inputs: audit_id | Mark an audit complete once the manual reviews are recorded. It can then be exported. |
| export_accessibility_audit | read | Inputs: audit_id | The full audit as a JSON evidence pack: pages, findings, manual reviews, WCAG rollups. Automated results do not establish conformance; say so when handing it over. |
Providers and subscriptions
scope: statusWhich providers the site depends on and which the account is subscribed to.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| get_status_incidents | read | Inputs: — | Open incidents across every tracked provider right now. Read with get_status_services when a user reports an outage. |
| get_status_history | read | Inputs: limit?, offset? | Past status changes across tracked providers, newest first. |
| list_status_subscriptions | read | Inputs: — | Which third-party providers this account is subscribed to for status alerts, and at what level. |
| get_status_subscription_suggestions | read | Inputs: — | Providers the account's domains depend on (host, DNS, email, CDN), each with its name, role, domains and whether it is already followed. Offer the ones that are not, during onboarding. |
| update_status_subscriptions | write | Inputs: subscriptions | Subscribe or unsubscribe from providers. Each entry names a service_id from get_status_services and a notify_level: all, major, or none. |
| subscribe_all_status_services | write | Inputs: — | Subscribe to every provider the account's domains depend on, in one call. |
| unsubscribe_all_status_services | write | Inputs: — | Clear every provider subscription. Confirm first. |
| suggest_status_service | write | Inputs: status_page_url, service_name?, notes? | Ask for a provider status page to be added to the catalogue. Needs its https:// status page URL. |
Compliance seeding
scope: complianceSeed or bulk-update the control list.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| initialize_compliance_records | write | Inputs: items | Create compliance control records from a list of items (item_id, framework, category, requirement, optional status and notes). Existing records are kept. |
| bulk_update_compliance | write | Inputs: items | Set status and notes on many controls in one call, by item_id. Same status vocabulary as update_compliance_item, same rule: never write not_met for a control nobody assessed. |
Audit a domain in one call
scope: domains, scans, vulnscanaudit_domain reads every stored result for a domain and hands back a verdict, the problems ranked by real risk across every area, with the measured evidence, exactly where to fix each one (the record or header lines to paste) and who does it, and a plain list of what hasn't been measured yet. The same problem seen by two scanners or on five hosts is one finding. It starts no scan and spends nothing, and each part is held to the key's scopes. The other tools here read stored results that had no tool of their own before.
| Tool | Access | Inputs | What it returns |
|---|---|---|---|
| audit_domain | read | Inputs: domain_id, limit? | Verdict, findings ranked by risk with duplicates merged (evidence, where, the fix to paste, who fixes it), what was not measured, open setup steps and a markdown summary, across every category DomainGuard scans. |
| get_domain_certificates | read | Inputs: domain_id | Every TLS certificate the domain serves: the site, www, watched subdomains and TLS ports, with expiry, issuer, chain, protocols and each problem. |
| get_subdomain_sightings | read | Inputs: domain_id, since_days?, limit? | Every subdomain seen in certificate logs or DNS probes, with when it first appeared. Baseline hosts were already there when watching began. |
| get_domain_vuln_state | read | Inputs: domain_id | The domain's vulnerability verdict, affected hosts with product, version, top CVE and fix version, and every product read on every host. |
| get_exploited_software | read | Inputs: — | CISA Known Exploited Vulnerabilities matching software seen running on the account's hosts, with CISA's due date and required action. |
| list_on_demand_scans | read | Inputs: domain_id?, domain?, limit? | Saved quick and full scans from the app's Scan tab, with score, grade and counts. |
| run_on_demand_scan | write | Inputs: domain, mode? | Scan any public domain, monitored or not: quick (passive) or full (active probes and SEO, one an hour, verified domains only). Returns the finished report. |
| share_on_demand_scan | write | Inputs: scan_id | A public link to a finished scan to send an IT provider, with private file paths hidden from visitors. |
| unshare_on_demand_scan | write | Inputs: scan_id | Revoke a scan's public link. |
| delete_on_demand_scan | destructive | Inputs: scan_id | Remove a finished scan from the history and revoke its link. |
| get_on_demand_scan | read | Inputs: scan_id | One saved on-demand scan with its whole report. |
| get_verification_summary | read | Inputs: days? | What agents have verified on this account: confirmed, incorrect and could-not-verify counts, the agents, and disputed findings. |
The Local SEO catalog
The local-search tools cover setup and measurement directly. Behind run_local_seo_action sit another 33 catalogued actions, and get_local_seo_catalog is the authority on all of them: exact required inputs, prerequisites, price basis, and whether a saved result can be reopened for free. Call it before running an action rather than assuming a shape — the catalog is the contract, and it can gain entries between deploys of this page.
# The shape of a catalogued run
run_local_seo_action {
action_id: "competitor_gap", // from get_local_seo_catalog
request_key: "dg-compgap-20260829-x1", // fresh, 8-100 chars [A-Za-z0-9._-]
input: { domain_id: 12 } // exactly the catalog's fields
}| Area | Action ids |
|---|---|
| Profile and reputation | profile_health · business_profile · reviews · review_velocity · multi_platform_reviews · reputation_audit |
| Rankings and maps | rank_check · geogrid · serp_local_finder · serp_maps |
| Keyword research | keyword_search_volume · keyword_opportunities · keywords_for_site · keywords_related · keyword_trends |
| AI search visibility | ai_visibility · serp_ai_mode · ai_mentions · ai_top_pages · ai_top_sources · ai_compare · ai_keyword_data · ai_llm_response · ai_scraper |
| Authority and links | backlinks_summary · backlinks_gap · local_authority · brand_mentions |
| Competition | competitor_gap · brand_mentions |
| Audits | local_audit · citation_audit · citations · page_audit |
Some actions cache: reopening a saved result is free and refreshing buys a new one. The catalog says which, per action. Prefer the saved result unless the question genuinely needs current data.
rank_check deserves a note
check_local_ranks is the quick path and measures the local pack only. The catalogued action measures more and is priced accordingly: two credits a phrase on the local pack and four on organic. surfaces chooses where to measure, and keywords narrows the run; omit it and every saved phrase is checked, so twenty tracked phrases across both surfaces is forty credits. Quote it first, and narrow the list when the user asked about one phrase.
run_local_seo_action {
action_id: "rank_check",
request_key: "dg-ranks-20260829-b2",
input: {
domain_id: 12,
surfaces: ["local_pack", "organic"], // both, or just one
keywords: ["emergency plumber akron"] // omit to check every saved phrase
}
}When something goes wrong
A tool that fails comes back as an ordinary result carrying isError and a readable reason, not as a protocol error — so an assistant can read why and adapt instead of ending the turn. Only transport-level problems return a non-200 status.
| What you see | What it means | What to do |
|---|---|---|
| 401 | Key missing, malformed, revoked, expired, or the plan does not include API access. | Check Settings, API Keys, and the plan. Do not retry. |
| 401 “requires a DomainGuard API key” | A dashboard session token was sent instead of a key. | MCP takes an nhm_ key only. Sessions are refused so a stolen browser token cannot drive it. |
| 403 Forbidden origin | The Origin header failed validation. | A client configuration problem, not a credential problem. |
| 405 on an authenticated GET | Correct. There is no SSE stream to open. An unauthenticated GET answers 401 first, because the key is checked before the method. | Use POST. |
| 429 | The key's hourly rate limit, or a per-plan manual-scan limit. | Wait. Free plans allow one manual SEO scan per day. |
| isError: “missing the … scope” | The key does not carry that resource scope. | Mint a key with the scope. Retrying will not help. |
| isError: “read-only” | The tool changes state and the key has no write scope. | Use the read equivalent, or upgrade to Enterprise. |
| 409 idempotency_mismatch | That request_key was already used for a different request. | Generate a fresh key for a genuinely new run. |
| Timeout on a paid action | Whether it ran is unknown. | Call get_local_seo_operation with the same request_key. Never re-run blind. |
| A scan returns with no findings | It is asynchronous and still running. | Poll the matching results tool. |
| 403 domain_verification_required or “requires ownership verification” | A deep scan of a domain the account has not verified. Basic scans need no proof. | request_ownership_email_link is the easiest proof; or get_scan_ownership_verification, publish, then verify_scan_ownership. |
| 402 plan_upgrade_required | The feature is not on the account's plan. | Say which plan has it. Do not retry. |
| 403 on report_scanner_issue or submit_verification_results | Reports and verdicts are accepted only from the account's own API keys (Pro or Enterprise), carrying scans or domains respectively. | Carry on without reporting. |
| 400 location_not_found | The city is not in the rank-data gazetteer as written. | Offer the suggestions in the response, or search_locations, then call again. |
Protocol notes
One endpoint
POST /api/mcp, speaking JSON-RPC 2.0. GET answers 405 with Allow: POST — there is no event stream to open, and saying so is more honest than holding one open with nothing to send.
Both protocol eras
The stateless 2026-07-28 revision and the handshake revisions 2025-11-25, 2025-06-18, and 2025-03-26 are all served, from the same code path. Holding no session state is what makes supporting both cheap.
Methods
initialize, server/discover, tools/list, tools/call, prompts/list, prompts/get, resources/list, resources/read, resources/templates/list (empty) and ping. prompts/list returns the nine prompts and resources/list the six resources above.
No sessions
No Mcp-Session-Id, nothing remembered between calls. Each request stands alone and carries its own authentication.
No batching
JSON-RPC batching was removed from the spec in the 2025-06-18 revision and is rejected here. Notifications receive 202 with no body.
Cacheable tool lists
tools/list results are marked private and scope-dependent. A shared intermediary must never serve one key's tool list to another.
Give this to Claude
Everything on this page is also published as one plain-text file written for an assistant to read. Point Claude at the URL, or paste the block below into your project's CLAUDE.md so every session starts knowing the rules instead of discovering them by spending credits.
The full operating guide
https://nhmohio.com/mcp/claude-guide.md# Paste into CLAUDE.md
## DomainGuard MCP
The `domainguard` MCP server is connected. It reaches every part of the
account: DNS, SSL, mail authentication and DMARC reports, security checkups,
Hijack Guard, lookalikes, vulnerabilities and ports, software CVE/KEV alerts,
dark web, on-page and site-wide SEO, accessibility, local rankings and the
Google Business Profile, provider status, compliance and incident records.
Rules:
- Start with `list_domains`; every other tool needs the numeric `domain_id`.
- Read stored results (`get_checkup_history`, `get_seo_results`,
`get_vuln_scan_latest`, `get_local_rank_history`, `get_domain_setup_guide`)
before running any scan.
- To add or set up a domain: `plan_domain_onboarding` first, ask its questions
in plain words, then `onboard_domain` once. It spends nothing. Paid steps
(`run_local_seo_quickstart`, `start_accessibility_audit`) come after, on a
quote the user agreed to.
- Verify, then report back: `get_verification_tasks` gives each claim with
how it was tested and read-only commands to re-test it. Run them on the
account's own domains only, then send every verdict (confirmations too) with
`submit_verification_results`. Other mistakes: `report_scanner_issue`,
then `submit_scanner_review` once per domain. Never log in, fuzz or exploit.
- `run_*`, `start_*`, `check_*`, `verify_*`, `scan_*`, `fetch_*`,
`discover_*` and `assess_*` cost time or credits. So do
`get_domain_email_security` and `get_scan_ownership_verification`. Say the
cost before spending.
- Call `get_local_seo_catalog` before `run_local_seo_action`; it is the
authority on inputs and price.
- Every paid action needs a fresh `request_key` (8-100 chars, [A-Za-z0-9._-]).
After a timeout use `get_local_seo_operation`, never a re-run.
- `start_vuln_scan`, `start_site_audit`, `start_deep_seo_job` and
`start_accessibility_audit` are asynchronous — poll their results tools.
- Confirm every `delete_*`, `remove_*`, `untrack_*` and `unsubscribe_*` in
words before calling it.
- DomainGuard monitors these domains, it does not host them. Deliver the
diagnosis plus the exact change, and say where the user applies it —
registrar, DNS provider, host, CMS, or Google Business Profile.
- Never estimate a score, position, volume, or price that a tool did not
return; never invent a business name, city, phrase or email address.
Full guide: https://nhmohio.com/mcp/claude-guide.md (also the MCP resource domainguard://guide).
Prompts: /mcp__domainguard__audit_domain, onboard_domain, set_up_local_seo,
review_domain, portfolio_triage, fix_email_deliverability.How access is limited
Your account only
Every tool runs through the same ownership checks as the dashboard. A key reaches the domains on its own account and nothing else.
Scopes decide the tool list
Tools outside a key's scopes are never offered and cannot be called. Mint one key per use and give each only what it needs.
Read-only means read-only
Without the write scope, an assistant cannot start live lookups or scans, spend credits, or change configuration. Write is a separate tick box, and only on Enterprise.
Keys cannot mint keys
An API key is refused at the key-management endpoints, so a narrow key handed to an agent can never issue itself a broader one. That stays a dashboard action.
Sessions are refused
The MCP endpoint takes an API key and nothing else. A browser token obtained through XSS cannot drive it.
Revocable and rate limited
Revoke a key and it stops working immediately. Each key carries its own hourly limit, and you can set an expiry date when you create it.
Point Claude at your domains
Pro reads your account. Enterprise reads it and acts on it. Both take about a minute to set up.
