{"$schema":"https://modelcontextprotocol.io/schema/draft/server-card.schema.json","name":"thatseoagent","description":"SEO analysis MCP server with 66 tools across Google Search Console, Google Analytics 4, PageSpeed Insights, and site-management workflows.","version":"1.0.0","serverUrl":"https://thatseoagent.com/mcp","serverInfo":{"name":"thatseoagent","title":"That SEO Agent MCP","version":"1.0.0","description":"SEO analysis MCP server with 66 tools across Google Search Console, Google Analytics 4, PageSpeed Insights, and site-management workflows.","vendor":"That SEO Agent","homepage":"https://thatseoagent.com","documentation":"https://thatseoagent.com/mcp-server-for-seo","openapi":"https://thatseoagent.com/openapi.json","license":"Proprietary"},"transport":{"type":"streamable-http","endpoint":"https://thatseoagent.com/mcp","methods":["POST","DELETE"]},"authentication":{"type":"oauth2","authorization_server":"https://thatseoagent.com/.well-known/oauth-authorization-server","protected_resource":"https://thatseoagent.com/.well-known/oauth-protected-resource","bearer_methods_supported":["header"],"apiKey":{"header":"Authorization","scheme":"Bearer","issuance":"https://thatseoagent.com/dashboard#api-keys"}},"capabilities":{"tools":{"listChanged":false},"resources":{"listChanged":false,"subscribe":false},"prompts":{"listChanged":false},"logging":{}},"toolCount":66,"toolsByCategory":{"Site management":11,"SEO":19,"Google Analytics 4":9,"Google Search Console":26,"PageSpeed":1},"tools":[{"name":"activate_site","title":"Activate Site","description":"Turn a registered site ON (mark it active) so its tools and audits work again. Your plan limit counts DISTINCT registrable domains: activating a site on a domain you already have active is always free (same slot); activating a site on a NEW domain consumes a slot. If that would exceed your limit, this returns a structured over-limit payload listing your active domains — deactivate all of another domain's sites with deactivate_site to make room, then try again.","category":"Site management","readOnly":false,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"ai_visibility_score","title":"AI Visibility Score","description":"Analyzes structured data, knowledge graph presence, content signals, and AI bot access — factors observed to correlate with AI citation in research literature. Returns a directional 0-100 score with per-layer breakdown. No AI platform publishes an official citation scoring standard; results are a best-effort heuristic. Requires the URL to return 2xx: on a 404, 401, 5xx or timeout it returns an error naming the status and runs no checks, because a non-2xx still serves a body and scoring it would describe an error page.","category":"SEO","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"complete_task","title":"Complete Task","description":"Mark an SEO task as done. Requires the task UUID (from get_tasks).","category":"Site management","readOnly":false,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"crawl_site","title":"Crawl Site","description":"Walk a site from the given URL and report what it finds. Up to 50 pages, 25 by default; pass maxPages: 1 to audit only the URL given. For the page you named: HTTP status and redirect hop count, final URL, title and meta description, canonical and noindex, H1s, word count, and the internal links it exposes (capped at 100, with the withheld count shown). The link list is the reason to reach for this tool — no other tool returns link targets, only counts. Across pages: duplicate titles, duplicate meta descriptions, broken internal links with where each was found, pages buried deep in the click hierarchy, and the shortest pages. Orphan pages are never reported: a crawler finds pages by following links, so it cannot reach the page nothing links to. At one page the cross-page checks are reported as n/a rather than as passing.","category":"SEO","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"create_shared_report","title":"Create Shared Report","description":"PUBLISHES a snapshot of a site's audit at a public URL: anyone holding the link can open it without an account or password, and the link stays valid for 14 days. Confirm with the user before calling this — it moves their site's data outside their account, and each call mints a new link rather than reusing the last one. Automatically runs a fresh audit first when the latest is stale (>7 days) or missing; that audit fetches the site's pages and is not free. It does not always publish fresh data: when the refresh is blocked — the site's refresh limit is spent, or the site refused to be read — the report is built from the last audit that succeeded, with the reason and that audit's date stated in the output. GSC and GA4 are optional — reports can be generated from HTTP-only audit data. Compiles from persistent audit data when available; falls back to cached tool data otherwise. If the site refuses to be read (a firewall or WAF answering 403 to our User-Agent), no report is minted from nothing: the block is reported with the status and the URL, or — when an audit from before the block survives — the report is built from it with the block stated first.","category":"Site management","readOnly":false,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"create_task","title":"Create Task","description":"Add a new SEO action-item task to a site's task list. Identify the site by siteUrl (e.g. example.com — the same identifier used by run_site_audit) or by its UUID via siteId.","category":"Site management","readOnly":false,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"deactivate_site","title":"Deactivate Site","description":"Turn a registered site OFF (mark it inactive). An inactive site keeps all its data. Your plan limit counts DISTINCT registrable domains (subdomains and paths of the same domain share one slot), so deactivating the LAST active site of a domain frees that domain's slot — letting you activate a site on a different domain. Use this to swap which domains are active. Reactivate later with activate_site.","category":"Site management","readOnly":false,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"delete_task","title":"Delete Task","description":"Permanently delete a task from a site's task list. Requires the task UUID (from get_tasks).","category":"Site management","readOnly":false,"destructive":true,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"entity_mentions","title":"Entity Mentions Audit","description":"Check whether a brand is mentioned or listed across key off-site platforms: Wikipedia, Wikidata, Reddit, LinkedIn, YouTube, and GitHub. Useful for understanding brand authority and entity establishment beyond the site itself.","category":"SEO","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"ga4_ai_traffic","title":"GA4 AI Engine Traffic","description":"Analyze referral traffic from AI engines (ChatGPT, Perplexity, Gemini, Claude, Copilot, Bing) in GA4. Shows sessions by AI source and top landing pages.","category":"Google Analytics 4","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"ga4_check_compatibility","title":"GA4 Check Field Compatibility","description":"Validate that a set of GA4 dimensions and metrics can be queried together BEFORE running a report. Returns which fields (if any) are incompatible so you fix the combination proactively instead of getting an opaque 400. Use before a large or expensive ga4_run_report / ga4_pivot_report, especially with custom fields.","category":"Google Analytics 4","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"ga4_custom_definitions","title":"GA4 Custom Dimensions & Metrics","description":"List a GA4 property's custom dimensions and custom metrics with their configuration (parameter name, scope, unit). Surfaces the property-specific fields a user set up.","category":"Google Analytics 4","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"ga4_get_realtime","title":"GA4 Get Realtime Data","description":"Get real-time active users and page-level data from Google Analytics 4. Shows who is on the site right now.","category":"Google Analytics 4","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"ga4_key_events","title":"GA4 Key Events (Conversions)","description":"List a GA4 property's key events (conversions) — the events the business marked as important. Use to frame reports around real outcomes.","category":"Google Analytics 4","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"ga4_list_properties","title":"GA4 List Properties","description":"List all Google Analytics 4 properties accessible to the authenticated user, including property ID, display name, and website URL. Each is annotated ACTIVE (a registered, active site), INACTIVE (a registered but deactivated site), or AVAILABLE (a property not yet registered), with current Site-Limit usage. Use the returned property IDs with ga4_run_report and other GA4 tools.","category":"Google Analytics 4","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"ga4_metadata","title":"GA4 Available Dimensions & Metrics","description":"Discover which dimensions and metrics can be queried for a GA4 property, including the property's own custom dimensions and metrics. Use before ga4_run_report to know what's measurable instead of guessing field names.","category":"Google Analytics 4","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"ga4_pivot_report","title":"GA4 Pivot Report","description":"Run a GA4 pivot report to cross-tabulate metrics across dimensions (e.g. channel × date, source × landing page). Clearer comparative views than a flat report.","category":"Google Analytics 4","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"ga4_run_report","title":"GA4 Run Report","description":"Run a Google Analytics 4 report with custom dimensions and metrics for a property. Supports filtering, ordering, and date ranges. Set compareStartDate/compareEndDate for period-over-period in one call, and includeTotals for an exact grand-total row (don't sum rows by hand). The result flags sampled or thresholded ((other)-row) data so you never present estimates as exact.","category":"Google Analytics 4","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"get_page_audits","title":"Get Page Audits","description":"Lists the stored page audits for a site, newest first. Identify the site by siteUrl (e.g. example.com — the same identifier used by run_site_audit) or by its UUID via siteId. Pass url to get that one page's full audit instead of the list.","category":"Site management","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"get_tasks","title":"Get Tasks","description":"List all SEO action-item tasks for a site, ordered newest first. Identify the site by siteUrl (e.g. example.com — the same identifier used by run_site_audit) or by its UUID via siteId.","category":"Site management","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"gsc_branded_split","title":"GSC Branded vs Non-branded Split","description":"Split a property's search traffic into branded vs non-branded by matching brand terms against queries. Shows clicks/impressions and share for each, plus top queries — reveals how much traffic is brand recognition vs genuine discovery.","category":"Google Search Console","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"gsc_bulk_url_inspection","title":"GSC Bulk URL Inspection","description":"Inspect up to 200 URLs at once in Google Search Console, grouped by indexing coverage state. Useful for auditing large batches of pages.","category":"Google Search Console","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"gsc_country_opportunity","title":"GSC Country Opportunity","description":"Rank countries by untapped demand — high impressions but low CTR — to find international markets where you appear but don't yet convert clicks.","category":"Google Search Console","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"gsc_crawl_freshness","title":"GSC Crawl Freshness","description":"Inspect a site's sitemap URLs and rank pages by how long ago Google last crawled them — surfaces indexed pages serving stale content that need a refresh or re-crawl.","category":"Google Search Console","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"gsc_detect_anomalies","title":"GSC Detect Anomalies","description":"Detect statistically significant traffic anomalies (drops and spikes) in Google Search Console data using modified Z-score analysis.","category":"Google Search Console","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"gsc_detect_cannibalization","title":"GSC Detect Cannibalization","description":"Find keyword cannibalization issues where multiple pages compete for the same search queries, diluting ranking potential.","category":"Google Search Console","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"gsc_detect_featured_snippets","title":"GSC Detect Featured Snippet Opportunities","description":"Find queries in positions 2–5 that are prime candidates for featured snippets. Analyzes HTML structure and scores each opportunity.","category":"Google Search Console","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"gsc_detect_lost_queries","title":"GSC Detect Lost Queries","description":"Compare two time periods to find keywords where traffic dropped significantly. Useful for diagnosing ranking losses after algorithm updates.","category":"Google Search Console","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"gsc_detect_quick_wins","title":"GSC Detect Quick Wins","description":"Find high-impression, low-CTR keywords in GSC that are quick optimization opportunities.","category":"Google Search Console","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"gsc_detect_trends","title":"GSC Detect Trends","description":"Identify rising and declining keyword trends in Google Search Console data using linear regression analysis over a date range.","category":"Google Search Console","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"gsc_device_gap","title":"GSC Device Gap (mobile vs desktop)","description":"Find queries where the site ranks worse on mobile than desktop — the gap, mobile/desktop positions and mobile impressions. Surfaces mobile-specific ranking problems.","category":"Google Search Console","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"gsc_discover_performance","title":"GSC Google Discover Performance","description":"Show Google Discover traffic (separate from web search) by page — clicks, impressions and CTR. Discover surfaces content to users who haven't searched; valuable for content sites.","category":"Google Search Console","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"gsc_get_sitemap","title":"GSC Get Sitemap Details","description":"Get detailed information about a specific sitemap submitted to Google Search Console, including URL counts and errors.","category":"Google Search Console","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"gsc_index_coverage_analysis","title":"GSC Index Coverage Analysis","description":"Analyze Google's indexing coverage quota-efficiently: HTTP health (404s/redirects/5xx) comes from a crawl at zero GSC quota, Search Analytics identifies pages Google already serves, and only the 'indexable gap' (live pages not served) spends URL Inspection budget. Source: sitemap (default), crawl, or a manual URL list. Returns HTTP health, served-skipped count, gap grouped by coverage state, and deferred/budget info.","category":"Google Search Console","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"gsc_inspect_url","title":"GSC Inspect URL","description":"Inspect a URL's indexing status, coverage state, mobile usability and last crawl time via Google Search Console.","category":"Google Search Console","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"gsc_list_properties","title":"GSC List Properties","description":"List all Google Search Console properties the authenticated user has access to. Each is annotated ACTIVE (a registered, active site), INACTIVE (a registered but deactivated site), or AVAILABLE (a property not yet registered), with current Site-Limit usage.","category":"Google Search Console","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"gsc_list_sitemaps","title":"GSC List Sitemaps","description":"List all sitemaps submitted to Google Search Console for a property, including status, errors and warnings.","category":"Google Search Console","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"gsc_page_changes","title":"GSC New & Lost Pages","description":"Compare two periods to list pages that newly started getting search impressions and pages that stopped — page-level companion to lost-query analysis.","category":"Google Search Console","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"gsc_page_query_map","title":"GSC Page ↔ Query Map","description":"Map each top page to the queries it ranks for — reveals which pages are well-focused vs ranking for many unrelated intents.","category":"Google Search Console","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"gsc_rich_results","title":"GSC Rich Results","description":"Show the rich result types Google actually detected on a URL (Product, Review, FAQ, Breadcrumb, etc.) and any structured-data issues per type — straight from Search Console's URL inspection, not inferred.","category":"Google Search Console","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"gsc_search_analytics","title":"GSC Search Analytics","description":"Fetch clicks, impressions, CTR and average position from Google Search Console for a property. Set dataState='all' to include fresh, still-incomplete data from the last ~2 days for early detection of traffic drops.","category":"Google Search Console","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"gsc_search_analytics_by_indexing_state","title":"GSC Search Analytics by Indexing State","description":"Combine GSC search analytics data with live URL inspection results to show top-traffic pages alongside their current indexing state.","category":"Google Search Console","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"gsc_search_appearance","title":"GSC Search Appearance Breakdown","description":"Break down search performance by the SERP feature your pages appear as (rich results, AMP, video, review snippet, etc.) — clicks, impressions, CTR and position per appearance type.","category":"Google Search Console","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"gsc_serp_features_gap","title":"GSC SERP Features Gap Analysis","description":"Identify structured data (schema markup) gaps on top-ranking pages by comparing detected schemas against query intent. Estimates CTR uplift for missing schemas.","category":"Google Search Console","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"gsc_sitemap_url_inspection","title":"GSC Sitemap URL Inspection","description":"Parse a sitemap and bulk-inspect all URLs in Google Search Console to find indexing issues. Returns a coverage breakdown with statistics.","category":"Google Search Console","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"gsc_sites_health_check","title":"GSC Multi-Site Health Check","description":"Run a health check across all GSC properties. Checks week-over-week traffic, sitemap errors and anomalies — prioritized by severity.","category":"Google Search Console","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"pagespeed_insights","title":"PageSpeed Insights","description":"Runs Google PageSpeed Insights for a URL and returns Core Web Vitals and Lighthouse scores. Results are stored in a temporary cache and are not persisted to the database.","category":"PageSpeed","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"run_page_audit","title":"Run Page Audit","description":"Audits a single URL and persists the result to the database, under the registered site that owns the URL's hostname. Use this for a page or a section (e.g. example.com/es/blog) — run_site_audit is for a whole site or subdomain. Unlike the seo_* tools, whose results are only cached temporarily, this is stored and can be read back with get_page_audits. Runs on-page, content, structured-data, crawlability, E-E-A-T and GEO checks, plus PageSpeed and per-URL Search Console data when available. The site must already be registered; this never registers one. A bare domain audits that site's homepage.","category":"Site management","readOnly":false,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"run_site_audit","title":"Run Site Audit","description":"Runs the site audit pipeline for a domain or subdomain and persists results to the database. Returns the full SEO audit. If the siteUrl names a page rather than a site (e.g. example.com/es), this audits that page instead and says so — a path is a page, not a site. Triggers a background refresh when results are stale (>7 days) or missing, then returns after completion. GSC and GA4 are optional — the audit runs on HTTP-only data when not connected. A refresh in progress returns a status message; check again in ~60s. If the site does not let us read the page (a firewall or WAF answering 403 to our User-Agent, a timeout), the pipeline stops at the reachability gate and returns the status, the URL and a curl line to reproduce it — no audit is produced and calling again within the hour will return the same answer without spending the site's refresh budget. Pass ga4PropertyId to link a specific GA4 property.","category":"Site management","readOnly":false,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"seo_agent_api_surface","title":"SEO Agent API Surface Audit","description":"Audits whether an agent could actually call this site's API. Finds the OpenAPI description (conventional paths, a Link rel=service-desc, or an RFC 9727 api-catalog), then reports per-operation fractions rather than a verdict: typed response schemas, unique operationIds, descriptions, typed parameters, and whether the API declares a version a caller can pin to. Also probes one read-only path that should not exist to see whether errors come back as parseable JSON and whether the response states the caller's remaining rate-limit budget. Every finding cites the operationId and path, and states the curl line that produced it. All probes are read-only GETs: this never writes, never authenticates, and never sends a request to a different registrable domain than the site being audited. If no API description is found, every check is n/a and nothing is scored — a site with no API is not a site with a failing API. Results are stored in a temporary cache and are not persisted to the database.","category":"SEO","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"seo_agent_discovery","title":"SEO Agent Discovery Artifacts Audit","description":"Audits the machine-readable artifacts an agent looks for before anything else, and validates their PAYLOAD rather than their status: the MCP server card and endpoint, OAuth protected-resource and authorization-server metadata (RFC 9728 / RFC 8414, including PKCE S256), auth.md and its seven sections, the Agent Skills index — whose sha256 digests are verified against the bytes actually served — the RFC 9727 api-catalog, the RFC 9421 Web Bot Auth key directory, and pricing.md. One check walks the auth discovery chain end to end and reports the step it stops at, because each document can be individually valid while the path between them is broken. This tier ONLY EVER ADDS: it reports a bonus out of +5, an absent artifact is n/a and costs nothing, and no site can score below what a site publishing none of them would get. All probes are read-only, unauthenticated GETs on the site's own origin. Results are stored in a temporary cache and are not persisted to the database.","category":"SEO","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"seo_agent_navigability","title":"SEO Agent Navigability Audit","description":"Audits the HTTP facts an agent depends on to navigate a site rather than just read one page: whether a missing path returns a real 404 instead of the app shell, whether that 404 body names a way back, whether redirects happen in HTTP rather than in a meta refresh or a JavaScript stub, whether the URL answers Accept: text/markdown and says Vary: Accept when it does, whether the extracted text fits an agent's reading budget, whether the served markdown's code fences are balanced, and whether RFC 8288 Link headers advertise the sitemap and API description. Every check states the curl line that produced it, so any finding can be re-run. Makes three read-only GET requests (the URL, a path that should not exist, and the URL again asking for markdown) and never authenticates. These are assertions about HTTP responses and claim nothing about ranking or AI citation. Checks a site cannot owe — Vary and code fences on a site that serves no markdown variant — are reported as n/a and excluded from both sides of the score, never as zeros. Results are stored in a temporary cache and are not persisted to the database.","category":"SEO","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"seo_analyze_page","title":"SEO Analyze Page","description":"Runs on-page SEO analysis for a URL: title, meta description, headings, canonical, structured data. Results are stored in a temporary cache and are not persisted to the database. Requires the URL to return 2xx: on a 404, 401, 5xx or timeout it returns an error naming the status and runs no checks, because a non-2xx still serves a body and scoring it would describe an error page.","category":"SEO","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"seo_canonical_audit","title":"SEO Canonical Audit","description":"Compares the declared canonical tag in HTML with the Google-selected canonical from Search Console inspection. Detects mismatches and explains causes. Results are stored in a temporary cache and are not persisted to the database.","category":"SEO","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"seo_content_analysis","title":"SEO Content Analysis","description":"Analyzes a page's content quality: word count, readability score, heading structure, link density and lexical diversity. Results are stored in a temporary cache and are not persisted to the database. Requires the URL to return 2xx: on a 404, 401, 5xx or timeout it returns an error naming the status and runs no checks, because a non-2xx still serves a body and scoring it would describe an error page.","category":"SEO","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"seo_crawlability_audit","title":"SEO Crawlability Audit","description":"Audits a URL for crawlability issues: canonical conflicts, redirect chains, noindex tags and indexability blockers. Results are stored in a temporary cache and are not persisted to the database. Answers whatever the URL returns — this is the tool that diagnoses a non-2xx status, so run it first when a URL looks broken.","category":"SEO","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"seo_eeat_score","title":"SEO E-E-A-T Score","description":"Scores a page's on-page Experience, Expertise, Authoritativeness and Trustworthiness signals. Results are stored in a temporary cache and are not persisted to the database. Requires the URL to return 2xx: on a 404, 401, 5xx or timeout it returns an error naming the status and runs no checks, because a non-2xx still serves a body and scoring it would describe an error page.","category":"SEO","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"seo_geo_score","title":"SEO GEO Score","description":"Analyzes a page's structured data, content structure, E-E-A-T signals, and AI crawler access — factors correlated with AI citation in peer-reviewed research (Princeton KDD 2024). Returns a directional score (0-100) with per-category breakdown. No official AI citation scoring standard exists; treat as a heuristic. Results are stored in a temporary cache and are not persisted to the database. Requires the URL to return 2xx: on a 404, 401, 5xx or timeout it returns an error naming the status and runs no checks, because a non-2xx still serves a body and scoring it would describe an error page. Expectations follow the identified Page Kind (homepage, article, product, faq, landing, collection, profile, generic); checks marked n/a do not apply to that kind and are not gaps. Scores are normalised per Page Kind and are not comparable across kinds.","category":"SEO","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"seo_hreflang_validator","title":"SEO Hreflang Validator","description":"Validate hreflang tags on a page for international SEO: language code correctness, self-reference, bidirectional links and x-default presence. Requires the URL to return 2xx: on a 404, 401, 5xx or timeout it returns an error naming the status and runs no checks, because a non-2xx still serves a body and scoring it would describe an error page.","category":"SEO","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"seo_llms_txt","title":"SEO LLMs.txt Audit","description":"Checks whether a site has a /llms.txt file, validates its completeness and format, and PROBES the links it declares — a bounded sample, with the count probed out of the count declared stated in the output. A 200 is not treated as a pass: a link answering with the homepage shell, or redirecting to the homepage, is reported as broken, because a single-page app answers every unknown path that way. A link that could not be reached is not scored either way and the reader is told coverage was partial. The /llms.txt format was proposed in 2024; no major AI platform has confirmed use for citation decisions. Results are stored in a temporary cache and are not persisted to the database.","category":"SEO","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"seo_metric_trend","title":"Metric Trend","description":"How a site's audit metrics have moved over time, from stored history rather than a fresh crawl. Ask for one metric by name (geo.score, robots.blocksAiCrawlers, schema.invalid, pagespeed.performance...) or omit it to get every metric that moved. Reports whether each change is an improvement, which depends on the metric: a rising score is good, a rising critical-issue count is not, and a rising maxScore is neither — it means our analyzer gained checks. Weekly detail is kept for 6 months; longer spans are answered monthly and the response says which resolution it used. Returns nothing for a site with no refresh history yet.","category":"SEO","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"seo_robots_validator","title":"SEO Robots.txt Validator","description":"Fetch and validate a site's robots.txt file. Checks AI crawler access, sitemap references, blocking rules and common syntax errors. Reads /robots.txt, so it answers regardless of what the page URL returns.","category":"SEO","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"seo_schema_detection","title":"SEO Schema Detection","description":"Detect and validate all structured data (JSON-LD, Microdata, RDFa) on a page. Reports schema types, validation errors and improvement recommendations. Requires the URL to return 2xx: on a 404, 401, 5xx or timeout it returns an error naming the status and runs no checks, because a non-2xx still serves a body and scoring it would describe an error page. Expectations follow the identified Page Kind (homepage, article, product, faq, landing, collection, profile, generic); checks marked n/a do not apply to that kind and are not gaps.","category":"SEO","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"seo_schema_generator","title":"SEO Schema Generator","description":"Generate valid JSON-LD structured data markup for a given schema type (Organization, Product, Article, etc.). Returns a ready-to-paste HTML snippet.","category":"SEO","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"seo_security_headers","title":"SEO Security Headers","description":"Audit a URL's HTTP security headers (HSTS, CSP, X-Frame-Options, etc.). Returns a grade, score and implementation recommendations. Headers are server configuration and come back with any response, so this answers on a non-2xx too.","category":"SEO","readOnly":true,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]},{"name":"sync_gsc_properties","title":"Sync Search Console Properties","description":"Reconcile your registered sites against what Google Search Console says you own right now. Use this after adding, removing or re-verifying a property in Search Console, or when a GSC tool reports a permission error for a site you know you own — audits read the stored property URL directly and do not re-check it. This links a site you registered manually to its matching GSC property, and rewrites a stored domain that drifted from its canonical form. It never registers a new site: an unowned-by-us property is left alone so your plan's site limit cannot be bypassed. Nothing is deleted and re-running it is safe.","category":"Site management","readOnly":false,"destructive":false,"parameters":["toJSONSchema","def","type","parse","safeParse","parseAsync","safeParseAsync","spa","encode","decode","encodeAsync","decodeAsync","safeEncode","safeDecode","safeEncodeAsync","safeDecodeAsync"]}],"rateLimits":{"note":"Rate limits align with the upstream Google APIs and per-user quota."},"contact":{"url":"https://thatseoagent.com/about","email":"support@thatseoagent.com"}}