API and MCP

Connecting the MCP server

Add https://nhmohio.com/api/mcp to Claude Code, Claude Desktop, Cursor, VS Code, Codex or any HTTP MCP client with an nhm_ key, keep the key to the job, confirm what it can reach, and use the prompts.

Updated · 5 min read

The MCP server hands an assistant your whole account: every domain, every stored result, and, with the write scope, the ability to add a domain by answering questions, start scans, spend credits, and update saved records. It speaks Model Context Protocol over Streamable HTTP with no OAuth flow and no event stream to open.

Plan: Pro (read) and Enterprise (read and write). Free and Starter get 401.

1. Create a key

Web dashboard, Settings, API keys. Pick the scopes the key should reach (domains, scans, seo, accessibility, vulnscan, compliance, status). On Enterprise tick write if the assistant should be able to act; leave it off for a key that only reports. Copy the key when it is shown; it is shown once. Give it 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"

Cursor (~/.cursor/mcp.json):

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

VS Code (.vscode/mcp.json). VS Code asks for the key once and keeps it in its secret storage, so it never goes into the repository:

{
  "inputs": [
    { "type": "promptString", "id": "domainguard-key", "description": "DomainGuard API key", "password": true }
  ],
  "servers": {
    "domainguard": {
      "type": "http",
      "url": "https://nhmohio.com/api/mcp",
      "headers": { "Authorization": "Bearer ${input:domainguard-key}" }
    }
  }
}

Claude Desktop (claude_desktop_config.json, from Settings, Developer, Edit Config). This goes through the mcp-remote bridge, which works in every version and needs Node.js installed:

{
  "mcpServers": {
    "domainguard": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://nhmohio.com/api/mcp", "--header", "Authorization:${DG_AUTH}"],
      "env": { "DG_AUTH": "Bearer nhm_your_key_here" }
    }
  }
}

Write the header with no space after the colon, and keep the key in env: on Windows a space inside an argument gets split. Restart Claude Desktop after saving.

OpenAI Codex CLI (~/.codex/config.toml), with the key in the environment variable it names:

[mcp_servers.domainguard]
url = "https://nhmohio.com/api/mcp"
bearer_token_env_var = "DOMAINGUARD_API_KEY"

Any MCP client that supports a remote server over Streamable HTTP with a custom header works the same way. One that only runs local servers can use the mcp-remote bridge shown for Claude Desktop. The dashboard's Connect an AI agent button writes the Claude Code, Cursor, VS Code and Claude Desktop setup for you with a new key filled in.

Keep the key to the job

Every tool a key can reach is described to the assistant before its first call, and that text stays in its context for the whole conversation. A key with every scope and write is offered 233 tools, about 40,000 tokens of descriptions. A narrower key leaves more room for your domains' data and makes the right tool easier to pick:

Key's scopes Tools offered
seo, read only 41
seo + write 75
domains + write 60
vulnscan + write 50
every scope, read only 125
every scope + write 233

An assistant that only reports needs no write. A local search assistant needs seo plus domains (for the domain list).

3. Confirm it works

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

Prompts and resources the server carries

Prompt What it does
onboard_domain The add-domain interview, start to finish
set_up_local_seo Profile, phrases, quote, first measurement
improve_local_seo The free SEO brief turned into a short, ordered plan
verify_findings Re-test every finding with read-only checks, send the verdicts back, tell you what was right and wrong
review_domain Read everything, verify it, report mistakes, deliver fixes
portfolio_triage One ranked list across every domain, spending nothing
fix_email_deliverability SPF, DKIM, DMARC and the report stream, in order
build_wisp Interview about your firm and build a written information security plan as a Word document
audit_domain Everything measured for one domain: a verdict, the problems worst first with evidence and fixes, and what has not been measured
Resource What it holds
domainguard://guide (operating-guide) The complete guide for an assistant: ground rules, the tools, the playbooks, the Local SEO catalog, scopes and errors
domainguard://onboarding (onboarding-protocol) The short protocol behind onboard_domain
domainguard://local-seo (local-seo-protocol) From access check to first measurement, in the order that spends least
domainguard://review (verify-and-report-protocol) What to verify before presenting a finding, and how to report a scanner mistake
domainguard://wisp (wisp-protocol) How to build a WISP by interview
domainguard://verification (verification-method) How DomainGuard tests each kind of claim, the read-only commands that re-test it, and the data sources with their licences

In Claude Code the prompts appear as /mcp__domainguard__onboard_domain and so on. The server also publishes a machine-readable operating guide at https://nhmohio.com/mcp/claude-guide.md, which tells a connected assistant to prefer stored results over new scans, to quote before spending, and to verify findings before presenting them as fact.

Rules the server enforces

  • Scopes decide the tool list. Tools outside a key's scopes are never offered and cannot be called.
  • Read-only means read-only. Without write, an assistant cannot start live lookups or scans, spend credits, or change configuration. Live-scan tools are write-gated even when they do not modify the target, because they spend allowances and contact upstream providers.
  • The plan is re-read per request. An account that moves from Enterprise to Pro loses write on the next call.
  • Ownership is inherited. Every tool goes through the same registered routes the dashboard uses, with the same tenant checks.
  • Tool lists are private. tools/list results are marked private and scope-dependent; a shared proxy must never serve one key's list to another.

Errors

You see Meaning
401 No key, or a plan below Pro
403 "Error 1010: Access denied" from Cloudflare Python's built-in urllib identifies itself with a user agent Cloudflare blocks, so the request never reached us. Send any other User-Agent; the MCP SDKs, requests, httpx, Node and curl all work
405 A GET. The server has no event stream; send POST
isError: "missing the … scope" Mint a key with that scope
isError: "read-only" The tool changes state and the key has no write scope
429 The key's hourly limit, or the plan's manual-scan allowance
409 idempotency_mismatch That request_key was used for a different request; generate a fresh one

Still stuck?

Ask the people who run the scanner.

Send the domain and what you expected to see. We look at the same scan you are looking at and write back with what it means and what to change.