Pro and Enterprise
DomainGuard MCP server
One endpoint that hands Claude your monitoring data and lets it act on it: what is broken across your domains, what is holding a page back in search, where you rank on a map, and what to change. This page is the complete reference plus the playbooks Claude should follow.
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
- 64 — 37 read, 27 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. 35 tools.
Everything that reads stored data, across every scope you grant.
Enterprise
Read and write. All 64 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 | Custom endpoint checks and third-party service status |
| write | Required on top of any of the above for anything that changes state |
How to use it well
Sixty 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.
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? ├─ 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 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_suggestions → expand a seed phrase
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
Four 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 business_listings → the shape of the local field run_local_seo_action competitor_ads → what they pay to say 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_overview → does the search trigger an AI
Overview, and what does it cite
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 phraseThe 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 business_qa → public questions, often unanswered 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 and unanswered public questions are both visible to searchers and both 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.
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 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 64 tools: 37 that read stored data and 27 that change something, run a live lookup, or spend credits. 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 | — | Every domain on the account with its health score, last scan time, and SSL expiry. Start here. |
| get_domain_history | read | domain_id | Recorded results for one domain over time — when something regressed and by how much. |
| get_dns_change_events | read | — | DNS changes across the account, so a new change can be told apart from a long-standing finding. |
| get_domain_events | read | — | Hijack Guard events with severity and lifecycle: DNS, registrar, certificate, and hosting changes. |
| get_uptime_snapshots | read | — | Recent uptime probe observations across the portfolio. |
| get_downtime_events | read | — | Recorded outage windows and whether they recovered. |
| get_dmarc_summary | read | domain | Thirty-day aggregate report volume and alignment rate for one monitored domain. |
| get_dmarc_diagnostics | read | domain | Ranked deliverability diagnostics joining DNS, reports, and sender attribution. |
| get_dmarc_setup_status | read | domain | The authoritative SPF, DKIM, DMARC, report-arrival, and inbox-routing checklist. |
| add_domain | write | domain | Start monitoring a new domain. Returns 403 once the plan's domain limit is reached. |
| update_domain | write | domain_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_domain | destructive | domain_id | Permanently removes the domain and its entire scan history. Re-adding does not recover it. |
| get_domain_email_security | write | 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 | 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 | domain_id | Past security checkups with every individual finding and its severity. The richest single answer to “what is wrong with this site”. |
| get_dark_web_status | read | — | Cached breach-monitoring results for the account, with no upstream lookup. |
| list_dark_web_domain_monitors | read | — | Verified whole-domain breach monitors and their latest scan state. |
| run_domain_scan | write | 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 | domain | A live checkup. On your own domain this includes the exposed-file probe; on any other hostname only the passive checks run. |
| run_dark_web_scan | write | — | Refresh every monitored email address against the breach index. Spends the manual-scan allowance. |
| run_dark_web_domain_scan | write | — | Refresh every verified whole-domain breach monitor. |
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 | domain_id | The latest SEO and accessibility scan: page titles, meta descriptions, heading structure, and violations. |
| get_seo_history | read | domain_id | SEO scores over time, so a change can be shown to have moved the number. |
| get_site_audit_status | read | audit_id | Progress of a whole-site crawl. |
| get_site_audit_results | read | audit_id | Page-level findings from a whole-site crawl. |
| run_seo_scan | write | 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 | domain_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: 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 | domain_id | The saved business profile: name, location, service radius, and targeting mode. |
| get_local_keyword_targets | read | domain_id | The phrases currently tracked for this domain. |
| get_local_rank_history | read | domain_id | Recorded positions for each tracked phrase on each past check. |
| get_geogrid_scans | read | domain_id | Past map-grid scans showing where across the service area rankings hold and where they fall away. |
| get_local_seo_catalog | read | — | All 39 catalogued actions with their exact inputs, prerequisites, price basis, and caching rules. Call this before running one. |
| get_local_seo_operation | read | request_key | Recover a paid action after a timeout instead of paying for it twice. |
| get_local_seo_credits | read | — | Remaining rank-check and map-scan credits on the account. |
| save_local_seo_profile | write | 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 | domain_id, keyword, targeting? | Track a phrase. Up to 25 per domain; adding the same phrase twice does nothing. |
| delete_local_keyword_target | destructive | keyword_id | Stop tracking a phrase. The rank history already recorded is kept. |
| check_local_ranks | write | domain_id, request_key | Live positions for every tracked phrase, measuring the local pack. Costs one credit per phrase per surface. |
| run_geogrid_scan | write | 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 | 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 | domain_id | Cost, available credits, page cap, and whether an audit can start right now. |
| list_accessibility_audits | read | domain_id?, limit? | Recent evaluations, optionally narrowed to one domain. |
| get_accessibility_audit | read | audit_id | Pages, axe findings, WCAG rollups, manual-review coverage, and regression data for one audit. |
| start_accessibility_audit | write | 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 | domain_id | The most recent completed scan with its findings and severities. |
| get_vuln_scan_results | read | scan_id | Findings for one scan by id. This is how you poll a scan you just started. |
| get_vuln_scan_history | read | domain_id | The last twenty scans with status, profile, timing, and severity summary. |
| get_vulnerability_assets | read | domain_id | Every public hostname discovered for a domain and the finding counts attached to each. |
| get_open_ports | read | domain_id | Per-host port, service, banner, version, and risk observations. |
| list_lookalikes | read | 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 | 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 | 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 | 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 | — | The portfolio's technology inventory with version confidence where a version was actually observed. |
| get_scan_ownership_verification | write | domain_id | Return the DNS, file, or email proof required before active scanning, creating a challenge if none exists. |
| verify_scan_ownership | write | domain_id | Re-check the published proof and record verification when it is found. |
| start_vuln_scan | write | 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 | — | The compliance checklist with each control's current status and notes. |
| update_compliance_item | write | 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. |
Uptime and dependencies
scope: statusCustom endpoint checks you define, plus the 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 |
|---|---|---|---|
| list_status_checks | read | — | Custom endpoint checks with their URLs and most recent result. |
| get_status_services | read | — | Current status of the third-party providers this account tracks. |
| create_status_check | write | name, url | Add a check that polls a URL on a schedule and records whether it responded. |
| run_status_check | write | check_id | Run one saved check immediately rather than waiting for its next poll. |
| delete_status_check | destructive | check_id | Remove a custom check. |
The Local SEO catalog
Thirteen tools cover local search directly. Behind run_local_seo_action sit another 39 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 · business_qa · reviews · review_velocity · multi_platform_reviews · reputation_audit |
| Rankings and maps | rank_check · geogrid · serp_local_finder · serp_maps · serp_lsa |
| Keyword research | keyword_suggestions · keyword_search_volume · keyword_opportunities · keywords_for_site · keywords_related · keyword_trends |
| AI search visibility | ai_visibility · serp_ai_overview · 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 · competitor_ads · business_listings |
| 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 — 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 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. |
| “requires ownership verification” | Active scanning needs proof of control. | get_scan_ownership_verification, publish the proof, then verify_scan_ownership. |
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, and ping. resources/list and prompts/list answer empty rather than not-found, so a client probing capabilities does not treat the server as broken.
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 reads and refreshes monitoring
data for the domains on this account: DNS, SSL, mail authentication, security
checkups, on-page and site-wide SEO, accessibility, local rankings, reviews,
citations, backlinks, and AI search visibility.
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`) before running any scan.
- `run_*`, `start_*`, `check_*` and `verify_*` cost time or credits. So do
`get_domain_email_security`, `discover_domain_subdomains` 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` and `start_accessibility_audit` are
asynchronous — poll their results tools.
- Confirm `delete_domain`, `delete_local_keyword_target` and
`delete_status_check` in words before calling them.
- 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, CMS, or Google Business Profile.
- Never estimate a score, position, volume, or price that a tool did not return.
Full guide: https://nhmohio.com/mcp/claude-guide.mdHow 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.
