ZIP-County Crosswalk MCP
ZIP-County Crosswalk MCP - Tra cứu mối quan hệ giữa mã ZIP và quận bằng dữ liệu crosswalk chính thức của HUD, bao gồm bộ lọc theo tỷ lệ dân số chồng lấn cho các mã ZIP nằm trên ranh giới nhiều quận.
Tài liệu
ZIP↔County Crosswalk MCP Server
A Model Context Protocol (MCP) server that lets Claude look up ZIP-to-county and county-to-ZIP relationships, using HUD's official USPS ZIP Code Crosswalk API — including residential-address overlap filtering, since ZIP codes routinely cross county lines.
Architecture
flowchart LR
Claude -->|MCP tool call| Server[zip-county-mcp server]
Server -->|overlap ratios| HUD[HUD USPS Crosswalk API]
Server -->|county names| BQ[(BigQuery:\ngeo_us_boundaries)]
Why this exists
ZIP codes and counties don't line up cleanly — a single ZIP can spread
across several counties, each holding a different share of that ZIP's
residential addresses. Most simple ZIP↔county lookups ignore this and just
return one answer, which is often wrong for the county holding a small
sliver of the ZIP. This server exposes HUD's real overlap-ratio data so a
caller can filter out negligible slivers via a min_overlap_pct threshold,
and get accurate county names via a BigQuery public dataset.
Example: ZIP 77494 (Katy, TX) is actually split across three counties —
Fort Bend (83.4%), Harris (16.5%), and Waller (0.17%). A caller who only
wants counties that meaningfully make up that ZIP can set
min_overlap_pct=5 and get back just Fort Bend and Harris.
How overlap is actually measured
The overlap percentage comes straight from HUD's res_ratio field, and
it's worth being precise about what that field is (verified against
HUD's own API docs,
not assumed):
- It's a ratio of residential addresses, not population/headcount. A single-person address and a five-person address both count as "1" toward the ratio — addresses are a reasonable proxy for population, but not the same measurement.
- The denominator flips with query direction. For
zip_to_county(HUDtype=2),res_ratiois addresses-in-this-county ÷ addresses-in-the-whole-ZIP. Forzips_in_county(HUDtype=7, the reverse lookup), it's addresses-in-this-ZIP ÷ addresses-in-the-whole- county. Same field name, different denominator — which is why a populous county like Harris shows dozens of ZIPs at only 1-3% each, while a single ZIP can show one county at 80%+: the two percentages aren't measuring against the same total.
Status
All three tools are implemented, tested (7 passing tests, pytest), and
verified end-to-end against live HUD + BigQuery data and a real Claude
Desktop connection.
Setup
- Get a free HUD API account and Bearer token at huduser.gov.
- Confirm you have BigQuery access to
bigquery-public-data.geo_us_boundaries(e.g. viagcloud auth application-default login). - Copy
.env.exampleto.envand fill inHUD_API_TOKENand your Google Cloud project. - Create a virtualenv with Python 3.10+ (the
mcppackage requires it — on macOS the systempython3is often older, so checkpython3 --versionfirst) and install dependencies:python3 -m venv .venv .venv/bin/pip install -r requirements.txt - Run it:
.venv/bin/python3 server.py
Connecting to Claude Desktop
Add an entry to your claude_desktop_config.json (macOS:
~/Library/Application Support/Claude/claude_desktop_config.json):
"mcpServers": {
"zip-county-mcp": {
"command": "/absolute/path/to/zip-county-mcp/.venv/bin/python3",
"args": ["/absolute/path/to/zip-county-mcp/server.py"]
}
}
Fully quit and reopen Claude Desktop (MCP servers only load at startup), then try one of the questions below.
Example usage
Once connected, just ask Claude in plain English — it picks the right tool and arguments on its own. A few real examples (verified against live data):
Look up a single ZIP:
"What county is ZIP 77002 in?"
Claude calls zip_to_county("77002") → ZIP 77002 (Houston, TX) is entirely
in Harris County, TX (FIPS 48201) — 100% overlap.
A ZIP that crosses county lines:
"What counties does ZIP 77494 overlap, and by how much?"
Claude calls zip_to_county("77494") → three counties: Fort Bend (83.4%),
Harris (16.5%), Waller (0.17%). Ask a follow-up like "only ones with at
least 5%" and it re-calls with min_overlap_pct=5, dropping Waller's
negligible sliver.
Reverse lookup — ZIPs inside a county:
"What ZIP codes are in Harris County, Texas?" (or give it the FIPS code, 48201, directly)
Claude calls zips_in_county("48201") → a list of every ZIP holding a
meaningful share of Harris County's residential addresses, sorted by
overlap.
A list of ZIP codes at once:
"What counties are ZIP codes 77002, 77494, and 10001 each in?"
Claude calls batch_zip_to_county(["77002", "77494", "10001"]) → one
result per ZIP in a single response, without querying BigQuery once per
ZIP behind the scenes.
Tools (v1 scope)
zip_to_county(zip_code, min_overlap_pct=0)— county/counties for a ZIP, with % overlapzips_in_county(county_fips, min_overlap_pct=0)— ZIP codes in a county, with % overlapbatch_zip_to_county(zip_codes, min_overlap_pct=0)— same as above, multiple ZIPs at once
Out of scope for v1: census tract-level lookups, CBSA/congressional district crosswalks, caching layer, other geography types.
Testing
.venv/bin/pip install -r requirements.txt
.venv/bin/python3 -m pytest tests/ -v
Tests mock HUD's API responses (httpx.MockTransport) and the BigQuery
name lookup, so they run in about a second with no live token or BigQuery
access required.