内容
# at-ris-mcp
<!-- mcp-name: io.github.paragraflabs/at-ris-mcp -->
[](https://github.com/paragraflabs/at-ris-mcp/actions/workflows/ci.yml)
[](https://pypi.org/project/at-ris-mcp/)
[](https://pypi.org/project/at-ris-mcp/)
[](LICENSE)
一个通用的 **MCP服务器** 和独立的 **Python客户端库**,用于奥地利的 **RIS** (Rechtsinformationssystem des Bundes,联邦法律信息系统),即奥地利共和国官方的法律信息系统,由联邦总理办公室(Bundeskanzleramt)运营。
它涵盖了 **联邦法律** (Bundesrecht,包括合并法律`BrKons`、官方公报、草案和政府法案)、**州法律** (Landesrecht,九个联邦州的法律)、**案例法** (Judikatur,包括最高法院、宪法法院、行政法院等)、部长令、区和市法律,以及通过`https://data.bka.gv.at/ris/api/v2.6/`提供的无密钥OGD API的变化监控。
## 为什么存在
与现有的RIS工具相比,`at-ris-mcp`添加了:
- **合并法律** (`BrKons`) — 当前适用的文本,而不仅仅是官方公报的修正案。
- **章节精确访问** — 检索单个章节(`§`/Artikel/Anlage)。
- **历史版本** — 特定日期的法律版本(`Fassung.FassungVom`)。
- **干净的Markdown** — RIS HTML(≈40 KB的CSS样板)被剥离到法律文本,具有`raw`开关用于原始文本。
## 两个软件包,一个仓库
- **`ris_client`** — 一个独立的、与MCP无关的库。可以直接导入。
- **`ris_mcp`** — 一个薄的FastMCP/stdio包装器,暴露了10个工具。本身不包含任何逻辑。
## 安装
```bash
pip install at-ris-mcp # 仅限库
pip install "at-ris-mcp[mcp]" # + MCP服务器(FastMCP)
```
## 运行MCP服务器(stdio)
```bash
at-ris-mcp
# 或
python -m ris_mcp
```
### 远程传输(HTTP / SSE)
对于托管或远程部署,服务器还可以提供可流式的HTTP或SSE,而不是stdio:
```bash
at-ris-mcp --transport http --host 0.0.0.0 --port 8000 # 可流式HTTP
at-ris-mcp --transport sse --port 9000 # SSE
# 或通过环境变量:
RIS_MCP_TRANSPORT=http RIS_MCP_PORT=8000 at-ris-mcp
```
HTTP端点默认情况下在`/mcp`提供(覆盖与 `--path` / `RIS_MCP_PATH`)。如果未给出传输方式,则stdio保持默认。
### 工具
| 工具 | 用途 |
|---|---|
| `ris_search_law` | 搜索联邦法律(默认`BrKons`;也包括`BgblAuth`、`Begut`、`RegV`等)。章节和版本过滤。 |
| `ris_get_law_text` | 法规/章节的全文(markdown \| html \| xml \| raw)。 |
| `ris_search_case` | 搜索案例法(默认`Justiz`;所有法院)。按适用的`norm`过滤。 |
| `ris_get_case_text` | 判决的全文。 |
| `ris_search_state_law` | 搜索州法律(9个联邦州;默认`LrKons`)。通过`bundeslaender`选择州。 |
| `ris_search_misc` | 搜索`Sonstige`(部长令`Erlaesse`、`Avsv`等)。 |
| `ris_search_district` | 搜索区级权威通知(`Bezirke` / `Bvb`)。 |
| `ris_search_municipality` | 搜索市法律(`Gemeinden` / Gemeinderecht `Gr`/`GrA`)。 |
| `ris_list_collections` | 哪些端点/应用程序被覆盖。 |
| `ris_list_changes` | 通过OGD SOAP端点(含已删除文档)的变更/预警订阅(RIS历史)。 |
## 库的使用
```python
import asyncio
from ris_client import RisClient, LawSearchRequest, TextFormat
async def main():
async with RisClient() as c:
res = await c.search_law(LawSearchRequest(suchworte="Datenschutzgesetz",
page_size="Ten"))
hit = res.items[0]
print(hit.human_readable_citation, hit.eli_uri)
text = await c.get_text(hit.content_urls["html"], TextFormat.markdown)
print(text.content[:500])
asyncio.run(main())
```
## 配置(环境变量)
| 变量 | 默认值 | 含义 |
|---|---|---|
| `RIS_BASE_URL` | `https://data.bka.gv.at/ris/api/v2.6` | API基础(版本隔离)。 |
| `RIS_SOAP_URL` | `https://data.bka.gv.at/ris/ogd/v2.6/` | OGD SOAP端点(由`ris_list_changes`使用)。 |
| `RIS_USER_AGENT` | `at-ris-mcp/<version> (+…)` | 描述性UA(网络礼仪)。 |
| `RIS_RATE_MS` | `1200` | 请求之间的最小延迟(毫秒)。 |
| `RIS_TIMEOUT_S` | `30` | HTTP超时。 |
| `RIS_MAX_RETRIES` | `3` | 429/5xx重试次数(含503)。 |
| `RIS_CACHE_DIR` | `~/.cache/at-ris-mcp` | SQLite缓存位置。 |
| `RIS_CACHE_ENABLED` | `true` | 切换缓存。 |
| `RIS_AUDIT_DIR` | *(未设置)* | 如果设置,则追加每个调用的JSONL审计行(无全文,无客户端数据)。 |
| `RIS_MCP_TRANSPORT` | `stdio` | 服务器传输:`stdio` \| `http` \| `sse` \| `streamable-http`。 |
| `RIS_MCP_HOST` | `127.0.0.1` | http/sse的绑定主机。 |
| `RIS_MCP_PORT` | `8000` | http/sse的绑定端口。 |
| `RIS_MCP_PATH` | *(传输默认)* | HTTP端点的URL路径。 |
## 网络礼仪和速率限制
根据RIS OGD常见问题解答:每页强制执行1-2秒的暂停;批量访问应在办公时间以外(18:00-06:00)或周末进行,并应通知`ris.it@bka.gv.at`。默认情况下会发送描述性User-Agent。
## 许可
- **代码:** Apache-2.0(参见`LICENSE`)。
- **数据:** 检索的文档由奥地利共和国在**CC BY 4.0**下提供。每个工具响应都包含一个`attribution`字段:
> 来源:RIS – Rechtsinformationssystem des Bundes(data.bka.gv.at),CC BY 4.0
- **无法律建议。** 只有原始公布文本(Bundesgesetzblatt/Landesgesetzblatt authentisch)具有法律约束力。合并法律和其他文档仅供信息使用。每个响应都包含一个`legal_notice`,说明这一点。
## 范围(v1.0)
涵盖:`Bundesrecht`(`BrKons`、`BgblAuth`、`BgblPdf`、`BgblAlt`、`Begut`、`RegV`、`Erv` — 英文翻译)、`Judikatur`(所有法院)、**历史变更订阅**(`ris_list_changes`,包括已删除文档)、**Landesrecht**(9个联邦州:`LrKons`、`LgblAuth`、`Lgbl`、`LgblNO`、`Vbl`)、**Sonstige**(`Erlaesse`、`Avsv`、`Avn`、`Spg`、`KmGer`、`Upts`、`Mrp`、`PruefGewO` — 带有应用特定细过滤器)、**Bezirke** (`Bvb`) 和 **Gemeinden** (`Gr`、`GrA`)。
> **英文翻译(`Erv`):** 通过`ris_search_law`搜索,带有`applikation="Erv"`。`suchworte`/`titel`自动映射到RIS `SearchTerms`/`Title`参数。
> **州法律说明:** 对于合并州法律(`LrKons`),通过`bundeslaender`选择州(例如`["Kaernten","Tirol"]`);这映射到API所需的带点`Bundesland.SucheIn<Land>=true`标志(扁平形式为`LrKons`默默忽略)。
> **历史说明:** 合并联邦法律在`Bundesnormen`应用程序名称下监控(不是`BrKons`),合并州法律在`Landesnormen`下监控。历史查询使用OGD **SOAP**端点,因为它未通过REST GET API公开。
## 开发
```bash
pip install -e ".[dev,mcp]"
pytest # 离线测试
RIS_SMOKE=1 pytest -m smoke # 针对真实API的实时烟雾测试
```
## 发布
发布是自动化的。推送版本号标签(`vX.Y.Z`)会触发GitHub Actions构建分发包、发布到 **PyPI** (通过Trusted Publishing / OIDC — 无API令牌)、创建 **GitHub Release**,并在 **MCP Registry**中注册新版本。
```bash
# 在pyproject.toml、src/ris_client/config.py和server.json中增加版本号,
# 更新CHANGELOG.md,然后:
git tag -a vX.Y.Z -m "vX.Y.Z"
git push origin vX.Y.Z
```
要在本地构建而不发布:
```bash
python -m build # sdist + wheel进入dist/
python -m twine check dist/*
```
MCP注册条目由`server.json`描述(名称`io.github.paragraflabs/at-ris-mcp`);匹配的`mcp-name:`标记嵌入在此README的顶部。
## 贡献和支持
问题和拉取请求欢迎在<https://github.com/paragraflabs/at-ris-mcp>提出。有关发布历史,请参见[`CHANGELOG.md`](CHANGELOG.md)。该项目与奥地利共和国或联邦总理办公室无关;它是公共RIS OGD接口的独立客户端。