cpl-mcp
# cpl-mcp
[](https://github.com/jonphilnj/cpl-mcp/actions/workflows/ci.yml)
[](https://www.python.org/)
[](https://github.com/jonphilnj/cpl-mcp/actions/workflows/ci.yml)
MCP server for the New York State Criminal Procedure Law (CPL). Wraps the
[NY Senate OpenLegislation API](https://legislation.nysenate.gov) so any MCP
client can look up CPL sections by citation and search the CPL by keyword.
## Installation
**With [uv](https://docs.astral.sh/uv/) (recommended):**
```bash
uvx cpl-mcp
```
**With pip:**
```bash
pip install cpl-mcp
python -m cpl_mcp.server
```
## Auth setup
The server requires a free OpenLegislation API key.
1. Go to <https://legislation.nysenate.gov> and click **Sign up for an API Key**.
2. Fill in the form — the key is emailed to you within a few minutes.
3. Set the environment variable before starting the server:
```bash
export NYS_LEG_API_KEY="your-key-here"
```
Or put it in a `.env` file in the project root — the server loads it automatically:
```dotenv
NYS_LEG_API_KEY=your-key-here
```
## Claude Desktop config
Add the following to `claude_desktop_config.json`
(`~/Library/Application Support/Claude/` on macOS,
`%APPDATA%\Claude\` on Windows):
```json
{
"mcpServers": {
"cpl": {
"command": "uvx",
"args": ["cpl-mcp"],
"env": {
"NYS_LEG_API_KEY": "your-key-here"
}
}
}
}
```
If you prefer a local checkout instead of `uvx`:
```json
{
"mcpServers": {
"cpl": {
"command": "uv",
"args": [
"--directory", "/absolute/path/to/cpl-mcp",
"run", "python", "-m", "cpl_mcp.server"
],
"env": {
"NYS_LEG_API_KEY": "your-key-here"
}
}
}
}
```
## Environment variables
| Variable | Required | Description |
| ----------------- | -------- | ------------------------------------------------------------------------ |
| `NYS_LEG_API_KEY` | Yes | OpenLegislation API key. Get one at <https://legislation.nysenate.gov>. |
## Tools
| Tool | Description |
|---|---|
| `cpl_lookup_section` | Retrieve the full text of a CPL section or article by citation (e.g. `245.20`, `A245`). |
| `cpl_search` | Full-text keyword search across the CPL. Returns a ranked list of matching sections with snippets. |
### `cpl_lookup_section`
Use when you know the section number. Accepts flexible citation formats —
`CPL § 245.20`, `section 245.20`, and `245.20` all resolve to the same
location. Returns the statute text, active date, structural breadcrumb
(article/title parents), and a link to the official nysenate.gov page.
### `cpl_search`
Use when searching by topic rather than citation. Supports pagination via
`limit` (1–50, default 10) and `offset` (1-based, default 1).
Both tools accept a `response_format` parameter: `"markdown"` (default,
human-readable) or `"json"` (machine-readable, useful for chaining tools).
## Running locally
```bash
# one-shot lookup — no MCP client needed
python -m cpl_mcp.server --selftest 245.20
# one-shot lookup + keyword search
python -m cpl_mcp.server --selftest 245.20 --search "speedy trial"
# HTTP transport for debugging (listens on 127.0.0.1:8000)
python -m cpl_mcp.server --http
```
TDQS
Scored across 2 tools
The two tools have clearly distinct purposes: cpl_lookup_section retrieves specific sections by citation, while cpl_search performs full-text topic searches. Each explicitly states when to use the other, leaving no ambiguity.
Both tools follow a consistent 'cpl_' prefix followed by a verb or verb_noun (lookup_section, search). The naming clearly signals the action and domain, and the pattern is uniform.
The server has only two tools, which feels thin for a general API but is appropriate for a focused legal statute lookup service. The two tools cover the essential search-and-retrieve workflow and earn their place.
The pair covers the key user journeys: finding a section by topic and reading a section by citation. A minor gap is the lack of a browse or list-all-articles tool, but search and citation lookup handle most practical needs.