AgentStack
MCP verified MIT Self-run

Nyc Council Mcp

mcp-betanyc-nyc-council-mcp · by BetaNYC

MCP server for NYC Council legislative data via the Legistar API

No reviews yet
0 installs
13 views
0.0% view→install

Install

$ agentstack add mcp-betanyc-nyc-council-mcp

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Nyc Council Mcp? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

nyc-council-mcp

An MCP (Model Context Protocol) server for NYC Council legislative data. Version 2 adds a hybrid mode: a local SQLite index for sub-second search and exploration, plus the live NYC Legistar API for authoritative real-time data.

Built by BetaNYC with Claude.


API key

A free API key is optional — it unlocks the live Legistar API tools, but the server also runs in local-only mode without one.

  • Live tools (get_bill current status, get_upcoming_hearings, confirmation queries) require a free Legistar API key. Register at council.nyc.gov/legislation/api — you'll receive a token by email — and set it as the LEGISTAR_TOKEN environment variable.
  • Local fast-path tools (search, browse, voting history, aggregation) need no key — they read the local SQLite index at LEGISTAR_DB_PATH.

You must set at least one of LEGISTAR_TOKEN or LEGISTAR_DB_PATH; set both for full hybrid mode. Example (live tools):

export LEGISTAR_TOKEN="your-legistar-token"

See [Setup](#setup) and [Environment variables](#environment-variables) for full details.


Two-speed design

| Path | Speed | Data | Use for | |---|---|---|---| | Local index (SQLite) | Note: The local index may be 1–7 days behind live Legistar depending on when you last updated. For current status and upcoming hearings, use the live API tools (get_bill, get_upcoming_hearings).


Configuration

Claude Code (recommended)

Register at user scope so the server is available from any project:

claude mcp add nyc-council-mcp \
  --scope user \
  npx -- -y @betanyc/nyc-council-mcp serve

Then add your environment variables to ~/.claude.json under the mcpServers entry:

{
  "mcpServers": {
    "nyc-council-mcp": {
      "command": "npx",
      "args": ["-y", "@betanyc/nyc-council-mcp", "serve"],
      "env": {
        "LEGISTAR_TOKEN": "your_token_here",
        "LEGISTAR_DB_PATH": "/Users/you/legistar/legistar.db"
      }
    }
  }
}

Set only LEGISTAR_TOKEN for live-only mode, or only LEGISTAR_DB_PATH for local-only mode.

Claude Desktop

Add to claude_desktop_config.json:

{
  "mcpServers": {
    "nyc-council": {
      "command": "npx",
      "args": ["-y", "@betanyc/nyc-council-mcp", "serve"],
      "env": {
        "LEGISTAR_TOKEN": "your_token_here",
        "LEGISTAR_DB_PATH": "/Users/you/legistar/legistar.db"
      }
    }
  }
}

Build from source

git clone https://github.com/BetaNYC/nyc-council-mcp.git
cd nyc-council-mcp
npm install && npm run build
LEGISTAR_TOKEN=your_token LEGISTAR_DB_PATH=./legistar.db node dist/index.js serve

Index CLI reference

nyc-council-mcp index [options]

Options:
  --archive     Path to jehiah/nyc_legislation clone (required)
  --db          SQLite output path (default: $LEGISTAR_DB_PATH or ./legistar.db)
  --full              Full rebuild (default: incremental)
  --verbose           Print progress to stderr
  --help              Show help

Tool reference

search_bills / search_legislation

Full-text search across the local index, which covers Introductions, Resolutions, and Land Use Applications. Multi-word queries match matters containing all the words in any order; quote a "phrase" to require adjacency.

> Upgrading from ≤ 2.1.1: Resolutions and Land Use matters were previously > absent from the index. Re-run npx @betanyc/nyc-council-mcp index … after > updating to pick them up.

| Parameter | Type | Required | Default | Description | |---|---|---|---|---| | query | string | yes | — | Search terms | | limit | number | no | 25 | Max results (max 100) | | agency | string | no | — | Agency key or name for role-context snippets (e.g. DEP, NYPD) | | status | string | no | — | Filter by status (e.g. Enacted, Laid Over) | | committee | string | no | — | Filter by committee name |

search_bills("open data")
search_bills("bicycle lane", agency="DOT", status="Enacted")
search_bills("tenant protection", committee="Housing")

aggregate_bills

Count bills grouped by a dimension.

| Parameter | Type | Required | Options | |---|---|---|---| | group_by | string | yes | status, type, committee, year |

aggregate_bills(group_by="status")
aggregate_bills(group_by="year")

> ⚠️ Caveat: vote_breakdown, get_voting_record, and get_bill_hearings currently return empty results. > The local index does not yet ingest vote or event-item data (the votes and event_items tables are empty pending a data-source decision), so these three tools always return []. > Worked example: vote_breakdown("Int 0743-2024") returns [] from the local index, even though the live Legistar API has the full 2024-06-06 Stated Meeting roll call at GET /eventitems/409436/votes (51 member votes). > Until this is resolved, get vote data from the live path: get_upcoming_hearings (or GET /events/{EventId}/eventitems) → take an EventItemIdget_votes(event_item_id).

vote_breakdown

Every council member's vote on a specific bill.

| Parameter | Type | Required | Description | |---|---|---|---| | file_number | string | yes | Bill file number, e.g. 0042-2024 |

get_voting_record

All votes cast by a council member.

| Parameter | Type | Required | Default | Description | |---|---|---|---|---| | member_name | string | yes | — | Full or partial name | | limit | number | no | 50 | Max results |

co_sponsors

Members who most frequently co-sponsor bills with a given member.

| Parameter | Type | Required | Default | Description | |---|---|---|---|---| | member_name | string | yes | — | Full or partial name | | limit | number | no | 20 | Top N co-sponsors |


Common workflows

Explore a topic, then confirm

1. search_bills("e-bike")              → sub-second results from local index
2. get_bill("0042-2024")               → authoritative current status from live API
3. get_bill_history(matter_id)         → full action trail from live API
4. get_votes(event_item_id)            → how each member voted

Analyze a council member's record

1. get_voting_record("Nurse")          → all votes cast
2. co_sponsors("Nurse")               → frequent co-sponsors
3. search_bills("bicycle", committee="Transportation")  → bills in their area

Track upcoming hearings

1. upcoming_events(days=14)            → from local index (may be 1–7 days stale)
2. get_upcoming_hearings()             → from live API (real-time)

get_upcoming_hearings populates each event's EventItems array with the agenda items (the bills/matters on that hearing's agenda), fetched per event from the Legistar /events/{EventId}/eventitems endpoint. The /events list endpoint itself always returns EventItems empty and ignores $expand, so the follow-up call is required. Pass include_agenda=false to skip it and return the hearing schedule faster with EventItems empty.


Agency snippets

When you pass agency to search_bills, results include a role-context snippet showing HOW the agency appears in the bill — whether it is directed, consulted, or reporting. This helps distinguish bills that merely mention an agency from those that grant or restrict its authority.

Supported agency keys: DEP, DOT, NYPD, FDNY, DOB, HPD, HRA, DSS, ACS, DOHMH, DHS, DCAS, DSNY, DPR, DCP, FINANCE, LAW, MAYOR, COMPTROLLER, MTA, EDC, SBS, DCWP, DYCD, DFTA, DOE, CUNY, and more.

You can also pass a full name: agency="department of transportation" or agency="sanitation".


Environment variables

| Variable | Required for | Notes | |---|---|---| | LEGISTAR_TOKEN | Live API tools | Register at council.nyc.gov/legislation/api | | LEGISTAR_DB_PATH | Local SQLite tools | Path to your built legistar.db | Do not commit tokens to version control.


Data sources


Acknowledgments

This project builds on the foundational work of @jehiah, whose nyclegislation project has been mirroring NYC Council legislative data since 2018 and powers intro.nyc.

The local SQLite index and agency snippet approach are adapted from WillHsiaoNYC/legistar-mcp, which introduced the two-speed architecture and role-context snippet design that v2 implements in TypeScript.

Thank you to Nathan Storey for including this project in the Civic AI Tools Directory.


Releases

Publishing is automated. To cut a release:

  1. Bump version in package.json in a PR (with a matching [CHANGELOG.md](CHANGELOG.md) entry).
  2. Merge the PR.
  3. Push the matching tag: git tag v && git push origin v.
  4. The [release workflow](.github/workflows/release.yml) runs tests, verifies the tag matches package.json, publishes to npm with provenance, and creates a GitHub Release.

Prerequisite: the NPM_TOKEN org secret (an npm automation token with publish rights on @betanyc) must be configured. Do not run npm publish by hand.


Contributing

Issues and pull requests welcome at github.com/BetaNYC/nyc-council-mcp.


Support our work

Freedom isn't free. Support BetaNYC.

License

MIT License — Copyright (c) 2026 BetaNYC

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.