loading…
Search for a command to run...
loading…
Validates legal citations against the CourtListener database to detect hallucinated citations in legal documents.
Validates legal citations against the CourtListener database to detect hallucinated citations in legal documents.
A Model Context Protocol (MCP) server for validating legal citations against the CourtListener database. Its primary use case is detecting AI-generated hallucinated citations in legal briefs and documents. Uses a local eyecite pass to inventory all citation types first, then a 3-tool fallback chain against the CourtListener API for case citation validation.
Platform Support Python API License: MIT
| Document | Description |
|---|---|
| 📥 Installation Guide | Complete cross-platform setup with automated scripts |
| 📖 Usage Examples | Workflows, fallback chain examples, and cross-MCP integration patterns |
| 🎯 Prompt Templates | Ready-to-use prompt templates for brief audits, hallucination triage, and pre-filing checklists |
| 🛡️ Security Scanning | Automated secret detection and prompt injection protection guide |
| 🏢 Enterprise Gateway Deployment | Multi-user deployment via Bifrost, Azure APIM, or Microsoft MCP Gateway — per-user API keys, Entra ID SSO, bulk provisioning |
| ⚖️ License | MIT License terms and conditions |
Citation validation of Mata v. Avianca. The MCP detects which citations are real, which are fabricated, and which resolve to the wrong case entirely.
https://github.com/user-attachments/assets/d1ba1b95-4bfe-4749-8ae7-a1255946e949
Prerequisites: Docker Desktop (or Docker Engine)
# 1. Clone the repo
git clone https://github.com/john-walkoe/courtlistener_citations_mcp.git
cd courtlistener_citations_mcp
# 2. Create a .env file with your CourtListener API token
# (free token at https://www.courtlistener.com/sign-in/)
echo COURTLISTENER_API_TOKEN=your_40_char_hex_token_here > .env
# 3. Start the server
docker compose up -d
# Verify it's running
curl http://localhost:8000/health
Claude Desktop config (%APPDATA%\Claude\claude_desktop_config.json):
{
"mcpServers": {
"courtlistener_citations": {
"command": "npx",
"args": ["mcp-remote", "http://localhost:8000/mcp"]
}
}
}
The
.envfile is gitignored. Never commit it. See.env.examplefor reference.
Note: STDIO mode is fully supported, including the interactive MCP App panel — color-coded citation cards render inline in Claude Desktop without Docker. DPAPI/Credential Manager secure token storage is Windows STDIO only.
Run PowerShell as Administrator, then:
# Navigate to your user profile
cd $env:USERPROFILE
# If git is installed:
git clone https://github.com/john-walkoe/courtlistener_citations_mcp.git
cd courtlistener_citations_mcp
# If git is NOT installed:
# Download and extract the repository to C:\Users\YOUR_USERNAME\courtlistener_citations_mcp
# Then navigate to the folder:
# cd C:\Users\YOUR_USERNAME\courtlistener_citations_mcp
# The script detects if uv is installed and if it is not it will install uv - https://docs.astral.sh/uv
# Run setup script (sets execution policy for this session only):
Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope Process
.\deploy\windows_setup.ps1
The PowerShell script will:
STDIO mode (no MCP App panel in Claude Desktop — text results only):
{
"mcpServers": {
"courtlistener_citations": {
"command": "uv",
"args": [
"--directory",
"C:/Users/YOUR_USERNAME/courtlistener_citations_mcp",
"run",
"courtlistener-mcp"
],
"env": {
"COURTLISTENER_API_TOKEN": "your_40_char_hex_token_here"
}
}
}
}
HTTP mode (via mcp-remote):
{
"mcpServers": {
"courtlistener_citations": {
"command": "npx",
"args": [
"mcp-remote",
"http://localhost:8000/mcp/"
]
}
}
}
Note: When using secure storage (Windows), the
envblock can be omitted entirely - the token is loaded automatically from Windows Credential Manager (or the DPAPI-encrypted file fallback) at runtime.
Claude Code — Docker/HTTP mode (via mcp-remote, no dev tunnel):
Add to .claude.json in your project root or ~/.claude.json globally:
{
"mcpServers": {
"courtlistener_citations": {
"command": "npx",
"args": [
"mcp-remote",
"http://localhost:8000/mcp"
]
}
}
}
Requires the Docker container to be running (
docker compose up -d) and the.envfile to containCOURTLISTENER_API_TOKEN. No token is needed in the JSON config itself — the container handles auth internally.
~/.courtlistener_citations_mcp/logs/wait_until parsing on 429 responsesAuthorization: Bearer (self-hosted) or X-CourtListener-Token (gateway-injected). See MCP_GATEWAY.md for Bifrost/APIM deployment.User requests:
LLM performs the 4-step workflow:
Step 0: courtlistener_extract_citations (DISCOVERY) - Runs eyecite locally to inventory ALL citation types in the document — case, statutory, law journal, id., supra. Free (no API), instant, no rate limits.
Step 1: courtlistener_validate_citations (PRIMARY) - Validate all case citations against CourtListener API using the eyecite parser
Step 2: courtlistener_search_cases (FALLBACK) - For any citations returning 404, search by case name to verify the case exists
Step 3: courtlistener_lookup_citation (LAST RESORT) - Direct reporter citation lookup when other methods fail
| Tool | Purpose | Use Case |
|---|---|---|
courtlistener_extract_citations |
Extract all citation types locally via eyecite | STEP 0 - Full census before API calls; identifies case, statute, journal, id., supra |
| Tool | Purpose | Use Case |
|---|---|---|
courtlistener_validate_citations |
Extract & validate all case citations from text | PRIMARY - Paste full document text |
courtlistener_search_cases |
Search by case name, court, date, query | FALLBACK - When citation returns 404 |
courtlistener_lookup_citation |
Direct reporter citation lookup | LAST RESORT - Direct citation search |
| Tool | Purpose | Use Case |
|---|---|---|
courtlistener_get_cluster |
Get full case details and CourtListener URLs | Deep dive into a specific case |
courtlistener_search_clusters |
Search opinion clusters with filters | Filtered search by judge, court, docket |
courtlistener_citations_get_guidance |
Workflow guidance and documentation (no API call) | Help with workflows and risk assessment |
This MCP supports Claude Code's built-in tool search optimization, reducing context window usage through dynamic tool discovery.
Always-Available Tools (loaded immediately — non-deferred):
courtlistener_validate_citations - Primary citation validationcourtlistener_citations_get_guidance - Workflow guidance and documentationDiscovered On-Demand (deferred — searched via BM25):
3. courtlistener_extract_citations - Local citation discovery (eyecite, no API)
4. courtlistener_search_cases - Fallback search by case name
5. courtlistener_get_cluster - Case details and CourtListener URLs
6. courtlistener_search_clusters - Filtered cluster search
7. courtlistener_lookup_citation - Direct citation lookup
Use courtlistener_citations_get_guidance(section) with these sections:
| Section | When to Use |
|---|---|
overview |
What this MCP does and quick-start workflow |
workflow |
Full discovery + 3-tool fallback chain explained |
response_format |
How to format results with ✅⚠️❌ symbols |
hallucination_patterns |
Common AI hallucination detection patterns |
edge_cases |
SCOTUS parallel citations, state courts, unpublished opinions |
risk_assessment |
How to interpret validation results |
limitations |
CourtListener coverage gaps and false negatives |
| Mode | Use Case | MCP App Panel | Auth / Token Storage | Configuration |
|---|---|---|---|---|
| STDIO | Claude Desktop, Claude Code (single user) | ✅ Full panel | Windows Credential Manager + DPAPI (Windows) or env var | Default |
| HTTP (Docker/direct) | CoPilot Studio, web clients, single-host remote | ✅ Full panel | COURTLISTENER_API_TOKEN in .env or Authorization: Bearer header |
TRANSPORT=http |
| HTTP (Gateway) | Law firm / enterprise, multi-user, Entra ID SSO | ❌ Panel not rendered through proxy | Per-user via X-CourtListener-Token injected by gateway (Bifrost, APIM) |
See MCP_GATEWAY.md |
MCP App panel renders interactive color-coded citation cards inline in Claude Desktop. Works in STDIO and direct HTTP mode. Does not render when proxied through any gateway — but the tool's structured output and prompt engineering guide the LLM to produce an equivalent in-conversation report without the panel.
Per-user rate limiting: In gateway deployments, each user's CourtListener API key gets its own 60-citation/min bucket. A shared circuit breaker reflects overall CourtListener API health without affecting per-user limits. See MCP_GATEWAY.md for architecture details.
DPAPI / Windows Credential Manager secure storage is only available in STDIO mode on Windows. Docker containers run Linux and cannot access Windows Credential Manager — use a
.envfile instead.
# Direct
set TRANSPORT=http
set PORT=8000
courtlistener-mcp
# Via uvicorn
uvicorn courtlistener_mcp.main:app --host 0.0.0.0 --port 8000
# Via Docker
docker compose up -d
# MCP endpoint: http://localhost:8000/mcp
# Health check: http://localhost:8000/health
Docker containers run Linux and cannot access Windows Credential Manager or DPAPI. The token must be provided via a .env file in the project root:
# .env (only this one variable is needed — TRANSPORT, HOST, PORT are hardcoded in docker-compose.yml)
COURTLISTENER_API_TOKEN=your_40_char_hex_token_here
Note: The
.envfile is gitignored. Never commit it. The.env.exampletemplate is provided for reference.
⚠️ Corporate & Regulatory Policy Notice
Dev tunnels create a publicly accessible endpoint for your local server. Before using this feature, you must:
- Consult your organization's IT security policy. Many law firms, corporations, and government entities prohibit or restrict the use of development tunnels, reverse proxies, and other tools that bypass network perimeter controls on managed devices or corporate networks.
- Check your bar association's ethics rules. Attorney obligations regarding client data confidentiality (Model Rules 1.6, 1.15) may impose additional constraints on transmitting client documents through third-party relay infrastructure.
- Do not use this feature on managed/corporate hardware without explicit written approval from your IT/security team.
- Do not use this feature for production deployments. Dev tunnels are intended for development and testing only. For production external access, use a properly secured reverse proxy (e.g., nginx with TLS) or a cloud-hosted deployment.
If in doubt, ask your IT department first.
For external access (CoPilot Studio, Claude.ai), use the dev tunnel launcher script. It starts the HTTP server locally and creates a Microsoft Dev Tunnel to expose it publicly.
Prerequisites: devtunnel.exe (download) and devtunnel user login
# Temporary tunnel (URL changes each time)
.\deploy\start_devtunnel.ps1
# Custom port
.\deploy\start_devtunnel.ps1 -Port 8889
# Persistent tunnel (URL stays the same across restarts)
.\deploy\start_devtunnel.ps1 -Persistent
The script will:
devtunnel.exe if not found, and add Windows Firewall rules automatically (requires Admin)https://<tunnel>.devtunnels.ms/mcp)Use the displayed tunnel URL as your MCP endpoint in CoPilot Studio or Claude.ai.
=== CourtListener MCP - Dev Tunnel Launcher ===
[OK] devtunnel: C:\Users\...\courtlistener_citations_mcp\devtunnel.exe
[OK] Firewall rule exists for devtunnel.exe
[OK] Logged in as [email protected] using Microsoft.
How is the MCP server running?
[1] Docker (already running via 'docker compose up -d')
[2] Local Python (start it now via uv/venv)
Enter choice (1 or 2, default is 1): 1
Port the server is/will run on (default: 8000):
[INFO] Docker mode - checking container health on port 8000...
[OK] Docker container healthy at http://localhost:8000
Health: http://localhost:8000/health
MCP: http://localhost:8000/mcp
[INFO] Starting temporary dev tunnel on port 8000...
========================================
Tunnel is starting...
Look for the URL below (*.devtunnels.ms)
Your MCP endpoint will be:
<tunnel-url>/mcp
For CoPilot Studio or Claude.ai, use:
https://<tunnel-subdomain>.devtunnels.ms/mcp
Press Ctrl+C to stop tunnel and server
========================================
Hosting port: 8000
Connect via browser: https://3tgxrktm.usw3.devtunnels.ms:8000, https://3tgxrktm-8000.usw3.devtunnels.ms
Inspect network activity: https://3tgxrktm-8000-inspect.usw3.devtunnels.ms
Ready to accept connections for tunnel: quick-pond-mprv3rk.usw3
MCP endpoint: https://3tgxrktm-8000.usw3.devtunnels.ms/mcp
Note: Temporary tunnel URLs change every run. Use
-Persistentfor a stable URL across restarts.
Getting devtunnel working on a hardened network required clearing multiple independent layers. If your tunnel fails with a connection timeout to global.rel.tunnels.api.visualstudio.com:443, work through this checklist:
1. Windows Firewall
The script automatically checks and adds outbound/inbound rules for devtunnel.exe. Run PowerShell as Administrator on the first run so it can create the rules. Verify with:
Get-NetFirewallApplicationFilter -Program "C:\path\to\devtunnel.exe"
2. Pi-hole / DNS sinkhole If you run Pi-hole or similar DNS blocking, add these to your allowlist:
(\.|^)devtunnels\.ms$(\.|^)visualstudio\.com$(\.|^)microsoftonline\.com$(\.|^)live\.com$3. Allow Outbound to Microsoft
The devtunnel relay uses Microsoft Azure US West IPs (20.125.0.0/16). If a firewall is blocking outbound traffic, add 20.125.0.0/16 to your Firewall's allow outbound list and Update.
5. Test connectivity before running the script
Test-NetConnection global.rel.tunnels.api.visualstudio.com -Port 443
# TcpTestSucceeded : True <-- required before devtunnel will work
| Limit | Value | Scope |
|---|---|---|
| General requests | 5,000 / hour | All endpoints |
| Citation-lookup throttle | 60 valid citations / minute | /citation-lookup/ only |
| Citations per request | 250 max | /citation-lookup/ only |
| Text per request | 64,000 chars (~50 pages) | /citation-lookup/ only |
Key distinction: the 60/min throttle counts valid citations (status 200 or 300), not requests. A single brief with 60 real cases consumes the entire minute's quota in one call. Invalid reporters and 404s do not count against the limit.
The client uses two token-bucket rate limiters:
floor(5000 ÷ 60)), keeping sustained throughput safely under the 5,000/hr capWhen the API returns HTTP 429, the response includes a wait_until ISO-8601 timestamp. The client parses that and waits precisely the right amount of time before retrying — no guessing, no wasted sleep.
The tool docstring is read by the LLM before it writes the tool call. The courtlistener_validate_citations docstring contains explicit guidance on how to handle documents with many citations — when to call once vs. when to split by section. This means:
In short: slightly longer time before the first tool call → much shorter total wall-clock time for large documents.
https://www.courtlistener.com/api/rest/v4Authorization: Token {token} (NOT Bearer)User-Agent header| Endpoint | Method | Purpose |
|---|---|---|
/citation-lookup/ |
POST | Validate citations from text (eyecite) |
/search/?type=o |
GET | Search opinions by name, court, citation |
/clusters/{id}/ |
GET | Get opinion cluster details |
| ID | Court |
|---|---|
scotus |
Supreme Court |
cafc |
Federal Circuit |
ca1 - ca11 |
Circuit Courts 1-11 |
cadc |
DC Circuit |
dcd |
District of Columbia |
COURTLISTENER_API_TOKEN environment variable ← Docker / all platformskeyring library) ← Windows STDIO only~/.courtlistener_api_token) ← Windows STDIO fallback (auto-migrated to Credential Manager on first access)Docker users: Only option 1 applies. Set
COURTLISTENER_API_TOKENin your.envfile. Options 2–4 require a native Windows process and are not available inside a Linux container.
# Store token securely (Credential Manager + DPAPI backup)
.\deploy\windows_setup.ps1
# Check stored token
.\deploy\manage_api_keys.ps1 -Action check
# Test API connection
.\deploy\manage_api_keys.ps1 -Action test
# Delete stored token
.\deploy\manage_api_keys.ps1 -Action delete
| Variable | Required | Default | Description |
|---|---|---|---|
COURTLISTENER_API_TOKEN |
Yes* | None | API token (*or use DPAPI storage) |
TRANSPORT |
No | stdio |
Transport mode: stdio or http |
HOST |
No | 0.0.0.0 |
HTTP server bind address |
PORT |
No | 8000 |
HTTP server port |
LOG_LEVEL |
No | INFO |
Logging level |
CORS_ORIGINS |
No | http://localhost:8080,... |
Comma-separated CORS allowed origins (HTTP mode) |
CORS_EXTRA_ORIGIN |
No | None | Single extra CORS origin to append (e.g. https://claude.ai for direct claude.ai connector) |
INTERNAL_AUTH_SECRET |
No | None | Shared secret for endpoint auth. If set, all non-health requests must include x-api-key: <secret>. Omit to run unauthenticated (dev/trusted environments). |
This MCP is designed to complement other legal research MCP servers:
| MCP Server | Purpose | GitHub Repository |
|---|---|---|
| CourtListener Citation Validation | Citation validation & hallucination detection | courtlistener_citations_mcp |
| USPTO Patent File Wrapper (PFW) | Patent prosecution history & documents | uspto_pfw_mcp |
| USPTO Patent Trial and Appeal Board (PTAB) | Post-grant challenges (IPR/PGR/CBM) | uspto_ptab_mcp |
| USPTO Final Petition Decisions (FPD) | Petition decisions during prosecution | uspto_fpd_mcp |
| USPTO Enriched Citation | AI-extracted citation intelligence from Office Actions | uspto_enriched_citation_mcp |
| Pinecone Assistant MCP | Patent law knowledge base (MPEP, examination guidance) | pinecone_assistant_mcp |
| Pinecone RAG MCP | Patent law knowledge base with custom embeddings | pinecone_rag_mcp |
courtlistener_citations_mcp/
├── pyproject.toml # FastMCP 3.0 beta 2, httpx, pydantic-settings
├── .env.example # Template for env vars
├── Dockerfile # Python 3.11-slim, STDIO default (HTTP via TRANSPORT=http)
├── docker-compose.yml # Single service, port 8000
├── CLAUDE.md # Claude Code guidance
├── README.md # This file
├── src/
│ └── courtlistener_mcp/
│ ├── __init__.py
│ ├── __main__.py # python -m courtlistener_mcp
│ ├── main.py # FastMCP server + 7 tools + health check + MCP Apps
│ ├── api/
│ │ └── client.py # CourtListenerClient (httpx async, rate limiting, retry)
│ ├── config/
│ │ ├── settings.py # Pydantic settings + Credential Manager + DPAPI fallback
│ │ ├── api_constants.py # No magic numbers
│ │ ├── tool_guidance.py # Sectioned guidance (7 sections, 80-95% token reduction)
│ │ └── log_config.py # File-based logging with rotation
│ ├── shared/
│ │ ├── dpapi_crypto.py # DPAPI encryption (Windows only)
│ │ ├── secure_storage.py # Unified API token storage
│ │ ├── log_sanitizer.py # Automatic sensitive data sanitization
│ │ └── safe_logger.py # SafeLogger with auto-sanitization
│ ├── prompts/
│ │ ├── __init__.py
│ │ └── validate_legal_brief.py # Full citation audit prompt (Step 0 + 3-tool chain)
│ └── ui/
│ └── citation_view.py # MCP Apps interactive citation results UI
├── skill/
│ └── courtlistener-citation-validator/
│ └── SKILL.md # Claude Code skill: validate citations in legal documents
├── deploy/
│ ├── windows_setup.ps1 # Full Windows deployment (uv, venv, token, Claude Desktop)
│ ├── manage_api_keys.ps1 # Token management (check/test/delete)
│ └── start_devtunnel.ps1 # Dev tunnel launcher for CoPilot Studio / Claude.ai
└── tests/
├── conftest.py # Shared fixtures (api_client, sample responses, global reset)
├── unit/
│ ├── test_client.py # RateLimiter, chunking, throttle parsing, HTTP errors,
│ │ # citation validation, security logging
│ ├── test_extract_citations.py # eyecite extraction: all citation types, id/supra resolution,
│ │ # empty text guard, async JSON return
│ ├── test_log_sanitizer.py # Token masking, ANSI/injection filtering, truncation
│ └── test_secure_storage.py # Keyring exception handling, token storage/migration
└── integration/
└── test_mcp_tools.py # _handle_client_errors, client reset on auth failure,
# concurrent init single-instance guarantee
Runtime Generated Files (not in repo):
~/.courtlistener_citations_mcp/
├── logs/
│ ├── courtlistener_citations_mcp.log # Application logs (10MB rotation, 5 backups)
│ └── security.log # Security events (10MB rotation, 10 backups)
└── .courtlistener_api_token # Encrypted API token (DPAPI, Windows only)
ToolError: CourtListener API token not configuredCOURTLISTENER_API_TOKEN env var, run .\deploy\windows_setup.ps1, or let elicitation prompt youThe "COURTLISTENER_API_TOKEN" variable is not set. Defaulting to a blank string. in docker compose up output.env file in the project root containing COURTLISTENER_API_TOKEN=your_token, then docker compose down && docker compose up -dBind for 0.0.0.0:8000 failed: port is already allocateddocker stop <name>), then docker compose up -d — do not use docker start on a previously-failed container as it won't get the port bindinghttps://www.courtlistener.com/api/rest/v4Bearer instead of TokenAuthorization: Token {key} (NOT Bearer {key})courtlistener_search_cases with the case namewindows_setup.ps1.venv files when running.venv folder: Remove-Item ./.venv -Force -Recurse -ErrorAction SilentlyContinue.\deploy\windows_setup.ps1 again# Navigate to the project directory
cd C:\Users\YOUR_USERNAME\courtlistener_citations_mcp
# Remove Python cache directories
Get-ChildItem -Path ./src -Directory -Recurse -Force | Where-Object { $_.Name -eq '__pycache__' } | Remove-Item -Recurse -Force
# Remove virtual environment
if (Test-Path ".venv") {
Remove-Item ./.venv -Force -Recurse -ErrorAction SilentlyContinue
}
# Now you can run the setup script again
.\deploy\windows_setup.ps1
keyring) as the primary secure store, with a DPAPI-encrypted file fallback (user-specific encryption + 256-bit entropy). Tokens are automatically migrated from file to Credential Manager on first access.Token <hex> auth headers, passwords, IPs, and emails in all log messages (CWE-532)User-Agent header - Identifies the MCP to CourtListenerINTERNAL_AUTH_SECRET to require an x-api-key header on all non-health requests. Leave unset for open access (local dev, trusted internal networks). In gateway deployments, the gateway injects x-api-key at the proxy layer so clients do not need to configure the header manually.MIT License
THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND.
Independent Project Notice: This is an independent personal project and is not affiliated with, endorsed by, or sponsored by Free Law Project or CourtListener.
The author makes no representations or warranties, express or implied, including but not limited to:
LIMITATION OF LIABILITY: Under no circumstances shall the author be liable for any direct, indirect, incidental, special, or consequential damages arising from use of this software, even if advised of the possibility of such damages.
By using this software, you acknowledge that you have read this disclaimer and agree to use the software at your own risk, accepting full responsibility for all outcomes.
Note for Legal Professionals: While this tool validates citations against the CourtListener database, a "valid" result only confirms the citation exists in CourtListener's index - it does not verify that the citation supports the legal proposition for which it is cited. Professional analysis is always required.
If you find this CourtListener Citation Validation MCP Server useful, please consider supporting the development!
Your support helps maintain and improve this open-source tool. Thank you!
courtlistener_extract_citationsQuestions? Review the troubleshooting section above, use courtlistener_citations_get_guidance(section='overview') for workflow help, or check .\deploy\manage_api_keys.ps1 -Action test to verify your API connection.
Выполни в терминале:
claude mcp add courtlistener-citation-validation-mcp-server -- npx Query your database in natural language
автор: AnthropicRead-only database access with schema inspection.
автор: modelcontextprotocolInteract with Redis key-value stores.
автор: modelcontextprotocolDatabase interaction and business intelligence capabilities.
автор: modelcontextprotocolНе уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории data