nl-eli-mcp
This server provides access to Dutch consolidated legislation (BWB) and court decisions (Rechtspraak Open Data), enabling research and citation of official Dutch legal sources via public, keyless APIs.
Available tools:
nl_search(query, on_date): Search for consolidated acts by keywords in their title, in force on a given date (defaults to today). Returns metadata with persistent identifiers, citations, and source URLs.nl_get_act(bwb_id, on_date): Retrieve detailed metadata for a specific act by its BWB identifier (e.g.BWBR0005537) — including title, authority, version date, and legal areas.nl_get_text(bwb_id, on_date): Fetch the full consolidated XML of a Dutch act in force on a given date, including byte size and version info.nl_case_search(date_from, date_to, creator, subject): List court decisions filtered by date range, court, or legal area. No free-text search — metadata filters only.nl_get_decision(ecli): Retrieve a specific court decision by its ECLI identifier (e.g.ECLI:NL:HR:2020:1), including court, dates, case number, subject, and full text.
Key notes:
All tools are read-only.
Every response includes a citation contract: a persistent identifier (
eli_uri), human-readable citation, and official source URL.Historical versions are accessible by passing an
on_date(YYYY-MM-DD) parameter.The
eli_uricarries the officialwetten.overheid.nl/idtoestand URI, as the Netherlands does not publish native ELI URIs.
Click on "Install 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., "@nl-eli-mcpget the full text of act BWBR0005537"
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.
nl-eli-mcp
Install (one command)
Published on PyPI + MCP Registry (io.github.matematicsolutions/nl-eli-mcp). Run without cloning:
uvx nl-eli-mcpConfigure your MCP client (stdio):
{ "mcpServers": { "nl-eli-mcp": { "command": "uvx", "args": ["nl-eli-mcp"] } } }Windows 11 with Smart App Control
Smart App Control blocks unsigned executables, which covers uvx.exe, pip.exe
and the nl-eli-mcp.exe launcher that pip writes at install time. The python.exe and
py.exe from the python.org installer are signed by the Python Software
Foundation, so running the module through the interpreter works:
python -m pip install nl-eli-mcp
python -m nl_eli_mcppip.exe is blocked for the same reason, so install with python -m pip, not
pip install. If python is not on PATH, use the Windows launcher: py -3 -m nl_eli_mcp.
{ "mcpServers": { "nl-eli-mcp": { "command": "python", "args": ["-m", "nl_eli_mcp"] } } }Do not turn Smart App Control off to work around this - it cannot be re-enabled without reinstalling Windows.
Building from source: see Install.
An MCP server for the Dutch consolidated legislation BWB (Basiswettenbestand), served by
KOOP over the official SRU API (zoekservice.overheid.nl, keyless). It gives an AI agent the
version of an act in force on a given date, with a verifiable citation: a persistent
identifier, a human-readable citation, and a link to the official source.
Part of the eu-legal-mcp line by MateMatic — one connector per EU member state, the same citation contract everywhere.
On ELI. The Netherlands does not publish native ELI (
/eli/) URIs on consolidated BWB. To keep the line's contract honest,eli_uricarries the official persistent identifier instead — thewetten.overheid.nl/idtoestand URI (e.g.http://wetten.overheid.nl/id/BWBR0005537/2026-06-04/0). The connector never fabricates an/eli/URI and says so in its tool instructions. SeeDISCOVERY.md.
Related MCP server: Agent.ai MCP Server
Tools
Tool | What it does |
| Find acts by words in the title that are in force on a date. Returns distinct acts, each with the citation contract. |
| Metadata for one act (e.g. |
| The full consolidated XML (BWB toestand) of one act. |
| List court decisions (Rechtspraak Open Data) by date range / court / subject. No free-text; each hit carries a native |
| A court decision by its ECLI (e.g. |
| Declare what this connector covers, when each family was captured, and - explicitly - what it does NOT cover. Every gap carries a fallback. |
Legislation comes from the BWB (KOOP SRU); case law comes from Rechtspraak Open Data
(data.rechtspraak.nl), keyed by native ECLI. Every response carries the citation contract:
eli_uri— the official persistent identifier (toestand URI; see the ELI note above).human_readable_citation— the official short title (citeertitel), e.g. Algemene wet bestuursrecht.source_url— the browsablewetten.overheid.nlpage for that version.
Versions and dates
Each act has many time-stamped versions. The tools default to the version in force today;
pass on_date (YYYY-MM-DD) to pin a historical or future version. An act with no version
valid on that date returns not_found — retry with another on_date.
Install
pip install -e ".[dev]"Register it with your MCP client (see .mcp.json.example):
{
"mcpServers": {
"nl-eli-mcp": {
"command": "nl-eli-mcp",
"env": {
"NL_ELI_BASE_URL": "https://zoekservice.overheid.nl/sru/Search",
"NL_ELI_CACHE_DIR": "~/.matematic/cache/nl-eli",
"NL_ELI_AUDIT_DIR": "~/.matematic/audit"
}
}
}
}Design
Public data only. Read-only against the keyless KOOP SRU API and the official repository host; nothing is sent beyond the query / identifier and the date.
Audit log. Every call appends one JSON line to
~/.matematic/audit/nl-eli-mcp.jsonl(AI Act art. 12 record-keeping).Vendor-neutral. No LLM provider, no telemetry; own backoff + on-disk cache.
No fabrication. Identifiers and titles are parsed from the source record. If KOOP's schema changes, the connector fails loudly rather than returning stale or invented data.
See CONSTITUTION.md (the 4 principles) and DISCOVERY.md (how the source was mapped).
Tests
pytest tests/test_instructions_drift.py tests/test_parse.py # offline
pytest tests/test_smoke.py # live KOOP APILicence
Apache-2.0. The Dutch legislation served is official public data of the Kingdom of the Netherlands; this connector adds no rights over it.
Available Tools
6 toolsnl_case_searchARead-onlyIdempotent
List Dutch court decisions (Rechtspraak Open Data) by metadata filters.
The open-data search has NO free-text query. Filter by a date range and, optionally, a
court (creator) or legal-area (subject) authority URI, then fetch a decision with
nl_get_decision.
| Name | Required | Description | Default |
|---|---|---|---|
| creator | No | optional court authority URI (Instantie), passed through verbatim. | |
| date_to | No | latest decision date (YYYY-MM-DD). | |
| subject | No | optional legal-area authority URI (Rechtsgebied), passed through verbatim. | |
| date_from | No | earliest decision date (YYYY-MM-DD). | |
| max_results | No | 1..50. |
Output Schema
| Name | Required | Description |
|---|---|---|
| items | No | |
| total | Yes | |
| returned | Yes | |
| dataset_note | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the tool as read-only and idempotent. The description adds a key behavioral constraint: no free-text query. This goes beyond annotations and provides valuable transparency, though it could mention more about pagination or result limits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise with three sentences: purpose, limitation and filter options, and next step. Every sentence adds value, and the structure is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's 5 optional parameters and existing output schema, the description covers the data source, the filtering workflow, the no-text limitation, and the recommended follow-up tool. It is sufficiently complete for someone to use it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% so baseline is 3. The description adds meaning by explaining that creator and subject are authority URIs and that date_from/date_to form a range. It also suggests the follow-up fetch, enhancing understanding of parameter usage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool lists Dutch court decisions by metadata filters, specifying the data source (Rechtspraak Open Data). It distinguishes from siblings by mentioning nl_get_decision for fetching, but does not explicitly contrast with other sibling tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains that there is no free-text query and recommends filtering by date range with optional authority URIs, then fetching a decision with nl_get_decision. This provides clear usage context but lacks explicit when-not-to-use or alternative tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
nl_coverageARead-onlyIdempotent
Declare what this connector covers, how it is sourced, and what it does NOT cover.
Call this before telling a user that the law "does not contain" something, and whenever a search comes back empty: the absence may be a gap in this connector rather than in the law. Every gap carries a fallback saying where to look instead.
Returns:
Coverage with families, an as-of note, and a non-empty list of known gaps.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| status | No | |
| families | No | |
| as_of_note | Yes | States what the dates mean, and what they do not promise. |
| known_gaps | No | Never empty. An empty list would mean 'not checked', not 'no gaps'. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnly, openWorld, idempotent), the description discloses important behavioral semantics: this tool is a safeguard against false negatives, may reveal connector gaps rather than legal absence, and returns a structured Coverage object with families, an as-of note, and fallback locations. This is substantive context not implied by the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose, then provides usage triggers, and ends with a clean return-value summary. Every sentence contributes meaningful guidance, with no filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter tool with an output schema, the description covers why to call it, when to call it, what it returns, and what business consequence follows from its results. No critical operational information is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so there is no parameter semantics to document. The baseline for no-parameter tools is 4, and the description appropriately focuses on output semantics instead.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a precise purpose: 'Declare what this connector covers, how it is sourced, and what it does NOT cover.' This clearly identifies a distinct meta-tool that reports coverage rather than performing legal search or retrieval, differentiating it from siblings like nl_search and nl_get_act.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit call conditions: use before telling a user the law 'does not contain' something, and whenever a search comes back empty. It also explains the rationale—absence may be a gap in the connector not the law—and notes that every gap points to a fallback source, giving the agent actionable guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
nl_get_actARead-onlyIdempotent
Fetch metadata for the version of a Dutch act in force on a date.
| Name | Required | Description | Default |
|---|---|---|---|
| bwb_id | Yes | e.g. ``"BWBR0005537"``. | |
| on_date | No | optional ``YYYY-MM-DD``; defaults to today. |
Output Schema
| Name | Required | Description |
|---|---|---|
| title | No | |
| bwb_id | No | |
| eli_uri | No | |
| act_type | No | |
| text_url | No | |
| authority | No | |
| source_url | No | |
| legal_areas | No | |
| version_date | No | |
| date_modified | No | |
| human_readable_citation | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and destructiveHint=false. The description does not add behavioral details beyond stating it fetches metadata, which is consistent with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Single sentence, front-loaded, no unnecessary words. Every part earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With comprehensive annotations and an existing output schema, the description is adequate for a simple metadata fetch tool. It could explicitly state that it only returns metadata, but that is implied.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, with descriptions already present in the input schema. The description merely repeats these (e.g., example for bwb_id and default for on_date), adding no new meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it fetches metadata for a version of a Dutch act in force on a date, using a specific verb and resource. It is distinct from sibling tools that deal with cases, decisions, text, or search.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The context is clear: this tool is for fetching metadata of Dutch acts. While no explicit alternatives or when-not-to-use guidance is provided, the sibling tool names alone allow inference of differentiation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
nl_get_decisionARead-onlyIdempotent
Fetch a Dutch court decision by its ECLI (Rechtspraak Open Data).
| Name | Required | Description | Default |
|---|---|---|---|
| ecli | Yes | e.g. ``ECLI:NL:HR:2020:1``. |
Output Schema
| Name | Required | Description |
|---|---|---|
| date | No | |
| ecli | No | |
| text | No | |
| court | No | |
| title | No | |
| issued | No | |
| subject | No | |
| byte_size | No | |
| source_url | No | |
| zaaknummer | No | |
| dataset_note | No | |
| human_readable_citation | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, openWorldHint, idempotentHint, destructiveHint=false. Description adds source context (Rechtspraak Open Data) but no additional behavioral details like error handling or rate limits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Single sentence, 13 words, zero wasted information. Front-loaded with purpose and key identifier.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter fetch tool with output schema and thorough annotations, the description covers the essential purpose and source. No missing critical information.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%. The description adds an example for the ecli parameter, but the schema already includes a similar example. No additional semantics beyond what schema provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description clearly states the action (Fetch), resource (Dutch court decision), and method (by its ECLI). It distinguishes from siblings like nl_case_search by specifying the exact identifier.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Implied usage: use when you have a known ECLI. However, no explicit guidance on when to avoid this tool or alternative tools (e.g., use nl_case_search if you don't have an ECLI).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
nl_get_textARead-onlyIdempotent
Fetch the full consolidated XML of a Dutch act in force on a date.
| Name | Required | Description | Default |
|---|---|---|---|
| bwb_id | Yes | e.g. ``"BWBR0005537"``. | |
| on_date | No | optional ``YYYY-MM-DD``; defaults to today. |
Output Schema
| Name | Required | Description |
|---|---|---|
| bwb_id | Yes | |
| format | No | |
| content | No | |
| eli_uri | No | |
| on_date | Yes | |
| text_url | No | |
| byte_size | No | |
| source_url | No | |
| dataset_note | No | |
| version_date | No | |
| human_readable_citation | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate read-only and idempotent behavior. The description adds context about the return format (XML) and date filtering, but does not disclose potential pagination or size limits. No contradictions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Single sentence with no redundancy. Efficiently conveys the tool's purpose and constraints.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given rich annotations, output schema presence, and simple parameters, the description provides sufficient context for correct use without missing critical details.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% with clear parameter descriptions (bwb_id example, on_date format and default). The description adds no extra meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it fetches the full consolidated XML of a Dutch act, specifying scope (in force on a date) and distinguishing it from sibling tools like nl_get_act which may return different formats.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance on when to use this tool versus alternatives such as nl_get_act or nl_search. The description implies usage for fetching XML data but does not exclude other use cases.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
nl_searchARead-onlyIdempotent
Search Dutch consolidated acts by words in the title, in force on a date.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | words to match in the act title, e.g. ``"bestuursrecht"``. | |
| on_date | No | optional ``YYYY-MM-DD``; defaults to today (acts in force today). |
Output Schema
| Name | Required | Description |
|---|---|---|
| items | No | |
| query | Yes | |
| on_date | Yes | |
| returned | Yes | |
| dataset_note | No | |
| total_matched | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and destructiveHint, making safety and idempotency clear. The description adds the detail that results are acts 'in force on a date', but does not disclose any additional behavioral traits (e.g., pagination, ordering). It does not contradict annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single concise sentence that efficiently conveys the tool's purpose and constraints. Every word is necessary, and no information is redundant. It is well-structured for quick comprehension.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the low parameter count (2), full schema coverage, and presence of output schema and annotations, the description sufficiently outlines the tool's behavior. It specifies the search target (title words) and temporal condition (in force on a date). It does not detail output format, but that is covered by the output schema. Minor missing context like result ordering or error cases, but overall complete for the tool's simplicity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with descriptions for both parameters. The description adds minimal extra meaning: it reiterates that query is 'words in the act title' and on_date is 'optional YYYY-MM-DD defaults to today'. This does not significantly enhance what the schema already provides, so baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description explicitly states the verb 'Search', the resource 'Dutch consolidated acts', and the scope 'by words in the title, in force on a date'. This clearly differentiates it from sibling tools like nl_case_search (cases) and nl_get_act (retrieve specific act).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage for finding acts by title words with a date constraint, but does not explicitly state when to use this tool versus alternatives (e.g., nl_get_act for a known act) or when not to use it. No exclusions or alternatives are mentioned.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
1 tool update
v0.4.3- Added
nl_coverage
5 tool updates
v0.2.0- First observed
nl_case_search - First observed
nl_get_act - First observed
nl_get_decision - First observed
nl_get_text - First observed
nl_search
TDQS
Scored across 6 tools
Each tool targets a clearly distinct operation: searching acts, fetching act metadata, fetching act text, searching cases, fetching a specific decision, and describing coverage. There is no realistic overlap that could lead an agent to pick the wrong tool.
All tools share the nl_ prefix, which creates a recognizable namespace, but the internal pattern is not uniform: nl_get_* uses verb-first naming, while nl_case_search is object-first and nl_coverage is a bare noun. This is a minor inconsistency rather than a confusing mix.
Six tools is well-scoped for a legal information connector covering both legislation and case law. Each tool serves a necessary retrieval or orientation purpose, and none feels redundant.
The set covers search, metadata retrieval, and full-text retrieval for acts, plus metadata-based search and full-decision retrieval for case law. The dedicated coverage tool explicitly documents limitations and fallbacks, which closes the main practical gap in legal data connectors.
Maintenance
Related MCP Connectors
- UnifAPIOAuthcom.unifapi
Hosted MCP server for live public-data APIs and Skills for AI agents.
Capability registry for the agentic economy. Semantic search over verified MCP server listings.
An MCP server that gives your AI access to the source code and docs of all public github repos
An MCP server that provides congressional transcripts
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceAn intelligent MCP server that enables AI agents to crawl, index, and semantically search official framework documentation using local RAG. It prevents hallucinations by providing precise, up-to-date documentation excerpts directly into the AI's context window.1-
- AlicenseCqualityDmaintenanceAn MCP server that integrates with the Agent.ai API to provide web text extraction, web screenshots, and YouTube transcript capabilities through a dynamic function loading system.100144MIT
- AlicenseNot gradedqualityDmaintenanceAn MCP server that provides tools to fetch live, version-accurate documentation, changelogs, examples, and method signatures for npm and PyPI packages, preventing AI coding agents from hallucinating stale APIs.15ISC
- FlicenseNot gradedqualityDmaintenanceThis MCP server provides LLMs with a live, curated knowledge base of AI agent research, world models, and source-code reviews, enabling personalized and context-aware responses. Users can either connect to the hosted knowledge or build and host their own vault.-