MCP Server for Canton Zurich legislation (ZH-Lex) โ full-text search, article extraction, and education law tools
Project description
๐จ๐ญ 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'."
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)
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 (port 8000)
python -m openlex_mcp.server --http --port 8000
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):
- 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 8000 - 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 |
|---|---|
zhlaw_search_laws |
Full-text search across all ~970 ZH laws (FTS5 + BM25 ranking) |
zhlaw_get_law |
Retrieve a law by LS number (e.g. 412.100) or abbreviation (e.g. VSG) |
zhlaw_list_laws |
List and filter laws by legal area prefix |
zhlaw_find_education_laws |
Specialized search in education law (LS 412.x series) |
Article Extraction
| Tool | Description |
|---|---|
zhlaw_get_article |
Extract a specific article from a law (e.g. Art. 28 VSG) |
zhlaw_search_articles |
Search within all articles of a specific law |
Metadata & Cache
| Tool | Description |
|---|---|
zhlaw_get_law_metadata |
Get live metadata from zh.ch (PDF links, validity status) |
zhlaw_update_cache |
Refresh the local data cache from HuggingFace |
Key Legal Area Prefixes (LS Numbers)
| 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?" | zhlaw_get_law |
| "Find laws about data protection" | zhlaw_search_laws |
| "Show me Art. 55 VSG" | zhlaw_get_article |
| "Which education laws mention Schulleitung?" | zhlaw_find_education_laws |
| "Find all articles about Elternrat in the VSG" | zhlaw_search_articles |
| "Is LS 412.100 still in force?" | 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 |
Project Structure
openlex-mcp/
โโโ src/openlex_mcp/
โ โโโ __init__.py # Package
โ โโโ __main__.py # Entry point for python -m
โ โโโ server.py # 8 MCP tool definitions (FastMCP)
โ โโโ 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/
โ โโโ test_server.py # Unit + integration tests
โโโ .github/workflows/ci.yml # GitHub Actions (Python 3.11/3.12/3.13)
โโโ pyproject.toml
โโโ claude_desktop_config.json # Example config for Claude Desktop
โโโ CHANGELOG.md
โโโ CONTRIBUTING.md
โโโ LICENSE
โโโ README.md # This file (English)
โโโ README.de.md # German version
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
Testing
# Unit tests (no API key required)
PYTHONPATH=src pytest tests/ -m "not live"
# Integration tests (live API calls)
pytest tests/ -m "live"
Changelog
See CHANGELOG.md
Contributing
See CONTRIBUTING.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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file openlex_mcp-0.1.0.tar.gz.
File metadata
- Download URL: openlex_mcp-0.1.0.tar.gz
- Upload date:
- Size: 26.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a925ba9c4ef6f0f8142590cf3d9ccb7ede4580370f44380b84c3f3cdfeaa7ffb
|
|
| MD5 |
72b89f97ef42a4cba74f4a5e226b7252
|
|
| BLAKE2b-256 |
69f67b9dfda96b3ff9f797e68543f9c7eb0a78b2f21e05df83e144c5273e12c0
|
Provenance
The following attestation bundles were made for openlex_mcp-0.1.0.tar.gz:
Publisher:
publish.yml on malkreide/openlex-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
openlex_mcp-0.1.0.tar.gz -
Subject digest:
a925ba9c4ef6f0f8142590cf3d9ccb7ede4580370f44380b84c3f3cdfeaa7ffb - Sigstore transparency entry: 1280747013
- Sigstore integration time:
-
Permalink:
malkreide/openlex-mcp@845a781313a9df6bfc39b7bdb66ae7e483eedded -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/malkreide
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@845a781313a9df6bfc39b7bdb66ae7e483eedded -
Trigger Event:
release
-
Statement type:
File details
Details for the file openlex_mcp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: openlex_mcp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 24.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5ab998540771fcb113f6c407bdcfcb023e0d137b39e28a4fa8e54873b396ae93
|
|
| MD5 |
0a8f8143fcd3342e79f71655e491714e
|
|
| BLAKE2b-256 |
8fcf4b8d6ec53622c9b1b4e73a46b83348ebaf8b9efe7b9cd74e76c7e4aace71
|
Provenance
The following attestation bundles were made for openlex_mcp-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on malkreide/openlex-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
openlex_mcp-0.1.0-py3-none-any.whl -
Subject digest:
5ab998540771fcb113f6c407bdcfcb023e0d137b39e28a4fa8e54873b396ae93 - Sigstore transparency entry: 1280747018
- Sigstore integration time:
-
Permalink:
malkreide/openlex-mcp@845a781313a9df6bfc39b7bdb66ae7e483eedded -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/malkreide
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@845a781313a9df6bfc39b7bdb66ae7e483eedded -
Trigger Event:
release
-
Statement type: