civic-mcp
by ky1emayers
README.md
# civic-mcp
A minimal [MCP](https://modelcontextprotocol.io) server that exposes U.S. election
dates. It has a single tool, `get_election_dates`, backed by
`election_dates.json` loaded into memory at startup.
## Requirements
- Python 3.10+
- `pip install "mcp[cli]"`
> **Only have Python 3.9 (macOS's default system Python)?** The `mcp` SDK
> requires 3.10+ and won't install on 3.9. Install a newer version alongside
> your system Python without touching it — e.g. via Homebrew:
>
> ```bash
> brew install python@3.12
> /opt/homebrew/bin/python3.12 -m venv .venv
> source .venv/bin/activate
> pip install -e ".[dev]"
> ```
>
> Then use `.venv/bin/python`, `.venv/bin/pytest`, etc. for this project.
## Run
```bash
python server.py
```
Or, for local development with the MCP Inspector:
```bash
mcp dev server.py
```
## Tool: `get_election_dates`
**Input**
| field | type | required | description |
|-------|--------|----------|-----------------------------------------------------------|
| state | string | yes | USPS two-letter state code (e.g. `"CA"`) or full state name (e.g. `"California"`), or `"DC"` / `"District of Columbia"`. Case-insensitive. |
**Output**
```json
{
"state": "CA",
"state_name": "California",
"primary": "2026-06-02",
"days_until_primary": -47,
"general_election": "2026-11-03",
"days_until_general": 107,
"cycle": "2026",
"source": "Federal Voting Assistance Program (FVAP.gov)",
"source_as_of": "2026-05"
}
```
`days_until_primary` / `days_until_general` are computed from the current
date at request time and may be negative if the date has already passed.
`days_until_primary` is `null` if the state has no primary currently
scheduled.
Covers the 50 states + DC only; U.S. territories and local/municipal races are
out of scope (see `election_dates.json` metadata).
**Input handling**
Unrecognized input raises `UnknownStateError` (a `ValueError` subclass) with a
message listing valid codes — never a silent `null` or an unhandled crash.
Input is trimmed, internal whitespace is collapsed, and stray punctuation
(e.g. `"D.C."`) is stripped before matching. A conservative fuzzy match
(cutoff 0.82) against full state names catches common misspellings (e.g.
`"Calfornia"` → `CA`); anything below that confidence fails clearly instead
of guessing.
## Tests
```bash
pip install -e ".[dev]"
pytest
```
`tests/test_server.py` covers: a valid two-letter code, a valid full name
(case-insensitive), invalid input, DC (by code, full name, and alias), a
state with no primary currently scheduled, and a snapshot-style check that
`general_election` is identical across every state. No state in
`election_dates.json` currently lacks a primary date, so that case is
exercised via `monkeypatch` on a synthetic entry rather than by inserting a
fabricated date into the real FVAP-sourced dataset.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessSyncing