openlex-mcp
Search and retrieve Canton Zurich legislation (ZH-Lex) — full-text law search, article extraction, education-law shortcuts, live zh.ch metadata, and cache refresh — all read-only except cache update.
Full-text search laws (
zhlaw_search_laws): FTS5/BM25 search across ~970 ZH laws, filterable by legal-area prefix (e.g. 412 education, 331 tax, 700 building); max 50 hits.Fetch a law (
zhlaw_get_law): look up by LS number (e.g.412.100) or abbreviation (e.g.VSG), optionally with full text (truncated at 5000 chars).Extract an article (
zhlaw_get_article): pull a specific article (e.g. Art. 28, 28a, 28bis) with title, paragraphs, and full text.List/browse laws (
zhlaw_list_laws): paginated listing filtered by legal-area prefix and active status — metadata only, no full text.Education-law shortcut (
zhlaw_find_education_laws): targeted search in the LS 412.x series (VSG, VSV, LPG, LPVO…), with automatic fallback to all areas.Search within one law (
zhlaw_search_articles): substring search across all articles of a known law (e.g. find 'Elternrat' in VSG).Live metadata from zh.ch (
zhlaw_get_law_metadata): fetch current PDF links, change date, and ZH-Lex URL for one LS number (only tool with a live HTTP call).Refresh cache (
zhlaw_update_cache): re-download the HuggingFace dataset into local SQLite+FTS5 (24h TTL; not truly read-only, though non-destructive).Caveats: corpus is frozen at 2023-01-01, repeals after that are invisible, and
zhlaw_update_cachere-downloads the same snapshot rather than newer laws; informational only, not legal advice.
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., "@openlex-mcpShow me Art. 55 of the Volksschulgesetz"
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.
🇨🇭 Part of the Swiss Public Data MCP Portfolio
⚖️ openlex-mcp
MCP Server for Canton Zurich legislation (ZH-Lex) — full-text search, article extraction, and education law tools for ~970 cantonal laws
Overview
openlex-mcp provides AI-native access to the entire legal collection of Canton Zurich (Zürcher Gesetzessammlung). It combines full-text data from HuggingFace with live metadata from the official zh.ch website, storing everything in a local SQLite database with FTS5 full-text indexing for sub-50ms search performance.
Source | Data | Access |
HuggingFace | 974 ZH laws — full text (PDF extracts) | Cached locally as SQLite + FTS5 |
zh.ch ZH-Lex | Current metadata, PDF links, validity status | Live HTTP requests |
Built for the Schulamt (school department) of the City of Zurich, but covers all areas of cantonal law — from tax law to building regulations.
Anchor demo query: "What does the Volksschulgesetz say about parental involvement? Show me Art. 55 VSG and find all articles that mention 'Elternrat'."
Related MCP server: swiss-courts-mcp
Features
⚖️ 8 tools covering search, retrieval, article extraction, and cache management
🔍 FTS5 full-text search across ~970 cantonal laws with BM25 ranking
📑 Article extraction — parse individual articles (Art. / §) with paragraph detection
🏫 Education law shortcuts — specialized search for LS 412.x series (Volksschulgesetz, Lehrpersonalverordnung, etc.)
🌐 Live metadata from zh.ch for current validity status and PDF links
💾 Hybrid architecture — cached full-text (HuggingFace) + live metadata (zh.ch)
🔓 No API key required — all data under open licenses (CC-BY-SA 4.0)
☁️ Dual transport — stdio (Claude Desktop) + Streamable HTTP (cloud)
Development Phase
Current phase: Phase 1 — Read-Only. All tools are read-only (readOnlyHint: true); no writes to external systems. See ROADMAP.md for the phase plan and transition gates before any write or multi-agent capability is added.
Prerequisites
Python 3.11+
uv (recommended) or pip
Internet connection (for initial data download and live metadata)
Installation
# Clone the repository
git clone https://github.com/malkreide/openlex-mcp.git
cd openlex-mcp
# Install
pip install -e .
# or with uv:
uv pip install -e .Quickstart
# stdio (for Claude Desktop)
python -m openlex_mcp.server
# Streamable HTTP — binds to 127.0.0.1:8000 by default (localhost only)
python -m openlex_mcp.server --http --port 8000Network binding
By default the HTTP transport binds to 127.0.0.1 (localhost only). The host
and port are configurable via the MCP_HOST / MCP_PORT environment variables
(or the --host / --port CLI flags, which take precedence).
Never bind to 0.0.0.0 outside a container — it exposes the server to your
local network (NeighborJack risk). For containerized/cloud deployments set
MCP_HOST=0.0.0.0 explicitly; when that happens outside a detected container the
server logs a warning.
Try it immediately in Claude Desktop:
"What is the Volksschulgesetz (VSG)?" "Find all Zurich laws about data protection" "Show me Art. 1 of the Volksschulgesetz" "Which education laws mention 'Schulleitung'?"
Configuration
Claude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"openlex": {
"command": "python",
"args": ["-m", "openlex_mcp.server"]
}
}
}Or with the installed entry point:
{
"mcpServers": {
"openlex": {
"command": "openlex-mcp"
}
}
}Config file locations:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:
%APPDATA%\Claude\claude_desktop_config.json
Cloud Deployment (SSE for browser access)
For use via claude.ai in the browser (e.g. on managed workstations without local software):
Render.com (recommended):
Push/fork the repository to GitHub
On render.com: New Web Service → connect GitHub repo
Set start command:
python -m openlex_mcp.server --http --port 8000Set environment variable
MCP_HOST=0.0.0.0so the container is reachable (the code default is127.0.0.1; Render sets theRENDERenv var, so no NeighborJack warning is logged)Set
MCP_CORS_ORIGINS=https://claude.aiso the browser can read theMcp-Session-Idheader (comma-separated list; no wildcard — defaults to empty, i.e. no cross-origin access)In claude.ai under Settings → MCP Servers, add:
https://your-app.onrender.com/sse
💡 "stdio for the developer laptop, SSE for the browser."
Available Tools
Search & Browse
Tool | Description |
| Full-text search across all ~970 ZH laws (FTS5 + BM25 ranking) |
| Retrieve a law by LS number (e.g. |
| List and filter laws by legal area prefix |
| Specialized search in education law (LS 412.x series) |
Article Extraction
Tool | Description |
| Extract a specific article from a law (e.g. Art. 28 VSG) |
| Search within all articles of a specific law |
Metadata & Cache
Tool | Description |
| Get live metadata from zh.ch (PDF links, validity status) |
| Refresh the local data cache from HuggingFace |
Key Legal Area Prefixes (LS Numbers)
Prefix | Legal Area | Example |
| Constitution and popular rights | Kantonsverfassung |
| Administrative procedure | Datenschutzgesetz |
| Tax law | Steuergesetz |
| Education and schools | Volksschulgesetz (VSG) |
| Spatial planning and building | Planungs- und Baugesetz |
| Health | Gesundheitsgesetz |
Example Use Cases
Query | Tool |
"What is the Volksschulgesetz?" |
|
"Find laws about data protection" |
|
"Show me Art. 55 VSG" |
|
"Which education laws mention Schulleitung?" |
|
"Find all articles about Elternrat in the VSG" |
|
"Is LS 412.100 still in force?" |
|
Architecture
┌─────────────────┐ ┌──────────────────────────────┐ ┌──────────────────────────┐
│ Claude / AI │────▶│ OpenLex MCP │────▶│ HuggingFace │
│ (MCP Host) │◀────│ (MCP Server) │◀────│ rcds/swiss_legislation │
└─────────────────┘ │ │ │ (974 ZH laws, cached) │
│ 8 Tools │ ├──────────────────────────┤
│ SQLite + FTS5 Cache │────▶│ zh.ch ZH-Lex │
│ Stdio | HTTP │◀────│ (live metadata + PDFs) │
│ │ ├──────────────────────────┤
│ No authentication required │ │ LexFind.ch │
└──────────────────────────────┘ │ (links only) │
└──────────────────────────┘Data Source Characteristics
Source | Protocol | Coverage | Auth | License |
HuggingFace | Datasets API | 974 ZH laws (full text) | None | CC-BY-SA 4.0 |
zh.ch ZH-Lex | HTTP/HTML | Current metadata, PDFs | None | Public |
LexFind.ch | HTTP | Cross-cantonal links | None | Public |
Design Decision: Tools-only (no MCP Resources)
All 8 endpoints are exposed as Tools rather than MCP Resources. Rationale:
Every lookup is parametric — queries, abbreviations, article numbers vary per call. Static Resources (one URI per document) don't capture this naturally.
The corpus is 974 laws × many articles — registering each as a Resource URI would create an impractically large resource list.
MCP Resource templates (
zhlex://laws/{sr_number}) are a future consideration for Phase 2 if clients benefit from resource-level caching or subscriptions.
Scaling Constraints
The constraint depends on the protocol era the client speaks:
2026-07-28(modern) — every request is a self-contained POST carrying its own_metaenvelope; the server answers without issuing anMcp-Session-Idand keeps no session between requests. Any replica can answer any request; no shared store, no sticky routing. (subscriptions/listenstreams live on the replica that opened them — this server's lists are fixed at import, so there is nothing to fan out.)Handshake era (
initialize, up to2025-11-25) — session state is kept in-process. Multiple replicas break active sessions because there is no shared session store (Redis, Durable Objects, etc.). A single-replica Render deployment routes all requests to one process, so no sticky-session LB is needed today.
Before scaling handshake-era clients beyond one instance: either add a shared session store or configure your edge load balancer to route on the Mcp-Session-Id header with a stick-table and an appropriate TTL.
MCP Protocol Version
Item | Value |
Served via the |
|
Served via the per-request envelope |
|
Who picks | The client's first request, once per connection. A request carrying the |
SDK |
|
Cache hints |
|
| The package version ( |
Deprecated in | Logging ( |
Pinned in |
|
Update policy
When
mcpis upgraded (via Dependabot PR), verify the protocol version in the SDK release notes.If the protocol version changes, update
MCP_PROTOCOL_VERSIONinserver.py, regeneratedocs/tool-hashes.json(PYTHONPATH=src python scripts/gen_tool_hashes.py --write), and note the change inCHANGELOG.md.Run
pytest tests/ -m "not live"to confirm compatibility before merging.
Project Structure
openlex-mcp/
├── src/openlex_mcp/
│ ├── __init__.py # Package
│ ├── __main__.py # Entry point for python -m
│ ├── server.py # 8 MCP tool definitions (FastMCP) + Settings
│ ├── responses.py # Typed structured response envelopes (SDK-002)
│ ├── logging_config.py # structlog JSON logging setup (OBS-003)
│ ├── net.py # SSRF/egress-hardened outbound HTTP
│ ├── api_client.py # zh.ch HTTP client + metadata extraction
│ ├── data_cache.py # SQLite + FTS5 cache management
│ └── law_parser.py # Article extraction from law texts
├── tests/ # 89 unit tests (parser, cache, net, tools…)
├── scripts/gen_tool_hashes.py # Tool-definition hash snapshot (SEC-022)
├── docs/ # network-egress, secret-management, tool-hashes
├── .github/workflows/ci.yml # GitHub Actions (Python 3.11/3.12/3.13)
├── .github/dependabot.yml # Monthly grouped dependency PRs (ARCH-012)
├── Dockerfile # Hardened multi-stage build (SEC-007/SCALE-004)
├── compose.yml # Resource limits for local testing (SCALE-006)
├── pyproject.toml
├── claude_desktop_config.json # Example config for Claude Desktop
├── CHANGELOG.md
├── ROADMAP.md # Phase plan + accepted-risk register
├── CONTRIBUTING.md # Contribution guide (English)
├── CONTRIBUTING.de.md # Contribution guide (German)
├── SECURITY.md # Security policy (English)
├── SECURITY.de.md # Security policy (German)
├── LICENSE
├── README.md # This file (English)
└── README.de.md # German versionTool output format
All tools return a structured response envelope (not Markdown text), so MCP
clients receive structuredContent they can parse directly:
{
"source": "Kanton Zürich Rechtssammlung — HuggingFace … & zh.ch",
"provenance": "cache", // cache | live | parser | cache+parser | none
"result_type": "law_summaries", // law_summaries | law_detail | articles | metadata | cache_status
"count": 2,
"message": null, // human-readable guidance for empty/edge results
"results": [ /* typed items */ ]
}Known Limitations
HuggingFace dataset: The
html_contentfield is unreliable (cross-contaminated between laws); the server usespdf_contentinstead, which is correct but has PDF extraction artefacts (hyphenation, layout artefacts)Article parser: PDF text extraction sometimes merges article boundaries; complex nested articles may not parse perfectly
Initial load: First start requires ~25s to download and index 974 laws from HuggingFace (~38 MB SQLite database)
zh.ch metadata: No official API; metadata extraction relies on HTML patterns that may change
Offline mode: Full-text search works offline after initial load; live metadata requires internet
The corpus is frozen at 2023-01-01. This is the limitation that matters most for a legal server, and it was the one not stated. The newest version in the entire dataset carries
version_active_since = 2023-01-01; the HuggingFace dataset itself was last touched 2024-10-10. The 24-hour cache TTL andprovenance="cache"describe where an answer came from, not how old the laws in it are. Every response now carriescorpus_as_ofandcorpus_notealongsideprovenance.Repeals after the cut-off are invisible. All 974 entries carry
is_active = Trueand not one has aversion_inactive_since. That is not a server bug — the source lists only the statutes in force at snapshot time. The consequence is what matters: a law repealed since then still appears to be in force. Consult the ZH-Lex permalink for the operative text.zhlaw_update_cachedoes not make the laws newer. It re-downloads the same frozen dataset. Its docstring previously read "only call when law search results seem outdated", which suggested exactly the effect it does not have.
Safety & Limits
Aspect | Details |
Access | Read-only ( |
Personal data | No personal data — all sources are aggregated, public legal texts |
Rate limits | Built-in per-query caps (max 50 search results, 5000 chars content preview) |
Timeout | 30 seconds per HTTP call to zh.ch |
Egress | Outbound requests are restricted to an allow-list ( |
Authentication | No API keys required — HuggingFace dataset is public, zh.ch is open |
Security posture (Lethal Trifecta) | Score 1 / 3: public data only (no private/sensitive data) ✓ · GET-only egress to |
Session handling |
|
Secrets | No secrets held — all data sources are public. See docs/secret-management.md. |
Licenses | Law data: CC-BY-SA 4.0 (rcds/swiss_legislation); zh.ch metadata: public |
Terms of Service | Subject to ToS of HuggingFace and Canton Zurich |
Disclaimer | This server provides legal texts for informational purposes only — it does not constitute legal advice |
To report a vulnerability, see the Security Policy.
Testing
# Unit + contract tests (no network) — this is what CI runs
PYTHONPATH=src pytest tests/ -m "not live"
# Live tests against zh.ch and HuggingFace
PYTHONPATH=src pytest tests/ -m "live"
# Re-measure the corpus date and the live hosts
PYTHONPATH=src python scripts/record_fixtures.py150 tests — 142 offline, 8 live. Eight tools, eight live tests: the best
coverage in this portfolio, which is why the finding here is not about
mechanics but about a confusion between two questions. provenance="cache"
answers where an answer came from; corpus_as_of answers how old the laws
in it are. Only the first was ever answered, and the second is the one a user
means when they ask "is this current?".
A measurement limit, deliberately not resolved by editing a test
test_live_get_law_metadata fails in the recording environment: zhlex.zh.ch
is not reachable from it. Nothing follows from that. Public DNS resolves
the host (NOERROR, 194.247.8.174) and an NXDOMAIN control shows the query
discriminates — so the limit is the environment's, not the source's.
The test was therefore left untouched. A test you see red because your own
network cannot get out is not a test to rewrite; rewriting it would leave you
measuring your own environment instead of the source. PROVENANCE.md records
this as open.
Changelog
See CHANGELOG.md
Roadmap
See ROADMAP.md
Contributing
See CONTRIBUTING.md
Security
See SECURITY.md
License
MIT License — see LICENSE
Author
Hayal Oezkan · malkreide
Credits & Related Projects
Data: rcds/swiss_legislation — HuggingFace dataset (CC-BY-SA 4.0)
ZH-Lex: zh.ch Gesetzessammlung — Official Canton Zurich legal collection
LexFind: lexfind.ch — Cross-cantonal legislation database
Protocol: Model Context Protocol — Anthropic / Linux Foundation
Related: swiss-courts-mcp — Law text + case law = complete legal research
Related: zurich-opendata-mcp — Law text + city council decisions = full context
Portfolio: Swiss Public Data MCP Portfolio
Installation
Run via uv's uvx — no clone or manual install needed. Add to your MCP client config (mcpServers for Claude Desktop, Cursor and Windsurf; use a top-level servers key for VS Code in .vscode/mcp.json):
{
"mcpServers": {
"openlex-mcp": {
"command": "uvx",
"args": [
"openlex-mcp"
]
}
}
}Available Tools
8 toolsopenlex__zhlaw_find_education_lawsARead-onlyIdempotent
Sucht gezielt im Zürcher Bildungsrecht (Ordnungsnummern 412.x).
Bevorzuge dieses Tool gegenüber openlex__zhlaw_search_laws wenn die Anfrage klar im Bildungsbereich liegt (Schule, Lehrpersonen, Kindergarten, Sonderpädagogik, Tagesstrukturen). Schneller und präziser als die allgemeine Suche, da nur die 412.x-Serie (VSG, VSV, LPG, LPVO, VSM u.a.) durchsucht wird.
Sucht ausschliesslich in aktiven 412.x-Gesetzen. Bei keinen Treffern: automatischer Fallback auf alle Rechtsgebiete mit Hinweis im message- Feld. Für Artikel innerhalb eines gefundenen Gesetzes: openlex__zhlaw_search_articles. Synergie: Fundstelle + swiss-courts-mcp → Rechtsprechung finden.
query='Elternrat', limit=10
| Name | Required | Description | Default |
|---|---|---|---|
| params | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | No | |
| source | No | |
| message | No | |
| results | No | |
| provenance | Yes | |
| corpus_note | No | |
| result_type | No | |
| corpus_as_of | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive/openWorld=false, so the safety profile is covered. The description adds genuine behavioral context beyond that: it searches only active 412.x laws and, crucially, falls back automatically to all legal areas with a hint in the message field when no hits occur.
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 XML-style tags (use_case, important_notes, example) front-load the routing decision and fallback behavior efficiently. Content is tight, though the tag scaffolding is slightly heavier than a plain sentence would need.
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 an output schema present, return values need not be explained. The description still covers fallback behavior, cross-tool routing, and a synergy note (swiss-courts-mcp) — enough for an agent to call it correctly. Only minor gaps (limit semantics) remain.
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 single required parameter 'query' is already well documented in the schema (subjects, examples). The description repeats the 412.x scoping and adds a usage example (query='Elternrat', limit=10), but adds little semantic detail beyond the schema, and the optional 'limit' parameter is not addressed. With the schema carrying the query semantics, 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?
States a specific verb (Sucht) plus resource (Zürcher Bildungsrecht, Ordnungsnummern 412.x), giving scope precisely. It explicitly distinguishes itself from the general sibling search_laws by contrasting the narrow 412.x-series with the full corpus.
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 <use_case> block names the alternative (openlex__zhlaw_search_laws) and the exact condition for choosing this tool (query clearly in the education domain: Schule, Lehrpersonen, Kindergarten, Sonderpädagogik, Tagesstrukturen). It also routes article-level lookups to openlex__zhlaw_search_articles, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
openlex__zhlaw_get_articleARead-onlyIdempotent
Extrahiert einen einzelnen Artikel aus einem Zürcher Gesetz.
Wenn der genaue Wortlaut eines bestimmten Artikels benötigt wird. Voraussetzung: Gesetz und Artikelnummer sind bekannt. Um zuerst relevante Artikel zu finden: openlex__zhlaw_search_articles nutzen.
Unterstützt Standard-Artikelnummern (28), Buchstaben-Artikel (28a) und Bis-Artikel (28bis). Liefert Titel, alle Absätze und Volltext des Artikels. Gibt count=0 zurück wenn der Artikel nicht existiert — Artikelnummer ohne 'Art.' angeben (nur die Zahl).
law_identifier='VSG', article_number='28'
| Name | Required | Description | Default |
|---|---|---|---|
| params | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | No | |
| source | No | |
| message | No | |
| results | No | |
| provenance | Yes | |
| corpus_note | No | |
| result_type | No | |
| corpus_as_of | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false, and openWorldHint=false, so the safety profile is covered. The description adds valuable behavioral context beyond annotations: it specifies the return content (title, all paragraphs, full text), the failure mode (count=0 if article doesn't exist), and supported article number formats (28, 28a, 28bis). It does not mention auth or rate limits, but none are implied.
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 structured with clear tags (<use_case>, <important_notes>, <example>) and front-loads the core purpose. Every sentence provides useful information without redundancy, and the example at the end is brief and directly actionable.
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 simplicity, the presence of an output schema, and the annotations covering safety, the description is complete. It covers purpose, usage, prerequisites, alternatives, return behavior, error handling, format details, and an example. Nothing essential is missing for an agent to invoke 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?
The context signals schema description coverage as 0%, so the description must compensate. It provides a concrete example (law_identifier='VSG', article_number='28') and thoroughly explains article_number formatting (no 'Art.' prefix, supports 28, 28a, 28bis). However, it does not explain the law_identifier parameter's accepted formats (Ordnungsnummer vs. Abkürzung) in the description itself, leaving that to 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 states a specific verb ('Extrahiert') and resource ('einzelnen Artikel aus einem Zürcher Gesetz'), and distinguishes itself from the sibling tool openlex__zhlaw_search_articles by noting that search is for finding relevant articles first. An agent can immediately understand this is for retrieving a specific known article.
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 <use_case> block explicitly states when to use this tool (when the exact wording of a specific article is needed), the prerequisite (law and article number known), and the alternative (openlex__zhlaw_search_articles to first find relevant articles). This is comprehensive guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
openlex__zhlaw_get_lawARead-onlyIdempotent
Ruft ein Zürcher Gesetz anhand der Ordnungsnummer oder Abkürzung ab.
Wenn die Ordnungsnummer oder Abkürzung eines Gesetzes bereits bekannt ist und Metadaten oder Volltext abgerufen werden sollen. Um ein Gesetz erst zu finden, openlex__zhlaw_search_laws oder openlex__zhlaw_find_education_laws vorschalten.
Unterstützt LS-Nummern ('412.100') und Abkürzungen ('VSG'). include_content=True liefert den Volltext (bis 5000 Zeichen, dann truncated=True). Bei Truncation: openlex__zhlaw_get_article für einzelne Artikel verwenden. Wichtige Gesetze: VSG, LPG, PBG, StG, KV.
identifier='VSG', include_content=False
| Name | Required | Description | Default |
|---|---|---|---|
| params | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | No | |
| source | No | |
| message | No | |
| results | No | |
| provenance | Yes | |
| corpus_note | No | |
| result_type | No | |
| corpus_as_of | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, idempotent, non-destructive, closed-world semantics, so the safety profile is covered. The description adds real behavioral detail beyond that: include_content=True returns full text capped at 5000 characters with truncated=True, and the recommended recovery path via get_article. It still doesn't state error behavior for unknown identifiers, which keeps it short of a 5.
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?
Three clearly tagged sections with the primary purpose front-loaded in the first sentence. The list of important laws (VSG, LPG, PBG, StG, KV) is mildly gratuitous for an agent that passes an identifier, but overall there is little waste.
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?
An output schema exists, so return values need no explanation here. The description covers identifiers, the content-vs-metadata toggle, the truncation limit, and the fallback tool — everything needed to call this one-required-parameter tool 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?
Measured schema coverage is 0%, so the description must carry the parameters and largely does: it names LS numbers ('412.100') and abbreviations ('VSG') for identifier and explains what include_content=True produces. It adds meaning beyond the raw schema, though it does not enumerate every supported abbreviation the schema lists.
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?
States a specific verb (abrufen) and resource (Zürcher Gesetz) plus the two accepted identifier forms (Ordnungsnummer or Abkürzung). It also names the sibling tools to route through when the identifier is unknown, so an agent can distinguish it from search_laws and get_law_metadata.
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 <use_case> block states the precondition explicitly (identifier already known) and names the alternatives (openlex__zhlaw_search_laws, openlex__zhlaw_find_education_laws) for the discovery path. The <important_notes> add a fallback route to get_article when content is truncated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
openlex__zhlaw_get_law_metadataARead-onlyIdempotent
Ruft aktuelle Metadaten eines Gesetzes live von zh.ch ab.
Wenn der aktuelle Stand eines Gesetzes auf zh.ch geprüft werden soll — z.B. ob es kürzlich geändert wurde, welche PDF-Version aktuell gilt oder welche ZH-Lex URL direkt verlinkt werden kann. Einziges Tool mit Live-HTTP-Aufruf; alle anderen Tools lesen den lokalen Cache.
Macht einen echten HTTP-Request an www.zh.ch (ca. 1–3 s). Erfordert Netzwerkzugang. Liefert: Seitentitel, PDF-Links, Änderungsdatum, ZH-Lex URL. Bei 404 oder Timeout: found=False mit Fehlerdetail im error-Feld. Nur Ordnungsnummern akzeptiert (kein Abkürzungs-Lookup).
sr_number='412.100'
| Name | Required | Description | Default |
|---|---|---|---|
| params | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | No | |
| source | No | |
| message | No | |
| results | No | |
| provenance | Yes | |
| corpus_note | No | |
| result_type | No | |
| corpus_as_of | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/openWorld/idempotent/non-destructive, so the description's added value is the operational detail: a real HTTP request to www.zh.ch taking 1-3s, the network-access requirement, the fields returned (title, PDF links, change date, ZH-Lex URL), and explicit 404/timeout behaviour (found=False with error detail). That is rich context beyond the structured hints.
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?
Tagged sections (<use_case>, <important_notes>, <example>) front-load the moment of use, then the caveats, then a concrete example. Every sentence carries information; nothing is padding despite the length.
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?
An output schema exists, yet the description still names the returned fields and the failure shape, which is more than required. For a single-parameter, open-world network tool, an agent has everything needed to call it correctly and interpret the result.
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 reported as 0%, so the description must carry the burden, and it largely does: it supplies an example (sr_number='412.100') and, more importantly, a constraint the schema does not encode — only Ordnungsnummern are accepted, no abbreviation lookup. It could still be clearer about format edge cases, but it meaningfully extends the bare pattern field.
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?
States a specific verb and resource ('Ruft aktuelle Metadaten eines Gesetzes live von zh.ch ab') and immediately distinguishes itself from every sibling by declaring it is the 'Einziges Tool mit Live-HTTP-Aufruf; alle anderen Tools lesen den lokalen Cache'. An agent can classify it without opening the schema.
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 <use_case> block gives concrete triggers (checking whether a law changed, which PDF version is current, which ZH-Lex URL to link) and explicitly contrasts this tool against the cache-reading alternatives. When-to-use and when-to-use-something-else are both present.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
openlex__zhlaw_list_lawsARead-onlyIdempotent
Listet Zürcher Gesetze auf mit optionalem Filter nach Rechtsgebiet.
Wenn eine strukturierte Übersicht aller Gesetze eines Rechtsgebiets benötigt wird (z.B. alle aktiven Bildungsgesetze). Für gezielte Textsuche ist openlex__zhlaw_search_laws besser; für reines Bildungsrecht openlex__zhlaw_find_education_laws.
sr_prefix filtert nach Ordnungsnummer-Prefix (412=Bildung, 331=Steuern, 700=Bau, 131=Verfassung, 810=Gesundheit). active_only=True blendet aufgehobene Gesetze aus. Unterstützt Paginierung via offset. Gibt Titel, Abkürzung, SR-Nummer und Status zurück — keinen Volltext.
sr_prefix='412', active_only=True, limit=50
| Name | Required | Description | Default |
|---|---|---|---|
| params | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | No | |
| source | No | |
| message | No | |
| results | No | |
| provenance | Yes | |
| corpus_note | No | |
| result_type | No | |
| corpus_as_of | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint/idempotentHint/destructiveHint=false, so safety is covered. The description adds genuine behavior beyond that: sr_prefix semantics, active_only hiding repealed laws, offset-based pagination, and a clear disclosure that the result is metadata (Titel, Abkürzung, SR-Nummer, Status) and NOT full text.
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?
Tags (use_case, important_notes, example) keep it front-loaded and skimmable, and every sentence carries routing, filter semantics, or return-shape information with no filler.
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 paginated list tool with annotations covering safety, the description supplies routing, filter semantics, pagination, and the explicit 'kein Volltext' return scope. Together with the output schema, an agent has everything needed to call 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?
Per the signal, schema description coverage is low, so the description must compensate. It does: it explains sr_prefix as an Ordnungsnummer prefix with real codes (412, 331, 700, 131, 810), confirms active_only semantics, and shows limit/offset usage in the example, adding meaning beyond the bare 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?
States a specific verb (auflisten) and resource (Zürcher Gesetze) with the scoping detail 'optionaler Filter nach Rechtsgebiet'. The use_case block explicitly differentiates from siblings search_laws and find_education_laws, so an agent can route without opening any schema.
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 use_case names the exact condition to pick this tool (structured overview of all laws in a legal area) and names the two alternatives with their own selecting conditions (targeted text search, education-only). Routing is fully specified.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
openlex__zhlaw_search_articlesARead-onlyIdempotent
Durchsucht alle Artikel eines bestimmten Gesetzes nach einem Begriff.
Wenn bekannt ist, in welchem Gesetz gesucht werden soll, aber nicht welcher Artikel relevant ist. Liefert alle Treffer-Artikel mit Inhalt. Für einen einzelnen Artikel mit bekannter Nummer: openlex__zhlaw_get_article.
Parst das Gesetz in einzelne Artikel und durchsucht Titel und Inhalt. Suche ist case-insensitive, kein FTS5 (einfaches Substring-Match). Gibt count=0 wenn kein Artikel den Begriff enthält. Benötigt Volltext im Cache — bei fehlendem Inhalt: Hinweis im message-Feld.
law_identifier='VSG', query='Elternrat'
| Name | Required | Description | Default |
|---|---|---|---|
| params | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | No | |
| source | No | |
| message | No | |
| results | No | |
| provenance | Yes | |
| corpus_note | No | |
| result_type | No | |
| corpus_as_of | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive), and the description adds substantial context beyond them: substring-match semantics (no FTS5), case-insensitivity, count=0 on no match, and the cache-dependency with a hint surfaced in the message field. This is rich, non-obvious behavioral disclosure.
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?
Front-loads the core purpose, then organizes usage, caveats, and an example into clearly labelled sections. Every sentence adds information; nothing is filler despite the multi-part structure.
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?
An output schema exists so return values need not be described, yet it still notes count=0 behavior. Combined with the cache requirement, match semantics, and routing to the sibling tool, an agent has everything needed to call 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 description coverage is reported as 0%, so the description must compensate, and it does: it explains that the law is parsed into articles and that title and content are both searched, plus a concrete example (law_identifier='VSG', query='Elternrat'). It still doesn't clarify the law_identifier format (Ordnungsnummer vs. Abkürzung) beyond the example, so not a full 5.
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?
States a specific verb (search) and resource (all articles of a specific law) with clear scope. It explicitly distinguishes itself from the sibling openlex__zhlaw_get_article, so an agent can route correctly without opening either schema.
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 <use_case> block states exactly when to use it (law known, article unknown) and names the alternative (openlex__zhlaw_get_article) for the case of a known article number. This is explicit when-to-use and when-to-use-something-else guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
openlex__zhlaw_search_lawsARead-onlyIdempotent
Volltextsuche in allen Zürcher Gesetzen mit FTS5-Ranking.
Allgemeine Suche nach einem Rechtsbegriff über alle ~970 kantonalen Gesetze. Wähle dieses Tool wenn das Rechtsgebiet unbekannt ist. Für das Bildungsrecht (412.x) ist openlex__zhlaw_find_education_laws schneller und präziser. Um Artikel innerhalb eines bekannten Gesetzes zu finden, nutze openlex__zhlaw_search_articles.
FTS5-Syntax: AND, OR, NOT, Phrasensuche "...". Ergebnisse nach BM25-Relevanz sortiert. Max 50 Treffer pro Aufruf (limit-Parameter). sr_prefix filtert nach Rechtsgebiet (412=Bildung, 331=Steuern, 700=Bau). Sucht im lokalen Cache — Aktualität der Metadaten via openlex__zhlaw_get_law_metadata prüfen.
query='Elternrat OR Elternmitwirkung', sr_prefix='412', limit=10
| Name | Required | Description | Default |
|---|---|---|---|
| params | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | No | |
| source | No | |
| message | No | |
| results | No | |
| provenance | Yes | |
| corpus_note | No | |
| result_type | No | |
| corpus_as_of | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so the safety profile is covered. The description adds genuine operational context beyond that: BM25 relevance ordering, a hard 50-result cap, cache-backed search, and a pointer to get_law_metadata for freshness. It does not describe pagination beyond the limit cap, keeping it just short of a 5.
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?
Tag-delimited sections (use_case, important_notes, example) front-load the routing decision and keep each block tight, with a concrete worked example. Slightly verbose for the amount of content, but every block carries distinct information.
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 an output schema present, return payloads need not be explained, and the description still covers scope, ranking, limits, and cache-freshness caveats. Coverage is strong; only finer ranking/pagination behavior is left implicit.
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 nested schema already documents every field (limit, query, sr_prefix, active_only) with examples, so the reported 0% coverage reflects the wrapper 'params' node rather than real gaps. The description reinforces sr_prefix examples (adding 700=Bau) and the limit cap, but largely restates schema content, warranting the baseline 3.
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?
States a specific verb and resource ('Volltextsuche in allen Zürcher Gesetzen') plus the retrieval mechanism (FTS5-Ranking). It explicitly distinguishes itself from siblings openlex__zhlaw_find_education_laws and openlex__zhlaw_search_articles by scope, so an agent can route without opening any schema.
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 <use_case> block states exactly when to pick this tool ('wenn das Rechtsgebiet unbekannt ist') and names two alternatives with the conditions that favor each (Bildungsrecht 412.x, articles within a known law). Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
openlex__zhlaw_update_cacheAIdempotent
Aktualisiert den lokalen Cache der Zürcher Gesetzesdaten.
Nur aufrufen wenn der Cache explizit neu geladen werden soll. Der Cache wird automatisch beim Start befüllt und ist 24 Stunden gültig — manuelles Update ist selten nötig.
Lädt ~970 Gesetze von HuggingFace (rcds/swiss_legislation) in die lokale SQLite-DB mit FTS5-Index (~25 s erster Lauf). force=False überspringt den Download wenn Cache <24h alt (gibt status='cache_fresh' zurück). force=True erzwingt Neudownload. Erfordert Internetzugang zu HuggingFace.
ACHTUNG — dieses Werkzeug macht die GESETZE nicht aktueller. Es lädt denselben Datensatz erneut, und der ist eingefroren: Die jüngste Fassung darin stammt vom 2023-01-01 (gemessen am 2026-08-08; der Datensatz selbst wurde zuletzt am 2024-10-10 angefasst). Bei Zweifeln an der Aktualität eines Wortlauts hilft nur der ZH-Lex-Permalink, nicht dieses Werkzeug.
force=False
| Name | Required | Description | Default |
|---|---|---|---|
| params | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | No | |
| source | No | |
| message | No | |
| results | No | |
| provenance | Yes | |
| corpus_note | No | |
| result_type | No | |
| corpus_as_of | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare write (readOnlyHint=false), openWorld, idempotent and non-destructive. The description adds substantial context beyond that: ~970 laws downloaded from HuggingFace, ~25s first run, specific SQLite/FTS5 target, internet requirement, and a critical caveat that the dataset is frozen (newest version dated 2023-01-01) so this tool does NOT make law texts more current. That last point is high-value behavioral disclosure no annotation could carry.
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 use_case / important_notes / example tagging is well front-loaded and each block earns its place. It is on the long side, but the length is justified by the frozen-dataset warning; only minor tightening is possible.
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?
An output schema exists, so return values need not be explained, and the annotations cover the safety profile. Combined with runtime, source, duration, network requirement, cache-freshness behavior and the data-staleness caveat, an agent has everything needed to decide and invoke 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 description coverage is 0% and there is one parameter, so the description must carry the semantics — and it does: force=False skips download when the cache is <24h old and returns status='cache_fresh', force=True forces a re-download, with a concrete example. Nothing about the parameter is left ambiguous.
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?
States a specific verb+resource: refreshing the local cache of Zurich legal data. A sibling like zhlaw_search_laws or zhlaw_get_law is clearly a read-of-laws tool, whereas this one is explicitly a cache-maintenance operation, so the agent can distinguish it without opening schemas.
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 <use_case> block gives explicit when-to-use guidance ('nur aufrufen wenn der Cache explizit neu geladen werden soll') plus a when-not ('manual update is rarely needed; cache is auto-filled at start and valid 24h'). This is exactly the routing information an agent needs.
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.
8 tool updates
v0.3.0- Changed
openlex__zhlaw_find_education_laws2 fields changed- added
Output schema / properties / corpus_as_ofAdded value: +{ + "default": "2023-01-01", + "title": "Corpus As Of", + "type": "string" +} - added
Output schema / properties / corpus_noteAdded value: +{ + "default": "Bestandsstand 2023-01-01 — die jüngste Fassung im Datensatz stammt von diesem Datum. Spätere Änderungen und Aufhebungen fehlen; ein zwischenzeitlich aufgehobenes Gesetz erscheint weiterhin als in Kraft. Für den geltenden Wortlaut den ZH-Lex-Permalink konsultieren.", + "title": "Corpus Note", + "type": "string" +}
- Changed
openlex__zhlaw_get_article2 fields changed- added
Output schema / properties / corpus_as_ofAdded value: +{ + "default": "2023-01-01", + "title": "Corpus As Of", + "type": "string" +} - added
Output schema / properties / corpus_noteAdded value: +{ + "default": "Bestandsstand 2023-01-01 — die jüngste Fassung im Datensatz stammt von diesem Datum. Spätere Änderungen und Aufhebungen fehlen; ein zwischenzeitlich aufgehobenes Gesetz erscheint weiterhin als in Kraft. Für den geltenden Wortlaut den ZH-Lex-Permalink konsultieren.", + "title": "Corpus Note", + "type": "string" +}
- Changed
openlex__zhlaw_get_law2 fields changed- added
Output schema / properties / corpus_as_ofAdded value: +{ + "default": "2023-01-01", + "title": "Corpus As Of", + "type": "string" +} - added
Output schema / properties / corpus_noteAdded value: +{ + "default": "Bestandsstand 2023-01-01 — die jüngste Fassung im Datensatz stammt von diesem Datum. Spätere Änderungen und Aufhebungen fehlen; ein zwischenzeitlich aufgehobenes Gesetz erscheint weiterhin als in Kraft. Für den geltenden Wortlaut den ZH-Lex-Permalink konsultieren.", + "title": "Corpus Note", + "type": "string" +}
- Changed
openlex__zhlaw_get_law_metadata2 fields changed- added
Output schema / properties / corpus_as_ofAdded value: +{ + "default": "2023-01-01", + "title": "Corpus As Of", + "type": "string" +} - added
Output schema / properties / corpus_noteAdded value: +{ + "default": "Bestandsstand 2023-01-01 — die jüngste Fassung im Datensatz stammt von diesem Datum. Spätere Änderungen und Aufhebungen fehlen; ein zwischenzeitlich aufgehobenes Gesetz erscheint weiterhin als in Kraft. Für den geltenden Wortlaut den ZH-Lex-Permalink konsultieren.", + "title": "Corpus Note", + "type": "string" +}
- Changed
openlex__zhlaw_list_laws2 fields changed- added
Output schema / properties / corpus_as_ofAdded value: +{ + "default": "2023-01-01", + "title": "Corpus As Of", + "type": "string" +} - added
Output schema / properties / corpus_noteAdded value: +{ + "default": "Bestandsstand 2023-01-01 — die jüngste Fassung im Datensatz stammt von diesem Datum. Spätere Änderungen und Aufhebungen fehlen; ein zwischenzeitlich aufgehobenes Gesetz erscheint weiterhin als in Kraft. Für den geltenden Wortlaut den ZH-Lex-Permalink konsultieren.", + "title": "Corpus Note", + "type": "string" +}
- Changed
openlex__zhlaw_search_articles2 fields changed- added
Output schema / properties / corpus_as_ofAdded value: +{ + "default": "2023-01-01", + "title": "Corpus As Of", + "type": "string" +} - added
Output schema / properties / corpus_noteAdded value: +{ + "default": "Bestandsstand 2023-01-01 — die jüngste Fassung im Datensatz stammt von diesem Datum. Spätere Änderungen und Aufhebungen fehlen; ein zwischenzeitlich aufgehobenes Gesetz erscheint weiterhin als in Kraft. Für den geltenden Wortlaut den ZH-Lex-Permalink konsultieren.", + "title": "Corpus Note", + "type": "string" +}
- Changed
openlex__zhlaw_search_laws2 fields changed- added
Output schema / properties / corpus_as_ofAdded value: +{ + "default": "2023-01-01", + "title": "Corpus As Of", + "type": "string" +} - added
Output schema / properties / corpus_noteAdded value: +{ + "default": "Bestandsstand 2023-01-01 — die jüngste Fassung im Datensatz stammt von diesem Datum. Spätere Änderungen und Aufhebungen fehlen; ein zwischenzeitlich aufgehobenes Gesetz erscheint weiterhin als in Kraft. Für den geltenden Wortlaut den ZH-Lex-Permalink konsultieren.", + "title": "Corpus Note", + "type": "string" +}
- Changed
openlex__zhlaw_update_cache2 fields changed- added
Output schema / properties / corpus_as_ofAdded value: +{ + "default": "2023-01-01", + "title": "Corpus As Of", + "type": "string" +} - added
Output schema / properties / corpus_noteAdded value: +{ + "default": "Bestandsstand 2023-01-01 — die jüngste Fassung im Datensatz stammt von diesem Datum. Spätere Änderungen und Aufhebungen fehlen; ein zwischenzeitlich aufgehobenes Gesetz erscheint weiterhin als in Kraft. Für den geltenden Wortlaut den ZH-Lex-Permalink konsultieren.", + "title": "Corpus Note", + "type": "string" +}
8 tool updates
v0.2.3- First observed
openlex__zhlaw_find_education_laws - First observed
openlex__zhlaw_get_article - First observed
openlex__zhlaw_get_law - First observed
openlex__zhlaw_get_law_metadata - First observed
openlex__zhlaw_list_laws - First observed
openlex__zhlaw_search_articles - First observed
openlex__zhlaw_search_laws - First observed
openlex__zhlaw_update_cache
TDQS
Scored across 8 tools
Each tool targets a distinct action (list, search, get, update cache), but find_education_laws and search_laws (especially with sr_prefix='412') overlap, as do get_law and get_law_metadata in returning metadata. Descriptions explicitly guide selection, reducing practical confusion.
All names use snake_case with a consistent zhlaw_ prefix and verb_noun pattern, making them predictable. The only minor inconsistency is using 'find' for one search operation while others use 'search'.
Eight tools are well-scoped for Zurich legal research, covering listing, searching, retrieving, and cache maintenance without redundancy. Each tool earns its place.
The surface covers core legal research workflows: list laws, search laws/articles, retrieve laws/articles, live metadata, and cache update. A minor gap is the lack of bulk article retrieval for large laws (get_law truncates at 5000 chars), though get_article works around this.
Maintenance
Related MCP Connectors
opendata.swiss MCP — Switzerland's federal open-data portal (CKAN catalogue).
Swiss federal law (Fedlex) and political data (LINDAS) for agents, every answer with sources
MCP for CanLII: Canadian case law and legislation metadata (federal, provincial, territorial).
TED MCP Server: Real-time EU public tenders access. https://www.lexsocket.ai/
Related MCP Servers
- AlicenseAqualityAmaintenanceMCP Server for Swiss federal law — search the SR, monitor legal changes, and query BBl/treaties via Claude Desktop or Claude.ai.126MIT
- AlicenseAqualityAmaintenanceMCP server for searching Swiss court decisions from federal and cantonal courts via entscheidsuche.ch. Enables full-text search, law reference lookup, and filtering by canton, court level, and date without API keys.847 PyPI1MIT

conformi-searchofficial
AlicenseAqualityAmaintenanceInstallable MCP server for EU legal research with verifiable CELEX citations from the EUR-Lex corpus (DE/EN/FR).21MIT- AlicenseAqualityBmaintenanceMCP server for Swiss federal legislation metadata via Fedlex, enabling search and retrieval of act details with ELI URIs, SR numbers, and multilingual support.342 PyPIApache 2.0