{"id":"83c628aa-810f-4db1-ab55-857565d046ab","slug":"legiscan-mcp","kind":"mcp","name":"legiscan-mcp","summary":"MCP server for the LegiScan API. Access legislative data from all 50 US states and Congress - search bills, get full text, track votes, look up legislators, and monitor legislation changes.","owner":"sh-patterson","repoUrl":"https://github.com/sh-patterson/legiscan-mcp","license":"MIT","licenseTier":"permissive","trust":"community","stars":12,"match":null,"fewStars":false,"format":"mcp","createdAt":"2025-12-23T02:59:12.000Z","addedAt":"2026-10-21T05:29:05.179Z","logoUrl":"https://avatars.githubusercontent.com/u/200695434?u=741749b5e0d20acd5b3e1c45235ea66b9271d2f9&v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["data-analytics","search","cloud-infra"],"tags":["legiscan","legislation","bills","congress","state-legislature","political-data","ai-tools","claude"],"runtime":"node","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-25T14:15:09.201Z","sample":false,"url":"https://conduits.dev/tools/legiscan-mcp","language":"TypeScript","transports":["stdio"],"install":{"npm":"legiscan-mcp-server"},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"# LegiScan MCP Server\n\n[![CI](https://github.com/sh-patterson/legiscan-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/sh-patterson/legiscan-mcp/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n[![Node](https://img.shields.io/badge/node-%3E%3D18-brightgreen)](package.json)\n[![TypeScript](https://img.shields.io/badge/TypeScript-5.3-blue.svg)](https://www.typescriptlang.org/)\n\nA Model Context Protocol (MCP) server that gives terminal agents structured access to the [LegiScan API](https://legiscan.com/) for legislative data from all 50 US states and Congress.\n\nBuilt for research workflows where you direct an agent (Codex, Claude Code, Claude Desktop, etc.) to gather bill history, sponsor context, and voting records quickly.\n\n## Features\n\n- **10 Streamlined MCP Tools** optimized for legislative research workflows\n- **Composite tools** that collapse multi-step research workflows into single MCP tool calls\n- Per-request batching and lookup caching for repeated bill and roll-call lookups\n- Full TypeScript type definitions for all API responses\n- Bill number normalization (handles AB 858, AB858, AB-858 formats)\n- Input validation guardrails for state codes, legislator name queries, and large bill batches\n\n## Installation\n\n### From npm (Recommended)\n\n```bash\nnpm install -g legiscan-mcp-server\n```\n\n### From Source\n\n```bash\ngit clone https://github.com/sh-patterson/legiscan-mcp.git\ncd legiscan-mcp\nnpm install\nnpm run build\n```\n\n## Setup\n\n### 1. Get a LegiScan API Key\n\n1. Create a free account at [LegiScan](https://legiscan.com/)\n2. Register for API access at https://legiscan.com/legiscan\n3. Copy your API key\n\n### 2. Add to Your MCP-Capable Agent\n\nAdd this server to whatever MCP host your terminal agent uses.\n\nClaude Desktop config paths:\n\n- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`\n- Windows: `%APPDATA%\\Claude\\claude_desktop_config.json`\n\nFor other MCP clients (Codex CLI, Claude Code, etc.), add the same `mcpServers.legiscan` entry in that client's MCP config file.\n\n#### Using npx (Recommended)\n\n```json\n{\n  \"mcpServers\": {\n    \"legiscan\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"legiscan-mcp-server\"],\n      \"env\": {\n        \"LEGISCAN_API_KEY\": \"your_api_key_here\"\n      }\n    }\n  }\n}\n```\n\n#### Using local installation\n\n```json\n{\n  \"mcpServers\": {\n    \"legiscan\": {\n      \"command\": \"node\",\n      \"args\": [\"/path/to/legiscan-mcp-server/dist/index.js\"],\n      \"env\": {\n        \"LEGISCAN_API_KEY\": \"your_api_key_here\"\n      }\n    }\n  }\n}\n```\n\n## Available Tools\n\n### Composite Tools (High-Level Research)\n\n| Tool                            | Description                                                         |\n| ------------------------------- | ------------------------------------------------------------------- |\n| `legiscan_find_legislator`      | Find a legislator's people_id by name. Supports partial matching.   |\n| `legiscan_get_legislator_votes` | Get how a legislator voted on multiple bills in one call.           |\n| `legiscan_get_primary_authored` | Get only bills where legislator is primary author (not co-sponsor). |\n\n### Bills\n\n| Tool                           | Description                                                                                |\n| ------------------------------ | ------------------------------------------------------------------------------------------ |\n| `legiscan_get_bill`            | Get detailed bill info (sponsors, history, votes, texts)                                   |\n| `legiscan_find_bill_by_number` | Find bill by number (handles AB 858, AB858, AB-858, A.B. 858). Best for exact bill lookup. |\n| `legiscan_get_roll_call`       | Get vote details with individual legislator votes                                          |\n\n### People\n\n| Tool                          | Description                                                             |\n| ----------------------------- | ----------------------------------------------------------------------- |\n| `legiscan_get_person`         | Get legislator info with third-party IDs (VoteSmart, OpenSecrets, etc.) |\n| `legiscan_get_session_people` | Get all legislators active in a session                                 |\n\n### Search\n\n| Tool              | Description                                                                                                                             |\n| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------- |\n| `legiscan_search` | Full-text search across legislation. Accepts bill-number variants like AB858, but use `legiscan_find_bill_by_number` for exact matches. |\n\n### Sessions\n\n| Tool                        | Description                                  |\n| --------------------------- | -------------------------------------------- |\n| `legiscan_get_session_list` | List available legislative sessions by state |\n\n## Researcher Workflow (Terminal Agent)\n\n### 1. Start with a scoped request\n\nGive your agent a goal, state, timeframe, and output format.\n\nExample prompt:\n\n```text\nUse the LegiScan MCP tools to find major California housing bills in the current session.\nReturn: bill number, title, latest action date, top sponsors, and whether there was a close roll-call vote (margin <= 5).\n```\n\n### 2. Ask the agent to follow a tool sequence\n\nFor high-quality results, tell the agent to do this order:\n\n1. `legiscan_get_session_list` to identify the correct session.\n2. `legiscan_search` or `legiscan_find_bill_by_number` to locate target bills.\n3. `legiscan_get_bill` for sponsor/history/vote references.\n4. `legiscan_get_roll_call` for individual vote details.\n5. `legiscan_get_person` only when legislator enrichment is needed.\n\nIf you start with `legiscan_find_legislator`, keep passing the returned `session.session_id` or the same `state` into follow-up authoring workflows so results stay in the intended legislature and timeframe.\n\n### 3. Reuse composite tools for analyst workflows\n\nThese cut tool-call volume and simplify instructions to your agent:\n\n- `legiscan_find_legislator`: get `people_id` from a name query.\n- `legiscan_get_primary_authored`: separate primary-authored from co-sponsored bills.\n- `legiscan_get_legislator_votes`: pull vote positions across many bills in one request.\n\nBoth composite tools cap API lookups per call. In `legiscan_get_legislator_votes`, check each bill's `roll_call_coverage`: `selected` is the number of roll-call references inspected on that page, and `next_offset` means older roll calls remain. Call again with that bill ID and `roll_call_offset: next_offset` before treating an empty vote list as complete. In `legiscan_get_primary_authored`, pass `offset: next_offset` with the same `people_id` and session or state until `next_offset` is absent. Results can change between pages if LegiScan updates its lists.\n\n## Prompt Templates\n\n### A) Opposition research on one legislator\n\n```text\nUse LegiScan MCP for Texas.\n1) Find legislator \"Jane Smith\".\n2) List all primary-authored bills in the current session.\n3) For these bills, summarize topic area and latest status.\n4) Then check votes on SB 12, HB 301, and SB 455, and show how the legislator voted.\n```\n\n### B) Bill tracking brief for an issue area\n\n```text\nUse LegiScan MCP to track \"climate resilience\" bills in New York.\nFocus on current session only.\nReturn top 15 bills by relevance with bill number, title, last action, sponsor party, and any recorded roll calls.\n```\n\n### C) Scorecard support workflow\n\n```text\nFor California session 2172, resolve bill numbers AB 858, SB 525, SB 616, SB 399.\nFor each bill, fetch details and any roll calls.\nThen report vote positions for people_id values 21719, 23214, and 25359.\nOutput as a table suitable for CSV export.\n```\n\n## Workflow Simplification\n\nThe composite tools dramatically reduce agent-to-tool round trips for common workflows:\n\n| Workflow                                         | Manual MCP Steps                                                                    | With Composites                                           |\n| ------------------------------------------------ | ----------------------------------------------------------------------------------- | --------------------------------------------------------- |\n| Get votes for 1 legislator on 10 bills           | Find legislator → search/resolve bills → inspect each bill → inspect each roll call | 1 tool call once you have `bill_ids`                      |\n| Filter primary authored from 150 sponsored bills | Sponsored list → fetch each bill → inspect sponsors                                 | 1 tool call with `limit: 150`, optionally scoped by `state` or `session_id` |\n| Find legislator by name                          | Session discovery → session people lookup → manual matching                         | 1 tool call                                               |\n\n## Research Tips\n\n- State codes are validated as two-letter strings and uppercased automatically (`ca` → `CA`). Invalid codes like `ZZ` pass local validation but return an API error from LegiScan.\n- Always pin state and session in your prompt to reduce ambiguous results.\n- Ask the agent to show `bill_id`, `roll_call_id`, and `people_id` in intermediate output so you can audit traceability.\n- For legislator search, provide at least a first and last name (name input must be at least 2 characters).\n- `legiscan_get_primary_authored` can return all available sessions, but passing `state` or `session_id` keeps results aligned to the intended legislature and timeframe.\n- `legiscan_get_legislator_votes` accepts up to 100 `bill_ids` per request; split larger jobs into chunks.\n- `legiscan_search` retries compact bill-number queries like `AB858` using a canonical spaced format. For exact bill resolution, prefer `legiscan_find_bill_by_number`.\n- Ask for final outputs in a table/CSV-ready shape if you plan downstream analysis.\n\n## Development\n\n```bash\nnpm run build        # Compile TypeScript\nnpm run typecheck    # Type-check src + tests\nnpm test             # Run deterministic unit tests (no API key)\nnpm run test:e2e     # Run offline MCP/HTTP workflows; also run live scenarios with an API key\nnpm run test:live    # Run live API integration tests (requires API key)\nnpm run test:coverage # Run unit tests with coverage\nnpm run lint         # Check for lint errors\nnpm run format       # Format code with Prettier\n```\n\n## Testing Modes\n\n- `npm test` / `npm run test:unit`: Fast deterministic tests with mocked network calls.\n- `npm run test:e2e`: Runs provider-free MCP-to-HTTP workflow tests. Its real LegiScan scenarios run only when `LEGISCAN_API_KEY` is available.\n- `npm run test:live`: Real LegiScan API integration tests. Requires `LEGISCAN_API_KEY`.\n\n## API Limits\n\n- Free public API keys have a **30,000 queries per month** limit\n- Composite tools batch requests (10 concurrent max) and cache repeated lookups inside a single request to avoid unnecessary duplication\n- Composite tools reduce MCP workflow friction, but LegiScan API usage still scales with the number of distinct bills and roll calls you inspect\n\n## Docker\n\nBuild the container image locally:\n\n```bash\ndocker build -t legiscan-mcp .\n```\n\nRun it with your API key provided at runtime:\n\n```bash\ndocker run --rm -i \\\n  -e LEGISCAN_API_KEY=your-api-key-here \\\n  legiscan-mcp\n```\n\n## Releases\n\nGlama checks expect a GitHub release. After merging your next repo changes, create and publish a tag such as `v1.0.0` from GitHub or with:\n\n```bash\ngit tag v1.0.0\ngit push origin v1.0.0\n```\n\n## License\n\nMIT - see [LICENSE](LICENSE) for details.\n"}