Lex: Luxembourg Law MCP Server

Lex: Luxembourg Law MCP Server

Point-in-time access to Luxembourg law and ten EU acts: what any law said on a given date, not just the current text. 1,409 consolidated works and 4,705 dated versions from the official Legilux and EUR-Lex sources. Ten read-only tools: as-of text, timelines, per-article history, diffs between dates, and hash-verifiable provenance. No key.

Category
访问服务器

README

Lex

CI License Live MCP Coverage

Point-in-time retrieval of regulatory text. Regulators publish the current rule; every audit, investigation and dispute is about a past date. Lex keeps every version it has seen and answers "what did this say on 15 March 2022?" with the exact validity interval, the timeline, the instrument that changed it, and a hashed provenance record, and an honest, machine-readable refusal when it cannot know.

Live demo · Ask the AI · MCP endpoint · Dataset (CC-BY) · Examples · Architecture · Verify it yourself · Spec (D1, D48)

Try it in 30 seconds

Give any MCP-capable AI the full toolset, no key, no install:

claude mcp add --transport http lex https://law.soufien.lu/mcp

Or ask the live site. A real answer, verbatim:

Q: What did CRR Article 92 require as capital ratios on 1 March 2020, and has that text changed since?

Quoted verbatim (Article 92(1)) from the CRR version in force on that date: "Subject to Articles 93 and 94, institutions shall at all times satisfy the following own funds requirements: (a) a Common Equity Tier 1 capital ratio of 4,5 %; (b) a Tier 1 capital ratio of 6 %; (c) a total capital ratio of 8 %." , eu-eurlex:32013r0575:2019-12-25 (valid 2019-12-25 → 2020-06-26), permalink.

Article 92 has had four distinct texts since 2013-2013-06-28 → 2021-06-28, 2021-06-29 → 2022-12-31, 2023-01-01 → 2024-12-31, 2025-01-01 onward, each with its own permalink and sha256.

Every claim in that answer came from a deterministic tool call (the trace is shown under each reply); the model never answers from its own memory. Do not take this file's word for it, the numbers above are checkable in one call, and if they ever drift from the live system, that is a bug worth reporting:

curl -s -X POST https://law.soufien.lu/mcp -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"article_history",
       "arguments":{"work":"eu-eurlex:32013r0575","anchor":"art_92"}}}'

Who uses this

  • A compliance officer checking which text of an obligation was in force on the date of the facts, with a permalink and a hash for the file.
  • A legal-tech developer building RAG over law that must not hallucinate versions: per-article chunks with valid_from/valid_to to filter before similarity (dataset).
  • An AI agent using the MCP tools directly, the same tools the site's own AI uses, at the same endpoint.
  • A researcher tracking how one article's text evolved across amendments (article_history: every distinct text state, dated).

What it never does

Lex answers what the rule was. It never answers "were we compliant?", "does this apply to me?", or "what does this mean?", those are professional opinions. No component in this system generates interpretive text (fitness rule F10).

Architecture (one screen)

APPS        Lex.Ingest (CLI)   Lex.Mcp (MCP server)        Lex.Web (demo)   Lex.Ask (AI loop)
DERIVED     Lex.Derive, evidence -> per-article Markdown+JSON (immutable profiles: akn-lu/1, fmx4-eu/1, xhtml-eu/1)
ADAPTERS    Lex.Sources.Legilux (Tier A, SPARQL)   Lex.Sources.EurLex (Tier A, Cellar + Formex)
MODEL       Lex.Law, Publisher, Work, Version, Expression, Observation. No publisher names.
FOUNDATION  Lex.Temporal (interval algebra)   Lex.Index (SQLite: filter-first, signed stamp)
  • One corpus repo per publisher; the corpus is human-readable JSON + git. The tree carries the legislative history, git log carries the ingest history, and the two are deliberately not the same (why).
  • Bitemporal: valid time is the publisher's; transaction time is ours, as append-only observation chains inside hashed content. Nothing is ever overwritten; publisher corrections become visible events.
  • Two layers: verbatim publisher bytes (evidence) → deterministic per-article extraction (consumption). Every derived article hash-chains to the exact bytes the state published; lex verify derive re-derives and byte-compares.
  • Filters before ranking, always, enforced by construction (a non-optional FilterSet on the only query entry point).
  • Signed index stamps (ECDSA-P256): every served hash is attributable.
  • Honest refusals: no_version_for_date, anchor_not_in_version, outside_observed_window, text_withheld, a flagged wrong answer is still a wrong answer, so Lex refuses instead.

Current coverage

Luxembourg (Legilux, Tier A): every work and consolidated version the publisher issues, 1,399 / 4,703, 1849→2030. Nothing is filtered out by type. Text is verbatim Akoma Ntoso XML from the publisher's official, robots-permitted filestore, licensed CC-BY-4.0.

Text is held for 2,949 of those versions, not all of them, and the reason is the publisher's format rather than our pipeline. Legilux offers XML for 2,892 consolidations, PDF only for 1,611, and no file at all for 130 (measured against its own catalogue, 2026-08-04). Lex reads the XML, because XML is the only format carrying article boundaries, which is what makes an article citable, hashable and diffable.

Where the publisher issues no XML, Lex falls back to the consolidated PDF (profile pdf-lu/1, spec D49). Those PDFs are born-digital with a real font layer, so no OCR is involved: 64 versions are read this way, and the profile id records per version that the article boundaries were inferred from typography rather than taken from publisher markup. The fallback deliberately refuses the 1,371 thematic-collection PDFs, which concatenate every act on a shelf, and the 176 Memorial gazette scans, where the act sits inside a whole day's journal. Everything else keeps its dated record, source and hash, with no wording.

The gap is concentrated outside the hierarchy of norms, not across it:

text held
Constitution, treaties 100%
Code (enacted as a law) 100%
Règlement de la Chambre, arrêté ministériel 100%
Règlement grand-ducal 96%
Loi 93%
Règlement ministériel, arrêté grand-ducal ~75%
RECUEIL / CODE_RECUEIL (thematic folders, not instruments) 9% / 2%

Roughly 1,371 of the textless versions are those folders, which nobody voted and which hold no rule of their own. Honest coverage claim: dense and reliable from 2017 onward; real but sparse before; isolated snapshots back to 1849; forward to 2030.

EU (EUR-Lex/Cellar, Tier A): 10 flagship acts (GDPR, DORA, AI Act, NIS2, MiFID II, CRR, PSD2, SFDR, RED II, electricity market), 56 consolidated versions, full text from the Publications Office's Formex 4 structural XML where served, including the large CRR consolidations the XHTML channel couldn't carry. The EU limit is scope, not format: flagship acts only, out of a much wider acquis.

Derived layer: 1,212 works · 88,981 articles · 102,773 dated text states. The never-consolidated LU acts (~24,579) and the wider EU acquis are staged next (spec §14). Communal regulations are deliberately out of scope: 17,232 exist as published acts, none is ever consolidated, so there is no point-in-time history to hold. The fallback ladder for XML-less versions is spec D49.

Run it

# ingest (paced, sequential; official open-data channels only)
dotnet run --project src/Lex.Ingest -- ingest --publisher lu-legilux --corpus ../lex-corpus-lu-legilux

# derive the per-article layer, build the signed index
dotnet run --project src/Lex.Ingest -- derive --publisher lu-legilux --corpus ../lex-corpus-lu-legilux --out ../lex-articles
dotnet run --project src/Lex.Ingest -- index --corpus ../lex-corpus-lu-legilux --articles ../lex-articles \
    --out indexes/index-lu-legilux.db --keyfile signing-key.pem

# web demo + MCP (stdio) locally
LEX_INDEX_DIR=indexes dotnet run --project src/Lex.Web
LEX_INDEX_DIR=indexes dotnet run --project src/Lex.Mcp

MCP tools

as_of (full / outline / per-article select) · timeline · in_force_on · diff · search · provenance · article_history · changes_in_period · coverage, changes_in_period answers across the corpus ("which laws moved most in this window"), the aggregate counterpart of diff and timeline; and coverage exists to say what we do not have, because a system that cannot state its own gaps cannot be trusted with a completeness question.

Contributing

Issues and PRs welcome, the highest-leverage areas:

  • A new publisher adapter (ISourceAdapter, ~200 lines): any jurisdiction with an official machine-readable channel. The seam is publisher-pure by fitness test; adapters never touch files or git.
  • Eval cases (evals/cases.json): questions where the AI should construct better tool calls, or refuse better.
  • Extraction improvements: profiles are immutable; improvements ship as a new profile beside the old (see fmx4-eu/1 beside xhtml-eu/1).

Contributions are accepted under the Developer Certificate of Origin (git commit -s).

Licence

Code: Apache-2.0 (LICENSE). The code licence does not extend to corpus data or index artefacts, see each corpus repository's NOTICE (three layers: official acts outside copyright / Lex's compilation rights / code licence inapplicable). Derived dataset: CC-BY-4.0 (LU) and EU reuse-with-attribution, licence inline in every file.

Support

This is free and open, and it stays that way whatever you decide. It is also not free to run: the live site, the nightly jobs and the storage sit on Azure infrastructure I pay for out of pocket, and I maintain it on my own time.

If it saved you an afternoon, you can buy me a coffee ☕ and put it towards the hosting bill. Starring the repo helps just as much, and costs nothing.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选