关于 swiss-environment-mcp
swiss-environment-mcp 将瑞士联邦环境数据通过 MCP 提供给 AI 助手,涵盖空气、水文、自然灾害及 BAFU 数据目录等领域。无需 API 密钥,可查询实时监测数据、警报和公开数据集。
主要功能
- 01查询 NABEL 空气质量及限值
- 02查看水位、流量和水温
- 03查询洪水与野火警报
- 04获取雪况和雪崩危险等级
- 05检索 BAFU 环境数据集
- 06查询飞机噪声与限值
适用场景
- 01检查苏黎世 NABEL 站的当前空气质量
- 02查询瑞士的活动洪水警报
- 03查看瓦莱州的野火危险等级
- 04搜索 BAFU 生物多样性数据集
MCP 相关
该 MCP 服务向客户端提供瑞士环境数据工具,覆盖空气质量、水文、灾害、雪况、狩猎统计、数据目录和飞机噪声。支持 stdio 与 Streamable HTTP/SSE 传输。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
🌿 swiss-environment-mcp
MCP 服务将 AI 模型连接到来自 BAFU 的瑞士环境数据,包括空气质量、水文、自然灾害、野火风险和开放环境数据集。
概述
swiss-environment-mcp 让 Claude 等 AI 助手能够直接访问瑞士联邦机构的实时环境数据,无需 API 密钥。通过单一标准化 MCP 接口,即可访问国家 NABEL 监测网络的空气质量读数、水文测量站数据、自然灾害公告以及完整的 BAFU 数据集目录。
该服务涵盖四个主题类别:空气质量(NABEL)、水文、自然灾害和 BAFU 开放数据目录。每个类别对应一组专用工具,可将机构原始数据转换为清晰的 JSON 响应。
演示查询: “Zürich-Kaserne 的 NABEL 测站当前空气质量如何?是否符合 WHO 2021 指南?” → 按受众分类的更多用例 →
功能
- 🌬️ 空气质量监测 – 16 个 NABEL 测站,NO₂/O₃/PM10/PM2.5/SO₂/CO,瑞士 LRV 和 WHO 2021 限值检查
- 💧 水文 – 瑞士各测站的水位、流速和温度
- 🚨 洪水预警 – 按危险等级和州筛选的有效警报
- 🏔️ 自然灾害公告 – SLF/BAFU 提供的 DE/FR/IT/EN 公告及地区特定预警
- 🔥 野火风险 – 州和地区级别的火灾风险指数
- ❄️ 积雪与雪崩(SLF) – 各 IMIS 测站的雪深和新增积雪;雪崩危险等级(EAWS)
- 🦌 狩猎统计 – 按物种、州和年份统计的猎获与野生动物损失数据(联邦狩猎统计)
- 📦 BAFU 开放数据目录 – 通过 CKAN 搜索和检索环境数据集
- 🔑 无需身份验证 – 所有数据源均可公开访问
- ☁️ 双传输方式 – 适用于 Claude Desktop 的 stdio,以及适用于云部署的 Streamable HTTP/SSE
先决条件
- Python 3.11+
- 无需 API 密钥 – 所有端点均可在未经身份验证的情况下公开访问
安装
# Clone the repository
git clone https://github.com/malkreide/swiss-environment-mcp.git
cd swiss-environment-mcp
# Install
pip install -e .
或使用 uvx(无需永久安装):
uvx swiss-environment-mcp
或通过 pip 安装:
pip install swiss-environment-mcp
快速开始
# Start the server (stdio mode for Claude Desktop)
swiss-environment-mcp
立即在 Claude Desktop 中试用:
“NABEL Zürich-Kaserne 测站当前空气质量如何?” “瑞士目前是否有任何有效的洪水预警?” “瓦莱州的野火风险等级是多少?”
配置
Claude Desktop
最简配置(推荐):
{
"mcpServers": {
"swiss-environment": {
"command": "uvx",
"args": ["swiss-environment-mcp"],
"env": {}
}
}
}
配置文件位置:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
保存后,请完全重启 Claude Desktop。
云端部署(用于浏览器访问的 SSE)
用于通过浏览器中的 claude.ai 使用(例如,在无法安装本地软件的受管工作站上):
Render.com(推荐):
- 将仓库推送到 GitHub,或在 GitHub 上复刻仓库
- 在 render.com 上:New Web Service → 连接 GitHub 仓库
- Render 会自动检测
render.yaml - 在 claude.ai 的 Settings → MCP Servers 下,添加:
https://your-app.onrender.com/sse
Docker:
docker build -t swiss-environment-mcp .
docker run -p 8000:8000 swiss-environment-mcp
💡 “开发者笔记本电脑用 stdio,浏览器用 SSE。”
可用工具
所有工具都使用稳定的 env_ 名称前缀——这是经过深思熟虑的命名空间选择,便于识别服务的工具,并降低同时挂载多个 MCP 服务时发生名称冲突的可能性。工具定义(名称、描述、输入架构)由 tool-snapshot.json 固定;任何更改都必须添加 CHANGELOG 条目(参见 CONTRIBUTING)。
工具预算(21 个工具,7 个集群)——已用尽。 每个工具都对应一个独立的用户问题,而非某个 REST 端点——这里没有 CRUD/端点镜像,每个核心查询都可以通过一次调用回答。工具数量超过了 ≤12 的经验规则,是因为该服务有意覆盖七个环境领域(空气、水、灾害、积雪、狩猎、目录、飞机噪声),每个领域都需要列表/详情工具对或特定领域的操作。我们曾考虑进一步整合,但最终否决了:*_stations/*_current 工具对(NABEL、水文、积雪)分别满足真正不同的需求(发现站点与读取已知站点数据),将其合并会让单个工具的参数负担过重。
这是上限。 随着飞机噪声集群的加入,服务的工具预算已用尽:任何新增数据源都应归入单独的 *-mcp 服务,而不是此处。下一次新增工具时,应转而评估是否要将某些列表迁移为 MCP 资源,而非工具。
🌬️ 空气质量 / NABEL(3 个工具)
| 工具 | 描述 | 数据来源 |
|---|---|---|
env_nabel_stations | 列出全部 16 个 NABEL 监测站及其位置类型和州 | NABEL / BAFU |
env_nabel_current | 某个站点的当前空气质量数据(NO₂、O₃、PM10、PM2.5、SO₂、CO) | NABEL / BAFU |
env_air_limits_check | 将测量值与瑞士 LRV 限值和 WHO 2021 指南进行比较 | 内置 |
💧 水文(5 个工具)
| 工具 | 描述 | 数据来源 |
|---|---|---|
env_hydro_stations | 按水体筛选水文测量站(无法按州筛选——参见说明) | LINDAS SPARQL |
env_hydro_current | 某个站点当前的水位、流量和温度 | LINDAS SPARQL |
env_hydro_history | LINDAS 的最新数值,以及获取实时序列数据的路径 ⚠️ | LINDAS SPARQL |
env_flood_warnings | 按危险等级筛选当前有效的洪水警报(覆盖全国——未应用州筛选) | LINDAS SPARQL |
env_bathing_water | 各沐浴地点的沐浴水质(E.coli、肠球菌)——多年时间序列 | LINDAS SPARQL(数据立方体 ubd0104) |
🏔️ 自然灾害(3 个工具)
| 工具 | 描述 | 数据来源 |
|---|---|---|
env_hazard_overview | 路由器:指向专用实时灾害工具和官方门户(不进行网络调用——汇总型 naturgefahren.ch API 已停用) | 本地 |
env_hazard_regions | 路由器:将灾害类型(洪水/雪崩/野火/积雪)映射到相应的实时工具和门户(不进行网络调用) | 本地 |
env_wildfire_danger | 按州和地区划分的野火危险指数 | waldbrandgefahr.ch |
❄️ 积雪与雪崩 / SLF(3 个工具)
| 工具 | 描述 | 数据来源 |
|---|---|---|
env_snow_stations | 列出自动 SLF/IMIS 积雪测量站(按州) | measurement-api.slf.ch |
env_snow_current | 各站点当前雪深(HS)和 24 h 新雪量(HN_1D),单位为 cm | measurement-api.slf.ch |
env_avalanche_bulletin | 各警报区域的雪崩危险等级(EAWS 1–5),按季节划分 | aws.slf.ch |
🦌 狩猎与野生动物(2 个工具)
| 工具 | 描述 | 数据来源 |
|---|---|---|
env_hunting_species | 列出联邦狩猎统计中跟踪的 36 个物种(含代码) | jagdstatistik.ch(内置) |
env_hunting_stats | 按物种、州和年份(2015–2024)统计的捕杀量、野生动物损失和种群数量 | jagdstatistik.ch |
📊 环境数据目录(2 个工具)
| 工具 | 描述 | 数据来源 |
|---|---|---|
env_bafu_datasets | 在 opendata.swiss 上搜索 BAFU 数据集(CKAN API) | opendata.swiss |
env_bafu_dataset_detail | 特定数据集的完整元数据和下载 URL | opendata.swiss |
✈️ 飞机噪声 / BAZL 噪声地籍(3 个工具)
| 工具 | 描述 | 数据来源 |
|---|---|---|
env_noise_aircraft_at | 查询 LV95 点的飞机噪声暴露情况——解析重叠的噪声等值线,并返回一个以最高值为上限的 dB 范围 | api3.geo.admin.ch(BAZL) |
env_noise_aircraft_registers | 哪些机场已发布噪声地籍,包括有效日期、dB 范围和官方规划图(PDF)——用于追溯数据来源的工具 | api3.geo.admin.ch(BAZL) |
env_noise_limits_check | 按敏感度等级 ES I–IV,将评定级与 LSV 暴露限值(规划值 / 影响限值 / 警报值)进行比较 | 内置(SR 814.41,附录 5) |
⚖️ 法律声明——每个工具的所有响应中均包含此声明。 噪声地籍仅是参考工具。建设项目的法律约束性信息由主管州级部门或 FOCA(BAZL)提供。这些工具不能替代建筑许可审查。
坐标必须使用 LV95(EPSG:2056,单位为米:E ≈ 2'480'000–2'840'000,N ≈ 1'070'000–1'300'000)。WGS84 度数(例如 8.54 / 47.37)会被拒绝,并立即报错提示如何转换——这是大模型处理瑞士地理数据时最常见的错误。请通过 swisstopo REFRAME 或 swisstopo-mcp 中的 convert_coordinates 进行转换。
等值线是线,而非区域。 噪声地籍发布的是 MultiLineString 等值线,因此 identify 会在搜索半径内执行邻近查询,而非点在多边形内测试。因此,env_noise_aircraft_at 返回的是一个范围(“该点位于 61 dB 和 62 dB 等值线之间”),并将最高值明确标为上限,绝不会返回插值得出的点值。每个响应都会报告搜索半径;扩大半径会使结果范围变宽(在 Kloten 的一个点位,100 m → 61–62 dB,而 500 m → 58–75 dB,因为 75 dB 的跑道等值线距离该点 1.5 km)。
演示核心查询
“计划中的学校选址是否位于有建筑限制的飞机噪声区域内?噪声级别是多少 dB?”
跨服务流程:通过 swiss-housing-mcp 解析地址或 EGID → 转换为 LV95 坐标 → env_noise_aircraft_at(east=…, north=…, period="day") → 将返回的 level_db 传入 env_noise_limits_check(level_db=…, sensitivity_level="II", period="day") 进行法律分类。
swiss-housing-mcp → address / EGID → LV95 E/N
↓
env_noise_aircraft_at → 62 dB (upper bound, LBK Zürich, valid from 03.07.2015)
↓
env_noise_limits_check → immission limit ES II (60 dB) exceeded by 2 dB
示例用例
| 查询 | 工具 |
|---|---|
| “苏黎世 Kaserne 当前的空气质量如何?” | env_nabel_current |
| “45 µg/m³ 的 NO₂ 是否超过瑞士限值?” | env_air_limits_check |
| “苏黎世利马特河当前水位是多少?” | env_hydro_current |
| “Küsnacht 海滨浴场的水质适合游泳吗?” | env_bathing_water |
| “瑞士有哪些正在生效的洪水警报?” | env_flood_warnings |
| “格劳宾登州的自然灾害公告是什么?” | env_hazard_overview |
| “瓦莱州的野火危险程度如何?” | env_wildfire_danger |
| “opendata.swiss 上有哪些 BAFU 生物多样性数据集?” | env_bafu_datasets |
| “计划中的学校选址是否位于飞机噪声区?噪声级是多少 dB?” | env_noise_aircraft_at |
| “日内瓦机场的噪声地籍数据有多久了?” | env_noise_aircraft_registers |
| “ES II 住宅区夜间 62 dB 是否超过 LSV 限值?” | env_noise_limits_check |
🛡️ 安全与限制
| 方面 | 详情 |
|---|---|
| 访问权限 | 只读(readOnlyHint: true)——服务无法修改或删除任何数据 |
| 个人数据 | 不涉及个人数据——所有来源均为汇总后的公开环境测量数据 |
| 速率限制 | 内置单次查询上限(例如,水文历史数据最多 30 天,数据集搜索结果最多 50 条) |
| 超时 | 每次 API 调用 30 秒 |
| 身份验证 | 无需 API 密钥——所有 BAFU 端点均可公开访问 |
| 许可证 | BAFU 开放政府数据(OGD)——可免费复用,但必须注明出处 |
| 服务条款 | 须遵守相应数据源的服务条款:BAFU / opendata.swiss、hydrodaten.admin.ch、naturgefahren.ch、waldbrandgefahr.ch |
架构
┌─────────────────┐ ┌───────────────────────────┐ ┌──────────────────────────┐
│ Claude / AI │────▶│ Swiss Environment MCP │────▶│ Upstreams (contacted) │
│ (MCP Host) │◀────│ (MCP Server) │◀────│ │
└─────────────────┘ │ │ │ lindas.admin.ch (SPARQL)│
│ 21 Tools · 3 Resources │ │ measurement-api.slf.ch │
│ Stdio | SSE │ │ aws.slf.ch │
│ │ │ waldbrandgefahr.ch │
│ api_client.py │ │ jagdstatistik.ch │
│ server.py (FastMCP) │ │ api3.geo.admin.ch │
└───────────────────────────┘ │ opendata.swiss (CKAN) │
└──────────────────────────┘
架构说明 — 可提取的 lindas/ 模块
所有 LINDAS SPARQL 访问都通过专门设计为可提取的
src/swiss_environment_mcp/lindas/ 模块进行,该模块由三个严格分层的部分构成:
client.py 仅处理 SPARQL 和 HTTP(GET/POST、客户端侧超时 45 s、
携带服务器 MALFORMED 消息的 QueryError、2 s/4 s/8 s 重试);
cube.py 处理 cube.link 词汇表(强制使用 observationSet
进行两阶段访问,通过 schema:expires 去重版本,将代码解析为标签,
查询许可证);工具只会调用 cube.py。一旦第二个服务使用
LINDAS(候选项目:wsl-envidat-mcp),该模块就会被提取为共享的
lindas-mcp。
架构决策 —— 飞机噪声地籍采用实时 API
本服务器的其余部分遵循项目组合的 优先使用数据转储 标准。飞机噪声数据集有意采用不同做法:env_noise_aircraft_at 和 env_noise_aircraft_registers 每次调用时都会实时查询 api3.geo.admin.ch。
这不是因为数据量。根据 2026-07-28 的测量,整个地籍在全部 8 个子图层中共包含 747 个对象(约 3 MB GeoJSON),轻松就能镜像。另有两个原因决定了这一做法:
- 镜像会让新鲜度声明失实。 各机场的地籍会单独修订,且没有公告(有效期为 2009–2024 年)。如果从数据转储读取,
source_freshness报告的validfrom就会是镜像日期;该工具会声称拥有实际上已不再具备的来源凭据。对于这样一个第三个工具恰恰是为了回答“依据有多旧”而存在的数据集,这会是最糟糕的故障模式。 - 空间查询才是价值所在,而非属性。 在本地评估意味着要对每个图层超过 26,000 个顶点计算点到线的距离。这需要使用 shapely/GEOS——这会成为特意保持不含二进制依赖的
pyproject.toml中第一个编译依赖(Docker 镜像、wheel 矩阵和安全面都会随之改变)——或者手写距离计算。后者可行,因为 LV95 是度量投影,欧几里得距离是精确的;但那样一来,负责官方噪声地籍声明准确性的就会变成本服务器,而不是联邦办公室。
完整的测量数据和推理过程:docs/probe-fluglaerm.md。
数据来源
| 来源 | 数据 | 许可证 |
|---|---|---|
| lindas.admin.ch | 通过 SPARQL 获取当前水文数据(水位、流量、水温)和沐浴水质 | BAFU Open-Use / OGD(按图谱/数据集声明——每个响应都包含许可证字段) |
| hydrodaten.admin.ch | 自 v0.6.0 起不再通过 HTTP 联系——/lhg/az/* 端点已停用,数据来自 LINDAS。仅作为工具输出中的链接出现,并已从出口允许列表中移除(SEC-021)。 | BAFU OGD |
| naturgefahren.ch | 自然灾害公告(SLF/BAFU) | BAFU/SLF |
| waldbrandgefahr.ch | 野火危险指数 | BAFU |
| SLF data service | 雪深、新雪(IMIS);雪崩公告 | SLF (WSL) CC BY 4.0 |
| jagdstatistik.ch | 联邦狩猎统计(捕获量、野生动物损失、种群数量) | BAFU——必须注明来源(未发布明确许可证) |
| api3.geo.admin.ch | BAZL 飞机噪声地籍(identify、LV95) | swisstopo / BAZL——可免费复用,但必须注明来源 |
| opendata.swiss | BAFU 数据目录(CKAN API) | OGD |
所有数据均可公开访问,无需身份验证。
必须注明来源: 使用 BAFU / SLF (WSL) 的数据时,必须将其列为来源。
项目结构
swiss-environment-mcp/
├── src/swiss_environment_mcp/
│ ├── __init__.py # Package
│ ├── server.py # FastMCP server: 21 tools, 3 resources
│ ├── api_client.py # HTTP client + egress allow-list (SSRF guard)
│ └── logging_setup.py # structlog -> stderr
├── tests/
│ ├── test_unit.py # Mocked unit tests (no network) — CI default
│ ├── test_integration.py # Live API tests (marker: live)
│ └── test_20_scenarios.py # Live scenario coverage
├── scripts/tool_snapshot.py # Tool-definition hash snapshot (rug-pull guard)
├── docs/ # security.md, scaling.md, roadmap.md
├── .github/
│ ├── dependabot.yml # Monthly dependency/action updates
│ └── workflows/ # ci.yml, security.yml (gitleaks), live-tests.yml, publish.yml
├── Dockerfile # Multi-stage, non-root container
├── render.yaml / Procfile # Cloud deployment
├── tool-snapshot.json # Committed tool-definition snapshot
├── .env.example # Non-secret config template
└── pyproject.toml # Build configuration (hatchling)
单模块布局(理由,审计 ARCH-011): 21 个工具集中在一个
server.py中,而非放入tools/包。它们是对api_client.py的轻量、统一封装,共享相同的输入/响应模式,因此将它们放在一个结构清晰的模块中,比拆分为 4 个几乎相同的文件更便于浏览。这是有意为之并已记录的偏离;如果工具逻辑不再统一,将重新评估是否拆分。
MCP 协议版本与维护
此服务通过同一端点支持两个协议时代。客户端在连接上的首个请求决定使用哪种协议;之后若声明另一个时代,则会被拒绝。
| 时代 | 修订版本 | 如何接入 |
|---|---|---|
initialize 握手 | 2024-11-05 … 2025-11-25 | 当前客户端使用的协议。服务会以请求中指定的修订版本响应;如果请求要求更新版本,则使用 2025-11-25 这一上限。 |
| 逐请求封装 | 2026-07-28 | 携带 2026-07-28 _meta 封装的请求会建立现代连接。 |
两个修订版本都固定在
tests/test_protocol_version.py 中,并与已安装的 SDK 进行断言比对,因此 Dependabot 升级 mcp 时,不会悄然改变任一版本。
不过,这项固定检查测量的是 SDK,而不是本服务:即使服务完全没有响应现代协议时代,检查也仍会通过。实际测量的部分位于
tests/test_modern_protocol.py 中——通过生产应用(build_cors_app(),即运行时由 uvicorn 启动的同一应用)发送两个时代的真实请求,并包含负向测试:缺少 _meta 封装、路由标头不匹配,以及在现代连接上发送 initialize。
2026-07-28 对本服务的实际含义
- 没有会话,也没有
initialize——因此握手结果中没有serverInfo。服务通过server/discover和每个响应携带的io.modelcontextprotocol/serverInfo_meta标记来介绍自身。名称、标题、描述、网站和版本均来自MCPServer构造函数;版本取自软件包元数据,绝不使用字面值。缺少该版本时,服务会报告version: "",无状态客户端便无法区分不同发行版。 - 路由标头。
Mcp-Method、Mcp-Name和MCP-Protocol-Version必须与请求正文一致,否则请求会以-32020被拒绝。因此这些标头会出现在CORS_ALLOW_HEADERS中——浏览器可能不会发送它们;遇到这种情况时,请求会被拒绝,而不是获得响应。 - 日志记录需要逐请求主动选择(SEP-2577)。能力声明已移除;没有保留的
io.modelcontextprotocol/logLevel_meta键时,服务不会发送任何内容。使用logLevel: "warning"时,响应会切换为text/event-stream并携带日志条目。两个方向都会进行测量。 - 新鲜度提示(SEP-2549):列表方法会携带
ttlMs和cacheScope——见CACHE_HINTS。
请注意,SDK 的 LATEST_PROTOCOL_VERSION 是现代协议时代的别名,而非握手协议时代的别名——仅依据它进行固定,会让当前客户端实际协商使用的协议时代处于不受约束的状态。
更新策略。 门禁检查失败时,不要盲目修改常量:应阅读两个修订版本之间的规范变更日志,确认服务行为仍然正常,然后一并更新常量、本节、README.de.md 和
CHANGELOG.md。
- 工具定义稳定性(审计 SEC-022): 任何对工具名称、描述或参数的更改都会改变
tool-snapshot.json;CI 会失败,直到重新生成快照,并添加CHANGELOG条目和版本升级。 - 更新策略: 每月审查 Dependabot PR;任何工具定义或行为变更都要升级版本(semver)。
生命周期阶段
此服务处于阶段 1(只读)——所有工具均为只读,不进行身份验证,也没有副作用。阶段模型以及阶段 2(写入/身份验证)的前置条件见
docs/roadmap.md。安全架构(SSRF/出站流量、密钥管理、致命三角评估):docs/security.md。
扩缩容/会话策略:docs/scaling.md。
已知限制
- 通过 LINDAS 获取水文数据:
env_hydro_current、env_hydro_stations和env_flood_warnings会查询 BAFU LINDAS SPARQL 端点(带类型的实时值:水位、流量、水温、危险等级)。LINDAS 仅保存当前值(每个站点一条观测记录),不是历史时间序列。参见docs/probe-lindas-hydro.md。 - 历史水文数据 /
env_hydro_history(BUG-01 已解决):旧版hydrodaten.admin.ch/lhg/az/*REST 端点(每小时 CSV、warnings.json、站点 JSON)已停用(404)。env_flood_warnings现在改用 LINDAS 的dangerLevel。真实的历史时间序列(每日数据 / 长期平均值,例如2024 年夏季与长期平均值的对比)无法通过 API 免费获取;必须向 BAFU 水文咨询服务订购([email protected])。env_hydro_history会返回最新的 LINDAS 值以及获取这些数据的途径。 - 洪水警报:
env_flood_warnings会读取 LINDAS 的dangerLevel。LINDAS 不提供州代码,因此不支持按州筛选,响应始终覆盖全国;如果请求中提供了canton值,响应会原样返回并标记该筛选未应用——JSON 信封中会通过match_type: "fuzzy"和说明标记,Markdown 中则会在表格上方显示警告行。完全没有警报时尤其需要注意:若请求中包含某个州的信息,“当前无有效警报”可能会被误解为该州已解除警报。 - 水文测站 / 按州筛选:
env_hydro_stations不再支持canton。唯一提供州代码的数据源——hydrodaten.admin.ch/lhg/az/json/mobile_stations.json——已停用(404),而 LINDAS 没有州属性。设置了canton的请求会返回说明,而非测站列表;请使用water_body,或不加筛选地获取完整列表(233 个测站)。 - 沐浴水质(
env_bathing_water):读取 LINDAS 数据立方体foen/ubd01041prod——这是唯一具有真实多年时间序列的水文数据立方体(自 2020 年起的季节性采样数据)。数据在每年沐浴季结束后更新(不提供实时监测),调查仅覆盖官方上报的沐浴地点(许多热门露天泳场不在调查范围内)。许可信息在图/数据集中声明,而非数据立方体中;因此每个响应都会包含明确的许可字段,如果没有许可信息,则会如实注明“未声明”。参见docs/probe-lindas-hydro.md(补充说明 N1–N7)。 - LINDAS 中没有地下水数据:已于 2026-07-24 通过多语言数据立方体搜索验证——LINDAS 没有地下水数据立方体(无法通过 SPARQL 获取 NAQUA 地下水位)。
- NABEL:仅提供近实时数据;此服务不提供历史时间序列。
- 自然灾害(
env_hazard_overview/env_hazard_regions):原有的naturgefahren.ch/api/v1/warnings/*REST 端点已于 2026 年停用;截至 2026-07-26 的验证结果表明,没有稳定且有文档说明的公共 JSON 警报汇总源(已检查 MeteoSwiss OGD/STAC、opendata.swiss 以及未公开文档的应用 API)。为避免不可靠的网页抓取,这两个工具现在是无网络的指引/路由工具:会以确定性的方式指向此服务中专用的实时工具(洪水→env_flood_warnings、雪崩→env_avalanche_bulletin、野火→env_wildfire_danger、积雪→env_snow_current)以及官方门户。汇总的天气警报(风暴/雷暴/高温)属于 MeteoSwiss 的职责范围,应由meteoswiss-mcp提供。参见docs/probe-naturgefahren-hazards.md。 - 野火危险等级(
env_wildfire_danger):waldbrandgefahr.ch于 2026 年以 Rails/React 应用取代其 REST API;目前没有稳定的 JSON 端点。当前危险等级通过两步式、由 HTML 承载的约定读取:首页的data-react-props会提供一个已签名的 ActiveStorage Blob URL(warnMapJsonPath)以及州映射,随后再获取该 URL 的内容。如果该结构发生变化,模式保护机制会优雅降级。未筛选的结果最多显示 40 个区域(按危险等级从高到低排列);若要获取某州的完整列表,请按canton筛选。参见docs/probe-naturgefahren-waldbrand.md。 - 狩猎统计(
env_hunting_stats):jagdstatistik.ch后端没有文档说明(这是一个根据内容协商返回数据的 Web 应用端点)。如果结构发生变化,模式保护机制会优雅降级。物种/州/数据类型查询信息已嵌入(采集于 2026-07-19);2015–2024 年的数值会实时获取。许可情况(调查于 2026-07-19):数据归 BAFU 所有(汇总自各州办事处;网站技术由 Wildtier Schweiz 提供),且未作为带许可的数据集发布在 opendata.swiss 上;数据源未声明明确许可。因此,响应必须注明数据来源为 BAFU;仍在等待 BAFU 正式确认许可。参见docs/probe-jagdstatistik.md。 - 道路和铁路噪声不在范围内(
ch.bafu.laerm-*、ch.bav.laermbelastung-*):已于 2026-07-28 验证。BAFU 道路噪声图层ch.bafu.laerm-strassenlaerm_tag/_nacht对相同的identify请求返回 HTTP 400——它们是纯栅格服务(type: wmts、tooltip: false),无法查询属性,因此从技术上讲不可能按点查询。铁路噪声的情况不同:ch.bav.laermbelastung-eisenbahn_*确实会返回 HTTP 200 和真实属性(de_es、de_pointofdetermination),因此可以查询,但有意未接入——此服务的工具预算已用尽,共 21 个;而铁路噪声需要单独设计时段/属性模型。记忆口诀:航空器噪声有线条,道路噪声只有像素——铁路噪声有数据,但这是有意省略的。参见docs/probe-fluglaerm.md。 - 航空器噪声是截止日期固定的地籍数据,而非实时服务(
env_noise_*):validfrom的日期范围从 01.03.2009(CDB Genève)到 16.04.2024(LBK St. Gallen-Altenrhein);各机场单独更新,且不另行通知。因此,source_freshness从不声称数据是“实时”的,而是记录实际匹配到的登记数据的validfrom。覆盖范围仅限机场周边;瑞士大部分地区根本没有噪声地籍数据,工具会明确报告这一点,而非返回空列表。小半径查询没有命中时,存在歧义(可能位于所有地籍数据的覆盖范围之外,也可能位于最内侧等值线内——在 Kloten 跑道上,半径为 100 m 时这两种情况看起来相同),因此工具会使用更大的半径再查询一次,以区分no_cadastre和wide_area_only。 - LSV 限值检查不包括军用机场:《噪声防治条例》附录 5 明确适用于民用机场。军用机场适用附录 8;由于尚未核实相关规定,
env_noise_limits_check会拒绝对period="military"进行检查,并指明正确的依据,而不会套用看似合理、实则错误的表格。
职责矩阵 — 水体、积雪与降水(与 meteoswiss-mcp 的职责划分)
为避免在整个项目组合中重复提供水体、积雪和降水数据,职责划分如下:meteoswiss-mcp 负责大气降水和天气;swiss-environment-mcp 负责地表水体(BAFU 领域:流量、水位、水温、沐浴水质)、地面积雪和雪崩危险。经核对实际 LINDAS 数据立方体维度(2026-07-24):测量量没有重叠。
| 数据 | swiss-environment-mcp(BAFU / SLF) | meteoswiss-mcp(MeteoSwiss) |
|---|---|---|
| 流量(m³/s) | ✅ env_hydro_current(LINDAS hydro/river) | ❌ |
| 水位(m a.s.l.) | ✅ env_hydro_current(LINDAS hydro/river + lake) | ❌ |
| 水温(°C) | ✅ env_hydro_current | ❌(测量空气温度) |
| 沐浴水质(E.coli 等) | ✅ env_bathing_water(LINDAS ubd0104) | ❌ |
地面积雪深度(HS) | ✅ env_snow_current(SLF IMIS) | ❌ |
24 小时新雪量(HN_1D) | ✅ env_snow_current(SLF IMIS) | ❌ |
| 雪崩危险等级 | ✅ env_avalanche_bulletin(SLF,EAWS 1–5) | ❌ |
| 作为当前天气状况的降雪 | ❌ | ✅ meteo_current / meteo_forecast(天气代码) |
| 降水量(mm):测量网络、预报、气候常年值 | ❌ | ✅ meteo_current / meteo_forecast / meteo_climate_normals |
| SLF IMIS 山区站点的降水 | ✅ 仅作为雪盖背景信息,没有独立的降水工具 | (MeteoSwiss 网络) |
| 天气预警(风暴、雷暴、酷热) | ❌ | ✅ meteo_warnings |
| 自然灾害预警(洪水、雪崩、野火) | ✅ env_flood_warnings、env_hazard_*、env_wildfire_danger | ❌ |
规则:所有水体内及水体上的数据(流量、水位、水温、沐浴水质)、地面上的积雪和雪崩危险均归 swiss-environment-mcp(BAFU/SLF)负责;大气降水(以 mm 表示的雨/降雪)以及天气、预报、预警和气候常年值均归 meteoswiss-mcp 负责。SLF IMIS 降水端点(RR_10MIN_SUM)有意不接入为工具,因此不会与 MeteoSwiss 重复。积雪/雪崩工具已上线(见 docs/probe-slf.md)。
TODO(不在此处范围内):在 meteoswiss-mcp README 中同步此矩阵——该仓库不属于本次更改范围。
测试
# Unit tests (no API keys or network required)
PYTHONPATH=src pytest tests/ -m "not live"
# Integration tests (requires live BAFU APIs)
PYTHONPATH=src pytest tests/ -m "live"
# Linting
ruff check src/
贡献
参见 CONTRIBUTING.md(英语)· CONTRIBUTING.de.md(德语)
安全
安全政策与安全态势:SECURITY.md(英语)· SECURITY.de.md(德语)。
完整安全架构:docs/security.md。
更新日志
参见 CHANGELOG.md
许可证
MIT 许可证 — 参见 LICENSE
源数据受 BAFU 使用条款约束。使用其数据时必须注明 BAFU。
作者
Hayal Oezkan · github.com/malkreide
致谢与相关项目
- 数据:BAFU / Bundesamt für Umwelt · hydrodaten.admin.ch · naturgefahren.ch · opendata.swiss
- 协议:Model Context Protocol – Anthropic / Linux Foundation
- 相关项目:
| 服务 | 描述 |
|---|---|
| zurich-opendata-mcp | 苏黎世市开放数据(OSTLUFT 空气质量、天气、停车和地理数据) |
| swiss-transport-mcp | 瑞士公共交通——OJP 2.0 行程规划、SIRI-SX 中断信息 |
| swiss-road-mobility-mcp | GBFS 共享出行、电动汽车充电、DATEX II 交通信息 |
| swiss-statistics-mcp | BFS STAT-TAB——682 个统计数据集 |
协同示例: “今天 Schulhaus Leutschenbach 的空气质量如何?与全国 NABEL 平均值相比如何?”
→ zurich-opendata-mcp(OSTLUFT,本地)+ swiss-environment-mcp(NABEL,全国)
安装
通过 uv 的 uvx 运行——无需克隆或手动安装。将其添加到 MCP 客户端配置中(Claude Desktop、Cursor 和 Windsurf 使用 mcpServers;VS Code 在 .vscode/mcp.json 中使用顶层 servers 键):
{
"mcpServers": {
"swiss-environment-mcp": {
"command": "uvx",
"args": [
"swiss-environment-mcp"
]
}
}
}
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。