Skip to main content
Glama
SpikeyCoder

Website Auditor MCP

Website Auditor MCP

An MCP server for website-auditor.io — AI-visibility (GEO) and site-audit tools you can call from any MCP client (Claude Desktop, Claude Code, Cursor, Codex, and other agents).

Ask an agent "does ChatGPT recommend my business?", "what's my AI-visibility score?", "audit example.com", or "how do I stack up against my competitors?" and it answers with real data — an overall AI-visibility score (0–100), a per-engine breakdown across ChatGPT, Perplexity, Claude and Gemini, a full site audit (security, performance, crawlability and markup), competitor comparisons, and ongoing monitoring.

The server is a thin, authenticated wrapper over the Website Auditor API — the audit engine, AI-visibility scoring and monitoring live in that service; this server just makes them available to agents.


Tools

Tool

Tier

What it does

get_sample_audit

Free — no key

A complete sample report for example.com in the exact shape a real audit returns. Needs no API key, no subscription and no network. Try this first to see what you'd be buying.

get_ai_visibility

Pro

Current AI-visibility score (0–100) + per-engine breakdown (ChatGPT, Perplexity, Claude, Gemini) + the top competitor appearing in your place. Pro subscribers also get trend: 7- and 30-day score movement from stored snapshot history for the question this audit asked, ending at its snapshot and compared only between measured snapshots that asked it, the overall further only between endpoints the same engines answered (a window engines differed over carries its engine deltas and an overall_note saying which answered each; null, with a note, when the audit stored no measured snapshot).

run_audit

Pro, rate-limited

Full one-time audit → category scores (AI visibility, crawlability and markup as seo, security, performance) + top issues + a shareable report URL.

get_changes

Pro

What changed in the AI-visibility score — the change in the overall score and the per-engine score changes, for engines measured both times, the overall only when the same engines answered both snapshots (else it is null with an overall_note naming which answered each, and the per-engine changes stand alone); competitor_changes, new_issues and resolved_issues are always empty. Only between two snapshots that asked the same question (the same business name, market and queries), read from the domain's series: its measured weekly re-audits and any audit that asked the same question as the newest recorded one, while it has no gap longer than four weeks and a day from the newest weekly re-audit that recorded its question, through each later snapshot of the series (weekly re-audits included, recorded or not), to the newest measured snapshot. When there is no such pair it says why instead of a number, with the date the series re-baselined when it did. The domain need not be tracked: history accrues from any audit of it, tracked or not — track_site adds the weekly re-audits to the series, it is not a precondition.

compare_competitors

Pro

Head-to-head AI-visibility ranking against named competitor domains + where each appears that you don't. Quota-aware: caps the audit fan-out to your remaining daily quota, reuses recent cached audits, and reports any competitors it had to skip rather than dropping them silently.

track_site

Pro

Start (or stop) weekly monitoring of a site's AI visibility. Its weekly re-audits join the history get_changes reads from, which audits accrue tracked or not — monitoring watches a site, it does not enable get_changes.

untrack_site

Pro

Stop monitoring a site and free up a monitoring slot. Deletes the site's monitoring enrollment; past audits are kept.

list_tracked_sites

Pro

List the sites you're monitoring, with cadence, active state, and slots used/remaining.

get_monitoring_status

Pro

A glanceable dashboard across all tracked sites — latest score of each site's series (the series get_changes reads), the date of each one's last scheduled run and when the next runs, and the most recent like-for-like change (or a note, or the summary, saying why there is none), shown as its per-engine changes with a note naming the engines when different ones answered the two snapshots; like get_changes, its change carries competitor_changes, new_issues and resolved_issues, always empty.

check_upgrade_status

Any valid key

Your own subscription standing — tier, status, period end, and what upgrading unlocks (starting Pro requires a payment method and accepting the Terms). Consumes no audit quota.

Related MCP server: seo-audit-mcp

Prompts

Clients that support MCP prompts (Claude Desktop, claude.ai) render these as something you can pick from a menu, so you don't have to phrase the request yourself or know which tool to ask for. In clients that don't surface prompts (Codex, currently), nothing is lost but the menu — ask in words and the same tools run.

Prompt

Needs a key?

What it does

See a sample report

No

Walks through a complete report for example.com. No arguments, no setup — one click from any install.

Check my AI visibility

Pro

Runs get_ai_visibility for a domain you name, then explains the score, which assistants name the business, and who is named instead.

Run a full site audit

Pro

Runs run_audit for a domain and summarises it by category, with the three fixes that matter most.

Compare me to a competitor

Pro

Runs compare_competitors for your domain against a named rival, and explains where they get named and you don't.

Each Pro prompt falls back to get_sample_audit when no API key is configured, so you always get output rather than an error.

Naming the business (optional)

get_ai_visibility and run_audit both accept two optional arguments that decide what question the AI-visibility check actually asks. compare_competitors accepts business_location only — see below for why it takes no name:

Argument

Omitted

Supplied

business_name

Detected from the site, and flagged with name_warning when it could not be verified

Taken as fact and recorded as caller-supplied — which suppresses the warning

business_location

Detected from the site; if nothing is found the questions widen to the country, or drop the place entirely

Scopes the questions to that place

Supply a name only when you actually know it. A supplied name overrides detection and is treated as confirmed, so a guess is scored exactly as if a human had verified it — and silences the warning that would have told you otherwise. Leaving it out is the safer default: detection is transparent about its own uncertainty.

The same applies to location, in the other direction. Omitting it is correct for a national or global business and wrong for a local one, since a local business measured without a place is measured against the wrong queries.

On compare_competitors: it takes business_location and applies it to your site and every competitor, because a comparison asks about one market — scoring you locally while scoring your rivals globally would rank the answers to two different questions. It deliberately takes no business_name: a name identifies one business, and forwarding yours to your competitors would score every one of them as you. The result names the market it used, so a scoped comparison is never mistaken for a global one.

"Check AI visibility for hawaiibackroad.com,
 the business is Big Island Backroad Adventures in Hilo, HI"

Install & configure

The server runs directly via npx — no clone or build required.

Try it before you buy it. Install with no API key at all and ask your agent for a sample audit — get_sample_audit returns a full report for example.com in the exact format a real run produces, so you can check the shape fits your needs first.

Pricing. Auditing real domains needs a Website Auditor subscription at $49/month — eligible new customers get a 7-day free trial (payment method required to start; no charge until the trial ends; customers who used a trial in the last 12 months are billed immediately). Sign up and create an API key at api.website-auditor.io/admin_portal, then set it as WA_API_KEY below. There is no free API tier — a key only functions with an active subscription.

Claude Desktop (claude_desktop_config.json), Cursor (~/.cursor/mcp.json), and most other clients use the same mcpServers shape:

{
  "mcpServers": {
    "website-auditor": {
      "command": "npx",
      "args": ["-y", "website-auditor-mcp"],
      "env": {
        "WA_API_KEY": "wa_your_key_here"
      }
    }
  }
}

Claude Code — add it from the CLI:

claude mcp add website-auditor -e WA_API_KEY=wa_your_key_here -- npx -y website-auditor-mcp

Codex — the CLI, IDE extension and ChatGPT desktop app all read the same ~/.codex/config.toml, so one of these covers all three:

codex mcp add website-auditor --env WA_API_KEY=wa_your_key_here -- npx -y website-auditor-mcp
[mcp_servers.website-auditor]
command = "npx"
args = ["-y", "website-auditor-mcp"]

[mcp_servers.website-auditor.env]
WA_API_KEY = "wa_your_key_here"

Codex doesn't render MCP prompts, so the Prompts above won't appear as menu entries there — ask in words instead ("show me a sample audit").

Or install the packaged Codex plugin, which bundles the same server and restores the prompts as skills (which Codex does render):

codex plugin marketplace add SpikeyCoder/website-auditor-mcp
codex plugin add website-auditor@spikeycoder

Cursor — one-click install, or put the same mcpServers JSON as above in ~/.cursor/mcp.json:

Install in Cursor

The one-click config arrives with an empty WA_API_KEY — the sample report works as-is; fill the key in under Settings → MCP to audit real domains. There is also a packaged Cursor plugin (this server plus the prompts as skills) in cursor-plugin/; its Cursor Marketplace listing is pending — status in docs/CURSOR-PLUGIN.md.

Restart the client and the tools appear.

Getting an API key

WA_API_KEY is a per-user key (it starts with wa_) minted from a Website Auditor account at api.website-auditor.io/admin_portal — the admin portal, where you subscribe and manage keys.

Minting a key requires an active subscription ($49/month; eligible new customers get a 7-day free trial — payment method required, no charge until the trial ends): there is no free API tier, so every tool except get_sample_audit, check_upgrade_status and get_recommendations needs one. get_sample_audit needs no key at all. get_recommendations answers any valid key with the next steps from an audit already on record; with Pro it also says where to get listed, what AI assistants get wrong about the business, and which fix file fixes each finding.

Treat the key like a password — set it only in your MCP client's env and never commit it.

Restart after setting or changing the key. WA_API_KEY is read once, when the server starts, so a key added while the client is running is invisible to it — in Claude Desktop, quit and reopen the app. Without the restart the tools keep returning the same AUTH_REQUIRED you just acted on, which looks identical to the key not working.

Configuration (environment variables)

Var

Default

Purpose

WA_API_KEY

(required)

Per-user API key (starts with wa_).

WA_API_BASE_URL

https://api.website-auditor.io

The Website Auditor API this server wraps.

WA_SITE_URL

https://website-auditor.io

Used to build shareable report links.

WA_UPGRADE_URL

https://api.website-auditor.io/admin_portal/

Where auth and subscription errors point you. ?source=mcp is appended so a signup that started here is attributable; set your own source to override. For tools that take a domain, site=<hostname> (the hostname only — no path or query) is added too, so the portal can name the site — but only when the link points at the portal (the host of WA_API_BASE_URL), never at another host. Not surfaced on quota errors — the daily cap is not an upsell.

WA_UPSELL_STYLE / WA_UPSELL_INFO_URL

link / WA_SITE_URL

info style (the hosted ChatGPT server) links every auth and plan error to WA_UPSELL_INFO_URL, an informational plans page, instead of WA_UPGRADE_URL, with no price or trial in the text. ?source=mcp is appended unless a source is set; site=<hostname> is added for tools that take a domain only when this URL points at the portal (the host of WA_API_BASE_URL) — not at the homepage default or any other host.

WA_TOOL_COPY

full

neutral (the hosted Claude connector) drops the price, the trial and the "call get_sample_audit first" pointer from tool descriptions, takes the terms out of the server instructions' billing paragraph, and turns the instructions' unasked-offer and "call it instead" blocks into descriptions. Anthropic's directory review rejects all of these as promotion or as telling Claude to call tools. Paywall answers still state the terms (see WA_UPSELL_STYLE).

WA_AUTH_CHALLENGE

result

Hosted with Mixed Auth only. http (the hosted Claude connector) answers with an HTTP 401 + WWW-Authenticate, before the tool runs, both a call to an account-only tool with nothing presented and any tool call with a token the authorization server rejects. It is the only signal Claude starts sign-in from. A token that could not be checked (introspection down) is not refused. result puts the challenge in the tool result's _meta, which is what ChatGPT reads.

WA_REQUEST_TIMEOUT_MS

120000

Timeout for API calls.

WA_AUDIT_CACHE_TTL_MS

86400000

Reuse a domain's audit within this window instead of spending quota (used by compare_competitors). Defaults to 24h.

WA_SUBSCRIPTION_CACHE_TTL_MS

60000

How long a resolved Pro/free tier is cached per key before re-checking the subscription.

WA_METRICS_DISABLED

(unset → metrics on)

Set to 1/true to disable anonymous usage telemetry.

Only WA_API_KEY is normally needed; the rest have sensible defaults. See .env.example for the full list.


Auth & tiers

Your key is validated on every call. The Pro/free tier is resolved live from the API and cached briefly, so upgrades and downgrades take effect within about a minute:

  • No key → get_sample_audit still works (that's the point of it); every other tool returns AUTH_REQUIRED with the price and a sign-up link.

  • Revoked or unrecognized key → INVALID_KEY, carrying the API's own remediation ("generate a new key"). Distinct from PRO_REQUIRED: the fix is a new key, not a purchase.

  • No active subscription (valid key, lapsed/canceled/never subscribed) → PRO_REQUIRED with the price and an upgrade link — there is no free API tier; check_upgrade_status still answers so the caller can learn why, and get_recommendations still answers with the free list ("tier": "free").

  • Subscribed (status active or a trial in progress) → all tools.

Errors are normalized to stable codes agents can branch on — e.g. AUTH_REQUIRED, INVALID_KEY, PRO_REQUIRED, OVER_QUOTA, UNREACHABLE_DOMAIN, INVALID_INPUT, TIMEOUT. A domain that resolves but whose pages never load (down, refusing, timing out, or answering 404/5xx on every page) returns UNREACHABLE_DOMAIN; one that does not resolve is refused before any audit runs, as INVALID_INPUT. Neither gets a fabricated score.


Develop

npm install
npm run build      # compile TypeScript → dist/
npm start          # serve over stdio
npm run dev        # run from source without building
npm test           # vitest
npm run typecheck

The suite is hermetic — the API client, subscription provider and meter are injected, and HTTP is mocked at the fetch boundary, so no network is touched.


Privacy Policy

Anonymous install id. When telemetry is enabled, the server generates a random UUID on first run and stores it at ~/.config/website-auditor-mcp/install-id (or $XDG_CONFIG_HOME), sending it with each event. It exists solely to tell one install restarting many times apart from many separate installs — without it, install counts are just restart counts. It is randomly generated, never derived from your machine, username or network, and is not a fingerprint. Setting WA_METRICS_DISABLED stops telemetry entirely: no id is generated and nothing is written to disk.

This connector talks to a single external service: the Website Auditor API at website-auditor.io. When you invoke a tool it sends only two things to that API:

  • the target domain you asked to audit or monitor, and

  • your API key (WA_API_KEY), used to authenticate the request and resolve your plan tier.

At startup, and at most hourly while tools are in use, the server also asks the same API for Pro's current price (GET /pricing.json), so the price it states is never out of date. That request carries no key, no install id and no data about you or your sites.

That's the full extent of what leaves your machine. The connector does not collect, store, or transmit your files, prompts, conversation content, or any other personal data, and it does not send data to any third party beyond the Website Auditor API. Your API key is held only in your MCP client's configuration (in Claude Desktop it is stored in the OS keychain and injected as an environment variable); it is never written to the bundle or logged.

Anonymous, aggregate usage telemetry (which tool ran, success/failure, latency — no domains, no keys, no personal data) may be emitted to improve the service, and can be disabled entirely by setting WA_METRICS_DISABLED=1. Installed as a desktop extension, the same opt-out is a "Disable anonymous usage telemetry" checkbox in the extension's settings.

Full privacy policy: https://website-auditor.io/privacy


License

MIT — © 2026 Kevin Armstrong / SpikeyCoder.

This covers the MCP server in this repo: the client that talks to the Website Auditor API. The audit engine and the API behind it are separate products, not covered here, and running real audits still needs a Website Auditor account.

Learn more at website-auditor.io.

Available Tools

15 tools
check_upgrade_statusCheck upgrade statusA
Read-only

Check the caller's own Website Auditor subscription standing. Use this when someone asks "am I on Pro," "is my trial still active," "when does my subscription renew/end," "why is this tool locked," or before suggesting an upgrade. Works with any valid API key and consumes no audit quota. Returns the tier (none/free/pro), raw subscription status, period end, whether the subscription is set to cancel, the upgrade URL, and a plain-language summary — including what starting Pro requires (a payment method and accepting the Terms).

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
tierYes"none" | "free" | "pro".
statusYesRaw subscription status: active, trialing, canceled, none, …
messageYes
upgrade_urlYes
current_period_endYes
cancel_at_period_endYes

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, destructiveHint=false and openWorldHint=false, so the safety profile is covered. The description still adds real value beyond them: no audit quota is consumed and any valid API key works, which the agent cannot infer from annotations. Most of the remaining text enumerates return fields that the output schema already carries, so this is strong but not maximal.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose then triggers, and every clause is actionable. The lengthy enumeration of return fields (tier, raw status, period end, cancel flag, upgrade URL, summary) partly duplicates the output schema, which is the one place the text does not fully earn its length.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter, read-only status tool with an output schema, the description covers everything an agent needs: when to call it, auth requirements, quota cost, and what starting Pro requires. Nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so schema coverage is moot and the baseline of 4 applies. The description usefully implies there is no subject argument — it only reports the caller's own subscription — which prevents an agent from hunting for a user ID to pass.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource — 'Check the caller's own Website Auditor subscription standing' — and the 'caller's own' scope cleanly separates it from every sibling, none of which touch subscription state. An agent can identify the tool from the first sentence alone.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit trigger conditions with quoted user phrasing ('am I on Pro', 'is my trial still active', 'why is this tool locked') plus a proactive case ('before suggesting an upgrade'). It also names the precondition for use (any valid API key) and confirms no cost, so an agent knows both when and how freely to call it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

compare_competitorsCompare against competitorsA

Compare a website's AI visibility head-to-head against named competitors. Use this when someone asks "how do I stack up against X and Y," "who does ChatGPT recommend instead of me," or wants a competitive AI-visibility view. Returns each competitor's score and where they appear that the site does not. Each competitor not already cached costs one audit against your daily quota; if the quota can't cover every competitor, it ranks the ones it could audit and returns a quota summary plus a skipped list naming the rest — it never drops competitors silently or invents scores. If the quota is already exhausted it returns an over-quota error with the reset time. Requires a Website Auditor subscription ($10/month; eligible new customers get a 7-day free trial — payment method required, no charge until the trial ends) — if the user doesn't have one, call get_sample_audit first to show them the exact output format, free and with no API key.

ParametersJSON Schema
NameRequiredDescriptionDefault
domainYesThe website domain, e.g. "example.com".
competitorsYesCompetitor domains to compare against.
business_locationNoOptional. The market to compare within, e.g. "Chiang Mai, Thailand". Applied to the site AND every competitor, because a comparison asks about one market — scoring one locally and the others globally would rank answers to two different questions. Leave it out and each audit detects its own location, which is right for national or global businesses and wrong for local ones.

Output Schema

ParametersJSON Schema
NameRequiredDescription
gapsYesEngines where a competitor appears in AI answers and this site does not.
quotaYes
marketYesThe market every audit in this comparison was scored in, or null when each domain's own location was detected.
rankingYes
skippedYes
summaryYes

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations by disclosing that each uncached competitor costs one audit against a daily quota, that partial results rank auditable competitors and return `quota`/`skipped` fields without dropping silently or inventing scores, that an over-quota error includes a reset time, and that a paid subscription is required with trial terms. This is rich operational context the annotations could not convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose and triggers, then behavior, then prerequisites. It is long, and the pricing/free-trial clause is dense, but essentially every sentence carries actionable information. Slightly heavy rather than wasteful.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers purpose, triggers, quota economics, failure modes, and subscription prerequisites; since an output schema exists, return-value detail needn't be restated. An agent has everything needed to decide to call it and what to expect.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all three parameters (including the nuanced location behavior) are already documented in the schema. The description adds quota context around the competitors parameter but no additional semantic detail beyond the schema, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Compare a website's AI visibility head-to-head against named competitors') with clear scope. An agent can distinguish this from siblings like get_benchmark or get_ai_visibility without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit trigger phrases ('how do I stack up against X and Y,' 'who does ChatGPT recommend instead of me') and names the alternative for the no-subscription case: call get_sample_audit first. When-to-use and fallback routing are both spelled out.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

generate_schemaGenerate JSON-LD schemaA
Read-only

Generate structured data (JSON-LD schema) tailored to a website, to improve how AI assistants and search engines understand it. Use this when someone asks for "schema," "structured data," "JSON-LD," or wants the actual markup to implement a recommendation. Returns a DRAFT, not finished markup: every name field arrives as a placeholder — "Your Business Name" on the business types, and on a Product the product's own name and brand as "Your Product Name" and "Brand Name" — that the owner must replace with real names confirmed with them, never guessed from the domain or copied from an audit. placement_notes says what to replace first, then where to embed the finished snippet, so relay the whole ask and do not tell the user to paste the draft as returned. Requires a Website Auditor subscription ($10/month; eligible new customers get a 7-day free trial — payment method required, no charge until the trial ends) — if the user doesn't have one, call get_sample_audit first to show them the exact output format, free and with no API key.

ParametersJSON Schema
NameRequiredDescriptionDefault
typeNoSchema type; "auto" (also the default when omitted) does not detect anything — it returns an Organization draft.
domainYesThe website domain, e.g. "example.com".

Output Schema

ParametersJSON Schema
NameRequiredDescription
jsonldNoThe JSON-LD draft (object or array). NOT ready to paste: every name field arrives as a placeholder — "Your Business Name" on the business types, and on a Product the product's own name and brand as "Your Product Name" and "Brand Name" — that the owner must replace with real names confirmed with them, never guessed from the domain or copied from an audit.
placement_notesYesWhat to replace in the draft first — each name placeholder, confirmed with the owner — then where to embed the finished snippet, e.g. "in the <head> of every page". Relay the whole string, in that order: the replacement ask comes before the placement.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare it is a non-destructive read, but the description goes far beyond: it discloses that output is a DRAFT with placeholder name fields, that names must never be guessed from the domain or copied from an audit, what placement_notes contains, how to relay it to the user, and the $10/month subscription with 7-day trial requirement. That is unusually rich behavioral context for a readOnly tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The paragraph is front-loaded with purpose, then triggers, then behavioral caveats, and nearly every sentence carries actionable content. It is dense and long, but the length is largely justified by the draft/placeholder and subscription prerequisites rather than padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present and full parameter coverage, the description only needs to supply what structured fields cannot: the subscription prerequisite, the draft-with-placeholders caveat, and the fallback tool. All of these are present, so an agent has everything needed to call and correctly relay the result.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents both `domain` and the `type` enum including the "auto" default behavior. The description adds no further syntax, format, or selection guidance for these parameters, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence names a specific verb and artifact — generate JSON-LD structured data tailored to a website — plus the outcome it serves. It is clearly distinguishable from the audit/report siblings because it produces markup rather than analysis.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit trigger phrases ("schema," "structured data," "JSON-LD") and states the alternative path when prerequisites are unmet: if the user lacks the required subscription, call get_sample_audit first. This is exactly the when/when-not/alternative guidance the dimension asks for.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_ai_visibilityCheck AI visibilityA

Check how visible a website is to AI assistants right now. Use this whenever someone asks "does ChatGPT/Perplexity/Claude/Gemini recommend this business," "is my site showing up in AI answers," "what's my AI visibility / GEO score," or wants a quick read on whether an AI assistant would surface a given domain. Returns an overall AI-visibility score (0–100), a per-engine breakdown (ChatGPT, Perplexity, Claude, Gemini), and the top competitor appearing in place of the site. When the audit recorded citations, sources lists the documents the assistants actually read, ranked by cross-engine agreement, each marked yours, competitor or third_party — treat competitor rows as context, not as placement targets; sources: null means the recorded answers cited nothing attributable, and an absent key means citations were not recorded for this audit. The result also includes trend data: 7- and 30-day score movement computed from the domain's stored snapshot history, for the question this audit asked, ending at the snapshot this audit stored; when it stored no measured snapshot, trend is null and trend_note says why. If name_warning is present, the business name behind the score could not be verified — relay that caveat rather than presenting the score as settled fact, and offer to re-run with an explicit business name. Requires a Website Auditor subscription ($10/month; eligible new customers get a 7-day free trial — payment method required, no charge until the trial ends) — if the user doesn't have one, call get_sample_audit first to show them the exact output format, free and with no API key.

ParametersJSON Schema
NameRequiredDescriptionDefault
domainYesThe website domain, e.g. "example.com".
business_nameNoOptional. The business's real name, if you know it. Leave it out and the audit detects the name from the site and flags it when unverified — a guessed name is scored as if confirmed, so supply one only when it is actually known.
business_locationNoOptional. The city the business trades in, e.g. "Hilo, HI". Leave it out and the audit detects it; when nothing is detectable the questions widen to the country or drop the place entirely, which is right for a national or global business and wrong for a local one.

Output Schema

ParametersJSON Schema
NameRequiredDescription
scoreYesOverall AI-visibility score, 0–100.
trendYesPro only; null when unavailable — trend_note says why.
sourcesNo
summaryYes
by_engineYesPer-engine AI-visibility score, 0–100. NULL means the engine was not scored — see engine_status for which of the two reasons. A null is NOT a zero: zero means the engine answered and never named the business.
trend_noteNoPresent exactly when trend is null: the reason.
name_sourceNo"detected" | "user_supplied" | "domain_fallback".
name_warningNoSet ONLY when the business name behind the score could not be verified. The score is computed from queries built around that name, so relay this caveat rather than presenting the score as settled.
coverage_noteNoPresent exactly when an engine was asked and did not answer. Relay it: the score covers fewer engines than the four this tool can query.
engine_statusYesWhy each engine's score is what it is. 'scored' — the engine answered and the number is a measurement. 'unanswered' — it was asked and returned nothing, so there is no score; do not report it as 0. 'not_asked' — it was not part of this run at all.
name_verifiedNo
top_competitorYesThe competitor appearing in place of the site, if any.
appears_by_engineYesWhether the site appeared at all on each engine. Distinct from the scores: an engine can have appearances yet a low score, or the reverse. NULL when the engine was not scored — false would assert it did not name the business, which is a claim an unmeasured engine cannot support.

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations cover the OpenWorld/readOnly/destructive profile, and the description adds substantial non-obvious context: the $10/month subscription and trial terms, the name_warning caveat to relay rather than present as settled fact, and the semantics of sources: null vs. absent key. The readOnlyHint=false is consistent with the description's statement that the audit stores a snapshot. Minor deduction only because it doesn't explain what is written/stored or any rate limits on repeated audits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the purpose and the matching user intents, then the return shape, then the subscription prerequisite. It is long, but nearly every clause carries actionable information (null semantics, trend_note, name_warning handling); a little more compression of the billing detail would help.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Although an output schema exists, the description goes further by explaining non-schema semantics that an agent must act on: sources null vs. absent, trend null with trend_note, competitor rows as context rather than targets, and the name_warning caveat. For a 3-param tool with an auth prerequisite, nothing needed to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description earns above that by explaining the consequence of omitting business_name (name_warning and the risk of a guessed name being scored as confirmed) and pointing to re-running with an explicit name. It does not add syntax beyond what the schema already gives for domain or business_location.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource (check AI visibility of a website to AI assistants) and immediately enumerates the user phrasings that map to it, so an agent can recognize the intent against siblings like run_audit or get_report. The scope (overall score, per-engine breakdown, competitor) is concrete.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says when to use it via quoted user intents ('does ChatGPT recommend this business', 'what's my GEO score'), and names the alternative path when the prerequisite is missing: call get_sample_audit first if the user lacks a Website Auditor subscription. Both the trigger and the fallback are stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_benchmarkBenchmark vs industry/geoA
Read-only

Benchmark a website's AI visibility against its industry and location. Use this when someone asks "how do I compare to others in my space," "is this a good score for my industry," or wants percentile/peer context rather than an absolute number. Backed by aggregated audit data. Requires a Website Auditor subscription ($10/month; eligible new customers get a 7-day free trial — payment method required, no charge until the trial ends) — if the user doesn't have one, call get_sample_audit first to show them the exact output format, free and with no API key.

ParametersJSON Schema
NameRequiredDescriptionDefault
geoNoOptional location override.
domainYesThe website domain, e.g. "example.com".
industryNoOptional industry override.

Output Schema

ParametersJSON Schema
NameRequiredDescription
percentileYesThe domain's percentile within its industry/geo peer set, 0–100.
peer_medianYes
sample_sizeYesHow many peers the percentile and median are computed over.
position_summaryYes

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false. The description adds valuable non-annotation context: subscription/payment requirements, trial terms, and the fallback to get_sample_audit. Does not disclose latency or data-freshness, but the billing/auth context is the key behavioral note here.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core verb and resource, then provides usage triggers. The subscription paragraph is long but earns its place as operational necessity. Slightly dense but well-ordered.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Output schema exists so return format needn't be explained. The description covers purpose, triggers, cost/auth prerequisites, and fallback path – everything needed to invoke correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3. The description adds meaning beyond the schema by clarifying that geo and industry act as overrides (implying defaults are derived from the domain), which the schema does not state.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Benchmark a website's AI visibility') with explicit scope (against industry and location), distinguishing it from absolute-score siblings like get_ai_visibility.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-use triggers with quoted user phrasings ('how do I compare to others,' 'is this a good score for my industry') and names the alternative get_sample_audit for users lacking a subscription. Clear routing logic.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_changesWhat changed in AI visibilityA
Read-only

Report what changed in a website's AI-visibility score, only between two snapshots that asked the same question. Use this when someone asks "did anything change," "what's different this week/month," or "did my AI visibility drop." The domain need not be tracked: history accrues from any audit of it, tracked or not — track_site adds the weekly re-audits to the series, it is not a precondition, so do not track a site just to answer a change question. Returns the change in the overall score and the per-engine score changes, for engines measured both times — the overall only when the same engines answered both snapshots, otherwise it is null with an overall_note naming which answered each, and the per-engine changes stand alone; competitor_changes, new_issues and resolved_issues are always empty, since snapshots record neither competitors nor audit issues. A change is only ever measured between two snapshots that asked the same question (the same business name, market and queries); when there is no such pair it says why instead of giving a number, with the date the series re-baselined when it did. The series is the measured weekly re-audits and any audit that asked the same question as the newest recorded one, while it has no gap longer than four weeks and a day from the newest weekly re-audit that recorded its question, through each later snapshot of the series (weekly re-audits included, recorded or not), to the newest measured snapshot; otherwise every measured snapshot. Requires a Website Auditor subscription ($10/month; eligible new customers get a 7-day free trial — payment method required, no charge until the trial ends) — if the user doesn't have one, call get_sample_audit first to show them the exact output format, free and with no API key.

ParametersJSON Schema
NameRequiredDescriptionDefault
sinceNoOptional ISO date or "last_check".
domainYesThe website domain, e.g. "example.com".

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNoPresent when skipped_snapshots is above 0, when the two snapshots compared were answered by different engines, when newer measured snapshots were left out of the series, or when newer weekly re-audits measured nothing of the business: which, and why, in words. Relay it.
new_issuesYesAlways empty: AI-visibility snapshots record no audit issues. Kept for clients that read it.
score_deltaYesOnly ever between two snapshots that asked the same question AND were answered by the same engines. When there is no such pair, including a re-baseline after the business name, market or queries changed, the tool returns NOT_YET_AVAILABLE saying so, never a number; when the pair exists but different engines answered the two snapshots, the overall is not subtracted and is null with overall_note, and engine_changes still compares every engine that answered both.
overall_noteNoPresent exactly when score_delta is null: the two snapshots were answered by different engines, and which answered each. Relay it — a null delta for this reason must not read like a null for want of history.
engine_changesYes
to_captured_atNoWhen the later one was.
resolved_issuesYesAlways empty: AI-visibility snapshots record no audit issues. Kept for clients that read it.
from_captured_atNoWhen the earlier snapshot compared was captured.
skipped_snapshotsNoSnapshots passed over because they asked a different question (another business name, market or queries) or do not record what they asked.
competitor_changesYesAlways empty: AI-visibility snapshots record no competitors. Kept for clients that read it.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare the safe read-only profile, yet the description adds substantial behavior: the null-overall rule when engines differ (with overall_note), that competitor_changes/new_issues/resolved_issues are always empty, the re-baselining date reporting, gating on a paid Website Auditor subscription, and the get_sample_audit fallback. This is well beyond what annotations supply.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose and triggers are correctly front-loaded, but the single-paragraph block is bloated and the 'series' sentence ('no gap longer than four weeks and a day from the newest weekly re-audit that recorded its question, through each later snapshot...') is nearly impenetrable. Some return-field narration is redundant given the output schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with an output schema and rich annotations, the description is more complete than needed, covering prerequisites, pricing/trial terms, the empty-field guarantees, and the no-valid-pair behavior. Nothing an agent needs to select or invoke it is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both parameters are already documented and the baseline is 3. The description's series/time analysis implicitly informs how far back the change is measured, but it never explicitly maps to the `since` parameter ('last_check') nor explains a domain-vs-question mismatch.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Report what changed in a website's AI-visibility score') and immediately scopes it to 'only between two snapshots that asked the same question.' This carving distinguishes it from siblings like get_ai_visibility, get_report, and compare_competitors without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit triggers are quoted verbatim ('did anything change,' 'what's different this week/month,' 'did my AI visibility drop'), and it names when NOT to use a sibling: 'do not track a site just to answer a change question,' clarifying that track_site adds re-audits but 'is not a precondition.' When/when-not/alternative are all covered.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_gtm_planBuild a GTM plan from the auditA

Build a written go-to-market plan from a website's latest audit, grounded in its citation evidence. Use this when someone asks "what should I do about my AI visibility," "turn this audit into a plan," or wants a GTM or marketing plan for their site. The plan is built from the sources the assistants actually read — each marked yours, competitor or third_party; competitor sources shape the analysis but are never placement targets. When the audit recorded no citation evidence the plan grounds itself in the report's issues and stats instead. Pass focus or constraints to steer it, and prior_plan (the markdown from an earlier call) to refine rather than start over. Requires a Website Auditor subscription ($10/month; eligible new customers get a 7-day free trial — payment method required, no charge until the trial ends) — if the user doesn't have one, call get_sample_audit first to show them the exact output format, free and with no API key.

ParametersJSON Schema
NameRequiredDescriptionDefault
focusNoWhat to emphasize — e.g. "local directories", "content", "a launch next month".
domainYesThe website domain, e.g. "example.com".
prior_planNoThe markdown of a plan from an earlier call, to refine instead of starting over.
constraintsNoBudget, team, or time constraints — e.g. "solo founder, $200/mo".

Output Schema

ParametersJSON Schema
NameRequiredDescription
planYes
modelYes
domainYes
summaryYes
sources_usedYes
evidence_noteNoAdditive, never an error: set when the plan had no citation evidence.

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well past the thin annotations by disclosing the grounding behavior (sources tagged yours/competitor/third_party, competitors never placement targets), the no-citation-evidence fallback, and the auth/cost requirement with trial terms. It stops short of describing side effects or whether the generated plan is persisted, which matters given readOnlyHint=false.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Trigger conditions and the core purpose are front-loaded, and every sentence carries distinct information. The subscription parenthetical is the longest stretch and could be trimmed, but it delivers the trial and payment details an agent needs before invoking.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return-value documentation is unnecessary, and the description covers the remaining agent-relevant gaps: what grounds the plan, the degraded fallback path, steering parameters, and the subscription gate plus its free alternative. Nothing needed to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is already 100%, so the baseline is 3, but the description adds real interpretation: focus/constraints "steer" the output and prior_plan is specifically the markdown from an earlier call used to refine rather than restart. That clarifies the relationship between parameters in a way the schema alone does not.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("Build a written go-to-market plan from a website's latest audit") and scopes the input as citation evidence from that audit. It is clearly distinguishable from siblings like get_report or get_recommendations, which retrieve rather than synthesize a plan.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit trigger phrases ("what should I do about my AI visibility", "turn this audit into a plan") and names the alternative path for users without a subscription: call get_sample_audit first. It also distinguishes the refine-vs-restart case via prior_plan, leaving nothing to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_monitoring_statusMonitoring status summaryA
Read-only

Get a glanceable summary of monitoring status across all tracked websites. Use this when someone asks "how are my tracked sites doing," "what's my current AI visibility across everything I monitor," "when were my sites last checked or when do they run next," or wants a dashboard of their monitored domains. Returns, per domain, the latest AI-visibility score of its series (the measured weekly re-audits and any audit that asked the same question as the newest recorded one, while it has no gap longer than four weeks and a day from the newest weekly re-audit that recorded its question, through each later snapshot of the series (weekly re-audits included, recorded or not), to the newest measured snapshot; otherwise every measured snapshot; a newer measured snapshot outside the series is not shown, and get_changes names it), the date of its last scheduled run and when the next one runs, and the most recent change against the last snapshot that asked the same question, or a note or the summary saying why there is none — when different engines answered the two snapshots, the change shows the per-engine changes only, with a note naming which answered each, and its score_delta is null; like get_changes, a change carries competitor_changes, new_issues and resolved_issues, always empty. Requires a Website Auditor subscription ($10/month; eligible new customers get a 7-day free trial — payment method required, no charge until the trial ends) — if the user doesn't have one, call get_sample_audit first to show them the exact output format, free and with no API key.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
usedYes
limitYes
sitesYes
summaryYes
remainingYes

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover read-only/closed-world/non-destructive, so the description correctly spends its effort elsewhere: it discloses the Website Auditor subscription requirement and trial terms, and describes what the change data contains (per-engine changes, null score_delta, always-empty competitor_changes/new_issues/resolved_issues). The gap is that the deeply convoluted series-inclusion rules are hard to act on, but auth and data-shape context are genuinely additive.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness2/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose and usage examples are front-loaded and useful, but the middle sentence describing the snapshot-series inclusion logic is a single unparseable run-on spanning roughly ten clauses. It is the opposite of glanceable and buries the actionable information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return-value detail is technically redundant, yet the description still enumerates the returned fields and the subscription prerequisite, leaving nothing an agent needs to call it correctly. It is arguably over-complete rather than incomplete for a zero-parameter, output-schema-backed tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so the baseline is 4; the description has no parameters to explain and does not confuse the reader with any.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Get a glanceable summary of monitoring status across all tracked websites') and scopes it to monitored domains, distinguishing it from siblings like list_tracked_sites and get_changes, which it even references by name for the out-of-series snapshot case.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit trigger phrases ('how are my tracked sites doing', 'what's my current AI visibility', 'when were my sites last checked') and a clear alternative path: if the user lacks a Website Auditor subscription, call get_sample_audit first. When-to-use and fallback behavior are both spelled out.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_recommendationsPrioritized fixesA
Read-only

Get specific, prioritized fixes to raise a website's AI visibility and audit scores. Use this when someone asks "how do I fix this," "what should I change," "how do I improve my AI visibility," or after an audit surfaces issues. Returns ranked actions with expected impact, each built from the domain's latest audit and citing its evidence (blocked AI crawlers, missing structured data, the competitor sites the assistants cited). Works with any Website Auditor API key and needs an audit on record for the domain; with Pro it also says where to get listed, what the assistants get wrong about the business, and which file in the fix package fixes each finding — without Pro the listing places are only counted.

ParametersJSON Schema
NameRequiredDescriptionDefault
domainYesThe website domain, e.g. "example.com".

Output Schema

ParametersJSON Schema
NameRequiredDescription
tierNoWhich list the API served. "free" omits where to get listed, what the assistants get wrong and each finding's fix file; its step marked `locked` only counts what Pro shows.
run_idNoThe audit the steps come from.
recommendationsYes

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations cover the safety profile (read-only, non-destructive, closed-world), and the description adds substantial context beyond them: the output is ranked with expected impact, is derived from the domain's latest audit, cites supporting evidence, and varies by plan tier (Pro adds listing places, assistant misconceptions, and per-file fixes; non-Pro only counts listing places). This is exactly the kind of gating and content-shape detail annotations cannot express.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose and usage triggers, then evidence and tiering. Dense but every clause carries information an agent needs; the long final sentence on Pro vs non-Pro behavior is the only place it verges on overload.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter tool with a rich output schema and full annotation coverage, the description supplies everything else: prerequisites, trigger conditions, evidence sources, and tier-dependent return differences. Nothing an agent needs to call or interpret it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There is a single parameter, and the schema already documents it at 100% coverage with a format example. The description usefully adds that the domain must have an audit on record, but contributes no syntax or format meaning beyond the schema, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (get) and resource (prioritized fixes) with the outcome it targets: raising a website's AI visibility and audit scores. It is clearly distinguishable from siblings like get_report or get_ai_visibility, which report status rather than prescribe ranked actions. An agent can route to it without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete trigger phrases ('how do I fix this', 'what should I change') and the timing condition ('after an audit surfaces issues'). It also states a prerequisite (an audit on record) and API-key compatibility. It does not name a specific alternative or a when-not-to-use condition, so it stops short of 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_reportShareable report + badgeA
Read-only

Get a shareable report URL and the embeddable "Audited by Website Auditor" badge snippet for a website. Use this when someone wants to "share," "export," "send a client," or "embed" the audit result. Returns a link and an HTML badge snippet. Requires a Website Auditor subscription ($10/month; eligible new customers get a 7-day free trial — payment method required, no charge until the trial ends) — if the user doesn't have one, call get_sample_audit first to show them the exact output format, free and with no API key.

ParametersJSON Schema
NameRequiredDescriptionDefault
domainYesThe website domain, e.g. "example.com".

Output Schema

ParametersJSON Schema
NameRequiredDescription
badge_htmlYes
report_urlYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations cover the safety profile (readOnlyHint=true, openWorldHint=false, destructiveHint=false), and the description adds the operationally critical gate: a required paid subscription, pricing, trial terms, and the fact that a payment method is needed. That is real value beyond the annotations, though it says nothing about failure modes or rate limits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the purpose, then usage triggers, then return payload, then the subscription prerequisite. Every sentence carries information, though the parenthetical pricing/trial detail is verbose and slightly buries the prerequisite at the tail.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so the return values need no further explanation, and the description still names them (link plus HTML badge snippet). For a single-parameter read tool, the subscription requirement and the get_sample_audit fallback cover everything an agent needs to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only one parameter with 100% schema description coverage ('The website domain, e.g. "example.com".'), so the schema does the heavy lifting. The description adds no format or syntax guidance beyond what the schema already states; baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (get) and two concrete resources (shareable report URL and embeddable badge snippet) for a website, which is immediately distinguishable from siblings like get_ai_visibility or get_benchmark. It also names the sibling get_sample_audit as the fallback path.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly enumerates the triggering user intents ("share," "export," "send a client," "embed") and gives a concrete when-not path: if the user lacks a subscription, call get_sample_audit first. Both the when and the alternative are spelled out.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_sample_auditSee a sample audit (no key needed)A
Read-only

Show a complete sample Website Auditor report — no API key required, nothing to set up. Use this whenever someone wants to "try it," "see a demo," "show me what this does," "what does the output look like," or is deciding whether Website Auditor is worth subscribing to — and use it INSTEAD of refusing when no API key is configured. Returns fixed sample data for example.com in the exact shape a real audit returns: scored summary, per-test results, and the AI-visibility breakdown across ChatGPT, Perplexity, Claude and Gemini. It is clearly marked as a sample and always describes example.com, never the user's own site — auditing a real domain needs a subscription.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteYes
auditYesA real GET /api/audit payload, populated with sample data.
priceYes
domainYesThe fixed sample domain. Never the caller's own.
is_sampleYesAlways true. Never present this as a live result.
upgrade_urlYes

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate read-only and non-destructive behavior, and the description goes further by disclosing that no API key or setup is required, the data is fixed for example.com, and the response is clearly marked as a sample. It also explains the return shape: scored summary, per-test results, and AI-visibility breakdown across specific models. This is thorough behavioral context beyond the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is detailed but each sentence contributes: it states the purpose, the trigger scenarios, the output contents, and the critical limitation that it never audits the user's own site. There is slight redundancy between 'no API key required' and 'INSTEAD of refusing when no API key is configured,' but overall it is well organized and front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given zero parameters and an existing output schema, the description is remarkably complete: it explains when to use the tool, what data it returns, how that data is structured, that it is sample data, and that real audits require a subscription. Nothing an agent needs to decide whether to call this tool is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so there is no schema burden to compensate for. The description adds helpful invocation context by stating that no API key or setup is needed, which reinforces that the tool is callable without prerequisites. This meets the baseline for parameterless tools.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Show a complete sample Website Auditor report.' It clearly distinguishes itself from a real audit by emphasizing that it returns fixed sample data for example.com and never the user's own site. This leaves no ambiguity about what the tool does.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit trigger scenarios such as 'try it,' 'see a demo,' and 'show me what this does,' and explicitly says to use it instead of refusing when no API key is configured. It also states the key negative condition: never use it for a user's real domain. It does not explicitly name an alternative tool like run_audit, but it makes the boundary between sample and real subscriptions clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_tracked_sitesList monitored sitesA
Read-only

List the websites currently being monitored for AI visibility on a schedule. Use this when someone asks "what am I tracking," "which sites am I monitoring," "how many monitoring slots am I using," or wants to see their tracked domains. Returns each tracked domain with its cadence and active state, plus slots used and remaining (out of 5). Requires a Website Auditor subscription ($10/month; eligible new customers get a 7-day free trial — payment method required, no charge until the trial ends) — if the user doesn't have one, call get_sample_audit first to show them the exact output format, free and with no API key.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
usedYes
limitYes
summaryYes
trackedYes
remainingYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare the safe read-only profile, but the description adds substantial context beyond them: a hard quota (slots out of 5), an auth/subscription requirement, trial and payment details, and a fallback tool for unsubscribed users. This is exactly the auth-needs and limit information annotations cannot convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The text is front-loaded with purpose and triggers, then return shape, then the subscription caveat. It is a little long, and the parenthetical on trial billing mechanics ($10/month, payment method required, no charge until trial ends) is verbose, though plausibly useful for the agent to relay.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter read tool with an output schema and read-only annotations, the description covers purpose, triggers, return shape, quota, subscription gating, and an alternative path. Nothing an agent needs to select or call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so the baseline is 4. The description also pre-describes the returned fields (domain, cadence, active state, slots used/remaining), which is helpful even though no parameter meaning is needed.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb (List) and resource (websites being monitored for AI visibility on a schedule), and clearly distinguishes this read tool from the write siblings track_site and untrack_site. An agent can identify it without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit triggering user phrasings ("what am I tracking," "which sites am I monitoring," "how many monitoring slots am I using") and an alternative path: if the user lacks a subscription, call get_sample_audit first. This is explicit when-to-use plus a named alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

run_auditRun a full auditA

Run a full one-time audit of a website — AI visibility, plus security headers, broken links, performance, and a crawlability-and-markup score (scores.seo: robots.txt, AI crawler access, sitemap, structured data, meta description and Open Graph tags). Use this when someone asks to "audit," "scan," "check," or "review" a website's health, or wants a complete report rather than just the AI-visibility number. Returns a scored summary across categories and a link to the full report. The ranked cited-sources evidence behind the AI-visibility number is returned by get_ai_visibility, not by this tool. If name_warning is present, the business name the AI-visibility score was measured against could not be verified — relay that caveat rather than presenting the score as settled fact. Requires a Website Auditor subscription ($10/month; eligible new customers get a 7-day free trial — payment method required, no charge until the trial ends) — if the user doesn't have one, call get_sample_audit first to show them the exact output format, free and with no API key.

ParametersJSON Schema
NameRequiredDescriptionDefault
domainYesThe website domain, e.g. "example.com".
business_nameNoOptional. The business's real name, if you know it. Leave it out and the audit detects the name from the site and flags it when unverified — a guessed name is scored as if confirmed, so supply one only when it is actually known.
business_locationNoOptional. The city the business trades in, e.g. "Hilo, HI". Leave it out and the audit detects it; when nothing is detectable the questions widen to the country or drop the place entirely, which is right for a national or global business and wrong for a local one.

Output Schema

ParametersJSON Schema
NameRequiredDescription
scoresYes
report_urlYes
top_issuesYes
name_warningNoSet ONLY when the business name could not be verified, which puts the AI-visibility score in question.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only supply the generic openWorldHint/readOnlyHint=false/destructiveHint=false profile; the description adds substantive context the annotations cannot: the paid-subscription requirement, trial terms, the name_warning caveat that must be relayed, and the fact that cited sources are excluded. It does not describe rate limits, audit duration, or failure modes, but the added disclosure is well beyond the structured fields.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Long but front-loaded: scope and coverage come first, then triggers, then the sibling distinction, then the caveat and billing detail. Each sentence carries distinct information, though the subscription/trial explanation is verbose enough to be tightened.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return values need not be explained, yet the description still summarizes them and flags the name_warning field's interpretation. Billing prerequisites, the free alternative, and the boundary against get_ai_visibility are all covered, leaving nothing an agent needs missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and the schema descriptions for business_name and business_location already carry the detailed guidance (guessed names scored as confirmed, location widening behavior). The description adds no parameter-level syntax or format detail beyond that, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Run a full one-time audit of a website') and enumerates exactly which categories are covered, including the precise components of scores.seo. It also explicitly distinguishes itself from get_ai_visibility, noting the ranked cited sources are returned by that sibling instead.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit trigger phrasing ('audit,' 'scan,' 'check,' 'review') and the selection condition against the nearest alternative ('wants a complete report rather than just the AI-visibility number'). It further routes users without a subscription to get_sample_audit first, so both when-to-use and the fallback path are spelled out.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

track_siteStart/stop monitoringA
Destructive

Start (or stop) ongoing monitoring of a website's AI visibility on a schedule. Use this when someone wants to "monitor," "track," "watch," or "get alerted about" a site's AI visibility over time, rather than a one-off check. Adds weekly re-audits to the history that get_changes reads from — a history every audit already accrues, tracked or not — so use this to be watched on a schedule, not to make get_changes work. Passing enabled: false stops monitoring by deleting the enrollment, as untrack_site does. Requires a Website Auditor subscription ($10/month; eligible new customers get a 7-day free trial — payment method required, no charge until the trial ends) — if the user doesn't have one, call get_sample_audit first to show them the exact output format, free and with no API key.

ParametersJSON Schema
NameRequiredDescriptionDefault
domainYesThe website domain, e.g. "example.com".
cadenceNoMonitoring cadence (weekly).weekly
enabledNoSet false to stop monitoring.

Output Schema

ParametersJSON Schema
NameRequiredDescription
domainYes
cadenceNo
createdNoPresent when starting: whether this call created a new tracking.
messageYes
removedNoPresent when stopping.
trackingYesTrue after a start/confirm; false after a stop.
already_trackedNo

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare destructiveHint=true, and the description explains concretely what is destroyed: passing enabled:false deletes the enrollment, equivalent to untrack_site. It also discloses prerequisites beyond the annotations — a $10/month Website Auditor subscription, 7-day trial, payment method required — which is exactly the kind of context an agent needs before calling.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose, then routing, then cost, and every clause carries information. It is slightly overlong and the parenthetical 'a history every audit already accrues, tracked or not' plus stacked em-dashes make one sentence harder to parse than it needs to be.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return values need no explanation, and the description covers the remaining agent needs: scheduling semantics, the stop path, the sibling alternative, and the subscription prerequisite.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents domain/cadence/enabled and the baseline is 3. The description adds real semantics on top by explaining the consequence of enabled:false (enrollment deletion) rather than merely repeating 'Set false to stop monitoring.'

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource with scope: 'Start (or stop) ongoing monitoring of a website's AI visibility on a schedule.' It differentiates from the one-off audit path and from untrack_site, so an agent can route correctly without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit trigger vocabulary ('monitor,' 'track,' 'watch,' 'get alerted about'), an explicit when-NOT ('not a one-off check,' 'not to make get_changes work'), and names the fallback path (untrack_site for stopping; get_sample_audit when there's no subscription).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

untrack_siteStop monitoringA
Destructive

Stop ongoing monitoring of a website's AI visibility. Use this when someone wants to "stop tracking," "unmonitor," "stop watching," or "remove" a site from scheduled monitoring, or to free up a monitoring slot. Removing a tracked site deletes its monitoring enrollment (its past audits are kept); calling it for a site that isn't tracked changes nothing. Returns how many monitoring slots are now free. Requires a Website Auditor subscription ($10/month; eligible new customers get a 7-day free trial — payment method required, no charge until the trial ends) — if the user doesn't have one, call get_sample_audit first to show them the exact output format, free and with no API key.

ParametersJSON Schema
NameRequiredDescriptionDefault
domainYesThe website domain, e.g. "example.com".

Output Schema

ParametersJSON Schema
NameRequiredDescription
usedNo
limitNo
domainYes
messageYes
removedYes
trackingYes
remainingNo

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already flag destructiveHint=true and readOnlyHint=false, and the description goes well beyond them: it discloses that past audits are retained, that calling it on an untracked site is a no-op, that it returns the number of free slots, and that a paid subscription is required. That is exactly the destructive/authorization/return context annotations alone cannot carry.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action and use cases, then consequences, then return value, then the subscription prerequisite. Dense and mostly waste-free; the pricing/trial sentence is long but serves a real routing decision (whether to redirect to get_sample_audit).

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return values need no exposition, yet the free-slot count is still surfaced. Prerequisites, idempotency, and data-retention behavior are all covered, leaving no gap an agent would need to guess at.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the single 'domain' parameter is fully documented there, so the description need not re-explain it. It reinforces that the target is a website/domain but adds no format or validation detail beyond the schema. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb+resource+scope: 'Stop ongoing monitoring of a website's AI visibility.' It is unambiguously the inverse of the sibling track_site, and an agent can pick between them without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit trigger phrases ('stop tracking,' 'unmonitor,' 'stop watching,' 'remove'), the slot-freeing motivation, and a routing rule for the non-subscriber case: call get_sample_audit first. When-to-use and when-to-do-something-else are both spelled out.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 1 tool updatev1.0.26
    • Changedget_recommendations8 fields changed
      • addedOutput schema / properties / recommendations / items / properties / evidence
        Added value: +{
        +  "additionalProperties": {},
        +  "type": "object"
        +}
      • addedOutput schema / properties / recommendations / items / properties / fix_id
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / recommendations / items / properties / id
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / recommendations / items / properties / locked
        Added value: +{
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / recommendations / items / properties / rank
        Added value: +{
        +  "type": "number"
        +}
      • addedOutput schema / properties / recommendations / items / properties / source
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / run_id
        Added value: +{
        +  "description": "The audit the steps come from.",
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
      • addedOutput schema / properties / tier
        Added value: +{
        +  "description": "Which list the API served. \"free\" omits where to get listed, what the assistants get wrong and each finding's fix file; its step marked `locked` only counts what Pro shows.",
        +  "enum": [
        +    "free",
        +    "pro"
        +  ],
        +  "type": "string"
        +}
  2. 4 tool updatesv1.0.25
    • Changedgenerate_schema3 fields changed
      • changedInput schema / properties / type / description
        Previous value: -"Schema type, or auto-detect."New value: +"Schema type; \"auto\" (also the default when omitted) does not detect anything — it returns an Organization draft."
      • changedOutput schema / properties / jsonld / description
        Previous value: -"The JSON-LD document, ready to paste into the site."New value: +"The JSON-LD draft (object or array). NOT ready to paste: every name field arrives as a placeholder — \"Your Business Name\" on the business types, and on a Product the product's own name and brand as \"Your Product Name\" and \"Brand Name\" — that the owner must replace with real names confirmed with them, never guessed from the domain or copied from an audit."
      • changedOutput schema / properties / placement_notes / description
        Previous value: -"Where to put the snippet, e.g. \"in the <head> of every page\"."New value: +"What to replace in the draft first — each name placeholder, confirmed with the owner — then where to embed the finished snippet, e.g. \"in the <head> of every page\". Relay the whole string, in that order: the replacement ask comes before the placement."
    • Changedget_ai_visibility1 field changed
      • changedOutput schema / properties / trend / anyOf
        Previous value: -[
        -  {
        -    "additionalProperties": true,
        -    "properties": {
        -      "change_30d": {
        -        "anyOf": [
        -          {
        -            "$ref": "#/properties/trend/anyOf/0/properties/change_7d/anyOf/0"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "change_7d": {
        -        "anyOf": [
        -          {
        -            "additionalProperties": true,
        -            "properties": {
        -              "engine_changes": {
        -                "items": {
        -                  "additionalProperties": true,
        -                  "properties": {
        -                    "delta": {
        -                      "type": "number"
        -                    },
        -                    "engine": {
        -                      "type": "string"
        -                    },
        -                    "from": {
        -                      "type": "number"
        -                    },
        -                    "to": {
        -                      "type": "number"
        -                    }
        -                  },
        -                  "required": [
        -                    "engine",
        -                    "from",
        -                    "to",
        -                    "delta"
        -                  ],
        -                  "type": "object"
        -                },
        -                "type": "array"
        -              },
        -              "from_captured_at": {
        -                "description": "When the snapshot this window compares against was captured.",
        -                "type": "string"
        -              },
        -              "from_score": {
        -                "type": "number"
        -              },
        -              "score_delta": {
        -                "type": "number"
        -              },
        -              "skipped_snapshots": {
        -                "description": "Snapshots in the window that were not compared: they asked a different question (another business name, market or queries), or do not record what they asked.",
        -                "type": "number"
        -              },
        -              "snapshots": {
        -                "description": "Snapshots that fell inside this window.",
        -                "type": "number"
        -              },
        -              "to_score": {
        -                "type": "number"
        -              },
        -              "window_days": {
        -                "type": "number"
        -              }
        -            },
        -            "required": [
        -              "window_days",
        -              "from_score",
        -              "to_score",
        -              "score_delta",
        -              "engine_changes",
        -              "snapshots"
        -            ],
        -            "type": "object"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Null when the window holds no earlier snapshot that asked the same question as the latest."
        -      },
        -      "includes_simulated": {
        -        "description": "Always false: simulated snapshots are left out of the trend. Kept for clients that read it.",
        -        "type": "boolean"
        -      },
        -      "latest_captured_at": {
        -        "type": "string"
        -      },
        -      "question_note": {
        -        "description": "Present when what the snapshots asked shaped the trend: no earlier snapshot asked the latest one's question, snapshots from the last 30 days were not compared, or the latest snapshot does not record what it asked. Relay it — a difference between scores that answered different questions is not a change in visibility.",
        -        "type": "string"
        -      },
        -      "snapshots_analyzed": {
        -        "type": "number"
        -      }
        -    },
        -    "required": [
        -      "change_7d",
        -      "change_30d",
        -      "snapshots_analyzed",
        -      "latest_captured_at",
        -      "includes_simulated"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": true,
        +    "properties": {
        +      "change_30d": {
        +        "anyOf": [
        +          {
        +            "$ref": "#/properties/trend/anyOf/0/properties/change_7d/anyOf/0"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "change_7d": {
        +        "anyOf": [
        +          {
        +            "additionalProperties": true,
        +            "properties": {
        +              "engine_changes": {
        +                "items": {
        +                  "additionalProperties": true,
        +                  "properties": {
        +                    "delta": {
        +                      "type": "number"
        +                    },
        +                    "engine": {
        +                      "type": "string"
        +                    },
        +                    "from": {
        +                      "type": "number"
        +                    },
        +                    "to": {
        +                      "type": "number"
        +                    }
        +                  },
        +                  "required": [
        +                    "engine",
        +                    "from",
        +                    "to",
        +                    "delta"
        +                  ],
        +                  "type": "object"
        +                },
        +                "type": "array"
        +              },
        +              "from_captured_at": {
        +                "description": "When the snapshot this window compares against was captured.",
        +                "type": "string"
        +              },
        +              "from_score": {
        +                "type": "number"
        +              },
        +              "overall_note": {
        +                "description": "Present exactly when score_delta is null: which engines answered each endpoint. Relay it — a null delta for this reason reads like one for want of history otherwise.",
        +                "type": "string"
        +              },
        +              "score_delta": {
        +                "description": "The overall move across the window, or null when its two endpoints were answered by different engines — an overall over a different set of engines is a different quantity. `overall_note` says which engines answered each; engine_changes still compares every engine that answered both.",
        +                "type": [
        +                  "number",
        +                  "null"
        +                ]
        +              },
        +              "skipped_snapshots": {
        +                "description": "Snapshots in the window that were not compared: they asked a different question (another business name, market or queries), or do not record what they asked.",
        +                "type": "number"
        +              },
        +              "snapshots": {
        +                "description": "Snapshots that fell inside this window.",
        +                "type": "number"
        +              },
        +              "to_score": {
        +                "type": "number"
        +              },
        +              "window_days": {
        +                "type": "number"
        +              }
        +            },
        +            "required": [
        +              "window_days",
        +              "from_score",
        +              "to_score",
        +              "score_delta",
        +              "engine_changes",
        +              "snapshots"
        +            ],
        +            "type": "object"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Null when the window holds no earlier snapshot that asked the same question as the latest."
        +      },
        +      "includes_simulated": {
        +        "description": "Always false: simulated snapshots are left out of the trend. Kept for clients that read it.",
        +        "type": "boolean"
        +      },
        +      "latest_captured_at": {
        +        "type": "string"
        +      },
        +      "question_note": {
        +        "description": "Present when what the snapshots asked shaped the trend: no earlier snapshot asked the latest one's question, snapshots from the last 30 days were not compared, or the latest snapshot does not record what it asked. Relay it — a difference between scores that answered different questions is not a change in visibility.",
        +        "type": "string"
        +      },
        +      "snapshots_analyzed": {
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "change_7d",
        +      "change_30d",
        +      "snapshots_analyzed",
        +      "latest_captured_at",
        +      "includes_simulated"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
    • Changedget_changes4 fields changed
      • changedOutput schema / properties / note / description
        Previous value: -"Present when skipped_snapshots is above 0, when newer measured snapshots were left out of the series, or when newer weekly re-audits measured nothing of the business: which, and why, in words. Relay it."New value: +"Present when skipped_snapshots is above 0, when the two snapshots compared were answered by different engines, when newer measured snapshots were left out of the series, or when newer weekly re-audits measured nothing of the business: which, and why, in words. Relay it."
      • addedOutput schema / properties / overall_note
        Added value: +{
        +  "description": "Present exactly when score_delta is null: the two snapshots were answered by different engines, and which answered each. Relay it — a null delta for this reason must not read like a null for want of history.",
        +  "type": "string"
        +}
      • changedOutput schema / properties / score_delta / description
        Previous value: -"Only ever between two snapshots that asked the same question. When there is no such pair, including a re-baseline after the business name, market or queries changed, the tool returns NOT_YET_AVAILABLE saying so, never a number."New value: +"Only ever between two snapshots that asked the same question AND were answered by the same engines. When there is no such pair, including a re-baseline after the business name, market or queries changed, the tool returns NOT_YET_AVAILABLE saying so, never a number; when the pair exists but different engines answered the two snapshots, the overall is not subtracted and is null with overall_note, and engine_changes still compares every engine that answered both."
      • changedOutput schema / properties / score_delta / type
        Previous value: -"number"New value: +[
        +  "number",
        +  "null"
        +]
    • Changedget_monitoring_status2 fields changed
      • changedOutput schema / properties / sites / items / properties / change / anyOf
        Previous value: -[
        -  {
        -    "additionalProperties": true,
        -    "properties": {
        -      "competitor_changes": {
        -        "description": "Always empty: AI-visibility snapshots record no competitors. Kept for clients that read it.",
        -        "items": {},
        -        "type": "array"
        -      },
        -      "engine_changes": {
        -        "items": {
        -          "additionalProperties": true,
        -          "properties": {
        -            "delta": {
        -              "type": "number"
        -            },
        -            "engine": {
        -              "type": "string"
        -            },
        -            "from": {
        -              "type": "number"
        -            },
        -            "to": {
        -              "type": "number"
        -            }
        -          },
        -          "required": [
        -            "engine",
        -            "from",
        -            "to",
        -            "delta"
        -          ],
        -          "type": "object"
        -        },
        -        "type": "array"
        -      },
        -      "from_captured_at": {
        -        "description": "When the earlier snapshot compared was captured.",
        -        "type": "string"
        -      },
        -      "new_issues": {
        -        "description": "Always empty: AI-visibility snapshots record no audit issues. Kept for clients that read it.",
        -        "items": {},
        -        "type": "array"
        -      },
        -      "resolved_issues": {
        -        "description": "Always empty: AI-visibility snapshots record no audit issues. Kept for clients that read it.",
        -        "items": {},
        -        "type": "array"
        -      },
        -      "score_delta": {
        -        "type": "number"
        -      },
        -      "skipped_snapshots": {
        -        "description": "Snapshots passed over because they asked a different question (another business name, market or queries) or do not record what they asked.",
        -        "type": "number"
        -      },
        -      "to_captured_at": {
        -        "description": "When the later one was.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "score_delta",
        -      "engine_changes",
        -      "competitor_changes",
        -      "new_issues",
        -      "resolved_issues"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": true,
        +    "properties": {
        +      "competitor_changes": {
        +        "description": "Always empty: AI-visibility snapshots record no competitors. Kept for clients that read it.",
        +        "items": {},
        +        "type": "array"
        +      },
        +      "engine_changes": {
        +        "items": {
        +          "additionalProperties": true,
        +          "properties": {
        +            "delta": {
        +              "type": "number"
        +            },
        +            "engine": {
        +              "type": "string"
        +            },
        +            "from": {
        +              "type": "number"
        +            },
        +            "to": {
        +              "type": "number"
        +            }
        +          },
        +          "required": [
        +            "engine",
        +            "from",
        +            "to",
        +            "delta"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "from_captured_at": {
        +        "description": "When the earlier snapshot compared was captured.",
        +        "type": "string"
        +      },
        +      "new_issues": {
        +        "description": "Always empty: AI-visibility snapshots record no audit issues. Kept for clients that read it.",
        +        "items": {},
        +        "type": "array"
        +      },
        +      "overall_note": {
        +        "description": "Present exactly when score_delta is null: which engines answered each snapshot. Relay it.",
        +        "type": "string"
        +      },
        +      "resolved_issues": {
        +        "description": "Always empty: AI-visibility snapshots record no audit issues. Kept for clients that read it.",
        +        "items": {},
        +        "type": "array"
        +      },
        +      "score_delta": {
        +        "description": "The overall move, or null when the two snapshots were answered by different engines: the overall is computed over the engines that answered, so an overall over a different set of engines is a different quantity and is not subtracted. `overall_note` says which engines answered each; engine_changes still compares every engine that answered both.",
        +        "type": [
        +          "number",
        +          "null"
        +        ]
        +      },
        +      "skipped_snapshots": {
        +        "description": "Snapshots passed over because they asked a different question (another business name, market or queries) or do not record what they asked.",
        +        "type": "number"
        +      },
        +      "to_captured_at": {
        +        "description": "When the later one was.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "score_delta",
        +      "engine_changes",
        +      "competitor_changes",
        +      "new_issues",
        +      "resolved_issues"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / properties / sites / items / properties / note / description
        Previous value: -"Present when there is no like-for-like change because of a re-baseline or snapshots that do not record what they asked, or when snapshots were passed over: why, in words. Relay it."New value: +"Present when there is no like-for-like change because of a re-baseline or snapshots that do not record what they asked, when snapshots were passed over, or when the change shown has no overall because different engines answered the two snapshots: why, in words. Relay it."
  3. 4 tool updatesv1.0.24
    • Changedget_ai_visibility1 field changed
      • changedOutput schema / properties / trend / anyOf
        Previous value: -[
        -  {
        -    "additionalProperties": true,
        -    "properties": {
        -      "change_30d": {
        -        "anyOf": [
        -          {
        -            "$ref": "#/properties/trend/anyOf/0/properties/change_7d/anyOf/0"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "change_7d": {
        -        "anyOf": [
        -          {
        -            "additionalProperties": true,
        -            "properties": {
        -              "engine_changes": {
        -                "items": {
        -                  "additionalProperties": true,
        -                  "properties": {
        -                    "delta": {
        -                      "type": "number"
        -                    },
        -                    "engine": {
        -                      "type": "string"
        -                    },
        -                    "from": {
        -                      "type": "number"
        -                    },
        -                    "to": {
        -                      "type": "number"
        -                    }
        -                  },
        -                  "required": [
        -                    "engine",
        -                    "from",
        -                    "to",
        -                    "delta"
        -                  ],
        -                  "type": "object"
        -                },
        -                "type": "array"
        -              },
        -              "from_score": {
        -                "type": "number"
        -              },
        -              "score_delta": {
        -                "type": "number"
        -              },
        -              "snapshots": {
        -                "description": "Snapshots that fell inside this window.",
        -                "type": "number"
        -              },
        -              "to_score": {
        -                "type": "number"
        -              },
        -              "window_days": {
        -                "type": "number"
        -              }
        -            },
        -            "required": [
        -              "window_days",
        -              "from_score",
        -              "to_score",
        -              "score_delta",
        -              "engine_changes",
        -              "snapshots"
        -            ],
        -            "type": "object"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Null when fewer than two snapshots fall in the window."
        -      },
        -      "includes_simulated": {
        -        "description": "True if any analyzed snapshot was estimated rather than measured.",
        -        "type": "boolean"
        -      },
        -      "latest_captured_at": {
        -        "type": "string"
        -      },
        -      "snapshots_analyzed": {
        -        "type": "number"
        -      }
        -    },
        -    "required": [
        -      "change_7d",
        -      "change_30d",
        -      "snapshots_analyzed",
        -      "latest_captured_at",
        -      "includes_simulated"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": true,
        +    "properties": {
        +      "change_30d": {
        +        "anyOf": [
        +          {
        +            "$ref": "#/properties/trend/anyOf/0/properties/change_7d/anyOf/0"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "change_7d": {
        +        "anyOf": [
        +          {
        +            "additionalProperties": true,
        +            "properties": {
        +              "engine_changes": {
        +                "items": {
        +                  "additionalProperties": true,
        +                  "properties": {
        +                    "delta": {
        +                      "type": "number"
        +                    },
        +                    "engine": {
        +                      "type": "string"
        +                    },
        +                    "from": {
        +                      "type": "number"
        +                    },
        +                    "to": {
        +                      "type": "number"
        +                    }
        +                  },
        +                  "required": [
        +                    "engine",
        +                    "from",
        +                    "to",
        +                    "delta"
        +                  ],
        +                  "type": "object"
        +                },
        +                "type": "array"
        +              },
        +              "from_captured_at": {
        +                "description": "When the snapshot this window compares against was captured.",
        +                "type": "string"
        +              },
        +              "from_score": {
        +                "type": "number"
        +              },
        +              "score_delta": {
        +                "type": "number"
        +              },
        +              "skipped_snapshots": {
        +                "description": "Snapshots in the window that were not compared: they asked a different question (another business name, market or queries), or do not record what they asked.",
        +                "type": "number"
        +              },
        +              "snapshots": {
        +                "description": "Snapshots that fell inside this window.",
        +                "type": "number"
        +              },
        +              "to_score": {
        +                "type": "number"
        +              },
        +              "window_days": {
        +                "type": "number"
        +              }
        +            },
        +            "required": [
        +              "window_days",
        +              "from_score",
        +              "to_score",
        +              "score_delta",
        +              "engine_changes",
        +              "snapshots"
        +            ],
        +            "type": "object"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Null when the window holds no earlier snapshot that asked the same question as the latest."
        +      },
        +      "includes_simulated": {
        +        "description": "Always false: simulated snapshots are left out of the trend. Kept for clients that read it.",
        +        "type": "boolean"
        +      },
        +      "latest_captured_at": {
        +        "type": "string"
        +      },
        +      "question_note": {
        +        "description": "Present when what the snapshots asked shaped the trend: no earlier snapshot asked the latest one's question, snapshots from the last 30 days were not compared, or the latest snapshot does not record what it asked. Relay it — a difference between scores that answered different questions is not a change in visibility.",
        +        "type": "string"
        +      },
        +      "snapshots_analyzed": {
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "change_7d",
        +      "change_30d",
        +      "snapshots_analyzed",
        +      "latest_captured_at",
        +      "includes_simulated"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
    • Changedget_changes8 fields changed
      • addedOutput schema / properties / competitor_changes / description
        Added value: +"Always empty: AI-visibility snapshots record no competitors. Kept for clients that read it."
      • addedOutput schema / properties / from_captured_at
        Added value: +{
        +  "description": "When the earlier snapshot compared was captured.",
        +  "type": "string"
        +}
      • addedOutput schema / properties / new_issues / description
        Added value: +"Always empty: AI-visibility snapshots record no audit issues. Kept for clients that read it."
      • addedOutput schema / properties / note
        Added value: +{
        +  "description": "Present when skipped_snapshots is above 0, when newer measured snapshots were left out of the series, or when newer weekly re-audits measured nothing of the business: which, and why, in words. Relay it.",
        +  "type": "string"
        +}
      • addedOutput schema / properties / resolved_issues / description
        Added value: +"Always empty: AI-visibility snapshots record no audit issues. Kept for clients that read it."
      • addedOutput schema / properties / score_delta / description
        Added value: +"Only ever between two snapshots that asked the same question. When there is no such pair, including a re-baseline after the business name, market or queries changed, the tool returns NOT_YET_AVAILABLE saying so, never a number."
      • addedOutput schema / properties / skipped_snapshots
        Added value: +{
        +  "description": "Snapshots passed over because they asked a different question (another business name, market or queries) or do not record what they asked.",
        +  "type": "number"
        +}
      • addedOutput schema / properties / to_captured_at
        Added value: +{
        +  "description": "When the later one was.",
        +  "type": "string"
        +}
    • Changedget_monitoring_status4 fields changed
      • changedOutput schema / properties / sites / items / properties / change / anyOf
        Previous value: -[
        -  {
        -    "additionalProperties": true,
        -    "properties": {
        -      "competitor_changes": {
        -        "items": {},
        -        "type": "array"
        -      },
        -      "engine_changes": {
        -        "items": {
        -          "additionalProperties": true,
        -          "properties": {
        -            "delta": {
        -              "type": "number"
        -            },
        -            "engine": {
        -              "type": "string"
        -            },
        -            "from": {
        -              "type": "number"
        -            },
        -            "to": {
        -              "type": "number"
        -            }
        -          },
        -          "required": [
        -            "engine",
        -            "from",
        -            "to",
        -            "delta"
        -          ],
        -          "type": "object"
        -        },
        -        "type": "array"
        -      },
        -      "new_issues": {
        -        "items": {},
        -        "type": "array"
        -      },
        -      "resolved_issues": {
        -        "items": {},
        -        "type": "array"
        -      },
        -      "score_delta": {
        -        "type": "number"
        -      }
        -    },
        -    "required": [
        -      "score_delta",
        -      "engine_changes",
        -      "competitor_changes",
        -      "new_issues",
        -      "resolved_issues"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": true,
        +    "properties": {
        +      "competitor_changes": {
        +        "description": "Always empty: AI-visibility snapshots record no competitors. Kept for clients that read it.",
        +        "items": {},
        +        "type": "array"
        +      },
        +      "engine_changes": {
        +        "items": {
        +          "additionalProperties": true,
        +          "properties": {
        +            "delta": {
        +              "type": "number"
        +            },
        +            "engine": {
        +              "type": "string"
        +            },
        +            "from": {
        +              "type": "number"
        +            },
        +            "to": {
        +              "type": "number"
        +            }
        +          },
        +          "required": [
        +            "engine",
        +            "from",
        +            "to",
        +            "delta"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "from_captured_at": {
        +        "description": "When the earlier snapshot compared was captured.",
        +        "type": "string"
        +      },
        +      "new_issues": {
        +        "description": "Always empty: AI-visibility snapshots record no audit issues. Kept for clients that read it.",
        +        "items": {},
        +        "type": "array"
        +      },
        +      "resolved_issues": {
        +        "description": "Always empty: AI-visibility snapshots record no audit issues. Kept for clients that read it.",
        +        "items": {},
        +        "type": "array"
        +      },
        +      "score_delta": {
        +        "type": "number"
        +      },
        +      "skipped_snapshots": {
        +        "description": "Snapshots passed over because they asked a different question (another business name, market or queries) or do not record what they asked.",
        +        "type": "number"
        +      },
        +      "to_captured_at": {
        +        "description": "When the later one was.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "score_delta",
        +      "engine_changes",
        +      "competitor_changes",
        +      "new_issues",
        +      "resolved_issues"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / properties / sites / items / properties / change / description
        Previous value: -"Latest vs previous snapshot; null if fewer than two."New value: +"The latest change against the most recent earlier snapshot that asked the same question; null when there is none — no scored latest snapshot (the summary says why), a first snapshot, a re-baseline, or snapshots that do not record what they asked."
      • addedOutput schema / properties / sites / items / properties / last_audited_at / description
        Added value: +"The date of the last scheduled run, stamped when the scheduler claims it and before the audit runs. It does not say how that run ended: it may still be going, or may have failed, been skipped or measured nothing of the business."
      • addedOutput schema / properties / sites / items / properties / note
        Added value: +{
        +  "description": "Present when there is no like-for-like change because of a re-baseline or snapshots that do not record what they asked, or when snapshots were passed over: why, in words. Relay it.",
        +  "type": "string"
        +}
    • Changedlist_tracked_sites1 field changed
      • addedOutput schema / properties / tracked / items / properties / last_audited_at / description
        Added value: +"The date of the last scheduled run, stamped when the scheduler claims it and before the audit runs. It does not say how that run ended: it may still be going, or may have failed, been skipped or measured nothing of the business."
  4. 15 tool updatesv1.0.23
    • Changedcheck_upgrade_status1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "cancel_at_period_end": {
        +      "type": "boolean"
        +    },
        +    "current_period_end": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "status": {
        +      "description": "Raw subscription status: active, trialing, canceled, none, …",
        +      "type": "string"
        +    },
        +    "tier": {
        +      "description": "\"none\" | \"free\" | \"pro\".",
        +      "type": "string"
        +    },
        +    "upgrade_url": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "tier",
        +    "status",
        +    "current_period_end",
        +    "cancel_at_period_end",
        +    "upgrade_url",
        +    "message"
        +  ],
        +  "type": "object"
        +}
    • Changedcompare_competitors2 fields changed
      • addedInput schema / properties / business_location
        Added value: +{
        +  "description": "Optional. The market to compare within, e.g. \"Chiang Mai, Thailand\". Applied to the site AND every competitor, because a comparison asks about one market — scoring one locally and the others globally would rank answers to two different questions. Leave it out and each audit detects its own location, which is right for national or global businesses and wrong for local ones.",
        +  "type": "string"
        +}
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "gaps": {
        +      "description": "Engines where a competitor appears in AI answers and this site does not.",
        +      "items": {
        +        "additionalProperties": true,
        +        "properties": {
        +          "competitor": {
        +            "type": "string"
        +          },
        +          "engine": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "engine",
        +          "competitor"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "market": {
        +      "description": "The market every audit in this comparison was scored in, or null when each domain's own location was detected.",
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "quota": {
        +      "additionalProperties": true,
        +      "properties": {
        +        "audits_skipped": {
        +          "description": "Competitors skipped because the daily quota ran out.",
        +          "type": "number"
        +        },
        +        "audits_used": {
        +          "description": "Fresh audits actually spent by this call.",
        +          "type": "number"
        +        },
        +        "cached_reused": {
        +          "description": "Domains served from a recent cached audit; cost no quota.",
        +          "type": "number"
        +        },
        +        "limit": {
        +          "type": [
        +            "number",
        +            "null"
        +          ]
        +        },
        +        "remaining": {
        +          "type": [
        +            "number",
        +            "null"
        +          ]
        +        },
        +        "reset": {
        +          "type": [
        +            "string",
        +            "null"
        +          ]
        +        }
        +      },
        +      "required": [
        +        "limit",
        +        "remaining",
        +        "audits_used",
        +        "audits_skipped",
        +        "cached_reused",
        +        "reset"
        +      ],
        +      "type": "object"
        +    },
        +    "ranking": {
        +      "items": {
        +        "additionalProperties": true,
        +        "properties": {
        +          "domain": {
        +            "type": "string"
        +          },
        +          "note": {
        +            "type": "string"
        +          },
        +          "score": {
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          }
        +        },
        +        "required": [
        +          "domain",
        +          "score"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "skipped": {
        +      "items": {
        +        "additionalProperties": true,
        +        "properties": {
        +          "detail": {
        +            "type": "string"
        +          },
        +          "domain": {
        +            "type": "string"
        +          },
        +          "reason": {
        +            "description": "\"quota\" | \"unreachable\" | \"error\".",
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "domain",
        +          "reason"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "summary": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "ranking",
        +    "gaps",
        +    "quota",
        +    "skipped",
        +    "summary",
        +    "market"
        +  ],
        +  "type": "object"
        +}
    • Changedgenerate_schema1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "jsonld": {
        +      "description": "The JSON-LD document, ready to paste into the site."
        +    },
        +    "placement_notes": {
        +      "description": "Where to put the snippet, e.g. \"in the <head> of every page\".",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "placement_notes"
        +  ],
        +  "type": "object"
        +}
    • Changedget_ai_visibility1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "appears_by_engine": {
        +      "additionalProperties": true,
        +      "description": "Whether the site appeared at all on each engine. Distinct from the scores: an engine can have appearances yet a low score, or the reverse. NULL when the engine was not scored — false would assert it did not name the business, which is a claim an unmeasured engine cannot support.",
        +      "properties": {
        +        "chatgpt": {
        +          "type": [
        +            "boolean",
        +            "null"
        +          ]
        +        },
        +        "claude": {
        +          "type": [
        +            "boolean",
        +            "null"
        +          ]
        +        },
        +        "gemini": {
        +          "type": [
        +            "boolean",
        +            "null"
        +          ]
        +        },
        +        "perplexity": {
        +          "type": [
        +            "boolean",
        +            "null"
        +          ]
        +        }
        +      },
        +      "required": [
        +        "chatgpt",
        +        "perplexity",
        +        "claude",
        +        "gemini"
        +      ],
        +      "type": "object"
        +    },
        +    "by_engine": {
        +      "additionalProperties": true,
        +      "description": "Per-engine AI-visibility score, 0–100. NULL means the engine was not scored — see engine_status for which of the two reasons. A null is NOT a zero: zero means the engine answered and never named the business.",
        +      "properties": {
        +        "chatgpt": {
        +          "type": [
        +            "number",
        +            "null"
        +          ]
        +        },
        +        "claude": {
        +          "type": [
        +            "number",
        +            "null"
        +          ]
        +        },
        +        "gemini": {
        +          "type": [
        +            "number",
        +            "null"
        +          ]
        +        },
        +        "perplexity": {
        +          "type": [
        +            "number",
        +            "null"
        +          ]
        +        }
        +      },
        +      "required": [
        +        "chatgpt",
        +        "perplexity",
        +        "claude",
        +        "gemini"
        +      ],
        +      "type": "object"
        +    },
        +    "coverage_note": {
        +      "description": "Present exactly when an engine was asked and did not answer. Relay it: the score covers fewer engines than the four this tool can query.",
        +      "type": "string"
        +    },
        +    "engine_status": {
        +      "additionalProperties": true,
        +      "description": "Why each engine's score is what it is. 'scored' — the engine answered and the number is a measurement. 'unanswered' — it was asked and returned nothing, so there is no score; do not report it as 0. 'not_asked' — it was not part of this run at all.",
        +      "properties": {
        +        "chatgpt": {
        +          "enum": [
        +            "scored",
        +            "unanswered",
        +            "not_asked"
        +          ],
        +          "type": "string"
        +        },
        +        "claude": {
        +          "enum": [
        +            "scored",
        +            "unanswered",
        +            "not_asked"
        +          ],
        +          "type": "string"
        +        },
        +        "gemini": {
        +          "enum": [
        +            "scored",
        +            "unanswered",
        +            "not_asked"
        +          ],
        +          "type": "string"
        +        },
        +        "perplexity": {
        +          "enum": [
        +            "scored",
        +            "unanswered",
        +            "not_asked"
        +          ],
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "chatgpt",
        +        "perplexity",
        +        "claude",
        +        "gemini"
        +      ],
        +      "type": "object"
        +    },
        +    "name_source": {
        +      "description": "\"detected\" | \"user_supplied\" | \"domain_fallback\".",
        +      "type": "string"
        +    },
        +    "name_verified": {
        +      "type": "boolean"
        +    },
        +    "name_warning": {
        +      "description": "Set ONLY when the business name behind the score could not be verified. The score is computed from queries built around that name, so relay this caveat rather than presenting the score as settled.",
        +      "type": "string"
        +    },
        +    "score": {
        +      "description": "Overall AI-visibility score, 0–100.",
        +      "type": "number"
        +    },
        +    "sources": {
        +      "anyOf": [
        +        {
        +          "items": {
        +            "additionalProperties": true,
        +            "properties": {
        +              "answers": {
        +                "description": "Answers citing this domain — not citation entries.",
        +                "type": "number"
        +              },
        +              "domain": {
        +                "type": "string"
        +              },
        +              "ownership": {
        +                "description": "\"yours\" | \"competitor\" | \"third_party\". Competitor rows are context, not targets.",
        +                "type": "string"
        +              },
        +              "platforms": {
        +                "items": {
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              },
        +              "title": {
        +                "type": "string"
        +              },
        +              "url": {
        +                "type": [
        +                  "string",
        +                  "null"
        +                ]
        +              }
        +            },
        +            "required": [
        +              "domain",
        +              "answers",
        +              "platforms",
        +              "ownership",
        +              "url",
        +              "title"
        +            ],
        +            "type": "object"
        +          },
        +          "type": "array"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "summary": {
        +      "type": "string"
        +    },
        +    "top_competitor": {
        +      "description": "The competitor appearing in place of the site, if any.",
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "trend": {
        +      "anyOf": [
        +        {
        +          "additionalProperties": true,
        +          "properties": {
        +            "change_30d": {
        +              "anyOf": [
        +                {
        +                  "$ref": "#/properties/trend/anyOf/0/properties/change_7d/anyOf/0"
        +                },
        +                {
        +                  "type": "null"
        +                }
        +              ]
        +            },
        +            "change_7d": {
        +              "anyOf": [
        +                {
        +                  "additionalProperties": true,
        +                  "properties": {
        +                    "engine_changes": {
        +                      "items": {
        +                        "additionalProperties": true,
        +                        "properties": {
        +                          "delta": {
        +                            "type": "number"
        +                          },
        +                          "engine": {
        +                            "type": "string"
        +                          },
        +                          "from": {
        +                            "type": "number"
        +                          },
        +                          "to": {
        +                            "type": "number"
        +                          }
        +                        },
        +                        "required": [
        +                          "engine",
        +                          "from",
        +                          "to",
        +                          "delta"
        +                        ],
        +                        "type": "object"
        +                      },
        +                      "type": "array"
        +                    },
        +                    "from_score": {
        +                      "type": "number"
        +                    },
        +                    "score_delta": {
        +                      "type": "number"
        +                    },
        +                    "snapshots": {
        +                      "description": "Snapshots that fell inside this window.",
        +                      "type": "number"
        +                    },
        +                    "to_score": {
        +                      "type": "number"
        +                    },
        +                    "window_days": {
        +                      "type": "number"
        +                    }
        +                  },
        +                  "required": [
        +                    "window_days",
        +                    "from_score",
        +                    "to_score",
        +                    "score_delta",
        +                    "engine_changes",
        +                    "snapshots"
        +                  ],
        +                  "type": "object"
        +                },
        +                {
        +                  "type": "null"
        +                }
        +              ],
        +              "description": "Null when fewer than two snapshots fall in the window."
        +            },
        +            "includes_simulated": {
        +              "description": "True if any analyzed snapshot was estimated rather than measured.",
        +              "type": "boolean"
        +            },
        +            "latest_captured_at": {
        +              "type": "string"
        +            },
        +            "snapshots_analyzed": {
        +              "type": "number"
        +            }
        +          },
        +          "required": [
        +            "change_7d",
        +            "change_30d",
        +            "snapshots_analyzed",
        +            "latest_captured_at",
        +            "includes_simulated"
        +          ],
        +          "type": "object"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "description": "Pro only; null when unavailable — trend_note says why."
        +    },
        +    "trend_note": {
        +      "description": "Present exactly when trend is null: the reason.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "score",
        +    "by_engine",
        +    "engine_status",
        +    "appears_by_engine",
        +    "top_competitor",
        +    "summary",
        +    "trend"
        +  ],
        +  "type": "object"
        +}
    • Changedget_benchmark1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "peer_median": {
        +      "type": "number"
        +    },
        +    "percentile": {
        +      "description": "The domain's percentile within its industry/geo peer set, 0–100.",
        +      "type": "number"
        +    },
        +    "position_summary": {
        +      "type": "string"
        +    },
        +    "sample_size": {
        +      "description": "How many peers the percentile and median are computed over.",
        +      "type": "number"
        +    }
        +  },
        +  "required": [
        +    "percentile",
        +    "peer_median",
        +    "sample_size",
        +    "position_summary"
        +  ],
        +  "type": "object"
        +}
    • Changedget_changes1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "competitor_changes": {
        +      "items": {},
        +      "type": "array"
        +    },
        +    "engine_changes": {
        +      "items": {
        +        "additionalProperties": true,
        +        "properties": {
        +          "delta": {
        +            "type": "number"
        +          },
        +          "engine": {
        +            "type": "string"
        +          },
        +          "from": {
        +            "type": "number"
        +          },
        +          "to": {
        +            "type": "number"
        +          }
        +        },
        +        "required": [
        +          "engine",
        +          "from",
        +          "to",
        +          "delta"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "new_issues": {
        +      "items": {},
        +      "type": "array"
        +    },
        +    "resolved_issues": {
        +      "items": {},
        +      "type": "array"
        +    },
        +    "score_delta": {
        +      "type": "number"
        +    }
        +  },
        +  "required": [
        +    "score_delta",
        +    "engine_changes",
        +    "competitor_changes",
        +    "new_issues",
        +    "resolved_issues"
        +  ],
        +  "type": "object"
        +}
    • Changedget_gtm_plan1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "domain": {
        +      "type": "string"
        +    },
        +    "evidence_note": {
        +      "description": "Additive, never an error: set when the plan had no citation evidence.",
        +      "type": "string"
        +    },
        +    "model": {
        +      "type": "string"
        +    },
        +    "plan": {
        +      "additionalProperties": true,
        +      "properties": {
        +        "markdown": {
        +          "type": "string"
        +        },
        +        "phases": {
        +          "description": "The same plan as `markdown`, cut into 30/60/90-day cards — a rendering, never extra content. An empty array means this plan was not written in card form: render `markdown` instead, and do not report it as a plan without actions. The key being absent means the plan came from a build that predates the cards, which is also not a claim about the plan.",
        +          "items": {
        +            "additionalProperties": true,
        +            "properties": {
        +              "actions": {
        +                "description": "Empty for a phase the plan wrote as prose. That is a real plan with nothing cut into cards for this band, not a plan with nothing in it.",
        +                "items": {
        +                  "additionalProperties": true,
        +                  "properties": {
        +                    "effort": {
        +                      "description": "The plan's own effort estimate, or null when it did not give one. Null means unknown — never render a substitute.",
        +                      "type": [
        +                        "string",
        +                        "null"
        +                      ]
        +                    },
        +                    "goal": {
        +                      "type": [
        +                        "string",
        +                        "null"
        +                      ]
        +                    },
        +                    "priority": {
        +                      "description": "Typically \"High\" or \"Medium\"; null when the plan gave none or gave one outside the two the engine keeps. Upstream text, so not an enum here.",
        +                      "type": [
        +                        "string",
        +                        "null"
        +                      ]
        +                    },
        +                    "steps": {
        +                      "description": "How to apply it, in order. May be empty.",
        +                      "items": {
        +                        "type": "string"
        +                      },
        +                      "type": "array"
        +                    },
        +                    "title": {
        +                      "type": "string"
        +                    },
        +                    "why": {
        +                      "type": [
        +                        "string",
        +                        "null"
        +                      ]
        +                    }
        +                  },
        +                  "type": "object"
        +                },
        +                "type": "array"
        +              },
        +              "focus": {
        +                "type": [
        +                  "string",
        +                  "null"
        +                ]
        +              },
        +              "headline": {
        +                "type": [
        +                  "string",
        +                  "null"
        +                ]
        +              },
        +              "name": {
        +                "type": "string"
        +              },
        +              "phase": {
        +                "description": "30, 60 or 90 — the day the band closes.",
        +                "type": "number"
        +              },
        +              "range": {
        +                "description": "The band as the engine names it, e.g. \"Days 1–30\".",
        +                "type": "string"
        +              },
        +              "short": {
        +                "type": "string"
        +              }
        +            },
        +            "type": "object"
        +          },
        +          "type": "array"
        +        },
        +        "sections": {
        +          "items": {
        +            "additionalProperties": true,
        +            "properties": {
        +              "body_lines": {
        +                "items": {
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              },
        +              "title": {
        +                "type": "string"
        +              }
        +            },
        +            "type": "object"
        +          },
        +          "type": "array"
        +        }
        +      },
        +      "required": [
        +        "markdown",
        +        "sections"
        +      ],
        +      "type": "object"
        +    },
        +    "sources_used": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "summary": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "domain",
        +    "plan",
        +    "sources_used",
        +    "model",
        +    "summary"
        +  ],
        +  "type": "object"
        +}
    • Changedget_monitoring_status1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "limit": {
        +      "type": "number"
        +    },
        +    "remaining": {
        +      "type": "number"
        +    },
        +    "sites": {
        +      "items": {
        +        "additionalProperties": true,
        +        "properties": {
        +          "active": {
        +            "type": "boolean"
        +          },
        +          "cadence": {
        +            "type": "string"
        +          },
        +          "change": {
        +            "anyOf": [
        +              {
        +                "additionalProperties": true,
        +                "properties": {
        +                  "competitor_changes": {
        +                    "items": {},
        +                    "type": "array"
        +                  },
        +                  "engine_changes": {
        +                    "items": {
        +                      "additionalProperties": true,
        +                      "properties": {
        +                        "delta": {
        +                          "type": "number"
        +                        },
        +                        "engine": {
        +                          "type": "string"
        +                        },
        +                        "from": {
        +                          "type": "number"
        +                        },
        +                        "to": {
        +                          "type": "number"
        +                        }
        +                      },
        +                      "required": [
        +                        "engine",
        +                        "from",
        +                        "to",
        +                        "delta"
        +                      ],
        +                      "type": "object"
        +                    },
        +                    "type": "array"
        +                  },
        +                  "new_issues": {
        +                    "items": {},
        +                    "type": "array"
        +                  },
        +                  "resolved_issues": {
        +                    "items": {},
        +                    "type": "array"
        +                  },
        +                  "score_delta": {
        +                    "type": "number"
        +                  }
        +                },
        +                "required": [
        +                  "score_delta",
        +                  "engine_changes",
        +                  "competitor_changes",
        +                  "new_issues",
        +                  "resolved_issues"
        +                ],
        +                "type": "object"
        +              },
        +              {
        +                "type": "null"
        +              }
        +            ],
        +            "description": "Latest vs previous snapshot; null if fewer than two."
        +          },
        +          "domain": {
        +            "type": "string"
        +          },
        +          "last_audited_at": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "latest_score": {
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "next_run_at": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "summary": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "domain",
        +          "latest_score",
        +          "change",
        +          "summary"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "summary": {
        +      "type": "string"
        +    },
        +    "used": {
        +      "type": "number"
        +    }
        +  },
        +  "required": [
        +    "limit",
        +    "used",
        +    "remaining",
        +    "sites",
        +    "summary"
        +  ],
        +  "type": "object"
        +}
    • Changedget_recommendations1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "recommendations": {
        +      "items": {
        +        "additionalProperties": true,
        +        "properties": {
        +          "action": {
        +            "type": "string"
        +          },
        +          "effort": {
        +            "type": "string"
        +          },
        +          "expected_impact": {
        +            "type": "string"
        +          },
        +          "why": {
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "recommendations"
        +  ],
        +  "type": "object"
        +}
    • Changedget_report1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "badge_html": {
        +      "type": "string"
        +    },
        +    "report_url": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "report_url",
        +    "badge_html"
        +  ],
        +  "type": "object"
        +}
    • Changedget_sample_audit1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "audit": {
        +      "additionalProperties": true,
        +      "description": "A real GET /api/audit payload, populated with sample data.",
        +      "properties": {
        +        "ai_visibility": {},
        +        "base_url": {
        +          "type": "string"
        +        },
        +        "results": {
        +          "items": {},
        +          "type": "array"
        +        },
        +        "run_id": {
        +          "type": "string"
        +        },
        +        "status": {
        +          "type": "string"
        +        },
        +        "summary": {}
        +      },
        +      "type": "object"
        +    },
        +    "domain": {
        +      "description": "The fixed sample domain. Never the caller's own.",
        +      "type": "string"
        +    },
        +    "is_sample": {
        +      "const": true,
        +      "description": "Always true. Never present this as a live result.",
        +      "type": "boolean"
        +    },
        +    "note": {
        +      "type": "string"
        +    },
        +    "price": {
        +      "type": "string"
        +    },
        +    "upgrade_url": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "is_sample",
        +    "domain",
        +    "note",
        +    "audit",
        +    "price",
        +    "upgrade_url"
        +  ],
        +  "type": "object"
        +}
    • Changedlist_tracked_sites1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "limit": {
        +      "type": "number"
        +    },
        +    "remaining": {
        +      "type": "number"
        +    },
        +    "summary": {
        +      "type": "string"
        +    },
        +    "tracked": {
        +      "items": {
        +        "additionalProperties": true,
        +        "properties": {
        +          "active": {
        +            "type": "boolean"
        +          },
        +          "cadence": {
        +            "type": "string"
        +          },
        +          "created_at": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "digest_enabled": {
        +            "type": "boolean"
        +          },
        +          "domain": {
        +            "type": "string"
        +          },
        +          "last_audited_at": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "next_run_at": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          }
        +        },
        +        "required": [
        +          "domain"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "used": {
        +      "type": "number"
        +    }
        +  },
        +  "required": [
        +    "limit",
        +    "used",
        +    "remaining",
        +    "tracked",
        +    "summary"
        +  ],
        +  "type": "object"
        +}
    • Changedrun_audit1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "name_warning": {
        +      "description": "Set ONLY when the business name could not be verified, which puts the AI-visibility score in question.",
        +      "type": "string"
        +    },
        +    "report_url": {
        +      "type": "string"
        +    },
        +    "scores": {
        +      "additionalProperties": true,
        +      "properties": {
        +        "ai_visibility": {
        +          "type": [
        +            "number",
        +            "null"
        +          ]
        +        },
        +        "performance": {
        +          "type": [
        +            "number",
        +            "null"
        +          ]
        +        },
        +        "security": {
        +          "type": [
        +            "number",
        +            "null"
        +          ]
        +        },
        +        "seo": {
        +          "type": [
        +            "number",
        +            "null"
        +          ]
        +        }
        +      },
        +      "required": [
        +        "ai_visibility",
        +        "seo",
        +        "security",
        +        "performance"
        +      ],
        +      "type": "object"
        +    },
        +    "top_issues": {
        +      "items": {
        +        "additionalProperties": true,
        +        "properties": {
        +          "details": {
        +            "type": "string"
        +          },
        +          "module": {
        +            "type": "string"
        +          },
        +          "name": {
        +            "type": "string"
        +          },
        +          "recommendation": {
        +            "type": "string"
        +          },
        +          "severity": {
        +            "type": "string"
        +          },
        +          "url": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "severity"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "scores",
        +    "top_issues",
        +    "report_url"
        +  ],
        +  "type": "object"
        +}
    • Changedtrack_site1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "already_tracked": {
        +      "type": "boolean"
        +    },
        +    "cadence": {
        +      "type": "string"
        +    },
        +    "created": {
        +      "description": "Present when starting: whether this call created a new tracking.",
        +      "type": "boolean"
        +    },
        +    "domain": {
        +      "type": "string"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "removed": {
        +      "description": "Present when stopping.",
        +      "type": "boolean"
        +    },
        +    "tracking": {
        +      "description": "True after a start/confirm; false after a stop.",
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "domain",
        +    "tracking",
        +    "message"
        +  ],
        +  "type": "object"
        +}
    • Changeduntrack_site1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "domain": {
        +      "type": "string"
        +    },
        +    "limit": {
        +      "type": "number"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "remaining": {
        +      "type": "number"
        +    },
        +    "removed": {
        +      "type": "boolean"
        +    },
        +    "tracking": {
        +      "type": "boolean"
        +    },
        +    "used": {
        +      "type": "number"
        +    }
        +  },
        +  "required": [
        +    "domain",
        +    "tracking",
        +    "removed",
        +    "message"
        +  ],
        +  "type": "object"
        +}
  5. 1 tool updatev1.0.20
    • Addedget_gtm_plan
  6. 3 tool updatesv1.0.15
    • Changedget_ai_visibility2 fields changed
      • addedInput schema / properties / business_location
        Added value: +{
        +  "description": "Optional. The city the business trades in, e.g. \"Hilo, HI\". Leave it out and the audit detects it; when nothing is detectable the questions widen to the country or drop the place entirely, which is right for a national or global business and wrong for a local one.",
        +  "type": "string"
        +}
      • addedInput schema / properties / business_name
        Added value: +{
        +  "description": "Optional. The business's real name, if you know it. Leave it out and the audit detects the name from the site and flags it when unverified — a guessed name is scored as if confirmed, so supply one only when it is actually known.",
        +  "type": "string"
        +}
    • Addedget_sample_audit
    • Changedrun_audit2 fields changed
      • addedInput schema / properties / business_location
        Added value: +{
        +  "description": "Optional. The city the business trades in, e.g. \"Hilo, HI\". Leave it out and the audit detects it; when nothing is detectable the questions widen to the country or drop the place entirely, which is right for a national or global business and wrong for a local one.",
        +  "type": "string"
        +}
      • addedInput schema / properties / business_name
        Added value: +{
        +  "description": "Optional. The business's real name, if you know it. Leave it out and the audit detects the name from the site and flags it when unverified — a guessed name is scored as if confirmed, so supply one only when it is actually known.",
        +  "type": "string"
        +}
  7. 13 tool updatesv1.0.6
    • First observedcheck_upgrade_status
    • First observedcompare_competitors
    • First observedgenerate_schema
    • First observedget_ai_visibility
    • First observedget_benchmark
    • First observedget_changes
    • First observedget_monitoring_status
    • First observedget_recommendations
    • First observedget_report
    • First observedlist_tracked_sites
    • First observedrun_audit
    • First observedtrack_site
    • First observeduntrack_site

TDQS

A4.4/5.0

Scored across 15 tools

Disambiguation4/5

Most tools target a clearly distinct output (report link, AI-visibility score, full audit, changes, competitor comparison, benchmark, tracking, recommendations, schema, GTM plan). A few boundaries blur — get_recommendations vs get_gtm_plan both answer 'what should I do', and run_audit overlaps get_ai_visibility since it includes the AI-visibility number — but descriptions explicitly cross-reference and draw the lines.

Naming Consistency5/5

Uniform verb_noun snake_case throughout (get_report, run_audit, track_site, list_tracked_sites, check_upgrade_status, generate_schema). No style drift or vague verbs; the naming is entirely predictable.

Tool Count4/5

15 tools sits at the top of the well-scoped band and each one maps to a distinct capability (audit, visibility, change detection, benchmarking, tracking lifecycle, recommendations, schema, GTM, billing, sample). Slightly heavy but nothing is obviously redundant.

Completeness4/5

Strong lifecycle coverage: sample, audit, visibility, changes, competitor/benchmark context, tracking add/remove/list/status, recommendations, schema, GTM plan, report sharing, and subscription status. Minor gaps exist — no explicit audit-history/list-reports or bulk/domain-management operations — but agents can work around them.

Maintenance

ActivityActive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    Lets any AI agent audit any website for SEO, GEO/AEO, and speed problems, reporting issues and recommendations without modifying the site.
    4
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI agents to perform instant SEO audits, check robots.txt, sitemaps, and AI crawler access for any URL without API keys.
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Enables users to scan any website for AI search visibility, producing AEO, GEO, agent readiness, and mention-readiness scores along with AI identity and business profile insights. Paid tools extend this to competitive comparisons, detailed audits, and generated fixes.
    4
    1
    MIT