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
17695 read, 81 write
Local SEO actions
39, catalogued
Sessions
None — stateless

Setting it up

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 report. Give each key an expiry if you have a date in mind.

2. Add the server

# Claude Code

claude mcp add --transport http domainguard https://nhmohio.com/api/mcp \ --header "Authorization: Bearer nhm_your_key_here"

# Claude Desktop, or any client taking a JSON config

{ "mcpServers": { "domainguard": { "type": "http", "url": "https://nhmohio.com/api/mcp", "headers": { "Authorization": "Bearer nhm_your_key_here" } } } }

Any MCP client that supports a remote server over HTTP with a custom header works the same way. There is no OAuth flow to complete and no event stream to open.

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."

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. 95 tools.

Everything that reads stored data, across every scope you grant.

Enterprise

Read and write. All 176 customer tools.

Adds the write scope: start scans, spend credits, change saved data.

ScopeWhat it unlocks
domainsInventory, history, DNS and registrar events, uptime, DMARC reporting
scansDomain scans, security checkups, dark-web monitoring
seoOn-page SEO, whole-site audits, and the entire Local SEO suite
accessibilityAudit-grade WCAG 2.2 AA evaluations
vulnscanVulnerability scans, ports, components, ownership verification
compliancePCI, HIPAA, and cyber-insurance control records
statusThird-party service status
writeRequired 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 clears the whole account for active 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 — two credits a phrase plus two. 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.

Claude checks our work

A scanner is a set of claims about the live world, and an assistant reading them can test many of those claims itself: resolve the DMARC record and compare it with what we quoted, fetch the page and read the headers, count the scripts. The server tells every connected assistant to do exactly that before it presents a finding as fact.

When what it verified disagrees with what we said — a false positive, a real problem we missed, a count or a record we got wrong, a check that errored — it files the difference with report_scanner_issue: what we reported, what is true, how it knows, what to change. The reports for one domain collect into a review, and submit_scanner_review sends us one message. That message goes to a person, and the fix comes back as a code change with a test.

The channel is deliberately narrow: Enterprise accounts, only from the account's own API keys (a dashboard session cannot file one), thirty reports a day, ten per domain, one message per review, repeats folded. Reporting never softens what you are told — Claude says what we said and what it found.

Prompts and resources the server carries

onboard_domain
the interview, start to finish
set_up_local_seo
profile, phrases, quote, first measurement
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

Resources: domainguard://guide, domainguard://onboarding, domainguard://local-seo, domainguard://review — 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

1

Start with list_domains

Almost every tool takes a numeric domain_id, and that is where the ids come from. Never guess one.

2

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.

3

Verify, then report

Before presenting a DNS, header, certificate or count finding, check it. When the scanner is wrong, report_scanner_issue says what it said, what is true and how you know; submit_scanner_review sends one message per domain.

4

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.

5

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.

6

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.

7

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.

8

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.

9

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.

10

Confirm deletions in words

delete_domain erases a domain's whole history and cannot be undone. Name the exact thing and get a yes.

11

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.

12

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?
  ├─ get_checkup_history     → what is broken, with severity
  └─ get_seo_results         → titles, descriptions, headings, violations
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 moved

Read 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 findings

Cluster 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 reviews

How 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 changes

Take 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 attribution

Read 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.

get_checkup_history                 → stored and free; start here
run_domain_checkup { domain }       → live. Your own domain gets the full
                                      check; any other hostname gets only
                                      the passive checks
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 proof

Ownership 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 180 tools: 99 that read stored data and 81 that change something, run a live lookup, or spend credits. 4 of the reads are operator-only, so a customer key can be offered at most 176. 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: domains

The 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.

ToolAccessInputsWhat it returns
list_domainsreaddetail?Every domain on the account, one compact row each: health score, last scan and scan state, SSL and registration expiry, SEO score, paused checks. detail: true returns the full stored scans. Start here.
get_domain_historyreaddomain_idRecorded results for one domain over time — when something regressed and by how much.
get_dns_change_eventsreadDNS changes across the account, so a new change can be told apart from a long-standing finding.
get_domain_eventsreadHijack Guard events with severity and lifecycle: DNS, registrar, certificate, and hosting changes.
get_uptime_snapshotsreadRecent uptime probe observations across the portfolio.
get_downtime_eventsreadRecorded outage windows and whether they recovered.
get_dmarc_summaryreaddomainThirty-day aggregate report volume and alignment rate for one monitored domain.
get_dmarc_diagnosticsreaddomainRanked deliverability diagnostics joining DNS, reports, and sender attribution.
get_dmarc_setup_statusreaddomainThe authoritative SPF, DKIM, DMARC, report-arrival, and inbox-routing checklist.
add_domainwritedomainStart monitoring a new domain. Returns 403 once the plan's domain limit is reached.
update_domainwritedomain_id, domain_group?, notes?, ignore_mail?, ignore_autoscan?Change one domain's group, notes, or which checks it skips. Only the fields passed are changed.
delete_domaindestructivedomain_idPermanently removes the domain and its entire scan history. Re-adding does not recover it.
get_domain_email_securitywritedomain_idFresh SPF, DKIM, DMARC, MX, MTA-STS, and TLS-RPT evidence. Performs live DNS lookups, so it counts as a write.
discover_domain_subdomainswritedomain_idPassive subdomain discovery from certificate transparency and DNS. Does not probe the hosts it finds.

Scans, checkups, and dark web

scope: scans

Security checkups and breach monitoring. The stored history is almost always enough — reach for a live run only when something has just changed.

ToolAccessInputsWhat it returns
get_checkup_historyreaddomain_idPast security checkups with every individual finding and its severity. The richest single answer to “what is wrong with this site”.
get_dark_web_statusreadCached breach-monitoring results for the account, with no upstream lookup.
run_domain_scanwritedomain_idDomain 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_checkupwritedomainA live checkup. On your own domain this includes the exposed-file probe; on any other hostname only the passive checks run.
run_dark_web_scanwriteRefresh every monitored email address against the breach index. Spends the manual-scan allowance.

SEO — one page and the whole site

scope: seo

What 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.

ToolAccessInputsWhat it returns
get_seo_resultsreaddomain_idThe latest SEO and accessibility scan: page titles, meta descriptions, heading structure, and violations.
get_seo_historyreaddomain_idSEO scores over time, so a change can be shown to have moved the number.
get_site_audit_statusreadaudit_idProgress of a whole-site crawl.
get_site_audit_resultsreadaudit_idPage-level findings from a whole-site crawl.
get_seo_intent_conflictsreaddomain_idWhich pages compete for one search, with the page to keep and the steps for the other. Read from the newest crawl; free.
run_seo_scanwritedomain_idRe-score a site after publishing changes. Free accounts get one manual scan a day; a second returns 429.
start_site_auditwritedomain_id, max_pages?Crawl the sitemap or same-site links and check every discovered page. Returns an audit id immediately.

Local SEO — rankings, maps, reviews, competitors

scope: seo

The 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.

ToolAccessInputsWhat it returns
get_local_seo_profilereaddomain_idThe saved business profile: name, location, service radius, and targeting mode.
get_local_keyword_targetsreaddomain_idThe phrases currently tracked for this domain.
get_local_rank_historyreaddomain_idRecorded positions for each tracked phrase on each past check.
get_geogrid_scansreaddomain_idPast map-grid scans showing where across the service area rankings hold and where they fall away.
get_local_seo_catalogreadAll 33 catalogued actions with their exact inputs, prerequisites, price basis, and caching rules. Call this before running one.
get_local_seo_operationreadrequest_keyRecover a paid action after a timeout instead of paying for it twice.
get_local_seo_creditsreadRemaining rank-check and map-scan credits on the account.
save_local_seo_profilewritedomain_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_targetwritedomain_id, keyword, targeting?Track a phrase. Up to 25 per domain; adding the same phrase twice does nothing.
delete_local_keyword_targetdestructivekeyword_idStop tracking a phrase. The rank history already recorded is kept.
check_local_rankswritedomain_id, request_keyLive positions for every tracked phrase, measuring the local pack. Costs one credit per phrase per surface.
run_geogrid_scanwritedomain_id, keyword, grid_size?, request_keyCheck one phrase from many points across the service area on a 5×5, 7×7, or 9×9 grid.
run_local_seo_actionwriteaction_id, request_key, inputRun any action from the catalog — reviews, citations, keyword research, competitor gap, backlinks, AI visibility, full audits.

Accessibility

scope: accessibility

Audit-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.

ToolAccessInputsWhat it returns
quote_accessibility_auditreaddomain_idCost, available credits, page cap, and whether an audit can start right now.
list_accessibility_auditsreaddomain_id?, limit?Recent evaluations, optionally narrowed to one domain.
get_accessibility_auditreadaudit_idPages, axe findings, WCAG rollups, manual-review coverage, and regression data for one audit.
start_accessibility_auditwritedomain_id, request_key, max_pages?, viewport?Queue a browser evaluation. Spends accessibility credits, so the request key matters.

Vulnerability and exposure

scope: vulnscan

Active scanning needs proof that the account controls the domain. Get the challenge, publish it, verify it, then scan.

ToolAccessInputsWhat it returns
get_vuln_scan_latestreaddomain_idThe most recent completed scan with its findings and severities.
get_vuln_scan_resultsreadscan_idFindings for one scan by id. This is how you poll a scan you just started.
get_vuln_scan_historyreaddomain_idThe last twenty scans with status, profile, timing, and severity summary.
get_vulnerability_assetsreaddomain_idEvery public hostname discovered for a domain and the finding counts attached to each.
get_open_portsreaddomain_idPer-host port, service, banner, version, and risk observations.
list_lookalikesreaddomain_idDomains 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_eventsreaddomain_idWhat changed about those impostors over time: one appearing, one gaining the ability to receive email, one becoming more dangerous.
run_lookalike_scanwritedomain_idGenerate 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_verdictwritedomain_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_componentsreadThe portfolio's technology inventory with version confidence where a version was actually observed.
get_scan_ownership_verificationwritedomain_idReturn the DNS, file, or email proof required before active scanning, creating a challenge if none exists.
verify_scan_ownershipwritedomain_idRe-check the published proof and record verification when it is found.
start_vuln_scanwritedomain_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: compliance

PCI, HIPAA, and cyber-insurance controls. These records are audit evidence — notes should quote the account owner's own wording rather than paraphrase it.

ToolAccessInputsWhat it returns
get_compliance_recordsreadThe compliance checklist with each control's current status and notes.
update_compliance_itemwriterecord_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.

Uptime and dependencies

scope: status

The live status of third-party providers — the fastest way to separate a problem with your site from an incident at your host.

ToolAccessInputsWhat it returns
get_status_servicesreadCurrent status of the third-party providers this account tracks.

Alerts

scope: domains

The account's alert feed. Alerts are read through the domain tools; this is the one write against them.

ToolAccessInputsWhat it returns
mark_alerts_readwriteids (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: scans

The 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.

ToolAccessInputsWhat it returns
report_scanner_issuewritedomain_id, category, title, detailOne thing the scanner got wrong: what it said, what is true, how you know, what to change. Collects into a review of that domain.
submit_scanner_reviewwritedomain_idClose the review and send it to the operators as one message. Call it once per domain, when you are done.

Operator reads (administrator only)

scope: admin

What 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 four reads.

ToolAccessInputsWhat it returns
list_error_eventsreaddays, 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_statusreadEvery self-check invariant's last verdict, failing first, and when each cron scope last completed a pass.
list_scan_failuresreaddays (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_reportsreaddays, status (optional)What customers' assistants reported wrong with the scanner, open ones first — the claim, the evidence, the suggested fix, who sent it.

Guided onboarding and setup

scope: domains

The 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.

ToolAccessInputsWhat it returns
plan_domain_onboardingreaddomain?Call this FIRST whenever the user wants to add or set up a domain.
onboard_domainwritedomain, 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_guidereaddomain_idThe 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_stepwritedomain_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_bulkwritedomainsAdd up to 100 domains in one call. Returns which were added and which were skipped (already here, invalid).

Account: alerts, settings, groups, clients

scope: domains

The account-wide plumbing: the alert feed and history, alert and scan settings, group labels, and the client records a consultancy files domains under.

ToolAccessInputsWhat it returns
list_alertsreadlimit?, 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_activityreadlimit?, 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_settingsreadThe 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_settingswritescan_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_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_groupsreadThe group labels used to organise the portfolio (clients, brands, regions) with how many domains sit in each.
create_domain_groupwritenameCreate an empty group label. Assigning domains to it is assign_domains_to_group; update_domain also takes a group name.
delete_domain_groupdestructivegroup_idRemove a group label. The domains in it are kept and become ungrouped.
assign_domains_to_groupwritedomain_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_clientsreadClients are the optional grouping a consultancy uses to hold domains and network targets per customer. Returns each with its id.
create_scan_clientwritenameCreate a client record to assign domains and IP targets to. Names are unique per account.
delete_scan_clientdestructiveclient_idRemove a client record. Domains and targets assigned to it are kept, unassigned.
list_support_conversationsreadThe account's support threads with NHM, newest first, with status.
get_support_conversationreadconversation_idOne support thread in full, including replies from NHM.
reply_to_support_conversationwriteconversation_id, messageAdd the user's message to an existing support thread. Opening a new thread needs the dashboard; say so if there is none.
update_support_conversationwriteconversation_id, status?, archived?Set a thread's status to open or closed, or archive/unarchive it.

Hijack Guard: change events

scope: domains

DNS, 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.

ToolAccessInputsWhat it returns
get_domain_hijack_eventsreaddomain_idHijack 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_eventreadevent_idOne Hijack Guard event in full: what changed, from what to what, when, and what has been done about it.
act_on_domain_eventwriteevent_id, actionMove 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: domains

The 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.

ToolAccessInputsWhat it returns
list_dmarc_reportsreaddomain?, 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_sendersreaddomain, 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_inboxreadThe 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_inboxwriteIssue 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_authreadWhich domains have delegated their DMARC or SPF record to DomainGuard to publish and maintain, and whether the delegation is live.
enable_managed_email_authwritedomain, 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_authwritedomain, serviceEnd a delegation. The user must publish their own record again or the domain will have none.
check_managed_email_authwritedomainLook 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_policywritedomain, actionFor 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: vulnscan

Active scanning needs one proven domain per account. The email link is the easiest proof; the operator queue covers a client's domain the account cannot prove.

ToolAccessInputsWhat it returns
get_scan_clearance_statusreadAccount-wide view of ownership proof: how many domains carry a current proof and which.
verify_scan_ownership_bulkwritedomain_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_linkwritedomain_id, addressThe 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 the whole account is cleared for active scanning for 90 days.
request_scan_authorizationwritedomain_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_authorizationreaddomain_idThe latest operator authorisation for one domain and whether it is currently active.
list_scan_authorizationsreadlimit?, offset?Every authorisation request the account has filed, newest first, with its status.

Lookalike controls

scope: vulnscan

Turning the watch on and off, the evidence pack for a filing, and how lookalike alerts are delivered.

ToolAccessInputsWhat it returns
set_lookalike_watchwritedomain_id, enabledContinuous impostor-domain monitoring for one domain. Turning it on needs the plan capability; turning it off is always allowed.
get_lookalike_evidencereaddomain_id, lookalikeEverything recorded about one lookalike domain — registration, DNS, mail capability, certificates, timeline — assembled for a registrar abuse report or a takedown filing.
act_on_lookalike_eventwriteevent_id, actionMark one lookalike change event as seen (acknowledge) or dealt with (resolve). Event ids come from get_lookalike_events.
get_lookalike_alert_settingsreadWhether 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_settingswritepushTurn 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: vulnscan

What 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.

ToolAccessInputsWhat it returns
list_vuln_dismissalsreadkind?Findings, inventory readings and software alerts the account has permanently silenced, with the reason given.
dismiss_vuln_findingwritekind, 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_dismissalwritedismissal_idRemove a dismissal so the finding, component or alert is reported again. Use the id from list_vuln_dismissals.
list_software_vendorsreadThe observed technology inventory rolled up by company: every vendor seen across the account's domains with component counts and open advisories.
get_software_vendorreadvendorEvery component, version and domain observed for one vendor, with its advisories. vendor is the lowercase slug from list_software_vendors.
get_vulnerability_feedreadThe 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_historyreadproduct, 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".
list_tracked_softwarereadThe software products the account watches for new vulnerabilities, with alert preferences and open alert counts.
search_software_catalogreadq?, category?Find a product to track by name or category. Returns slugs to pass to track_software.
get_software_catalogreadEvery product in the catalog. Large; prefer search_software_catalog.
get_software_catalog_categoriesreadThe categories the software catalog is organised by.
track_softwarewriteapp_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_softwarewriteapp_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_softwaredestructiveapp_idRemove a tracked product and its alerts. Confirm the product name first.
list_software_alertsreadstatus?, 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_summaryreadCounts of unread, critical, KEV and confirmed-exposure software alerts, per tracked product and in total.
update_software_alertwritealert_id, alert_statusSet the status of one software alert. remediated records that the fix was applied; dismissed means it will not be.

IP and network targets

scope: vulnscan

Daily port scans of public IPs and small ranges the account owns or is authorised to test. Adding one records the attestation.

ToolAccessInputsWhat it returns
list_ip_targetsreadThe IP addresses and CIDR ranges the account port-scans daily, with their client and last result.
add_ip_targetwritetarget, 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_targetwritetarget_id, client_id?, daily_scan?Move a target to another client or turn its daily scan on or off.
delete_ip_targetdestructivetarget_idStop scanning a target and remove it with its history. Confirm first.
list_ip_target_scansreadtarget_idPast port scans of one target with the open ports and services seen each time.
scan_ip_targetwritetarget_idRun the port scan of one target immediately instead of waiting for the daily run. Sends traffic to the target.

Dark web: addresses

scope: scans

Which addresses are watched in breach data, and one breach in detail. New hits land in the alert feed and are pushed to the app.

ToolAccessInputsWhat it returns
get_dark_web_breachreadbreachDetails of one breach that a monitored address appeared in: what was exposed, when, and which monitored addresses it touched.
add_dark_web_emailwriteemail, 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_emaildestructiveemail_hashRemove one monitored address by its hash, as get_dark_web_status lists it.

Deep crawls, single-URL scoring, reports

scope: seo

Crawl chosen pages rather than the whole site, score any public URL on demand, and send the branded report.

ToolAccessInputsWhat it returns
get_seo_policyreadThe account's SEO allowances: manual scans per day, crawl page caps, whether deep crawls and reports are on the plan.
list_manual_url_scansreadPast one-off SEO scans of individual URLs saved on the account.
fetch_sitemapwritedomainRead 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_jobwritedomain_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_jobsreadEvery queued, running and finished deep crawl on the account with progress.
get_deep_seo_jobreadjob_idProgress and status of one crawl job by id.
cancel_deep_seo_jobwritejob_idStop a queued or running crawl. Pages already scored are kept.
get_deep_seo_scansreaddomain_idThe 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_pagesreadscan_idEvery page in one deep crawl with its title, description, headings, score and defects.
check_page_seowriteurlFetch any public page and return its on-page SEO checks: title, description, headings, images, links, canonical. Works on any URL, not only monitored domains.
assess_websitewriteurlA quick combined read of any public URL: performance, accessibility and SEO signals in one result. A live fetch.
score_page_accessibilitywriteurlA quick static accessibility score of any public page. Not audit grade — start_accessibility_audit is.
score_page_performancewriteurlA quick performance read of any public page: weight, requests, render-blocking resources. A live fetch.
email_seo_reportwritedomain_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_brandingreadThe white-label branding applied to emailed reports (company name, logo, accent colour, footer) and whether the plan allows changing it.
save_report_brandingwritecompany_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: seo

The 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.

ToolAccessInputsWhat it returns
get_local_seo_quickstartreaddomain_idOne 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_quickstartwritedomain_id, business_name, location, keywords, request_keyThe 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.
discover_local_seo_detailswritedomain_idRead 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_locationwritedomain_id, locationCheck a "City, ST" against the rank-data gazetteer before saving it, and get the resolved name or close matches. Free.
get_local_seo_accessreadSays whether this account can use the Local SEO suite and on which plan. Check it before promising a rank check.
quote_local_ranksreaddomain_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_scanreaddomain_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_entitlementreaddomain_idFree map scans remaining this period for a domain, and what more would cost.
quote_local_seo_endpointreaddomain_id, endpointThe credit cost of one catalogued endpoint for a domain before running it. get_local_seo_catalog gives the price basis; this gives the number.
search_locationsreadq, state?, country?, limit?Find the exact "City, ST" the rank data covers, from a partial name. Use it when verify_local_seo_location or the quick start says the city was not found.
list_covered_locationsreadprefix?, state?, country?, limit?, offset?Page through the cities the rank data covers, optionally by state or name prefix.
get_local_keyword_ideasreaddomain_id, limit?Phrase ideas already gathered for a domain by earlier keyword research, without spending anything.
get_backlink_snapshotsreaddomain_idPast backlink summaries recorded for a domain, so link growth can be shown over time without a new lookup.
get_local_seo_audit_historyreaddomain_id, kind?Saved local, citation and reputation audits for a domain — reopening one is free.
list_local_seo_reportsreaddomain_idSaved profile-health, reviews, AI-visibility, competitor-gap and citation reports for a domain. Reopening is free; the catalog actions refresh them.
quote_local_seo_reportreaddomain_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: accessibility

The human half of an audit: record the manual WCAG judgements, close the audit, export the evidence pack.

ToolAccessInputsWhat it returns
record_accessibility_manual_reviewwriteaudit_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_auditwriteaudit_idMark an audit complete once the manual reviews are recorded. It can then be exported.
export_accessibility_auditreadaudit_idThe 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: status

Which providers the site depends on and which the account is subscribed to.

ToolAccessInputsWhat it returns
get_status_incidentsreadOpen incidents across every tracked provider right now. Read with get_status_services when a user reports an outage.
get_status_historyreadlimit?, offset?Past status changes across tracked providers, newest first.
list_status_subscriptionsreadWhich third-party providers this account is subscribed to for status alerts, and at what level.
get_status_subscription_suggestionsreadProviders the account's domains were observed depending on (host, DNS, email, CDN) but is not yet subscribed to. Offer these during onboarding.
update_status_subscriptionswritesubscriptionsSubscribe 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_serviceswriteSubscribe to every provider the account's domains depend on, in one call.
unsubscribe_all_status_serviceswriteClear every provider subscription. Confirm first.
suggest_status_servicewritestatus_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: compliance

Seed or bulk-update the control list.

ToolAccessInputsWhat it returns
initialize_compliance_recordswriteitemsCreate compliance control records from a list of items (item_id, framework, category, requirement, optional status and notes). Existing records are kept.
bulk_update_compliancewriteitemsSet 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.

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 }
AreaAction ids
Profile and reputationprofile_health · business_profile · reviews · review_velocity · multi_platform_reviews · reputation_audit
Rankings and mapsrank_check · geogrid · serp_local_finder · serp_maps
Keyword researchkeyword_search_volume · keyword_opportunities · keywords_for_site · keywords_related · keyword_trends
AI search visibilityai_visibility · serp_ai_mode · ai_mentions · ai_top_pages · ai_top_sources · ai_compare · ai_keyword_data · ai_llm_response · ai_scraper
Authority and linksbacklinks_summary · backlinks_gap · local_authority · brand_mentions
Competitioncompetitor_gap · brand_mentions
Auditslocal_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 — one credit per phrase per surface. 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 seeWhat it meansWhat to do
401Key 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 originThe Origin header failed validation.A client configuration problem, not a credential problem.
405 on an authenticated GETCorrect. There is no SSE stream to open. An unauthenticated GET answers 401 first, because the key is checked before the method.Use POST.
429The 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_mismatchThat request_key was already used for a different request.Generate a fresh key for a genuinely new run.
Timeout on a paid actionWhether it ran is unknown.Call get_local_seo_operation with the same request_key. Never re-run blind.
A scan returns with no findingsIt is asynchronous and still running.Poll the matching results tool.
“requires ownership verification”Active scanning needs one proven domain on the account.request_ownership_email_link is the easiest proof; or get_scan_ownership_verification, publish, then verify_scan_ownership.
402 plan_upgrade_requiredThe feature is not on the account's plan.Say which plan has it. Do not retry.
403 on report_scanner_issueReports are accepted only from the account's own API keys carrying scans and write, on Enterprise.Carry on without reporting.
400 location_not_foundThe 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 five prompts and resources/list the four resources below.

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
Open the guide

# 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 what you can before presenting it (resolve the record, fetch the headers, count the tags). When the scanner is wrong, `report_scanner_issue` with what it said, what is true, how you know, what to change; then `submit_scanner_review` once per domain. Report only what you verified. - `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__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.