openlex-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@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 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 balancer to route on the Mcp-Session-Id header with a stick-table and an appropriate TTL.
MCP Protocol Version
Item | Value |
Supported protocol version |
|
SDK |
|
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 > docs/tool-hashes.json), 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 # Weekly 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
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 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
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"
]
}
}
}Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
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.Last updated122MIT
- 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.Last updated71MIT

conformi-searchofficial
AlicenseAqualityAmaintenanceInstallable MCP server for EU legal research with verifiable CELEX citations from the EUR-Lex corpus (DE/EN/FR).Last updated21MIT- AlicenseAqualityAmaintenanceMCP server for Swiss federal legislation metadata via Fedlex, enabling search and retrieval of act details with ELI URIs, SR numbers, and multilingual support.Last updated2Apache 2.0
Related MCP Connectors
opendata.swiss MCP β Switzerland's federal open-data portal (CKAN catalogue).
MCP for CanLII: Canadian case law and legislation metadata (federal, provincial, territorial).
Search Swiss federal legislation: laws, articles, amendments via the Fedlex SPARQL endpoint.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/malkreide/openlex-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server