Access FEC campaign finance data. Query data about candidates, money trails, and election filings.
Access FEC campaign finance data through MCP. Query data about candidates, money trails, and election filings. STDIO & Streamable HTTP.
Public Hosted Server: https://openfec.caseyjhand.com/mcp
US federal campaign finance data from the FEC's OpenFEC API. Search candidates, committees, and filings, trace contributions (Schedule A), disbursements (Schedule B), and independent and coordinated party expenditures (Schedules E/F), and look up election races, legal documents, and filing deadlines. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above.
| Tool | Description |
|---|---|
openfec_search_candidates | Find federal candidates by name, state, office, party, or cycle; fetch one by FEC ID with financial totals. |
openfec_search_committees | Find political committees by name, type, candidate affiliation, or state; fetch one by FEC ID. |
openfec_get_committee_totals | Pre-aggregated committee financial totals — one committee's per-cycle summary, or a ranked search across committees of one entity type. |
openfec_search_contributions | Search itemized individual contributions (Schedule A) or aggregate breakdowns by size, state, employer, or occupation. |
openfec_search_disbursements | Search itemized committee spending (Schedule B) or aggregate breakdowns by purpose or recipient. |
openfec_search_expenditures | Search independent expenditures (Schedule E) supporting or opposing federal candidates, itemized or aggregated by candidate. |
openfec_search_coordinated_expenditures | Search coordinated party expenditures (Schedule F) made on behalf of a candidate. |
openfec_search_filings | Search FEC filings and reports by committee, candidate, form type, or date range. |
openfec_lookup_elections | Look up federal election races and candidate financial summaries. |
openfec_search_legal | Search FEC legal documents: advisory opinions, enforcement cases, administrative fines, and statutes. |
openfec_get_legal_document | Fetch one legal document in full, including the arrays search trims away. |
openfec_lookup_calendar | Look up FEC calendar events, filing deadlines, and election dates. |
| Resource | Description |
|---|---|
openfec://candidate/{candidate_id} | Federal candidate profile with current financial totals and principal committees. |
openfec://committee/{committee_id} | Political committee profile with type, designation, and financial summary. |
openfec://election/{cycle}/{office} | Presidential election race with candidate financial totals. |
openfec://election/{cycle}/{office}/{state} | Senate or at-large House election race with candidate financial totals. |
openfec://election/{cycle}/{office}/{state}/{district} | House district election race with candidate financial totals. |
| Prompt | Description |
|---|---|
openfec_money_trail | Framework for tracing the flow of money around a candidate or race. |
openfec_campaign_analysis | Structured analysis of a candidate's financial position. |
openfec_search_candidates toolinclude_totals merges receipts/disbursements/cash-on-hand per cycle — defaults to true on an ID lookup, false on search; capped at 5 pages of 100 rows, with uncovered IDs listed in missing_totals for re-querycandidate_not_found; inputs_not_applicable_to_id_lookup when search-only filters accompany a direct ID lookupopenfec_search_committees toolC + eight digits)committee_not_found; inputs_not_applicable_to_id_lookup when search-only filters accompany a direct ID lookupopenfec_get_committee_totals toolmode: "single" (default): one committee's totals, one row per two-year cycle filed. mode: "by_entity_type": ranks or screens every committee of one entity type (presidential, pac, party, pac-party, house-senate, ie-only)by_entity_type-only filters: committee_state, committee_type, committee_designation, organization_type, and receipts/disbursements min/max boundscommittee_id_required_for_single_mode, entity_type_required_for_group_mode, inputs_not_applicable_to_mode, committee_totals_not_foundopenfec_search_contributions toolitemized (Schedule A records, requires committee_id, keyset cursor pagination), by_size/by_state (committee_id or candidate_id), by_employer/by_occupation (committee_id only)-contribution_receipt_date; a cursor is valid only for an otherwise-identical callitemized_requires_committee_id, aggregate_requires_committee_id, itemized_only_filters_in_aggregate_mode, inputs_not_applicable_to_modeopenfec_search_disbursements toolitemized (Schedule B records, keyset cursor pagination), by_purpose, by_recipient, by_recipient_id — committee_id required for every mode-disbursement_dateitemized_only_filters_in_aggregate_mode; inputs_not_applicable_to_mode for an explicit page in itemized modeopenfec_search_expenditures toolitemized (Schedule E, keyset cursor pagination, defaults to the current cycle and most_recent: true) and by_candidate (aggregated per targeted candidate — needs candidate_id or a full race scope: office alone for President, plus state for Senate, plus district for House)by_candidate_requires_scope, itemized_only_filters_in_aggregate_mode, inputs_not_applicable_to_modeopenfec_search_coordinated_expenditures toolopenfec_search_filings toolmost_recent defaults to true, filtering out superseded amendmentsopenfec_lookup_elections toolmode: "search" (default): candidates in a race with financial totals. mode: "summary": aggregate race financial totalselection_full defaults to true (expands to the full election period: 4yr president, 6yr senate, 2yr house); rejected on ZIP-scoped searchescycle_must_be_even, missing_state_for_office, missing_district_for_house, summary_does_not_support_zip, inputs_not_applicable_to_modeopenfec_search_legal tooldate_kind the type records (advisory opinions: issue/request/document date; murs/adrs: open/close/document date; admin_fines: rtb/fd date; statutes have none)documents array replaced by a count and category summary, commission_votes cut to a date and a 200-character action — retrieve the untrimmed record with openfec_get_legal_documentfrom_hit/hits_returned), up to 200 results per pageopenfec_get_legal_document tooldocuments array and complete commission_votes that openfec_search_legal trimsdoc_type is the plural of a search result's document_type (mur → murs); no is that result's no fieldlegal_document_not_foundopenfec_lookup_calendar toolevents (calendar_category_id, one of 18 category codes), filing_deadlines (report_type, report_year), election_dates (state, office, election_year)min_date/max_date apply in every mode; other filters are mode-specific and rejected outside their modeinputs_not_applicable_to_modeopenfec://candidate/{candidate_id} resourceP)candidate_id comes from openfec_search_candidatescandidate_not_foundopenfec://committee/{committee_id} resourcecommittee_id comes from openfec_search_committeescommittee_not_foundopenfec://election/{cycle}/{office} resourceoffice literal P); candidates returned with financial totals for the full election periodopenfec_lookup_elections mode search to page furtheropenfec://election/{cycle}/{office}/{state} resourceoffice S or H)openfec://election/{cycle}/{office}/{state}/{district} resourceoffice H)openfec_money_trail promptcandidate_name or candidate_id (one required), optional cycle (defaults to the current cycle)openfec_campaign_analysis promptcandidate_name or candidate_id (one required), optional cycle (defaults to the current cycle)Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
OpenFEC-specific:
openfec_money_trail, openfec_campaign_analysis) chain multiple tools into a financial investigationAgent-friendly output:
search_criteria echo of the effective (post-default) filters, so an implicit cycle default is never hiddennotice enrichment suggesting how to broaden the query, instead of a bare empty arrayreason plus actionable recovery text) instead of generic validation failuresA public instance is available at https://openfec.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"openfec-mcp-server": {
"type": "streamable-http",
"url": "https://openfec.caseyjhand.com/mcp"
}
}
}
Add the following to your MCP client configuration file.
{
"mcpServers": {
"openfec-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/openfec-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"FEC_API_KEY": "your-api-key"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"openfec-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/openfec-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"FEC_API_KEY": "your-api-key"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"openfec-mcp-server": {
"type": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "-e", "FEC_API_KEY=your-api-key", "ghcr.io/cyanheads/openfec-mcp-server:latest"]
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 FEC_API_KEY=your-key bun run start:http
# Server listens at http://localhost:3010/mcp
DEMO_KEY)git clone https://github.com/cyanheads/openfec-mcp-server.git
cd openfec-mcp-server
bun install
cp .env.example .env
# edit .env and set FEC_API_KEY (optional)
| Variable | Description | Default |
|---|---|---|
FEC_API_KEY | OpenFEC API key. Optional — defaults to DEMO_KEY (30 req/hr). Provide your own key (free at api.data.gov/signup) for 1,000 req/hr. | DEMO_KEY |
FEC_BASE_URL | OpenFEC API base URL. | https://api.open.fec.gov/v1 |
FEC_MAX_RETRIES | Max retry attempts for failed API requests. | 3 |
FEC_REQUEST_TIMEOUT | Request timeout in milliseconds. | 30000 |
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | Port for HTTP server. | 3010 |
MCP_HTTP_HOST | Hostname for HTTP server. | localhost |
MCP_SESSION_MODE | HTTP session mode: auto, stateful, or stateless. createApp() declares stateless in src/; set this only to override it. | stateless |
MCP_AUTH_MODE | Auth mode: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (RFC 5424). | info |
LOGS_DIR | Directory for log files (Node.js only). | <project-root>/logs |
STORAGE_PROVIDER_TYPE | Storage backend. | in-memory |
OTEL_ENABLED | Enable OpenTelemetry instrumentation (spans, metrics, completion logs). | false |
See .env.example for the full list of optional overrides.
Build and run:
bun run rebuild
bun run start:stdio # or start:http
Run checks and tests:
bun run devcheck # Lint, format, typecheck, security audit
bun run test # Vitest test suite
bun run lint:mcp # Validate MCP definitions against spec
docker build -t openfec-mcp-server .
docker run --rm -e FEC_API_KEY=your-key -p 3010:3010 openfec-mcp-server
The Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/openfec-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point — registers tools/resources/prompts and inits services. |
src/config/ | Server-specific environment variable parsing and validation with Zod. |
src/mcp-server/tools/definitions/ | Tool definitions (*.tool.ts). |
src/mcp-server/resources/definitions/ | Resource definitions (*.resource.ts). |
src/mcp-server/prompts/definitions/ | Prompt definitions (*.prompt.ts). |
src/services/openfec/ | OpenFEC API client and domain types. |
tests/ | Unit and integration tests. |
scripts/ | Build, clean, devcheck, tree, and lint scripts. |
docs/ | Design docs and OpenAPI spec. |
See CLAUDE.md for development guidelines and architectural rules. The short version:
try/catch in tool logicctx.log for domain-specific logging, ctx.state for storageindex.ts barrel filesIssues are welcome. Run checks before submitting:
bun run devcheck
bun run test
Apache-2.0 — see LICENSE for details.
Source-derived launch command. Check the maintainer’s required arguments and credentials before running:
npx -y @cyanheads/openfec-mcp-serverMerge this template into ~/Library/Application Support/Claude/claude_desktop_config.json. Keep existing servers. Add any arguments, credentials, and permissions required by the maintainer; this template has not been install-tested.
{
"mcpServers": {
"io-github-cyanheads-openfec-mcp-server": {
"command": "npx",
"args": [
"-y",
"@cyanheads/openfec-mcp-server"
]
}
}
}Restart Claude Desktop completely for changes to take effect. Confirm the server appears connected in the client’s tool list, then try a read-only example from its documentation.
Claude Desktop setup referenceio.github.cyanheads/openfec-mcp-server works with any MCP-compatible client. Copy the config snippet from the Configuration section above and add it to the file shown for your client, then restart the application.
~/Library/Application Support/Claude/claude_desktop_config.jsonRestart Claude Desktop completely for changes to take effect.~/.cursor/mcp.jsonRestart Cursor for changes to take effect..vscode/mcp.jsonReload VS Code window for changes to take effect.~/.codeium/windsurf/mcp_config.jsonRestart Windsurf for changes to take effect..mcp.jsonSave at the project root, then start Claude Code in that project and review the MCP server approval prompt. Keep real credentials out of shared files.