census-mcp-server
This server has a remotely hosted endpoint. Open its connector listing for connection details, authentication requirements, and setup instructions:
Public Hosted Server: https://census.caseyjhand.com/mcp
Overview
US Census Bureau demographic, economic, and housing data. Find datasets and variables, resolve place names or addresses to FIPS codes, and query or rank estimates across any set of geographies.
Tools
Tool | Description |
| Browse available Census Bureau datasets (ACS5 and ACS1 with their profile, subject, and comparison tables, ACS Supplemental Estimates and Selected Population Profiles, Population Estimates, Decennial, County Business Patterns, Economic Census, Nonemployer Statistics) with vintage years and dataset codes. |
| List the geography levels supported by a dataset and year, with parent requirements and example FIPS values. |
| Keyword search across variable labels and concept groups, or lookup by variable or table code. On ACS, returns estimate and margin-of-error codes together. |
| Fetch full metadata for one or more variable codes — label, concept, predicate type, universe, MOE sibling — including the annotation and flag columns the data tools accept. |
| List the codes a filter dimension accepts ( |
| Convert place names (e.g., "King County, WA"), ZIP codes, or street addresses to Census FIPS identifiers via TIGERweb and Census Geocoder. |
| Query a Census dataset for variables at one geography, a comma-separated list of them, or every geography at a level. Returns estimates with MOE, Census sentinel values and withheld business values resolved to their published meanings, and predicate filtering for the business datasets. |
| Rank and compare variables across multiple geographies — all counties in a state, all states nationally, or a named set. Sorted table output, with the same predicate filtering. |
Related MCP server: Census MCP Server
Capability reference
census_list_datasets tool
Returns dataset codes, names, descriptions, and available vintage years, with an optional keyword filter. Covers ACS5 and ACS1 (data profiles, subject tables, comparison profiles, and
acs/acs1/spp),acs/acsse, Population Estimates, the 2020 Decennial files (Redistricting (P.L. 94-171),dec/dhc,dec/dp,dec/sdhc,dec/ddhca,dec/ddhcb),cbp,ecnbasic, andnonempEach description names the filter predicates the dataset requires and the geography levels it publishes
Dataset codes (e.g.,
acs/acs5) are what the other tools take. Case is ignored and a two-part code works by its last part alone (acs5,pl); three-part codes such asacs/acs5/profilemust be given in fullavailable_yearsis exhaustive: any other year fails withyear_not_available, naming the years that work
census_list_geographies tool
Returns one row per geography level and parent hierarchy:
geography_level, whether a parent is required,required_parent_levels, and an example FIPS value.totalLevelscounts each level oncegeography_levelvalues are the exact inputs tocensus_query_dataandcensus_compare_geographies;yeardefaults to the latest vintageFails with
dataset_not_foundoryear_not_available(naming the years served)
census_search_variables tool
Whole-word search across label and concept: every query word must match, otherwise the closest matches come back with a notice. A variable or table code in any case returns that variable, or the whole table in code order, first (
B19013returnsB19013_001EthenB19013_001M)A code the dataset does not publish gets a notice naming the sibling dataset that holds it (
S1701inacs/acs5points toacs/acs5/subject) orcensus_get_variablefor an attribute column such asB19013_001EAOn ACS datasets, estimate (E suffix) and margin-of-error (M suffix) codes come back together; comparison profiles and the other families publish no margins of error. Also finds predicate codes by keyword (
naics) or code (NAICS2017incbp)limitis an integer from 1 to 100 (default 20), rejected rather than clamped when out of range.offsetpages the complete match ordering;totalMatchescounts matches before paging,truncatedmeans another page exists, andnextOffsetnames it. variables.json is cached per dataset+year (default TTL 24h)
census_get_variable tool
Takes one or more variable codes (case-insensitive) and returns label, concept, predicate type, and the table's universe, in the order given. If
groups.jsoncan't be fetched, variables come back without universe and a notice says to retryResolves annotation and flag columns such as
B19013_001EAandEMP_F, withattribute_ofnaming the column each belongs to andattribute_typeits kind (ANNOTATION,FLAG,MARGIN_OF_ERROR). On ACS datasets it also returnsestimate_code/moe_codesibling referencesConfirms predicate dimension codes (
NAICS2017,SEX) exist in a dataset;census_list_predicate_valueslists their values.datasetdefaults toacs/acs5andyearto the latest vintagevariable_not_foundwhen a code isn't defined, naming the sibling dataset that publishes it when one is found (DP03_0062Einacs/acs5points toacs/acs5/profile)
census_list_predicate_values tool
Lists the codes a filter dimension accepts, read from the dataset dictionary when it publishes a list and enumerated live otherwise.
NAICS*andPOPGROUPhave long lists (thousands of codes; narrow withquery);EMPSZES,LFO,RCPSZES,TAXSTAT, andTYPOPare live-onlyDictionary lists are checked against the rows the dataset actually publishes and unpublished codes are dropped;
sourcesays whether the check ran and the notice gives the number withheld. A dictionary list does not validate publication at a supplied geography levelLive enumeration takes
geography_level(defaultus) and echoes that scope. Codes vary by level; only levels whose dataset metadata permits an unparented wildcard are acceptedquerymatches code and label; results are sorted by code beforeoffset/limitpaging (limit1 to 500, default 50).totalCountcounts all matches;truncatedmeans another page exists, withnextOffsetonly then. Onecnbasic,within_naicsscopesTAXSTATandTYPOPto one industryThe live route and the dictionary check read the data endpoint, so they need
CENSUS_API_KEY: without a working key a live-only dimension fails withmissing_api_key, while a dictionary list still answers, unchecked, with a notice naming the key
census_resolve_geography tool
Named places (e.g., "King County, WA") resolve via TIGERweb; street addresses resolve to tract level via Census Geocoder, with
block_group_fipsandplace_fips. A 5-digit ZIP (or ZIP+4) resolves to its ZIP Code Tabulation Area (zip code tabulation area)Auto-detects
geography_typefor state, county, place, tract, and ZIP. Metropolitan/micropolitan statistical areas, combined statistical areas, consolidated cities, and economic places need an explicitgeography_type;economic placereturns the 8-digitecnbasiccode (Seattle03363000)The place level includes census-designated places, which answer a name only when no incorporated place or county matches exactly; use the full name ("Arlington CDP, VA") or
geography_type: "place"to reach one. Optionalcounty_fipsscopes county and tract resolution (county_scope_unsupportedfor any other level or an address)Matching ignores case, accepts a state abbreviation or full name, and tolerates Saint/St. and accent differences. New York City boroughs resolve to their counties ("Brooklyn, NY" → Kings County
047) with anoticeA name matching several geographies returns
ambiguous_namewith every candidate's FIPS code and state. Results carrystate_fips(→parent_fips) andfips_summary(→geography_fips) for the next tool; statistical areas and ZCTAs omitstate_fips
census_query_data tool
Requires FIPS codes (use
census_resolve_geographyfor place names).geography_fips: "*"returns every geography at the level within the parent; each row carriesgeography_fipsand the nationally uniquegeography_geoid. Wildcards return up tolimitrows (default 50, max 500) in GEOID order, withoffsetfor paging andtotalCountfor all matches.truncatedis true only when another page exists;nextOffsetnames that pageA comma-separated list (
"06,53", or"033,061"withparent_fips: "53") returns one row per listed code at the same level, in GEOID order and paged the same way; codes take the level's width, no"*"member, and the parents a single code needs. The notice names each listed code no row came back forUp to 49 variable codes per call, fewer on datasets that add label or record columns (
too_many_variablesstates the maximum). Unknown codes fail withvariable_not_found; level and parent problems fail withparent_requiredorparent_not_accepted. Optionaltract_fips(6 digits, with a concretecounty_fips) scopes a block-group or decennial block query to one tractOptional
predicatesmap filters the business,pep, anddecdatasets andacs/acs1/spp(e.g.,{"NAICS2017": "5112"}). Unset dimensions take a Census default, echoed per row inapplied_filters;"*"returns one row per category, labelled inrecord.pep/charvreturns several rows per geography, so pin one (e.g.,{"MONTH": "7"})ACS sentinel values resolve to their published meanings, and a median in an open-ended interval is flagged
open_ended. Oncbp,ecnbasic, andnonemp, withheld values are reported as suppressed with the flag's meaning. A nullestimatemeans suppressed, a text cell (returned undervalue), or emptyOn
dec/ddhcaanddec/ddhcb, a geography'sPOPGROUPgroup sits in only one table of a family; ano_datahint or notice names the sibling tables. RequiresCENSUS_API_KEYMissing-geography guidance names applicable ACS publication thresholds as possible causes alongside code checks, and pairs broader-coverage datasets with variable rediscovery
census_compare_geographies tool
Ranks all geographies at a level, or a named
geographieslist of GEOIDs/bare level codes;within/within_countyscope to a state/county, omit for a national comparisonRanks on one variable:
sort_by(default the first code; must be a requested code, elsesort_by_not_requested),sort_dir(defaultdesc), andlimit(1 to 500, default 50). Equal numeric values share competition ranks (1, 2, 2, 4) and are ordered by GEOID; a notice identifies a page boundary inside a tie. A count ranks by size, not rate, so rank a published percentage for a rate (S1701_C03_001Einacs/acs5/subject,DP04_0047PEinacs/acs5/profile)offsetcounts rows in the sorted matched set; ranks are assigned before paging.totalCountcounts that set,truncatedmeans another page exists, andnextOffsetappears only then. A nonemptygeographiesfilter also returnsscope_rankagainst all fetched geographies andscopeCountfor that denominatorTakes the same
predicates, variable limit, validation, andapplied_filtersascensus_query_data; multi-record datasets (pep/charv) or a"*"predicate fail withambiguous_rowsunlesspredicatespins one. Suppressed values sort last with the same reasons, and text values can't be ranked (the notice says so). RequiresCENSUS_API_KEY
Features
Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
Census-specific:
In-process variable cache with configurable TTL — variables.json fetched once per dataset+year, searched client-side
Three-API backend: Census Data API for data queries, TIGERweb for named-place resolution, Census Geocoder for address-to-tract
Automatic retry with backoff on all external API calls
Keyed tool calls share a 50-second upstream budget across metadata, data, retries, and optional probes; data requests retain a 40-second ceiling within the remaining budget
FIPS formatting helpers — zero-padded state, county, and tract codes ready to pass between tools
Agent-friendly output:
Workflow-oriented tool surface —
fips_summaryandstate_fipsreturn values are ready to pass asgeography_fipsandparent_fipsto the next toolSuppression codes decoded — Census negative sentinel values (e.g.,
-666666666) and business-dataset withholding flags (e.g.,D) surfaced as their published meanings instead of raw numbers or false zerosRecovery hints on errors — ambiguous geography names include candidate lists; missing API key errors include registration URL
Getting started
Connect to the hosted instance, no install:
claude mcp add --transport http census-mcp-server https://census.caseyjhand.com/mcpOr run it locally:
claude mcp add census-mcp-server -e CENSUS_API_KEY=your-key -- npx -y @cyanheads/census-mcp-serverFor other clients, add this to the MCP config file:
{
"mcpServers": {
"census-mcp-server": {
"command": "npx",
"args": ["-y", "@cyanheads/census-mcp-server"],
"env": { "CENSUS_API_KEY": "your-key" }
}
}
}Register a free key at api.census.gov/data/key_signup.html. Data queries (census_query_data, census_compare_geographies) require it, as does census_list_predicate_values for a dimension it enumerates live; variable search and geography resolution work without one. For Docker or a source build, see Running the server.
Configuration
Variable | Description | Default |
| Required for data queries ( | — |
| Default vintage year when no year is specified. |
|
| Hours to cache variables.json per dataset+year in memory. |
|
| Transport: |
|
| HTTP session mode: |
|
| Port for HTTP server. |
|
| Auth mode: |
|
| Log level ( |
|
| Log each failed tool call's arguments and result, redacted by key name and capped at |
|
| Enable OpenTelemetry instrumentation. |
|
See .env.example for the full list of optional overrides.
Running the server
Local development
Requires Bun v1.4.0 or higher (or Node.js v24+).
Clone and install:
git clone https://github.com/cyanheads/census-mcp-server.git cd census-mcp-server && bun install cp .env.example .env # set CENSUS_API_KEYBuild and run:
# One-time build bun run rebuild # Run the built server bun run start:stdio # or bun run start:httpRun checks and tests:
bun run devcheck # Lint, format, typecheck, security audit bun run test # Vitest test suite bun run lint:mcp # Validate MCP definitions against spec
Docker
docker run --rm -e CENSUS_API_KEY=your-key -p 3010:3010 ghcr.io/cyanheads/census-mcp-server:latestThe image defaults to HTTP transport, stateless session mode, and logs to /var/log/census-mcp-server. To run it over stdio from an MCP client, use "command": "docker" with "args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "-e", "CENSUS_API_KEY=your-key", "ghcr.io/cyanheads/census-mcp-server:latest"]. To build locally, docker build -t census-mcp-server .; OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
Project structure
Path | Purpose |
|
|
| Census-specific env var parsing and validation with Zod. |
| Tool definitions ( |
| Census Data API client — data queries, suppression code mapping, retry logic. |
| Geography resolution — TIGERweb named-place lookup and Census Geocoder address-to-tract. |
| In-process variables.json cache with TTL and keyword search. |
| Vitest tests mirroring |
Development guide
See CLAUDE.md for development guidelines and architectural rules. The short version:
Handlers throw, framework catches — no
try/catchin tool logicUse
ctx.logfor request-scoped logging,ctx.statefor tenant-scoped storageRegister new tools via the barrel in
src/mcp-server/tools/definitions/index.tsWrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
Contributing
Issues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run testLicense
Apache-2.0 — see LICENSE for details.
This server cannot be deployed
Maintenance
Related MCP Connectors
Census MCP — U.S. Census Bureau housing-relevant APIs.
FCC public geo/census APIs (geo.fcc.gov) MCP.
MCP server for US nursing facility search and ownership lookup (NursingHomeDatabase).
Hosted MCP servers for US federal data: 19 servers, 147 tools, one endpoint.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables access to U.S. Census Bureau data including demographics, population, income, and housing statistics. Users can query specific variables, search datasets, and retrieve geographic FIPS codes across various surveys like the American Community Survey and Decennial Census.1-
- AlicenseAqualityDmaintenanceNode.js MCP server enabling AI agents to access comprehensive U.S. Census Bureau demographic and economic data, including ACS, decennial census, and business patterns.1770 npmMIT
- FlicenseNot gradedqualityCmaintenanceA production-grade MCP server for querying U.S. Census Bureau data (ACS 5-Year and Decennial) with tools for geographic fuzzy matching, variable search, and batched data retrieval, backed by a PostgreSQL cache for performance.-
- AlicenseAqualityDmaintenanceAn MCP server that exposes the IPUMS API as LLM tools for browsing metadata, creating and downloading extracts, and generating reproducible R/Python code.23MIT