SEO & GEO
NPM · SEO-GEO-MCP-SERVER · SCANNED SEP 21
Audit a page's SEO and its readiness for AI answer engines: meta, schema, robots, sitemaps, AI bots.
Available components
How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. How we score → Why this is hard to score →
Supply Chain Security98
- No malware found by supply-chain analysis.Pass
- No known CVEs affecting this package version or its production dependencies.Pass
- No install/post-install scripts declared.Pass
- 25 of 96 dependencies flagged as unhealthy (1 deprecated). View diagnostics → Partial
Provenance & Transparency45
- Source repository is publicly reachable at the declared URL. View diagnostics → Pass
- Provenance check failed: no build-provenance attestation is published. See how to fix → View diagnostics → Fail
- Clear OSI-approved license (MIT).Pass
- Actively maintained (last published 9 days ago).Pass
- Disclosure check failed: no security disclosure policy was found in the source repository. See how to fix → Fail
Schema Quality & AI Usability66
- AI-judged instruction clarity (excellent).Pass
- Context-footprint check failed: tool/resource definitions use about 5645 tokens (~332/item across 17 items; 17 tools + 0 resources), over budget; trim descriptions and params. See how to fix → Fail
- Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management33
- Stability observed for 10 of 30 days with no destabilising changes; credit accrues until the full window elapses.Partial
Tool Coverage100
- 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
- 100% of tool parameters carry a description.Pass
- Structured output schemas are declared (100% of tools); any adoption earns full credit.Pass
Tool Safety100
- No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.Pass
- We read all 17 captured tool definition(s), and no name or description among them implies an irreversible operation.Pass
- An AI judge read all 18 captured unit(s) of tool text and found none that tries to manipulate the model reading it.Pass
Capabilities100
- Implements a current MCP spec version (2026-07-28).Pass
How do I install the SEO & GEO MCP server?
SEO & GEO runs locally as an npm package, launched with npx -y seo-geo-mcp-server. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.
npm · seo-geo-mcp-server
claude mcp add ortamarco-seo-geo-mcp-server -- npx -y seo-geo-mcp-server
{
"mcpServers": {
"ortamarco-seo-geo-mcp-server": {
"command": "npx",
"args": [
"-y",
"seo-geo-mcp-server"
]
}
}
} {
"servers": {
"ortamarco-seo-geo-mcp-server": {
"command": "npx",
"args": [
"-y",
"seo-geo-mcp-server"
]
}
}
} codex mcp add ortamarco-seo-geo-mcp-server -- npx -y seo-geo-mcp-server
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"ortamarco-seo-geo-mcp-server": {
"type": "local",
"command": [
"npx",
"-y",
"seo-geo-mcp-server"
],
"enabled": true
}
}
} openclaw mcp add ortamarco-seo-geo-mcp-server --command npx --arg -y --arg seo-geo-mcp-server
mcp_servers:
ortamarco-seo-geo-mcp-server:
command: "npx"
args: ["-y", "seo-geo-mcp-server"] {
"McpServers": {
"ortamarco-seo-geo-mcp-server": {
"Transport": "stdio",
"Command": "npx",
"Arguments": [
"-y",
"seo-geo-mcp-server"
]
}
}
} assistant mcp add ortamarco-seo-geo-mcp-server -t stdio -c npx -a -y seo-geo-mcp-server
{
"mcpServers": {
"ortamarco-seo-geo-mcp-server": {
"command": "npx",
"args": [
"-y",
"seo-geo-mcp-server"
]
}
}
} Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.
- 21 Sept 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 30 to 33. That category is still filling its 30-day observation window: 9 days of observed history at the previous scan, 10 at this one. The score rises as the window fills, whether or not the server changes.
- 19 Sept 26 +4
- Stability: unverified → 0.27 ▲ functional
- 13 Sept 26 +15
- Malware scan: unverified → pass ▲ security
- 12 Sept 26 0
- Security disclosure: unverified → fail ▼ functional
- 11 Sept 26 53
First indexed and scored.
Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.
Captured 21 Sept 2026 · Analysed npm/seo-geo-mcp-server@1.2.0
Provenance No attestation
The registry publishes no build provenance for this version, so there is nothing to verify.
| Result | No attestation |
|---|---|
| Ecosystem | npm |
Background: How many MCP packages publish verified provenance →
Dependencies 96 packages
| Packages resolved | 96 |
|---|---|
| Deprecated | 1 |
| Stale | 25 |
| Tree resolution | Complete |
Background: SBOMs and build attestations, explained →
The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability. A tool's description is untrusted text the model reads on every call, which is what makes this list a security surface and not just an inventory: how tool poisoning works →
ai_crawler_access AI Crawler Access Check ~592
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: 1. **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. 2. **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. 3. **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…
| Name | Type | Req | Description |
|---|---|---|---|
| include_deprecated | boolean | – | Also resolve retired tokens (anthropic-ai, claude-web) for historical coverage. |
| path | string | – | Path to test the rules against, e.g. '/blog/post'. Defaults to '/'. |
| response_format | string | – | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. |
| site | string | yes | Domain or any URL on it, e.g. 'example.com'. |
| Name | Type | Req | Description |
|---|---|---|---|
| allowed_count | number | yes | – |
| blocked_citation_critical | array | yes | – |
| blocked_count | number | yes | – |
| crawlers | array | yes | – |
| findings | array | yes | – |
| path | string | yes | – |
| robots_found | boolean | yes | – |
| undocumented_vendors | array | yes | – |
| unenforceable_blocks | array | yes | – |
| url | string | yes | – |
No examples provided.
canonical_host_check Canonical Host Check ~261
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 | Type | Req | Description |
|---|---|---|---|
| response_format | string | – | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. |
| site | string | yes | Site domain or any URL on it, e.g. 'example.com'. Only the origin is used. |
| Name | Type | Req | Description |
|---|---|---|---|
| canonical_url | string|null | yes | – |
| converges | boolean | yes | – |
| distinct_endpoints | array | yes | – |
| domain | string | yes | – |
| findings | array | yes | – |
| forces_https | boolean | yes | – |
| grade | string | yes | – |
| score | number | yes | – |
| variants | array | yes | – |
No examples provided.
content_analysis Content Quality Analysis ~270
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 <main>/<article> 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 | Type | Req | Description |
|---|---|---|---|
| response_format | string | – | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. |
| url | string | yes | Page URL to analyse, e.g. 'https://example.com/blog/post'. The scheme defaults to https://. |
| Name | Type | Req | Description |
|---|---|---|---|
| avg_words_per_sentence | number | yes | – |
| final_url | string | yes | – |
| findings | array | yes | – |
| grade | string | yes | – |
| html_bytes | number | yes | – |
| paragraph_count | number | yes | – |
| reading_ease | number | yes | – |
| reading_level | string | yes | – |
| reading_time_minutes | number | yes | – |
| score | number | yes | – |
| sentence_count | number | yes | – |
| text_to_html_ratio | number | yes | – |
| thin_content | boolean | yes | – |
| top_terms | array | yes | – |
| url | string | yes | – |
| used_content_landmark | boolean | yes | – |
| word_count | number | yes | – |
No examples provided.
geo_audit GEO / AI Answer-Engine Readiness Audit ~369
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 | Type | Req | Description |
|---|---|---|---|
| response_format | string | – | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. |
| url | string | yes | Page URL to analyse, e.g. 'https://example.com/blog/post'. The scheme defaults to https://. |
| Name | Type | Req | Description |
|---|---|---|---|
| crawler_access | – | yes | – |
| geo | object | yes | – |
| llms_txt | – | yes | – |
| rendering | object | yes | – |
| robots | – | yes | – |
No examples provided.
heading_structure Heading Structure ~228
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 | Type | Req | Description |
|---|---|---|---|
| response_format | string | – | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. |
| url | string | yes | Page URL to analyse, e.g. 'https://example.com/blog/post'. The scheme defaults to https://. |
| Name | Type | Req | Description |
|---|---|---|---|
| empty_headings | number | yes | – |
| final_url | string | yes | – |
| findings | array | yes | – |
| grade | string | yes | – |
| h1_count | number | yes | – |
| h1_text | array | yes | – |
| headings | array | yes | – |
| level_skips | number | yes | – |
| outline | string | yes | – |
| question_headings | array | yes | – |
| score | number | yes | – |
| url | string | yes | – |
No examples provided.
hreflang_check Hreflang Check ~322
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 | Type | Req | Description |
|---|---|---|---|
| check_reciprocity | boolean | – | Fetch each alternate to confirm it links back. Catches the most common hreflang bug. |
| response_format | string | – | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. |
| url | string | yes | Page URL to analyse, e.g. 'https://example.com/blog/post'. The scheme defaults to https://. |
| Name | Type | Req | Description |
|---|---|---|---|
| declared_lang | string|null | yes | – |
| duplicate_codes | array | yes | – |
| entries | array | yes | – |
| final_url | string | yes | – |
| findings | array | yes | – |
| has_x_default | boolean | yes | – |
| invalid_codes | array | yes | – |
| reciprocity_checked | boolean | yes | – |
| self_referencing | boolean | yes | – |
| url | string | yes | – |
No examples provided.
image_seo_check Image SEO Check ~242
Audit every <img> 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. <picture> 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 | Type | Req | Description |
|---|---|---|---|
| response_format | string | – | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. |
| url | string | yes | Page URL to analyse, e.g. 'https://example.com/blog/post'. The scheme defaults to https://. |
| Name | Type | Req | Description |
|---|---|---|---|
| decorative_alt | number | yes | – |
| final_url | string | yes | – |
| findings | array | yes | – |
| grade | string | yes | – |
| images | array | yes | – |
| lazy_loaded | number | yes | – |
| legacy_format | number | yes | – |
| missing_alt | number | yes | – |
| missing_dimensions | number | yes | – |
| modern_format | number | yes | – |
| score | number | yes | – |
| total_images | number | yes | – |
| url | string | yes | – |
No examples provided.
link_audit Link Audit ~333
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 | Type | Req | Description |
|---|---|---|---|
| check_broken | boolean | – | Sample links and verify they resolve. Adds up to sample_size requests (default 25), six at a time. |
| response_format | string | – | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. |
| sample_size | integer | – | How many links to verify when check_broken is true. |
| url | string | yes | Page URL to analyse, e.g. 'https://example.com/blog/post'. The scheme defaults to https://. |
| Name | Type | Req | Description |
|---|---|---|---|
| broken | array | yes | – |
| checked_count | number | yes | – |
| empty_anchor_text | number | yes | – |
| external_domains | array | yes | – |
| external_links | number | yes | – |
| final_url | string | yes | – |
| findings | array | yes | – |
| generic_anchor_text | array | yes | – |
| grade | string | yes | – |
| internal_links | number | yes | – |
| nofollow_links | number | yes | – |
| score | number | yes | – |
| sponsored_links | number | yes | – |
| total_links | number | yes | – |
| ugc_links | number | yes | – |
| url | string | yes | – |
No examples provided.
llms_txt_check llms.txt Check ~373
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 | Type | Req | Description |
|---|---|---|---|
| response_format | string | – | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. |
| site | string | yes | Site domain or any URL on it, e.g. 'example.com'. Only the origin is used. |
| Name | Type | Req | Description |
|---|---|---|---|
| adoption_status | string | yes | – |
| bytes | number | yes | – |
| findings | array | yes | – |
| found | boolean | yes | – |
| full_variant_found | boolean | yes | – |
| has_optional_section | boolean | yes | – |
| has_summary_blockquote | boolean | yes | – |
| link_count | number | yes | – |
| sections | array | yes | – |
| spec_compliant | boolean | yes | – |
| status | number|null | yes | – |
| title | string|null | yes | – |
| url | string | yes | – |
No examples provided.
meta_tags_check Meta Tags Check ~230
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 | Type | Req | Description |
|---|---|---|---|
| response_format | string | – | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. |
| url | string | yes | Page URL to analyse, e.g. 'https://example.com/blog/post'. The scheme defaults to https://. |
| Name | Type | Req | Description |
|---|---|---|---|
| canonical | string|null | yes | – |
| canonical_is_self | boolean | yes | – |
| charset | string|null | yes | – |
| description | string|null | yes | – |
| description_length | number | yes | – |
| favicon | string|null | yes | – |
| final_url | string | yes | – |
| findings | array | yes | – |
| followable | boolean | yes | – |
| grade | string | yes | – |
| indexable | boolean | yes | – |
| lang | string|null | yes | – |
| meta_robots | string|null | yes | – |
| robots_directives | array | yes | – |
| score | number | yes | – |
| title | string|null | yes | – |
| title_length | number | yes | – |
| url | string | yes | – |
| viewport | string|null | yes | – |
| x_robots_tag | string|null | yes | – |
No examples provided.
redirect_trace Redirect Trace ~221
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 | Type | Req | Description |
|---|---|---|---|
| response_format | string | – | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. |
| url | string | yes | Page URL to analyse, e.g. 'https://example.com/blog/post'. The scheme defaults to https://. |
| Name | Type | Req | Description |
|---|---|---|---|
| elapsed_ms | number | yes | – |
| ends_https | boolean | yes | – |
| final_status | number | yes | – |
| final_url | string | yes | – |
| findings | array | yes | – |
| has_loop | boolean | yes | – |
| has_temporary_redirect | boolean | yes | – |
| hop_count | number | yes | – |
| hops | array | yes | – |
| https_upgrade | boolean | yes | – |
| url | string | yes | – |
No examples provided.
render_check JavaScript Rendering Check ~276
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 | Type | Req | Description |
|---|---|---|---|
| response_format | string | – | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. |
| url | string | yes | Page URL to analyse, e.g. 'https://example.com/blog/post'. The scheme defaults to https://. |
| Name | Type | Req | Description |
|---|---|---|---|
| findings | array | yes | – |
| framework_hint | string|null | yes | – |
| html_bytes | number | yes | – |
| renders_without_js | boolean | yes | – |
| script_bytes | number | yes | – |
| server_text_words | number | yes | – |
| spa_shell_detected | boolean | yes | – |
No examples provided.
robots_txt_check robots.txt Check ~266
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 | Type | Req | Description |
|---|---|---|---|
| response_format | string | – | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. |
| site | string | yes | Site domain or any URL on it, e.g. 'example.com'. Only the origin is used. |
| Name | Type | Req | Description |
|---|---|---|---|
| blocks_everything | boolean | yes | – |
| findings | array | yes | – |
| found | boolean | yes | – |
| group_count | number | yes | – |
| groups | array | yes | – |
| parse_warnings | array | yes | – |
| sitemaps | array | yes | – |
| status | number|null | yes | – |
| url | string | yes | – |
No examples provided.
seo_audit Full On-Page SEO Audit ~382
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 | Type | Req | Description |
|---|---|---|---|
| check_broken_links | boolean | – | Sample up to 25 links and verify they resolve. Slower, but catches dead links. |
| include_geo | boolean | – | Also score GEO (AI answer-engine) readiness. Adds ~2 requests. |
| response_format | string | – | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. |
| url | string | yes | Page URL to analyse, e.g. 'https://example.com/blog/post'. The scheme defaults to https://. |
| Name | Type | Req | Description |
|---|---|---|---|
| fetch_ms | number | yes | – |
| final_url | string | yes | – |
| findings | array | yes | – |
| geo | – | yes | – |
| grade | string | yes | – |
| indexable | boolean | yes | – |
| redirect_hops | number | yes | – |
| score | number | yes | – |
| sections | array | yes | – |
| status | number | yes | – |
| top_recommendations | array | yes | – |
| url | string | yes | – |
No examples provided.
sitemap_check XML Sitemap Check ~343
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, <lastmod> 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 | Type | Req | Description |
|---|---|---|---|
| follow_children | integer | – | How many child sitemaps of an index to follow (default 3). |
| response_format | string | – | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. |
| site | string | yes | Domain or any URL on it, e.g. 'example.com'. |
| sitemap_url | string | – | Explicit sitemap URL. Omit to discover it via robots.txt, then the conventional paths. |
| Name | Type | Req | Description |
|---|---|---|---|
| bytes | number | yes | – |
| child_sitemaps | array | yes | – |
| child_sitemaps_followed | number | yes | – |
| discovered_via | string | yes | – |
| duplicate_urls | array | yes | – |
| entries | array | yes | – |
| exceeds_size_limit | boolean | yes | – |
| exceeds_url_limit | boolean | yes | – |
| findings | array | yes | – |
| found | boolean | yes | – |
| grade | string | yes | – |
| invalid_lastmod | array | yes | – |
| newest_lastmod | string|null | yes | – |
| non_https_urls | array | yes | – |
| off_origin_urls | array | yes | – |
| oldest_lastmod | string|null | yes | – |
| score | number | yes | – |
| status | number|null | yes | – |
| type | string | yes | – |
| url | string | yes | – |
| url_count | number | yes | – |
| with_lastmod | number | yes | – |
No examples provided.
social_preview_check Social Preview (Open Graph & Twitter Card) Check ~268
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").
| Name | Type | Req | Description |
|---|---|---|---|
| check_image | boolean | – | Issue a HEAD request to confirm the og:image actually loads. |
| response_format | string | – | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. |
| url | string | yes | Page URL to analyse, e.g. 'https://example.com/blog/post'. The scheme defaults to https://. |
| Name | Type | Req | Description |
|---|---|---|---|
| final_url | string | yes | – |
| findings | array | yes | – |
| grade | string | yes | – |
| og_image_content_type | string|null | yes | – |
| og_image_reachable | boolean|null | yes | – |
| og_image_status | number|null | yes | – |
| og_image_url | string|null | yes | – |
| open_graph | object | yes | – |
| score | number | yes | – |
| object | yes | – | |
| url | string | yes | – |
No examples provided.
structured_data_check Structured Data (Schema.org) Check ~281
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 | Type | Req | Description |
|---|---|---|---|
| response_format | string | – | Output format: 'markdown' for a human-readable summary (default) or 'json' for the full structured payload. |
| url | string | yes | Page URL to analyse, e.g. 'https://example.com/blog/post'. The scheme defaults to https://. |
| Name | Type | Req | Description |
|---|---|---|---|
| final_url | string | yes | – |
| findings | array | yes | – |
| grade | string | yes | – |
| has_article | boolean | yes | – |
| has_breadcrumb | boolean | yes | – |
| has_faq | boolean | yes | – |
| has_organization | boolean | yes | – |
| has_person | boolean | yes | – |
| has_website | boolean | yes | – |
| items | array | yes | – |
| json_ld_blocks | number | yes | – |
| microdata_items | number | yes | – |
| parse_errors | array | yes | – |
| rdfa_items | number | yes | – |
| score | number | yes | – |
| types_found | array | yes | – |
| url | string | yes | – |
No examples provided.
What is the SEO & GEO MCP server?
SEO & GEO is an MCP server listed in the public MCP registry as io.github.OrtaMarco/seo-geo-mcp-server. Audit a page's SEO and its readiness for AI answer engines: meta, schema, robots, sitemaps, AI bots. This page covers its npm package (seo-geo-mcp-server).
Is the SEO & GEO MCP server safe to use?
SEO & GEO scores 73 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 21 September 2026. It declares no install or post-install scripts. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.
What tools does the SEO & GEO MCP server expose?
SEO & GEO exposes 17 tools: seo_audit, geo_audit, ai_crawler_access, llms_txt_check, render_check, and 12 more. Their descriptions and schemas cost roughly 5,257 tokens of context every time the server is loaded.
Is the SEO & GEO MCP server still maintained?
SEO & GEO is still listed as active in the MCP registry. We last reached this channel on 21 September 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.
What licence is the SEO & GEO MCP server under?
SEO & GEO declares the MIT licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.