Skip to main content
Glama

SEO GSC Wizard MCP

Query Search Console analytics

query_search_analytics
Read-only

Use this when the user asks an ad-hoc question that needs raw Search Console rows, like "top queries last 28 days" or "page-level performance for /pricing". Runs searchAnalytics.query on a property: date / query / page / country / device / searchAppearance dimensions, filters, and the web, image, video, news, discover, googleNews or all (combined) search type. Not for totals or period comparisons: use get_site_summary. Eligible requests are served from the GSC Wizard ClickHouse warehouse (longer history); searchAppearance, googleNews or 3+ distinct dimensions use the live Search Console API (dataSource says which). Rows are sorted by clicks, highest first, or by date then clicks when date is a dimension (a live-API result over 5,000 rows keeps clicks order); sortedBy states it. ctr is a 0-100 percentage. Query rows cover only the queries Google lists: coverage.hiddenClicksShare (0-1) is the share of clicks with no query row, so quote totals from coverage.siteTotals, or coverage.filteredTotals when coverage.scope is "filtered", not summed rows. Regex filters use RE2 (no lookahead or backreferences; use excludingRegex to exclude). Returns 100 rows by default: pagination says whether the result was truncated; page with startRow or raise rowLimit. Date range is optional: omit startDate/endDate to analyze the last 28 settled days (data lags ~2-3 days).

Input Schema

NameRequiredDescriptionDefault
endDateNoOptional. Window end as YYYY-MM-DD (e.g. 2026-05-31). You do NOT need to know today's date or the latest available date: omit this and the server uses the latest settled Search Console date (data lags ~2-3 days behind today). Never pass null or the string "null".
filtersNoDimension filters joined with AND. Pass an empty list or omit for no filtering.
siteUrlYesThe property URL as returned by list_sites (e.g. "sc-domain:example.com").
rowLimitNoRows to return per call (default 100, max 25000). Large values return a lot of raw rows; prefer paging with startRow.
startRowNoRows to skip. Use pagination.nextOffset from a previous call to get the next page.
startDateNoOptional. Window start as YYYY-MM-DD (e.g. 2026-05-03). You do NOT need to know today's date. Omit BOTH startDate and endDate to analyze the last 28 settled days automatically (Search Console data lags ~2-3 days). Never pass null or the string "null".
dimensionsNo
searchTypeNoSearch type: web (default), image, video, news (the News tab), discover, googleNews (news.google.com), or all (web + image + video + news + discover combined, position impression-weighted, like the app's "All" filter). Discover and googleNews carry no query dimension, so query-level results for them are empty, and no position: it reads null, not 0.web

Output Schema

NameRequiredDescriptionDefault
noteNo
rowsNo
thenByNo
endDateNo
listKeyNoName of the top-level field that holds the rows sortedBy describes.
siteUrlNo
warningNo
coverageNoHow much of the property total the rows cover, totals inline. Quote totals from here; do not sum rows.
orderingNo
rowCountNo
sortedByNo
sortOrderNo
startDateNo
thenOrderNo
dataSourceNo
dimensionsNo
paginationNo
searchTypeNo
partialDaysNo
dataMaturityNo
settledThroughNo
coverageUnavailableNoWhy coverage is null, when it is.
warehouseLatestDateNo

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changed
    • addedOutput schema / properties / listKey
      Added value: +{
      +  "$ref": "#/properties/siteUrl",
      +  "description": "Name of the top-level field that holds the rows sortedBy describes."
      +}
  2. Changed1 schema field changed
    • changedInput schema / properties / searchType / description
      Previous value: -"Search type: web (default), image, video, news (the News tab), discover, googleNews (news.google.com), or all (web + image + video + news + discover combined, position impression-weighted, like the app's \"All\" filter). Discover and googleNews carry no query dimension, so query-level results for them are empty."New value: +"Search type: web (default), image, video, news (the News tab), discover, googleNews (news.google.com), or all (web + image + video + news + discover combined, position impression-weighted, like the app's \"All\" filter). Discover and googleNews carry no query dimension, so query-level results for them are empty, and no position: it reads null, not 0."
  3. Changed2 schema fields changed
    • addedInput schema / properties / searchType / description
      Added value: +"Search type: web (default), image, video, news (the News tab), discover, googleNews (news.google.com), or all (web + image + video + news + discover combined, position impression-weighted, like the app's \"All\" filter). Discover and googleNews carry no query dimension, so query-level results for them are empty."
    • changedInput schema / properties / searchType / enum
      Previous value: -[
      -  "web",
      -  "image",
      -  "video",
      -  "news",
      -  "discover",
      -  "googleNews"
      -]New value: +[
      +  "web",
      +  "image",
      +  "video",
      +  "news",
      +  "discover",
      +  "googleNews",
      +  "all"
      +]
  4. Changed13 schema fields changed
    • changedOutput schema / additionalProperties
      Previous value: -falseNew value: +true
    • addedOutput schema / properties / coverage
      Added value: +{
      +  "anyOf": [
      +    {
      +      "additionalProperties": true,
      +      "properties": {
      +        "clicksCovered": {
      +          "$ref": "#/properties/rowCount",
      +          "description": "0-1 share of the totals named by sharesOf that this page's rows carry."
      +        },
      +        "filteredTotals": {
      +          "$ref": "#/properties/coverage/anyOf/0/properties/siteTotals",
      +          "description": "The same totals with the filters applied (scope \"filtered\")."
      +        },
      +        "hiddenClicksShare": {
      +          "$ref": "#/properties/rowCount",
      +          "description": "0-1 share of those totals that no row of this dimension carries (anonymised queries on query rows, near zero on page, country and device rows); null when unknown."
      +        },
      +        "hiddenImpressionsShare": {
      +          "$ref": "#/properties/rowCount"
      +        },
      +        "impressionsCovered": {
      +          "$ref": "#/properties/rowCount"
      +        },
      +        "note": {
      +          "$ref": "#/properties/siteUrl",
      +          "description": "Why some fields are null, when they are."
      +        },
      +        "rowsReturned": {
      +          "$ref": "#/properties/rowCount",
      +          "description": "Rows on this page."
      +        },
      +        "rowsTotal": {
      +          "$ref": "#/properties/rowCount",
      +          "description": "Rows across every page; null when unknown."
      +        },
      +        "scope": {
      +          "$ref": "#/properties/siteUrl",
      +          "description": "\"property\", or \"filtered\" when the rows were read with filters."
      +        },
      +        "sharesOf": {
      +          "$ref": "#/properties/siteUrl",
      +          "description": "\"siteTotals\", or \"filteredTotals\" when scope is \"filtered\"."
      +        },
      +        "siteTotals": {
      +          "anyOf": [
      +            {
      +              "additionalProperties": true,
      +              "properties": {
      +                "avgPositionWeighted": {
      +                  "$ref": "#/properties/rowCount",
      +                  "description": "Impression-weighted average position."
      +                },
      +                "clicks": {
      +                  "$ref": "#/properties/rowCount"
      +                },
      +                "ctrPercent": {
      +                  "$ref": "#/properties/rowCount",
      +                  "description": "A 0-100 percentage."
      +                },
      +                "impressions": {
      +                  "$ref": "#/properties/rowCount"
      +                }
      +              },
      +              "type": "object"
      +            },
      +            {
      +              "type": "null"
      +            }
      +          ],
      +          "description": "The property's totals for this window and search type, with no dimension and no filter."
      +        },
      +        "totalsFrom": {
      +          "$ref": "#/properties/siteUrl",
      +          "description": "\"get_site_summary\" (the read and arithmetic that tool uses) or \"property_totals\" (the same, for a search type other than web)."
      +        }
      +      },
      +      "type": "object"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "description": "How much of the property total the rows cover, totals inline. Quote totals from here; do not sum rows."
      +}
    • addedOutput schema / properties / coverageUnavailable
      Added value: +{
      +  "$ref": "#/properties/siteUrl",
      +  "description": "Why coverage is null, when it is."
      +}
    • changedOutput schema / properties / dataMaturity / anyOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "dateBasis": {
      -        "$ref": "#/properties/siteUrl"
      -      },
      -      "firstIncompleteDate": {
      -        "$ref": "#/properties/siteUrl"
      -      },
      -      "note": {
      -        "$ref": "#/properties/siteUrl"
      -      },
      -      "probe": {
      -        "anyOf": [
      -          {
      -            "additionalProperties": false,
      -            "properties": {
      -              "dataState": {
      -                "$ref": "#/properties/siteUrl"
      -              },
      -              "endDate": {
      -                "$ref": "#/properties/siteUrl"
      -              },
      -              "searchType": {
      -                "$ref": "#/properties/siteUrl"
      -              },
      -              "startDate": {
      -                "$ref": "#/properties/siteUrl"
      -              }
      -            },
      -            "type": "object"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ]
      -      },
      -      "settledThrough": {
      -        "$ref": "#/properties/siteUrl"
      -      },
      -      "source": {
      -        "$ref": "#/properties/siteUrl"
      -      },
      -      "warehouseCutoff": {
      -        "$ref": "#/properties/siteUrl"
      -      }
      -    },
      -    "type": "object"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": true,
      +    "properties": {
      +      "dateBasis": {
      +        "$ref": "#/properties/siteUrl"
      +      },
      +      "firstIncompleteDate": {
      +        "$ref": "#/properties/siteUrl"
      +      },
      +      "note": {
      +        "$ref": "#/properties/siteUrl"
      +      },
      +      "probe": {
      +        "anyOf": [
      +          {
      +            "additionalProperties": true,
      +            "properties": {
      +              "dataState": {
      +                "$ref": "#/properties/siteUrl"
      +              },
      +              "endDate": {
      +                "$ref": "#/properties/siteUrl"
      +              },
      +              "searchType": {
      +                "$ref": "#/properties/siteUrl"
      +              },
      +              "startDate": {
      +                "$ref": "#/properties/siteUrl"
      +              }
      +            },
      +            "type": "object"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ]
      +      },
      +      "settledThrough": {
      +        "$ref": "#/properties/siteUrl"
      +      },
      +      "source": {
      +        "$ref": "#/properties/siteUrl"
      +      },
      +      "warehouseCutoff": {
      +        "$ref": "#/properties/siteUrl"
      +      }
      +    },
      +    "type": "object"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • addedOutput schema / properties / ordering
      Added value: +{
      +  "anyOf": [
      +    {
      +      "additionalProperties": {
      +        "additionalProperties": true,
      +        "properties": {
      +          "sortOrder": {
      +            "$ref": "#/properties/siteUrl"
      +          },
      +          "sortedBy": {
      +            "$ref": "#/properties/siteUrl"
      +          },
      +          "thenBy": {
      +            "$ref": "#/properties/siteUrl"
      +          },
      +          "thenOrder": {
      +            "$ref": "#/properties/siteUrl"
      +          }
      +        },
      +        "type": "object"
      +      },
      +      "type": "object"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ]
      +}
    • changedOutput schema / properties / pagination / anyOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "hasMore": {
      -        "type": [
      -          "boolean",
      -          "null"
      -        ]
      -      },
      -      "limit": {
      -        "$ref": "#/properties/rowCount"
      -      },
      -      "nextOffset": {
      -        "$ref": "#/properties/rowCount"
      -      },
      -      "note": {
      -        "$ref": "#/properties/siteUrl"
      -      },
      -      "offset": {
      -        "$ref": "#/properties/rowCount"
      -      },
      -      "returned": {
      -        "$ref": "#/properties/rowCount"
      -      }
      -    },
      -    "type": "object"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": true,
      +    "properties": {
      +      "hasMore": {
      +        "type": [
      +          "boolean",
      +          "null"
      +        ]
      +      },
      +      "limit": {
      +        "$ref": "#/properties/rowCount"
      +      },
      +      "nextOffset": {
      +        "$ref": "#/properties/rowCount"
      +      },
      +      "note": {
      +        "$ref": "#/properties/siteUrl"
      +      },
      +      "offset": {
      +        "$ref": "#/properties/rowCount"
      +      },
      +      "returned": {
      +        "$ref": "#/properties/rowCount"
      +      }
      +    },
      +    "type": "object"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • addedOutput schema / properties / partialDays
      Added value: +{
      +  "$ref": "#/properties/dimensions"
      +}
    • changedOutput schema / properties / rows / items / additionalProperties
      Previous value: -falseNew value: +true
    • addedOutput schema / properties / sortOrder
      Added value: +{
      +  "$ref": "#/properties/siteUrl"
      +}
    • addedOutput schema / properties / sortedBy
      Added value: +{
      +  "$ref": "#/properties/siteUrl"
      +}
    • addedOutput schema / properties / thenBy
      Added value: +{
      +  "$ref": "#/properties/siteUrl"
      +}
    • addedOutput schema / properties / thenOrder
      Added value: +{
      +  "$ref": "#/properties/siteUrl"
      +}
    • addedOutput schema / properties / warning
      Added value: +{
      +  "$ref": "#/properties/siteUrl"
      +}
  5. Changed1 schema field changed
    • addedOutput schema / properties / warehouseLatestDate
      Added value: +{
      +  "$ref": "#/properties/siteUrl"
      +}
  6. First observed

TDQS

A4.5/5.0
Behavior4/5

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

Goes well beyond the readOnly/destructive annotations: discloses data source selection (ClickHouse vs live API), sort order rules and their exceptions, ctr units, RE2 regex limitations (no lookahead/backreferences, use excludingRegex), default 100-row pagination with 5,000-row live cap, and the ~2-3 day data lag. Missing only error/permission failure modes and quota behavior for a tool with openWorldHint.

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

Conciseness3/5

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

Front-loaded with purpose and exclusions, which is right, but the body is a dense run of semicolon-joined clauses covering sorting, units, coverage caveats, regex dialect, and pagination. Every fact is useful, but it reads as a reference dump rather than a structured, scannable description.

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?

Covers the hard parts of this query surface: why summed query rows under-count clicks and where to quote totals from (coverage.siteTotals/filteredTotals), dataSource reporting, sort determinism via sortedBy, and truncation via pagination. With an output schema present and 88% schema coverage, the remaining needs are addressed.

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 88% and the description still adds real value: it clarifies the omitted-date-range default (last 28 settled days), the dimensions/searchAppearance/googleNews constraints ('no query dimension', '3+ distinct dimensions use live API'), and searchType semantics including 'all' weighting. Regex operator semantics are explained in prose rather than left to the enum.

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 concrete verb+resource framing ('ad-hoc question that needs raw Search Console rows') and examples ('top queries last 28 days', 'page-level performance for /pricing'), then names the underlying API call. It distinguishes itself from siblings by explicitly ruling out totals/period comparisons and pointing to get_site_summary, and from query_top_queries-style tools by its ad-hoc dimensional nature.

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 when-to-use (ad-hoc raw rows), when-not ('Not for totals or period comparisons: use get_site_summary'), and a fallback-alternative route for the same data. It also explains the routing tradeoff between warehouse and live API based on dimensions/searchType, which lets an agent predict behavior before calling.

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.

Resources