Skip to main content
Glama
who_reps-mcp

who_reps-mcp

by cstillick

who_reps-mcp

Address → your elected officials, as an MCP server. A free, open replacement for the Google Civic Information Representatives API, which was shut down on April 30, 2025 and left a generation of civic apps broken.

Give it a U.S. street address and it returns the people who represent it — U.S. Senators, U.S. House member, Governor, and state legislators — by stitching together free public data: address → districts (Census) → officials (open congressional + state-legislator data).

Why this exists

When Google killed representativeInfoByAddress, the official guidance was: use our Divisions API for an OCD id, then go buy officeholder data from BallotReady, Cicero, or Ballotpedia. This rebuilds the free path so an agent can just answer "who represents this address?"

Related MCP server: oravan

Quick start

The federal tier needs no API keys — the Census geocoder and the unitedstates/congress-legislators dataset are both free and key-less.

uv sync

# As an MCP server (stdio):
uv run whoreps-mcp

# Or try the data path from a terminal (no keys needed):
uv run whoreps-mcp lookup "1600 Pennsylvania Ave NW, Washington, DC 20500"
uv run whoreps-mcp lookup "2300 N Lincoln Blvd, Oklahoma City, OK 73105"
#  4 officials for 2300 N LINCOLN BLVD, ...: U.S. Senator James Lankford (R);
#  U.S. Senator Markwayne Mullin (R); U.S. Representative Stephanie I. Bice (R, 5);
#  Governor Kevin Stitt (R). State legislators omitted — set OPENSTATES_API_KEY ...

To add the state-legislator tier, get a free OpenStates key, cp .env.example .env, set OPENSTATES_API_KEY, and the same lookups will include state senators and representatives.

Use it as an MCP server

{
  "mcpServers": {
    "whoreps": {
      "command": "uv",
      "args": ["run", "whoreps-mcp"],
      "cwd": "/path/to/whoreps-mcp"
    }
  }
}

Tools

Tool

What it does

lookup_officials(address)

The headline tool. Address in, full slate out (federal + state where available), each official with party, contact, term, source, and as-of date, plus OCD divisions and coverage notes.

list_districts(address)

Just the districts/divisions for an address — congressional + state-legislative districts and OCD-IDs (the piece Google's Divisions API gave, free and self-hosted).

lookup_by_district(state, chamber, district)

Skip geocoding: senate/house (federal) or upper/lower (state).

get_official_details(official_id)

Enriched detail for one official — committees + full contact where available.

Each tool returns structured JSON plus a concise text summary.

Graceful degradation

This is a civic tool, so correctness and honesty matter:

  • Federal always works, with zero keys. Missing tiers never fail the whole request — you get what's available plus coverage_notes explaining any gap.

  • DC and territories return the non-voting delegate (no senators), and note that DC has a Mayor rather than a Governor and no state legislature.

  • Bad/PO-box/new-construction addresses that don't geocode return an empty result with a note, not an error.

  • Freshness is visible. Every official carries its source and as_of date. Governors are a vendored, dated snapshot (see docs/governors.md); everything else is fetched live and cached.

How it works

address ─▶ Census geocoder ─▶ {lat/lon, congressional district, state-leg districts, OCD divisions}
                                     │
              ┌──────────────────────┼───────────────────────┐
              ▼                      ▼                         ▼
     congress-legislators     OpenStates people.geo      governors.json
     (U.S. Senate + House)    (state legislators)        (vendored)
              └──────────────────────┼───────────────────────┘
                                     ▼
                     merge + normalize -> OfficialsResponse  (SQLite-cached)

Sources live behind sources/ so the whole flow is tested against recorded fixtures — CI is fully offline.

Development

uv run pytest        # offline suite (recorded fixtures)
uv run ruff check .  # lint

If uv run whoreps-mcp ever reports No module named 'whoreps_mcp' (a known editable-install quirk on some setups, e.g. paths with spaces), run with PYTHONPATH=src uv run whoreps-mcp ....

See SPEC.md and BUILD_PLAN.md for the design.

License

MIT.

Available Tools

5 tools
get_official_detailsA

Enriched detail for one official (committees + full contact where available), by the id returned from the other tools.

Inputs: official_id (required).

list_districtsC

Just the districts/divisions for an address (the piece Google's Divisions API still gives) — congressional + state-legislative districts and OCD-IDs.

Inputs: address (required).

lookup_by_districtB

Officials for a chamber + district, skipping geocoding. chamber is senate|house (federal) or upper|lower (state legislature).

Inputs: state (required), chamber (required), district.

lookup_officialsA

Who represents this address? Returns U.S. Senators + House member (and, where available, Governor + state legislators), each with party, contact, term, source, and as-of date, plus the OCD divisions and coverage notes.

Inputs: address (required).

pingA

Health check. Returns 'pong' if the server is alive.

Inputs: no named parameters. Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.6/5.0

    Scored across 5 tools

    Disambiguation5/5

    Each tool has a clearly distinct purpose: lookup_officials and lookup_by_district differ in input (address vs. chamber+district), list_districts provides district IDs, get_official_details gives detailed info on a single official, and ping is a health check. No ambiguity.

    Naming Consistency4/5

    Tool names follow a pattern of verb_noun (list_districts, get_official_details, lookup_by_district, lookup_officials) with one exception (ping). The verbs 'list', 'get', and 'lookup' are thematically coherent, though using 'lookup' for two tools could cause slight confusion.

    Tool Count4/5

    Five tools is a reasonable count for a focused domain like legislative representation lookup. Each tool serves a distinct function, and the set feels neither sparse nor bloated.

    Completeness4/5

    The tool set covers core operations: address-based lookup, district-based lookup, district listing, and official details. Missing features like coordinate-based lookup or batch queries are minor gaps that don't significantly hinder typical use cases.

    Maintenance

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      D
      maintenance
      Provides tools to search and retrieve US federal and state legislative data, including bills, votes, campaign contributions, and legislator information, with provenance tracking.
      8
      1
      MIT
    • A
      license
      A
      quality
      B
      maintenance
      Remote MCP server for nonpartisan U.S. Congress data: plain-language bill decodes (bilingual EN/ES), representative lookup by ZIP with district-office phones, and what's-moving urgency ranking. Read-only, keyless.
      5
      1
      AGPL 3.0
    • F
      license
      Not graded
      quality
      D
      maintenance
      Enables users to look up every layer of local government for any Cook County address, including representatives, finances, and agendas, with provenance and certainty levels for data.
      -
    • A
      license
      Not graded
      quality
      C
      maintenance
      Enables cited site feasibility and pre-development project workflows for Canada and the US, returning lot, zoning, permitted uses, and material envelope details with provenance for a given street address.
      Apache 2.0