Official MCP RegistryListed
Georgia Civic Data
Query, filter, aggregate, and link Georgia education, Census, immigration, and health datasets.
First seen 2 Oct 2026. Evidence as of 2 Nov 2026.
12
Tools
From an anonymous probe
1
Source listings
Each with its own history
50
Recorded changes
Since first seen
Tools
| Tool | Description | Behaviour |
|---|---|---|
| aggregate | 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=[<column>] (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. | Read-only |
| describe_dataset | The full schema of one dataset: every column (type, role, unit, value range, what a NULL means), the exact `filters` with their valid values (the keys query_dataset and aggregate accept), how the code columns join to the lookup tables (`foreign_keys`), example queries, usage notes, limitations, and null semantics. `key_metric` names the headline figure most answers want. Per column, `key_metric_grain_contributor` marks a category the headline figure is only comparable within (pin it or group by it) and `metric_component` marks the numerator and denominator of a rate. `recommended_query` is a safe default query (headline figure, the filters to pin, required single-value choices) plus a `ranking` recipe for top or bottom N. `filter_hints` lists paired filters. `non_additive` lists columns whose rows overlap, so summing across them double counts; `partitions` lists columns with no total whose values partition the whole (each value's `share` adds up to 1 across them), so they are read side by side and never pinned by default; `value_implications` lists values that imply another column's value. `year_meaning`, when set, says what `year` labels when it is not when the figures were measured. `pooled_rates` lists rates whose figure for several rows is scale * SUM(numerator) / SUM(denominator), `scale` the rate's per-N factor (1,000 for a rate per 1,000) (aggregate with agg='weighted_rate'), not an average of the rows' rates. `series_breaks` lists years from which figures are not comparable with earlier years (each with its `reason`; `metrics`, when present, limits it to those columns), so the step into such a year is not a trend. `year_window`, when set, says every figure pools `years` years named by the window's last year, and `overlapping` whether consecutive windows share years (then they are not an annual series). Each category filter carries `has_total` and `requires_single_value`. verbosity='schema' drops the prose (descriptions, usage, limitations, examples) for a much smaller payload that still has everything needed to build a query; the limitations prose in the default 'full' carries the caveats. An unknown dataset returns an error listing the available ones with a 'did you mean'. | Read-only |
| describe_dimension | The schema of one shared lookup table (a dimension: districts, schools, counties, tracts, block_groups, or demographics): its key columns (schools use district_code plus school_code together), the attribute columns a join adds, the keys that link to other data (`link_keys`: districts.district_census_id reaches Census data through a crosswalk; it is a 5-digit Census school-district code, not a county FIPS code), and, for demographics, how the values relate (`semantics`: groups may overlap across or within categories; use the dataset's definitions and non_additive declarations, and its published `all` total when available). Useful before a link_query join. | Read-only |
| get_contract | The full data contract of one dataset (kind='topic') or lookup table (kind='dimension'): the machine-readable document, in the Open Data Contract Standard (ODCS) v3.2 format, that defines its columns, keys, units, quality checks, source, and limitations. fmt='yaml' (default) returns the document as published; fmt='json' returns it parsed. It is long (often 10 to 50 KB); describe_dataset gives the same schema in a smaller, query-ready form. | Read-only |
| get_dimension | The rows of one shared lookup table: district, school, county, census tract, or demographic codes with their names and attributes, in key order so paging is stable. describe_dimension gives the schema. Pages are small; when `truncated` is true, `bulk_export` gives the REST API address for the full table. | Read-only |
| link_query | Runs one read-only SQL query across datasets, for analysis the per-dataset filters cannot express, such as joining education, Census, immigration, or health figures to a lookup table or to each other on shared geography (immigration, county-level Census, and health data share county_fips; Census and health tract data share tract_geoid). The dialect is DuckDB SQL (https://duckdb.org/docs/sql/introduction). Allowed: one SELECT (or WITH ... SELECT) that names only the tables link_tables lists, by their `table` names (FROM education.attendance a JOIN dimensions.districts d ON a.district_code = d.district_code; without an alias a table is referenced by its bare name, 'attendance'); no DDL, DML, COPY, ATTACH, INSTALL, PRAGMA, SET, or CALL, and no read_parquet(), other file readers, or file paths. Joins use the keys from describe_dimension's link_keys (districts.district_census_id reaches Census data through the crosswalk; it is a school-district code, not a county FIPS code, and a district is not the same as a county). Results are capped by rows, bytes, and time; `truncated` says a cap was hit, and grouping or a tighter WHERE fits more. NULL means suppressed, not zero. A rejected query returns an error naming the token or table at fault, with the closest table names. | Read-only |
| link_tables | The tables link_query can read and the keys that join them: datasets to lookup tables to Census geography. With no arguments, a short index: each dataset's `table` name for SQL (e.g. 'education.attendance', its default detail level), what one row is (`grain`), detail levels, and join keys, plus each lookup table's name (e.g. 'dimensions.districts'). `tables` (names from the index, e.g. 'education.attendance', 'education/gosa/attendance', 'attendance', or 'districts') returns those tables in full: every column and a table name per detail level ('education.attendance__districts'). `main_topic` limits either form to one subject area. | Read-only |
| list_datasets | The catalog: every published Georgia dataset and the shared lookup tables (district, school, county, census tract, and demographic names). By default each dataset is compact: its key (main_topic/sub_topic/topic), title, one-line summary, and first and last year. detail='full' adds detail levels, year gaps, whether it has a demographic breakdown, tags, and the contract version. main_topic ('education', 'census', 'immigration', 'health') limits the list to one subject area. The `license` object gives the terms the data is published under (CC BY 4.0). For a question about a known subject, search_datasets returns fewer, more relevant entries; describe_dataset gives one dataset's full schema. | Read-only |
| lookup_school_zone | Which Georgia public school attendance zones (elementary, middle, high) contain a place, or (attendance_rules=true) how attendance zones work in Georgia. Give exactly one of: lat and lon; an address (located with the U.S. Census Geocoder, an outside service); a 2020 census tract_geoid (every zone covering the tract with the share of its 2020 population in each, or, when none does, a coverage_reason); or attendance_rules=true with no place. Optional grade (pk, k, 01-12) and year. Returns the district, the zoned schools with names and where each zone came from (method, accuracy_class, positional_rmse_m, boundary_vintage, currency_status, currency_note, source_url), a level_status per school level, a coverage_status (zoned; gap: some level has no zone there; one_school_per_grade; not_available: the district publishes no zones at some level, with the reason; not_zoned: no zone assigns the grade asked, i.e. pre-K), a currency_warning when a zone's source predates an adopted change that could not be applied, an overlap_warning when two schools' zones cover the point for the same grades, the point's tract and county, and a geojson_url per zone (never the shapes themselves). Zones are rebuilt from published sources of varying currency and are not an official enrollment determination; families confirm with the district. The zoned school is the default assignment (assignment_note). attendance_rules=true returns instead who draws zones and the main ways a student attends a public school other than the zoned one, with the statute or rule behind each, for questions about how zones work. A dated summary, not legal advice; lang="es" gives it in Spanish. Addresses and points are never stored or logged. | Read-only |
| query_dataset | Rows of one dataset, filtered, with the district, school, county, and demographic names joined in. `filters` takes code columns and category columns (describe_dataset's `filters` lists the exact keys and valid values). Use `year` or `year_min`/`year_max`, not both. `detail` picks what one row describes (default: the dataset's finest level). Returns `rows` and a `columns` list (type, role, unit, what a NULL means, and `is_key_metric` on the headline column); `key_metric` repeats the headline column's name. A NULL usually means the source suppressed the value, not zero. `columns` returns only the listed columns, `include_labels=false` leaves out the names, and `order_by` with `order` sorts on the server, so a top-N needs only N rows. Pages are small (default 100, at most 500); when `truncated` is true, `bulk_export` gives the REST API address that returns the whole result as CSV or Parquet. A bad filter returns an error listing the valid keys and values. | Read-only |
| resolve_entity | Turns a place or demographic name or code into the code the data uses (district_code, school_code, county_fips, or demographic) with its label, e.g. 'Atlanta Public Schools' or 'Fulton'. A guessed code otherwise returns an empty page. `kind` is district, school, county, or demographic; 'Fulton' as a county is the county and as a district is the school district, which are different things. Matches loosely, ranks candidates, and flags `ambiguous` when several are close. A real Georgia place is never matched to a different one: a consolidated city returns its county ('Columbus' -> Muscogee, matched_on=consolidated_city), another city asked as a county returns the county it is in, flagged ambiguous, and a one-letter misspelling returns matched_on=typo. A city school system answers to the common forms of its name ('Decatur Public Schools' -> City Schools Of Decatur, matched_on=city_system), and a county's system to its place name ('Cobb Schools' -> the county's district, matched_on=county_system). A school or district is also found by an earlier name ('Brookhaven Innovation Academy' -> BIA Charter School, matched_on=former_name). `place_note`, when present, explains the match and is worth passing on to the user. Census tracts have no kind here: filter by tract_geoid, the 11-digit Census tract ID. | Read-only |
| search_datasets | Search the catalog by meaning and keywords: dataset names, titles, everyday search phrases in English and Spanish, summaries, descriptions, and column names and descriptions. Plain wording works ('kids missing school', 'jobless', 'desempleo'), as do acronyms ('ap', 'el', 'ib'). Returns short dataset summaries, best first, with the fields and columns that matched, a `confidence` of 'high', 'medium' or 'low' (low: nothing in the catalog may fit), plus `dimension_matches` when a lookup table fits (e.g. 'school directory'). main_topic, level and year narrow the results to datasets that have them. The query text is sent to Voyage AI to compute its meaning; the results come only from this catalog. | Read-only |
Change history
- Repository changed (registry)
- Description changed (registry)
- search_datasets: input schema changed (+level, +main_topic, +year)
- search_datasets: description changed (+"Search" +"catalog by meaning and keywords:" +"everyday search phrases in English and Spanish, summaries,")
- search_datasets: annotations changed
- query_dataset: input schema changed (+numeric_filters)
- list_datasets: input schema changed
- list_datasets: description changed (+"'immigration', 'health')" -"'immigration')")
- link_tables: input schema changed
- link_query: description changed (+"immigration," +"health" +"(immigration, county-level Census,")
- get_contract: input schema changed
- distinct_values: tool removed
- describe_dimension: description changed (+"groups may overlap across or" +"categories; use" +"dataset's definitions and non_additive declarations,")
- describe_dataset: input schema changed
- describe_dataset: description changed (+"`partitions` lists columns with no total whose values partition the whole (each value's `share` adds up to 1 across them), so they are read side by side and never pinned by default;" +"scale *" +"SUM(denominator), `scale` the rate's per-N factor (1,000 for a rate per 1,000)")
- aggregate: input schema changed (+numeric_filters)
- aggregate: description changed (+"To list observed values of a filter column, use agg='count', group_by=[<column>] (one value per row, plus its count); describe_dataset lists allowed enum values without a scan." +"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`)," -"SUM(denominator),")
- server instructions changed (+"catalog by meaning and keywords." +"Use agg='count' and group_by=[<column>] to list observed filter values." +"Dataset-specific tools accept globally unique bare topic names or full keys; main_topic is optional. query_dataset and aggregate accept numeric_filters: ANDed comparisons on numeric metrics (gt/gte/lt/lte with value; inclusive between with values=[lower, upper]). Use stored units (0.9 for 90%); NULLs do not match.")
- resolve_entity: description changed (+"A school or district is also found by an earlier name ('Brookhaven Innovation Academy' -> BIA Charter School, matched_on=former_name).")
- describe_dataset: description changed (+"`series_breaks` lists years from which figures are not comparable with earlier years (each with its `reason`; `metrics`, when present, limits it to those columns), so the step into such a year is not a trend.")
- server instructions changed (+"A dataset's `series_breaks` (describe_dataset) name years from which figures are not comparable with earlier years (a revised method or count basis), so the change across such a step is not a trend.")
- search_datasets: title changed
- search_datasets: input schema changed
- search_datasets: description changed (+"catalog: dataset" +"titles," +"and")
- search_datasets: annotations changed
- resolve_entity: title changed
- resolve_entity: input schema changed
- resolve_entity: description changed (+"Turns" +"name or code into the code the data uses (district_code, school_code, county_fips," +"demographic) with")
- resolve_entity: annotations changed
- query_dataset: title changed
- query_dataset: input schema changed
- query_dataset: description changed (+"Rows of" +"dataset, filtered," +"the district, school, county, and demographic names")
- query_dataset: annotations changed
- lookup_school_zone: title changed
- lookup_school_zone: input schema changed
- lookup_school_zone: description changed (+"and" +"(located with" +"Geocoder, an outside service);")
- lookup_school_zone: annotations changed
- list_datasets: title changed
- list_datasets: input schema changed (+detail, +main_topic)
- list_datasets: description changed (+"The catalog:" +"published" +"lookup tables (district, school, county, census tract, and demographic names). By default each dataset")
- list_datasets: annotations changed
- link_tables: title changed
- link_tables: input schema changed (+main_topic)
- link_tables: description changed (+"The" +"join them: datasets to lookup tables to" +"With no arguments,")
- link_tables: annotations changed
- link_query: title changed
- link_query: input schema changed
- link_query: description changed (+"Runs one read-only" +"across datasets, for analysis" +"per-dataset")
- link_query: annotations changed
- get_dimension: title changed
| Source | Listing | First seen | Last seen | Versions |
|---|---|---|---|---|
| Official MCP Registry | org.georgiacivicdata/georgia-civic-data | 2 Oct 2026 | 2 Nov 2026 | 2 |