CanLII
MCP for CanLII: Canadian case law and legislation metadata (federal, provincial, territorial).
Open source Repository Open in the app JSON README (API)
About
MCP for CanLII: Canadian case law and legislation metadata (federal, provincial, territorial).
Details
- Kind
- MCP servers
- Topic
- Government & public data
- Publisher
- vaquill-ai
- Origin
- official
- Category
- ferramentas
- Transport
- http
- Version
- 0.1.0
- Stars
- 5
- Forks
- 1
- Last push
- 2026-07-09T04:40:52Z
- Repository state
- ativo
- Language
- TypeScript
- License
- MIT
- Added
- 2026-08-29 03:02:18
- Updated
- 2026-08-29 03:02:18
- Origin id
io.github.Vaquill-AI/canlii-mcp
README
# canlii-mcp
An [MCP (Model Context Protocol)](https://modelcontextprotocol.io) server for the [CanLII](https://www.canlii.org) Canadian legal information API. Gives AI assistants access to Canadian case law and legislation metadata across all federal, provincial, and territorial jurisdictions.
> **Forked from** [tomilashy/canlii-mcp](https://github.com/tomilashy/canlii-mcp). This fork adds bring-your-own-key (BYOK) auth, a `/health` route, and a hosted endpoint at `canlii-mcp.vaquill.ai`. Tools are unchanged.
> **Note:** The CanLII API provides metadata only — titles, citations, dates, keywords, and citation relationships. Full document text is not available through the API.
## Use the hosted endpoint (no install)
```
https://canlii-mcp.vaquill.ai/mcp
```
The hosted instance is public. No Vaquill token is required. Provide your own CanLII key one of two ways:
- **Header (recommended, keeps the key out of the URL):** `X-CanLII-Token: <your_canlii_api_key>`
- **URL parameter (simplest; works in header-less clients like the Claude Desktop connector UI and claude.ai web):** append `?token=<your_canlii_api_key>` to the URL:
```
https://canlii-mcp.vaquill.ai/mcp?token=YOUR_CANLII_API_KEY
```
Apply for a key at [canlii.org/en/api/](https://www.canlii.org/en/feedback/feedback.html). The server never stores your key, and there is no server-side fallback key, so every call counts against your own CanLII quota.
### Claude Desktop / Claude Code
```json
{
"mcpServers": {
"canlii": {
"url": "https://canlii-mcp.vaquill.ai/mcp",
"headers": {
"X-CanLII-Token": "YOUR_CANLII_API_KEY"
}
}
}
}
```
### Cursor / VS Code / Windsurf
Same pattern: any client supporting MCP streamable HTTP with custom headers works. For stdio-only clients use `mcp-remote` to proxy.
## Authentication
| Mode | Header | When |
|---|---|---|
| BYOK header (preferred) | `X-CanLII-Token: <key>` | Hosted / shared deployments |
| BYOK URL param | `?token=<key>` (or `?canlii_token=`) | Header-less clients: Claude Desktop connector UI, claude.ai web |
| Server fallback | (env `CANLII_API`) | Self-hosted single-tenant. Required for stdio. |
| MCP gate | `Authorization: Bearer <MCP_AUTH_TOKEN>` | Optional, self-host only. The public hosted endpoint at `canlii-mcp.vaquill.ai` does **not** use it, so no bearer token is required. |
## Tools
| Tool | Description |
|------|-------------|
| `list_case_databases` | List all courts and tribunals in the CanLII collection |
| `list_cases` | Browse decisions from a specific court/tribunal database |
| `get_case` | Get metadata for a specific case (title, citation, date, keywords) |
| `get_case_citations` | Get cases cited by a case, cases citing it, or legislation it references |
| `list_legislation_databases` | List all statute and regulation databases |
| `list_legislation` | Browse statutes or regulations from a specific database |
| `get_legislation` | Get metadata for a specific piece of legislation |
## Requirements
- Node.js 22+
- A CanLII API key — [apply here](https://www.canlii.org/en/feedback/feedback.html)
## Usage
### stdio via npx (quickest)
```json
{
"mcpServers": {
"canlii": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@tomilashy/canlii-mcp"],
"env": {
"CANLII_API": "your_api_key"
}
}
}
}
```
### stdio (from source)
```bash
npm install
npm run build
node dist/index.js
```
Add to your MCP config:
```json
{
"mcpServers": {
"canlii": {
"command": "node",
"args": ["/path/to/canlii-mcp/dist/index.js"],
"env": {
"CANLII_API": "your_api_key"
}
}
}
}
```
### HTTP server
```bash
PORT=3000 CANLII_API=your_api_key node dist/index.js --transport http
```
The MCP endpoint is available at `http://localhost:3000/mcp`. The server runs in stateless mode — each request is self-contained, no session ID or initialize handshake required. Clients can call tools directly:
```bash
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"list_case_databases","arguments":{"language":"en"}}}'
```
### Docker
```bash
docker run -e CANLII_API=your_api_key -e MCP_AUTH_TOKEN=your_secret -p 3000:3000 ghcr.io/tomilashy/canlii-mcp
```
Or with Docker Compose:
```yaml
services:
canlii-mcp:
image: ghcr.io/tomilashy/canlii-mcp
environment:
CANLII_API: your_api_key
MCP_AUTH_TOKEN: your_secret # optional
ports:
- "3000:3000"
```
### Cloudflare Workers
The server includes a Workers-compatible entry point (`src/worker.ts`).
#### CLI deploy
```bash
npx wrangler secret put CANLII_API
npx wrangler secret put MCP_AUTH_TOKEN # optional
npx wrangler deploy
```
#### Dashboard deploy (Connect to Git)
1. Go to [Cloudflare Dashboard](https://dash.cloudflare.com) → **Workers & Pages** → **Create** → **Connect to Git**
2. Select your `tomilashy/canlii-mcp` repository
3. On the **Set up your application** page:
- **Project name**: `canlii-mcp`
- **Build command**: `npm install && npm run build`
- **Deploy command**: `npx wrangler deploy` (pre-filled)
4. Expand **Advanced settings**:
- **Variable name**: `CANLII_API`
- **Variable value**: your CanLII API key
- Check **Encrypt** to store it as a secret
5. Click **Deploy**
The MCP endpoint will be at `https://canlii-mcp.<your-subdomain>.workers.dev/mcp`.
## Configuration
| Environment Variable | Required | Default | Description |
|---------------------|----------|---------|-------------|
| `CANLII_API` | Yes | — | Your CanLII API key |
| `PORT` | No | `3000` | HTTP server port (HTTP mode only) |
| `MCP_AUTH_TOKEN` | No | — | Bearer token for HTTP authentication. If set, all HTTP requests must include `Authorization: Bearer <token>`. If not set, the server runs without authentication. |
## Rate Limits
The server enforces CanLII's API limits automatically, **per CanLII key**, so one caller's usage never throttles another's:
- 1 request at a time
- 2 requests per second
- 5,000 requests per day
These mirror CanLII's own per-key limits. Each `X-CanLII-Token` gets its own independent budget (keyed by a hash of the key; raw keys are never retained). Requests that exceed the daily limit return an error rather than hitting the API.
## Development
```bash
npm install
npm run build # compile TypeScript
npm run watch # watch mode
```
## Release
This project uses [Semantic Versioning](https://semver.org) via [semantic-release](https://semantic-release.gitbook.io). Commit messages follow the [Conventional Commits](https://www.conventionalcommits.org) spec:
| Commit prefix | Release type |
|---------------|-------------|
| `fix:` | Patch (`1.0.0` → `1.0.1`) |
| `feat:` | Minor (`1.0.0` → `1.1.0`) |
| `feat!:` or `BREAKING CHANGE` | Major (`1.0.0` → `2.0.0`) |
Pushing to `main` triggers the release workflow. If a release is cut, the Docker image is automatically built and published to `ghcr.io`.
## License
MIT