Skip to main content
Glama

Summarize a Dataset by Group

aggregate
Read-onlyIdempotent

A summary of one dataset computed on the server: one small row per group instead of raw rows. agg is avg, sum, min, max, count, or weighted_rate. To list observed values of a filter column, use agg='count', group_by=[] (one value per row, plus its count); describe_dataset lists allowed enum values without a scan. metric is the figure to summarize (default: the dataset's key_metric; ignored for count). group_by lists columns to group by (year, code columns like district_code or county_fips, or category columns). weighted_rate is a population-weighted rate, SUM(numerator) / SUM(denominator) times the rate's per-N scale (1,000 for a rate per 1,000, so the figure reads like the rows' own rates; the value column's rate_scale), over the rows that publish both counts (pooled_rows; a row withholding its numerator is left out, not counted as zero); for a rate across several places or years it is the right figure, since avg averages the rows' rates without weighting by population. With metric set to one of the dataset's pooled_rates (a school zone's people per square mile), it pools that rate's own numerator and denominator. Takes the same filters, years, and detail as query_dataset, plus order_by ('value' for the summarized figure) and order. Each row has <metric>_<agg> (or row_count) and coverage counts (input rows, pooled rows, non-null counts), so suppression is visible. aggregation_scope says whether the source publishes rows at this level or they are recomputed from finer rows. A sum or weighted_rate across a column the dataset declares non_additive (overlapping rows) is returned with a non_additive block and a leading non_additive_sum advisory: that figure is not a total. NULLs are skipped. No SQL: every column name is checked against the dataset's schema.

Tool call template

Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {
      "topic": "<topic>"
    },
    "name": "aggregate"
  }
}

Input Schema

NameRequiredDescriptionDefault
aggNoHow to summarize (default 'avg').avg
yearNoExact year. Use this or year_min/year_max, not both.
limitNoGroups per page (default 100, at most 500).
orderNoSort direction for order_by: 'asc' or 'desc'.asc
topicYesDataset name, e.g. 'act_scores' (the `name` from list_datasets or search_datasets). Names are unique across subject areas.
detailNoLevel of detail, i.e. what one row describes: 'schools', 'districts', 'counties', 'tracts', 'states', ... (each dataset lists its own). Omit for the dataset's default.
metricNoFigure (metric column) to summarize. Default: the dataset's key_metric.
offsetNoNumber of rows to skip, for paging.
filtersNoColumn -> value (or list of values). Keys are the code columns (district_code, school_code, county_fips, tract_geoid, demographic), the dataset's category columns, and a few lookup-table attributes (demographic_category, district_type, school_level, locale); describe_dataset's `filters` lists the exact keys and valid values. A list is OR; several keys AND together. A wrong key or value returns an error listing the valid ones.
group_byNoColumns to group by: year, code columns, or category columns. Omit for one overall row.
order_byNoSort by 'value' (the summarized figure) or a group_by column. NULLs sort last.
year_maxNoLast year of a range (inclusive).
year_minNoFirst year of a range (inclusive).
numeric_filtersNoANDed comparisons on numeric metric columns, before pagination or aggregation. gt/gte/lt/lte use value; inclusive between uses values=[lower, upper]. Stored units: 0.9 means 90%. NULLs do not match. describe_dataset lists numeric_filter_columns.

Output Schema

NameRequiredDescriptionDefault

No arguments

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed2 schema fields changed
    • removedInput schema / properties / main_topic
      Removed value: -{
      -  "anyOf": [
      -    {
      -      "type": "string"
      -    },
      -    {
      -      "type": "null"
      -    }
      -  ],
      -  "default": null,
      -  "description": "Optional subject-area consistency check. Omit: globally unique topic names and full keys identify the dataset on their own.",
      -  "enum": [
      -    "census",
      -    "education",
      -    "health",
      -    "immigration",
      -    null
      -  ],
      -  "title": "Main Topic"
      -}
    • changedInput schema / properties / topic / description
      Previous value: -"Dataset name, e.g. 'act_scores' (the last part of a key from list_datasets or search_datasets). The full key, e.g. 'education/gosa/act_scores', also works. main_topic is optional."New value: +"Dataset name, e.g. 'act_scores' (the `name` from list_datasets or search_datasets). Names are unique across subject areas."
  2. Changed8 schema fields changed
    • addedInput schema / $defs
      Added value: +{
      +  "NumericFilter": {
      +    "additionalProperties": false,
      +    "description": "One comparison on a numeric metric; between includes both endpoints.",
      +    "properties": {
      +      "column": {
      +        "description": "Numeric metric from describe_dataset's numeric_filter_columns.",
      +        "title": "Column",
      +        "type": "string"
      +      },
      +      "op": {
      +        "description": "Comparison; between is inclusive.",
      +        "enum": [
      +          "gt",
      +          "gte",
      +          "lt",
      +          "lte",
      +          "between"
      +        ],
      +        "title": "Op",
      +        "type": "string"
      +      },
      +      "value": {
      +        "anyOf": [
      +          {
      +            "type": "integer"
      +          },
      +          {
      +            "type": "number"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "default": null,
      +        "description": "Finite bound for gt/gte/lt/lte, in stored units (0.9 for 90%).",
      +        "title": "Value"
      +      },
      +      "values": {
      +        "anyOf": [
      +          {
      +            "maxItems": 2,
      +            "minItems": 2,
      +            "prefixItems": [
      +              {
      +                "anyOf": [
      +                  {
      +                    "type": "integer"
      +                  },
      +                  {
      +                    "type": "number"
      +                  }
      +                ]
      +              },
      +              {
      +                "anyOf": [
      +                  {
      +                    "type": "integer"
      +                  },
      +                  {
      +                    "type": "number"
      +                  }
      +                ]
      +              }
      +            ],
      +            "type": "array"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "default": null,
      +        "description": "Ordered [lower, upper] bounds for between; omit value.",
      +        "title": "Values"
      +      }
      +    },
      +    "required": [
      +      "column",
      +      "op"
      +    ],
      +    "title": "NumericFilter",
      +    "type": "object"
      +  }
      +}
    • addedInput schema / properties / main_topic / anyOf
      Added value: +[
      +  {
      +    "type": "string"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • changedInput schema / properties / main_topic / default
      Previous value: -"education"New value: +null
    • changedInput schema / properties / main_topic / description
      Previous value: -"Subject area: 'education' (the default), 'census', or 'immigration'. A dataset's key starts with it."New value: +"Optional subject-area consistency check. Omit: globally unique topic names and full keys identify the dataset on their own."
    • changedInput schema / properties / main_topic / enum
      Previous value: -[
      -  "census",
      -  "education",
      -  "immigration"
      -]New value: +[
      +  "census",
      +  "education",
      +  "health",
      +  "immigration",
      +  null
      +]
    • removedInput schema / properties / main_topic / type
      Removed value: -"string"
    • addedInput schema / properties / numeric_filters
      Added value: +{
      +  "anyOf": [
      +    {
      +      "items": {
      +        "$ref": "#/$defs/NumericFilter"
      +      },
      +      "maxItems": 20,
      +      "type": "array"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "ANDed comparisons on numeric metric columns, before pagination or aggregation. gt/gte/lt/lte use value; inclusive between uses values=[lower, upper]. Stored units: 0.9 means 90%. NULLs do not match. describe_dataset lists numeric_filter_columns.",
      +  "title": "Numeric Filters"
      +}
    • changedInput schema / properties / topic / description
      Previous value: -"Dataset name, e.g. 'act_scores' (the last part of a key from list_datasets or search_datasets). The full key, e.g. 'education/gosa/act_scores', also works and sets main_topic."New value: +"Dataset name, e.g. 'act_scores' (the last part of a key from list_datasets or search_datasets). The full key, e.g. 'education/gosa/act_scores', also works. main_topic is optional."
  3. Changed1 schema field changed
    • changedInput schema / properties / topic / description
      Previous value: -"Dataset name, e.g. 'act_scores' (the last part of a key from list_datasets or search_datasets)."New value: +"Dataset name, e.g. 'act_scores' (the last part of a key from list_datasets or search_datasets). The full key, e.g. 'education/gosa/act_scores', also works and sets main_topic."
  4. Changed27 schema fields changed
    • addedInput schema / properties / agg / description
      Added value: +"How to summarize (default 'avg')."
    • addedInput schema / properties / agg / enum
      Added value: +[
      +  "avg",
      +  "sum",
      +  "min",
      +  "max",
      +  "count",
      +  "weighted_rate"
      +]
    • addedInput schema / properties / detail / description
      Added value: +"Level of detail, i.e. what one row describes: 'schools', 'districts', 'counties', 'tracts', 'states', ... (each dataset lists its own). Omit for the dataset's default."
    • addedInput schema / properties / detail / enum
      Added value: +[
      +  "counties",
      +  "districts",
      +  "schools",
      +  "states",
      +  "tracts",
      +  null
      +]
    • addedInput schema / properties / filters / description
      Added value: +"Column -> value (or list of values). Keys are the code columns (district_code, school_code, county_fips, tract_geoid, demographic), the dataset's category columns, and a few lookup-table attributes (demographic_category, district_type, school_level, locale); describe_dataset's `filters` lists the exact keys and valid values. A list is OR; several keys AND together. A wrong key or value returns an error listing the valid ones."
    • addedInput schema / properties / group_by / description
      Added value: +"Columns to group by: year, code columns, or category columns. Omit for one overall row."
    • addedInput schema / properties / limit / description
      Added value: +"Groups per page (default 100, at most 500)."
    • addedInput schema / properties / limit / maximum
      Added value: +500
    • addedInput schema / properties / limit / minimum
      Added value: +1
    • addedInput schema / properties / main_topic / description
      Added value: +"Subject area: 'education' (the default), 'census', or 'immigration'. A dataset's key starts with it."
    • addedInput schema / properties / main_topic / enum
      Added value: +[
      +  "census",
      +  "education",
      +  "immigration"
      +]
    • addedInput schema / properties / metric / description
      Added value: +"Figure (metric column) to summarize. Default: the dataset's key_metric."
    • addedInput schema / properties / offset / description
      Added value: +"Number of rows to skip, for paging."
    • addedInput schema / properties / offset / minimum
      Added value: +0
    • addedInput schema / properties / order / description
      Added value: +"Sort direction for order_by: 'asc' or 'desc'."
    • addedInput schema / properties / order / enum
      Added value: +[
      +  "asc",
      +  "desc"
      +]
    • addedInput schema / properties / order_by / description
      Added value: +"Sort by 'value' (the summarized figure) or a group_by column. NULLs sort last."
    • addedInput schema / properties / topic / description
      Added value: +"Dataset name, e.g. 'act_scores' (the last part of a key from list_datasets or search_datasets)."
    • addedInput schema / properties / year / description
      Added value: +"Exact year. Use this or year_min/year_max, not both."
    • addedInput schema / properties / year / maximum
      Added value: +2100
    • addedInput schema / properties / year / minimum
      Added value: +1900
    • addedInput schema / properties / year_max / description
      Added value: +"Last year of a range (inclusive)."
    • addedInput schema / properties / year_max / maximum
      Added value: +2100
    • addedInput schema / properties / year_max / minimum
      Added value: +1900
    • addedInput schema / properties / year_min / description
      Added value: +"First year of a range (inclusive)."
    • addedInput schema / properties / year_min / maximum
      Added value: +2100
    • addedInput schema / properties / year_min / minimum
      Added value: +1900
  5. First observed

TDQS

A4.7/5.0
Behavior5/5

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

Goes far beyond the readOnlyHint/idempotentHint annotations: it explains how weighted_rate pools numerator/denominator over pooled_rows, that withheld numerators are excluded rather than zeroed, that suppressed cells are visible via coverage counts, that aggregation_scope reports whether rows are published or recomputed, and that non_additive columns trigger a non_additive block plus an advisory. It also discloses NULL handling and that column names are validated with no SQL pass-through — exactly the behavioral context annotations cannot carry.

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 core purpose and generally dense with earned content, appropriate for a 14-parameter tool. The weighted_rate passage is a single run-on sentence with multiple nested parentheticals that could be split for readability, which costs a point.

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?

Even with an output schema available, the description sketches the row shape (aggregate column or row_count, plus coverage counts) and the non_additive response block, and it covers suppression, scope, defaults, and error behavior. Nothing an agent needs to invoke this correctly is missing.

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

Parameters5/5

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

Schema coverage is already 100%, so the baseline is 3, but the description earns more: it defines each agg value's meaning, states that metric defaults to key_metric and is ignored for count, explains group_by's column families and the omit-for-one-row case, and clarifies order_by='value' refers to the summarized figure. The agg='count'-to-enumerate-values trick is a usage insight not present in the 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?

States a specific verb and resource up front — a server-side summary of one dataset returning one row per group rather than raw rows. The contrast with raw-row retrieval implicitly distinguishes it from query_dataset, and the title reinforces it. An agent can tell what this does 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 Guidelines4/5

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

Gives concrete routing guidance: use agg='count' with group_by to list observed filter values, and use describe_dataset to see allowed enum values without a scan. It also signals it takes the same filters/years/detail as query_dataset, implying that tool for raw rows. It stops short of an explicit 'do not use this when...' exclusion, so a 4 rather than 5.

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