Search US lobbying disclosures and foreign-agent registrations via MCP.
One address for any MCP client. No sign-in needed on this server.
9 read
Grouped by tool name. At most: moves money, runs code or commands, deletes data, or sends messages for you.
Odel charges nothing per call. The publisher may charge for its own service.
Search US lobbying disclosures and foreign-agent registrations via MCP. STDIO or Streamable HTTP.
Public Hosted Server: https://us-lobbying.caseyjhand.com/mcp
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.
| 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 |
uslobbying_search_filings toolfiling_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, or foreign_entity_country. Dates are real YYYY-MM-DD calendar 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; optional issue_code applies locally and cannot narrow upstream requests.filing_uuid from lobbyist evidence or analytical selections to retrieve the complete filing, including nested source fields and document links.filings with amendment_policy: "all_versions", separate nullable USD decimal-string income / expenses, document links, and nested disclosures. Shared acquisition and record-window rules appear under Features.uslobbying_get_client_profile toolmode: "resolve" (default) requires client_name; mode: "profile" requires explicit client_ids and years (1999–current UTC year). Pass each candidate's id, not its registrant-assigned client_id. IDs identify relationships with registrants; candidates are never automatically merged into a corporate identity.status: "collecting" until acquisition completes, then typed annual_ledgers, selections, firms, issue_codes, targeted_entities, selected_filings, activities, and raw_filings across output windows. row_set_totals / row_set_offsets describe each list's delivery.row_sets selects which of those lists to deliver inline. Omission delivers every set; raw_filings always 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 equivalent row_sets; changing the selection fails cursor_invalid. Offsets, handles and output_complete follow the selected stream; notices remain deliverable for every selection.total_records and delivery counters, while row_set_totals counts domain rows only. Follow every cursor.CANVAS_PROVIDER_TYPE=duckdb, the first completed-acquisition delivery window returns a dataset containing all acquired filings, selected filings, and selected activities. Its exact replay retains the dataset; later windows retain canvas_id, describe_tool, query_tool and table guidance without repeating schemas. Optional input canvas_id reuses an existing canvas; an expired token fails canvas_not_found.uslobbying_get_issue_spending toolissue_code and explicit years; optional client_id / registrant_id narrow upstream acquisition. All versions are acquired before latest-period selection and local issue filtering; broad scans can take hours.row_sets selection and dataset routing as profile mode, with attribution_basis: "whole_filing_mentions_issue". Whole-filing amounts overlap across issue buckets and are not allocated issue spending.uslobbying_search_lobbyists toolmode: "search" (default) requires name, registrant_name, or registrant_id; mode: "activity" requires lobbyist_id and filing_year, with optional client_id and covered_positions_only.lobbyists or filing-scoped evidence, including the matching participant, complete activity, original indexes, and filing UUID/document. Use that UUID with uslobbying_search_filings for the complete filing. Covered positions are disclosed text, not verified current employment.uslobbying_get_contributions toolfiling_year (2008–current UTC year); optional filing_period (mid_year / year_end), registrant/lobbyist selectors, contribution_type, contributor, payee, honoree, inclusive contribution_date_after / contribution_date_before, and inclusive local item amount_min / amount_max decimal USD strings. Unknown item amounts cannot satisfy a bound. Contribution amount predicates run locally because native amount filters do not reliably select matching reports.reports, complete contribution_items, and matched_item_indexes where every child predicate matched the same item. Originals and amendments remain separate; report_count_in_batch and item_count_in_batch are not donation totals.uslobbying_search_foreign_agents toolmode: "search" (default) searches daily XML snapshots; choose entity: "registrants" (default) or "foreign_principals", optional literal token-AND name_contains, and exact country labels for principals only. status is active (default), terminated, or all; principal status is independent of registrant status.mode: "detail" requires a digit-string registration_number and retrieves only the chosen live collection: foreign_principals (default), short_forms, or documents. Documents require status: "all" (the effective default for documents); an empty collection does not prove a registration never existed.page_size controls local windows over pinned results (default 25; larger positive integers clamp to 25); follow next_cursor. Responses retain source fields, official links, and snapshot retrieval metadata where applicable.uslobbying_list_reference tooltopic: issue_codes, filing_types, government_entities, contribution_types, countries, identifiers, methodology, or fara_rules; optional filter applies literal case-insensitive token-AND matching.entries, total_entries, and matched_entries; follow next_cursor for pinned windows of up to 125 entries, or record_handles for oversized entries. Countries retain separately attributed LDA codes and FARA labels, without a guessed ISO mapping.uslobbying_dataframe_query toolcanvas_id and either one read-only SELECT in sql (optional fresh register_as) or a stored result_table with optional offset. row_limit defaults to 25; larger positive integers clamp to 100, then any lower provider ceiling. The response byte budget may deliver fewer whole rows.result_table / next_offset; row_count is exact and row_order: "canonical_values" describes delivery ordering. Writes, multiple statements, external reads, and prohibited plan operators fail with typed reasons.query_row_too_large while retaining the materialization: select fewer columns or explicit SUBSTR windows. Missing/expired tables fail missing_table; SQL is unavailable without an enabled canvas.uslobbying_dataframe_describe toolcanvas_id; optional table_name selects one table. Inspect authoritative columns and types before SQL.uslobbying_dataframe_drop toolcanvas_id and table_name; idempotent, returning dropped: false for an absent table.USLOBBYING_DATAFRAME_DROP_ENABLED=true; when disabled it is absent from tools/list. This deletes local staged data only.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:
Agent-friendly output:
page_size defaults to 25 and max_pages to one for discovery, five for analytics; larger positive integers clamp to 25 and five respectively. Follow next_cursor until coverage.complete, then continue final windows until output_complete. Filters may be omitted or repeated unchanged; page sizes compare after clamping, while workload controls do not change scope identity.record_handles, readable through the same tool with JSON Pointer record_path and record_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_limits with {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.coverage.upstream_count, when known for every partition, sums each partition's latest observed envelope count. It can include duplicate source rows and differs from unique_records; live pagination is not a frozen snapshot.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.structuredContent and the JSON text in content[] carry the same fields, plus clickable official source links. Analytical dataset responses name the staged tables and route to the describe/query tools.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
USLOBBYING_LDA_API_KEY.git clone https://github.com/cyanheads/us-lobbying-mcp-server.git
cd us-lobbying-mcp-server
bun install
cp .env.example .env
# edit .env for optional overrides
| 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.
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 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.
| 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. |
See CLAUDE.md and AGENTS.md for development guidelines and architectural rules. The short version:
try/catch in tool logicctx.log for logging, ctx.state for storagecreateApp() array in src/index.tsIssues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
This project is licensed under the Apache 2.0 License. See the LICENSE file for details.