UK legal research MCP server — case law, legislation, parliament, bills, votes, committees, citations, HMRC
Project description
uk-legal-mcp
A Model Context Protocol server for UK legal research. One MCP connection wires your AI assistant into UK case law, legislation, parliamentary debates, bills, votes, committees, OSCOLA citation parsing, and HMRC guidance — every response carrying the metadata you'd need to footnote it.
No API keys required for the legal sources (HMRC's authenticated endpoint is optional).
For best results remind the agent to use the uk-legal-mcp server. The location depends on the agent or setup you are using. It maybe project instructions, MEMORY.md, AGENTS.md etc.
If a tool stops responding, refresh the server from your client's Apps / Customise menu.
Connect
Hosted
Use this URL in any MCP-aware client (Claude, Claude Desktop, VS Code, Cursor, etc.):
https://uk-legal-mcp.fly.dev/mcp
For clients that use mcpServers JSON:
{
"mcpServers": {
"uk-legal": {
"type": "http",
"url": "https://uk-legal-mcp.fly.dev/mcp"
}
}
}
Local install (stdio)
Runs on your own machine and IP — the most reliable path for very large Acts (e.g. the Companies Act 2006), which legislation.gov.uk occasionally rate-limits against shared cloud IPs:
uvx uk-legal-mcp
Claude Desktop config:
{
"mcpServers": {
"uk-legal": {
"command": "uvx",
"args": ["uk-legal-mcp"]
}
}
}
Local development
stdio against your local checkout — spawns a fresh process per MCP connection from the project's [project.scripts] entry, so the source is always read as edited. Replace <abs-path> with the absolute path to your clone:
{
"mcpServers": {
"local-uk-legal": {
"command": "uv",
"args": ["run", "--project", "<abs-path>", "uk-legal-mcp"],
"env": { "VIRTUAL_ENV": "" }
}
}
}
Run streamable-HTTP locally:
# Direct invocation — the production runtime. main() wires _HttpGuard,
# _AcceptNormalizer, uvicorn proxy_headers, and lifespan="on" — these are
# load-bearing for the Fly deployment and the Dockerfile CMD.
python -m src.gateway
# Declarative invocation via fastmcp.json — convenient for `fastmcp inspect`
# and for ops tooling that reads the manifest. Wraps the FastMCP runner
# directly, so the custom uvicorn shape (HttpGuard, AcceptNormalizer,
# proxy_headers) is NOT applied. Use for dev / inspection, not for prod.
fastmcp run
Inspect the tool surface without running the server:
fastmcp inspect # reads fastmcp.json
What's here
Eight namespaced modules covering the UK's primary legal sources:
| Module | What it covers |
|---|---|
| case_law | UK court judgments from TNA Find Case Law — search, paragraph-level reads, in-document grep |
| legislation | Acts and Statutory Instruments from legislation.gov.uk — search, section retrieval with territorial extent and in-force signals, point-in-time historical reads |
| parliament | Hansard debates and contributions, deterministic facet aggregates, debate→divisions chain, OSCOLA column-citation lookup, member biographies, petitions |
| bills | Parliamentary Bills — stages, sponsors, publications |
| votes | Commons and Lords division records with per-member voting |
| committees | Select committees, membership, oral and written evidence |
| citations | Pure OSCOLA citation parser — no network, self-contained |
| hmrc | UK VAT rate lookups, Making Tax Digital status, GOV.UK guidance search |
Plus a small set of judgment://, legislation://, and hansard:// URI-addressed resources for content the LLM can read on demand, keeping tool responses compact, and four orchestration prompts for common research workflows.
A lawyer's workflow
The server returns primary sources with the citation metadata you need to footnote them. It does not interpret the law, classify members' positions, or recommend a research strategy — your agent does that work on your behalf.
A realistic end-to-end run: advising a Manchester landlord on their eviction-notice exposure under the new Renters' Rights regime, including verifying a column citation an opponent quoted at you.
The lawyer's prompt to their agent:
"My client is a landlord with a private assured shorthold tenancy started in 2020, dwelling in Manchester. Can he still serve a Section 21 notice? I also need to check what was said about no-fault evictions in the Lords debate around 14 October 2025, and the divisions held. Opposing counsel cites HL Deb 14 Oct 2025, vol 849, col 200 — verify what's actually at that column."
A reasonable path the agent walks — and what the server returns at each step:
- The statute —
legislation_get_section(type="ukpga", year=1988, number=50, section="21"). The response carriesextent(England + Wales — confirms the Manchester tenancy is in scope, Scotland is not),in_force(False — the section is marked repealed by the Renters' Rights Act 2025, with the original text retained for reference), andversion_date(the date the repeal commenced, not 1988's original enactment). - The new Act —
legislation_search(query="Renters' Rights")thenlegislation_get_tocto locate commencement / transitional provisions, thenlegislation_get_sectionfor the substantive sections. - The parliamentary debate —
parliament_search_hansard(query="Renters' Rights Bill"). One call returns the corpus envelope: how many contributions, debates, divisions, written answers across the whole record, plus previews of the top debates and divisions touching the topic. Pick the relevant Lords debate fromtop_debates. - The full debate — read
hansard://debate/{ext_id}/headerfor the ordered contribution index (every contribution carrying its citable column number via carry-forward), thenhansard://debate/{ext_id}/contribution/{ext_id}for the full text of any specific intervention. - The divisions held —
parliament_get_debate_divisions(debate_ext_id=...). Returns each formal vote with motion text, result, ayes/noes counts, and division IDs that chain intovotes_get_divisionfor the per-member voting record. - Verifying opposing counsel's citation —
parliament_lookup_by_column(column_number="200", volume_number=849, house="Lords"). Resolves the OSCOLA footnote directly to its debate, returning thedebate_ext_idthat chains intohansard://debate/{ext}/headerso you read the exact contribution opposing counsel quoted. - The case law —
case_law_search(query="Renters' Rights Act 2025")for judgments already citing the Act,case_law_grep_judgment(slug=..., pattern=...)for the paragraphs that actually treat each section. - Citations for the brief — pass your draft into
citations_parsefor a clean OSCOLA-formatted list with canonical URLs.
Every response carries the metadata needed for an OSCOLA footnote: attributed_to, column_ref, citable column numbers, debate title, sitting date, public Hansard URL. The server returns the primary source verbatim — your agent and your judgement do the legal work.
Example output
A real ChatGPT session. First, an OSCOLA citation resolved to its neutral citation, and a "what did this peer say?" question answered by resolving the member to their ID before searching Hansard:
The result: each contribution returned with its date and substance, ready to quote and footnote.
Tools reference
Case Law
| Tool | What it does |
|---|---|
case_law_search |
Full-text search of UK judgments. Filter by court, judge, party, date range. |
case_law_grep_judgment |
Pattern-match within a judgment; returns {eId, snippet, match} per hit. |
| Resource | Returns |
|---|---|
judgment://{slug*}/header |
Metadata: parties, judges, neutral citation. |
judgment://{slug*}/index |
Paragraph eId + first-line per row. Walk to discover. |
judgment://{slug*}/para/{eId} |
A single paragraph with its sub-paragraphs. |
Legislation
| Tool | What it does |
|---|---|
legislation_search |
Find Acts and SIs by keyword. |
legislation_get_toc |
Table of contents for an Act — parts, chapters, sections, schedules. |
legislation_get_section |
A specific section with extent, in_force, version_date, and either CLML XML or HTML fallback. |
| Resource | Returns |
|---|---|
legislation://{type}/{year}/{number}/section/{section}{?date} |
CLML XML for a section; optional point-in-time date. |
legislation://{type}/{year}/{number}/toc{?date} |
Flat id: title table of contents. |
Parliament
| Tool | What it does |
|---|---|
parliament_search_hansard |
Search Hansard contributions; returns citation-grade metadata per contribution PLUS a corpus envelope (totals + top_debates/top_divisions previews). |
parliament_policy_position_summary |
Deterministic facet counts on a topic — by house, section, year, top debates. No LLM, no editorial labels. |
parliament_get_debate_divisions |
Divisions held within a debate. Chain via id to votes_get_division. Empty list when no votes. |
parliament_lookup_by_column |
Resolve a Hansard column citation (column + volume) to its debate. Works for any era — current Daily Part records, consolidated Bound Volumes, and pre-2005 Historic Hansard. Each match tells you which kind. |
parliament_find_member |
Name → integer member ID. |
parliament_member_debates |
One member's Hansard contributions, optionally filtered by topic. |
parliament_member_interests |
A member's registered financial interests. |
parliament_search_petitions |
UK Parliament petitions by keyword. |
| Resource | Returns |
|---|---|
hansard://debate/{ext_id}/header |
Debate overview + ordered contribution index with citable column numbers via carry-forward. |
hansard://debate/{ext_id}/contribution/{ext_id} |
A single contribution's full text + metadata. |
hansard://member/{id}/biography |
Government / opposition / committee posts with start/end dates so you can resolve a member's role at the time of any contribution. |
Bills
| Tool | What it does |
|---|---|
bills_search_bills |
Search current and historical Bills by keyword, session, or type. |
bills_get_bill |
Full bill detail — stages, sponsors, publications. |
Votes
| Tool | What it does |
|---|---|
votes_search_divisions |
Search Commons and Lords divisions by keyword or date. |
votes_get_division |
Full division detail — vote counts, per-member voting record. |
Committees
| Tool | What it does |
|---|---|
committees_search_committees |
Select committees by keyword. |
committees_get_committee |
Committee detail — membership, sub-committees. |
committees_search_evidence |
Oral and written evidence submissions. |
Citations
| Tool | What it does |
|---|---|
citations_parse |
Extract OSCOLA citations from free text. Resolves to canonical URLs. |
citations_resolve |
Parse and resolve a single citation string. |
citations_network |
Fetch a judgment and map every citation within — cases, legislation, SIs, EU law. |
Supported citation formats:
| Format | Example |
|---|---|
| Neutral citation | [2024] UKSC 12 |
| Law report (with or without volume) | [2024] 1 WLR 100, [1932] AC 562 |
| Legislation section | s.47 Companies Act 2006 |
| Statutory Instrument | SI 2018/1234 |
| Retained EU law | Regulation (EU) 2016/679 |
HMRC
| Tool | What it does |
|---|---|
hmrc_get_vat_rate |
VAT rate lookup for any commodity or service. |
hmrc_check_mtd_status |
Check Making Tax Digital VAT mandate status for a VRN. Requires HMRC OAuth. |
hmrc_search_guidance |
Search GOV.UK for HMRC guidance documents. |
hmrc_check_mtd_status requires HMRC_CLIENT_ID and HMRC_CLIENT_SECRET — register at developer.service.hmrc.gov.uk. Defaults to sandbox; set HMRC_API_BASE=https://api.service.hmrc.gov.uk for production.
Prompts
Workflow templates exposed as tools via PromptsAsTools (for ChatGPT) and natively on protocol-aware clients (Claude, Inspector). All produce citable evidence packs; none classify positions or recommend an argumentative line.
| Prompt | Module | What it produces |
|---|---|---|
summarise_act |
legislation | Structured summary of a UK Act or SI. |
compare_legislation |
legislation | Comparative analysis of two pieces of legislation on a topic. |
policy_reception_review |
parliament | Citation-grade review of how a policy topic is being received in Parliament. |
member_record_on_topic |
parliament | Citable evidence pack of a named member's contributions on a topic — their own words, footnoted. |
Important constraints
- Territorial extent always matters.
legislation_get_sectionexposes theextentfield. Acts that apply in England and Wales do not automatically apply in Scotland or Northern Ireland. Read this before citing a section as binding in a jurisdiction. - Verifying opposing counsel's citations — when a brief cites HL Deb [date], vol N, col M, run
parliament_lookup_by_column(column_number="M", volume_number=N, house="Lords")to resolve the citation to its debate, then read the header resource to find the contribution at the cited column. Citations from any era resolve — current Daily Part records, finalised Bound Volumes, and pre-2005 Historic Hansard. Each match tells you which Hansard format the volume sits in. Empty matches usually mean the volume number is wrong (e.g. opposing counsel quoted the running session-volume number rather than the bound-volume one) or the citation is to a Written Answer and needs theWsuffix. - What this server does not do. It does not classify a member as supporting or opposing a policy, summarise a judgment's outcome in your client's favour, or recommend an argumentative line. Those are interpretive acts. The server returns the primary source verbatim with citation metadata; your agent and your judgement do the legal work.
- Very large Acts. A few exceptionally large Acts (notably the Companies Act 2006) can occasionally time out on the hosted endpoint when legislation.gov.uk rate-limits shared cloud IPs. Running the local install (
uvx uk-legal-mcp) on your own IP resolves this.
Releasing
Version is held in pyproject.toml. Runtime surfaces (serverInfo.version, the Smithery server-card, server://about) derive from the installed package via importlib.metadata. File-on-disk surfaces (pyproject.toml + server.json × 2) bump together via bump-my-version:
uv run bump-my-version bump patch # 0.5.0 → 0.5.1
uv run bump-my-version bump minor # 0.5.0 → 0.6.0
uv run bump-my-version bump major # 0.5.0 → 1.0.0
The tool only edits files; it does not commit or tag. After bumping, commit the version files, push, then publish a GitHub release at the new tag — .github/workflows/release.yml builds, publishes to PyPI, and deploys to Fly.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file uk_legal_mcp-0.5.1.tar.gz.
File metadata
- Download URL: uk_legal_mcp-0.5.1.tar.gz
- Upload date:
- Size: 585.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bcc24770422e4d4cb56c8563ee5008030569917fbb60b33fab85cf2fdb4bd9cd
|
|
| MD5 |
b560be4d1b5263c14a8de0264b9b2919
|
|
| BLAKE2b-256 |
4a1a01256d186a5177a01011b275853fcfe2e320a66218e346765730691ce5dc
|
Provenance
The following attestation bundles were made for uk_legal_mcp-0.5.1.tar.gz:
Publisher:
release.yml on paulieb89/uk-legal-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
uk_legal_mcp-0.5.1.tar.gz -
Subject digest:
bcc24770422e4d4cb56c8563ee5008030569917fbb60b33fab85cf2fdb4bd9cd - Sigstore transparency entry: 1676025281
- Sigstore integration time:
-
Permalink:
paulieb89/uk-legal-mcp@4507958e0fc6d82ca7a8110a9c6d5b3cb72a9d7b -
Branch / Tag:
refs/tags/v0.5.1 - Owner: https://github.com/paulieb89
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4507958e0fc6d82ca7a8110a9c6d5b3cb72a9d7b -
Trigger Event:
release
-
Statement type:
File details
Details for the file uk_legal_mcp-0.5.1-py3-none-any.whl.
File metadata
- Download URL: uk_legal_mcp-0.5.1-py3-none-any.whl
- Upload date:
- Size: 112.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
27a4297840ca43e727cee1a1fead693fbd83e9568a5efeaf12ca4a0b3f8e9e7d
|
|
| MD5 |
989d11235ad876c32bcef4c2fb3cf0c5
|
|
| BLAKE2b-256 |
e5b448e49d538530dd56c1e73a6a7a272202fb9a8972b65b639caf810afd8732
|
Provenance
The following attestation bundles were made for uk_legal_mcp-0.5.1-py3-none-any.whl:
Publisher:
release.yml on paulieb89/uk-legal-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
uk_legal_mcp-0.5.1-py3-none-any.whl -
Subject digest:
27a4297840ca43e727cee1a1fead693fbd83e9568a5efeaf12ca4a0b3f8e9e7d - Sigstore transparency entry: 1676025292
- Sigstore integration time:
-
Permalink:
paulieb89/uk-legal-mcp@4507958e0fc6d82ca7a8110a9c6d5b3cb72a9d7b -
Branch / Tag:
refs/tags/v0.5.1 - Owner: https://github.com/paulieb89
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4507958e0fc6d82ca7a8110a9c6d5b3cb72a9d7b -
Trigger Event:
release
-
Statement type: