A Model Context Protocol (MCP) server for structured legal workflows. This legal MCP server provides tools, resources, and prompts for precedent retrieval, statute analysis, citation validation, contract clause comparison, and guided brief scaffolding. Production mode is the default: bundled sample legal content is disabled, while real-document tools and optional opt-in live legal databases remain available.
This server provides legal‑workflow augmentation, not legal advice. It does not replace attorney review and judgment.
- Status: V1 — implemented and tested.
- Transport: stdio, SSE, and streamable‑HTTP (via FastMCP).
- Runtime: Python 3.10+ and the official
mcpSDK.
- Data flow & privacy boundaries
- PACER and paid‑database fees (read first)
- Quick start
- Capabilities
- Feature flags (tool categories)
- Live integrations (PACER & CourtListener/RECAP)
- Docker (optional)
- Use as an Agent Skill (Claude, Cursor, Codex, and more)
- Built on legal-mcp (showcase)
- Forking & building your own
- Architecture
- Testing, linting & types
- Legal & compliance notes
- AI agent privacy considerations
- Further reading
- Integration & development support
- License
Understanding where data goes is essential before connecting this server to an AI assistant or enabling live integrations. The diagram below shows the three separate trust boundaries involved in a typical workflow.
flowchart LR
user[User]
aiClient[AI Assistant]
inference[Inference Provider]
mcpServer[Legal MCP Server]
localData[Real local files]
demoData[Opt-in demo content]
courtlistener[CourtListener / RECAP]
pacer[PACER]
user -->|"prompts and documents"| aiClient
aiClient -->|"full conversation context"| inference
aiClient <-->|"MCP tool calls and JSON responses"| mcpServer
mcpServer -->|"local processing"| localData
mcpServer -.->|"explicit demo mode"| demoData
mcpServer -.->|"opt-in, free"| courtlistener
mcpServer -.->|"opt-in, billable"| pacer
| Boundary | What crosses it | Default behavior | Privacy note |
|---|---|---|---|
| You → AI assistant | Prompts, uploaded files, tool results pasted into chat | Always active when using an AI client | Your inference provider's ToS governs retention, training, and privilege — not this server |
| AI assistant → MCP server | Tool arguments (file paths, queries, contract IDs) and JSON responses | Local transport (stdio/SSE/HTTP on your machine) | Tool calls are audit-logged locally (utils.audit); responses stay on your network unless you expose the server |
| MCP server → external databases | Search queries to CourtListener or PACER | Disabled by default | Enable only when needed; PACER may incur fees (see below) |
Key takeaway: this MCP server performs local document workflows offline by
default. It does not expose the bundled sample cases, statutes, or contracts
unless LEGAL_MCP_DEMO_MODE=true is explicitly set.
The highest privacy risk in most setups is the inference provider (OpenAI,
Anthropic, Google, OpenRouter, etc.) receiving your full prompt context —
including excerpts returned by these tools. See
AI agent privacy considerations for
provider-specific guidance.
If you connect this MCP (or an AI assistant using it) to PACER or other paid legal databases, you are responsible for all charges incurred on your account. PACER bills per page, per document, or per search. AI agents can issue many requests in minutes; in real‑world testing a short (~10 minute) agent session nearly exhausted a standard PACER account's $30 per quarter fee waiver.
To protect you from surprise fees, every live integration in this server is disabled by default and must be explicitly enabled with a feature flag and credentials (see Live integrations). Prefer the free CourtListener / RECAP source over PACER wherever possible.
For official PACER billing rules, see pacer.gov.
| Folder | Purpose |
|---|---|
tools/ |
MCP tool implementations (27 tools across 8 categories) |
resources/ |
MCP resource endpoints (legal:// URIs) |
prompts/ |
Workflow prompt templates (8 prompts) |
data/ |
Offline JSON seed data (cases, statutes, contracts, templates, citations) |
integrations/ |
Optional live integrations (CourtListener/RECAP, PACER) — disabled by default |
tests/ |
pytest test suite (unit + integration) |
.agents/ |
Vendor-agnostic agent skills (legal-mcp-toolkit) |
# 1. Install dependencies (uses your user site-packages; a venv also works)
pip install -r requirements.txt
# 2. Run the server (SSE transport on http://127.0.0.1:8000/sse by default)
python main.py
# 3. (Optional) Explore it in the MCP Inspector
npx @modelcontextprotocol/inspector
# In the Inspector: Transport = SSE, URL = http://127.0.0.1:8000/sse, Connect.Run over a different transport:
python main.py --transport stdio # for Claude Desktop / CLI clients
python main.py --transport streamable-http # modern HTTP transport
python main.py --transport sse --port 9000 # custom portAll flags also read from environment variables: MCP_TRANSPORT, HOST,
PORT, LOG_LEVEL.
Bundled cases, statutes, and sample contracts are disabled by default. To use them for demonstrations or tests:
export LEGAL_MCP_DEMO_MODE=true
python main.pyOn startup the server emits a warning, and every demo-derived payload begins
with warning and data_mode: "demo". Demo case matches are not citation
verification and must not be presented as real or current legal authority.
The server exposes a module‑level mcp object, so you can load it with the
MCP CLI:
mcp dev main.py:mcp # launches the Inspector wired to this server
mcp run main.py:mcp # runs the server via the CLI| Category | Tool | Purpose |
|---|---|---|
| Research | search_precedents |
Keyword‑ranked precedent search over local cases |
| Research | search_case_law |
Case‑law search with relevance ranking and summaries |
| Research | extract_statute |
Statute text with optional legislative context |
| Research | research_legal_issue |
Multi‑source research across local cases, statutes, and CourtListener |
| Citation | validate_citation |
Validate structure and reporter format; does not establish existence or good-law status |
| Citation | normalize_citation |
Normalize spacing + Bluebook‑style abbreviations |
| Citation | check_demo_database |
Check whether a citation appears in explicitly enabled demo case data |
| Contract | compare_contracts |
Clause‑level differ with risk flags |
| Contract | analyze_clauses |
Rule‑based clause risk analysis; includes missing_clauses on full‑contract runs |
| Contract | extract_clauses |
Template‑filtered clause extraction |
| Contract | suggest_clause_alternatives |
Curated alternative phrasings for risky clauses |
| Contract | generate_negotiation_guide |
Per‑clause accept/negotiate/reject guide with fallback language and missing_clauses |
| Contract | deep_analyze_clause |
Keyword heuristics plus optional MCP LLM sampling for deeper reasoning (falls back when the client lacks sampling support) |
| Document | analyze_document |
Risk analysis for real .docx / .txt files; optional contract_type enables missing_clauses |
| Document | compare_documents |
Clause‑level diff for real .docx / .txt files |
| Document | export_analysis_report |
Export a formatted .docx risk report |
| Document | extract_contract_metadata |
Extract parties, dates, governing law, term, liability cap, and payment terms as structured JSON |
| Privilege | check_privilege_risk |
Assess AI routing risk for potentially privileged documents; references Heppner and ABA Rule 1.6 |
| Brief | generate_brief_outline |
Outline from a brief framework by case type |
| Brief | create_argument_structure |
IRAC‑style argument scaffold |
| Brief | generate_issue_statement |
Issue‑statement framework from facts + law |
| Analysis Queue | queue_document_analysis |
Queue a document for local AI risk analysis; returns a job ID |
| Analysis Queue | get_analysis_status |
Check status of a queued analysis job (queued/complete/error) |
| Analysis Queue | get_analysis_result |
Retrieve the completed analysis result for a job |
| Analysis Queue | list_analysis_jobs |
List all jobs with statuses and timestamps |
| Integrations | integration_status |
Report which live sources are enabled/configured |
| Integrations | search_live_case_law |
Query CourtListener/RECAP or PACER (when enabled) |
Demo mode includes 13 sample contract templates covering NDAs, MSAs, DPAs, HIPAA BAA, Terms of Use, Privacy Policy, Advisor Agreement, California Offer Letter, Post-Money SAFE, and Cookie Notice.
Static:
legal://server-config— enabled tool categories and feature‑flag env var names (always available)legal://case-database— precedent indexlegal://statute-library— statutory materials indexlegal://contract-templates— contract/template indexlegal://brief-frameworks— brief outline templateslegal://citation-standards— reporter + Bluebook reference datalegal://integrations— live‑integration status (feature flags/config)
Dynamic templates:
legal://case/{case_id}/analysislegal://statute/{statute_id}/contextlegal://contract/{contract_id}/differlegal://brief/{brief_id}/outline
precedent_analysis, statutory_interpretation, brief_construction,
argument_development, contract_review, clause_comparison,
citation_validation, authority_integration.
See WORKFLOW_EXAMPLES.md for end‑to‑end workflow
walkthroughs.
Every tool category is enabled by default. Set a LEGAL_MCP_ENABLE_*
environment variable to false before starting the server to disable an
entire category — its tools and matching resources will not be registered.
There is no hard floor: disabling every category yields a server with zero
tools (avoid this in production).
Check the current state at any time via the always‑on resource
legal://server-config.
| Category | Environment variable | What it controls |
|---|---|---|
| Research | LEGAL_MCP_ENABLE_RESEARCH |
search_*, extract_statute, research_legal_issue; case/statute resources |
| Citation | LEGAL_MCP_ENABLE_CITATION |
validate_citation, normalize_citation, check_demo_database |
| Contract | LEGAL_MCP_ENABLE_CONTRACT |
Contract tools including deep_analyze_clause; contract resources |
| Document | LEGAL_MCP_ENABLE_DOCUMENT |
analyze_document, compare_documents, export_analysis_report, extract_contract_metadata |
| Privilege | LEGAL_MCP_ENABLE_PRIVILEGE |
check_privilege_risk |
| Brief | LEGAL_MCP_ENABLE_BRIEF |
Brief tools; brief framework resources |
| Analysis Queue | LEGAL_MCP_ENABLE_ANALYSIS_QUEUE |
queue_document_analysis, get_analysis_status, get_analysis_result, list_analysis_jobs |
| Integrations | LEGAL_MCP_ENABLE_INTEGRATIONS |
integration_status, search_live_case_law; integration resources |
Example (disable the local analysis queue only):
export LEGAL_MCP_ENABLE_ANALYSIS_QUEUE=false
python main.pySee .env.example for a copy‑paste template including live
integration credentials.
LEGAL_MCP_DEMO_MODE is separate from category flags and defaults to false.
With demo mode off, seed-dependent tools and resources remain discoverable but
return error: "demo_data_disabled"; they never silently query a live source.
- Bundled cases, statutes, and sample contracts now require
LEGAL_MCP_DEMO_MODE=true. verify_citation_integritywas removed. Usecheck_demo_databaseonly for demo lookups; its fields arefound_in_demo_databaseandmatched_demo_case.validate_citationchecks citation structure and reporter formatting only. It does not prove that a case exists or remains good law.
Note on deep_analyze_clause: this tool uses MCP
sampling/createMessage to ask the connected client's LLM for deeper clause
reasoning. Most MCP clients (including Cursor and Claude Desktop) do not yet
advertise sampling support — in those environments the tool returns the same
keyword heuristics as analyze_clauses plus an explanatory note, not an error.
Live legal databases are optional and disabled by default. Each is controlled by a feature flag plus API credentials, all supplied via environment variables. Check the current state at any time:
# via the tool
search_live_case_law / integration_status
# or the resource
legal://integrationsintegration_status and the legal://integrations resource return only
booleans and non‑sensitive metadata — credentials are never echoed back.
CourtListener exposes a free, rate‑limited REST API
(v4) that also serves the
RECAP Archive of PACER documents. Authentication is
an Authorization: Token <token> header.
| Variable | Default | Description |
|---|---|---|
COURTLISTENER_ENABLED |
false |
Feature flag to enable the integration |
COURTLISTENER_API_TOKEN |
(unset) | Token from your CourtListener profile |
COURTLISTENER_BASE_URL |
https://www.courtlistener.com/api/rest/v4 |
Override for testing |
export COURTLISTENER_ENABLED=true
export COURTLISTENER_API_TOKEN="your-token-here" # https://www.courtlistener.com/profile/api/
python main.pyPACER uses a two‑step flow described in the PACER Authentication API User Guide:
- Authenticate —
POST {auth}/services/cso-authwith yourloginIdandpassword(and optional client code / TOTP passcode). Returns anextGenCSOtoken. - Search — reuse the
nextGenCSOtoken as a cookie against the PACER Case Locator (PCL) API.
Per PACER guidance the token is reused across requests (the client caches it); it does not re‑authenticate on every call.
| Variable | Default | Description |
|---|---|---|
PACER_ENABLED |
false |
Feature flag to enable the integration |
PACER_ENVIRONMENT |
qa |
qa (non‑billable test) or production (billable) |
PACER_LOGIN_ID |
(unset) | PACER username |
PACER_PASSWORD |
(unset) | PACER password |
PACER_CLIENT_CODE |
(unset) | Optional client/billing code |
PACER_OTP_SECRET |
(unset) | Optional base32 TOTP secret if 2FA is enabled |
export PACER_ENABLED=true
export PACER_ENVIRONMENT=qa # start with the non-billable QA env
export PACER_LOGIN_ID="your-username"
export PACER_PASSWORD="your-password"
python main.pyRegister for a non‑billable QA account at qa-pacer.uscourts.gov to test safely. Production accounts are billable. See the developer resources.
Copy .env.example to .env for a template of all settings.
# Build and run over SSE at http://localhost:8000/sse
docker compose up --buildEnable integrations by exporting variables (or using a .env file next to
docker-compose.yml) before docker compose up:
COURTLISTENER_ENABLED=true COURTLISTENER_API_TOKEN=... docker compose up --buildOr with plain Docker:
docker build -t legal-mcp .
docker run --rm -p 8000:8000 \
-e COURTLISTENER_ENABLED=true -e COURTLISTENER_API_TOKEN=... \
legal-mcpMCP and Agent Skills are complementary, not
competing: MCP is the execution layer (the 27 tools this server exposes),
while a Skill is the methodology layer — a portable SKILL.md file that
teaches an agent which tools to chain, in what order, and what to
surface to the user for a given task. Connecting the MCP server alone gives
an agent tools without a playbook; the skill is the playbook. Agent Skills
are an open, vendor‑neutral standard — the same SKILL.md works unchanged
across Claude Code, Cursor, Codex CLI, Gemini CLI, and other compliant
agents.
This repo ships one at
.agents/skills/legal-mcp-toolkit/SKILL.md —
the emerging cross‑agent convention for project‑level skills (recognized
natively by Cursor, Codex CLI, and Gemini CLI; Claude Code can load it via
its skills installer, or you can symlink/copy it into .claude/skills/). It
encodes eight workflow patterns (contract risk triage, negotiation prep,
metadata lookup, privilege-safe AI review, legal research, brief drafting,
citation cleanup, and batch analysis) as tool-call sequences, so an agent
with this server connected knows how to combine tools instead of guessing.
To use it:
- Automatically, if you clone or fork this repo — compliant agents
discover project skills under
.agents/skills/(or their own vendor‑specific path) for anyone working in the repository. - In another project, copy the
legal-mcp-toolkit/directory into that project's.agents/skills/(or your personal~/.agents/skills/) alongside connecting this MCP server, so the guidance travels with you.
See the Agent Skills specification for the full open standard this skill follows.
Want to see what a full product looks like on top of this MCP server? Legal Terminal is a reference showcase application — a Bloomberg-style, keyboard-first legal workstation with two front ends (a React web terminal and a Python TUI) that call the same 27 tools this server exposes.
| Live demo | legal-terminal.up.railway.app — runs in mock mode by default; no backend required |
| Source | github.com/genego-io/legal-terminal — viewing for evaluation; proprietary license (not AGPL) |
The demo is intentionally mock-ready: panels work offline with fixture
data so you can explore the UX immediately. Toggle Live in the status bar
(or wire up LiveClient in the repo) to connect to a running legal-mcp
instance over SSE and exercise real tool calls.
What it demonstrates
- Multi-panel workflows — precedent search (
PREC), statute viewer (STAT), citation console (CITE), contract workbench (CTRX), document analyzer (DOCA), privilege check (PRIV), brief builder (BRF), analysis queue (JOBS), integration status (LIVE), and more — each mapped to MCP tools by name. - Paralegal chat (F1) — conversational layer over
research_legal_issue,validate_citation,generate_brief_outline, and related tools. - Agent Skill in the UI — the
WKFLpanel surfaces the samelegal-mcp-toolkitworkflow playbooks as runnable checklists. - Privacy posture —
CONF(Confidential Mode) andPRIVpanels illustrate routing sensitive matter data throughcheck_privilege_riskand local-only inference options. - Keyboard-first UX — Ctrl+K command palette, mnemonic command bar
(
PREC breach of contract,CITE 2022 Cal.App.4th 1234), and F-key module shortcuts — the kind of density-focused interface you can build once tools are standardized behind MCP.
Legal Terminal is maintained separately as a showcase (not a submodule of this repo). Clone it to study client architecture, panel design, and mock/live client patterns; fork this repo to extend the MCP server itself.
This project is designed to be forked and extended, including by AI coding assistants:
- Predictable structure. Tools live in
tools/, resources inresources/, prompts inprompts/, integrations inintegrations/, and all seed data indata/. Each module exposes aregister_*function and is wired up centrally (tools/__init__.py,resources/__init__.py,prompts/__init__.py). - Deterministic + offline by default. No hidden network calls; live sources are opt‑in.
AGENTS.mddocuments how to run, test, and extend the server so an agent can navigate the repo quickly.
# tools/my_tools.py
import json
from utils import audit, get_data_manager
def register_my_tools(mcp):
data = get_data_manager()
@mcp.tool()
def my_tool(param: str) -> str:
"""Describe the legal intent clearly."""
audit("my_tool", param=param)
return json.dumps({"result": param}, indent=2)Then call register_my_tools(mcp) from tools/__init__.py. Resources and
prompts follow the same pattern with @mcp.resource(uri) and @mcp.prompt().
legal-mcp/
├── main.py # FastMCP server entry point (exposes `mcp`)
├── utils.py # LegalDataManager + CitationParser + audit log
├── tools/ # MCP tools (research, citation, contract, brief, integrations)
├── resources/ # MCP resources (case, statute, contract, brief, integrations)
├── prompts/ # MCP prompts (research, drafting, analysis, argument)
├── integrations/ # Optional live sources (config, courtlistener, pacer)
├── data/ # Seed data (cases, statutes, contracts, templates, citations)
├── tests/ # Unit + integration tests
├── Dockerfile # Optional container image
├── docker-compose.yml # Optional compose setup
└── requirements.txt # Dependencies
The server initializes a FastMCP instance, registers all tools, resources,
and prompts, logs an audit trail, and runs the selected transport.
pip install -r requirements.txt
pytest # run the full unit + integration suite
pytest --cov=. --cov-report=term-missing
python -m black . # format
python -m flake8 . # lint
python -m mypy . # type-checkIntegration tests exercise tools, resources, and prompts through the
in‑memory FastMCP API. The live integrations are tested with an
httpx.MockTransport so no real network calls are made.
If the
pytest,black, etc. scripts are not on yourPATHafter apip install --user, invoke them viapython -m <tool>as shown above.
- Audit trails. Every tool/resource call emits a structured audit log
entry (
utils.audit). - Deterministic core. Local data operations are reproducible and make no hidden network calls.
- Opt‑in external data. PACER and CourtListener are disabled until you enable them; PACER may incur fees.
- Not legal advice. Output is a scaffold for attorney review.
See Data flow & privacy boundaries for a visual overview of where data moves in a typical setup.
When an AI assistant (Claude, GPT-4, Gemini, etc.) calls this MCP server, the MCP server itself makes no external calls by default — tool responses stay between the server and the client. However, the AI agent's own inference provider receives your full prompt context, which may include excerpts from the documents and queries you pass to these tools.
Legal documents — especially privileged communications, client information, and work product — carry confidentiality obligations under ABA Model Rule 1.6 and equivalent state rules. In United States v. Heppner (S.D.N.Y. Feb. 2026), a court held that consumer AI outputs were not privileged because the user had no reasonable expectation of confidentiality under the provider's standard terms.
| Data class | Recommended AI inference approach |
|---|---|
| Attorney-client privileged / work product | Self-hosted model (Ollama, vLLM) or Azure OpenAI / Vertex AI with Zero Data Retention + BAA/DPA + regional pinning. Never consumer free-tier APIs. |
| Confidential but not privileged | Enterprise cloud API with no-training contract and modified abuse monitoring |
| Public record / non-sensitive research | Standard managed cloud APIs acceptable with standard review |
Self-hosted (strongest control) Run an open-weight model (Llama, Mistral, Gemma) locally with Ollama or vLLM. No data leaves your machine. Ollama binds to loopback by default. Suitable for pro se litigants and firms on a budget who need strong confidentiality without enterprise cloud contracts.
Azure OpenAI (Microsoft Foundry) Prompts are not shared with OpenAI or used for training by default. Regional and DataZone deployments pin processing geography. For Zero Data Retention, apply for Modified Abuse Monitoring via the Limited Access program. HIPAA BAA available. Privacy docs.
Google Vertex AI / Model Garden No-training default under Google's Service Specific Terms. Regional residency configurable; use Assured Workloads for US-only boundaries. Avoid Google Search grounding (forces 30-day retention). HIPAA BAA available. Data governance docs. You can also deploy open-weight models from Model Garden inside your own GCP project so inference runs entirely within your VPC.
OpenRouter
A routing layer — prompts are always forwarded to an upstream inference
provider. Use ZDR routing
("provider": {"zdr": true}), data_collection: "deny", and Enterprise EU
routing if you need in-region processing. Still adds a routing hop compared
to direct enterprise tenancy; treat as higher risk for privileged content
without enterprise contractual controls in place.
- Minimize payload — redact names, SSNs, account numbers before cloud inference where possible
- Audit who queries what — the MCP server's audit log (
utils.audit) records every tool call; pair this with your inference provider's logging - Counsel-directed workflows — document that AI-assisted research was directed by an attorney (relevant to privilege analysis post-Heppner)
- Read the vendor ToS before routing client matter data — ABA Opinion 512 requires it
- Separate environments — never use dev/sandbox API keys (which may lack ZDR) on production matter data
This server is a research and analysis scaffold. It does not provide legal advice and does not substitute for attorney review. For questions about ethical AI use in legal practice, consult your jurisdiction's bar ethics guidance and ABA Formal Opinion 512 (PDF) (2024).
- Model Context Protocol
- ABA Formal Opinion 512 — Generative AI (PDF) (2024)
- CourtListener API · RECAP
- PACER developer resources
Need help integrating this legal MCP server into your practice workflows, enabling the PACER or CourtListener/RECAP adapters, or building custom law MCP tools and extensions? Professional integration and development support is available.
- Email: edwin@genego.io
- LinkedIn: Edwin Genego
We're happy to help with deployment, custom integrations, and tailored legal workflow automation.
GNU Affero General Public License v3.0 (AGPL-3.0).
Free to use, fork, and self-host. If you run a modified version as a network service, AGPL-3.0 requires you to publish your changes. Organizations that need to keep modifications private can contact edwin@genego.io for a commercial license.