Skip to main content
Glama
Ankur-stockheads

break-clause-analyzer

UK Break Clause Analyzer (MCP)

CI

A self-evaluating MCP server that assesses whether a UK commercial-lease tenant break clause can actually be exercised — and publishes its own measured hallucination rate.

⚖️ Decision-support only — NOT legal advice. Built on a deliberately simplified, non-proprietary ruleset over synthetic data. A qualified solicitor must verify any real decision.


The £2m full stop

In 2012, a tenant served a valid break notice to walk away from a lease — but on the break date they hadn't paid one quarter's rent that had fallen due a few weeks earlier. The break failed. They were bound to the lease (and its rent) for years. No drama, no bad faith — just one unmet condition precedent that everyone missed until it was too late.

Break clauses are unforgiving like that. Whether a tenant can actually leave turns on a short checklist — notice served in time, notice served correctly, no rent arrears, vacant possession given — and getting any one wrong is catastrophic. It is exactly the kind of task you might hand to an LLM... if you could trust it not to confidently invent the answer.

This project is about earning that trust, and measuring it. It is not a clever parser. It is a reliability harness: every claim is grounded to verbatim source text or it isn't made, genuinely-ambiguous cases are routed to a human instead of guessed, and the whole thing ships with an eval that publishes how often it lies.

Related MCP server: contract-risk-analyzer

The edge

  • Grounded — every asserted condition is backed by a verbatim source span. If the system can't find the text, it returns NOT_FOUND; it never invents a quote. A deterministic gate slices the span out of the source, so it can't echo hallucinated text.

  • Calibrated — when the lease genuinely doesn't settle a point, the answer is AMBIGUOUS — human verify, not a coin-flip. Abstaining honestly is a feature.

  • Self-evaluating — a pytest harness scores extraction accuracy, citation faithfulness, hallucination rate, and calibration against 24 labelled cases.

  • Reasons + verifies — the LLM only proposes; deterministic code disposes (grounds every quote, does the date arithmetic, applies the vacant-possession legal test, aggregates the verdict).

The headline number

See report/report.md for the full eval (all four metrics, per-model comparison, confusion matrix, caught-hallucination examples).

The committed report is the heuristic baseline (it runs with no API key) — and it already tells the core story: the grounding gate drives ungrounded (fabricated) hallucinations to zero, while a non-reasoning baseline still misgrounds and never abstains on the genuinely-ambiguous cases. That gap is exactly what a calibrated LLM is meant to close:

uv run python scripts/run_eval.py --record   # measure claude-haiku-4-5 vs claude-sonnet-4-6

How it works

flowchart LR
    A["Lease + Background Facts"] --> T["MCP tools"]
    T --> L["LLM adapter<br/>extract + reason · temperature 0"]
    L -- "proposes verbatim quotes<br/>+ findings" --> G{"Grounding gate<br/>verbatim? else NOT_FOUND"}
    G -- "spans sliced from source" --> C["Deterministic core<br/>checklist · UK date math · VP legal test"]
    C --> R["Strict-precedence aggregate<br/>fail→INVALID · uncertain→AMBIGUOUS · else VALID"]
    R --> O["Assessment<br/>verdict + calibration + human-verify gates"]
    subgraph EVAL["Eval (the point)"]
      D["24 labelled cases"] --> H["harness"] --> M["4 metrics"] --> P["report.md + SVG"]
    end

The trust boundary is structural: the deterministic core/ package physically cannot import the llm/ package (enforced by a test). "The LLM proposes, deterministic code disposes" is a property of the codebase, not a discipline.

The four MCP tools (each does one thing)

Tool

What it does

extract_break_clause

Returns the break clause + its verbatim source span

check_conditions

The four-condition checklist: each pass / fail / uncertain, with grounded evidence

find_citation

Exact verbatim supporting text for a claim, or NOT_FOUND

assess_validity

Orchestrated verdict + calibration note + mandatory human-verify gates

Quickstart (clone to running in under 2 minutes)

# 1. Install uv (skip if you have it)
curl -LsSf https://astral.sh/uv/install.sh | sh

# 2. Install deps (uv fetches its own Python 3.12)
uv sync

# 3. Run the test suite — proves the eval apparatus is correct
uv run pytest -q

# 4. Check the dataset (every gold span verbatim, every label coherent)
uv run python scripts/validate_dataset.py

# 5. Regenerate the eval report
uv run python scripts/run_eval.py        # heuristic baseline, no key needed

No ANTHROPIC_API_KEY is required for any of the above — the eval falls back to the heuristic baseline and is fully reproducible. Set the key (and --record) to measure the real Claude models.

Your Anthropic API key

The key is only needed for live LLM extraction (the eval --record step and the server's real mode). Everything else runs without one.

  • Never commit it. .env is git-ignored and the cassettes redact the x-api-key header.

  • For local commands, either export it or use a .env file:

    export ANTHROPIC_API_KEY=sk-ant-…           # option 1: shell
    # or
    cp .env.example .env && $EDITOR .env          # option 2: .env, then:
    uv run --env-file .env python scripts/run_eval.py --record
  • For an MCP client, put it in the server config's env block (below).

Run the MCP server

# Inspect it interactively (the official MCP Inspector)
npx @modelcontextprotocol/inspector uv run break-clause-analyzer

Claude Desktop — add to claude_desktop_config.json (use the absolute path to your clone so it runs from the project):

{
  "mcpServers": {
    "break-clause-analyzer": {
      "command": "uv",
      "args": ["run", "--directory", "/absolute/path/to/rubo-mcp", "break-clause-analyzer"],
      "env": { "ANTHROPIC_API_KEY": "sk-ant-…" }
    }
  }
}

Claude Code — one command:

claude mcp add break-clause-analyzer -e ANTHROPIC_API_KEY=sk-ant-… \
  -- uv run --directory /absolute/path/to/rubo-mcp break-clause-analyzer

Without a key the server still runs and responds — it uses the heuristic baseline and says so. Every tool response carries the decision-support disclaimer.

Reproducible evals (cassettes)

temperature=0 is not a determinism guarantee from the API, so reproducibility comes from recorded cassettes (VCR.py). scripts/run_eval.py --record records one cassette set per model with the x-api-key header redacted; re-running without --record replays them with no key in seconds. See eval/cassettes/README.md.

Layout

src/break_clause_analyzer/
  core/       # deterministic trust boundary (no network; cannot import llm/)
    grounding.py  dates.py  checklist.py  aggregate.py
  llm/        # the only network egress (Anthropic + heuristic fallback)
  pipeline.py # propose → gate → dispose orchestration
  server.py   # FastMCP server: the four tools
data/cases/   # 24 labelled synthetic case files (+ dataset README)
eval/         # harness, metrics, report generator, cassettes
docs/METHODOLOGY.md  # pre-registered metric definitions
report/       # generated eval report + SVG
.planning/    # the eval-first roadmap, requirements, and decision log

Methodology & honesty

The metric definitions are pre-registered in docs/METHODOLOGY.md before any model is run, so the headline number can't be defined after the fact to look good. The hallucination rate counts misgrounding and overconfidence — not just fabrication — precisely because a grounding gate makes fabrication trivially zero. The scorer uses no LLM judge; it is validated against a gold oracle and deliberately-broken systems in tests/test_harness.py.

Scope (deliberately narrow)

Tenant break clauses only · four conditions precedent · synthetic/public data only · decision-support, not legal advice. Other lease provisions, landlord breaks, real client data, and a production engine are explicitly out of scope.


Built as a reliability-engineering artifact. The eval is the point.

Available Tools

4 tools
assess_validityA
Read-only

Orchestrated assessment: VALID / INVALID / AMBIGUOUS with per-condition results, the conditions that forced the verdict, a calibration note, and mandatory human-verify gates. Abstains to AMBIGUOUS rather than guess. Decision-support only.

ParametersJSON Schema
NameRequiredDescriptionDefault
case_textYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
verdictYesOverall assessment. AMBIGUOUS means 'human verify', not a coin-flip.
conditionsYes
disclaimerNo
calibrationYes
human_verifyNo
decisive_conditionsNo

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, but the description adds valuable behavioral context: it discloses abstention to AMBIGUOUS rather than guessing, mandatory human-verify gates, and decision-support-only intent. These go beyond the annotations and help the agent understand safety and verification requirements.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and front-loaded, starting with the core purpose and verdict types, then adding key behaviors (abstention, human-verify gates, decision-support). Every sentence contributes value without redundancy or waste.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the tool's orchestrated nature, output components (per-condition results, conditions forcing verdict, calibration note), abstention behavior, and human-verify requirement. It is largely complete given the schema and output schema exist, though it omits any mention of the input parameter and when to use it, which is partially covered by other dimensions.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate for the single parameter (case_text). It does not explicitly explain what case_text should contain, its format, or any requirements. While the parameter name is self-explanatory, the description provides no direct semantic guidance, leaving a gap for low coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's function with a specific verb ('Orchestrated assessment') and resource (the case text), and defines the output verdicts (VALID/INVALID/AMBIGUOUS). It distinguishes itself from siblings (extract_break_clause, check_conditions, find_citation) by being an orchestrated, holistic assessment rather than a targeted extraction or check.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage context ('Orchestrated assessment', 'Decision-support only') but does not explicitly state when to use this tool versus alternatives, nor does it provide exclusions or when-not-to-use guidance. The abstention behavior is a partial guideline, but there is no direct comparison to sibling tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

check_conditionsA
Read-only

Evaluate the four conditions precedent (notice timing, notice validity, rent/no-arrears, vacant possession) against the document, each pass/fail/uncertain with grounded evidence. Decision-support only.

ParametersJSON Schema
NameRequiredDescriptionDefault
case_textYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
conditionsYes
disclaimerNo

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds context about the output format ('pass/fail/uncertain with grounded evidence') and decision-support nature. Since annotations already declare readOnlyHint: true, the description does not need to restate safety, but it does not reveal additional behavioral details like authentication or reversibility.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no redundant wording, and the key information is front-loaded. Every phrase earns its place: the conditions, the output nature, and the decision-support scope are all stated efficiently.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has only one input parameter and an output schema, so the description does not need to explain return values. It names all four conditions and specifies the pass/fail/uncertain plus evidence format. This is complete for a decision-support tool, though it does not mention edge cases like empty input or handling of ambiguous documents.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, but the single parameter case_text is self-explanatory as the document text. The description refers to 'the document' providing a light mapping, though it does not explicitly say the parameter represents the document. This is adequate for a simple string parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Evaluate') and resource ('four conditions precedent') against the document, and names the four conditions (notice timing, notice validity, rent/no-arrears, vacant possession). It clearly distinguishes itself from siblings like extract_break_clause, find_citation, and assess_validity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage when evaluating conditions precedent, and states 'Decision-support only' which hints at its advisory role. However, it does not explicitly mention when to use this tool over alternatives, nor does it provide any exclusions or prerequisites.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

extract_break_clauseA
Read-only

Extract the tenant break clause from a lease document, returning its verbatim text and source span (or found=false). Decision-support only.

ParametersJSON Schema
NameRequiredDescriptionDefault
lease_textYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
clauseYesOutput of extract_break_clause: the clause + its grounded span, or not found.
disclaimerNo

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations (readOnlyHint: true, openWorldHint: false) already declare safe read-only behavior, and the description adds the behavioral detail of returning verbatim text and a source span, or found=false when absent. It also includes 'Decision-support only,' which signals its role as an analytical aid. The description is consistent with the annotations, providing extra context without contradiction.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, well-structured sentence that packs essential information: extraction action, input reference, output details, and fallback behavior. There is no wasted wording, and each clause adds value. It is appropriately concise and front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity (one string parameter) and presence of an output schema, the description is sufficient to convey the tool's function and return behavior. It covers the core purpose, the input, and the failure case (found=false), which is important. It does not need to elaborate on output format since the output schema exists, and the description is complete for this level of complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The only parameter, lease_text, is described implicitly through 'lease document,' indicating it should contain the lease text. However, the schema description coverage is 0%, and the description does not elaborate on input format, length, or preconditions. The parameter name itself is fairly self-explanatory, but the description adds minimal meaning beyond that.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's function: extracting the tenant break clause from a lease document, with a specific verb ('Extract') and resource ('tenant break clause'). It also specifies the return format (verbatim text and source span, or found=false), making the purpose unambiguous. While it doesn't explicitly compare to sibling tools, the unique extraction task distinguishes it from check_conditions, find_citation, and assess_validity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies the tool is for extracting a specific clause but provides no explicit guidance on when to use this tool versus alternatives. 'Decision-support only' is a caveat about usage context, not a comparison with sibling tools. No exclusions or alternative tool references are given, so the usage guidance is limited to what's self-evident.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_citationA
Read-only

Return the exact verbatim text in the source that supports a claim, or NOT_FOUND. Never invents text. Deterministic. Decision-support only.

ParametersJSON Schema
NameRequiredDescriptionDefault
claimYes
source_textYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
citationYesThe result of grounding a claim. ``found=False`` is the NOT_FOUND outcome: the system could not locate verbatim support and refuses to invent any. There is no path that substitutes model text for a real span.
disclaimerNo

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark the tool as read-only, so the description adds value by disclosing deterministic behavior, the constraint of never inventing text, and the explicit NOT_FOUND return convention. This goes beyond the structured annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise—two sentences front-loaded with the core action and output behavior. Every clause adds value (verbatim, NOT_FOUND, never invents, deterministic, decision-support). No wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity, the description covers the essential return values and constraints. The presence of an output schema (not shown) likely documents return structure; description explains the high-level behavior. Missing edge-case details but acceptable for the tool's scope.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, but the parameter names (source_text, claim) are self-explanatory. The description refers to 'source' and 'claim' without adding format or constraints beyond what the schema provides, leaving room for more detail but not critical.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's function: returning exact verbatim text from a source that supports a claim, or NOT_FOUND. This is a specific verb-resource combination that distinguishes it from siblings like extract_break_clause or check_conditions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage (when you need supporting evidence for a claim) but does not explicitly state when to prefer this over alternatives or provide exclusions. The phrase 'Decision-support only' hints at appropriate contexts but lacks explicit guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

TDQS

A4.2/5.0
Disambiguation5/5

Each tool targets a distinct step in the analysis pipeline: extract the clause, check conditions, find supporting evidence, and produce the final assessment. There is no overlap in purpose.

Naming Consistency5/5

All tool names follow the verb_noun pattern (extract_break_clause, check_conditions, find_citation, assess_validity), making the naming scheme predictable and uniform.

Tool Count5/5

With 4 tools, the server is well-scoped for a focused break-clause analysis workflow. Each tool serves a necessary, non-redundant role.

Completeness5/5

The tool set covers the full analysis lifecycle: extraction, condition evaluation, citation retrieval, and final validity assessment. No obvious dead ends or missing operations for the stated purpose.

Maintenance

ActivityStale
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Ankur-stockheads/rubo-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server