CanLII MCP Server
A local Model Context Protocol (MCP) server for macOS that lets Claude Desktop search the CanLII Canadian legal database and read the full text of matching documents.
What it does
Exposes a single MCP tool — search_canlii — that Claude can call to:
- Search CanLII using either full-text or case-name search
- Fetch the full text of the top matching documents
- Return cleaned plain text (no HTML markup) back to Claude
Tool reference
search_canlii(
query: str,
search_type: "text" | "name" = "text",
max_results: int = 5 # 1–10
)
| search_type | When to use | |---|---| | "text" | Legal concepts, keywords, or phrases within judgment bodies | | "name" | Case name, document title, file number, author, or citation (e.g. R v Oakes, 2024 SCC 12) |
Requirements
- macOS
- Python 3.11+
- uv — Python package manager
- Claude Desktop
Installation
1. Clone the repository
git clone <repo-url>
cd canlii_mcp_server
2. Install dependencies and Chromium
uv sync
uv run playwright install chromium
3. Add the server to Claude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"canlii": {
"command": "/path/to/uv",
"args": [
"run",
"--project",
"/path/to/canlii_mcp_server",
"canlii-mcp-server"
]
}
}
}
Replace /path/to/uv with the output of which uv, and /path/to/canlii_mcp_server with the absolute path to this directory.
4. Restart Claude Desktop
Fully quit Claude Desktop (menu bar → Quit), then reopen it. The canlii server will appear under Settings → Developer.
Usage
In a Claude Desktop conversation:
"Search CanLII for cases about reasonable apprehension of bias."
"Find the case R v Oakes."
"What does CanLII say about the duty to accommodate in employment law?"
Claude will call search_canlii automatically with the appropriate search_type.
How it works
CanLII's website is a JavaScript single-page application — search results are rendered client-side and not available in raw HTML. This server uses Playwright (headless Chromium) to load pages as a real browser would, then extracts clean text with BeautifulSoup.
playwright-stealth is applied to each page load to reduce the likelihood of bot detection by CanLII's DataDome protection. Requests are rate-limited to 1.5 seconds between document fetches to avoid triggering blocks.
Note: CanLII's bot protection may occasionally flag automated requests. If Claude reports a "blocked" error, wait an hour and try again.
Development
Run unit tests
uv run pytest tests/ --ignore=tests/test_smoke.py -v
Run live integration tests (requires network access to canlii.org)
uv run pytest tests/test_smoke.py -v -s
Project structure
src/canlii_mcp_server/
server.py — MCP server entry point, tool registration
search.py — URL builder, search results parser
fetch.py — document text extractor, Playwright browser manager
tests/
test_url_builder.py — URL building (5 tests)
test_search_parser.py — search results parsing (4 tests)
test_document_extractor.py — document text extraction (5 tests)
test_smoke.py — live integration tests (3 tests, manual)
fixtures/ — saved CanLII HTML used by unit tests
scripts/
recon.py — captures CanLII HTML structure for fixture updates
recon_document.py — captures a single document page slowly
Limitations
- No full-text API: CanLII does not provide an API that returns document text — only metadata. Playwright scraping is the only viable approach.
- Bot detection: CanLII uses DataDome. Occasional temporary blocks are possible.
- No noteup search: CanLII's "Noteup/Discussion" search requires a document path as input rather than a free-text query. This search type is not currently supported.
- English only: The server searches the English index (
indexLang=en).
License
MIT











