Ask your AI assistant about commuting patterns, journey-to-work data, and transportation statistics β powered by the Census CTPP API.
An MCP (Model Context Protocol) server for the Census Transportation Planning Products (CTPP) API. Plug commuting and journey-to-work data directly into any MCP-compatible AI client. A generate-code tool exports any query as a self-contained R or Python script, so analyses are easy to share and reproduce outside of the AI client.
The CTPP dataset is produced by AASHTO from US Census ACS data. It captures detailed commuting patterns at state, county, place, and tract levels:
- π Residence tables (B1xx) β where workers live
- π’ Workplace tables (B2xx) β where workers work
- π Flow/O-D tables (B3xx) β origin-destination commute pairs
| Tool | Description |
|---|---|
ποΈ list-datasets |
List all available CTPP dataset vintages (years) |
π list-table-groups |
Browse/search tables for a given year |
π¬ get-table-variables |
Get variable names (estimates + MOE) for a specific table |
π get-group-geographies |
Get available geography levels for a table |
π fetch-ctpp-data |
Fetch statistical data with geography and variable filters |
π resolve-geography-fips |
Convert place names β FIPS codes via fuzzy matching (no DB required) |
π» generate-code |
Export a fetch-ctpp-data query as a self-contained R or Python script; optionally annotates variables with labels (annotate=true) and generates a pagination loop to fetch all records (fetchAll=true) |
| Year | ACS Coverage |
|---|---|
| 2000 | 2000 Census |
| 2010 | 2006β2010 ACS |
| 2016 | 2012β2016 ACS |
| 2021 | 2017β2021 ACS |
ctpp-mcp/
βββ mcp-server/ # π¦ TypeScript MCP server (stdio transport)
β βββ src/
β βββ index.ts # Server entry point
β βββ apiClient.ts # ctppFetch() with X-API-Key header auth
β βββ geo.ts # In-memory geography search (trigram similarity)
β βββ data/
β β βββ geographies.ts # Bundled states + counties (3,287 records)
β βββ tools/ # One file per tool + BaseTool base class
βββ scripts/
β βββ mcp-connect.sh # π MCP client entry point (auto-builds if needed)
β βββ generate-geo-data.ts # Refreshes geographies.ts from TIGERweb
βββ docker-compose.yml # π³ HTTP transport only (no database)
The server runs over stdio β your MCP client launches it as a subprocess. Geography lookups are resolved in-memory from bundled data; no database is required. All CTPP data queries go directly to the CTPP REST API.
- Node.js 18+
- CTPP API key β request one at ctppdata.transportation.org
cd mcp-server && npm install && npm run buildOutput lands in mcp-server/dist/.
Copy .env.example to .env and fill in your key:
cp .env.example .env
# then edit .env and set CTPP_API_KEY=your_api_key_hereAdd this to your MCP client config (e.g. claude_desktop_config.json, Cursor settings, or equivalent):
Unix/Mac β use mcp-connect.sh, which auto-loads .env and auto-builds dist/ if needed:
{
"mcpServers": {
"ctpp-mcp": {
"command": "bash",
"args": ["/absolute/path/to/ctpp-mcp/scripts/mcp-connect.sh"]
}
}
}Windows / without .env β pass the key directly in the config:
{
"mcpServers": {
"ctpp-mcp": {
"command": "node",
"args": ["/absolute/path/to/ctpp-mcp/mcp-server/dist/index.js"],
"env": {
"CTPP_API_KEY": "your_api_key_here"
}
}
}
}Find commute mode share for King County, WA in 2021:
- π
list-table-groupsyear=2021, keyword="means of transportation"β finds tableB202105 - π¬
get-table-variablesgroupId="B202105", year=2021β discovers variables likeB202105_e1 - π
resolve-geography-fipsname="King County, Washington"βforGeo="county:033", inGeo="state:53" - π
fetch-ctpp-datayear=2021, get="B202105_e1,B202105_m1", forGeo="county:033", inGeo="state:53" - π»
generate-codelanguage="r", year=2021, get="B202105_e1,B202105_m1", forGeo="county:033", inGeo="state:53"β runnablehttr2script
For flow (O-D) tables, add destination params:
fetch-ctpp-data: year=2021, get="B302105_e1", forGeo="county:033", inGeo="state:53",
dForGeo="county:*", dInGeo="state:53"
All commands from mcp-server/:
npm test # π§ͺ Run Vitest test suite
npm run watch # π Rebuild on file changes (tsc --watch)
npm run lint # π ESLint (typescript-eslint v8)
npm run format # β¨ Prettier (auto-fix)
npm run format:check # β
Prettier (CI check)
npm run inspect # π MCP Inspector for interactive tool testing
npm run generate-geo-data # πΊοΈ Refresh bundled geography data from TIGERweb| Variable | Required | Description |
|---|---|---|
CTPP_API_KEY |
Yes (API tools) | API key for ctppdata.transportation.org |
CTPP_API_URL |
No | Override API base URL (e.g., dev/beta endpoint) |
MCP_TRANSPORT |
No | Set to http to enable HTTP transport (default: stdio) |
PORT |
No | HTTP port when MCP_TRANSPORT=http (default: 3000) |
MCP_AUTH_TOKEN |
No* | Bearer token for HTTP transport. Strongly recommended when using MCP_TRANSPORT=http β without it the endpoint is unauthenticated and anyone with network access can use your CTPP API key. |
DEBUG_LOGS |
No | Set to true to enable console.log (suppressed by default β stdout carries MCP protocol) |
Security note: When running the HTTP transport, always set
MCP_AUTH_TOKENand keep the port off the public internet (or behind a reverse proxy with TLS). The stdio transport (default) is inherently local and does not require a token.
cd mcp-server
# If you have a .env in the project root:
source ../.env && npm run inspect
# Or pass the key inline:
CTPP_API_KEY=your_key npm run inspectWindows (PowerShell):
$env:CTPP_API_KEY = "your_key"; npm run inspect
Opens a browser UI to call each tool and inspect inputs/outputs.
resolve-geography-fips uses a bundled dataset of all US states and ~3,200 counties, searched in-memory using trigram similarity (same algorithm as PostgreSQL's pg_trgm). No database is required.
To refresh the bundled data from Census TIGERweb (e.g. after county boundary changes):
cd mcp-server && npm run generate-geo-data && npm run build- Remove PostgreSQL / Docker dependency:
resolve-geography-fipsnow uses a bundled dataset searched in-memory with a JS trigram similarity implementation (replicatespg_trgm) - Remove
mcp-db/package,docker-compose.ymldbservice, andpgdependency frommcp-server - Add
scripts/generate-geo-data.tsto refresh the bundled geography data from TIGERweb - Setup is now just
npm install && npm run buildβ no database required
- Add
generate-codetool β exports anyfetch-ctpp-dataquery as a self-contained R (httr2+dplyr) or Python (requests+pandas) scriptannotate=true: fetches variable labels from the CTPP API and embeds them as comments in the generated scriptfetchAll=true: generates a pagination loop (page size 1000) that fetches all records instead of a single page
- Update install instructions to be platform-agnostic (Windows PowerShell notes,
nodeinstead ofbashin MCP client config)
- Switch license from CC0 to MIT
- Add HTTP transport support (
MCP_TRANSPORT=http) with Bearer token auth, 1 MB body cap, and 100-session limit - Harden input validation across all tools
- Bump
@types/nodeto^22to match Dockerfile runtime
This project is released under the MIT License.