seo-geo-mcp-server
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@seo-geo-mcp-serverCheck if ChatGPT can cite example.com"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
seo-geo-mcp-server
An MCP server that lets an AI agent audit a page for SEO and GEO (Generative Engine Optimization) — on-page tags, structured data, robots.txt, sitemaps, hreflang, and whether ChatGPT, Claude, Perplexity and Gemini can actually crawl and cite you. No API keys required.
Built on the v2 MCP SDK: the server speaks the 2026-07-28 protocol revision and still accepts 2025-era clients (Claude Desktop, Claude Code, Cursor) from the same factory — one build, both eras, nothing to configure.
Ask Claude "how is this page doing, and will AI assistants cite it?" and it runs a full audit and hands you a graded report with prioritised fixes — instead of you pasting a URL into six different web tools.
> Audit https://example.com/guide and tell me if ChatGPT can cite it
seo_audit(url="https://example.com/guide", include_geo=true)
Overall: A (92/100) · indexable: yes
Meta tags & social preview 95 (A)
Heading structure 100 (A)
Structured data 75 (C)
GEO readiness: B (85/100)
✅ AI crawler access 25/25
✅ Server-rendered content 20/20
❌ Authorship & entity 2/10
1. Add author and Organization markup with `sameAs` links to official profiles.Why this exists
Two gaps, one server.
The SEO gap: the on-page checkers are all web UIs. None of them let an agent run the audit, read the result and fix the code in the same loop.
The GEO gap: "generative engine optimization" tooling is mostly rank-tracking dashboards behind a subscription. The mechanics that actually decide whether an AI assistant can cite you are cheap to check and almost never checked:
Can the AI search crawlers reach you? Blocking
GPTBotstops training. BlockingOAI-SearchBotstops you being cited. Most sites that meant to do the first have accidentally done the second. This server separates them.Does your content exist without JavaScript? Googlebot renders JS.
GPTBot,ClaudeBot,PerplexityBotandCCBotlargely do not. A client-rendered page can rank fine in Google and be invisible to every AI assistant.
It is the agent-facing companion to the tools at ortamarco.me,
and shares its core (the connect-time SSRF guard and host validation)
with domain-security-mcp-server.
Related MCP server: librecrawl-technical-seo-audit-mcp
Tools
Audits
Tool | What it does |
| One fetch → seven weighted sections (meta, headings, content, schema, images, links, crawlability) → 0–100 score, A–F grade, prioritised fixes. |
| AI answer-engine readiness: crawler access (25), server-rendered content (20), structured data (15), extractable structure (15), authorship (10), freshness (8), depth (7) |
GEO
Tool | What it does |
| Resolves ~35 AI crawler tokens against robots.txt. Separates training from citation bots, flags blocks that vendors document as unenforceable, handles the Applebot→Googlebot fallback |
| Whether content survives without JavaScript — detects unhydrated SPA shells that AI crawlers cannot read |
| Detects and validates |
On-page
Tool | What it does |
| Title, description, canonical, robots (meta and |
| Open Graph + Twitter Card, and verifies the |
| Full h1–h6 outline, multiple h1s, skipped levels, question-shaped headings |
| JSON-LD/microdata/RDFa extraction, parse errors, and Google rich-result requirements for 21 schema types |
| Word count, Flesch reading ease, thin-content detection, text-to-HTML ratio, term density (EN + ES stopwords) |
| Missing alt text, missing dimensions (layout shift), lazy loading, WebP/AVIF adoption |
Technical
Tool | What it does |
| RFC 9309 parse; flags wildcard |
| Discovery via robots.txt → conventional paths; index following, gzip, 50k/50MiB limits, |
| All four http/https × apex/www variants — do they converge on one canonical URL, and via 301 or 302? |
| Hop-by-hop chain with loop and temporary-redirect detection |
| Internal/external split, rel attributes, generic anchor text, optional broken-link sampling |
| BCP-47 validity, self-reference, x-default, duplicates — plus optional reciprocity verification |
Every tool is read-only, declares an outputSchema and returns
structuredContent (validated by the SDK) alongside human-readable Markdown
(default) or JSON (response_format="json"), plus actionable error messages.
Honesty notes
This server deliberately refuses to overstate two things that most GEO content gets wrong. Both are surfaced in tool output, not buried here:
llms.txtis not an adopted standard. It is a community proposal from September 2024. No major AI vendor has documented that its crawlers read it from third-party sites, and Google has publicly said it does not. The tool reports presence and validates shape — andgeo_auditdeliberately does not score it. (llms-full.txtis a docs-tooling convention, not part of the proposal.)Some robots.txt blocks are advisory.
Perplexity-User,ChatGPT-Userandmeta-externalfetcherare documented by their own vendors as ignoring or possibly ignoring robots.txt. Reporting those as cleanly "blocked" would be misleading, so they are listed separately as unenforceable.
Crawler tokens carry a provenance field distinguishing first-party vendor
documentation from community aggregators, and vendors that publish no token at
all (xAI/Grok, Microsoft Copilot) are named explicitly — because a missing rule
cannot be read as either allowed or blocked.
Install
Requires Node.js 20.18+. Nothing to clone — every MCP client can run it with npx.
Use it with Claude Code
claude mcp add seo-geo -- npx -y seo-geo-mcp-serverUse it with Claude Desktop or Cursor
Add to claude_desktop_config.json (or ~/.cursor/mcp.json) — see examples/:
{
"mcpServers": {
"seo-geo": {
"command": "npx",
"args": ["-y", "seo-geo-mcp-server"]
}
}
}On Windows use "command": "cmd" with "args": ["/c", "npx", "-y", "seo-geo-mcp-server"].
Restart the client, then ask: "Audit the SEO and GEO of example.com."
Self-host (HTTP transport)
The same server speaks stateless Streamable HTTP for remote or multi-client
use. One endpoint serves both protocol eras; there is no session state and no
Mcp-Session-Id to carry.
TRANSPORT=http npx -y seo-geo-mcp-server
# POST JSON-RPC to http://127.0.0.1:3000/mcp · health at /healthzIt is safe by default: it binds to 127.0.0.1 and only accepts localhost
Host and Origin headers, which blocks DNS-rebinding attacks from a web page.
To expose it — for example behind Coolify or Traefik — opt in explicitly:
Variable | Default | Purpose |
|
|
|
|
| Listening port |
|
| Bind address; |
| — | Comma-separated hostnames the |
| — | Comma-separated origins allowed to call from a browser |
| — | If set, every request needs |
Binding to a non-loopback address without ALLOWED_HOSTS or MCP_AUTH_TOKEN
works, but the server says so on stderr. With Docker (the image sets HOST=0.0.0.0):
docker build -t seo-geo-mcp .
docker run -p 3000:3000 -e ALLOWED_HOSTS=mcp.example.com -e MCP_AUTH_TOKEN=change-me seo-geo-mcpDevelop
npm run dev # tsx watch (stdio)
npm test # deterministic unit tests: SSRF guard, robots matcher, nesting guard,
# gzip sitemaps, SPA detection, JSON-LD, HTTP transport defaults
npm run smoke # call all 17 tools over MCP, in BOTH protocol eras, and validate
# structuredContent vs outputSchema
npm run inspect # open the MCP Inspector against the built server
npm run build # type-check + emit dist/evals/ holds a 10-question LLM evaluation set (stable, verifiable)
and instructions for running it — see evals/README.md.
How it works
src/
├── index.ts # transport selection: serveStdio | createMcpHandler + Express
├── server.ts # the factory: registers every tool on one McpServer
├── schemas.ts # Zod 4 outputSchema for each tool
├── core/ # pure logic, no MCP coupling — reusable & testable
│ ├── validate.ts # host/URL validation and the address classifier
│ ├── netguard.ts # connect-time SSRF guard (every socket's address is checked)
│ ├── fetch.ts # fetch: guarded dispatcher, manual redirects, loop detection, byte caps
│ ├── page.ts # HTML loading + the shared parsed-document model
│ ├── meta.ts # title/description/canonical/robots, Open Graph, hreflang
│ ├── content.ts # headings, readability, word counts, image SEO
│ ├── structured-data.ts # JSON-LD/microdata + Google rich-result requirements
│ ├── robots.ts # RFC 9309 parser and rule matcher
│ ├── ai-crawlers.ts # the AI crawler registry (token, purpose, compliance, provenance)
│ ├── sitemap.ts # discovery, index following, gzip, protocol limits
│ ├── links.ts # link classification + broken-link sampling
│ ├── redirects.ts # chain tracing + host canonicalisation
│ ├── geo.ts # llms.txt, JS-rendering detection, GEO scoring
│ └── seo-audit.ts # the composite audits (one fetch, every analyser)
└── tools/ # thin MCP wrappers (Zod schemas, descriptions, formatting)The core/ layer is deliberately free of any MCP types, so the same logic can
power both this server and a web UI.
Security
The tools fetch URLs the caller names and URLs the audited site names (links,
og:image, hreflang alternates, sitemap children, redirects), so every outbound
connection is screened against server-side request forgery:
Private, loopback, link-local (cloud metadata), shared (CGNAT), multicast and reserved addresses are refused in every spelling, including IPv4 embedded in IPv6 (
[::ffff:127.0.0.1]).The check runs at connect time, on the address the socket is about to use, so DNS rebinding and names only an internal resolver knows are refused too. Redirects are followed by hand, every hop is screened, and loops are reported.
Untrusted input is bounded: 2 MB of HTML, 512 levels of nesting (what browsers keep), a backtracking-free robots.txt matcher, 10 MiB per sitemap (gzip output included), six link checks at a time, and at most 200 items per list in a result.
Found a problem? Please open a private security advisory.
License
MIT © Marco Orta
Available Tools
17 toolsai_crawler_accessAI Crawler Access CheckARead-onlyIdempotent
Resolve every known AI/LLM crawler against a site's robots.txt and report which may fetch a given path. Covers OpenAI (GPTBot, OAI-SearchBot, ChatGPT-User, OAI-AdsBot), Anthropic (ClaudeBot, Claude-User, Claude-SearchBot), Google (Google-Extended, Googlebot, Google-CloudVertexBot), Perplexity, Apple, Meta, Amazon, Mistral, Common Crawl, ByteDance and others.
Three things this gets right that a naive robots.txt reader does not:
Training vs citation. Blocking GPTBot stops training; blocking OAI-SearchBot stops you being cited in ChatGPT search. Most people want the first, not the second. Blocked citation-critical bots are called out separately.
Which blocks are actually enforceable. Perplexity-User, ChatGPT-User and meta-externalfetcher are documented by their own vendors as ignoring or possibly ignoring robots.txt. A "blocked" verdict for those is advisory, and is reported as such rather than as a clean block.
Vendor quirks. Apple documents that when robots.txt has no Applebot group but does have a Googlebot group, Applebot follows the Googlebot rules — so the effective verdict differs from the literal one.
Each crawler also carries its provenance: whether the token comes from first-party vendor documentation or only from community aggregators. Vendors that publish no crawler token at all (xAI/Grok, Microsoft Copilot) are listed separately, because absence of a rule cannot be read as allowed or blocked.
Args:
site (string): domain or any URL on it.
path (string): path to test (default '/').
include_deprecated (boolean): include retired tokens (default false).
response_format ('markdown' | 'json'): output format (default 'markdown').
Returns: { crawlers[{token, vendor, purpose, allowed, via_wildcard, matched_rule, respects_robots_txt, compliance_note, provenance, quirk}], allowed_count, blocked_count, blocked_citation_critical[], unenforceable_blocks[], undocumented_vendors[], findings[] }.
Example: "Can ChatGPT and Perplexity crawl example.com?" -> ai_crawler_access(site="example.com").
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | Path to test the rules against, e.g. '/blog/post'. Defaults to '/'. | / |
| site | Yes | Domain or any URL on it, e.g. 'example.com'. | |
| response_format | No | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. | markdown |
| include_deprecated | No | Also resolve retired tokens (anthropic-ai, claude-web) for historical coverage. |
Output Schema
| Name | Required | Description |
|---|---|---|
| url | Yes | |
| path | Yes | |
| crawlers | Yes | |
| findings | Yes | |
| robots_found | Yes | |
| allowed_count | Yes | |
| blocked_count | Yes | |
| undocumented_vendors | Yes | |
| unenforceable_blocks | Yes | |
| blocked_citation_critical | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Despite annotations already declaring read-only and idempotent behavior, the description adds substantial interpretive context: which blocks are enforceable, vendor-documented provenance, vendor quirks, and the caveat that absence of a rule is not a verdict. This is beyond what the annotations or schema convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but well structured: purpose, differentiators, Args, Returns, and example. The Args section is somewhat redundant with the schema, but the overall organization and front-loaded purpose keep it usable given the tool's complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-required-parameter tool with moderate complexity, this description is complete: coverage list, special cases, return shape, output formats, defaults, and an example. Nothing an agent needs to decide on or invoke the tool is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, and the description's Args section mostly restates the schema's names, defaults, and enum values. It adds a helpful example but does not materially extend the parameter semantics beyond what the input schema already provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence states a specific verb and resource: resolving every known AI/LLM crawler against a site's robots.txt to see what may fetch a path. It also distinguishes the tool from a naive robots.txt reader by naming concrete crawler coverage and special-case behaviors.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context: use this for AI/LLM crawlability questions, with an explicit example and useful distinctions like training vs. citation blocking. It does not explicitly name a sibling alternative or state when to prefer a different tool, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
canonical_host_checkCanonical Host CheckARead-onlyIdempotent
Fetch all four host/scheme variants of a domain — http/https × apex/www — and confirm they converge on a single canonical URL. Divergence is the classic cause of a homepage competing with itself in the index.
Also reports whether plain HTTP is upgraded to HTTPS, whether canonicalisation uses permanent (301/308) rather than temporary (302/307) redirects, and which variants do not serve content at all.
Args:
site (string): a domain such as 'example.com' (www and scheme are ignored).
response_format ('markdown' | 'json'): output format (default 'markdown').
Returns: { domain, variants[{variant, reachable, status, final_url, hop_count, redirect_statuses[]}], canonical_url, converges, distinct_endpoints[], forces_https, score, grade, findings[] }.
Example: "Do all versions of example.com redirect to one URL?" -> canonical_host_check(site="example.com").
| Name | Required | Description | Default |
|---|---|---|---|
| site | Yes | Site domain or any URL on it, e.g. 'example.com'. Only the origin is used. | |
| response_format | No | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| grade | Yes | |
| score | Yes | |
| domain | Yes | |
| findings | Yes | |
| variants | Yes | |
| converges | Yes | |
| forces_https | Yes | |
| canonical_url | Yes | |
| distinct_endpoints | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly and idempotent annotations, the description discloses useful behavioral details: it reports whether HTTP is upgraded to HTTPS, whether redirects are permanent versus temporary, and which variants do not serve content. This gives the agent a concrete picture of what the tool will compute.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well organized: purpose, additional behavior, Args, Returns, and Example. It is front-loaded with the core function, and every section earns its place without redundant filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With a full output schema, complete parameter documentation, behavioral details, and an example call, the description gives an agent everything needed to select and invoke the tool correctly. No important operational context is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Although schema coverage is 100%, the description adds meaning by explaining that 'www and scheme are ignored' for the site parameter, specifying the default for response_format, and showing a natural-language-to-API example. This goes beyond the schema's property descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: fetch all four host/scheme variants and confirm they converge on a single canonical URL. This clearly distinguishes the tool from siblings like redirect_trace, which traces a single redirect path rather than comparing variants.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear context by noting divergence is the classic cause of a homepage competing with itself in the index, and it gives an example query. It does not explicitly name alternative tools or state when not to use it, so it falls short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
content_analysisContent Quality AnalysisARead-onlyIdempotent
Measure the page's main content: word count, sentence and paragraph counts, Flesch reading ease with a plain-language reading level, estimated reading time, text-to-HTML ratio, thin-content detection, and the top non-stopword terms with their density (English and Spanish stopwords are both filtered).
Content is read from the / landmark when present, so navigation and footer chrome do not inflate the counts.
Args:
url (string): the page to check.
response_format ('markdown' | 'json'): output format (default 'markdown').
Returns: { word_count, sentence_count, paragraph_count, avg_words_per_sentence, reading_ease, reading_level, reading_time_minutes, thin_content, text_to_html_ratio, used_content_landmark, top_terms[{term, count, density}], score, grade, findings[] }.
Example: "Is the content on https://example.com/post too thin?" -> content_analysis(url="https://example.com/post").
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Page URL to analyse, e.g. 'https://example.com/blog/post'. The scheme defaults to https://. | |
| response_format | No | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| url | Yes | |
| grade | Yes | |
| score | Yes | |
| findings | Yes | |
| final_url | Yes | |
| top_terms | Yes | |
| html_bytes | Yes | |
| word_count | Yes | |
| reading_ease | Yes | |
| thin_content | Yes | |
| reading_level | Yes | |
| sentence_count | Yes | |
| paragraph_count | Yes | |
| text_to_html_ratio | Yes | |
| reading_time_minutes | Yes | |
| used_content_landmark | Yes | |
| avg_words_per_sentence | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With readOnlyHint=true and idempotentHint=true already covering safety, the description adds valuable non-obvious behavior: content is scoped to the <main>/<article> landmark so navigation/footer chrome don't inflate counts, and both English and Spanish stopwords are filtered. The return contract's used_content_landmark field reinforces this. It does not disclose fallback behavior when no landmark exists, which is a minor residual gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-organized and front-loaded: purpose, behavioral note, args, returns, and a concrete example. Each block earns its place, though the Args section duplicates schema content and the Returns block partially repeats what the output schema already documents, keeping it from a 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given two well-documented parameters, an output schema covering the rich return shape, and annotations covering safety, the description covers the remaining essentials: extraction behavior, supported languages, output contract, and a usage example. It omits only edge-case behavior (unreachable URLs, or the content fallback when no landmark is present), which is a minor gap for an otherwise complete definition.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema fully documents both url and response_format, including the enum and default. The Args section largely repeats that structured data, adding no meaning beyond inline convenience and an example value. A baseline 3 is appropriate since the description does not need to compensate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Measure') and resource ('the page's main content') and enumerates a concrete metric list: word/sentence/paragraph counts, Flesch reading ease, reading time, text-to-HTML ratio, thin-content detection, and top non-stopword terms. This clearly distinguishes it from siblings like robots_txt_check, meta_tags_check, and link_audit, which target wholly different concerns.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The metric list and the worked example ('Is the content on https://example.com/post too thin?') provide clear context for when to invoke this tool: content-depth, readability, and thinness questions. It does not explicitly name alternatives or exclusion criteria versus the closest sibling (seo_audit), so it stops short of a 5, but the context is unambiguous enough to route an agent correctly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
geo_auditGEO / AI Answer-Engine Readiness AuditARead-onlyIdempotent
Score how readily an AI answer engine (ChatGPT, Claude, Perplexity, Gemini, Copilot) can fetch, parse and cite this page. Weighted across: AI crawler access (25), server-rendered content (20), structured data (15), extractable structure (15), authorship & entity signals (10), freshness (8) and content depth (7).
Two things this catches that a classic SEO tool does not:
Pages that rank fine in Google but are invisible to AI assistants, because most AI crawlers do not execute JavaScript and the content only appears after hydration.
robots.txt rules that block AI search crawlers (OAI-SearchBot, Claude-SearchBot, PerplexityBot) — the ones that build citation indexes — as opposed to the training crawlers people usually mean to block.
Args:
url (string): the page to audit.
response_format ('markdown' | 'json'): output format (default 'markdown').
Returns: { geo{score, grade, signals[], top_recommendations[]}, rendering, crawler_access, llms_txt, robots }.
Example: "Is https://example.com/guide ready to be cited by ChatGPT?" -> geo_audit(url="https://example.com/guide"). Note: llms.txt presence is reported but deliberately NOT scored — it is a community proposal with no committed vendor support, and Google has stated it does not use it.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Page URL to analyse, e.g. 'https://example.com/blog/post'. The scheme defaults to https://. | |
| response_format | No | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| geo | Yes | |
| robots | Yes | |
| llms_txt | Yes | |
| rendering | Yes | |
| crawler_access | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so the description doesn't need to restate safety. It adds behavioral context beyond annotations: the rationale for not scoring llms.txt, the distinction between AI search crawlers and training crawlers, and the return structure. No contradictions with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is moderately long but well structured: purpose, weighting, unique value, args, returns, example, and a clarifying note. Each section earns its place; the bullet points condense key differentiators. It is not overly verbose, though it could be tightened slightly without losing value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a composite audit tool with two parameters and an output schema (present but not shown), the description is remarkably complete. It covers purpose, methodology, edge cases (llms.txt), example usage, and return structure. An agent has everything needed to decide when and how to invoke it, and the llms.txt note prevents a common misunderstanding.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with descriptions for both url and response_format, so the baseline is 3. The description adds an example invocation ('Is https://example.com/guide ready to be cited by ChatGPT?' -> geo_audit(url=...)) and the exact return object shape, which goes beyond the schema and helps an agent understand parameter usage and output. That lifts it to 4.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Score how readily an AI answer engine can fetch, parse and cite this page.' It enumerates the weighted categories and explicitly names the two unique catches (AI crawlers not executing JS and AI search crawler blocking) that distinguish it from classic SEO tools. This clearly separates it from the many sibling tools that focus on individual aspects like robots_txt_check or render_check.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use this tool by contrasting it with 'classic SEO tools' and listing its composite nature, but it does not explicitly name alternative tools or conditions for selecting them. It does clarify what it does NOT score (llms.txt) and why, which helps an agent avoid misusing it. A clear exclusion is present, but explicit routing to siblings is missing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
heading_structureHeading StructureARead-onlyIdempotent
Extract the full h1–h6 outline and evaluate it: how many h1s, whether levels are skipped (h2 followed by h4), empty heading tags, and how many headings are phrased as questions — the last being a strong signal for featured snippets and AI citations.
Args:
url (string): the page to check.
response_format ('markdown' | 'json'): output format (default 'markdown').
Returns: { headings[{level, text, skips_level}], h1_count, h1_text[], level_skips, empty_headings, question_headings[], outline, score, grade, findings[] }.
Example: "Show me the heading outline of https://example.com/guide" -> heading_structure(url="https://example.com/guide").
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Page URL to analyse, e.g. 'https://example.com/blog/post'. The scheme defaults to https://. | |
| response_format | No | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| url | Yes | |
| grade | Yes | |
| score | Yes | |
| h1_text | Yes | |
| outline | Yes | |
| findings | Yes | |
| h1_count | Yes | |
| headings | Yes | |
| final_url | Yes | |
| level_skips | Yes | |
| empty_headings | Yes | |
| question_headings | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and non-destructive behavior, so the description's job is lighter. It adds value by specifying the exact metrics computed (level_skips, question_headings, grade/score) and the rationale for question headings being a strong snippet/citation signal. No contradictions with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with an Args, Returns, and Example section, front-loading the core purpose. It is slightly verbose but every sentence adds functional or contextual value (e.g., the snippet-signal note). No filler or tautology.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's moderate complexity, the description covers the input, output format (with return fields), and an example invocation. The presence of an output schema reduces the need to spell out return structure, and the description provides enough for an agent to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both url and response_format are already well documented. The description repeats the parameter list and adds an example call, but does not add new meaning beyond the schema. The baseline of 3 applies because the schema carries the full semantic weight.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Extract') and resource ('full h1–h6 outline'), then details exactly what is evaluated (h1 count, level skips, empty headings, question phrasing). It clearly distinguishes itself from sibling tools like meta_tags_check or content_analysis by focusing solely on heading structure and its SEO signals.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No explicit guidance on when to use this tool versus alternatives. It does not mention that heading analysis is part of a broader SEO audit or when to prefer seo_audit over this specific check. The context is implicit from the name and description, but the tool does not state exclusions or preferred scenarios.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
hreflang_checkHreflang CheckARead-onlyIdempotent
Validate a page's <link rel="alternate" hreflang> annotations: language/region code validity (BCP-47), the required self-referencing entry, the x-default fallback, and duplicate codes.
With check_reciprocity=true it fetches each alternate and confirms it links back to this page — non-reciprocal hreflang is silently ignored by Google, and it is impossible to detect from one page in isolation.
Args:
url (string): the page to check.
check_reciprocity (boolean): verify alternates link back (default false).
response_format ('markdown' | 'json'): output format (default 'markdown').
Returns: { declared_lang, entries[{hreflang, href, valid_code, is_self, reciprocates}], has_x_default, self_referencing, duplicate_codes[], invalid_codes[], findings[] }.
Example: "Is hreflang set up correctly on https://example.com/es/pagina?" -> hreflang_check(url="https://example.com/es/pagina", check_reciprocity=true).
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Page URL to analyse, e.g. 'https://example.com/blog/post'. The scheme defaults to https://. | |
| response_format | No | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. | markdown |
| check_reciprocity | No | Fetch each alternate to confirm it links back. Catches the most common hreflang bug. |
Output Schema
| Name | Required | Description |
|---|---|---|
| url | Yes | |
| entries | Yes | |
| findings | Yes | |
| final_url | Yes | |
| declared_lang | Yes | |
| has_x_default | Yes | |
| invalid_codes | Yes | |
| duplicate_codes | Yes | |
| self_referencing | Yes | |
| reciprocity_checked | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate read-only, idempotent, and non-destructive behavior. The description adds valuable behavioral context by disclosing that enabling check_reciprocity fetches each alternate and explaining that non-reciprocal hreflang is silently ignored by Google and undetectable from a single page. It stops short of mentioning timeouts or rate limits, but the behavioral disclosure is strong.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well organized: purpose first, then the advanced reciprocity behavior, followed by compact Args, the return shape, and a concrete example. Every section earns its place and there is no filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With 100% schema coverage, relevant annotations, an output schema, and a description that explains the non-obvious reciprocity behavior and return payload, an agent has everything it needs to select and invoke the tool correctly. The example query further anchors intended usage.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description repeats each parameter's name and default value but adds some useful context, especially for check_reciprocity ('catches the most common hreflang bug'). This is helpful but doesn't substantially go beyond what the schema already documents.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the resource (a page's `<link rel="alternate" hreflang>` annotations), the action (validate), and the specific validation checks: BCP-47 validity, self-referencing entry, x-default fallback, and duplicate codes. This is specific enough to distinguish it from sibling tools like sitemap_check or geo_audit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The opening sentence explicitly states the tool's purpose, making it clear when an agent should use it. The check_reciprocity paragraph also tells the agent when to enable that option and why it matters. It doesn't explicitly name alternative tools or give when-not-to-use guidance, but the scope is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
image_seo_checkImage SEO CheckARead-onlyIdempotent
Audit every on the page: missing alt attributes (an accessibility failure and a lost image-search signal), decorative alt="" usage, missing width/height (which causes layout shift, a Core Web Vitals factor), lazy-loading adoption, and how many images use modern formats (WebP/AVIF) versus legacy JPEG/PNG. sources are counted as modern delivery.
Args:
url (string): the page to check.
response_format ('markdown' | 'json'): output format (default 'markdown').
Returns: { total_images, missing_alt, decorative_alt, missing_dimensions, lazy_loaded, modern_format, legacy_format, images[], score, grade, findings[] }.
Example: "Which images on https://example.com are missing alt text?" -> image_seo_check(url="https://example.com").
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Page URL to analyse, e.g. 'https://example.com/blog/post'. The scheme defaults to https://. | |
| response_format | No | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| url | Yes | |
| grade | Yes | |
| score | Yes | |
| images | Yes | |
| findings | Yes | |
| final_url | Yes | |
| lazy_loaded | Yes | |
| missing_alt | Yes | |
| total_images | Yes | |
| legacy_format | Yes | |
| modern_format | Yes | |
| decorative_alt | Yes | |
| missing_dimensions | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds meaningful behavioral context: it explains what counts as modern delivery ('<picture> sources are counted as modern delivery'), what the audit covers, and the return payload structure. It does not disclose rate limits or failure behavior, but for a read-only audit tool the added context is solid.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured: a dense first sentence enumerating checks, a compact Args block, a Returns line, and an example. It is slightly longer than necessary because the Returns line duplicates the output schema, but every sentence earns its place and the key scope is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has an output schema, so the description need not explain return values in depth, yet it still provides a Returns summary. The description covers the audit scope, parameters, and an example. It lacks explicit guidance on edge cases (e.g., pages with no images) but is complete enough for an agent to select and invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 parameters fully. The description adds a brief mention of the parameters in the Args block but does not add meaning beyond the schema. Baseline 3 is appropriate when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb ('Audit') and a precise resource ('every <img> on the page'), then enumerates the exact checks performed: missing alt, decorative alt, missing dimensions, lazy-loading, and modern formats. This clearly distinguishes it from sibling SEO tools like meta_tags_check or robots_txt_check, which target different page elements.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use this tool: when auditing image-specific SEO/accessibility issues on a page. It does not explicitly state when NOT to use it or name alternatives, but the detailed scope makes the use case clear. The example query reinforces the intended usage pattern.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
link_auditLink AuditARead-onlyIdempotent
Audit a page's outbound links: the internal/external split, rel attributes (nofollow, sponsored, ugc), links with no anchor text at all, generic anchor text ("click here", "leer más") that carries no topical signal, and the distribution of external domains. Optionally sample-verifies that links actually resolve, retrying with GET when a server rejects HEAD.
Args:
url (string): the page to audit.
check_broken (boolean): verify links resolve (default false).
sample_size (number): how many links to verify (default 25).
response_format ('markdown' | 'json'): output format (default 'markdown').
Returns: { total_links, internal_links, external_links, nofollow_links, empty_anchor_text, generic_anchor_text[], external_domains[{domain, count}], checked_count, broken[], score, grade, findings[] }.
Example: "Are there broken links on https://example.com/resources?" -> link_audit(url="https://example.com/resources", check_broken=true).
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Page URL to analyse, e.g. 'https://example.com/blog/post'. The scheme defaults to https://. | |
| sample_size | No | How many links to verify when check_broken is true. | |
| check_broken | No | Sample links and verify they resolve. Adds up to sample_size requests (default 25), six at a time. | |
| response_format | No | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| url | Yes | |
| grade | Yes | |
| score | Yes | |
| broken | Yes | |
| findings | Yes | |
| final_url | Yes | |
| ugc_links | Yes | |
| total_links | Yes | |
| checked_count | Yes | |
| external_links | Yes | |
| internal_links | Yes | |
| nofollow_links | Yes | |
| sponsored_links | Yes | |
| external_domains | Yes | |
| empty_anchor_text | Yes | |
| generic_anchor_text | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and idempotentHint=true, so the agent knows it's a safe read operation. The description adds valuable behavioral context beyond that: it explains the optional sample verification, the HEAD-then-GET retry logic, and the exact structure of the returned payload. This gives the agent insight into how the tool behaves without contradicting any annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured: the core purpose is front-loaded, followed by a clear Args list, a Returns summary, and a concrete example. It is slightly longer than strictly necessary because it repeats parameter details from the schema, but every sentence serves a purpose and the layout aids scanning. It is appropriately concise for a tool with four parameters and a non-trivial output.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with four parameters, an output schema, and no hidden prerequisites, the description is complete. It covers the full behavior (including the optional broken-link verification), the return structure is explicitly described (redundant with the output schema but still useful), and the example shows realistic invocation. Nothing an agent needs 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.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% – every parameter has a clear description, including defaults and constraints (e.g., sample_size min/max, response_format enum). The tool description largely restates these in its Args list, adding little semantic value beyond the schema. The example does clarify the interplay between check_broken and sample_size, but that is also present in the schema. Per the rubric, baseline 3 is appropriate when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb ('Audit') and a clearly defined resource ('a page's outbound links'), then enumerates the exact aspects it covers (internal/external split, rel attributes, anchor text issues, domain distribution, broken-link verification). This specificity distinguishes it from siblings like seo_audit or meta_tags_check, which target different SEO facets. An agent can immediately recognize that this tool is the one for link-level analysis.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides a concrete example query that maps to the tool, illustrating when it should be invoked ('Are there broken links...'). It also implies the tool is for outbound-link auditing rather than broader SEO checks, though it does not explicitly name alternatives or state when not to use it. The context is clear enough for correct selection, but explicit exclusions are absent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
llms_txt_checkllms.txt CheckARead-onlyIdempotent
Check whether a site publishes /llms.txt and validate it against the llmstxt.org proposal: a required H1 title, an optional blockquote summary, and H2-delimited lists of - [name](url): notes links. Also detects /llms-full.txt.
Important context this tool always reports: llms.txt is a community proposal from September 2024, not an adopted standard. No major AI vendor has documented that its crawlers read llms.txt from third-party sites, and Google has publicly stated it does not support it. Publishing one is cheap and may help human readers and some documentation tooling, but it does not earn AI visibility on its own — robots.txt access, structured data and server-rendered content do. Note also that llms-full.txt is a de-facto convention popularised by docs tooling, not part of the proposal.
Use this tool to answer "do they publish one, and is it well-formed?" — not as evidence that a site is or is not AI-optimised.
Args:
site (string): domain or any URL on it.
response_format ('markdown' | 'json'): output format (default 'markdown').
Returns: { found, status, full_variant_found, bytes, title, has_summary_blockquote, sections[], link_count, spec_compliant, adoption_status, findings[] }.
Example: "Does example.com publish an llms.txt?" -> llms_txt_check(site="example.com").
| Name | Required | Description | Default |
|---|---|---|---|
| site | Yes | Site domain or any URL on it, e.g. 'example.com'. Only the origin is used. | |
| response_format | No | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| url | Yes | |
| bytes | Yes | |
| found | Yes | |
| title | Yes | |
| status | Yes | |
| findings | Yes | |
| sections | Yes | |
| link_count | Yes | |
| spec_compliant | Yes | |
| adoption_status | Yes | |
| full_variant_found | Yes | |
| has_optional_section | Yes | |
| has_summary_blockquote | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark this as read-only, idempotent, and open-world, so the safety profile is covered. The description adds valuable behavioral detail beyond that: it always reports adoption_status and explains the llms-full.txt convention, and it clarifies the tool's limitations regarding AI visibility. This gives the agent an accurate model of what the tool will and won't tell them.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is longer than the minimum but well-structured: the core action is front-loaded, followed by important contextual caveats, then args and returns. The extra context about llms.txt's non-adopted status is relevant to correct usage, so it earns its place. However, it could be tightened by omitting the schema-redundant parameter block.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has an output schema (per context signals), so the return-value list in the description is supplementary. The description covers the non-obvious aspects: validation criteria, full-variant detection, and the adoption-status context an agent needs to interpret results. With a simple two-parameter input and a live read-only check, nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the parameter meaning is fully carried by the input schema. The description's Args section repeats the schema content without adding new semantics, and the example usage illustrates a call pattern rather than parameter meaning. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Check whether a site publishes /llms.txt and validate it against the llmstxt.org proposal.' It also names the alternate variant detection (/llms-full.txt), which distinguishes it from sibling robots.txt/sitemap checks. An agent can immediately tell exactly what this tool does.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when to use it: 'Use this tool to answer "do they publish one, and is it well-formed?"' and, more importantly, what not to use it for: 'not as evidence that a site is or is not AI-optimised.' It also embeds relevant context about llms.txt's non-standard status, which helps the agent decide if the tool is appropriate for a given user question.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
meta_tags_checkMeta Tags CheckARead-onlyIdempotent
Inspect a page's head tags: title, meta description, canonical, robots directives (meta AND the X-Robots-Tag header), html lang, charset, viewport and favicon. Flags length problems, missing or duplicated tags, and anything that makes the page non-indexable.
Args:
url (string): the page to check.
response_format ('markdown' | 'json'): output format (default 'markdown').
Returns: { title, title_length, description, description_length, canonical, canonical_is_self, meta_robots, x_robots_tag, indexable, followable, lang, charset, viewport, score, grade, findings[] }.
Example: "Are the meta tags on https://example.com correct?" -> meta_tags_check(url="https://example.com").
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Page URL to analyse, e.g. 'https://example.com/blog/post'. The scheme defaults to https://. | |
| response_format | No | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| url | Yes | |
| lang | Yes | |
| grade | Yes | |
| score | Yes | |
| title | Yes | |
| charset | Yes | |
| favicon | Yes | |
| findings | Yes | |
| viewport | Yes | |
| canonical | Yes | |
| final_url | Yes | |
| indexable | Yes | |
| followable | Yes | |
| description | Yes | |
| meta_robots | Yes | |
| title_length | Yes | |
| x_robots_tag | Yes | |
| canonical_is_self | Yes | |
| robots_directives | Yes | |
| description_length | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, establishing the safety profile. The description adds behavioral context by listing the return object and noting it checks both meta robots and the X-Robots-Tag header, which is a non-obvious detail. It also states what it flags (length problems, duplicates, non-indexable), giving insight into output behavior. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-organized: a concise overview sentence, then Args, Returns, and Example sections. Each part serves a purpose—no redundancy. The main purpose is front-loaded, and the structured format makes it easy for an agent to scan. It is detailed but not verbose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's moderate complexity (checks many tags, returns a structured object) and the presence of an output schema (implied by 'Has output schema: true'), the description covers the essential information: the return fields, the flags it produces, and an example. It doesn't discuss error handling or redirect behavior, but those are minor gaps given the annotations and schema richness. Overall, it is sufficiently complete for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema fully describes both parameters: url with example and scheme default, response_format with enum and default. Schema coverage is 100%, so the baseline is 3. The description repeats these parameters but does not add new semantic information; the example call reinforces usage but doesn't deepen parameter understanding beyond what the schema already provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Inspect') and resource ('a page's head tags'), enumerating the exact tags checked (title, meta description, canonical, robots directives, lang, charset, viewport, favicon). This is precise and implicitly distinguishes it from sibling tools like robots_txt_check (which inspects robots.txt) or seo_audit (broader audit). It also describes the outcome (flags length problems, missing/duplicated tags, non-indexable issues), making the purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides a clear example query ('Are the meta tags on https://example.com correct?') that illustrates when to use the tool. However, it does not explicitly mention alternatives or when not to use it, lacking the explicit 'when-not' guidance that would earn a 5. Still, the context is clear and the example provides practical direction.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
redirect_traceRedirect TraceARead-onlyIdempotent
Follow a URL's redirect chain hop by hop, reporting each status code and target. Flags long chains (which waste crawl budget), redirect loops, temporary 302/307 redirects where a permanent 301/308 belongs, and chains that do not end on HTTPS.
Args:
url (string): the starting URL.
response_format ('markdown' | 'json'): output format (default 'markdown').
Returns: { final_url, final_status, hops[{url, status, location}], hop_count, https_upgrade, ends_https, has_loop, has_temporary_redirect, elapsed_ms, findings[] }.
Example: "Where does http://example.com/old-page end up?" -> redirect_trace(url="http://example.com/old-page").
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Page URL to analyse, e.g. 'https://example.com/blog/post'. The scheme defaults to https://. | |
| response_format | No | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| url | Yes | |
| hops | Yes | |
| findings | Yes | |
| has_loop | Yes | |
| final_url | Yes | |
| hop_count | Yes | |
| elapsed_ms | Yes | |
| ends_https | Yes | |
| final_status | Yes | |
| https_upgrade | Yes | |
| has_temporary_redirect | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and non-destructive behavior, so the description is not burdened with proving safety. It adds meaningful behavioral context beyond annotations: it describes hop-by-hop traversal, flags crawl-budget waste, detects loops, and identifies temporary vs permanent redirects. The Returns section also outlines the structured result fields, which is useful context even though an output schema exists.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with a front-loaded purpose, followed by Args, Returns, and an example. Every section serves a purpose, and the example is highly actionable. There is some redundancy between the Args section and the schema, but it does not harm clarity enough to warrant a lower score.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The definition fully equips an agent to select and invoke the tool: it states the exact operation, the conditions it flags, parameter defaults and formats, the return payload shape, and provides a natural-language example. Combined with the rich annotations and schema, nothing needed for correct usage is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema itself already documents url and response_format in detail, including defaults, enums, and the https:// scheme fallback. The description duplicates this information with its Args section and adds a useful example, but it does not meaningfully extend parameter semantics beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Follow a URL's redirect chain hop by hop', and explicitly enumerates the reported status codes and targets. It also lists the issues it flags (long chains, loops, temporary redirects, non-HTTPS endings), which clearly distinguishes it from the sibling tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The tool's use case is clearly stated in the first sentence and reinforced with a concrete example query-to-call mapping. It does not explicitly name alternatives or state when not to use it, but the context makes it obvious that this is the redirect-specific diagnostic tool among the siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
render_checkJavaScript Rendering CheckARead-onlyIdempotent
Determine whether a page's content exists in the server HTML, or only appears after JavaScript runs.
This matters more for AI visibility than for classic SEO: Googlebot renders JavaScript, but GPTBot, ClaudeBot, PerplexityBot and CCBot largely do not. A client-rendered page can rank perfectly well in Google and still be completely invisible to every AI assistant — this tool is how you catch that.
Detects unhydrated SPA shells (empty #root / #app / #__next containers), reports how many words survive without JS, and flags documents dominated by inline script bytes.
Args:
url (string): the page to check.
response_format ('markdown' | 'json'): output format (default 'markdown').
Returns: { renders_without_js, server_text_words, script_bytes, html_bytes, spa_shell_detected, framework_hint, findings[] }.
Example: "Can ChatGPT actually read https://example.com/app?" -> render_check(url="https://example.com/app").
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Page URL to analyse, e.g. 'https://example.com/blog/post'. The scheme defaults to https://. | |
| response_format | No | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| findings | Yes | |
| html_bytes | Yes | |
| script_bytes | Yes | |
| framework_hint | Yes | |
| server_text_words | Yes | |
| renders_without_js | Yes | |
| spa_shell_detected | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover safety (readOnly, idempotent, non-destructive), and the description adds specific behavioral details such as detecting SPA shells, counting server-side words, and flagging script-heavy pages. It also describes the return fields, enriching beyond the annotations without contradicting them.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured and front-loaded with the core purpose, followed by context, arguments, and returns. While it is somewhat lengthy, every sentence contributes to understanding, and the structure aids scanning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
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 safety annotations, the description covers purpose, usage context, parameters, and return format, including an example. It lacks edge-case handling or error details, but these are not essential given the available structured data.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so both url and response_format are documented. The description reinforces the meaning of response_format, provides the default, and gives a concrete example mapping a natural-language query to the tool call, adding value beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool determines whether content is server-rendered or appears only after JavaScript runs, and explicitly contrasts this with classic SEO concerns. It distinguishes itself from siblings like robots_txt_check and ai_crawler_access by focusing on rendering rather than access or crawling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explains when the tool matters (AI visibility over classic SEO) and gives an example query, implying when to use it. However, it does not explicitly name alternatives or state when NOT to use it, though the context is sufficient given the sibling list.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
robots_txt_checkrobots.txt CheckARead-onlyIdempotent
Fetch and parse a site's robots.txt per RFC 9309. Reports every user-agent group with its Allow/Disallow rules, the declared sitemaps, and any lines that could not be parsed. Flags the two failures that silently deindex a site: a wildcard Disallow: /, and a robots.txt that returns 5xx (which Google treats as "disallow everything").
Args:
site (string): domain or any URL on it, e.g. 'example.com'.
response_format ('markdown' | 'json'): output format (default 'markdown').
Returns: { found, status, group_count, sitemaps[], blocks_everything, groups[{agents[], rules[], crawl_delay}], parse_warnings[], findings[] }.
Example: "What does example.com's robots.txt allow?" -> robots_txt_check(site="example.com").
For AI-crawler specifics use ai_crawler_access instead — it resolves each known AI bot against these rules.
| Name | Required | Description | Default |
|---|---|---|---|
| site | Yes | Site domain or any URL on it, e.g. 'example.com'. Only the origin is used. | |
| response_format | No | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| url | Yes | |
| found | Yes | |
| groups | Yes | |
| status | Yes | |
| findings | Yes | |
| sitemaps | Yes | |
| group_count | Yes | |
| parse_warnings | Yes | |
| blocks_everything | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, and non-destructive behavior. The description goes well beyond by disclosing exact parsing behavior (per RFC 9309), the special flags for `Disallow: /` and 5xx responses, and the structure of the returned payload. No contradictions with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Every sentence earns its place: purpose, special behavior flags, args, return shape, example, and sibling routing. The structure is logical and front-loaded with the core purpose before operational details.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with two params and rich annotations, the description includes everything needed to select and invoke it correctly: parameter usage, return fields, default behavior, and a clear alternative for a related but different task. The example further anchors correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already fully explains `site` and `response_format`. The description repeats the args and adds a concrete example mapping a natural-language query to a call, but does not add meaning beyond the schema's existing detail.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Starts with a specific verb and resource: 'Fetch and parse a site's robots.txt per RFC 9309'. It clearly defines the scope (every user-agent group, Allow/Disallow rules, sitemaps, unparseable lines) and distinguishes itself from sibling `ai_crawler_access` by naming that alternative explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides an example query ('What does example.com's robots.txt allow?') and an explicit when-not-to-use instruction: 'For AI-crawler specifics use ai_crawler_access instead'. It also signals a diagnostic use case by explaining the two silent deindexing failures it flags.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
seo_auditFull On-Page SEO AuditARead-onlyIdempotent
Fetch a page once and audit it across seven weighted sections — meta tags & social preview, heading structure, content quality, structured data, image SEO, links and crawlability — returning a 0–100 score, an A–F grade and a prioritised fix list.
This is the tool to start with for any "how is this page doing for SEO?" question; drill into the single-purpose tools afterwards for detail.
Args:
url (string): the page to audit.
include_geo (boolean): also score AI answer-engine readiness (default false).
check_broken_links (boolean): sample-verify that links resolve (default false).
response_format ('markdown' | 'json'): output format (default 'markdown').
Returns: { score, grade, indexable, sections[{id, label, score, grade, weight, issues[]}], top_recommendations[], geo, findings[] }.
Example: "Audit the SEO of https://example.com/pricing" -> seo_audit(url="https://example.com/pricing"). Note: a noindex page or a site-wide robots.txt block caps the score, because nothing else matters until that is fixed. Errors: returns an error if the URL is unreachable, non-HTML, or returns an HTTP error.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Page URL to analyse, e.g. 'https://example.com/blog/post'. The scheme defaults to https://. | |
| include_geo | No | Also score GEO (AI answer-engine) readiness. Adds ~2 requests. | |
| response_format | No | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. | markdown |
| check_broken_links | No | Sample up to 25 links and verify they resolve. Slower, but catches dead links. |
Output Schema
| Name | Required | Description |
|---|---|---|
| geo | Yes | |
| url | Yes | |
| grade | Yes | |
| score | Yes | |
| status | Yes | |
| fetch_ms | Yes | |
| findings | Yes | |
| sections | Yes | |
| final_url | Yes | |
| indexable | Yes | |
| redirect_hops | Yes | |
| top_recommendations | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only/idempotent behavior, and the description adds meaningful behavioral context beyond that: it fetches the page once, caps the score on noindex or robots-blocked pages, and reports errors for unreachable, non-HTML, or HTTP-error responses. It also tells the agent what payload shape to expect.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is appropriately sized for a comprehensive tool: purpose, usage rule, args, return shape, example, and critical edge-case note each earn their place. It is front-loaded with the most important scoping information and remains scannable despite covering a lot of ground.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 4-parameter aggregator with many siblings, the description covers selection context, output format, error behavior, and a crucial caveat (noindex/robots-block caps the score). The return structure is spelled out in prose, and the error note addresses the main call-time risks, so an agent has what it needs to invoke this tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 all four parameters, defaults, and side effects. The description's Args section largely restates that information, but the natural-language example ('Audit the SEO of https://example.com/pricing' -> seo_audit(url=...)) adds a concrete invocation pattern beyond the structured schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Fetch a page once and audit it across seven weighted sections', enumerating exactly what is audited and the outputs (0–100 score, A–F grade, prioritised fix list). It also distinguishes itself from the many single-purpose siblings by positioning itself as the starting audit tool, so an agent can tell it apart from tools like meta_tags_check.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says 'This is the tool to start with for any "how is this page doing for SEO?" question; drill into the single-purpose tools afterwards for detail.' This gives a clear selection rule and points to follow-up tools, though it does not enumerate exactly which sibling to choose for each specific follow-up need.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
sitemap_checkXML Sitemap CheckARead-onlyIdempotent
Discover, fetch and validate an XML sitemap. Finds it via the robots.txt Sitemap: directive, then falls back to /sitemap.xml, /sitemap_index.xml and /sitemap-index.xml. Handles sitemap indexes (following children) and gzipped sitemaps.
Validates: URL count against the 50,000 limit, uncompressed size against 50 MiB, presence and W3C-datetime validity, URLs pointing off-origin, http:// URLs, and duplicates.
Args:
site (string): domain or any URL on it.
sitemap_url (string, optional): explicit sitemap URL.
follow_children (number): child sitemaps of an index to follow (default 3).
response_format ('markdown' | 'json'): output format (default 'markdown').
Returns: { found, type, url_count, child_sitemaps[], with_lastmod, invalid_lastmod[], newest_lastmod, off_origin_urls[], exceeds_url_limit, discovered_via, score, grade, findings[] }.
Example: "Check the sitemap for example.com" -> sitemap_check(site="example.com").
| Name | Required | Description | Default |
|---|---|---|---|
| site | Yes | Domain or any URL on it, e.g. 'example.com'. | |
| sitemap_url | No | Explicit sitemap URL. Omit to discover it via robots.txt, then the conventional paths. | |
| follow_children | No | How many child sitemaps of an index to follow (default 3). | |
| response_format | No | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| url | Yes | |
| type | Yes | |
| bytes | Yes | |
| found | Yes | |
| grade | Yes | |
| score | Yes | |
| status | Yes | |
| entries | Yes | |
| findings | Yes | |
| url_count | Yes | |
| with_lastmod | Yes | |
| child_sitemaps | Yes | |
| discovered_via | Yes | |
| duplicate_urls | Yes | |
| newest_lastmod | Yes | |
| non_https_urls | Yes | |
| oldest_lastmod | Yes | |
| invalid_lastmod | Yes | |
| off_origin_urls | Yes | |
| exceeds_url_limit | Yes | |
| exceeds_size_limit | Yes | |
| child_sitemaps_followed | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/openWorld/idempotent annotations, the description adds real behavioral detail: robots.txt discovery, fallback paths, index/gzip handling, exact limits (50,000 URLs, 50 MiB), lastmod validation, off-origin checking, duplicate detection, and the returned fields. This gives the agent a precise model of what the tool does without contradicting 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.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with purpose, then discovery logic, validation criteria, arguments, return payload, and an example. Although it is long, each section contributes directly to selecting and invoking the tool correctly, and the structure is easy to scan.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The definition covers discovery strategy, supported edge cases, validation rules, parameter behavior, return fields, and even includes an example invocation. Given the output schema is available, nothing critical is missing for an agent to call this tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the description largely restates what the schema already says: site semantics, sitemap_url discovery behavior, follow_children default, and response_format choices. It adds little new parameter-level meaning beyond the structured schema, so the baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Discover, fetch and validate an XML sitemap.' It then details the discovery fallbacks and validation checks, which clearly differentiates it from sibling tools like robots_txt_check or llms_txt_check by focusing on the XML sitemap artifact and its rules.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The intended usage is clear: call this tool when an XML sitemap needs to be found, fetched, or validated, including index and gzip handling. It does not explicitly name alternatives or say when not to use it, but the context is strong enough to route an agent correctly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
structured_data_checkStructured Data (Schema.org) CheckARead-onlyIdempotent
Extract and validate JSON-LD, microdata and RDFa. Reports every @type found, flags JSON-LD blocks that fail to parse (those are invisible to search engines), and checks recognised types against Google's rich-result requirements — required properties that are missing, plus recommended ones worth adding.
Covers Article/BlogPosting/NewsArticle, Product, FAQPage, HowTo, Recipe, Event, Organization, LocalBusiness, Person, WebSite, BreadcrumbList, VideoObject, JobPosting, Course, Review and AggregateRating.
Args:
url (string): the page to check.
response_format ('markdown' | 'json'): output format (default 'markdown').
Returns: { json_ld_blocks, microdata_items, parse_errors[], items[{type, properties[], missing_required[], missing_recommended[], valid}], types_found[], has_organization, has_breadcrumb, score, grade, findings[] }.
Example: "Does https://example.com/product have valid Product schema?" -> structured_data_check(url="https://example.com/product").
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Page URL to analyse, e.g. 'https://example.com/blog/post'. The scheme defaults to https://. | |
| response_format | No | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| url | Yes | |
| grade | Yes | |
| items | Yes | |
| score | Yes | |
| has_faq | Yes | |
| findings | Yes | |
| final_url | Yes | |
| has_person | Yes | |
| rdfa_items | Yes | |
| has_article | Yes | |
| has_website | Yes | |
| types_found | Yes | |
| parse_errors | Yes | |
| has_breadcrumb | Yes | |
| json_ld_blocks | Yes | |
| microdata_items | Yes | |
| has_organization | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish the safety profile (readOnlyHint, idempotentHint, destructiveHint=false), so the bar is lowered. The description adds meaningful behavioral context beyond that: it discloses that unparseable JSON-LD blocks are 'invisible to search engines' and that the tool reports missing required and recommended rich-result properties against Google's requirements. This describes the checking behavior and its significance without contradicting the read-only, non-destructive annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with its core purpose in the first sentence, then layers covered types, args, returns, and an example in a logical order. It is longer than typical but the length is justified by the tool's breadth (many schema types and a complex return payload). The Args section is somewhat redundant with the schema, but the Returns section and example earn their place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description needn't detail return values, yet it still lists the return fields, which is helpful. It covers what is extracted, what is validated, which types are recognized, parameter defaults, and a concrete example. For a read-only analysis tool whose safety profile is carried by annotations, nothing essential for an agent 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.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both url and response_format are already fully documented with type, default, and format details. The description's Args section largely restates the schema rather than adding new meaning, though it does provide an illustrative example invocation. Per the rubric, with high schema coverage the baseline is 3, and the description adds only marginal value beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb+resource pair — 'Extract and validate JSON-LD, microdata and RDFa' — which names both the action and the exact subject matter. The tool title and covered-types list (Article, Product, FAQPage, etc.) reinforce the scope, and the focus on Schema.org structured data clearly differentiates it from siblings like robots_txt_check, meta_tags_check, and sitemap_check, which target entirely different SEO concerns.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The example ('Does https://example.com/product have valid Product schema?') implies a concrete use case, and the covered-types enumeration hints at when the tool applies. However, there is no explicit statement of when to use this versus an alternative, nor any exclusionary guidance (e.g., 'for general SEO issues use seo_audit'). The usage context is implied but never stated, which is a genuine gap given the 16 sibling tools.
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.
17 tool updates
v1.2.0- Changed
ai_crawler_access4 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / path / maxLengthAdded value: +2048 - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
canonical_host_check3 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
content_analysis3 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
geo_audit9 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - changed
Output schema / properties / crawler_access / anyOfPrevious value: -[ - { - "additionalProperties": false, - "properties": { - "allowed_count": { - "type": "number" - }, - "blocked_citation_critical": { - "items": { - "type": "string" - }, - "type": "array" - }, - "blocked_count": { - "type": "number" - }, - "crawlers": { - "items": { - "additionalProperties": false, - "properties": { - "allowed": { - "type": "boolean" - }, - "compliance_note": { - "type": [ - "string", - "null" - ] - }, - "deprecated": { - "type": "boolean" - }, - "matched_rule": { - "type": [ - "string", - "null" - ] - }, - "provenance": { - "type": "string" - }, - "purpose": { - "type": "string" - }, - "quirk": { - "type": [ - "string", - "null" - ] - }, - "respects_robots_txt": { - "type": "string" - }, - "token": { - "type": "string" - }, - "vendor": { - "type": "string" - }, - "via_wildcard": { - "type": "boolean" - } - }, - "required": [ - "token", - "vendor", - "purpose", - "allowed", - "via_wildcard", - "matched_rule", - "respects_robots_txt", - "compliance_note", - "provenance", - "deprecated", - "quirk" - ], - "type": "object" - }, - "type": "array" - }, - "findings": { - "$ref": "#/properties/geo/properties/findings" - }, - "path": { - "type": "string" - }, - "robots_found": { - "type": "boolean" - }, - "undocumented_vendors": { - "items": { - "additionalProperties": false, - "properties": { - "note": { - "type": "string" - }, - "vendor": { - "type": "string" - } - }, - "required": [ - "vendor", - "note" - ], - "type": "object" - }, - "type": "array" - }, - "unenforceable_blocks": { - "items": { - "type": "string" - }, - "type": "array" - }, - "url": { - "type": "string" - } - }, - "required": [ - "url", - "path", - "robots_found", - "crawlers", - "allowed_count", - "blocked_count", - "blocked_citation_critical", - "unenforceable_blocks", - "undocumented_vendors", - "findings" - ], - "type": "object" - }, - { - "type": "null" - } -]New value: +[ + { + "additionalProperties": false, + "properties": { + "allowed_count": { + "type": "number" + }, + "blocked_citation_critical": { + "items": { + "type": "string" + }, + "type": "array" + }, + "blocked_count": { + "type": "number" + }, + "crawlers": { + "items": { + "additionalProperties": false, + "properties": { + "allowed": { + "type": "boolean" + }, + "compliance_note": { + "type": [ + "string", + "null" + ] + }, + "deprecated": { + "type": "boolean" + }, + "matched_rule": { + "type": [ + "string", + "null" + ] + }, + "provenance": { + "type": "string" + }, + "purpose": { + "type": "string" + }, + "quirk": { + "type": [ + "string", + "null" + ] + }, + "respects_robots_txt": { + "type": "string" + }, + "token": { + "type": "string" + }, + "vendor": { + "type": "string" + }, + "via_wildcard": { + "type": "boolean" + } + }, + "required": [ + "token", + "vendor", + "purpose", + "allowed", + "via_wildcard", + "matched_rule", + "respects_robots_txt", + "compliance_note", + "provenance", + "deprecated", + "quirk" + ], + "type": "object" + }, + "type": "array" + }, + "findings": { + "items": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + }, + "severity": { + "type": "string" + } + }, + "required": [ + "severity", + "message" + ], + "type": "object" + }, + "type": "array" + }, + "path": { + "type": "string" + }, + "robots_found": { + "type": "boolean" + }, + "undocumented_vendors": { + "items": { + "additionalProperties": false, + "properties": { + "note": { + "type": "string" + }, + "vendor": { + "type": "string" + } + }, + "required": [ + "vendor", + "note" + ], + "type": "object" + }, + "type": "array" + }, + "unenforceable_blocks": { + "items": { + "type": "string" + }, + "type": "array" + }, + "url": { + "type": "string" + } + }, + "required": [ + "url", + "path", + "robots_found", + "crawlers", + "allowed_count", + "blocked_count", + "blocked_citation_critical", + "unenforceable_blocks", + "undocumented_vendors", + "findings" + ], + "type": "object" + }, + { + "type": "null" + } +] - changed
Output schema / properties / llms_txt / anyOfPrevious value: -[ - { - "additionalProperties": false, - "properties": { - "adoption_status": { - "type": "string" - }, - "bytes": { - "type": "number" - }, - "findings": { - "$ref": "#/properties/geo/properties/findings" - }, - "found": { - "type": "boolean" - }, - "full_variant_found": { - "type": "boolean" - }, - "has_optional_section": { - "type": "boolean" - }, - "has_summary_blockquote": { - "type": "boolean" - }, - "link_count": { - "type": "number" - }, - "sections": { - "items": { - "type": "string" - }, - "type": "array" - }, - "spec_compliant": { - "type": "boolean" - }, - "status": { - "type": [ - "number", - "null" - ] - }, - "title": { - "type": [ - "string", - "null" - ] - }, - "url": { - "type": "string" - } - }, - "required": [ - "url", - "found", - "status", - "full_variant_found", - "bytes", - "title", - "has_summary_blockquote", - "sections", - "link_count", - "has_optional_section", - "spec_compliant", - "adoption_status", - "findings" - ], - "type": "object" - }, - { - "type": "null" - } -]New value: +[ + { + "additionalProperties": false, + "properties": { + "adoption_status": { + "type": "string" + }, + "bytes": { + "type": "number" + }, + "findings": { + "items": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + }, + "severity": { + "type": "string" + } + }, + "required": [ + "severity", + "message" + ], + "type": "object" + }, + "type": "array" + }, + "found": { + "type": "boolean" + }, + "full_variant_found": { + "type": "boolean" + }, + "has_optional_section": { + "type": "boolean" + }, + "has_summary_blockquote": { + "type": "boolean" + }, + "link_count": { + "type": "number" + }, + "sections": { + "items": { + "type": "string" + }, + "type": "array" + }, + "spec_compliant": { + "type": "boolean" + }, + "status": { + "type": [ + "number", + "null" + ] + }, + "title": { + "type": [ + "string", + "null" + ] + }, + "url": { + "type": "string" + } + }, + "required": [ + "url", + "found", + "status", + "full_variant_found", + "bytes", + "title", + "has_summary_blockquote", + "sections", + "link_count", + "has_optional_section", + "spec_compliant", + "adoption_status", + "findings" + ], + "type": "object" + }, + { + "type": "null" + } +] - removed
Output schema / properties / rendering / properties / findings / $refRemoved value: -"#/properties/geo/properties/findings" - added
Output schema / properties / rendering / properties / findings / itemsAdded value: +{ + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + }, + "severity": { + "type": "string" + } + }, + "required": [ + "severity", + "message" + ], + "type": "object" +} - added
Output schema / properties / rendering / properties / findings / typeAdded value: +"array" - changed
Output schema / properties / robots / anyOfPrevious value: -[ - { - "additionalProperties": false, - "properties": { - "blocks_everything": { - "type": "boolean" - }, - "findings": { - "$ref": "#/properties/geo/properties/findings" - }, - "found": { - "type": "boolean" - }, - "group_count": { - "type": "number" - }, - "groups": { - "items": { - "additionalProperties": false, - "properties": { - "agents": { - "items": { - "type": "string" - }, - "type": "array" - }, - "crawl_delay": { - "type": [ - "number", - "null" - ] - }, - "rules": { - "items": { - "additionalProperties": false, - "properties": { - "path": { - "type": "string" - }, - "type": { - "type": "string" - } - }, - "required": [ - "type", - "path" - ], - "type": "object" - }, - "type": "array" - } - }, - "required": [ - "agents", - "rules", - "crawl_delay" - ], - "type": "object" - }, - "type": "array" - }, - "parse_warnings": { - "items": { - "type": "string" - }, - "type": "array" - }, - "sitemaps": { - "items": { - "type": "string" - }, - "type": "array" - }, - "status": { - "type": [ - "number", - "null" - ] - }, - "url": { - "type": "string" - } - }, - "required": [ - "url", - "found", - "status", - "group_count", - "sitemaps", - "blocks_everything", - "groups", - "parse_warnings", - "findings" - ], - "type": "object" - }, - { - "type": "null" - } -]New value: +[ + { + "additionalProperties": false, + "properties": { + "blocks_everything": { + "type": "boolean" + }, + "findings": { + "items": { + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + }, + "severity": { + "type": "string" + } + }, + "required": [ + "severity", + "message" + ], + "type": "object" + }, + "type": "array" + }, + "found": { + "type": "boolean" + }, + "group_count": { + "type": "number" + }, + "groups": { + "items": { + "additionalProperties": false, + "properties": { + "agents": { + "items": { + "type": "string" + }, + "type": "array" + }, + "crawl_delay": { + "type": [ + "number", + "null" + ] + }, + "rules": { + "items": { + "additionalProperties": false, + "properties": { + "path": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "type", + "path" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "agents", + "rules", + "crawl_delay" + ], + "type": "object" + }, + "type": "array" + }, + "parse_warnings": { + "items": { + "type": "string" + }, + "type": "array" + }, + "sitemaps": { + "items": { + "type": "string" + }, + "type": "array" + }, + "status": { + "type": [ + "number", + "null" + ] + }, + "url": { + "type": "string" + } + }, + "required": [ + "url", + "found", + "status", + "group_count", + "sitemaps", + "blocks_everything", + "groups", + "parse_warnings", + "findings" + ], + "type": "object" + }, + { + "type": "null" + } +]
- Changed
heading_structure3 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
hreflang_check3 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
image_seo_check3 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
link_audit4 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - changed
Input schema / properties / check_broken / descriptionPrevious value: -"Sample links and verify they resolve. Adds up to 25 requests."New value: +"Sample links and verify they resolve. Adds up to sample_size requests (default 25), six at a time." - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
llms_txt_check3 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
meta_tags_check3 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
redirect_trace3 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
render_check3 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
robots_txt_check3 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
seo_audit6 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Output schema / properties / findings / $refRemoved value: -"#/properties/geo/anyOf/0/properties/findings" - added
Output schema / properties / findings / itemsAdded value: +{ + "additionalProperties": false, + "properties": { + "message": { + "type": "string" + }, + "severity": { + "type": "string" + } + }, + "required": [ + "severity", + "message" + ], + "type": "object" +} - added
Output schema / properties / findings / typeAdded value: +"array"
- Changed
sitemap_check3 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
social_preview_check5 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - added
Output schema / properties / open_graph / propertyNamesAdded value: +{ + "type": "string" +} - added
Output schema / properties / twitter / propertyNamesAdded value: +{ + "type": "string" +}
- Changed
structured_data_check3 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - changed
Output schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
17 tool updates
v1.0.0- First observed
ai_crawler_access - First observed
canonical_host_check - First observed
content_analysis - First observed
geo_audit - First observed
heading_structure - First observed
hreflang_check - First observed
image_seo_check - First observed
link_audit - First observed
llms_txt_check - First observed
meta_tags_check - First observed
redirect_trace - First observed
render_check - First observed
robots_txt_check - First observed
seo_audit - First observed
sitemap_check - First observed
social_preview_check - First observed
structured_data_check
TDQS
Scored across 17 tools
Each tool targets a distinct SEO/geo concern: robots.txt, AI crawler access, llms.txt, page rendering, meta tags, social preview, headings, structured data, content, images, sitemap, links, hreflang, redirects, and canonical host. No two tools overlap; even the closely related robots_txt_check and ai_crawler_access are clearly differentiated by scope (all bots vs. AI bots).
All tools follow a consistent snake_case verb_noun pattern: robots_txt_check, seo_audit, geo_audit, ai_crawler_access, llms_txt_check, render_check, meta_tags_check, social_preview_check, heading_structure, structured_data_check, content_analysis, image_seo_check, sitemap_check, link_audit, hreflang_check, redirect_trace, canonical_host_check. Naming clearly indicates what each tool does with no convention mixing.
At 17 tools, the set is on the heavier side but appropriate for a comprehensive SEO/geo audit server covering a wide range of technical checks. The count is justified by the breadth of the domain; no tool feels redundant or trivial.
The server covers the major technical SEO and AI-visibility surfaces: robots.txt, rendering, meta tags, social preview, headings, structured data, content quality, images, sitemaps, links, hreflang, redirects, and canonicalization. Minor gaps exist (e.g., no tool for keyword research, backlink analysis, or mobile usability), but these fall outside the apparent scope of a technical/geo audit server.
Maintenance
Related MCP Connectors
- RampifyOAuthdev.rampify
SEO MCP server: crawl your site, find AI-visibility gaps, and ship the fix from your coding agent.
Open-source AI SEO over MCP: audits, ranks, keywords, backlinks + AI visibility (GEO).
Run SEO + AI-visibility (GEO) audits from Claude, Cursor & other AI clients.
Free technical-SEO audit MCP: crawl a site, run checks, return an LLM-ready shareable report.
Related MCP Servers
- AlicenseNot gradedqualityNot gradedmaintenanceMCP server for website SEO + GEO analysis. Scan any URL to get scores across 5 categories (SEO, GEO, Performance, Security, Accessibility) with actionable fix recommendations. Enables AI coding assistants to audit websites and implement fixes autonomously.-
- AlicenseNot gradedqualityCmaintenanceOpen-source technical SEO crawler MCP server built on LibreCrawl. Runs full audits inside Claude, Cursor, or Codex — 50+ checks (hreflang, schema.org, security headers, WAF detection on 200-OK pages), chunked-progressive engine for large sites, ephemeral by design (server forgets every audit after download).40MIT
- AlicenseAqualityDmaintenanceEnables AI agents to perform comprehensive SEO audits on web pages, including meta tags, headings, links, images, performance, and more, via a CLI or MCP server.1815 PyPI1MIT

atomno-mcp-seo-auditofficial
AlicenseAqualityAmaintenanceMCP server for technical SEO audits, powered by the detail.web engine. Run a site audit straight from your AI agent to get a health score, issues across 8 categories, and a GEO sub-score.840 PyPI1MIT
social_preview_checkSocial Preview (Open Graph & Twitter Card) CheckARead-onlyIdempotent
Validate the tags that build link-preview cards on X, LinkedIn, Facebook, Slack, WhatsApp and Discord: og:title, og:description, og:image, og:url, og:type, og:site_name and the twitter:* family. Optionally verifies the preview image actually loads, and flags the classic bug of a relative og:image URL (social scrapers require absolute URLs).
Args:
url (string): the page to check.
check_image (boolean): verify the og:image resolves (default true).
response_format ('markdown' | 'json'): output format (default 'markdown').
Returns: { open_graph{}, twitter{}, og_image_url, og_image_reachable, og_image_status, score, grade, findings[] }.
Example: "Why does my link preview look broken on LinkedIn?" -> social_preview_check(url="https://example.com/post").
Output Schema
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnlyHint, idempotentHint, openWorldHint, non-destructive). The description adds genuinely useful behavioral context beyond that: it discloses that the tool optionally issues a HEAD request to verify the og:image loads, and that it specifically flags relative og:image URLs — a classic pitfall behavior an agent wouldn't infer from annotations alone.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured: purpose is front-loaded in the first sentence with platforms and tag families, followed by behavioral specifics, then Args/Returns/Example sections. The Args section is somewhat redundant with the fully-covered schema, which prevents a 5, but every other sentence earns its place and the example is tightly scoped.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-URL validation tool with 3 well-documented params, rich annotations, and an output schema, the description is complete: it explains the return payload shape, provides an example, and covers the main behavioral nuance (image reachability check). Nothing essential for correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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's Args section largely restates what the schema already documents (defaults for check_image and response_format are duplicated). The example does demonstrate realistic invocation syntax, but the description adds minimal semantic value beyond the schema's parameter descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb-resource pair ('Validate the tags that build link-preview cards') and enumerates the exact tag families (og:title, og:description, og:image, og:url, og:type, og:site_name, twitter:*) as well as the target platforms (X, LinkedIn, Facebook, Slack, WhatsApp, Discord). This clearly distinguishes it from siblings like meta_tags_check (generic meta tags), image_seo_check, and render_check.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The example query ('Why does my link preview look broken on LinkedIn?') provides a concrete, actionable when-to-use signal that an agent can match against a user's intent. However, it does not explicitly name alternatives or state when NOT to use this tool (e.g., versus meta_tags_check for general tag validation), so it stops short of full exclusion guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.