MCP Server for Canton Zurich legislation (ZH-Lex) — full-text search, article extraction, and education law tools
- ✓Open-source license (MIT)
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Topics declared
claude mcp add openlex-mcp -- python -m -e{
"mcpServers": {
"openlex-mcp": {
"command": "python",
"args": ["-m", "openlex_mcp.server"],
"env": {
"MCP_HOST": "<mcp_host>"
}
}
}
}MCP_HOSTMCP Servers overview
> 🇨🇭 **Part of the [Swiss Public Data MCP Portfolio](https://github.com/malkreide)**
# ⚖️ openlex-mcp

[](https://opensource.org/licenses/MIT)
[](https://www.python.org/downloads/)
[](https://modelcontextprotocol.io/)
[](https://github.com/malkreide/openlex-mcp)
> MCP Server for Canton Zurich legislation (ZH-Lex) — full-text search, article extraction, and education law tools for ~970 cantonal laws
[🇩🇪 Deutsche Version](README.de.md)
<p align="center">
<img src="assets/demo.png" alt="Demo: Claude searches Zurich education law via MCP tool call" width="720">
</p>
---
## 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)
---
## Development Phase
**Current phase: Phase 1 — Read-Only.** All tools are read-only (`readOnlyHint: true`); no writes to external systems. See [ROADMAP.md](ROADMAP.md) for the phase plan and transition gates before any write or multi-agent capability is added.
---
## Prerequisites
- Python 3.11+
- [uv](https://github.com/astral-sh/uv) (recommended) or pip
- Internet connection (for initial data download and live metadata)
---
## Installation
```bash
# 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
```bash
# 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):
```json
{
"mcpServers": {
"openlex": {
"command": "python",
"args": ["-m", "openlex_mcp.server"]
}
}
}
```
Or with the installed entry point:
```json
{
"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](https://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 |
### 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?"* | `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 Streamable-HTTP transport keeps session state **in-process** (FastMCP default). This has two implications:
- **Single-instance only** — horizontal scaling (multiple replicas) breaks active sessions because there is no shared session store (Redis, Durable Objects, etc.).
- **No sticky-session LB needed today** — a single-replica Render deployment naturally routes all requests to one process.
Before scaling beyond one instance: either add a shared session store **or** configure your edge load balanceWhat people ask about openlex-mcp
What is malkreide/openlex-mcp?
+
malkreide/openlex-mcp is mcp servers for the Claude AI ecosystem. MCP Server for Canton Zurich legislation (ZH-Lex) — full-text search, article extraction, and education law tools It has 0 GitHub stars and was last updated today.
How do I install openlex-mcp?
+
You can install openlex-mcp by cloning the repository (https://github.com/malkreide/openlex-mcp) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is malkreide/openlex-mcp safe to use?
+
Our security agent has analyzed malkreide/openlex-mcp and assigned a Trust Score of 87/100 (tier: Trusted). See the full breakdown of passed checks and flags on this page.
Who maintains malkreide/openlex-mcp?
+
malkreide/openlex-mcp is maintained by malkreide. The last recorded GitHub activity is from today, with 0 open issues.
Are there alternatives to openlex-mcp?
+
Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.
Deploy openlex-mcp to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/malkreide-openlex-mcp)<a href="https://claudewave.com/repo/malkreide-openlex-mcp"><img src="https://claudewave.com/api/badge/malkreide-openlex-mcp" alt="Featured on ClaudeWave: malkreide/openlex-mcp" width="320" height="64" /></a>More MCP Servers
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
The fastest path to AI-powered full stack observability, even for lean teams.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!