Skip to main content
Glama

🇨🇭 Part of the Swiss Public Data MCP Portfolio

⚖️ openlex-mcp

Version License: MIT Python 3.11+ MCP No Auth Required

MCP Server for Canton Zurich legislation (ZH-Lex) — full-text search, article extraction, and education law tools for ~970 cantonal laws

🇩🇪 Deutsche Version


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 8000

Network 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.json

  • Windows: %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):

  1. Push/fork the repository to GitHub

  2. On render.com: New Web Service → connect GitHub repo

  3. Set start command: python -m openlex_mcp.server --http --port 8000

  4. Set environment variable MCP_HOST=0.0.0.0 so the container is reachable (the code default is 127.0.0.1; Render sets the RENDER env var, so no NeighborJack warning is logged)

  5. Set MCP_CORS_ORIGINS=https://claude.ai so the browser can read the Mcp-Session-Id header (comma-separated list; no wildcard — defaults to empty, i.e. no cross-origin access)

  6. 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

openlex__zhlaw_search_laws

Full-text search across all ~970 ZH laws (FTS5 + BM25 ranking)

openlex__zhlaw_get_law

Retrieve a law by LS number (e.g. 412.100) or abbreviation (e.g. VSG)

openlex__zhlaw_list_laws

List and filter laws by legal area prefix

openlex__zhlaw_find_education_laws

Specialized search in education law (LS 412.x series)

Article Extraction

Tool

Description

openlex__zhlaw_get_article

Extract a specific article from a law (e.g. Art. 28 VSG)

openlex__zhlaw_search_articles

Search within all articles of a specific law

Metadata & Cache

Tool

Description

openlex__zhlaw_get_law_metadata

Get live metadata from zh.ch (PDF links, validity status)

openlex__zhlaw_update_cache

Refresh the local data cache from HuggingFace

Prefix

Legal Area

Example

131

Constitution and popular rights

Kantonsverfassung

170

Administrative procedure

Datenschutzgesetz

331

Tax law

Steuergesetz

412

Education and schools

Volksschulgesetz (VSG)

700

Spatial planning and building

Planungs- und Baugesetz

810

Health

Gesundheitsgesetz

Example Use Cases

Query

Tool

"What is the Volksschulgesetz?"

openlex__zhlaw_get_law

"Find laws about data protection"

openlex__zhlaw_search_laws

"Show me Art. 55 VSG"

openlex__zhlaw_get_article

"Which education laws mention Schulleitung?"

openlex__zhlaw_find_education_laws

"Find all articles about Elternrat in the VSG"

openlex__zhlaw_search_articles

"Is LS 412.100 still in force?"

openlex__zhlaw_get_law_metadata


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 rcds/swiss_legislation

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 _meta envelope; the server answers without issuing an Mcp-Session-Id and keeps no session between requests. Any replica can answer any request; no shared store, no sticky routing. (subscriptions/listen streams 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 to 2025-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 initialize handshake

2024-11-05 … 2025-11-25 — the handshake ceiling

Served via the per-request envelope

2026-07-28

Who picks

The client's first request, once per connection. A request carrying the 2026-07-28 _meta envelope opens a modern connection; anything else opens a handshake connection.

SDK

mcp[cli]>=2.0.0,<3

Cache hints

tools/list, prompts/list, resources/list, resources/templates/list and server/discover: ttlMs 300000, cacheScope public

serverInfo.version

The package version (openlex_mcp.__version__), in every server/discover result

Deprecated in 2026-07-28, not used

Logging (ctx.info/ctx.warning, SEP-2577) — status goes into the tool result, diagnostics into the server log

Pinned in

src/openlex_mcp/server.py — MCP_PROTOCOL_VERSION constant

Update policy

  1. When mcp is upgraded (via Dependabot PR), verify the protocol version in the SDK release notes.

  2. If the protocol version changes, update MCP_PROTOCOL_VERSION in server.py, regenerate docs/tool-hashes.json (PYTHONPATH=src python scripts/gen_tool_hashes.py --write), and note the change in CHANGELOG.md.

  3. 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 version

Tool 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_content field is unreliable (cross-contaminated between laws); the server uses pdf_content instead, 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 and provenance="cache" describe where an answer came from, not how old the laws in it are. Every response now carries corpus_as_of and corpus_note alongside provenance.

  • Repeals after the cut-off are invisible. All 974 entries carry is_active = True and not one has a version_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_cache does 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 (readOnlyHint: true) — the server cannot modify or delete any data

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 (www.zh.ch over HTTPS, plus the HTTP-only legacy permalink host www.zhlex.zh.ch), with SSRF IP-blocking and DNS-pinning — see docs/network-egress.md

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 *.zh.ch — no POST, no webhooks, no email ✓ · no code execution ✓. Structurally safe by design.

Session handling

Mcp-Session-Id generated and managed by the MCP SDK (cryptographically secure UUIDs). No user-identity binding — auth_model=none is correct for public read-only data. If authentication is ever added, bind sessions to the validated OAuth sub claim before deployment.

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.py

150 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


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 tools
openlex__zhlaw_find_education_lawsA
Read-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

ParametersJSON Schema
NameRequiredDescriptionDefault
paramsYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
countNo
sourceNo
messageNo
resultsNo
provenanceYes
corpus_noteNo
result_typeNo
corpus_as_ofNo

TDQS

A4.3/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_articleA
Read-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'

ParametersJSON Schema
NameRequiredDescriptionDefault
paramsYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
countNo
sourceNo
messageNo
resultsNo
provenanceYes
corpus_noteNo
result_typeNo
corpus_as_ofNo

TDQS

A4.5/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_lawA
Read-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

ParametersJSON Schema
NameRequiredDescriptionDefault
paramsYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
countNo
sourceNo
messageNo
resultsNo
provenanceYes
corpus_noteNo
result_typeNo
corpus_as_ofNo

TDQS

A4.6/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_metadataA
Read-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'

ParametersJSON Schema
NameRequiredDescriptionDefault
paramsYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
countNo
sourceNo
messageNo
resultsNo
provenanceYes
corpus_noteNo
result_typeNo
corpus_as_ofNo

TDQS

A4.9/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_lawsA
Read-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

ParametersJSON Schema
NameRequiredDescriptionDefault
paramsYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
countNo
sourceNo
messageNo
resultsNo
provenanceYes
corpus_noteNo
result_typeNo
corpus_as_ofNo

TDQS

A4.7/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_articlesA
Read-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'

ParametersJSON Schema
NameRequiredDescriptionDefault
paramsYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
countNo
sourceNo
messageNo
resultsNo
provenanceYes
corpus_noteNo
result_typeNo
corpus_as_ofNo

TDQS

A4.9/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_lawsA
Read-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

ParametersJSON Schema
NameRequiredDescriptionDefault
paramsYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
countNo
sourceNo
messageNo
resultsNo
provenanceYes
corpus_noteNo
result_typeNo
corpus_as_ofNo

TDQS

A4.3/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_cacheA
Idempotent

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

ParametersJSON Schema
NameRequiredDescriptionDefault
paramsYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
countNo
sourceNo
messageNo
resultsNo
provenanceYes
corpus_noteNo
result_typeNo
corpus_as_ofNo

TDQS

A4.9/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters5/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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.

  1. 8 tool updatesv0.3.0
    • Changedopenlex__zhlaw_find_education_laws2 fields changed
      • addedOutput schema / properties / corpus_as_of
        Added value: +{
        +  "default": "2023-01-01",
        +  "title": "Corpus As Of",
        +  "type": "string"
        +}
      • addedOutput schema / properties / corpus_note
        Added 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"
        +}
    • Changedopenlex__zhlaw_get_article2 fields changed
      • addedOutput schema / properties / corpus_as_of
        Added value: +{
        +  "default": "2023-01-01",
        +  "title": "Corpus As Of",
        +  "type": "string"
        +}
      • addedOutput schema / properties / corpus_note
        Added 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"
        +}
    • Changedopenlex__zhlaw_get_law2 fields changed
      • addedOutput schema / properties / corpus_as_of
        Added value: +{
        +  "default": "2023-01-01",
        +  "title": "Corpus As Of",
        +  "type": "string"
        +}
      • addedOutput schema / properties / corpus_note
        Added 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"
        +}
    • Changedopenlex__zhlaw_get_law_metadata2 fields changed
      • addedOutput schema / properties / corpus_as_of
        Added value: +{
        +  "default": "2023-01-01",
        +  "title": "Corpus As Of",
        +  "type": "string"
        +}
      • addedOutput schema / properties / corpus_note
        Added 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"
        +}
    • Changedopenlex__zhlaw_list_laws2 fields changed
      • addedOutput schema / properties / corpus_as_of
        Added value: +{
        +  "default": "2023-01-01",
        +  "title": "Corpus As Of",
        +  "type": "string"
        +}
      • addedOutput schema / properties / corpus_note
        Added 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"
        +}
    • Changedopenlex__zhlaw_search_articles2 fields changed
      • addedOutput schema / properties / corpus_as_of
        Added value: +{
        +  "default": "2023-01-01",
        +  "title": "Corpus As Of",
        +  "type": "string"
        +}
      • addedOutput schema / properties / corpus_note
        Added 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"
        +}
    • Changedopenlex__zhlaw_search_laws2 fields changed
      • addedOutput schema / properties / corpus_as_of
        Added value: +{
        +  "default": "2023-01-01",
        +  "title": "Corpus As Of",
        +  "type": "string"
        +}
      • addedOutput schema / properties / corpus_note
        Added 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"
        +}
    • Changedopenlex__zhlaw_update_cache2 fields changed
      • addedOutput schema / properties / corpus_as_of
        Added value: +{
        +  "default": "2023-01-01",
        +  "title": "Corpus As Of",
        +  "type": "string"
        +}
      • addedOutput schema / properties / corpus_note
        Added 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"
        +}
  2. 8 tool updatesv0.2.3
    • First observedopenlex__zhlaw_find_education_laws
    • First observedopenlex__zhlaw_get_article
    • First observedopenlex__zhlaw_get_law
    • First observedopenlex__zhlaw_get_law_metadata
    • First observedopenlex__zhlaw_list_laws
    • First observedopenlex__zhlaw_search_articles
    • First observedopenlex__zhlaw_search_laws
    • First observedopenlex__zhlaw_update_cache

TDQS

A4.4/5.0

Scored across 8 tools

Disambiguation4/5

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.

Naming Consistency4/5

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'.

Tool Count5/5

Eight tools are well-scoped for Zurich legal research, covering listing, searching, retrieving, and cache maintenance without redundancy. Each tool earns its place.

Completeness4/5

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

ActivityActive
ResponsivenessUnresponsive

Related MCP Connectors

Related MCP Servers