---
summary: "Added County Business Patterns, Economic Census, and Nonemployer Statistics with predicate filtering (#9), and fixed census_search_variables/census_get_variable fabricating margin-of-error codes on non-ACS datasets (#17)"
breaking: false
security: false
---

# 0.1.14 — 2026-07-31

## Added

- **`cbp`, `ecnbasic`, `nonemp` datasets** — County Business Patterns (2012–2023), Economic Census (2012, 2017, 2022), and Nonemployer Statistics (1997–2007, 2012–2023) registered in `KNOWN_DATASETS` and `DATASET_LATEST_YEARS`, and in the `census_list_datasets` catalog. `cbp` excludes vintages before 2012 and `nonemp` excludes 2008–2011 — those years reject the `NAME` column every query here sends, so they're left out of `available_years` rather than advertised and then failing. ([#9](https://github.com/cyanheads/census-mcp-server/issues/9))
- **`predicates` input** on `census_query_data` and `census_compare_geographies` — a `Record<string, string>` filter map (e.g. `{"NAICS2017": "5112"}`) keyed by variable code rather than dataset-aware named parameters, since predicate codes are vintage-specific (`cbp` 2023 takes `NAICS2017`, `cbp` 2012 takes `NAICS2012`). Validated against the dataset's own cached `variables.json` via the new `VariableCacheService.checkPredicates`. King County, WA establishments in `cbp` 2023: 577 with `{"NAICS2017": "5112"}`, 70,376 without.
- **`predicate_not_supported` error** on both data tools — an unrecognized predicate key is rejected client-side before the call, since the Census API's own `400` for the same case names only the request URL, never which key was wrong.
- **Unset-predicate notice** — when a dataset declares a required predicate (`NAICS2017`, `LFO`, `EMPSZES`, etc.) the query left unset, `ctx.enrich.notice()` names each dimension and states that the Census API substituted its own default, since an unfiltered `cbp` count silently returns the all-industries total rather than erroring. `GEOCOMP` is excluded from the report — every registered dataset declares it and its default is always the whole geography.

## Changed

- **Predicate-key validation reads `variables.json` unguarded** on the query path in `census_query_data`/`census_compare_geographies`, ahead of the data call. The prior use of `variables.json` on that path (best-effort label enrichment) was wrapped in `try/catch`; this one is not, so an upstream `variables.json` outage now fails the query instead of returning unlabeled data. Intentional — an unrecognized predicate key needs to be caught before the call is spent, and the Census API's rejection doesn't say which key was wrong.

## Fixed

- **`census_search_variables` / `census_get_variable`**: margin-of-error inference fabricated `M`-suffix codes for datasets outside the ACS family. `VariableCacheService` now gates both the E↔M sibling inference and the synthetic `M`-entry synthesis on `isAcsDataset()` (an `acs/` prefix). `pep/charv` `UNIVERSM`/`AGM` and `cbp` `STATM` now correctly return `variable_not_found` instead of a fabricated "Margin of Error" entry; ACS is unchanged. `CensusApiService.parseResponse` carries the same gate when pairing a requested `E` value with a requested `M` value into `.moe`. ([#17](https://github.com/cyanheads/census-mcp-server/issues/17))
- **`CensusApiService.parseResponse`**: predicate values the API echoed back as their own response columns were being folded into the composed GEOID — a predicated county query would have produced `511200100153033` instead of `53033`. Echoed predicate keys are now excluded from the geography-hierarchy columns.
- **`ecnbasic` `no_data` recovery**: named FIPS codes as the likely fix even though `ecnbasic` publishes nothing below the national level until an industry is named. The hint now names the unset predicates first when the dataset has any, since a missing `NAICS2022` — not a bad FIPS code — is the more likely cause.

Tests: `tests/services/variable-cache/variable-cache-service.test.ts` is new — `isAcsDataset` classification, MOE inference on and off ACS, `checkPredicates` against `variables.json`, and the `describeUnsetPredicates`/`describeEmptyPredicatedResult` wording. `census-api-service.test.ts` adds predicate URL encoding, echoed-column GEOID exclusion, and ACS-gated MOE pairing. `census-query-data.tool.test.ts` and `census-compare-geographies.tool.test.ts` cover predicate forwarding, the unset-dimension notice (including notice ordering ahead of truncation advice), `predicate_not_supported`, and the two `no_data` recovery paths. `census-list-datasets.tool.test.ts` covers the three new catalog entries, their trimmed year ranges, and that the catalog stays in step with `KNOWN_DATASETS`.
