guardian-contributions-mcp
This server lets you query, analyze, and monitor Oklahoma Ethics Commission campaign-finance data for candidates and committees, using either a REST API or MCP tools from an AI host like Claude. It automates the workflow of combining Pre-Primary reports with continuing contributions and enforces business rules around deduplication, PDF-sourced summaries, and flagging issues.
Search & Resolve Candidates — Find candidates and map them to their Ethics Commission committee (Org ID), filtering by name, district, office, party, or cycle; surfaces cases where one candidate has multiple committees.
Get Committee Details — Retrieve full committee information by Org ID, including any other committees the same candidate has filed under.
List District Candidates — Pull every candidate/committee running in a given House or Senate district for a whole-race rollup.
Browse Filing History — List all reports a committee has filed (type, period, amended status), ordered newest-first.
Get Pre-Primary Summary — Fetch official Pre-Primary figures (Beginning, Raised, Loans, Expended, Ending) sourced strictly from parsed report PDFs — never re-summed from bulk data.
Get Itemized Contributions — Retrieve itemized receipts for a committee or district, with optional filters for date range, receipt type, and minimum amount.
Get Continuing-Window Total — Compute the deduplicated continuing-period total (Raised vs. Loans split), counting each receipt exactly once across multiple reports.
Get Combined Headline Figures — Layer continuing-window contributions on top of Pre-Primary base figures to produce headline numbers for one committee or an entire district.
Get Computed Flags/Alerts — Surface automated alerts such as large self-dealing loans (loan ≥ raised), sub-$1,000 continuing receipts, amended reports, multiple committees, missing Pre-Primary filings, and identity mismatches.
Get Reporting Calendar — Retrieve the cycle's computed reporting calendar (primary date, Pre-Primary period, continuing window), calculated dynamically.
Check Data Freshness — See when the data was last updated and whether it actually changed since the prior pull.
Flexible Query Tool — A catch-all selector combining a who/where axis (candidate, committee, district, office, party, cycle) with a what axis (summary, combined, contributions, flags, etc.) in a single call, with optional filters like date windows and minimum amounts.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@guardian-contributions-mcpcombined Pre-Primary + Continuing for HD-42 Cynthia Roe"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Guardian Contributions — MCP + API
⚠️ Archived — this is the original open-source prototype (
v0.1.0, MIT). Active development has moved to a maintained commercial edition with a hosted API + MCP, monitored data freshness (SLA), automated backups, and broader coverage. This repository is frozen atv0.1.0and will not receive updates. For a demo or licensing, contact cooperstillick@icloud.com.
A reusable service for Oklahoma Ethics Commission "Guardian" campaign-finance data. It pulls and normalizes the data, then answers narrow questions through a REST API and an MCP server (so Claude — or any MCP host — can use it as tools).
It automates a workflow that's otherwise done by hand: for a roster of candidates, combine each one's Pre-Primary report (Beginning, Raised, Loans, Expended, Ending) with all their Continuing contributions layered on top, and flag things like self-dealing loans. The business rules come from a manual workflow distilled into 14 hard rules — each is enforced as a service invariant (table below) and backed by a test.
Status: v0.1.0. 51 tests pass; the combined figures reproduce a known-good
deliverable to the penny (HD-42 Cynthia Roe: $29,863.66 + $42,750.00 − $4,278.24 = $68,335.42), and an opt-in live test verifies the whole pipeline
against guardian.ok.gov end-to-end.
Get started (about 2 minutes)
Prerequisites: Python 3.11+ and uv
(curl -LsSf https://astral.sh/uv/install.sh | sh). No API key needed for local use.
git clone https://github.com/cstillick/guardian-contributions-mcp.git
cd guardian-contributions-mcp
uv sync # create the env + install the package
# 1) run the tests (offline; proves the rules against known-good fixtures)
uv run --extra dev pytest -q
# 2) load real data from Guardian
uv run guardian-ingest --no-reports # fast: bulk contributions only (~5s)
# or the full load (also fetches Pre-Primary report PDFs for the roster,
# ~1–2 min because it walks Guardian's report pages one at a time):
# uv run guardian-ingest
# 3) start the server — web dashboard + REST API + interactive docs
uv run guardian-api # dashboard: http://localhost:8000 · API docs: /docsThen ask it things:
# the cycle's reporting calendar (computed, not hardcoded)
curl localhost:8000/v1/calendar
# one candidate's combined Pre-Primary + Continuing figures
curl "localhost:8000/v1/committees/11932/combined"
# -> {"beginning":"29863.66","raised":"42750.00","ending":"68335.42", ...}
# every candidate in a district
curl "localhost:8000/v1/districts/HD-42/combined"
# computed alerts (large loans, sub-$1,000 receipts, ...)
curl "localhost:8000/v1/flags?district=HD-42"
guardian-ingestneeds outbound access toguardian.ok.gov. Reads come entirely from the local database — Guardian is never touched on the request path.
Related MCP server: USAspending MCP Server
Web dashboard
guardian-api also serves a browsable "Public Ledger" UI at / — for people
who just want to open a link and read the numbers, no API knowledge needed:
/— the roster as a sortable, filterable ledger (combined Beginning / Raised / Loan / Expended / Ending, flags, freshness dateline) plus money-over-time and "who's raised the most" charts./c/{org_id}— a candidate dossier: the balance as an equation, the per-reporting-period balance chain (every Quarterly / Pre-Primary / Pre-General report via the layering model) with an itemized vs unitemized split, itemized contributions, filings, flags, and animated charts (money over time, funding sources, top donors)./flags— every computed alert across the roster, grouped by severity./search— find any committee on file (candidates, PACs, parties) by name.
Editorial broadsheet design; server-rendered (Jinja2 + bespoke CSS), no build step.
Use it from Claude (MCP)
Point any MCP host at the server. For Claude Desktop / Claude Code, add to your MCP config:
{
"mcpServers": {
"guardian-contributions": {
"command": "uv",
"args": ["run", "guardian-mcp"],
"cwd": "/absolute/path/to/guardian-contributions-mcp"
}
}
}Then ask in plain language — "combined Pre-Primary + Continuing for HD-42 Cynthia
Roe," "which candidates in HD-99 took loans larger than they raised?" The model
picks from 13 focused tools plus a flexible query tool.
What you're selecting between (the two axes)
A request = who/where × what:
Axis A — who / where | Axis B — what |
candidate · committee (Org ID) · district · office · party · cycle | summary · combined · continuing_total · contributions · loans · report · filing_history · flags |
How it works
guardian.ok.gov ──▶ ingestion (bulk CSV + report-PDF postback chain) ──▶ store
│
REST API ◀── service layer (the 14 rules) ◀─┘
MCP tools ◀──┘Two halves hinged on the database: a write path (the only code that touches Guardian — scrapes and normalizes on a schedule) and a read path (API + MCP, serving fast from the store). Ingestion downloads one bulk extract for all committees, then walks Guardian's ASP.NET report pages to fetch each Pre-Primary PDF, parses the Schedule Summary, and stores it. Reads layer the stored Pre-Primary figures on top of deduped continuing-window receipts.
API surface (/v1, JSON, optional X-API-Key)
Endpoint | Returns |
| resolve candidates → committees |
| committee, filings, Pre-Primary figures |
| deduped continuing total · the headline number |
| whole-race rollups |
| itemized receipts |
| one report · alerts · windows · freshness |
| flexible Axis A × Axis B selector |
| trigger ingestion (background) |
Full interactive docs at /docs when the API is running.
Deployment
One always-on host (recommended) — Postgres + API + nightly scheduler, no code changes:
cd deploy
GUARDIAN_API_KEYS=staff-key-1,staff-key-2 docker compose up -d --build
docker compose run --rm api guardian-ingest # initial loadSet GUARDIAN_DATABASE_URL to a Postgres DSN for production (SQLite is the local
default — same schema). Pass X-API-Key on every request once keys are set.
Serverless split (Vercel) — the read API + web UI deploy fine to Vercel, but
the ingestion is a long, stateful scrape that doesn't fit serverless. The repo
ships a ready split: Vercel (UI + /v1) + a GitHub Actions cron (the
scraper) + managed Postgres. Files: vercel.json, api/index.py,
requirements.txt, .github/workflows/ingest.yml. Step-by-step in DEPLOY.md.
The 14 Hard Rules → enforced invariants
# | Rule | Where it's enforced |
1 | Windows computed, never hardcoded |
|
2 | Continuing reports are incremental → dedup receipts |
|
3 | Pre-Primary can't be rebuilt from bulk |
|
4 | Report PDFs are retrievable |
|
5 | Match by Org ID, confirm district |
|
6 | One person, multiple committees |
|
7 | Confirm year + committee | ingester rejects a report whose year ≠ cycle |
8 | Use the amended version | postback takes the last |
9 | Sub-$1,000 not on continuing reports |
|
10 | Data is a moving target |
|
11 | Version everything | runs append-only; builder archives, never overwrites |
12 | Full verification before delivery |
|
13 | Freshness gate |
|
14 | Drop blank-Org-ID rows before dedup |
|
Project layout
src/guardian_contrib/
ingest/ bulk CSV + report-PDF postback chain + run orchestration
compute/ continuing-sum · combined-layering · flags (the rules)
service.py the one place rules are applied on read (API + MCP call this)
api/ FastAPI app mcp_server/ MCP server (stdio)
builder/ Book(Sheet1) xlsx scheduler.py nightly/election refresh
tests/ 51 tests + fixtures (incl. opt-in live e2e: GUARDIAN_LIVE=1)
deploy/ Dockerfile + docker-compose (Postgres + API + scheduler)Troubleshooting
guardian-ingesthangs or errors: confirm outbound access toguardian.ok.gov. Tryuv run guardian-ingest --no-reportsfirst (bulk only).API returns empty/
nulldata: you haven't ingested yet — runguardian-ingest, then check/v1/statusfor the extract as-of date.Imports fail in a checkout under a path with spaces: prefix commands with
PYTHONPATH=src(the editable install can be flaky there); a normal path needs nothing.
License
MIT — see LICENSE.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/cstillick/guardian-contributions-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server