swiss-courts-mcp
MCP 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.
README
Part of the Swiss Public Data MCP Portfolio
๐๏ธ swiss-courts-mcp
MCP Server for Swiss court decisions โ Federal Supreme Court (BGer), Federal Administrative Court (BVGer), Federal Criminal Court (BStGer), and all 26 cantonal courts via entscheidsuche.ch
<p align="center"> <img src="assets/demo.svg" alt="Demo: Claude searches Swiss court decisions via MCP tool call" width="720"> </p>
Overview
Access Swiss court decisions from all judicial levels through a single MCP interface. Combines full-text search with structured filters for canton, court level, date range, and law references.
| Source | Coverage | Data |
|---|---|---|
| entscheidsuche.ch | Federal + 26 cantons | Court decisions since ~2000 |
Synergy with fedlex-mcp: Legislation (SR) + case law = complete legal research.
Features
- Full-text search across all Swiss court decisions
- Multi-stage law reference search with regex parser and Elasticsearch boost scoring
- Dedicated Federal Supreme Court search with chamber filter
- Canton and court level filtering
- Recent decisions feed
- Court taxonomy listing
- Decision statistics with aggregations
- Trilingual support (German, French, Italian)
- No API key required
Prerequisites
- Python 3.11 or higher
- An MCP-compatible client (Claude Desktop, Cursor, Windsurf, etc.)
Installation
pip install swiss-courts-mcp
Or install from source:
git clone https://github.com/malkreide/swiss-courts-mcp.git
cd swiss-courts-mcp
pip install -e ".[dev]"
Quickstart
# Run directly
swiss-courts-mcp
# Or via Python module
python -m swiss_courts_mcp
Configuration
Claude Desktop
Add to your claude_desktop_config.json:
{
"mcpServers": {
"swiss-courts": {
"command": "python",
"args": ["-m", "swiss_courts_mcp"]
}
}
}
Cloud Deployment (HTTP transport)
The HTTP transport is off by default. The default bind host is 127.0.0.1
(loopback only) โ 0.0.0.0 must be opted into explicitly (the Dockerfile does
this). Running HTTP without authentication logs a warning; only do so behind an
authenticating reverse proxy.
# Local HTTP (loopback), no auth โ development only
swiss-courts-mcp --http --port 8000
# Container (binds 0.0.0.0, auth enabled) โ see Dockerfile
docker build -t swiss-courts-mcp .
docker run -p 8000:8000 -e MCP_AUTH_SECRET="$(openssl rand -hex 32)" swiss-courts-mcp
Relevant environment variables (see .env.example):
| Variable | Default | Purpose |
|---|---|---|
MCP_HOST |
127.0.0.1 |
Bind host. Set to 0.0.0.0 only in containers. |
MCP_PORT |
8000 |
Bind port. |
MCP_ALLOW_PUBLIC_BIND |
false |
Suppress the 0.0.0.0 warning (containers). |
MCP_STATELESS_HTTP |
true |
Stateless HTTP โ horizontal scaling without sticky sessions. |
MCP_AUTH_ENABLED |
false |
Enable bearer-token auth for HTTP. |
MCP_AUTH_SECRET |
โ | HS256 signing key (dev). |
MCP_OAUTH_JWKS_URL |
โ | JWKS URL for RS256 validation (production). |
MCP_REQUIRED_SCOPES |
โ | Comma-separated required scopes. |
MCP_CORS_ORIGINS |
โ | Comma-separated allowed origins (no wildcard in prod). |
Authentication validates the user identity from the JWT sub claim only; see
ADR 0001.
MCP Protocol Version
This server pins MCP protocol version 2025-11-25 (constant
PROTOCOL_VERSION in server.py). A regression test detects drift against the
installed SDK so a protocol bump is a conscious change (version + CHANGELOG +
this section). SDK updates land monthly via Dependabot.
Project Phase
Phase 1 โ read-only (see ROADMAP.md). All tools are
readOnlyHint: true; there are no writing or destructive operations. A move to
Phase 2 (write) requires a clean re-audit and the gates listed in the roadmap.
Available Tools
Court Decision Search
| Tool | Description |
|---|---|
search_court_decisions |
Full-text search across all court decisions with canton, court level, and date filters |
get_court_decision |
Retrieve a single decision by its unique signature |
search_bger_decisions |
Search Federal Supreme Court decisions with optional chamber filter |
search_by_law_reference |
Find decisions citing a specific law article (e.g., "Art. 8 BV") |
Court Information
| Tool | Description |
|---|---|
list_courts |
List all indexed courts, optionally filtered by canton |
get_recent_decisions |
Latest decisions, filterable by canton and court level |
get_decision_statistics |
Statistics on indexed decisions by canton and year |
Tool Annotations
All seven tools share the same hints โ they are read-only, idempotent, non-destructive, and reach an external system:
| Annotation | Value |
|---|---|
readOnlyHint |
true |
destructiveHint |
false |
idempotentHint |
true |
openWorldHint |
true |
A rechtsrecherche prompt is also provided (a second MCP primitive
alongside tools).
Example Use Cases
| Use Case | Tool Chain |
|---|---|
| Research case law on data protection | search_court_decisions("Datenschutz") |
| Find practice on a constitutional right | search_by_law_reference("Art. 8 BV") |
| Latest Federal Supreme Court rulings | search_bger_decisions("Arbeitsrecht", date_from="2024-01-01") |
| Combined: Law text + case law | fedlex_search_laws("DSG") then search_by_law_reference("Art. 25 DSG") |
โ More use cases by audience โ
Architecture
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ MCP Client (LLM) โ
โ Claude / Cursor / Windsurf โ
โโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโ
โ MCP Protocol
โโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโ
โ swiss-courts-mcp โ
โ 7 tools ยท Pydantic validation โ
โ Elasticsearch query builder โ
โโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโ
โ HTTPS (POST/GET)
โโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโ
โ entscheidsuche.ch โ
โ Elasticsearch backend โ
โ No authentication required โ
โ Federal + 26 cantonal courts โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Safety & Limits
| Aspect | Details |
|---|---|
| Access | Read-only (readOnlyHint: true) โ the server cannot modify or delete any data |
| Personal data | No personal data โ all decisions are public court rulings |
| Rate limits | Built-in per-query caps (max 50 results per search, 50 aggregation buckets) |
| Timeout | 30 seconds per API call |
| Data source auth | No API keys required โ entscheidsuche.ch is publicly accessible |
| HTTP transport auth | Optional bearer-token auth (JWT, sub-claim identity); see ADR 0001 |
| Egress | Code-layer allow-list (entscheidsuche.ch only, HTTPS-enforced); see egress policy |
| Error masking | Internal exceptions are logged server-side only; clients receive friendly messages |
| Secrets | No secrets in code/logs; .env git-ignored, Gitleaks on PRs; see secret management |
| Licenses | Court decisions are public domain under Swiss law (BGG Art. 27) |
| Terms of Service | Subject to entscheidsuche.ch usage terms โ please be kind to the server |
Project Structure
swiss-courts-mcp/
โโโ src/
โ โโโ swiss_courts_mcp/
โ โโโ __init__.py
โ โโโ __main__.py
โ โโโ server.py # MCP server, 7 tools + 1 prompt, lifespan, auth wiring
โ โโโ api_client.py # HTTP client, ES query builder, egress allow-list
โ โโโ auth.py # JWT bearer-token verifier (HTTP transport)
โ โโโ config.py # Settings object (env-driven)
โ โโโ logging_config.py # structured logging on stderr
โ โโโ models.py # structured response envelope
โโโ tests/ # unit (respx-mocked) + live + security tests
โโโ docs/ # egress, secret-management, ADRs
โโโ .github/workflows/ # ci ยท security (gitleaks) ยท live ยท publish
โโโ Dockerfile # hardened container (non-root, 0.0.0.0 only here)
โโโ ROADMAP.md
โโโ pyproject.toml ยท CHANGELOG.md ยท LICENSE
โโโ CONTRIBUTING.md ยท CONTRIBUTING.de.md
โโโ SECURITY.md ยท SECURITY.de.md
โโโ README.md ยท README.de.md
Note (single-file tools): the 7 tools live in
server.pyrather than atools/package. At this count a single module stays readable; the registry (register_tools) keeps registration declarative. This is a deliberate deviation from the "split when > 5 tools" convention and will be revisited if the tool count grows.
Known Limitations
- Search is limited to decisions indexed by entscheidsuche.ch (not all decisions are publicly available)
- Full-text document content is not returned โ only metadata, title, and abstract
- Statistics depend on Elasticsearch aggregation support of the backend
- The court taxonomy structure from
Facetten_alle.jsonmay vary
Testing
Unit tests mock all HTTP with respx; live tests hit the real API and run in a
separate nightly workflow (live.yml), never
blocking PRs.
# Unit tests (HTTP mocked) โ what CI runs
pytest tests/ -v -m "not live"
# Live API tests (real entscheidsuche.ch)
pytest tests/ -v -m live
# Linting
ruff check src/ tests/
ruff format src/ tests/
Changelog
See CHANGELOG.md.
Contributing
See CONTRIBUTING.md.
Security
See SECURITY.md for the security posture and how to report a vulnerability.
License
Author
Hayal Oezkan ยท malkreide
Credits & Related Projects
- entscheidsuche.ch โ Swiss court decision search engine
- fedlex-mcp โ MCP Server for Swiss federal law (legislation synergy)
- zurich-opendata-mcp โ MCP Server for Zurich open data
- Model Context Protocol โ Open protocol for AI tool integration
<!-- mcp-name: io.github.malkreide/swiss-courts-mcp -->
<!-- BEGIN GENERATED: install -->
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": {
"swiss-courts-mcp": {
"command": "uvx",
"args": [
"swiss-courts-mcp"
]
}
}
}
<!-- END GENERATED: install -->
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.