Content
# 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
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
markitdown
MarkItDown-MCP is a lightweight server for converting URIs to Markdown.
markitdown
Python tool for converting files and office documents to Markdown.
Filesystem
Node.js MCP Server for filesystem operations with dynamic access control.
TrendRadar
TrendRadar: Your hotspot assistant for real news in just 30 seconds.
mempalace
The highest-scoring AI memory system ever benchmarked. And it's free.
mempalace
The highest-scoring AI memory system ever benchmarked. And it's free.