关于 swiss-courts-mcp
用于研究瑞士联邦及全部 26 个州法院判决的 MCP 服务,结合全文与法律条文检索及多种筛选条件。实时数据源不可用时,可改用明确标注来源和覆盖范围的部分离线数据。
主要功能
- 01搜索判决全文
- 02按引用的法律条文搜索
- 03按州、法院级别和日期筛选
- 04按审判庭搜索联邦最高法院判决
- 05查看近期判决和法院列表
- 06使用标注来源的离线备用数据
适用场景
- 01研究瑞士某法律主题的判例
- 02查找引用特定法条的判决
- 03按州或法院级别查看近期裁决
- 04实时数据源中断时继续搜索联邦判决
MCP 相关
向 MCP 客户端提供只读搜索、判决查询、法院信息和统计工具,并附带提示词。离线备用数据会标明来源及覆盖范围。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
🏛️ swiss-courts-mcp
瑞士法院判决 MCP 服务——涵盖瑞士联邦最高法院(BGer)、联邦行政法院(BVGer)、联邦刑事法院(BStGer)以及通过 entscheidsuche.ch 提供的全部 26 个州级法院
概述
通过单一 MCP 接口获取瑞士各级法院的判决。结合全文搜索与州、法院级别、日期范围和法律条文引用等结构化筛选条件。
🎯 示例查询: “查找 2020 年以来瑞士联邦最高法院关于数据保护(Art. 25 DSG)的判例;如果 entscheidsuche.ch 无法访问,则从离线转储中作答,并明确标注。”
| 来源 | 覆盖范围 | 数据 |
|---|---|---|
| entscheidsuche.ch(实时,默认) | 联邦 + 26 个州 | 约自 2000 年以来的法院判决 |
| SCD dump(离线备用) | 仅瑞士联邦最高法院,2007–2024 年 | 元数据/判决摘要,无全文 |
与 fedlex-mcp 协同使用: 法规(SR)+ 判例 = 完整的法律研究。
可用性: entscheidsuche.ch 是一项没有 SLA 的非营利基础设施。无法访问时,服务会透明地回退到缓存的公共转储(参见离线备用)。每个响应都会声明其来源(source: "live" | "dump"),转储数据的回答还会附带 coverage_note——备用数据仅覆盖部分内容,并不等同于实时数据。
功能
- 对所有瑞士法院判决进行全文搜索
- 多阶段法律条文引用搜索,支持正则表达式解析器和 Elasticsearch 加权评分
- 专用瑞士联邦最高法院搜索,支持审判庭筛选
- 按州和法院级别筛选
- 最新判决动态
- 法院分类列表
- 含聚合统计的判决统计信息
- 支持三种语言(德语、法语、意大利语)
- 当 entscheidsuche.ch 无法访问时,离线回退到缓存的公共转储,并在每个响应中明确标注来源
- 无需 API 密钥
前提条件
- Python 3.11 或更高版本
- 兼容 MCP 的客户端(Claude Desktop、Cursor、Windsurf 等)
安装
pip install swiss-courts-mcp
或从源码安装:
git clone https://github.com/malkreide/swiss-courts-mcp.git
cd swiss-courts-mcp
pip install -e ".[dev]"
快速开始
# Run directly
swiss-courts-mcp
# Or via Python module
python -m swiss_courts_mcp
配置
Claude Desktop
将以下内容添加到你的 claude_desktop_config.json:
{
"mcpServers": {
"swiss-courts": {
"command": "python",
"args": ["-m", "swiss_courts_mcp"]
}
}
}
云端部署(HTTP 传输)
HTTP 传输默认关闭。默认绑定主机为 127.0.0.1
(仅限回环地址)——必须显式选择 0.0.0.0(Dockerfile 中已如此设置)。
在未启用身份验证的情况下运行 HTTP 会记录警告;仅应在经过身份验证的反向代理后运行。
# 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
相关环境变量(参见 .env.example):
| 变量 | 默认值 | 用途 |
|---|---|---|
MCP_HOST | 127.0.0.1 | 绑定主机。仅在容器中设置为 0.0.0.0。 |
MCP_PORT | 8000 | 绑定端口。 |
MCP_ALLOW_PUBLIC_BIND | false | 抑制 0.0.0.0 警告(容器)。 |
MCP_STATELESS_HTTP | true | 无状态 HTTP → 无需粘性会话即可水平扩展。 |
MCP_AUTH_ENABLED | false | 为 HTTP 启用 bearer 令牌身份验证。 |
MCP_AUTH_SECRET | — | HS256 签名密钥(开发环境)。 |
MCP_OAUTH_JWKS_URL | — | 用于 RS256 验证的 JWKS URL(生产环境)。 |
MCP_OAUTH_AUDIENCE | — | 启用身份验证时必填。 IdP 将令牌绑定到的资源标识符(aud)。 |
MCP_OAUTH_ISSUER | — | 启用身份验证时必填。 签发令牌的 IdP 的签发者(iss),按字符逐一比对。 |
MCP_RESOURCE_URL | 绑定地址 | 此服务的公开 URL——RFC 9728 资源标识符。在任何非回环绑定时都应设置。 |
MCP_REQUIRED_SCOPES | — | 以逗号分隔的必需作用域。 |
MCP_CORS_ORIGINS | — | 以逗号分隔的允许来源(生产环境中不能使用通配符)。 |
身份验证仅根据 JWT 的 sub 声明验证用户身份;参见
ADR 0001。
启用身份验证后,必须设置 MCP_OAUTH_AUDIENCE。 aud 声明用于将令牌绑定到此服务。如果没有该设置,验证器完全不会检查受众,并会接受来自同一签发者的任何有效签名令牌——包括为其他服务签发的令牌(混淆代理问题)。现在,服务在身份验证模式下启动时若未设置该变量,就会拒绝启动。
出于令牌另一端的相同原因,也必须设置 MCP_OAUTH_ISSUER。 iss 声明将令牌绑定到此服务信任的那个 IdP。多个租户共用一个 JWKS URL 时(托管 IdP 中的常见情况),这一点尤其重要:此时签名对所有租户都有效,只有 iss 能将它们区分开来。实测中,未设置该变量但受众正确时,iss: https://another-tenant.example 的令牌被接受,不含 iss 的令牌也被接受。该值按照 RFC 8414/9207 进行字面比对,包括结尾斜杠,因此不会被规范化——这与会去除结尾斜杠的 MCP_RESOURCE_URL 不同。
该变量也是发现机制正常工作所必需的。RFC 9728 文档中的 authorization_servers[0] 是 SDK 客户端采用的授权服务器值。如果未设置该变量,服务会将自身列为授权服务器——而访问该地址下的
/.well-known/oauth-authorization-server、
/.well-known/openid-configuration、/authorize、/token 和 /register 时都会返回 404,因为此服务是资源服务器,而非授权服务器。
OAuth 客户端需要 MCP_RESOURCE_URL。 根据 RFC 9728,服务会在 /.well-known/oauth-protected-resource 发布资源标识符,并将其写入每个 401 响应的 WWW-Authenticate 标头——客户端会通过它查找获取令牌的位置。如果未设置该变量,服务会发布其绑定地址;在容器绑定场景下实测结果为 {"resource": "http://0.0.0.0:8000", …},客户端无法连接到该地址。在任何非回环绑定时都应设置该变量;若未设置,服务会在启动时发出警告。
由于有实测原因,SDK 自带的 validate_token_resource 保持关闭:它会将令牌的资源指示符与 resource_server_url 进行字面比对,而此处的 resource_server_url 是绑定地址。受众并非该精确 URL 的令牌会被拒绝并返回 401——因此,启用此检查会排斥所有真实客户端,而上文的受众检查才是真正保护服务的机制。
离线回退(环境变量)
| 变量 | 默认值 | 用途 |
|---|---|---|
SWISS_COURTS_FALLBACK_ENABLED | true | 总开关。设为 0 可禁用转储回退(仅实时模式)。 |
SWISS_COURTS_FORCE_DUMP | false | 强制使用转储路径(跳过实时模式)——用于预热缓存或离线测试。 |
SWISS_COURTS_CACHE_DIR | platformdirs cache | 覆盖下载转储文件的缓存目录。 |
SWISS_COURTS_DUMP_RECORD | 14867950 | 要使用的 SCD 转储文件的 Zenodo 记录 ID。 |
预热缓存(一次性下载约 120 MB 的 SCD CSV 文件,避免首次真正发生中断时还要花时间下载):
SWISS_COURTS_FORCE_DUMP=1 python -m swiss_courts_mcp # then issue one search
MCP 协议版本
此服务通过同一端点提供两个协议时代;客户端的第一个请求决定使用哪个:
| 时代 | 修订版本 | server.py 中的常量 | 握手 |
|---|---|---|---|
| 旧版 | 2025-11-25 | HANDSHAKE_PROTOCOL_VERSION | initialize,会话 ID |
| 现代 | 2026-07-28 | MODERN_PROTOCOL_VERSION | 无——每个请求都带有 _meta 信封 |
两个修订版本均已固定,且都有针对已安装 SDK 的漂移防护,因此协议升级会是经过慎重考虑的变更(常量 + CHANGELOG + 本节)。SDK 每月通过 Dependabot 更新。
SDK 自带的客户端选择的是规范 2026-07-28 所属的时代。 mcp.Client 会探测
server/discover,只有在探测被拒绝时才回退到握手;对于此服务,它不会回退。此结果是在
tests/test_modern_era.py 中通过组装后的 ASGI 堆栈测得,而非根据常量名称推断得出。
现代时代的差异:
- 没有
initialize,没有会话 ID。 每个 POST 都是独立的,并带有包含协议版本和客户端能力的params._meta,以及路由标头MCP-Protocol-Version、Mcp-Method,还有(对于tools/call、prompts/get、resources/read)Mcp-Name。 server/discover取代握手以发现能力,而subscriptions/listen取代变更通知。ping、logging/setLevel和resources/subscribe组合均已移除。 在此时代,服务会以-32601响应这些请求;旧版时代则仍保留这些功能。ttlMs/cacheScope随列表方法传递(SEP-2549)——参见CACHE_HINTS。serverInfo会写入每个响应的_meta,因为握手不再承载一次性信息。它包含构建版本、显示标题和项目 URL;用途说明保留在instructions中,该字段随server/discover传递一次。
即使 initialize 请求使用 2026-07-28,得到的仍是 2025-11-25:握手不是进入现代时代的方式,而该响应也不能说明服务是否支持现代时代。
项目阶段
阶段 1——只读(参见 ROADMAP.md)。所有工具均为
readOnlyHint: true;没有写入或破坏性操作。进入阶段 2(写入)前,必须重新完成审计,且通过路线图中列出的门槛。
可用工具
法院裁决搜索
| 工具 | 描述 |
|---|---|
search_court_decisions | 对所有法院裁决进行全文搜索,并可按州、法院级别和日期筛选 |
get_court_decision | 根据唯一标识检索单份裁决 |
search_bger_decisions | 搜索瑞士联邦最高法院裁决,可选择按法庭筛选 |
search_by_law_reference | 查找引用特定法律条文(例如,“Art. 8 BV”)的裁决 |
法院信息
| 工具 | 描述 |
|---|---|
list_courts | 列出所有已编入索引的法院,可选择按州筛选 |
get_recent_decisions | 最新裁决,可按州和法院级别筛选 |
get_decision_statistics | 按州和年份统计已编入索引的裁决 |
get_fallback_status | 离线转储缓存状态、覆盖范围、版本及预热情况(只读) |
工具注释
所有 8 个工具具有相同的提示:它们是只读、幂等、非破坏性的,并且会访问外部系统:
| 注释 | 值 |
|---|---|
readOnlyHint | true |
destructiveHint | false |
idempotentHint | true |
openWorldHint | true |
此外还提供了一个 rechtsrecherche 提示词(与工具并列的第二种 MCP 原语)。
使用场景示例
| 使用场景 | 工具链 |
|---|---|
| 研究数据保护方面的判例 | search_court_decisions("Datenschutz") |
| 查找有关某项宪法权利的实践 | search_by_law_reference("Art. 8 BV") |
| 联邦最高法院最新裁决 | search_bger_decisions("Arbeitsrecht", date_from="2024-01-01") |
| 综合查询:法律文本 + 判例 | fedlex_search_laws("DSG"),然后调用 search_by_law_reference("Art. 25 DSG") |
架构
┌─────────────────────────────────────┐
│ MCP Client (LLM) │
│ Claude / Cursor / Windsurf │
└──────────────┬──────────────────────┘
│ MCP Protocol
┌──────────────▼──────────────────────────────┐
│ swiss-courts-mcp │
│ 8 tools · Pydantic validation │
│ Elasticsearch query builder │
│ Provenance envelope: source = live | dump │
└───────┬──────────────────────────────┬──────┘
│ ① live (default) │ ② fallback
│ HTTPS POST/GET │ on bot-block / 5xx / 429 /
│ │ timeout, or SWISS_COURTS_FORCE_DUMP=1
┌───────▼──────────────────┐ ┌───────▼───────────────────────────────┐
│ entscheidsuche.ch │ │ SCD dump — Zenodo 14867950 (CC BY) │
│ Elasticsearch backend │ │ lazy download → platformdirs cache │
│ Federal + 26 cantons │ │ → local SQLite search │
│ no auth · no SLA │ │ BGer only · 2007–2024 · no full text │
└──────────────────────────┘ └───────────────────────────────────────┘
始终优先使用实时数据:只有在实时数据不可用(机器人拦截、HTTP 5xx/429、超时)或被强制启用时,才会使用离线转储。这是现有工具的行为,并非独立的搜索工具 — 为什么选择此数据源而非全文数据源,请参阅 ADR 0002;有关其覆盖范围及未覆盖内容,请参阅已知限制。你可以随时使用 get_fallback_status 检查缓存。
安全与限制
| 方面 | 详情 |
|---|---|
| 访问权限 | 只读(readOnlyHint: true)— 服务无法修改或删除任何数据 |
| 个人数据 | 不含个人数据 — 所有裁决均为公开的法院判决 |
| 速率限制 | 内置每次查询上限(每次搜索最多 50 条结果,最多 50 个聚合桶) |
| 超时 | 每次 API 调用 30 秒 |
| 数据源身份验证 | 无需 API 密钥 — entscheidsuche.ch 可公开访问 |
| HTTP 传输身份验证 | 可选的 bearer-token 身份验证(JWT,sub 声明用于标识身份);请参阅 ADR 0001 |
| 出站流量 | 代码层允许列表(实时数据为 entscheidsuche.ch;离线转储为 zenodo.org),强制使用 HTTPS;请参阅出站流量策略 |
| 错误屏蔽 | 内部异常仅记录在服务端;客户端会收到易于理解的消息 |
| 密钥 | 代码和日志中不包含密钥;.env 已加入 Git 忽略规则,PR 上运行 Gitleaks;请参阅密钥管理 |
| 许可 | 根据瑞士法律,法院裁决属于公有领域(BGG Art. 27) |
| 服务条款 | 受 entscheidsuche.ch 使用条款约束 — 请友善使用服务器 |
已知限制
- 搜索仅限 entscheidsuche.ch 已编入索引的判决(并非所有判决都已公开)
- 不会返回文档全文内容——仅返回元数据、标题和摘要
- 统计数据取决于后端对 Elasticsearch 聚合的支持
Facetten_alle.json中的法院分类结构可能会变化
**离线回退(覆盖范围有限——请阅读):**回退机制是保障可用性的安全网,并非实时来源的等效镜像:
- 法院范围:仅涵盖联邦最高法院(BGer/BGE)。不涵盖联邦行政法院、联邦刑事法院以及全部 26 个州级法院。
- **时间范围:**2007 年至 2024 年 12 月(SCD 转储的范围)。此时间段以外的判决不在转储中。
- 内容:仅包含元数据/摘要——离线时没有全文。
- **更新延迟:**SCD 转储大约每季度在 Zenodo 上更新一次,因此离线数据会滞后于实时索引。
get_fallback_status会报告缓存版本,并可检查 Zenodo 是否有更新版本。 - 离线法律条文引用搜索仅匹配判决主题/摘要(
topic/issue)中提及的引用——离线没有法律条文引用索引。 - **离线时的
get_court_decision尽力而为:**SCD 案件 ID(docref,例如1C_517/2016)与 entscheidsuche 签名不同,因此有些查询会如实报告为无法解析。 - 响应始终通过
source(live/dump)和coverage_note说明来源;服务绝不会静默缩小覆盖范围——查询未涵盖时会明确回答“未涵盖”,绝不会静默返回空结果。
测试
单元测试使用 respx 模拟所有 HTTP 请求。请从项目根目录运行。CI 运行的五项检查——check_gate_docs.py 会将此列表与 ci.yml 对照,确保它不会悄然过时:
PYTHONPATH=src pytest tests/ -m "not live"
python scripts/check_ruff_pin.py
ruff check src/ tests/ scripts/
ruff format --check src/ tests/ scripts/
python scripts/check_version_sync.py
python scripts/check_gate_docs.py
实时测试不是检查门槛——它们会访问真实来源,并按计划运行(live.yml),而不是在拉取请求时运行:
PYTHONPATH=src pytest tests/ -v -m live
编辑 live.yml 属于特殊情况:GitHub 仅会在默认分支上执行 schedule,因此更改要在合并后才会生效——请手动触发(workflow_dispatch),以便在此之前测试更改。
离线回退测试使用 respx 模拟 Zenodo 下载,并使用一个已提交的小型测试样本——CI 不会下载约 120 MB 的转储文件。
更新日志
请参阅 CHANGELOG.md。
参与贡献
请参阅 CONTRIBUTING.md。
安全
有关安全状况以及如何报告漏洞,请参阅 SECURITY.md。
许可证
作者
Hayal Oezkan · malkreide
致谢与相关项目
- entscheidsuche.ch — 瑞士法院判决搜索引擎(实时来源)
- Swiss Federal Supreme Court Dataset (SCD) — 离线回退来源,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 服务(立法协同)
- zurich-opendata-mcp — 苏黎世开放数据 MCP 服务
- Model Context Protocol — 用于 AI 工具集成的开放协议
安装
通过 uv 的 uvx 运行——无需克隆或手动安装。将其添加到 MCP 客户端配置中(Claude Desktop、Cursor 和 Windsurf 使用 mcpServers;VS Code 在 .vscode/mcp.json 中使用顶层 servers 键):
{
"mcpServers": {
"swiss-courts-mcp": {
"command": "uvx",
"args": [
"swiss-courts-mcp"
]
}
}
}
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。