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 -->
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。