---
summary: "Added census_list_predicate_values to discover filter-dimension codes (#23), plus fixes for a raw 400 on an unaccepted parent (#21), silent no_data on an unpadded FIPS code (#25), and dec/ddhca/ecnbasic returning one category as if it were a total (#24)"
breaking: false
security: false
---

# 0.3.0 — 2026-07-31

## Added

- **`census_list_predicate_values`** — new tool listing the codes a Census filter dimension accepts, so a `predicates` map can be written without guessing. Two routes, picked by where the answer lives: dimensions with a published `values.item` map (`NAICS*`, `POPGROUP`, and `ecnbasic`'s `TAXSTAT`/`TYPOP` on the 2017 and 2012 vintages) are read from the cached dataset dictionary; everything else is enumerated live by setting `<CODE>=*` and requesting its `<CODE>_LABEL` attribute, which turns the wildcard into a group-by. Takes `predicate`, `dataset`, `year`, an optional `query` keyword matched against code and label, `within_naics` to scope a per-industry dimension (`ecnbasic`'s `TAXSTAT`/`TYPOP` return only the all-establishments row until a sector is named), and `limit`. Returns `{ values: [{ code, label }], predicate, predicate_label, dataset, year }` sorted by code, with an enrichment block carrying `totalCount`, `truncated`, `source` (`"dataset_dictionary"` or `"live_query"`), and a `notice` for truncation, a keyword match miss, or an industry-scoped result. Errors: `dataset_not_found`, `predicate_not_supported`, `not_a_filter_dimension`, `no_values`, `upstream_error`. Live enumerations are cached per dataset, year, dimension, and NAICS scope for the discovery TTL. ([#23](https://github.com/cyanheads/census-mcp-server/issues/23))

## Changed

- **`parent_fips`/`county_fips`** on `census_query_data` and **`within`/`within_county`** on `census_compare_geographies` are now zero-padded to the width the Census API matches on — 2 digits for state, 3 for county — bringing them in line with what `census_resolve_geography` already returns. Each also carries a JSON Schema `pattern` (`^(\*|\d{1,2})$` / `^(\*|\d{1,3})$`, unioned with the empty string so a blank from a form client still reads as omitted), rejecting non-numeric input, over-width codes, and stray whitespace at the schema boundary instead of silently trimming or mismatching. `*` is unaffected by the padding — it passes through as given, since it's a scope rather than a code: `in=state:53 county:*` is the only way to reach every block group in a state. `geography_fips` is unchanged; its width follows `geography_level`, so it can't be padded generically, and its description and the `no_data` recovery hint now say the API matches it literally at that width. ([#25](https://github.com/cyanheads/census-mcp-server/issues/25))
- **`applied_filters`** — every row from `census_query_data` and `census_compare_geographies` now echoes the label of any filter dimension the query left unset, keyed by predicate code (e.g. `{"POPGROUP": "European alone"}`). The Census API's substituted default is not always an all-categories total: `dec/ddhca` defaults `POPGROUP` to a single population group, and `ecnbasic` defaults its NAICS dimension to one sector that varies by vintage (Construction in 2022, Mining, quarrying, and oil and gas extraction in 2017 and 2012) — the label is what tells them apart from `cbp`'s all-industries default. The unset-dimension notice now quotes the same label per dimension instead of only naming it. Two dimensions publish no label attribute to echo — `pep/charv`'s `YEAR` and `nonemp`'s NAICS codes before 2012 — and the notice says the applied value isn't visible for those rather than leaving them looking undefaulted. ([#24](https://github.com/cyanheads/census-mcp-server/issues/24))
- **`census_list_datasets`** — `dec/ddhca`'s description now states every value is scoped by `POPGROUP`, that no all-groups code exists (dictionary code `001` returns nothing), and points to `dec/pl` `P1_001N` for a population total; `ecnbasic`'s now names the per-vintage NAICS default instead of implying an unset dimension returns nothing; `cbp`, `nonemp`, and `pep/charv` descriptions also now point to `census_list_predicate_values` for their dimensions' codes.

## Fixed

- **`parent_not_accepted`** — `census_query_data` and `census_compare_geographies` now validate a supplied `parent_fips`/`county_fips` (or `within`/`within_county`) against the geography level's own accepted-parent list before querying, instead of building an `in=` clause the Census API rejects with an unreasoned raw `400`. The check reuses the level's cached `geography.json` entry; the recovery hint names which input to drop and what the level does accept. Levels with no state parent at all — `zip code tabulation area`, `urban area`, `metropolitan statistical area/micropolitan statistical area`, `combined statistical area` — are the common trigger. ([#21](https://github.com/cyanheads/census-mcp-server/issues/21))

327 tests pass across 11 files; `bun run devcheck` clean.
