io.github.cyanheads/us-lobbying-mcp-server
Search US lobbying disclosures and foreign-agent registrations via MCP.
Que pouvez-vous faire avec io.github.cyanheads/us-lobbying-mcp-server ?
- Shared source pacing: anonymous LDA access uses 15 requests/minute per originating IP; an optional registered token uses 120/minute. FARA requests start at least 4.1 seconds apart; separate processes must coordinate shared upstream budgets.
- Analytical selection uses the latest posting within each registrant/client/year/quarter. Equal-latest candidates are marked ambiguous and excluded from sums; this is an analytical rule, not a verified legal amendment lineage.
- Income and expenses remain separate, missing amounts remain unknown, and expense methods retain separate ledgers. Disclosure records establish neither wrongdoing nor policy outcomes or influence.
- FARA search uses complete official daily XML snapshots cached for 24 hours; chosen registration details use the live API. LDA pagination is live and does not promise an immutable historical snapshot.
- Explicit completion: LDA
page_sizedefaults to 25 andmax_pagesto one for discovery, five for analytics; larger positive integers clamp to 25 and five respectively. Follownext_cursoruntilcoverage.complete, then continue final windows until `outp... - Complete record retrieval: responses target 24,000 UTF-8 bytes across both surfaces. Oversized parents come back as
record_handles, readable through the same tool with JSON Pointerrecord_pathandrecord_offset/record_limit(default 25 entries or ... - Delivery controls: source/reference responses expose
delivery_limitswith{requested,effective}pairs for controls clamped on this call; an empty map means none. SQL returns the same metadata when a ceiling lowers its request. Exact cursor replay retain... - Source counts:
coverage.upstream_count, when known for every partition, sums each partition's latest observed envelope count. It can include duplicate source rows and differs fromunique_records; live pagination is not a frozen snapshot.
Installation
Ajoutez ceci à la configuration MCP de votre client (Claude Desktop : claude_desktop_config.json ; Cursor : .cursor/mcp.json ; VS Code et les autres utilisent la même forme « mcpServers »).
claude mcp add --transport http us-lobbying-mcp-server 'https://us-lobbying.caseyjhand.com/mcp'
{
"mcpServers": {
"us-lobbying-mcp-server": {
"type": "http",
"url": "https://us-lobbying.caseyjhand.com/mcp"
}
}
}
@cyanheads/us-lobbying-mcp-serverclaude mcp add us-lobbying-mcp-server -e 'USLOBBYING_LDA_API_KEY=<your uslobbying_lda_api_key>' -e 'USLOBBYING_DATAFRAME_DROP_ENABLED=false' -e 'CANVAS_PROVIDER_TYPE=none' -e 'MCP_LOG_LEVEL=info' -- npx -y @cyanheads/us-lobbying-mcp-server@0.1.2
{
"mcpServers": {
"us-lobbying-mcp-server": {
"command": "npx",
"args": [
"-y",
"@cyanheads/us-lobbying-mcp-server@0.1.2"
],
"env": {
"USLOBBYING_LDA_API_KEY": "<your uslobbying_lda_api_key>",
"USLOBBYING_DATAFRAME_DROP_ENABLED": "false",
"CANVAS_PROVIDER_TYPE": "none",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Variables d'environnement
USLOBBYING_LDA_API_KEYsecret Optional registered LDA API token; anonymous access works without it.USLOBBYING_DATAFRAME_DROP_ENABLEDEnable the local dataframe table deletion tool.CANVAS_PROVIDER_TYPEOptional SQL canvas provider: none or duckdb.MCP_LOG_LEVELSets the minimum log level for output (e.g., 'debug', 'info', 'warn').
@cyanheads/us-lobbying-mcp-serverclaude mcp add us-lobbying-mcp-server -e 'USLOBBYING_LDA_API_KEY=<your uslobbying_lda_api_key>' -e 'USLOBBYING_DATAFRAME_DROP_ENABLED=false' -e 'CANVAS_PROVIDER_TYPE=none' -e 'MCP_TRANSPORT_TYPE=<MCP_TRANSPORT_TYPE>' -e 'MCP_HTTP_HOST=127.0.0.1' -e 'MCP_HTTP_PORT=3010' -e 'MCP_HTTP_ENDPOINT_PATH=/mcp' -e 'MCP_AUTH_MODE=none' -e 'MCP_LOG_LEVEL=info' -- npx -y @cyanheads/us-lobbying-mcp-server@0.1.2
{
"mcpServers": {
"us-lobbying-mcp-server": {
"command": "npx",
"args": [
"-y",
"@cyanheads/us-lobbying-mcp-server@0.1.2"
],
"env": {
"USLOBBYING_LDA_API_KEY": "<your uslobbying_lda_api_key>",
"USLOBBYING_DATAFRAME_DROP_ENABLED": "false",
"CANVAS_PROVIDER_TYPE": "none",
"MCP_TRANSPORT_TYPE": "<MCP_TRANSPORT_TYPE>",
"MCP_HTTP_HOST": "127.0.0.1",
"MCP_HTTP_PORT": "3010",
"MCP_HTTP_ENDPOINT_PATH": "/mcp",
"MCP_AUTH_MODE": "none",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Variables d'environnement
USLOBBYING_LDA_API_KEYsecret Optional registered LDA API token; anonymous access works without it.USLOBBYING_DATAFRAME_DROP_ENABLEDEnable the local dataframe table deletion tool.CANVAS_PROVIDER_TYPEOptional SQL canvas provider: none or duckdb.MCP_TRANSPORT_TYPESelects the HTTP transport.MCP_HTTP_HOSTThe hostname for the HTTP server.MCP_HTTP_PORTThe port to run the HTTP server on.MCP_HTTP_ENDPOINT_PATHThe endpoint path for the MCP server.MCP_AUTH_MODEAuthentication mode to use: 'none', 'jwt', or 'oauth'.MCP_LOG_LEVELSets the minimum log level for output (e.g., 'debug', 'info', 'warn').
Documentation
Tirée du README du projet sur GitHub, actualisée chaque semaine. Les liens ouvrent GitHub.
Sommaire
@cyanheads/us-lobbying-mcp-server
Search US lobbying disclosures and foreign-agent registrations via MCP. STDIO or Streamable HTTP.
9 Tools (+1 opt-in)
Public Hosted Server: https://us-lobbying.caseyjhand.com/mcp
Overview
US federal lobbying disclosures from the Senate's LDA API and foreign-agent registrations from the Department of Justice's FARA records. Search filings, resolve client relationships, inspect lobbyist and contribution disclosures, and analyze reported amounts with optional local SQL. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above; no API key required.
Tools
| Tool | Description |
|---|---|
uslobbying_search_filings | Search registrations and activity reports, retaining original and amended filings |
uslobbying_get_client_profile | Resolve client relationships, then analyze explicitly selected IDs and years |
uslobbying_get_issue_spending | Analyze reported amounts on quarterly filings mentioning an issue |
uslobbying_search_lobbyists | Find lobbyists and retrieve filing-specific activity and covered-position evidence |
uslobbying_get_contributions | Retrieve LD-203 reports with complete contribution lists, PAC disclosures, and certifications |
uslobbying_search_foreign_agents | Search FARA snapshots or retrieve a registration's chosen live detail collection |
uslobbying_list_reference | Look up official codes, identifiers, methodology, and source limitations |
uslobbying_dataframe_query | Materialize a read-only SQL result and page its complete rows |
uslobbying_dataframe_describe | Inspect staged table schemas, counts, lifecycle, and provenance |
uslobbying_dataframe_drop | Remove a staged table; opt-in |
Capability reference
uslobbying_search_filings tool
- Supply at least one upstream filter:
filing_uuid,filing_year(1999–current UTC year), client/registrant/lobbyist ID or name,filing_type,filing_period,specific_issues,posted_after/posted_before,amount_min/amount_max,client_state,client_country,foreign_entity_name, orforeign_entity_country. Dates are realYYYY-MM-DDcalendar dates; amounts are exact decimal USD strings with at most two fractional digits and use native filing-filter semantics. Text is trimmed, blanks omitted, and state/country codes uppercased. Filters combine conjunctively; optionalissue_codeapplies locally and cannot narrow upstream requests. - Pass a
filing_uuidfrom lobbyist evidence or analytical selections to retrieve the complete filing, including nested source fields and document links. - Returns complete
filingswithamendment_policy: "all_versions", separate nullable USD decimal-stringincome/expenses, document links, and nested disclosures. Shared acquisition and record-window rules appear under Features.
uslobbying_get_client_profile tool
mode: "resolve"(default) requiresclient_name;mode: "profile"requires explicitclient_idsandyears(1999–current UTC year). Pass each candidate'sid, not its registrant-assignedclient_id. IDs identify relationships with registrants; candidates are never automatically merged into a corporate identity.- Profile returns
status: "collecting"until acquisition completes, then typedannual_ledgers,selections,firms,issue_codes,targeted_entities,selected_filings,activities, andraw_filingsacross output windows.row_set_totals/row_set_offsetsdescribe each list's delivery. - Optional nonempty, unique
row_setsselects which of those lists to deliver inline. Omission delivers every set;raw_filingsalways means every acquired version, including selected versions. Selection never limits acquisition, analysis, complete-set totals or SQL staging. Omitted sets remain available by restarting the same scope with another selection or querying staged tables. Continue with omitted or equivalentrow_sets; changing the selection failscursor_invalid. Offsets, handles andoutput_completefollow the selected stream; notices remain deliverable for every selection. - Empty client/year partitions produce factual notices naming the selected ID and year; zero rows do not establish whether an ID is valid. Notices share bounded delivery windows and count in
total_recordsand delivery counters, whilerow_set_totalscounts domain rows only. Follow every cursor. - With
CANVAS_PROVIDER_TYPE=duckdb, the first completed-acquisition delivery window returns adatasetcontaining all acquired filings, selected filings, and selected activities. Its exact replay retains the dataset; later windows retaincanvas_id,describe_tool,query_tooland table guidance without repeating schemas. Optional inputcanvas_idreuses an existing canvas; an expired token failscanvas_not_found.
uslobbying_get_issue_spending tool
- Requires
issue_codeand explicityears; optionalclient_id/registrant_idnarrow upstream acquisition. All versions are acquired before latest-period selection and local issue filtering; broad scans can take hours. - Returns the same collecting/final analytical lists, optional
row_setsselection and dataset routing as profile mode, withattribution_basis: "whole_filing_mentions_issue". Whole-filing amounts overlap across issue buckets and are not allocated issue spending.
uslobbying_search_lobbyists tool
mode: "search"(default) requiresname,registrant_name, orregistrant_id;mode: "activity"requireslobbyist_idandfiling_year, with optionalclient_idandcovered_positions_only.- Returns identity
lobbyistsor filing-scopedevidence, including the matching participant, complete activity, original indexes, and filing UUID/document. Use that UUID withuslobbying_search_filingsfor the complete filing. Covered positions are disclosed text, not verified current employment.
uslobbying_get_contributions tool
- Requires
filing_year(2008–current UTC year); optionalfiling_period(mid_year/year_end), registrant/lobbyist selectors,contribution_type,contributor,payee,honoree, inclusivecontribution_date_after/contribution_date_before, and inclusive local itemamount_min/amount_maxdecimal USD strings. Unknown item amounts cannot satisfy a bound. Contribution amount predicates run locally because native amount filters do not reliably select matching reports. - Returns full parent
reports, completecontribution_items, andmatched_item_indexeswhere every child predicate matched the same item. Originals and amendments remain separate;report_count_in_batchanditem_count_in_batchare not donation totals.
uslobbying_search_foreign_agents tool
mode: "search"(default) searches daily XML snapshots; chooseentity: "registrants"(default) or"foreign_principals", optional literal token-ANDname_contains, and exactcountrylabels for principals only.statusisactive(default),terminated, orall; principal status is independent of registrant status.mode: "detail"requires a digit-stringregistration_numberand retrieves only the chosen live collection:foreign_principals(default),short_forms, ordocuments. Documents requirestatus: "all"(the effective default for documents); an empty collection does not prove a registration never existed.page_sizecontrols local windows over pinned results (default 25; larger positive integers clamp to 25); follownext_cursor. Responses retain source fields, official links, and snapshot retrieval metadata where applicable.
uslobbying_list_reference tool
- Start with
topic:issue_codes,filing_types,government_entities,contribution_types,countries,identifiers,methodology, orfara_rules; optionalfilterapplies literal case-insensitive token-AND matching. - Returns attributed
entries,total_entries, andmatched_entries; follownext_cursorfor pinned windows of up to 125 entries, orrecord_handlesfor oversized entries. Countries retain separately attributed LDA codes and FARA labels, without a guessed ISO mapping.
uslobbying_dataframe_query tool
- Requires
canvas_idand either one read-only SELECT insql(optional freshregister_as) or a storedresult_tablewith optionaloffset.row_limitdefaults to 25; larger positive integers clamp to 100, then any lower provider ceiling. The response byte budget may deliver fewer whole rows. - New SQL materializes the complete result. Continue with
result_table/next_offset;row_countis exact androw_order: "canonical_values"describes delivery ordering. Writes, multiple statements, external reads, and prohibited plan operators fail with typed reasons. - A row that cannot fit fails
query_row_too_largewhile retaining the materialization: select fewer columns or explicitSUBSTRwindows. Missing/expired tables failmissing_table; SQL is unavailable without an enabled canvas.
uslobbying_dataframe_describe tool
- Requires a returned
canvas_id; optionaltable_nameselects one table. Inspect authoritative columns and types before SQL. - Returns exact row counts, grain, creation/expiry, source tool, acquisition provenance, and materializing SQL where applicable. It does not enumerate other canvases.
uslobbying_dataframe_drop tool
- Requires
canvas_idandtable_name; idempotent, returningdropped: falsefor an absent table. - Off unless
USLOBBYING_DATAFRAME_DROP_ENABLED=true; when disabled it is absent fromtools/list. This deletes local staged data only.
Features
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.
LDA/FARA-specific:
- Shared source pacing: anonymous LDA access uses 15 requests/minute per originating IP; an optional registered token uses 120/minute. FARA requests start at least 4.1 seconds apart; separate processes must coordinate shared upstream budgets.
- Analytical selection uses the latest posting within each registrant/client/year/quarter. Equal-latest candidates are marked ambiguous and excluded from sums; this is an analytical rule, not a verified legal amendment lineage.
- Income and expenses remain separate, missing amounts remain unknown, and expense methods retain separate ledgers. Disclosure records establish neither wrongdoing nor policy outcomes or influence.
- FARA search uses complete official daily XML snapshots cached for 24 hours; chosen registration details use the live API. LDA pagination is live and does not promise an immutable historical snapshot.
Agent-friendly output:
- Explicit completion: LDA
page_sizedefaults to 25 andmax_pagesto one for discovery, five for analytics; larger positive integers clamp to 25 and five respectively. Follownext_cursoruntilcoverage.complete, then continue final windows untiloutput_complete. Filters may be omitted or repeated unchanged; page sizes compare after clamping, while workload controls do not change scope identity. - Complete record retrieval: responses target 24,000 UTF-8 bytes across both surfaces. Oversized parents come back as
record_handles, readable through the same tool with JSON Pointerrecord_pathandrecord_offset/record_limit(default 25 entries or items, larger positive integers clamp to 25); strings page by Unicode code point within the byte budget. - Delivery controls: source/reference responses expose
delivery_limitswith{requested,effective}pairs for controls clamped on this call; an empty map means none. SQL returns the same metadata when a ceiling lowers its request. Exact cursor replay retains the original response and its disclosure. Zero, negative, fractional and nonfinite controls remain invalid. - Source counts:
coverage.upstream_count, when known for every partition, sums each partition's latest observed envelope count. It can include duplicate source rows and differs fromunique_records; live pagination is not a frozen snapshot. - Recoverable progress: cursors and retained parents expire 24 hours after acquisition starts. The latest cursor replays its response; older or expired ones fail
cursor_invalid. In-memory restarts lose progress, filesystem storage keeps it until expiry, and the default 128 MiB acquisition budget favors narrow year/client/registrant scopes. - Matching response surfaces:
structuredContentand the JSON text incontent[]carry the same fields, plus clickable official source links. Analyticaldatasetresponses name the staged tables and route to the describe/query tools.
Getting started
Connect to the hosted instance, no install:
claude mcp add --transport http us-lobbying-mcp-server https://us-lobbying.caseyjhand.com/mcp
Or run it locally. Add the following to your MCP client configuration file.
{
"mcpServers": {
"us-lobbying-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/us-lobbying-mcp-server@latest"],
"env": { "MCP_TRANSPORT_TYPE": "stdio" }
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"us-lobbying-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/us-lobbying-mcp-server@latest"],
"env": { "MCP_TRANSPORT_TYPE": "stdio" }
}
}
}
Or with Docker:
{
"mcpServers": {
"us-lobbying-mcp-server": {
"type": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/us-lobbying-mcp-server:latest"]
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
Prerequisites
- Bun v1.4.0 or higher (or Node.js v24+).
- Anonymous access needs no account or key. Optional registered LDA tokens can be configured as
USLOBBYING_LDA_API_KEY.
Installation
- Clone the repository:
git clone https://github.com/cyanheads/us-lobbying-mcp-server.git
- Navigate into the directory:
cd us-lobbying-mcp-server
- Install dependencies:
bun install
- Configure environment:
cp .env.example .env
# edit .env for optional overrides
Configuration
| Variable | Description | Default |
|---|---|---|
USLOBBYING_LDA_API_KEY | Optional registered LDA token for the authenticated request allowance. | — |
USLOBBYING_DATAFRAME_DROP_ENABLED | Expose uslobbying_dataframe_drop, which removes local staged tables. | false |
CANVAS_PROVIDER_TYPE | none or duckdb; npm/Docker installs can enable local SQL. MCPB fixes this to none and keeps complete inline delivery. | none |
STORAGE_PROVIDER_TYPE | Acquisition checkpoint storage; filesystem opts into durable public-record retention. | in-memory |
STORAGE_FILESYSTEM_PATH | Explicit writable directory when selecting filesystem storage. Checkpoints expire 24 hours after acquisition starts. | — |
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_HOST | HTTP bind address; Docker defaults to 0.0.0.0. | 127.0.0.1 |
MCP_HTTP_PORT | HTTP server port. | 3010 |
MCP_HTTP_ENDPOINT_PATH | MCP endpoint path. | /mcp |
MCP_AUTH_MODE | Authentication: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (debug, info, warning, error, etc.). | info |
LOG_TOOL_FAILURE_PAYLOADS | Log failed tool arguments/results, redacted by key name and capped at LOG_TOOL_FAILURE_PAYLOAD_MAX_BYTES (default 16384). Free-form secrets are not redacted. | false |
OTEL_ENABLED | Enable OpenTelemetry instrumentation. | false |
OTEL_EXPORTER_OTLP_ENDPOINT | OTLP base URL for traces and metrics. | — |
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT | Opt-in OTLP log export endpoint. | — |
See .env.example for the full list of optional overrides.
Running the server
Local development
- Build and run the production version:
bun run rebuild bun run start:http # or start:stdio - Run checks and tests:
bun run devcheck # Lints, formats, type-checks bun run test # Runs test suite
Docker
docker build -t us-lobbying-mcp-server .
docker run -p 3010:3010 us-lobbying-mcp-server
The image defaults to HTTP on port 3010. Enable SQL with -e CANVAS_PROVIDER_TYPE=duckdb; use one server process per storage/upstream budget because acquisition locks and pacing are process-local.
Project structure
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point, direct tool registration, service/canvas lifecycle. |
src/config | Server environment validation and shared tool deadlines. |
src/domain | Validated disclosure records, provenance, delivery contracts, and lossless formatting. |
src/mcp-server/tools/definitions | LDA, FARA, reference, and dataframe tools. |
src/services/lda | Fixed-host LDA client with shared pacing and validated pagination. |
src/services/fara | Daily XML snapshots and live per-registration detail collections. |
src/services/acquisition | Resumable acquisition, replay, storage admission, and retained-record windows. |
src/services/lobbying | Quarterly version selection, exact accounting, and filing-specific evidence. |
src/services/canvas | Complete analytical table staging and stable SQL result delivery. |
scripts | Build, devcheck, packaging, and release tooling. |
tests | Unit and integration tests mirroring the source structure. |
Development guide
See CLAUDE.md and AGENTS.md for development guidelines and architectural rules. The short version:
- Handlers throw, framework catches — no
try/catchin tool logic - Use
ctx.logfor logging,ctx.statefor storage - Register tools directly in the
createApp()array insrc/index.ts - Validate complete upstream records, preserve sparse and unknown fields, and keep income, expenses, relationship IDs, and acquisition/output completion distinct
Contributing
Issues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
License
This project is licensed under the Apache 2.0 License. See the LICENSE file for details.
Questions fréquentes
Qu'est-ce que io.github.cyanheads/us-lobbying-mcp-server ?
Search US lobbying disclosures and foreign-agent registrations via MCP.
Comment installer io.github.cyanheads/us-lobbying-mcp-server ?
Il fonctionne comme serveur distant. Dans Claude Code : claude mcp add --transport http us-lobbying-mcp-server 'https://us-lobbying.caseyjhand.com/mcp'. Pour les autres clients, collez la configuration JSON de cette page dans leurs réglages MCP.
Faut-il une clé API pour io.github.cyanheads/us-lobbying-mcp-server ?
Oui. Il attend USLOBBYING_LDA_API_KEY, à renseigner dans sa configuration.
io.github.cyanheads/us-lobbying-mcp-server est-il open source ?
Oui. Son code est sur GitHub sous licence Apache-2.0.
Qui maintient io.github.cyanheads/us-lobbying-mcp-server ?
Il est publié par cyanheads. AI.tn le référence sans le maintenir ni le recommander.
Issu du registre MCP officiel. Être listé n'est pas une recommandation : vérifiez le code et les permissions d'un serveur avant de lui donner accès à vos données.