Skip to main content
Glama
README.md
# legal-contract-mcp

[![CI](https://github.com/Rajasrikondaveeti/legal-contract-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/Rajasrikondaveeti/legal-contract-mcp/actions/workflows/ci.yml)

An MCP (Model Context Protocol) server that gives an LLM client (Claude, Claude Code, Claude Desktop, etc.) tools to do a first-pass review of contracts: load a `.txt`/`.docx`/`.pdf`, detect standard clause types, flag heuristic risk issues, generate a summary, and diff two contracts against each other.

This is **not legal advice** — it's a rules-based first pass meant to speed up human review, built to demonstrate a real, non-trivial MCP server (as opposed to a toy "add two numbers" example).

## Why this exists

Most MCP server examples are thin wrappers around an API call. This one does actual work locally:

- Parses real document formats (txt/docx/pdf)
- Detects 12 standard clause types via a maintained pattern library, not a single regex
- Runs 8 explainable risk heuristics (e.g. indemnification without a liability cap, auto-renewal without a clear notice period, non-competes with no defined scope) — every flag cites the exact clause text it's based on
- Falls back gracefully to an extractive summary if no `  OPENAI_API_KEY` is set, and upgrades to an LLM-generated summary if one is

## Tools exposed

| Tool | Description |
|---|---|
| `load_contract(path)` | Load a `.txt`/`.docx`/`.pdf` file, returns a `doc_id` |
| `list_documents()` | List contracts loaded in this session |
| `extract_clauses(doc_id)` | Detected clause types with snippets |
| `missing_clauses(doc_id)` | Standard clause types NOT found — gap check |
| `flag_risks(doc_id)` | Heuristic risk flags with severity + evidence |
| `summarize_contract(doc_id)` | Plain-English summary (LLM or extractive fallback) |
| `compare_contracts(doc_id_a, doc_id_b)` | Diff clause types and risk flags between two contracts |
| `search_clause_library(query)` | Look up a clause type's definition by keyword |

## Setup

```bash
python -m venv .venv
source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
```

Optional — enable LLM-powered summaries:

```bash
export OPENAI_API_KEY=sk-ant-...
```

## Run it

**Inspector (interactive dev UI):**

```bash
mcp dev src/legal_contract_mcp/server.py
```

**As a stdio server** (for Claude Desktop / Claude Code config):

```json
{
  "mcpServers": {
    "legal-contract-mcp": {
      "command": "python",
      "args": ["-m", "legal_contract_mcp.server"],
      "cwd": "/absolute/path/to/legal-contract-mcp",
      "env": { "OPENAI_API_KEY": "sk-ant-..." }
    }
  }
}
```

Then in a chat with the connected client:

> Load the contract at tests/sample_contracts/weak_nda.txt and flag its risks.

## Test

```bash
pytest                    # unit tests for clause detection + risk rules
python scripts/smoke_test.py   # spins up the real MCP server over stdio and calls every tool
```

Includes two sample contracts (`tests/sample_contracts/weak_nda.txt` and `solid_msa.txt`) chosen so the risk engine's output differs meaningfully between a weak and a well-drafted agreement — tests assert on that difference, not just "does it run."

## Project structure

```
src/legal_contract_mcp/
  parsing.py         # txt/docx/pdf -> plain text, in-memory doc store
  clause_library.py  # 12 clause types: definitions + detection patterns
  clauses.py         # runs the library against a document
  risk_rules.py       # 8 heuristic risk rules, each with cited evidence
  llm.py              # optional Claude-powered summary, extractive fallback
  server.py           # FastMCP tool definitions
tests/
  sample_contracts/   # weak NDA vs. solid MSA fixtures
  test_clauses_and_risks.py
```

## Extending it

- Add a clause type: add an entry to `CLAUSE_LIBRARY` in `clause_library.py` with a definition and one or more regex patterns.
- Add a risk rule: add a function block to `evaluate_risks()` in `risk_rules.py` — return a `RiskFlag` with `rule`, `severity`, `message`, and `evidence`.
- Swap the in-memory store in `parsing.py` for a database if you want documents to persist across server restarts.

## Disclaimer

This tool provides automated, heuristic pattern-matching only. It is not a substitute for review by a licensed attorney and should not be relied on as legal advice.

TDQS

A3.9/5.0

Scored across 8 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: loading, listing, extracting clauses, flagging risks, summarizing, comparing, gap analysis, and library search. There is no meaningful overlap between tool responsibilities.

Naming Consistency4/5

Most tools follow a consistent snake_case verb_noun pattern like load_contract, extract_clauses, and compare_contracts. The one minor deviation is missing_clauses, which is not in an imperative verb form.

Tool Count5/5

With 8 tools, the server is well-scoped for contract analysis. Each tool covers a distinct part of the workflow without redundancy or bloat.

Completeness4/5

The core analysis workflow is well covered: load, extract, flag, summarize, compare, and check missing clauses. Minor gaps exist such as no tool for unloading documents or retrieving raw full contract text, but agents can work around these.

Maintenance

ActivitySlowing
ResponsivenessNo issues