
Swiss Courts Mcp
io.github.malkreide由 GitHub 账号 malkreide 发布v0.5.0更新于 Oct 24, 2026
Swiss court decisions via entscheidsuche.ch, including federal and cantonal courts
发布方自己的服务:Nyc Tennis Courts
概览
让助手检索瑞士联邦与各州法院判决,并在实时来源不可用时回退到离线数据。
- 可以做什么
- 通过 entscheidsuche.ch 提供八个只读工具:按州、法院层级和日期筛选的判决全文检索、按签名获取单份判决、带法庭筛选的联邦最高法院检索,以及按所引法律条文检索。还可列出法院、返回最新判决、给出判决统计,并查看离线数据缓存的覆盖情况。另提供一个法律研究提示词,每个响应都会标明来源是实时还是离线数据。
- 适用场景
- 适合瑞士判例法研究,例如查找某项宪法权利的实践或联邦最高法院在某一主题上的裁判。与瑞士联邦法律服务器配合使用时,可同时获得法条文本与判例。
- 运行要求
- 作为本地 Python 包运行(需 Python 3.11 或更高版本),可通过 uvx 或 pip 安装,并在兼容 MCP 的客户端中使用。无需 API 密钥。实时结果需要访问 entscheidsuche.ch,可选的离线数据下载需要访问 zenodo.org。可选的 HTTP 模式使用 MCP_AUTH_SECRET、MCP_OAUTH_AUDIENCE、MCP_OAUTH_ISSUER、MCP_RESOURCE_URL 等环境变量。
安装
在 SourceWeft 中
- 打开 控制台中的 Swiss Courts Mcp,将其添加到工作区。
- 为需要使用其工具的对话启用该服务。
Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。
其他 MCP 客户端
参照 仓库 中的启动说明。
README
Part of the Swiss Public Data MCP Portfolio
🏛️ swiss-courts-mcp
[Version] [License: MIT] [Python 3.11+] [MCP] [No Auth Required] [CI]
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
[Demo: Claude searches Swiss court decisions via MCP tool call]
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.
🎯 Anchor demo query: "Find Federal Supreme Court case law on data protection (Art. 25 DSG) since 2020 — and if entscheidsuche.ch is down, still answer from the offline dump, clearly flagged."
Synergy with fedlex-mcp: Legislation (SR) + case law = complete legal research.
Availability: entscheidsuche.ch is non-profit infrastructure without an SLA. When it is unreachable, the server transparently falls back to a cached public dump (see Offline fallback). Every response declares its origin (source: "live" | "dump"), and dump answers carry a coverage_note — the fallback is partial, not equivalent.
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)
- Offline fallback to a cached public dump when entscheidsuche.ch is unreachable — with explicit provenance on every response
- No API key required
Prerequisites
- Python 3.11 or higher
- An MCP-compatible client (Claude Desktop, Cursor, Windsurf, etc.)
Installation
Or install from source:
Quickstart
Configuration
Claude Desktop
Add to your claude_desktop_config.json:
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.
Relevant environment variables (see .env.example):
Authentication validates the user identity from the JWT sub claim only; see
ADR 0001.
MCP_OAUTH_AUDIENCE is mandatory once auth is on. The aud claim is what
binds a token to this server. Without it the verifier did not check the
audience at all and accepted any correctly signed token from the same issuer —
including one minted for a different service (confused deputy). The server now
refuses to start in auth mode without it.
MCP_OAUTH_ISSUER is mandatory too, for the same reason on the other side of
the token. The iss claim binds a token to the IdP this server trusts. This
matters as soon as several tenants share one JWKS URL — the normal case with a
hosted IdP: the signature is then valid for all of them, and only iss
separates them. Measured with the variable unset, audience correct: a token with
iss: https://another-tenant.example was accepted, and so was a token with
no iss at all. The value is compared literally per RFC 8414/9207, trailing
slash included, and is therefore not normalised — unlike MCP_RESOURCE_URL,
where a trailing slash is trimmed.
It is also what makes discovery work. authorization_servers[0] in the RFC 9728
document is the value an SDK client adopts as its authorization server. Without
the variable the server named itself there — and under that address
/.well-known/oauth-authorization-server,
/.well-known/openid-configuration, /authorize, /token and /register all
answer 404, because this is a resource server, not an authorization server.
MCP_RESOURCE_URL is what an OAuth client needs. Per RFC 9728 the server
publishes a resource identifier at /.well-known/oauth-protected-resource and
names it in the WWW-Authenticate header of every 401 — that is where a client
looks to find out where to get a token. Without the variable the server
publishes its bind address; measured with a container bind, that was
{"resource": "http://0.0.0.0:8000", …}, an address no client can dial. Set it
on any non-loopback bind; the server warns at startup when it is missing.
The SDK's own validate_token_resource stays off for a measured reason: it
compares the token's resource indicator literally against
resource_server_url, which here is the bind address. A token whose audience
is not that exact URL is rejected with 401 — so switching it on would lock out
every real client while the audience check above is what actually protects the
server.
Offline fallback (env)
Pre-warm the cache (downloads the ~120 MB SCD CSV once, so the first real outage does not pay the download cost):
MCP Protocol Versions
The server serves two protocol eras over the same endpoint; the client's first request decides which one it gets:
Both revisions are pinned and both have a drift guard against the installed SDK, so a protocol bump stays a conscious change (constant + CHANGELOG + this section). SDK updates land monthly via Dependabot.
Spec 2026-07-28 is the era the SDK's own client picks. mcp.Client probes
server/discover and only falls back to the handshake if that is refused; against
this server it does not fall back. Measured through the assembled ASGI stack in
tests/test_modern_era.py, not inferred from constant names.
What differs in the modern era:
- No
initialize, no session ID. Every POST is self-contained and carriesparams._metawith the protocol version and the client capabilities, plus the routing headersMCP-Protocol-Version,Mcp-Methodand (fortools/call,prompts/get,resources/read)Mcp-Name. server/discoverreplaces the handshake for capability discovery, andsubscriptions/listenreplaces the change notifications.ping,logging/setLeveland theresources/subscribepair are gone. In this era the server answers them with-32601; in the legacy era they remain.ttlMs/cacheScoperide on the listing methods (SEP-2549) — seeCACHE_HINTS.serverInfois stamped into the_metaof every response, because there is no handshake to carry it once. It names the build version, the display title and the project URL; the purpose text stays ininstructions, which travels once withserver/discover.
An initialize asking for 2026-07-28 still gets 2025-11-25 back: the
handshake is not the way into the modern era, and that answer says nothing about
whether the server speaks it.
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
Court Information
Tool Annotations
All eight tools share the same hints — they are read-only, idempotent, non-destructive, and reach an external system:
A rechtsrecherche prompt is also provided (a second MCP primitive
alongside tools).
Example Use Cases
→ More use cases by audience →
Architecture
Live-first, always: the offline dump only engages on an availability failure
(bot-block, HTTP 5xx/429, timeout) or when forced. It is a behaviour of the
existing tools, not a separate search tool — why this source and not the
full-text one is in ADR 0002; what it does
and does not cover is under Known Limitations. Inspect
the cache at any time with get_fallback_status.
Safety & Limits
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
Offline fallback (partial coverage — read this): the fallback is a safety net for availability, not an equivalent mirror of the live source:
- Court scope: Federal Supreme Court only (BGer/BGE). Bundesverwaltungsgericht, Bundesstrafgericht and all 26 cantonal courts are not covered.
- Time span: 2007 – December 2024 (the SCD dump's range). Decisions outside this window are not in the dump.
- Content: metadata/regesten only — no full text offline.
- Update latency: the SCD dump is refreshed roughly quarterly on Zenodo, so
the offline data lags the live index.
get_fallback_statusreports the cached version and can check Zenodo for a newer one. - Law-reference search offline only matches references named in the decision's
subject/regest (
topic/issue) — there is no offline cited-law index. get_court_decisionis best-effort offline: SCD case ids (docref, e.g.1C_517/2016) differ from entscheidsuche signatures, so some lookups are honestly reported as non-resolvable.- Responses always disclose their origin via
source(live/dump) and acoverage_note; the server never silently narrows coverage — an uncovered query gets an explicit "not covered" answer, never a silent empty result.
Testing
Unit tests mock all HTTP with respx. Run from the project root. The five
gates CI runs — check_gate_docs.py holds this list against ci.yml, so it
cannot quietly fall behind:
The live tests are not a gate — they hit the real source and run on a schedule
(live.yml), not on pull requests:
Editing live.yml is a special case: GitHub only honours schedule on the
default branch, so changes take effect after the merge — trigger it by hand
(workflow_dispatch) to test them before that.
The offline-fallback tests mock the Zenodo download with respx and use a
small committed fixture — the ~120 MB dump is never downloaded in CI.
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 (live source)
- Swiss Federal Supreme Court Dataset (SCD) — offline fallback source, CC BY 4.0: Geering, F. & Merane, J. (2025). Swiss Federal Supreme Court Dataset (SCD), Version 2024-3. Zenodo. https://doi.org/10.5281/zenodo.14867950
- 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
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):
来源:README.md,提交 4b8fc7f
工具
0版本历史
2- v0.5.0最新Sep 19, 2026
- v0.4.0Sep 16, 2026
评分
已满足适用检查项的 50%
该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。
- 近 30 天内可连通25 分
请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。
- 已声明认证方式10 分
请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。
- 已列出工具15 分
请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。
- 描述必需15 分
- 图标10 分
- 文档15 分
- 许可证10 分
