Skip to main content
Glama
AutomateLab-tech

automatelab-ai-seo

Official

Score AI citation worthiness

score_citation_worthiness
Read-onlyIdempotent

Score how citable a page or text block is for AI engines by checking BLUF openings, FAQ patterns, statistic density, entity clarity, and per-section answer extractability.

Instructions

Score how citable a page or text block is for AI engines (ChatGPT, Claude, Perplexity, Google AI Overviews). Evaluates BLUF (bottom-line-up-front) opening, FAQ patterns, statistic density, entity clarity, and answer-shape fit for the optional target_query.

Also returns extractability_score plus per-section chunk_analysis: how cleanly an LLM can lift a self-contained answer from each heading-delimited section (length band, lead-sentence directness, anaphora, concrete anchors). This is the GEO mechanic - it pinpoints the exact sections to tighten, with most_extractable / least_extractable called out.

Read-only when given url (one HTTP GET). Zero network when given text. No writes.

Deterministic, rule-based; no LLM calls. Returns reproducible scores.

When to use: pre-publish content QA, or to triage which existing pages are worth optimizing for AI citation first. Distinct from score_ai_overview_eligibility which scores Google-AI-Overview ranking probability for a URL; this scores the inherent citability of a text passage regardless of host.

Either url or text must be provided.

Input Schema

NameRequiredDescriptionDefault
urlNoPublic URL to fetch and score. Either this OR `text` is required.
textNoRaw text/markdown/HTML to score directly without fetching. Either this OR `url` is required.
target_queryNoOptional target search query the content is supposed to answer (e.g. `how to fix CORS errors in Next.js`). When provided, scoring weights answer-shape fit and query-term coverage. Omit if you want a query-agnostic citability score.
respect_robotsNoIf true (default), respect robots.txt when fetching `url`. Ignored when `text` is used.

Output Schema

NameRequiredDescriptionDefault
findingsYes
sub_scoresYes
improvementsYes
engine_scoresYes
overall_scoreYes
chunk_analysisYes
most_extractableYes
least_extractableYes
extractability_scoreYes

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed19 schema fields changed
    • removedOutput schema / properties / chunk_analysis / description
      Removed value: -"Per-section extractability: how cleanly an LLM can lift a standalone answer from each chunk."
    • removedOutput schema / properties / chunk_analysis / items / properties / score / maximum
      Removed value: -100
    • removedOutput schema / properties / chunk_analysis / items / properties / score / minimum
      Removed value: -0
    • removedOutput schema / properties / extractability_score / description
      Removed value: -"Length-weighted mean of per-section extractability scores."
    • removedOutput schema / properties / extractability_score / maximum
      Removed value: -100
    • removedOutput schema / properties / extractability_score / minimum
      Removed value: -0
    • addedOutput schema / properties / findings
      Added value: +{
      +  "items": {
      +    "additionalProperties": false,
      +    "properties": {
      +      "category": {
      +        "enum": [
      +          "schema",
      +          "robots",
      +          "technical",
      +          "freshness",
      +          "structure",
      +          "authority",
      +          "presence",
      +          "sitemap",
      +          "llms_txt",
      +          "citation",
      +          "evidence",
      +          "trust",
      +          "entity",
      +          "content"
      +        ],
      +        "type": "string"
      +      },
      +      "estimated_impact": {
      +        "anyOf": [
      +          {
      +            "not": {}
      +          },
      +          {
      +            "const": "high",
      +            "type": "string"
      +          },
      +          {
      +            "const": "medium",
      +            "type": "string"
      +          },
      +          {
      +            "const": "low",
      +            "type": "string"
      +          }
      +        ]
      +      },
      +      "failure_signal": {
      +        "anyOf": [
      +          {
      +            "not": {}
      +          },
      +          {
      +            "type": "string"
      +          }
      +        ]
      +      },
      +      "fix": {
      +        "type": "string"
      +      },
      +      "leading_indicator": {
      +        "anyOf": [
      +          {
      +            "not": {}
      +          },
      +          {
      +            "type": "string"
      +          }
      +        ]
      +      },
      +      "message": {
      +        "type": "string"
      +      },
      +      "severity": {
      +        "enum": [
      +          "critical",
      +          "warning",
      +          "info"
      +        ],
      +        "type": "string"
      +      },
      +      "where": {
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "severity",
      +      "category",
      +      "where",
      +      "message",
      +      "fix"
      +    ],
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
    • addedOutput schema / properties / improvements
      Added value: +{
      +  "items": {
      +    "type": "string"
      +  },
      +  "type": "array"
      +}
    • changedOutput schema / properties / least_extractable / anyOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "heading": {
      -        "type": "string"
      -      },
      -      "score": {
      -        "type": "number"
      -      }
      -    },
      -    "required": [
      -      "heading",
      -      "score"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "type": "null"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "heading": {
      +        "type": "string"
      +      },
      +      "score": {
      +        "type": "number"
      +      }
      +    },
      +    "required": [
      +      "heading",
      +      "score"
      +    ],
      +    "type": "object"
      +  }
      +]
    • changedOutput schema / properties / most_extractable / anyOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "heading": {
      -        "type": "string"
      -      },
      -      "score": {
      -        "type": "number"
      -      }
      -    },
      -    "required": [
      -      "heading",
      -      "score"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "type": "null"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "heading": {
      +        "type": "string"
      +      },
      +      "score": {
      +        "type": "number"
      +      }
      +    },
      +    "required": [
      +      "heading",
      +      "score"
      +    ],
      +    "type": "object"
      +  }
      +]
    • removedOutput schema / properties / overall_score / maximum
      Removed value: -100
    • removedOutput schema / properties / overall_score / minimum
      Removed value: -0
    • removedOutput schema / properties / signals
      Removed value: -{
      -  "additionalProperties": {
      -    "type": "number"
      -  },
      -  "description": "Per-signal subscores (bluf, faq, stats, entities, etc.).",
      -  "type": "object"
      -}
    • removedOutput schema / properties / source
      Removed value: -{
      -  "enum": [
      -    "url",
      -    "text"
      -  ],
      -  "type": "string"
      -}
    • addedOutput schema / properties / sub_scores
      Added value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "answer_completeness": {
      +      "type": "number"
      +    },
      +    "bluf_present": {
      +      "type": "boolean"
      +    },
      +    "entity_clarity": {
      +      "type": "number"
      +    },
      +    "faq_blocks": {
      +      "type": "number"
      +    },
      +    "heading_question_ratio": {
      +      "type": "number"
      +    },
      +    "statistic_density": {
      +      "type": "number"
      +    }
      +  },
      +  "required": [
      +    "bluf_present",
      +    "faq_blocks",
      +    "statistic_density",
      +    "entity_clarity",
      +    "heading_question_ratio",
      +    "answer_completeness"
      +  ],
      +  "type": "object"
      +}
    • removedOutput schema / properties / suggestions
      Removed value: -{
      -  "items": {
      -    "type": "string"
      -  },
      -  "type": "array"
      -}
    • removedOutput schema / properties / target_query
      Removed value: -{
      -  "type": [
      -    "string",
      -    "null"
      -  ]
      -}
    • removedOutput schema / properties / url
      Removed value: -{
      -  "type": [
      -    "string",
      -    "null"
      -  ]
      -}
    • changedOutput schema / required
      Previous value: -[
      -  "source",
      -  "url",
      -  "target_query",
      -  "overall_score",
      -  "engine_scores",
      -  "signals",
      -  "suggestions"
      -]New value: +[
      +  "overall_score",
      +  "engine_scores",
      +  "sub_scores",
      +  "extractability_score",
      +  "chunk_analysis",
      +  "most_extractable",
      +  "least_extractable",
      +  "improvements",
      +  "findings"
      +]
  2. Changed1 schema field changedv1.0.0
    • changedOutput schema / (root)
      Previous value: -nullNew value: +{
      +  "$schema": "http://json-schema.org/draft-07/schema#",
      +  "additionalProperties": false,
      +  "properties": {
      +    "chunk_analysis": {
      +      "description": "Per-section extractability: how cleanly an LLM can lift a standalone answer from each chunk.",
      +      "items": {
      +        "additionalProperties": false,
      +        "properties": {
      +          "heading": {
      +            "type": "string"
      +          },
      +          "issues": {
      +            "items": {
      +              "type": "string"
      +            },
      +            "type": "array"
      +          },
      +          "level": {
      +            "type": "number"
      +          },
      +          "score": {
      +            "maximum": 100,
      +            "minimum": 0,
      +            "type": "number"
      +          },
      +          "word_count": {
      +            "type": "number"
      +          }
      +        },
      +        "required": [
      +          "heading",
      +          "level",
      +          "word_count",
      +          "score",
      +          "issues"
      +        ],
      +        "type": "object"
      +      },
      +      "type": "array"
      +    },
      +    "engine_scores": {
      +      "additionalProperties": false,
      +      "properties": {
      +        "chatgpt": {
      +          "type": "number"
      +        },
      +        "claude": {
      +          "type": "number"
      +        },
      +        "google_ai_overviews": {
      +          "type": "number"
      +        },
      +        "perplexity": {
      +          "type": "number"
      +        }
      +      },
      +      "required": [
      +        "perplexity",
      +        "chatgpt",
      +        "google_ai_overviews",
      +        "claude"
      +      ],
      +      "type": "object"
      +    },
      +    "extractability_score": {
      +      "description": "Length-weighted mean of per-section extractability scores.",
      +      "maximum": 100,
      +      "minimum": 0,
      +      "type": "number"
      +    },
      +    "least_extractable": {
      +      "anyOf": [
      +        {
      +          "additionalProperties": false,
      +          "properties": {
      +            "heading": {
      +              "type": "string"
      +            },
      +            "score": {
      +              "type": "number"
      +            }
      +          },
      +          "required": [
      +            "heading",
      +            "score"
      +          ],
      +          "type": "object"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ]
      +    },
      +    "most_extractable": {
      +      "anyOf": [
      +        {
      +          "additionalProperties": false,
      +          "properties": {
      +            "heading": {
      +              "type": "string"
      +            },
      +            "score": {
      +              "type": "number"
      +            }
      +          },
      +          "required": [
      +            "heading",
      +            "score"
      +          ],
      +          "type": "object"
      +        },
      +        {
      +          "type": "null"
      +        }
      +      ]
      +    },
      +    "overall_score": {
      +      "maximum": 100,
      +      "minimum": 0,
      +      "type": "number"
      +    },
      +    "signals": {
      +      "additionalProperties": {
      +        "type": "number"
      +      },
      +      "description": "Per-signal subscores (bluf, faq, stats, entities, etc.).",
      +      "type": "object"
      +    },
      +    "source": {
      +      "enum": [
      +        "url",
      +        "text"
      +      ],
      +      "type": "string"
      +    },
      +    "suggestions": {
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    "target_query": {
      +      "type": [
      +        "string",
      +        "null"
      +      ]
      +    },
      +    "url": {
      +      "type": [
      +        "string",
      +        "null"
      +      ]
      +    }
      +  },
      +  "required": [
      +    "source",
      +    "url",
      +    "target_query",
      +    "overall_score",
      +    "engine_scores",
      +    "signals",
      +    "suggestions"
      +  ],
      +  "type": "object"
      +}
  3. Changed4 schema fields changedv0.1.2
    • addedInput schema / properties / respect_robots / description
      Added value: +"If true (default), respect robots.txt when fetching `url`. Ignored when `text` is used."
    • addedInput schema / properties / target_query / description
      Added value: +"Optional target search query the content is supposed to answer (e.g. `how to fix CORS errors in Next.js`). When provided, scoring weights answer-shape fit and query-term coverage. Omit if you want a query-agnostic citability score."
    • addedInput schema / properties / text / description
      Added value: +"Raw text/markdown/HTML to score directly without fetching. Either this OR `url` is required."
    • addedInput schema / properties / url / description
      Added value: +"Public URL to fetch and score. Either this OR `text` is required."
  4. First observedv0.1.0

TDQS

A4.6/5.0
Behavior4/5

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

Annotations already declare readOnly/idempotent/non-destructive and open-world, so the safety bar is covered. The description still adds genuine value beyond them: the network profile is parameter-contingent ('one HTTP GET' with url, 'zero network' with text) and it states the engine is deterministic and rule-based with no LLM calls, yielding reproducible scores.

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

Conciseness4/5

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

Front-loads the core purpose, then progressively details the mechanic (chunk_analysis), runtime behavior, and routing. Every sentence carries information, though the section list and the extractability paragraph are dense enough to nudge past ideal brevity.

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

Completeness5/5

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

An output schema exists, yet the description still orients the agent by naming the returned fields (extractability_score, per-section chunk_analysis, most_extractable/least_extractable). With the url/text requirement, usage scenarios, and sibling differentiation all present, nothing an agent needs to call it correctly is missing.

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

Parameters4/5

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

Schema coverage is 100%, so baseline is 3. The description nonetheless sharpens parameter meaning: `text` is characterized as the zero-network path, `url` as the one-GET path, and `target_query` is the query that reweights answer-shape fit. Only `respect_robots` goes unmentioned in prose, keeping this just short of a 5.

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

Purpose5/5

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

States a specific verb+resource ('Score how citable a page or text block is for AI engines') and enumerates the exact dimensions scored (BLUF, FAQ patterns, statistic density, entity clarity, answer-shape fit). It explicitly names the sibling it is not, `score_ai_overview_eligibility`, and differentiates on host-independence.

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 when-to-use scenarios ('pre-publish content QA, or to triage which existing pages are worth optimizing for AI citation first') and an explicit alternative with the selecting condition ('this scores the inherent citability of a text passage regardless of host').

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