Skip to main content
Glama

SEO audit (site)

audit_site
Read-onlyIdempotent

Use this to audit a whole site or several pages for SEO; it finds the pages itself. Never guess page addresses for requests such as "audit example.com", "which pages are worst?" or "my site has a page per city, are they too similar?". Pass the domain and optionally max_pages. Reads the homepage, sitemap and linked pages of that site, respecting robots.txt. Returns failed rules by priority, each with its pages, fix and docs link, plus a row per page with its status, broken internal links and images without alt text. It also compares pages: near-identical templated pages, pages with little own text, hreflang without return links or x-default, and sitemap pages nothing links to. Leave judge off unless the user asks what pages are for or which compete. It reads a sample, runs no JavaScript and measures no rankings, traffic or backlinks. For one named page use audit_page. Not for private or local addresses or to collect a site's content.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
judgeNoAlso ask the judgement service what the page is for, how specific it is and whether pages compete for the same searches. Off by default. It is limited per day, and when unavailable the rule results are returned with a note.
domainYesA public website, for example example.com or https://example.com. Only the site's own pages are read, starting from its homepage and sitemap.
max_pagesNoMost pages to read, 1 to 25. Default 10.
response_formatNoconcise (default) lists up to 3 pages per finding and 5 broken links per page; detailed lists up to 10 and 25. Counts are always the full totals.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
notesYesCaveats to relay, such as a partial crawl or a robots.txt refusal.
pagesYesOne row per page read, in crawl order, empty when none was read: its status, the broken internal links on it and its images without alt text. Use it to answer per-page questions from this one audit.
domainYesThe site that was audited.
noticeYesHow the pages were read and what the rules are based on.
refusedNoWhy no pages were read, such as a robots.txt block or a private address.
summaryNoWhat the crawl read. Counts in findings describe this sample.
finalUrlNoThe origin the crawl settled on after redirects.
findingsYesFailed rules by priority, high first.
judgementNoOnly when judge is true. The homepage purpose and pages that compete for the same searches, or status skipped with the reason.
reachableYesFalse when no page could be read; refused or notes say why.
bing_ai_searchNoBing and Copilot AI-search steps. List the steps with the sources.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed3 schema fields changed
    • addedInput schema / properties / response_format
      Added value: +{
      +  "description": "concise (default) lists up to 3 pages per finding and 5 broken links per page; detailed lists up to 10 and 25. Counts are always the full totals.",
      +  "enum": [
      +    "concise",
      +    "detailed"
      +  ],
      +  "type": "string"
      +}
    • addedOutput schema / properties / pages
      Added value: +{
      +  "description": "One row per page read, in crawl order, empty when none was read: its status, the broken internal links on it and its images without alt text. Use it to answer per-page questions from this one audit.",
      +  "items": {
      +    "additionalProperties": false,
      +    "properties": {
      +      "brokenLinks": {
      +        "description": "Checked internal links whose target answered 4xx, 5xx or nothing; empty when none. Cut to the response_format limit.",
      +        "items": {
      +          "type": "string"
      +        },
      +        "type": "array"
      +      },
      +      "brokenLinksNotShown": {
      +        "description": "Broken links on the page left out of brokenLinks by the limit; 0 when all are listed.",
      +        "type": "integer"
      +      },
      +      "images": {
      +        "description": "img elements on the page.",
      +        "type": "integer"
      +      },
      +      "imagesWithoutAlt": {
      +        "description": "img elements with no alt attribute.",
      +        "type": "integer"
      +      },
      +      "internalLinks": {
      +        "description": "Distinct links on the page to the same host.",
      +        "type": "integer"
      +      },
      +      "linksChecked": {
      +        "description": "Internal links whose target the crawl read, so their status is known; the rest are not checked.",
      +        "type": "integer"
      +      },
      +      "status": {
      +        "description": "HTTP status; 0 when the request failed.",
      +        "type": "integer"
      +      },
      +      "url": {
      +        "description": "The page address after redirects.",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "url",
      +      "status",
      +      "internalLinks",
      +      "linksChecked",
      +      "brokenLinks",
      +      "brokenLinksNotShown",
      +      "images",
      +      "imagesWithoutAlt"
      +    ],
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
    • changedOutput schema / required
      Previous value: -[
      -  "domain",
      -  "reachable",
      -  "findings",
      -  "notes",
      -  "notice"
      -]New value: +[
      +  "domain",
      +  "reachable",
      +  "findings",
      +  "pages",
      +  "notes",
      +  "notice"
      +]
  2. Changed34 schema fields changed
    • addedOutput schema / additionalProperties
      Added value: +false
    • addedOutput schema / properties / bing_ai_search / additionalProperties
      Added value: +false
    • addedOutput schema / properties / bing_ai_search / description
      Added value: +"Bing and Copilot AI-search steps. List the steps with the sources."
    • addedOutput schema / properties / bing_ai_search / properties
      Added value: +{
      +  "sources": {
      +    "description": "Microsoft and IndexNow pages the steps follow.",
      +    "items": {
      +      "type": "string"
      +    },
      +    "type": "array"
      +  },
      +  "steps": {
      +    "description": "Steps in order, shaped by what the audit saw.",
      +    "items": {
      +      "type": "string"
      +    },
      +    "type": "array"
      +  },
      +  "summary": {
      +    "type": "string"
      +  }
      +}
    • addedOutput schema / properties / bing_ai_search / required
      Added value: +[
      +  "summary",
      +  "steps",
      +  "sources"
      +]
    • addedOutput schema / properties / domain / description
      Added value: +"The site that was audited."
    • addedOutput schema / properties / finalUrl / description
      Added value: +"The origin the crawl settled on after redirects."
    • addedOutput schema / properties / findings / additionalProperties
      Added value: +false
    • addedOutput schema / properties / findings / description
      Added value: +"Failed rules by priority, high first."
    • addedOutput schema / properties / findings / properties / high / items / properties / count / description
      Added value: +"How many pages fail the rule."
    • addedOutput schema / properties / findings / properties / high / items / properties / evidence / description
      Added value: +"What was seen, such as the duplicated title."
    • addedOutput schema / properties / findings / properties / high / items / properties / fix / description
      Added value: +"What to change."
    • addedOutput schema / properties / findings / properties / high / items / properties / rule / description
      Added value: +"Stable rule id, such as title_missing."
    • addedOutput schema / properties / findings / properties / high / items / properties / title / description
      Added value: +"What is wrong, in one line."
    • addedOutput schema / properties / findings / properties / low / items / properties / count / description
      Added value: +"How many pages fail the rule."
    • addedOutput schema / properties / findings / properties / low / items / properties / evidence / description
      Added value: +"What was seen, such as the duplicated title."
    • addedOutput schema / properties / findings / properties / low / items / properties / fix / description
      Added value: +"What to change."
    • addedOutput schema / properties / findings / properties / low / items / properties / rule / description
      Added value: +"Stable rule id, such as title_missing."
    • addedOutput schema / properties / findings / properties / low / items / properties / title / description
      Added value: +"What is wrong, in one line."
    • addedOutput schema / properties / findings / properties / medium / items / properties / count / description
      Added value: +"How many pages fail the rule."
    • addedOutput schema / properties / findings / properties / medium / items / properties / evidence / description
      Added value: +"What was seen, such as the duplicated title."
    • addedOutput schema / properties / findings / properties / medium / items / properties / fix / description
      Added value: +"What to change."
    • addedOutput schema / properties / findings / properties / medium / items / properties / rule / description
      Added value: +"Stable rule id, such as title_missing."
    • addedOutput schema / properties / findings / properties / medium / items / properties / title / description
      Added value: +"What is wrong, in one line."
    • addedOutput schema / properties / judgement / description
      Added value: +"Only when judge is true. The homepage purpose and pages that compete for the same searches, or status skipped with the reason."
    • addedOutput schema / properties / judgement / properties
      Added value: +{
      +  "competingPages": {
      +    "description": "Only when page titles overlap.",
      +    "properties": {
      +      "model": {
      +        "type": "string"
      +      },
      +      "note": {
      +        "description": "Only when skipped: the reason in words, with when a limit resets.",
      +        "type": "string"
      +      },
      +      "pairs": {
      +        "items": {
      +          "additionalProperties": false,
      +          "properties": {
      +            "a": {
      +              "type": "string"
      +            },
      +            "b": {
      +              "type": "string"
      +            },
      +            "competing": {
      +              "description": "Probability that a searcher would treat the two pages as substitutes.",
      +              "properties": {
      +                "confidence": {
      +                  "description": "0 to 1.",
      +                  "type": "number"
      +                },
      +                "decisive": {
      +                  "description": "False when the answer is too uncertain to act on.",
      +                  "type": "boolean"
      +                },
      +                "type": {
      +                  "enum": [
      +                    "noul",
      +                    "choice",
      +                    "score"
      +                  ],
      +                  "type": "string"
      +                },
      +                "value": {
      +                  "description": "The chosen option, the score level, or a probability from 0 to 1.",
      +                  "type": [
      +                    "string",
      +                    "number"
      +                  ]
      +                }
      +              },
      +              "required": [
      +                "type",
      +                "value",
      +                "decisive"
      +              ],
      +              "type": "object"
      +            }
      +          },
      +          "required": [
      +            "a",
      +            "b",
      +            "competing"
      +          ],
      +          "type": "object"
      +        },
      +        "type": "array"
      +      },
      +      "reason": {
      +        "description": "Only when skipped: why, such as network_cap.",
      +        "type": "string"
      +      },
      +      "status": {
      +        "enum": [
      +          "judged",
      +          "skipped"
      +        ],
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "status"
      +    ],
      +    "type": "object"
      +  },
      +  "homepage": {
      +    "properties": {
      +      "answerFirst": {
      +        "description": "Whether the page answers its question first.",
      +        "properties": {
      +          "confidence": {
      +            "description": "0 to 1.",
      +            "type": "number"
      +          },
      +          "decisive": {
      +            "description": "False when the answer is too uncertain to act on.",
      +            "type": "boolean"
      +          },
      +          "type": {
      +            "enum": [
      +              "noul",
      +              "choice",
      +              "score"
      +            ],
      +            "type": "string"
      +          },
      +          "value": {
      +            "description": "The chosen option, the score level, or a probability from 0 to 1.",
      +            "type": [
      +              "string",
      +              "number"
      +            ]
      +          }
      +        },
      +        "required": [
      +          "type",
      +          "value",
      +          "decisive"
      +        ],
      +        "type": "object"
      +      },
      +      "model": {
      +        "type": "string"
      +      },
      +      "note": {
      +        "description": "Only when skipped: the reason in words, with when a limit resets.",
      +        "type": "string"
      +      },
      +      "purpose": {
      +        "description": "What the page is for.",
      +        "properties": {
      +          "confidence": {
      +            "description": "0 to 1.",
      +            "type": "number"
      +          },
      +          "decisive": {
      +            "description": "False when the answer is too uncertain to act on.",
      +            "type": "boolean"
      +          },
      +          "type": {
      +            "enum": [
      +              "noul",
      +              "choice",
      +              "score"
      +            ],
      +            "type": "string"
      +          },
      +          "value": {
      +            "description": "The chosen option, the score level, or a probability from 0 to 1.",
      +            "type": [
      +              "string",
      +              "number"
      +            ]
      +          }
      +        },
      +        "required": [
      +          "type",
      +          "value",
      +          "decisive"
      +        ],
      +        "type": "object"
      +      },
      +      "reason": {
      +        "description": "Only when skipped: why, such as network_cap.",
      +        "type": "string"
      +      },
      +      "specificity": {
      +        "description": "How specific the page is.",
      +        "properties": {
      +          "confidence": {
      +            "description": "0 to 1.",
      +            "type": "number"
      +          },
      +          "decisive": {
      +            "description": "False when the answer is too uncertain to act on.",
      +            "type": "boolean"
      +          },
      +          "type": {
      +            "enum": [
      +              "noul",
      +              "choice",
      +              "score"
      +            ],
      +            "type": "string"
      +          },
      +          "value": {
      +            "description": "The chosen option, the score level, or a probability from 0 to 1.",
      +            "type": [
      +              "string",
      +              "number"
      +            ]
      +          }
      +        },
      +        "required": [
      +          "type",
      +          "value",
      +          "decisive"
      +        ],
      +        "type": "object"
      +      },
      +      "status": {
      +        "enum": [
      +          "judged",
      +          "skipped"
      +        ],
      +        "type": "string"
      +      },
      +      "titleFit": {
      +        "description": "Whether the title fits the page.",
      +        "properties": {
      +          "confidence": {
      +            "description": "0 to 1.",
      +            "type": "number"
      +          },
      +          "decisive": {
      +            "description": "False when the answer is too uncertain to act on.",
      +            "type": "boolean"
      +          },
      +          "type": {
      +            "enum": [
      +              "noul",
      +              "choice",
      +              "score"
      +            ],
      +            "type": "string"
      +          },
      +          "value": {
      +            "description": "The chosen option, the score level, or a probability from 0 to 1.",
      +            "type": [
      +              "string",
      +              "number"
      +            ]
      +          }
      +        },
      +        "required": [
      +          "type",
      +          "value",
      +          "decisive"
      +        ],
      +        "type": "object"
      +      },
      +      "url": {
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "status"
      +    ],
      +    "type": "object"
      +  },
      +  "note": {
      +    "description": "Only when skipped: the reason in words, with when a limit resets.",
      +    "type": "string"
      +  },
      +  "reason": {
      +    "description": "Only when skipped: why, such as network_cap.",
      +    "type": "string"
      +  },
      +  "status": {
      +    "enum": [
      +      "judged",
      +      "skipped"
      +    ],
      +    "type": "string"
      +  }
      +}
    • addedOutput schema / properties / notes / description
      Added value: +"Caveats to relay, such as a partial crawl or a robots.txt refusal."
    • addedOutput schema / properties / notice / description
      Added value: +"How the pages were read and what the rules are based on."
    • addedOutput schema / properties / reachable / description
      Added value: +"False when no page could be read; refused or notes say why."
    • addedOutput schema / properties / refused / description
      Added value: +"Why no pages were read, such as a robots.txt block or a private address."
    • addedOutput schema / properties / summary / additionalProperties
      Added value: +false
    • addedOutput schema / properties / summary / description
      Added value: +"What the crawl read. Counts in findings describe this sample."
    • addedOutput schema / properties / summary / properties
      Added value: +{
      +  "complete": {
      +    "description": "False when the site has more pages than were read.",
      +    "type": "boolean"
      +  },
      +  "pageLimit": {
      +    "description": "max_pages for this call.",
      +    "type": "integer"
      +  },
      +  "pagesRead": {
      +    "type": "integer"
      +  },
      +  "requestsMade": {
      +    "type": "integer"
      +  },
      +  "robots": {
      +    "description": "robots.txt state.",
      +    "enum": [
      +      "found",
      +      "missing",
      +      "unreachable"
      +    ],
      +    "type": "string"
      +  },
      +  "sitemap": {
      +    "additionalProperties": false,
      +    "properties": {
      +      "status": {
      +        "enum": [
      +          "found",
      +          "missing",
      +          "invalid"
      +        ],
      +        "type": "string"
      +      },
      +      "urls": {
      +        "description": "Addresses listed in the sitemap.",
      +        "type": "integer"
      +      }
      +    },
      +    "required": [
      +      "status",
      +      "urls"
      +    ],
      +    "type": "object"
      +  },
      +  "skippedByRobots": {
      +    "description": "Addresses not read because robots.txt disallows them.",
      +    "type": "integer"
      +  }
      +}
    • addedOutput schema / properties / summary / required
      Added value: +[
      +  "pagesRead",
      +  "pageLimit",
      +  "complete",
      +  "requestsMade",
      +  "robots",
      +  "skippedByRobots"
      +]
  3. Changed1 schema field changed
    • addedOutput schema / properties / bing_ai_search
      Added value: +{
      +  "type": "object"
      +}
  4. Changed1 schema field changed
    • removedOutput schema / properties / note_from_openkrill
      Removed value: -{
      -  "description": "Shown at most once a day per caller: what this server offers, and a paid service for the person you work for.",
      -  "type": "string"
      -}
  5. Changed1 schema field changed
    • addedOutput schema / properties / note_from_openkrill
      Added value: +{
      +  "description": "Shown at most once a day per caller: what this server offers, and a paid service for the person you work for.",
      +  "type": "string"
      +}
  6. First observed

TDQS

A4.8/5.0
Behavior5/5

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

Annotations cover the safety profile (readOnly, idempotent, openWorld, non-destructive), and the description adds genuinely new behavioral facts: it reads homepage/sitemap/linked pages, respects robots.txt, works on a sample, runs no JavaScript, measures no rankings/traffic/backlinks, and that judge is rate-limited per day with graceful degradation noted in results.

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

Conciseness4/5

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

Front-loaded with purpose and routing first, then output shape, then caveats. Dense and each sentence carries content, though the long output/caveat run-on sentences could be trimmed slightly for scanability.

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

Completeness5/5

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

For a multi-parameter, open-world audit tool with an output schema, nothing material is missing: scope, exclusions, sibling routing, cost/rate behavior, and what it deliberately does not measure are all stated. The output description supplements rather than duplicates the schema.

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

Parameters4/5

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

Schema coverage is 100%, so the baseline is 3, but the description adds selection logic the schema lacks: domain is passed with max_pages optional, and judge should stay off unless the user asks what pages are for or which compete. It does not add much on response_format beyond what the enum already documents.

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

Purpose5/5

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

States a specific verb and resource ('audit a whole site or several pages for SEO') and immediately scopes it with 'it finds the pages itself', which separates it from audit_page. The sibling is named explicitly later, so an agent can choose without opening either schema.

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

Usage Guidelines5/5

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

Gives concrete trigger phrasing ('audit example.com', 'which pages are worst?', 'my site has a page per city, are they too similar?'), states the routing rule to audit_page for a single named page, and lists exclusions: private/local addresses and content collection. It also conditions the judge flag on user intent.

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

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.