# Nyc Council Mcp

> MCP server for NYC Council legislative data via the Legistar API

- **Type:** MCP server
- **Install:** `agentstack add mcp-betanyc-nyc-council-mcp`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [BetaNYC](https://agentstack.voostack.com/s/betanyc)
- **Installs:** 0
- **Category:** [Integrations](https://agentstack.voostack.com/c/integrations)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [BetaNYC](https://github.com/BetaNYC)
- **Source:** https://github.com/BetaNYC/nyc-council-mcp
- **Website:** https://council.nyc.gov/legislation/

## Install

```sh
agentstack add mcp-betanyc-nyc-council-mcp
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# nyc-council-mcp

An [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) 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](https://council.nyc.gov/legislation/api/) for authoritative real-time data.

Built by [BetaNYC](https://beta.nyc) with [Claude](https://claude.ai).

---

## 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](https://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):

```bash
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:

```bash
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:

```json
{
  "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`:

```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

```bash
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 `EventItemId` → `get_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](https://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

- **Live tools:** [NYC Council Legistar API](https://council.nyc.gov/legislation/api/), provided by [Granicus](https://granicus.com/)
- **Local index:** [jehiah/nyc_legislation](https://github.com/jehiah/nyc_legislation) archive — has been mirroring Legistar since 2018, updated most weekdays

---

## Acknowledgments

This project builds on the foundational work of [@jehiah](https://github.com/jehiah), whose [nyc_legislation](https://github.com/jehiah/nyc_legislation) project has been mirroring NYC Council legislative data since 2018 and powers [intro.nyc](https://intro.nyc/).

The local SQLite index and agency snippet approach are adapted from [WillHsiaoNYC/legistar-mcp](https://github.com/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](https://www.civicaitools.org/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](https://github.com/BetaNYC/nyc-council-mcp).

---

## Support our work

Freedom isn't free. [Support BetaNYC](https://beta.nyc/donate/).

## 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.

- **Author:** [BetaNYC](https://github.com/BetaNYC)
- **Source:** [BetaNYC/nyc-council-mcp](https://github.com/BetaNYC/nyc-council-mcp)
- **License:** MIT
- **Homepage:** https://council.nyc.gov/legislation/

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

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-betanyc-nyc-council-mcp
- Seller: https://agentstack.voostack.com/s/betanyc
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
