Skip to main content
Glama

SEO GSC Wizard MCP

Detect traffic anomalies

detect_anomalies
Read-only

Use this when the user asks whether something broke or spiked on a specific day. Flags statistically anomalous days in a property's Search Console series for a chosen metric (clicks, impressions, CTR, or position). Not for level shifts or gradual trends: use detect_change_points. Uses a robust Modified Z-score with median absolute deviation and day-of-week baselines (mean absolute deviation when most days are identical, as on a low-traffic property), then scores each spike/drop by severity (critical to info). Anomalies are listed by date, oldest first; for ctr, actual and expected are 0-100 percentages. direction is numeric (actual above or below expected), so for position "down" is a better ranking; outcome (improved or worsened) is the good-or-bad reading for every metric. Each anomaly carries the day's impressions and clicks. For ctr and position an outlier the day's volume can explain is dropped, and a day under minImpressions is kept but marked lowVolume with severity capped at low. episodes groups flagged days that follow each other: a run of 3 or more (possibleLevelShift) is usually one level shift, not separate events, and nextStep then says how to check it with detect_change_points. Days without rows count as zero for clicks and impressions, so a drop to zero (deindexing) is flagged; the 21-day minimum is measured in calendar days from the first day with data. CTR and position use only days with impressions. coverage reports the days analysed and how an empty tail at the end of the window was treated. Reads the ClickHouse warehouse when available, else the live Search Console API.

Input Schema

NameRequiredDescriptionDefault
daysNoTrailing days of daily data to analyze (min 21, default 90).
metricNoWhich metric to scan for anomalies.clicks
siteUrlYes
sensitivityNoModified Z-score threshold: lower = more sensitive (more anomalies). Default 3.5; 3-4 is typical.
minImpressionsNoctr and position only (ignored for clicks and impressions): a day with fewer impressions is kept but marked lowVolume, severity capped at low. Omit for the automatic floor, the larger of 10 and 20% of the median daily impressions; 0 turns it off. The value used is returned as minImpressions.

Output Schema

NameRequiredDescriptionDefault
noteNo
rangeNo
metricNo
thenByNo
listKeyNoName of the top-level field that holds the rows sortedBy describes.
siteUrlNo
summaryNo
warningNo
coverageNo
episodesNo
nextStepNo
orderingNo
sortedByNo
anomaliesNo
sortOrderNo
thenOrderNo
dataSourceNo
partialDaysNo
sensitivityNo
dataMaturityNo
emptyBecauseNo
methodLimitsNo
minImpressionsNo
settledThroughNo
warehouseLatestDateNo
baselineContaminatedNo

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed11 schema fields changed
    • addedInput schema / properties / minImpressions
      Added value: +{
      +  "description": "ctr and position only (ignored for clicks and impressions): a day with fewer impressions is kept but marked lowVolume, severity capped at low. Omit for the automatic floor, the larger of 10 and 20% of the median daily impressions; 0 turns it off. The value used is returned as minImpressions.",
      +  "maximum": 1000000,
      +  "minimum": 0,
      +  "type": "integer"
      +}
    • addedOutput schema / properties / anomalies / items / properties / clicks
      Added value: +{
      +  "$ref": "#/properties/sensitivity"
      +}
    • addedOutput schema / properties / anomalies / items / properties / direction / description
      Added value: +"Numeric: actual above (\"up\") or below (\"down\") expected. For position, \"down\" is a better ranking."
    • addedOutput schema / properties / anomalies / items / properties / impressions
      Added value: +{
      +  "$ref": "#/properties/sensitivity"
      +}
    • addedOutput schema / properties / anomalies / items / properties / lowVolume
      Added value: +{
      +  "type": [
      +    "boolean",
      +    "null"
      +  ]
      +}
    • addedOutput schema / properties / anomalies / items / properties / outcome
      Added value: +{
      +  "$ref": "#/properties/siteUrl",
      +  "description": "\"improved\" or \"worsened\": the good-or-bad reading of direction for this metric."
      +}
    • addedOutput schema / properties / baselineContaminated
      Added value: +{
      +  "$ref": "#/properties/anomalies/items/properties/lowVolume"
      +}
    • addedOutput schema / properties / episodes
      Added value: +{
      +  "items": {
      +    "additionalProperties": true,
      +    "properties": {
      +      "days": {
      +        "$ref": "#/properties/sensitivity"
      +      },
      +      "direction": {
      +        "$ref": "#/properties/siteUrl"
      +      },
      +      "endDate": {
      +        "$ref": "#/properties/siteUrl"
      +      },
      +      "meanActual": {
      +        "$ref": "#/properties/sensitivity"
      +      },
      +      "meanExpected": {
      +        "$ref": "#/properties/sensitivity"
      +      },
      +      "ongoing": {
      +        "$ref": "#/properties/anomalies/items/properties/lowVolume"
      +      },
      +      "outcome": {
      +        "$ref": "#/properties/siteUrl"
      +      },
      +      "peakSeverity": {
      +        "$ref": "#/properties/siteUrl"
      +      },
      +      "possibleLevelShift": {
      +        "$ref": "#/properties/anomalies/items/properties/lowVolume"
      +      },
      +      "startDate": {
      +        "$ref": "#/properties/siteUrl"
      +      }
      +    },
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
    • addedOutput schema / properties / listKey
      Added value: +{
      +  "$ref": "#/properties/siteUrl",
      +  "description": "Name of the top-level field that holds the rows sortedBy describes."
      +}
    • addedOutput schema / properties / minImpressions
      Added value: +{
      +  "$ref": "#/properties/sensitivity"
      +}
    • changedOutput schema / properties / summary / anyOf
      Previous value: -[
      -  {
      -    "additionalProperties": true,
      -    "properties": {
      -      "critical": {
      -        "$ref": "#/properties/sensitivity"
      -      },
      -      "high": {
      -        "$ref": "#/properties/sensitivity"
      -      },
      -      "info": {
      -        "$ref": "#/properties/sensitivity"
      -      },
      -      "largestDeviation": {
      -        "$ref": "#/properties/sensitivity"
      -      },
      -      "low": {
      -        "$ref": "#/properties/sensitivity"
      -      },
      -      "medium": {
      -        "$ref": "#/properties/sensitivity"
      -      },
      -      "mostAffectedMetric": {
      -        "$ref": "#/properties/siteUrl"
      -      },
      -      "total": {
      -        "$ref": "#/properties/sensitivity"
      -      }
      -    },
      -    "type": "object"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": true,
      +    "properties": {
      +      "critical": {
      +        "$ref": "#/properties/sensitivity"
      +      },
      +      "high": {
      +        "$ref": "#/properties/sensitivity"
      +      },
      +      "info": {
      +        "$ref": "#/properties/sensitivity"
      +      },
      +      "largestDeviation": {
      +        "$ref": "#/properties/sensitivity"
      +      },
      +      "low": {
      +        "$ref": "#/properties/sensitivity"
      +      },
      +      "lowVolume": {
      +        "$ref": "#/properties/sensitivity"
      +      },
      +      "medium": {
      +        "$ref": "#/properties/sensitivity"
      +      },
      +      "mostAffectedMetric": {
      +        "$ref": "#/properties/siteUrl"
      +      },
      +      "total": {
      +        "$ref": "#/properties/sensitivity"
      +      }
      +    },
      +    "type": "object"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
  2. Changed16 schema fields changed
    • changedOutput schema / additionalProperties
      Previous value: -falseNew value: +true
    • changedOutput schema / properties / anomalies / items / additionalProperties
      Previous value: -falseNew value: +true
    • changedOutput schema / properties / coverage / anyOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "calendarDays": {
      -        "$ref": "#/properties/sensitivity"
      -      },
      -      "daysAnalyzed": {
      -        "$ref": "#/properties/sensitivity"
      -      },
      -      "daysWithData": {
      -        "$ref": "#/properties/sensitivity"
      -      },
      -      "firstDataDate": {
      -        "$ref": "#/properties/siteUrl"
      -      },
      -      "lastDataDate": {
      -        "$ref": "#/properties/siteUrl"
      -      },
      -      "trailingGap": {
      -        "anyOf": [
      -          {
      -            "additionalProperties": false,
      -            "properties": {
      -              "lastDataDate": {
      -                "$ref": "#/properties/siteUrl"
      -              },
      -              "missingDays": {
      -                "$ref": "#/properties/sensitivity"
      -              },
      -              "note": {
      -                "$ref": "#/properties/siteUrl"
      -              },
      -              "status": {
      -                "$ref": "#/properties/siteUrl"
      -              }
      -            },
      -            "type": "object"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ]
      -      },
      -      "zeroFilledDays": {
      -        "$ref": "#/properties/sensitivity"
      -      }
      -    },
      -    "type": "object"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": true,
      +    "properties": {
      +      "calendarDays": {
      +        "$ref": "#/properties/sensitivity"
      +      },
      +      "daysAnalyzed": {
      +        "$ref": "#/properties/sensitivity"
      +      },
      +      "daysWithData": {
      +        "$ref": "#/properties/sensitivity"
      +      },
      +      "firstDataDate": {
      +        "$ref": "#/properties/siteUrl"
      +      },
      +      "lastDataDate": {
      +        "$ref": "#/properties/siteUrl"
      +      },
      +      "trailingGap": {
      +        "anyOf": [
      +          {
      +            "additionalProperties": true,
      +            "properties": {
      +              "lastDataDate": {
      +                "$ref": "#/properties/siteUrl"
      +              },
      +              "missingDays": {
      +                "$ref": "#/properties/sensitivity"
      +              },
      +              "note": {
      +                "$ref": "#/properties/siteUrl"
      +              },
      +              "status": {
      +                "$ref": "#/properties/siteUrl"
      +              }
      +            },
      +            "type": "object"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ]
      +      },
      +      "zeroFilledDays": {
      +        "$ref": "#/properties/sensitivity"
      +      }
      +    },
      +    "type": "object"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • 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 / emptyBecause
      Added value: +{
      +  "$ref": "#/properties/siteUrl"
      +}
    • addedOutput schema / properties / methodLimits
      Added value: +{
      +  "$ref": "#/properties/siteUrl"
      +}
    • addedOutput schema / properties / nextStep
      Added value: +{
      +  "$ref": "#/properties/siteUrl"
      +}
    • 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"
      +    }
      +  ]
      +}
    • addedOutput schema / properties / partialDays
      Added value: +{
      +  "anyOf": [
      +    {
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ]
      +}
    • changedOutput schema / properties / range / anyOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "days": {
      -        "$ref": "#/properties/sensitivity"
      -      },
      -      "endDate": {
      -        "$ref": "#/properties/siteUrl"
      -      },
      -      "startDate": {
      -        "$ref": "#/properties/siteUrl"
      -      }
      -    },
      -    "type": "object"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": true,
      +    "properties": {
      +      "days": {
      +        "$ref": "#/properties/sensitivity"
      +      },
      +      "endDate": {
      +        "$ref": "#/properties/siteUrl"
      +      },
      +      "startDate": {
      +        "$ref": "#/properties/siteUrl"
      +      }
      +    },
      +    "type": "object"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • addedOutput schema / properties / sortOrder
      Added value: +{
      +  "$ref": "#/properties/siteUrl"
      +}
    • addedOutput schema / properties / sortedBy
      Added value: +{
      +  "$ref": "#/properties/siteUrl"
      +}
    • changedOutput schema / properties / summary / anyOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "critical": {
      -        "$ref": "#/properties/sensitivity"
      -      },
      -      "high": {
      -        "$ref": "#/properties/sensitivity"
      -      },
      -      "info": {
      -        "$ref": "#/properties/sensitivity"
      -      },
      -      "largestDeviation": {
      -        "$ref": "#/properties/sensitivity"
      -      },
      -      "low": {
      -        "$ref": "#/properties/sensitivity"
      -      },
      -      "medium": {
      -        "$ref": "#/properties/sensitivity"
      -      },
      -      "mostAffectedMetric": {
      -        "$ref": "#/properties/siteUrl"
      -      },
      -      "total": {
      -        "$ref": "#/properties/sensitivity"
      -      }
      -    },
      -    "type": "object"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": true,
      +    "properties": {
      +      "critical": {
      +        "$ref": "#/properties/sensitivity"
      +      },
      +      "high": {
      +        "$ref": "#/properties/sensitivity"
      +      },
      +      "info": {
      +        "$ref": "#/properties/sensitivity"
      +      },
      +      "largestDeviation": {
      +        "$ref": "#/properties/sensitivity"
      +      },
      +      "low": {
      +        "$ref": "#/properties/sensitivity"
      +      },
      +      "medium": {
      +        "$ref": "#/properties/sensitivity"
      +      },
      +      "mostAffectedMetric": {
      +        "$ref": "#/properties/siteUrl"
      +      },
      +      "total": {
      +        "$ref": "#/properties/sensitivity"
      +      }
      +    },
      +    "type": "object"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • 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"
      +}
  3. Changed2 schema fields changed
    • addedOutput schema / properties / coverage
      Added value: +{
      +  "anyOf": [
      +    {
      +      "additionalProperties": false,
      +      "properties": {
      +        "calendarDays": {
      +          "$ref": "#/properties/sensitivity"
      +        },
      +        "daysAnalyzed": {
      +          "$ref": "#/properties/sensitivity"
      +        },
      +        "daysWithData": {
      +          "$ref": "#/properties/sensitivity"
      +        },
      +        "firstDataDate": {
      +          "$ref": "#/properties/siteUrl"
      +        },
      +        "lastDataDate": {
      +          "$ref": "#/properties/siteUrl"
      +        },
      +        "trailingGap": {
      +          "anyOf": [
      +            {
      +              "additionalProperties": false,
      +              "properties": {
      +                "lastDataDate": {
      +                  "$ref": "#/properties/siteUrl"
      +                },
      +                "missingDays": {
      +                  "$ref": "#/properties/sensitivity"
      +                },
      +                "note": {
      +                  "$ref": "#/properties/siteUrl"
      +                },
      +                "status": {
      +                  "$ref": "#/properties/siteUrl"
      +                }
      +              },
      +              "type": "object"
      +            },
      +            {
      +              "type": "null"
      +            }
      +          ]
      +        },
      +        "zeroFilledDays": {
      +          "$ref": "#/properties/sensitivity"
      +        }
      +      },
      +      "type": "object"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ]
      +}
    • addedOutput schema / properties / warehouseLatestDate
      Added value: +{
      +  "$ref": "#/properties/siteUrl"
      +}
  4. First observed

TDQS

A4.8/5.0
Behavior5/5

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

Annotations only cover the safety profile (readOnly, non-destructive, open world); the description goes far beyond by disclosing the statistical method (Modified Z-score with MAD, day-of-week baselines, MAD fallback on low-traffic properties), severity grading, output ordering (oldest first), zero-imputation for missing days, the 21-calendar-day minimum, lowVolume capping, episode grouping rules, and the ClickHouse-vs-live-API data source.

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 the usage trigger and the sibling exclusion, then ordered from method to output shape to edge cases — a sensible structure for a complex tool. A few clauses repeat schema content (ctr as 0-100 percentages, the lowVolume cap), which is the only reason it is not a 5.

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 five-parameter statistical tool with an output schema, the description covers everything an agent needs to call it correctly and interpret results: metric caveats, missing-day handling, volume-driven outlier suppression, episode/nextStep guidance, and coverage reporting. Nothing material is left to inference.

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 80%, so the baseline is 3; the description adds real meaning on top by explaining metric-specific interpretation (for position, 'down' is better; outcome is the good-or-bad reading) and the interplay between minImpressions, lowVolume, and severity capping. It does not elaborate on what sensitivity values imply beyond the schema's own threshold note, which keeps it from 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 and resource — flags statistically anomalous days in a property's Search Console metric series — and immediately names the sibling it is not (detect_change_points). An agent can distinguish anomaly detection from change-point detection 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?

Opens with an explicit trigger ('when the user asks whether something broke or spiked on a specific day') and an explicit exclusion ('Not for level shifts or gradual trends: use detect_change_points'). It also routes follow-up cases via episodes/nextStep back to detect_change_points, so both selection and hand-off are covered.

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