census-geocoding-mcp
# πΊοΈ Census Geocoding MCP
[](https://opensource.org/licenses/MIT)
[](https://modelcontextprotocol.io)
[](https://nodejs.org)
[](https://www.typescriptlang.org)
[](https://geocoding.geo.census.gov/geocoder)
An **MCP (Model Context Protocol) server** that gives AI assistants full access to the [U.S. Census Bureau Geocoding Services API](https://geocoding.geo.census.gov/geocoder). Geocode addresses, reverse-geocode coordinates, and retrieve Census geographies β all without an API key.
---
## β¨ Features
- π **No API key required** β the Census Geocoding API is completely free and public
- π **Single-record geocoding** β one-line or parsed addresses (stateside + Puerto Rico)
- ποΈ **Geography lookup** β resolve addresses or coordinates to Census tracts, blocks, counties, congressional districts, and more
- π¦ **Batch processing** β up to **10,000 records per request**, as CSV or structured arrays
- π **Puerto Rico support** β dedicated endpoints with Urbanization and Municipio fields
- ποΈ **Benchmark & vintage control** β target specific MAF/TIGER database versions and Census geography vintages
- π¦ **TypeScript** β fully typed, ESM, Node.js β₯ 18
---
## π§° Tools (12 total)
### π Discovery
| Tool | Description |
|------|-------------|
| `list_benchmarks` | List all available MAF/TIGER locator database versions |
| `list_vintages` | List vintages (Census geography versions) for a given benchmark |
### π Single-Record Geocoding (Locations)
| Tool | Description |
|------|-------------|
| `geocode_oneline_address` | Geocode a full address on one line |
| `geocode_parsed_address` | Geocode a US (stateside) address with separate fields |
| `geocode_pr_address` | Geocode a Puerto Rico address (supports Urbanization & Municipio) |
### πΊοΈ Single-Record Geography Lookup
| Tool | Description |
|------|-------------|
| `find_geographies_oneline` | Geocode a one-line address + return Census geographies |
| `find_geographies_parsed` | Geocode a parsed address + return Census geographies |
| `find_geographies_pr` | Geocode a PR address + return Census geographies |
| `find_geographies_coordinates` | Look up Census geographies for a lon/lat coordinate pair |
### π¦ Batch Processing
| Tool | Description |
|------|-------------|
| `batch_geocode_locations` | Batch geocode up to 10,000 addresses (coordinates only) |
| `batch_geocode_geographies` | Batch geocode up to 10,000 addresses + Census geographies |
| `batch_geolookup_coordinates` | Batch geography lookup for up to 10,000 coordinate pairs |
---
## π Quick Start
### Prerequisites
- [Node.js](https://nodejs.org) β₯ 18.0.0
### Install & Build
```bash
git clone https://github.com/your-username/census-geocoding-mcp.git
cd census-geocoding-mcp
npm install
npm run build
```
### Add to Claude Desktop
Edit your Claude Desktop configuration file:
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
```json
{
"mcpServers": {
"census-geocoding": {
"command": "node",
"args": ["/absolute/path/to/census-geocoding-mcp/dist/index.js"]
}
}
}
```
Restart Claude Desktop β the 12 geocoding tools will be available immediately.
---
## π οΈ Tool Reference
### `list_benchmarks`
Lists all available benchmarks (MAF/TIGER locator database versions).
```
No parameters required.
```
---
### `list_vintages`
Lists all vintages available for a given benchmark.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `benchmark` | string | β
| Benchmark name or ID (e.g. `Public_AR_Current`) |
---
### `geocode_oneline_address`
Geocode a complete address provided as a single string.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `address` | string | β
| Full address, e.g. `4600 Silver Hill Rd, Washington, DC, 20233` |
| `benchmark` | string | β | Default: `Public_AR_Current` |
**Returns:** matched address, interpolated coordinates, Tigerline ID, address range components.
---
### `geocode_parsed_address`
Geocode a US stateside address with fields parsed separately. Requires at minimum `street` + `zip` OR `street` + `city` + `state`.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `street` | string | β
| House number and street name |
| `city` | string | β | City name |
| `state` | string | β | 2-letter state abbreviation |
| `zip` | string | β | 5-digit ZIP code |
| `benchmark` | string | β | Default: `Public_AR_Current` |
---
### `geocode_pr_address`
Geocode a Puerto Rico address with optional Urbanization and Municipio.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `street` | string | β
| House number and street name |
| `urb` | string | β | Urbanization name |
| `city` | string | β | City name |
| `municipio` | string | β | Municipio name |
| `zip` | string | β | ZIP code (begins with 006, 007, or 009) |
| `benchmark` | string | β | Default: `Public_AR_Current` |
---
### `find_geographies_oneline` / `find_geographies_parsed` / `find_geographies_pr`
Same parameters as their `geocode_*` counterparts, plus:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `vintage` | string | β | Default: `Current_Current` |
| `layers` | string | β | Comma-delimited layer names/IDs, or `all` |
**Geography layers returned include:** States, Counties, Census Tracts, Census Blocks, Congressional Districts, County Subdivisions, Incorporated Places, State Legislative Districts, Urban Areas, Combined Statistical Areas, and more.
---
### `find_geographies_coordinates`
Reverse geocode a coordinate pair to Census geographies.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `longitude` | number | β
| Longitude (X) in decimal degrees, range `[-180, 180]`, e.g. `-84.39215` |
| `latitude` | number | β
| Latitude (Y) in decimal degrees, range `[-90, 90]`, e.g. `33.75649` |
| `benchmark` | string | β | Default: `Public_AR_Current` |
| `vintage` | string | β | Default: `Current_Current` |
| `layers` | string | β | Comma-delimited layer names/IDs, or `all` |
---
### `batch_geocode_locations`
Batch geocode up to 10,000 addresses. Accepts either raw CSV or a structured array.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `csv_content` | string | β | Raw CSV: `UniqueID,Street,City,State,ZIP` per row |
| `addresses` | array | β | Array of `{id, street, city?, state?, zip?}` objects |
| `benchmark` | string | β | Default: `Public_AR_Current` |
> `csv_content` takes precedence if both are provided. At least one must be supplied.
**Returns CSV columns:** Record ID, Input Address, Match Indicator, Match Type, Output Address, Coordinates, Tigerline ID, Tigerline Side.
---
### `batch_geocode_geographies`
Like `batch_geocode_locations` but also returns Census geography codes.
Additional parameter:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `vintage` | string | β | Default: `Current_Current` |
**Returns CSV columns:** all location columns + State Code, County Code, Tract Code, Block Code.
---
### `batch_geolookup_coordinates`
Batch geography lookup for coordinate pairs.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `csv_content` | string | β | Raw CSV: `UniqueID,Longitude,Latitude` per row |
| `coordinates` | array | β | Array of `{id, x, y}` objects; `x` (longitude) must be in `[-180, 180]`, `y` (latitude) in `[-90, 90]` |
| `benchmark` | string | β | Default: `Public_AR_Current` |
| `vintage` | string | β | Default: `Current_Current` |
---
## π‘ Example Prompts
Once connected to Claude Desktop, try prompts like:
- *"What Census tract and block is 1600 Pennsylvania Avenue NW, Washington DC in?"*
- *"Geocode these 500 addresses and give me their lat/lon coordinates"* (paste a CSV)
- *"What congressional district is at longitude -87.6298, latitude 41.8781?"*
- *"List all available Census geocoding benchmarks"*
- *"Geocode this Puerto Rico address: 123 Calle Luna, Urb El ParaΓso, San Juan, PR 00926"*
---
## βοΈ Development
```bash
# Watch mode (recompile on save)
npm run dev
# One-time build
npm run build
# Run the server directly
npm start
```
---
## π Notes & Limits
- **Batch limit:** 10,000 records per file β enforced client-side before the request is sent; exceeding it raises a clear error immediately
- **Batch size limit:** CSV content is additionally capped at **5 MB** (UTF-8 bytes) β this catches oversized inputs that could pass the row count check via very long lines
- **No authentication required** β all endpoints are public
- **Single-record responses** are JSON; **batch responses** are CSV text
- **Default benchmark:** `Public_AR_Current` (current MAF/TIGER database)
- **Default vintage:** `Current_Current` (required for all geography endpoints)
- **Request timeout:** all API calls time out after **30 seconds**; the server raises an abort error rather than hanging indefinitely
- **Input length validation:** all string parameters have maximum lengths enforced before any network request is made (`address` 200 chars, `street`/`city`/`urb`/`municipio` 100, `state`/`zip` 10, `benchmark`/`vintage` 50, `layers` 500)
- **Coordinate validation:** `longitude` must be in `[-180, 180]` and `latitude` in `[-90, 90]`; out-of-range values are rejected before the request is sent
- **CSV field escaping:** address fields passed to batch endpoints are escaped per RFC 4180 (embedded quotes doubled, fields containing commas or newlines quoted) to prevent malformed CSV
- The underlying API is provided by the [U.S. Census Bureau](https://www.census.gov/) and subject to their [terms of service](https://www.census.gov/data/developers/about/terms-of-service.html)
---
## π References
- [Census Geocoding Services API Specification](https://geocoding.geo.census.gov/geocoder)
- [Model Context Protocol](https://modelcontextprotocol.io)
- [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/typescript-sdk)
---
## βοΈ License
This project is licensed under the [MIT License](LICENSE).
TDQS
Scored across 12 tools
Tools follow a clear two-axis matrix: geocode (coordinates) vs find_geographies (geographies), crossed with input format (oneline/parsed/pr/coordinates) and batch variants. The oneline/parsed/pr trios return the same content for different address formats, so a careless agent could misselect, but descriptions clearly delineate input requirements and PR-specific handling.
Names are predominantly consistent snake_case verb_noun (geocode_oneline_address, find_geographies_pr, batch_geocode_locations). Minor inconsistencies exist (e.g. 'oneline' token placement and the batch_ prefix convention), but the pattern remains predictable and readable.
12 tools is well-scoped for a geocoding API. Each tool earns its place: catalog lookups, three address-format variants, a coordinate lookup, and three batch operations mirror the underlying Census endpoints without redundancy.
The surface covers the full lifecycle: benchmark/vintage discovery, single and batch geocoding, coordinate reverse geolookup, geography lookups, and all address formats including PR Urbanization/Municipio. No obvious dead ends for geocoding workflows.