lector
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@lectorCan an employer use AI to read employees' emotions?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Lector
Agentic RAG over the EU AI Act. Ask in English or Italian; every sentence of the answer is cited to the exact article, paragraph or point of Regulation (EU) 2024/1689, and every citation is checked against the text the agent actually retrieved.
$ lector ask "Can an employer use AI to read the emotions of its staff?"The answer comes back with citations like [Article 5(1)(f)], each linked to EUR-Lex,
plus the tool calls the agent made, tokens, cost and latency.
Agent — a LangGraph state machine around Claude's tool use: it searches, reads whole articles when a passage is cut, follows cross-references (Article 6 → Annex III), and has to back every citation with retrieved text before the answer leaves the graph.
Retrieval — structure-aware chunks (one per paragraph or point, never across them) with multilingual embeddings in pgvector. BM25, hybrid fusion (RRF) and cross-encoder reranking are built in and measured against dense retrieval; the default is whatever the evaluation says works best.
Knowledge graph — 398 cross-references between articles and annexes, extracted from the text and exposed as a tool.
MCP server — the same tools for Claude Code, Claude Desktop or any MCP client.
Measured — 50 hand-written questions with the articles that answer them; hit@k and MRR for every retrieval mode.
How it works
flowchart LR
Q([question]) --> G[guard<br/>injection, length, language]
G -->|blocked| E([end])
G --> A[agent<br/>Claude + tools]
A -->|tool calls| T[tools<br/>search · get_article · get_references]
T --> A
A -->|answer| V[verify<br/>every citation retrieved?]
V -->|no: one revision| A
V -->|yes| EStep | What happens |
guard | Rejects empty, oversized and prompt-injection inputs before any model call; detects the language so tools search the English or Italian text. |
agent | Claude ( |
tools | Run against Postgres; every unit shown to the model ( |
verify | Extracts the |
Conversations are kept per thread_id with a LangGraph checkpointer, so follow-up
questions work. Each response reports input/output/cache tokens and cost in USD.
Ingestion
The official XHTML from the EU Publications Office gives every article, paragraph,
recital and annex a stable element id. corpus.py walks that structure and emits:
306 documents per language: 113 articles, 180 recitals, 13 annexes;
~1,050 chunks per language: one per paragraph, split into its points (a), (b)… when a paragraph is too long to embed, each point keeping the paragraph's lead-in so it still reads on its own;
citation labels in both legal styles:
Article 5(1)(f)andArticolo 5, paragrafo 1, lettera f);cross-references, with references to other acts (
Article 16 of Regulation (EU) 2016/679,Article 114 TFEU) filtered out.
Related MCP server: mcp-eur-lex
Evaluation
eval/questions.jsonl: 50 questions (25 English, 25 Italian) written the way a
compliance officer or a developer would ask them — "Is an AI tool that screens job
applications considered high-risk?", "Il fornitore deve monitorare il sistema anche
dopo averlo immesso sul mercato?" — each with the articles, annexes or recitals that
answer it. A question counts as a hit at k if one of them is in the top k results.
Retrieval | hit@1 | hit@3 | hit@5 | hit@10 | MRR@10 | median ms |
keyword (BM25) | 0.48 | 0.78 | 0.84 | 0.92 | 0.641 | 3 |
vector (default) | 0.64 | 0.92 | 0.94 | 0.98 | 0.780 | 107 |
hybrid (RRF) | 0.52 | 0.86 | 0.92 | 0.96 | 0.698 | 118 |
hybrid + rerank | 0.66 | 0.90 | 0.92 | 0.98 | 0.790 | 4579 |
intfloat/multilingual-e5-large embeddings, jina-reranker-v2-base-multilingual
reranker, CPU only (Ryzen 9 7940HX). Reproduce with lector eval retrieval.
Dense retrieval is the default. It puts a correct article in the top 3 for 92% of the questions, and the agent reads 8 passages per search.
BM25 is computed on the lexemes Postgres stems for English and Italian, with inverse document frequency — Postgres' own
ts_rankhas none, so "AI" and "system" would weigh as much as "subliminal". It is strong for exact terms but weaker on paraphrased questions, and in an equal-weight fusion it pulls the dense ranking down.Reranking adds +0.01 MRR for 40× the latency on CPU, and the only multilingual cross-encoder available is CC-BY-NC, so it is off unless
LECTOR_RERANK_MODELis set.
Quickstart
Requirements: Docker, Python 3.11+, and an Anthropic API key
for the agent (retrieval, the API's /search and the MCP server work without one).
git clone https://github.com/namespaceMarcello/lector && cd lector
docker compose up -d db # Postgres 17 + pgvector on localhost:5433
python -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"
lector ingest # loads the pre-computed vectors from data/
export ANTHROPIC_API_KEY=sk-ant-...
lector ask "Quali pratiche di IA sono vietate?"The first run downloads the embedding model (intfloat/multilingual-e5-large,
2.2 GB) into the fastembed cache; it is needed to embed queries. Passage vectors for the
whole Act ship in data/, so ingestion takes seconds instead of ~20 minutes per
language on CPU (lector ingest --recompute rebuilds them).
Or everything in containers:
ANTHROPIC_API_KEY=sk-ant-... docker compose up -d
docker compose run --rm api lector ingest
curl -s localhost:8000/ask -H 'content-type: application/json' \
-d '{"question": "Do chatbots have to disclose that they are AI?"}'Usage
lector search "real-time remote biometric identification" -k 5 # retrieval only
lector search "sistemi ad alto rischio" --lang it --mode keyword
lector ask "Which obligations do deployers of high-risk systems have?" --json
lector eval retrieval # the table above
lector eval answers --limit 10 --out results/answers.json # needs an API key
lector serve # http://127.0.0.1:8000/docs
lector fetch # re-download and re-parse the ActHTTP API
Method | Path | |
|
|
|
|
| passages only, no LLM |
|
| an article, annex or recital ( |
|
| chunk counts per language |
MCP
claude mcp add lector -- lector mcpTools: search_regulation(query, lang, k), get_article(doc_id, lang),
get_references(doc_id, lang). The client's model does the reasoning; Lector supplies
the passages and the citation ids.
Configuration
Variable | Default |
| — |
|
|
|
|
|
|
|
|
| empty (off); e.g. |
| fastembed default |
Project layout
src/lector/
corpus.py fetch + structure-aware parsing + cross-references
store.py Postgres: pgvector HNSW, BM25 on stemmed lexemes, reference graph
retrieve.py dense / BM25 / hybrid (RRF) retrieval, optional reranking
tools.py search_regulation · get_article · get_references
agent.py LangGraph: guard → agent ⇄ tools → verify
llm.py Anthropic SDK, cost accounting, refusal fallback
api.py FastAPI
mcp_server.py MCP server (stdio)
evaluate.py retrieval and answer metrics
eval/questions.jsonl
data/ parsed corpus and cached passage vectors
tests/ parser, graph, agent (scripted model), API, MCP, PostgresTests
pytest -q # no network, no API key, no model downloads
LECTOR_TEST_DATABASE_URL=postgresql://lector:lector@localhost:5433/lector_test pytest -qThe agent tests replace the Anthropic client with a scripted one, so the graph — tool loop, citation checks, revision round, tool budget, per-thread memory, refusal fallback handling — is tested deterministically.
Data
The text of Regulation (EU) 2024/1689 in data/ is © European Union
(EUR-Lex), reused under Commission
Decision 2011/833/EU. Lector is not legal advice.
Built by Marcello Costagliola with Claude Code. MIT license.
This server cannot be deployed
Maintenance
Related MCP Connectors
EU compliance corpus across 8 frameworks (NIS2, DORA, AI Act, ISO 27001 + more) via MCP.
Provenance-backed EU and UK legislation for AI agents, addressable to the individual provision.
Search German and EU law from official sources with your AI assistant. PRIMAMCP provides citable legal texts via MCP, with daily updates and hosting in Germany.
AI governance MCP server for EU AI Act compliance and jurisdiction verification
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables querying US compliance regulations including HIPAA, CCPA, SOX, and more directly from AI assistants and MCP-compatible clients.72 npmApache 2.0
- AlicenseNot gradedqualityBmaintenanceEnables searching and quoting EU legislation with verifiable EUR-Lex citations, including GDPR, NIS2, DORA, and the EU AI Act.131 npmMIT
- AlicenseNot gradedqualityFmaintenanceEnables AI assistants to search and retrieve French legislation, case law, and EU law integrations from official sources via MCP.115 npm1Apache 2.0
- AlicenseNot gradedqualityBmaintenanceAcquis gives your assistant exact, verifiable access to EU digital regulation. Instead of paraphrasing from training data, it returns the verbatim provision of the current consolidated version — with the full citation (act, article, paragraph, point), its in-force status, the consolidation date, and a deep link to EUR-Lex so every claim can be checked. The legal text is rendered from the signed cMIT