census-mcp-server

census-mcp-server

A 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.

Category
Visit Server

README

census-mcp-server

Production-grade Model Context Protocol server for the U.S. Census Bureau Data API, backed by a PostgreSQL cache layer for FIPS geography mappings and variable metadata.

Tools

Tool Purpose
get_census_data Fetch ACS 5-Year / Decennial data with multi-variable chunked batching and geographic nesting (e.g. all tracts in a county).
search_census_variables Full-text search over cached variable metadata (labels, concepts, table codes).
resolve_geography Fuzzy-resolve place names → FIPS codes via a lazily hydrated pg_trgm cache.

Live deployment: https://census-mcp-server-production-4b30.up.railway.app/mcp (streamable HTTP, Railway, bearer-token protected — see Deployed on Railway below).

All tools support response_format: 'markdown' | 'json', return structured content alongside text, and are annotated read-only/idempotent.

Supported datasets

id Dataset Vintages
acs5 ACS 5-Year Detailed Tables 2009–2023
acs5_profile ACS 5-Year Data Profiles 2010–2023
acs5_subject ACS 5-Year Subject Tables 2010–2023
dec_pl Decennial Redistricting (P.L. 94-171) 2000, 2010, 2020
dec_dhc Decennial DHC 2020
dec_sf1 Decennial Summary File 1 2000, 2010

Architecture

src/
├── index.ts                  Bootstrap + transports (stdio / streamable HTTP)
├── server.ts                 McpServer factory (composition root)
├── config/env.ts             Zod-validated environment config (fail-fast)
├── constants.ts              Limits, sentinels, state abbreviations
├── errors/census-error.ts    CensusError taxonomy + remediation hints
├── http/census-http-client.ts  fetch wrapper: retries, backoff+jitter, timeouts
├── logging/logger.ts         pino → stderr (stdout reserved for MCP frames)
├── schemas/tool-schemas.ts   Zod input/output schemas for every tool
├── tools/                    Controllers: schema ↔ service ↔ response shaping
├── services/                 CensusApi / CensusData / Geography / VariableSearch / Database
├── repositories/             SQL access: geographies, variables, ingestions
├── db/                       Embedded migrations + advisory-locked runner + CLI
└── utils/                    Bounded concurrency, name normalization, Markdown

Design notes:

  • Resilience — upstream 429/5xx/timeouts retry with exponential backoff + full jitter, honoring Retry-After. Errors map onto a typed CensusError taxonomy (rate limits, invalid FIPS, invalid variables, missing API key, ...) with agent-actionable hints.
  • Chunked batching — variable lists split into API-sized chunks (48/request), fetched with bounded concurrency, and merged on geography keys. Cache hydration writes in 1,000-row batched unnest() upserts. Responses are row-capped (max_rows) and character-capped with explicit truncation flags.
  • Cache layer — geography names (~32k places) and variable catalogs (~28k entries) hydrate lazily on first use, then serve locally: trigram-indexed fuzzy search for names, GIN-indexed full-text search for variables. Migrations are embedded, idempotent, and serialized with a PostgreSQL advisory lock.

Quickstart (local, stdio)

Requires Node 20+ and a reachable PostgreSQL 14+ instance.

npm install                 # also generates package-lock.json (needed for Docker builds)
cp .env.example .env        # set CENSUS_API_KEY and DATABASE_URL
npm run build
npm run db:migrate          # optional; the server also migrates at startup
npm run start:local         # loads .env via node --env-file

(npm start runs without loading .env — it expects the environment to be provided externally, as in Docker or an MCP client config.)

Get a free API key at https://api.census.gov/data/key_signup.html.

Claude Desktop / Claude Code registration

{
  "mcpServers": {
    "census": {
      "command": "node",
      "args": ["/absolute/path/to/census-mcp-server/dist/index.js"],
      "env": {
        "CENSUS_API_KEY": "your-key",
        "DATABASE_URL": "postgres://census:change_me@localhost:5432/census_cache"
      }
    }
  }
}

Docker deployment (streamable HTTP)

npm install          # generate package-lock.json before the first image build
cp .env.example .env # set CENSUS_API_KEY and POSTGRES_PASSWORD
docker compose up --build -d
curl http://localhost:3000/healthz
  • Multi-stage build: TypeScript compiles in a build stage; the runtime stage ships only production node_modules + dist, running as a non-root mcp user.
  • Healthchecks: pg_isready for PostgreSQL; a Node probe against /healthz (which verifies database connectivity) for the server. The server only starts after PostgreSQL is healthy.
  • Network isolation: PostgreSQL lives on an internal-only network with no published ports; data persists in the census_pgdata volume.
  • MCP endpoint: POST http://localhost:3000/mcp (stateless JSON mode).

Scripts

Command Description
npm run build Compile TypeScript to dist/
npm start Run the compiled server (env provided externally)
npm run start:local Run the compiled server, loading .env
npm run dev Watch-mode development server (tsx)
npm run lint ESLint (strict: no any, explicit return types)
npm run typecheck tsc --noEmit
npm run db:migrate Apply pending schema migrations and exit

Example workflow

  1. resolve_geography{ "name": "San Francisco", "level": "county", "state": "CA" }state_fips: "06", geo_code: "075".

  2. search_census_variables{ "query": "median household income" }B19013_001E.

  3. get_census_data

    {
      "variables": ["B19013_001E", "B01001_001E"],
      "geography": {
        "level": "tract",
        "codes": ["*"],
        "within": [
          { "level": "state", "code": "06" },
          { "level": "county", "code": "075" }
        ]
      }
    }
    

Deployed on Railway

The server is deployed at project census-mcp-server in Railway (workspace: Greg Peters's Projects), built directly from this repo's Dockerfile on every push to master:

  • App service census-mcp-server — env vars TRANSPORT=http, PORT=3000, LOG_LEVEL=info, CENSUS_API_KEY, MCP_AUTH_TOKEN, and DATABASE_URL set as a Railway reference variable (${{Postgres.DATABASE_URL}}) pointing at the sibling Postgres service — so the cache survives redeploys and the connection string is never duplicated.
  • Postgres service — managed Railway PostgreSQL; migrations run automatically at container startup (see src/db/migration-runner.ts).
  • Public domain — a generated *.up.railway.app domain targets container port 3000. /mcp requires Authorization: Bearer <MCP_AUTH_TOKEN>; /healthz is open for Railway's health probes.

To redeploy: push to master (Railway auto-builds), or run railway redeploy --service census-mcp-server --yes --from-source to force a fresh pull. To rotate secrets: railway variable set CENSUS_API_KEY=<new-key> --service census-mcp-server (a set triggers a redeploy unless --skip-deploys is passed).

Security notes

  • The API key is only read from the environment, appended per-request, and redacted from all log output.
  • Every tool input is validated by Zod schemas (strict bounds and patterns) before any I/O.
  • Internal errors are logged server-side and never leaked to MCP clients verbatim.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured