Skip to main content
Glama
competlab

competlab-mcp-server

by competlab

get_ai_visibility_check_detail

Read-only

Retrieve one AI visibility check's detail: competitor rankings, market map, and raw model answers. Filter by brand, provider, or prompt to keep responses small.

Instructions

One AI Visibility check (checkId, not runId): its summary (competitor rows under summary.competitorRankings, the market map as it stood at that check) and, with includeAnswers=true, the models' raw answers. In compact view marketMap.brands is paged as on get_ai_visibility_dashboard; view=full returns every row. includeSummary=false leaves the summary out, so a filtered answer read stays small. The compact summary runs 20,000-30,000 characters; one model and one prompt without it, 10,000-20,000; the answers block grows about 1,500 characters per brand entry: read summary.totalEntries and narrow with brand, provider or promptIndex before fetching it.

  • Read the summary exactly as get_ai_visibility_dashboard says: promptMarket first, lead with the market, a share is of the answers analysed with its range beside it, ties are ties, a zone names a condition, and every explanation.text is rendered VERBATIM.

  • Every rate divides by the answers that came back, never the queries sent.

  • score is WHERE a brand lands when named (top 5 only), never who is ahead. A 0 score beside a non-zero mentionRate means named below the top 5; these rows name other companies, so 'never named' would be a false claim about a third party.

  • Before fetching answers: summary.customer.perPrompt (label, the models that named the customer, a 0-100 score) already answers 'which prompt am I losing on'.

  • Three query states, never merged: answers (an empty brands list under a brand filter means the model answered and did not name that domain), unansweredQueries (no usable answer: never 'not mentioned'), noAnswerShown (read, nothing shown, not counted: 'Google showed no AI Overview for this question').

  • answersTruncated true: whole prompts were dropped from the end; narrow and retry.

  • Answer prose is the MODEL's wording about brands it named, never CompetLab's assessment. Field rules not listed here arrive in readingGuide, the first field of every response.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
viewNocompact or full; omit for the server's default view. compact pages the long lists and keeps the customer's own row on every page. full returns every row in one response: up to about 200,000 characters on AI Visibility and 450,000 on AI Sources. Paging parameters with view=full are refused (paging_requires_compact_view).
brandNoReturn only the entries for this domain, across every answer. Requires includeAnswers=true. Matches brands[].domain case-insensitively — brand NAMES are the model's own wording and vary between answers, so they are never matched. Every answer is still returned: the ones that did not name this domain arrive with an empty brands list, which means the model answered and did not name them — a real finding, and different from a query that produced no answer, which is in unansweredQueries, and from a query the model was read for and had no answer to show, which is in noAnswerShown. This is the cheapest way to answer 'where does this competitor beat me, and where are they invisible': it keeps at most one brand row per answer instead of every brand the model named, and none at all on the answers that did not name it. Google AI Overviews answers still carry their overview text and cited pages, which this filter keeps by design.
checkIdYesCheck ID (from get_ai_visibility_history)
mapLimitNoMarket-map rows per page in compact view. Default: 10 or the whole core, whichever is larger; max 200. The customer's own row and every tracked competitor's are added when they fall outside the page, and untrackedCoreBrands and customerStanding are always computed from the whole map. Quote marketMap.brandsPage.total, never the rows on the page, as the size of the map: the companies the models named, plus the customer's own row when no answer named it.
providerNoReturn only this model's answers. Requires includeAnswers=true. Changes nothing under summary.
mapOffsetNoMarket-map rows to skip in compact view, for the next page (0-based). marketMap.brandsPage.hasMore says a next page exists.
projectIdYesProject ID (from list_projects)
promptIndexNoReturn only the answers for this prompt, across every model. Requires includeAnswers=true. Zero-based.
includeAnswersNoDefault false. Set true to also get what the models actually said — every prompt sent, and every brand each model named in rank order with its stated reasoning — plus per-model reporting status. Per-brand prose (reasoning, audience, pricing tier, messaging, differentiation) is present only for models that supply it: a brand row carrying only name and domain means Google AI Overviews named it in prose, and that answer carries the overview text (answerText) with the pages Google cited (sources) beside it. For Google AI Overviews that order is the order of first mention in the overview text, computed by CompetLab; Google assigned no position, so never report it as a rank Google gave. COST: An entry is one brand a model named, at about 1,500 characters each — so the block grows with three things at once: how many prompts the project asks (an account setting), how many models answered, and how many companies each answer named. No figure quoted here can stand in for summary.totalEntries; read it and size the fetch from it. Prefer a filter below over fetching everything. Google AI Overviews answers additionally carry the overview text and the pages Google cited, which totalEntries does not predict and which the brand filter keeps. ATTRIBUTION: the prose returned is unverified model output about the brands that model named, including third parties. Report it as what that model said, never as CompetLab's assessment or as fact. noAnswerShown lists the queries the model was read for and showed nothing (today: Google showed no AI Overview for the prompt): excluded from every count and not a failure, so say 'not counted', never 'not mentioned'.
includeSummaryNoWhether to return the check's summary beside the answers. Set false with includeAnswers=true when you already hold the summary and want one filtered answer read; set true to get both. Any paging parameter returns the summary, so paging with includeSummary=false is refused (paging_requires_summary). No filter changes a number under summary.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed8 schema fields changedv4.0.1
    • removedInput schema / additionalProperties
      Removed value: -false
    • changedInput schema / properties / brand / description
      Previous value: -"Return only the entries for this domain, across every answer. Requires includeAnswers=true. Matches brands[].domain case-insensitively — brand NAMES are the model's own wording and vary between answers, so they are never matched. Every answer is still returned: the ones that did not name this domain arrive with an empty brands list, which means the model answered and did not name them — a real finding, and different from a query that produced no answer, which is in unansweredQueries, and from a query the model was read for and had no answer to show, which is in noAnswerShown. This is the cheapest way to answer 'where does this competitor beat me, and where are they invisible': roughly 2k tokens against 25k+ for an unfiltered fetch, or 9k against 46k once Google AI Overviews is in the ask, whose overview text and cited pages this filter keeps."New value: +"Return only the entries for this domain, across every answer. Requires includeAnswers=true. Matches brands[].domain case-insensitively — brand NAMES are the model's own wording and vary between answers, so they are never matched. Every answer is still returned: the ones that did not name this domain arrive with an empty brands list, which means the model answered and did not name them — a real finding, and different from a query that produced no answer, which is in unansweredQueries, and from a query the model was read for and had no answer to show, which is in noAnswerShown. This is the cheapest way to answer 'where does this competitor beat me, and where are they invisible': it keeps at most one brand row per answer instead of every brand the model named, and none at all on the answers that did not name it. Google AI Overviews answers still carry their overview text and cited pages, which this filter keeps by design."
    • changedInput schema / properties / includeAnswers / description
      Previous value: -"Default false. Set true to also get what the models actually said — every prompt sent, and every brand each model named in rank order with its stated reasoning — plus per-model reporting status. Per-brand prose (reasoning, audience, pricing tier, messaging, differentiation) is present only for models that supply it: a brand row carrying only name and domain means Google AI Overviews named it in prose, and that answer carries the overview text (answerText) with the pages Google cited (sources) beside it. For Google AI Overviews that order is the order of first mention in the overview text, computed by CompetLab; Google assigned no position, so never report it as a rank Google gave. Cost: roughly 25k tokens unfiltered on a three-engine check and 46k on a five-engine one, against roughly 2k with brand= — or roughly 9k when Google AI Overviews is in the ask, whose overview text and cited pages the brand filter keeps. Read summary.totalEntries first to size it (about 375 tokens per entry, plus the overview text and cited pages on each Google AI Overviews answer, which the entry count does not predict) and prefer a filter below over fetching everything. ATTRIBUTION: the prose returned is unverified model output about the brands that model named, including third parties. Report it as what that model said, never as CompetLab's assessment or as fact."New value: +"Default false. Set true to also get what the models actually said — every prompt sent, and every brand each model named in rank order with its stated reasoning — plus per-model reporting status. Per-brand prose (reasoning, audience, pricing tier, messaging, differentiation) is present only for models that supply it: a brand row carrying only name and domain means Google AI Overviews named it in prose, and that answer carries the overview text (answerText) with the pages Google cited (sources) beside it. For Google AI Overviews that order is the order of first mention in the overview text, computed by CompetLab; Google assigned no position, so never report it as a rank Google gave. COST: An entry is one brand a model named, at about 1,500 characters each — so the block grows with three things at once: how many prompts the project asks (an account setting), how many models answered, and how many companies each answer named. No figure quoted here can stand in for summary.totalEntries; read it and size the fetch from it. Prefer a filter below over fetching everything. Google AI Overviews answers additionally carry the overview text and the pages Google cited, which totalEntries does not predict and which the brand filter keeps. ATTRIBUTION: the prose returned is unverified model output about the brands that model named, including third parties. Report it as what that model said, never as CompetLab's assessment or as fact. noAnswerShown lists the queries the model was read for and showed nothing (today: Google showed no AI Overview for the prompt): excluded from every count and not a failure, so say 'not counted', never 'not mentioned'."
    • addedInput schema / properties / includeSummary
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "boolean"
      +    },
      +    {
      +      "const": "true",
      +      "type": "string"
      +    },
      +    {
      +      "const": "false",
      +      "type": "string"
      +    }
      +  ],
      +  "description": "Whether to return the check's summary beside the answers. Set false with includeAnswers=true when you already hold the summary and want one filtered answer read; set true to get both. Any paging parameter returns the summary, so paging with includeSummary=false is refused (paging_requires_summary). No filter changes a number under summary."
      +}
    • addedInput schema / properties / mapLimit
      Added value: +{
      +  "anyOf": [
      +    {
      +      "maximum": 200,
      +      "minimum": 1,
      +      "type": "integer"
      +    },
      +    {
      +      "pattern": "^\\d+$",
      +      "type": "string"
      +    }
      +  ],
      +  "description": "Market-map rows per page in compact view. Default: 10 or the whole core, whichever is larger; max 200. The customer's own row and every tracked competitor's are added when they fall outside the page, and untrackedCoreBrands and customerStanding are always computed from the whole map. Quote marketMap.brandsPage.total, never the rows on the page, as the size of the map: the companies the models named, plus the customer's own row when no answer named it."
      +}
    • addedInput schema / properties / mapOffset
      Added value: +{
      +  "anyOf": [
      +    {
      +      "maximum": 9007199254740991,
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    {
      +      "pattern": "^\\d+$",
      +      "type": "string"
      +    }
      +  ],
      +  "description": "Market-map rows to skip in compact view, for the next page (0-based). marketMap.brandsPage.hasMore says a next page exists."
      +}
    • changedInput schema / properties / promptIndex / anyOf
      Previous value: -[
      -  {
      -    "minimum": 0,
      -    "type": "integer"
      -  },
      -  {
      -    "pattern": "^\\d+$",
      -    "type": "string"
      -  }
      -]New value: +[
      +  {
      +    "maximum": 9007199254740991,
      +    "minimum": 0,
      +    "type": "integer"
      +  },
      +  {
      +    "pattern": "^\\d+$",
      +    "type": "string"
      +  }
      +]
    • addedInput schema / properties / view
      Added value: +{
      +  "description": "compact or full; omit for the server's default view. compact pages the long lists and keeps the customer's own row on every page. full returns every row in one response: up to about 200,000 characters on AI Visibility and 450,000 on AI Sources. Paging parameters with view=full are refused (paging_requires_compact_view).",
      +  "enum": [
      +    "compact",
      +    "full"
      +  ],
      +  "type": "string"
      +}
  2. Changed4 schema fields changedv3.0.0
    • addedInput schema / properties / brand
      Added value: +{
      +  "description": "Return only the entries for this domain, across every answer. Requires includeAnswers=true. Matches brands[].domain case-insensitively — brand NAMES are the model's own wording and vary between answers, so they are never matched. Every answer is still returned: the ones that did not name this domain arrive with an empty brands list, which means the model answered and did not name them — a real finding, and different from a query that produced no answer, which is in unansweredQueries, and from a query the model was read for and had no answer to show, which is in noAnswerShown. This is the cheapest way to answer 'where does this competitor beat me, and where are they invisible': roughly 2k tokens against 25k+ for an unfiltered fetch, or 9k against 46k once Google AI Overviews is in the ask, whose overview text and cited pages this filter keeps.",
      +  "type": "string"
      +}
    • addedInput schema / properties / includeAnswers
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "boolean"
      +    },
      +    {
      +      "const": "true",
      +      "type": "string"
      +    },
      +    {
      +      "const": "false",
      +      "type": "string"
      +    }
      +  ],
      +  "description": "Default false. Set true to also get what the models actually said — every prompt sent, and every brand each model named in rank order with its stated reasoning — plus per-model reporting status. Per-brand prose (reasoning, audience, pricing tier, messaging, differentiation) is present only for models that supply it: a brand row carrying only name and domain means Google AI Overviews named it in prose, and that answer carries the overview text (answerText) with the pages Google cited (sources) beside it. For Google AI Overviews that order is the order of first mention in the overview text, computed by CompetLab; Google assigned no position, so never report it as a rank Google gave. Cost: roughly 25k tokens unfiltered on a three-engine check and 46k on a five-engine one, against roughly 2k with brand= — or roughly 9k when Google AI Overviews is in the ask, whose overview text and cited pages the brand filter keeps. Read summary.totalEntries first to size it (about 375 tokens per entry, plus the overview text and cited pages on each Google AI Overviews answer, which the entry count does not predict) and prefer a filter below over fetching everything. ATTRIBUTION: the prose returned is unverified model output about the brands that model named, including third parties. Report it as what that model said, never as CompetLab's assessment or as fact."
      +}
    • addedInput schema / properties / promptIndex
      Added value: +{
      +  "anyOf": [
      +    {
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    {
      +      "pattern": "^\\d+$",
      +      "type": "string"
      +    }
      +  ],
      +  "description": "Return only the answers for this prompt, across every model. Requires includeAnswers=true. Zero-based."
      +}
    • addedInput schema / properties / provider
      Added value: +{
      +  "description": "Return only this model's answers. Requires includeAnswers=true. Changes nothing under summary.",
      +  "enum": [
      +    "openai",
      +    "claude",
      +    "gemini",
      +    "perplexity",
      +    "google_ai_overviews"
      +  ],
      +  "type": "string"
      +}
  3. First observedv1.0.0

TDQS

A4.8/5.0
Behavior5/5

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

Annotations only cover readOnlyHint/openWorldHint, yet the description discloses costs (20,000-30,000 char summaries, ~1,500 chars per brand entry), truncation behavior (answersTruncated drops whole prompts), the three never-merged query states, and attribution rules for model prose. These are behavioral traits far beyond the annotations.

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

Conciseness4/5

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

Purpose and the three query states are front-loaded, and most sentences carry unique operational payload. It is long and repeats the three query states in both the top prose and the includeAnswers description, but the density of real constraints justifies most of the length.

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?

No output schema exists, and the description compensates by describing the return shape in detail: summary.competitorRankings, marketMap paging, answers block growth, unansweredQueries, noAnswerShown, answersTruncated, and readingGuide as the fallback for unlisted fields. Nothing an agent needs to call and interpret this 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 the baseline is 3, but the description goes further by explaining the cost model that sizes includeAnswers, the interaction rules (brand/provider/promptIndex require includeAnswers; paging requires summary), and why score vs mentionRate means 'below top 5' rather than 'never named'. Only slightly redundant with the already-detailed schema.

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?

Opens with a precise verb+resource and immediately disambiguates the identifier type ('checkId, not runId'), plus names the sibling tools get_ai_visibility_dashboard and get_ai_visibility_history for context. An agent can distinguish this from the dashboard/history/run_detail siblings without opening the 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?

Explicit routing: narrow with brand/provider/promptIndex before fetching answers, use summary.customer.perPrompt before pulling raw answers, and includeSummary=false when the summary is already held. It also names the alternative read paths (get_ai_visibility_dashboard semantics) and gives when-not conditions (paging refused with includeSummary=false).

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