内容
[](https://github.com/INGV/mcp-fdsnws-event/actions/workflows/docker-build-push.yml?query=branch%3Amain)
[](https://github.com/INGV/mcp-fdsnws-event/blob/main/publiccode.yml)
[](https://hub.docker.com/r/ingv/mcp-fdsnws-event)
[](https://github.com/INGV/mcp-fdsnws-event/blob/main/LICENSE)
[](https://github.com/INGV/mcp-fdsnws-event/issues)
# FDSNWS 事件 MCP 服务器
一个用于查询多个地震数据中心的 FDSN Web 服务事件 API 的 MCP(模型上下文协议)服务器,并以 JSON 格式检索地震信息。
## 功能
- **多数据中心**:与任何符合 FDSN 的数据中心合作(INGV、IRIS、EMSC、GFZ 等)
- **6 种 MCP 工具**:事件搜索、单个事件详情、到达时间、震级、起源、震源机制
- **两种输出级别**:紧凑的表格搜索结果(来自 FDSN 的 `format=text`)和单个事件的完整 QuakeML→JSON 详情(`*_by_id` 工具)
- **标准输入/输出传输**:JSON-RPC 2.0 via 标准输入/输出
- **容器化**:准备好与 Docker 一起使用
## 安装
### 先决条件
- Docker
- Python 3.11+(用于本地开发)
### 选项 A:从 Docker Hub 拉取(推荐)
预构建的多架构镜像(linux/amd64, linux/arm64)已发布在 Docker Hub 上:
```bash
# 最新版本
docker pull ingv/mcp-fdsnws-event:latest
# 特定版本(用已发布的标签替换 X.Y.Z)
docker pull ingv/mcp-fdsnws-event:X.Y.Z
```
> `mcpo` 变体(OpenAPI/REST 包装器,见下文)发布在同一个存储库中,带有 `-mcpo` 后缀,例如 `ingv/mcp-fdsnws-event:latest-mcpo` 和 `ingv/mcp-fdsnws-event:X.Y.Z-mcpo`。
### 选项 B:本地构建容器
```bash
# 克隆存储库
git clone https://github.com/INGV/mcp-fdsnws-event.git
cd mcp-fdsnws-event
# 构建 Docker 镜像
docker build --no-cache -t ingv/mcp-fdsnws-event .
```
## 使用
### 启动 MCP 服务器
```bash
# 拉取已发布的镜像(仅第一次运行)
docker pull ingv/mcp-fdsnws-event
# 启动 MCP 服务器(标准输入/输出)
docker run -i --rm ingv/mcp-fdsnws-event
```
服务器通过标准输入/输出监听 MCP 连接。
### 测试
```bash
# 完整的统一测试套件(推荐)
./run_tests.sh
# 单独运行(如果需要)
# 单元测试(离线)
docker run --rm ingv/mcp-fdsnws-event pytest
# MCP 协议烟雾测试
echo -e '{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": {"name": "test", "version": "1.0.0"}}}\n{"jsonrpc": "2.0", "method": "notifications/initialized", "params": {}}\n{"jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {}}' | docker run -i --rm mcp-fdsnws-event-server
```
`run_tests.sh` 自动运行:
1. Docker 镜像构建
2. 单元测试(离线)
3. MCP 协议烟雾测试
要运行针对 INGV 的实时测试:`./run_tests.sh --integration`。这是验证所有功能性的推荐方法。
### 可用工具
服务器暴露了 6 种工具。它们都接受一个可选的 `datacenter` 参数(默认为 `"INGV"`)。支持的数据中心:INGV、IRIS、EMSC、GFZ 和其他符合 FDSN 的服务。
#### 1. `fdsn_query_earthquakes`
使用灵活的过滤器搜索地震事件。无需参数即可返回今日事件。
**参数(所有参数均为可选):**
- `starttime` / `endtime`:时间窗口(ISO 格式:`YYYY-MM-DDTHH:MM:SS`)。默认:今日 00:00:00–23:59:59 UTC
- `updatedafter`:仅限更新后的事件
- `minmag` / `maxmag`:震级范围
- `mindepth` / `maxdepth`:深度范围(以公里为单位,FDSN 查询参数单位)
- `minlat` / `maxlat` / `minlon` / `maxlon`:地理边界框
- `latitude` / `longitude` / `minradiuskm` / `maxradiuskm`:径向搜索
- `limit`:最大事件数(默认:100,最大:1000)
- `offset`:第一个事件的基于 1 的索引(默认:1),用于与 `limit` 一起分页
- `orderby`:排序顺序 — `time`(默认,最近第一个),`time-asc`,`magnitude`,`magnitude-asc`
- `datacenter`:查询的 FDSN 数据中心(默认:`"INGV"`,可覆盖)
> **注意:**边界框参数和径向搜索参数是互斥的。
**输出:**一个紧凑的表格结果(`columns` + `rows`,每个事件一行,带有首选起源/震级;**深度以公里为单位**)以及一个分页块(`returned_count`,`has_more`,`next_offset`)。对于单个事件的完整详情,请使用 `*_by_id` 工具(完整的 QuakeML,深度以米为单位)。
**示例:**
```json
// 今日事件(默认)
{}
// 过去一周的显著事件(M>=4.0)
{"minmag": 4.0, "starttime": "2025-07-08T00:00:00", "limit": 50}
// 特定地理区域(中意大利)
{"minlat": 41.0, "maxlat": 43.0, "minlon": 12.0, "maxlon": 15.0, "minmag": 2.0}
// 径向搜索(罗马周围 50 公里)
{"latitude": 41.9, "longitude": 12.5, "maxradiuskm": 50}
// 查询 IRIS 而不是 INGV
{"minmag": 5.0, "starttime": "2025-01-01T00:00:00", "datacenter": "IRIS"}
```
#### 2. `fdsn_get_earthquake_by_id`
返回单个事件的基本信息:首选起源、首选震级、台站震级和振幅。
**参数:**
- `eventid`(必填):事件 ID(整数)
- `datacenter`(可选):默认 `"INGV"`
#### 3. `fdsn_get_arrivals_by_id`
返回事件的所有地震相到达时间,包含相关的拾取信息(台站、到达时间、相位)。有助于了解哪些台站记录了事件。
**参数:**
- `eventid`(必填):事件 ID(整数)
- `datacenter`(可选):默认 `"INGV"`
#### 4. `fdsn_get_allmagnitudes_by_id`
返回为事件计算的所有震级解(ML、Mw、Mb、Md 等),指示哪一个是首选的。有助于比较震级类型或机构。
**参数:**
- `eventid`(必填):事件 ID(整数)
- `datacenter`(可选):默认 `"INGV"`
#### 5. `fdsn_get_allorigins_by_id`
返回事件的所有起源解(震中位置),指示哪一个是首选的。有助于比较不同机构计算的位置。
**参数:**
- `eventid`(必填):事件 ID(整数)
- `datacenter`(可选):默认 `"INGV"`
#### 6. `fdsn_get_focalmechanism_by_id`
返回事件的震源机制和矩张量:节点平面(走向、倾角、滑动角)、主轴(T、P、N)和矩张量分量。
**参数:**
- `eventid`(必填):事件 ID(整数)
- `datacenter`(可选):默认 `"INGV"`
## MCP 客户端配置
要将此服务器与 MCP 客户端(例如 Claude Desktop)一起使用,请添加以下配置:
```json
{
"mcpServers": {
"fdsnws-event": {
"command": "docker",
"args": ["run", "-i", "--rm", "ingv/mcp-fdsnws-event"]
}
}
}
```
## 示例查询
### 今日事件
```
"显示我今天在意大利的地震"
```
### 显著事件
```
"过去一周最强的地震是什么?"
```
### 特定区域的事件
```
"在过去 30 天内找到意大利中部震级大于 3.0 的地震"
```
## 开发
### 项目结构
```
mcp-fdsnws-event/
├── src/fdsnws_event_server/
│ ├── __init__.py
│ ├── server.py # MCP 服务器(FastMCP 工具定义)
│ ├── models.py # Pydantic 输入验证模型
│ └── obspy_client.py # FDSN 格式=text 查询 + ObsPy QuakeML→JSON 详情
├── tests/ # pytest:单元(离线)+ 集成(在线)
│ ├── fixtures/ # 真实的 FDSN 格式=text 响应
│ ├── unit/ # 解析器、查询、模型(网络模拟)
│ ├── integration/ # 在线 INGV 测试(@pytest.mark.integration)
│ └── README.md # 如何运行测试
├── pyproject.toml # Python 配置
├── Dockerfile # Docker 容器
├── run_tests.sh # 完整的测试套件
└── README.md
```
### 本地测试
```bash
# 安装依赖项(包含 pytest 的开发额外功能)
pip install -e ".[dev]"
# 运行测试
pytest # 单元(离线,默认)
pytest -m integration # 在线测试针对 INGV(需要网络)
```
测试详情和约定参见 [`tests/README.md`](tests/README.md)。
### FDSN API
服务器查询任何符合 FDSN 的数据中心:
- **INGV**(默认):`https://webservices.ingv.it/fdsnws/event/1/query`
- **IRIS**:`https://service.iris.edu/fdsnws/event/1/query`
- **EMSC**:`https://www.seismicportal.eu/fdsnws/event/1/query`
- **GFZ**:`https://geofon.gfz-potsdam.de/fdsnws/event/1/query`
- **格式**:通过 `format=text` 搜索(表格);通过 QuakeML(XML)→ JSON 详细
- **文档**:[FDSNWS 事件 API](https://www.fdsn.org/webservices/fdsnws-event-1.1.pdf)
## OpenWebUI 集成(mcpo)
[OpenWebUI](https://docs.openwebui.com/features/extensibility/mcp/) 通过 [`mcpo`](https://github.com/open-webui/mcpo) 与 MCP 服务器通信,`mcpo` 是一个代理,公开 MCP 服务器作为 OpenAPI/REST 端点。本存储库附带了一个 `mcpo` 包装器,直接运行服务器(无需 Docker-in-Docker,无需 Docker 套接字挂载):参见 `Dockerfile.mcpo` 和 `compose.mcpo.yml`。
### 运行
拉取并运行已发布的 `mcpo` 镜像(推荐):
```bash
docker pull ingv/mcp-fdsnws-event:latest-mcpo
docker run -d -p 8000:8000 --name mcp-fdsnws-event_mcpo ingv/mcp-fdsnws-event:latest-mcpo
```
或本地构建(用于开发):
```bash
docker build -t ingv/mcp-fdsnws-event . # 基础镜像
docker compose -f compose.mcpo.yml up -d --build # mcpo 包装器在 :8000
```
这暴露了:
- OpenAPI 规范:`http://<host>:8000/openapi.json`
- Swagger UI:`http://<host>:8000/docs`
- 每个工具的一个端点,例如 `POST http://<host>:8000/fdsn_query_earthquakes`
### 连接 OpenWebUI
在 OpenWebUI 中,转到 **设置 → 工具**(或 **管理员 → 设置 → 工具**)并添加 URL `http://<host>:8000`。
- **如果 OpenWebUI 本身在 Docker 中运行**,则 `localhost:8000` 从其容器内无法访问主机。使用 `http://host.docker.internal:8000`(Docker Desktop)或主机局域网 IP,或将两个服务放在同一 Docker 网络中。
- **保护端点**:默认情况下,mcpo 无需身份验证即可公开。如需保护,请取消注释 `compose.mcpo.yml` 中的 `command:` 行以添加 `--api-key "<your-key>"`,然后在 OpenWebUI 中设置相同的密钥。
> 包装器镜像将 `mcpo` 和服务器捆绑在一个镜像中,并运行 `mcpo ... -- python -m fdsnws_event_server.server`,因此它 **不** 挂载 Docker 套接字或启动嵌套容器。
### 验证工具调用可靠性(A/B 套件)
当客户端模型在多个回合中丢失标识符时,它可能会 *发明* 一个 - 例如,通过 `fdsn_get_arrivals_by_id` 调用时使用占位符 `eventid`(`123456`)而不是先前 `fdsn_query_earthquakes` 返回的 `EventID`。服务器通过三态按 ID 合同(`found` / `message`,参见 `docs/adr/0006`)来防范这一点,但其行为本身存在于 OpenWebUI ↔ 模型循环中,最好通过实证方法衡量。
`tests/ab/eventid_hallucination_ab.py` 是一个独立的 A/B 测试工具(不由 `pytest` 运行),它通过 OpenWebUI OpenAI 兼容的 API 将失败的对话重放给一个在线模型,并报告模型传递正确的 `eventid` 与虚构的次数:
```bash
export OPENWEBUI_API_KEY=sk-... # OpenWebUI:设置 → 账户 → API 密钥
python tests/ab/eventid_hallucination_ab.py \
--base-url http://<host>:8080 \
--model <model-id-as-listed-in-openwebui> \
--repeat 10 --variant both --temperature 0.7
```
如果 `--model` 不存在于实例上,它将快速失败,并且比较两个工具描述(`baseline` vs `fixed`),以便您可以将任何增量归因于服务器端措辞。使用它来检查新模型,或确认 OpenWebUI 配置更改(例如 **Native** 函数调用)实际上修复了 ID 重用。
## 许可证
该项目在 **GNU Affero 通用公共许可证 v3.0 或更高版本**(AGPL-3.0-or-later)下发布。有关完整文本,请参见 [`LICENSE`](LICENSE) 文件。
## 作者
参见 [`AUTHORS.md`](AUTHORS.md)。
## 贡献
欢迎贡献!请:
1. 复刻存储库
2. 从 `main` 创建一个功能分支
3. 提交您的更改(参见 [Conventional Commits](https://www.conventionalcommits.org/))
4. 对 `main` 打开一个拉取请求
通过贡献,您同意您的贡献根据该项目的 AGPL-3.0-or-later 许可证获得许可。
## 支持
对于问题或疑问,请在 [GitHub 存储库](https://github.com/INGV/mcp-fdsnws-event/issues) 中打开一个问题。