关于 meteoswiss-mcp
meteoswiss-mcp 是一个 MCP 服务,提供来自 MeteoSwiss 数据源的瑞士天气观测、预报、气候常年值和官方预警,适用于学校活动安排、当地天气查询和气候比较。
主要功能
- 01气象站当前观测数据
- 02按地点或坐标查询预报
- 03户外活动适宜度检查
- 04选定气象站的气候常年值
- 05按地区查询官方天气预警
- 06按州筛选气象站列表
适用场景
- 01为学校运动会选择合适日期
- 02查询附近气象站的当前读数
- 03比较不同城市的月度气候常年值
- 04查询某州或邮政编码的有效预警
MCP 相关
通过 stdio 或 Streamable HTTP 向 MCP 客户端提供六种只读天气与气候工具。工具访问 MeteoSwiss 及相关公共数据源,查询观测、预报、常年值和预警。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
🌦️ meteoswiss-mcp
MeteoSwiss 瑞士天气和气候数据的 MCP 服务。
将 AI 模型连接到 SwissMetNet 测量网络(160 多个站点,每 10 分钟一次)、MeteoSwiss ICON-CH1/CH2-EPS 预报和 1991–2020 年气候平均值。属于 swiss-public-data-mcp 项目集。
🇩🇪 德语版
演示查询(示例)
How suitable is next Wednesday for the sports day at Leutschenbach school?
→ meteo_school_check(location="Zürich Oerlikon", activity="Sporttag") 根据 MeteoSwiss ICON 模型,为接下来一周的每一天返回 🟢/🟡/🔴 红绿灯指示。
与 swiss-environment-mcp 结合使用:
How were air quality and weather at Leutschenbach school yesterday?
→ meteo_current(station='REH') + env_nabel_current(station='ZUE') = 完整的环境概况。
→ 按受众查看更多用例 →
工具(6 个)
| 工具 | 描述 | 数据源 |
|---|---|---|
meteo_stations | 列出 SwissMetNet 站点(可按州筛选) | 内嵌 |
meteo_current | 某站点当前的 10 分钟观测数据 | BGDI STAC API |
meteo_forecast | 某地点或坐标未来 1–16 天的预报 | Open-Meteo / MeteoSwiss ICON |
meteo_school_check | 户外学校活动的 🟢/🟡/🔴 红绿灯指示 | Open-Meteo / MeteoSwiss ICON |
meteo_climate_normals | 1991–2020 年月度气候平均值 | 内嵌(KLO、SMA、BER、LUG、GVE) |
meteo_warnings | 当前有效的官方天气预警(风暴、雷暴、高温、森林火灾等)——全国范围、按州或按邮政编码查询 | MeteoSwiss App-API + opendata.swiss |
工具注解(MCP 提示)
所有工具都带有明确的 MCP 注解——这与客户端审批界面和大模型的安全决策有关。
| 工具 | readOnlyHint | destructiveHint | idempotentHint | openWorldHint |
|---|---|---|---|---|
meteo_stations | ✅ | ✗ | ✅ | ✗(精选列表) |
meteo_current | ✅ | ✗ | ✗(实时数据) | ✅(上游 STAC) |
meteo_forecast | ✅ | ✗ | ✗(实时数据) | ✅(上游 Open-Meteo) |
meteo_school_check | ✅ | ✗ | ✗(实时数据) | ✅(地理编码 + 预报) |
meteo_climate_normals | ✅ | ✗ | ✅ | ✗(内嵌的气候平均值) |
meteo_warnings | ✅ | ✗ | ✗(实时数据) | ✅(MeteoSwiss App-API) |
读取规则:全部 6 个工具都是 readOnly + non-destructive——该服务从根本上无法写入或删除任何内容。idempotentHint=False 表示工具返回的值会根据调用时间而有所不同。
MCP 协议版本
| 方面 | 值 |
|---|---|
| 已测试的规范版本 | 2024-11-05、2025-03-26、2025-06-18(通过 mcp[cli] SDK) |
| MCP SDK 版本 | 参见 pyproject.toml → mcp[cli]>=2.0.0,<3(来自 mcp.server.mcpserver 的 MCPServer API) |
| 更新策略 | Dependabot 会监控 mcp[cli];规范版本升级会在 CHANGELOG 中使用 "Tool Definition Changes" 标记记录 |
→ 完整路线图和更新策略:docs/roadmap.md
快速开始
Claude Desktop
{
"mcpServers": {
"meteoswiss": {
"command": "uvx",
"args": ["meteoswiss-mcp"]
}
}
}
Claude Desktop(本地开发)
{
"mcpServers": {
"meteoswiss": {
"command": "uv",
"args": ["run", "--directory", "/path/to/meteoswiss-mcp", "meteoswiss-mcp"]
}
}
}
Cloud / Render.com(Streamable HTTP)
通过 ENV 变量配置(CLI 标志 --http / --port N 仍可用作覆盖项):
| 变量 | 默认值 | 含义 |
|---|---|---|
MCP_TRANSPORT | stdio | stdio 或 streamable-http |
MCP_HOST | 127.0.0.1 | 绑定地址 — 本地绝不能更改 |
MCP_PORT | 8000 | 端口 |
MCP_ALLOW_ANY_HOST | unset | 必须设为 1 才能允许服务绑定到 0.0.0.0(仅限容器/云环境) |
MCP_LOG_LEVEL | INFO | DEBUG / INFO / WARNING / ERROR — 在 stderr 上输出结构化 JSON 日志 |
MCP_ALLOWED_ORIGINS | unset | 允许的 CORS 来源列表,以逗号分隔。为空 = 禁用 CORS(仅同源)。自动公开 Mcp-Session-Id。 |
MCP_API_KEY | unset | 如果已设置:除 /health 外的每个请求都需要 X-API-Key: <key> 或 Authorization: Bearer <key>。使用恒定时间比较。 |
MCP_STATELESS_HTTP | 0 | 设为 1 可启用 SDK 的无状态模式 → 每个 HTTP 请求都会打开一个新会话。无粘性会话的多副本部署前提(SCALE-002/003)。 |
OTEL_EXPORTER_OTLP_ENDPOINT | unset | 如果已设置且已运行 pip install meteoswiss-mcp[otel]:每次工具调用的 OpenTelemetry spans 和自动 httpx 插桩数据都会以 OTLP-HTTP 形式发送到收集器。 |
OTEL_SERVICE_NAME | meteoswiss_mcp | OTel 资源中的服务名称 |
MCP_CACHE_ENABLED | 1 | 设为 0 可完全禁用 TTL 缓存(例如用于端到端测试) |
MCP_CACHE_TTL_STAC | 300 | STAC SMN 观测数据的 TTL,单位为秒(默认 5 分钟) |
MCP_CACHE_TTL_OPEN_METEO | 600 | ICON 预报的 TTL(默认 10 分钟) |
MCP_CACHE_TTL_GEOCODING | 3600 | 地理编码查询的 TTL(默认 1 小时) |
MCP_CACHE_TTL_OPENDATA | 3600 | opendata.swiss 目录的 TTL(默认 1 小时) |
MCP_CACHE_TTL_WARNINGS | 300 | 警报的 TTL(MeteoSwiss App-API / 结构化覆盖;默认 5 分钟) |
MCP_CLIMATE_NORMALS_PATH | unset | 包含额外气候常年的 JSON 文件路径 — 参见 data/climate-normals.example.json |
MCP_WARNINGS_API_URL | unset | 默认 MeteoSwiss App-API 来源的覆盖项:结构化 MeteoSwiss 警报 API 的 URL(例如未来的 OGD 警报 REST 端点)。主机必须在出口允许列表中。兼容不同架构(GeoJSON features、warnings 数组或 items)。未设置 → 实时 App-API。 |
MCP_CLIMATE_NORMALS_URL_TEMPLATE | unset | 用于运行时查询气候常年的 URL 模板(适用于没有嵌入值或 JSON 值的站点)。标记:{station}(小写)、{STATION}(大写)、{param}(MeteoSwiss 代码 tre200m0/rre150m0/sre000m0)。示例:https://data.geo.admin.ch/.../{station}/{param}.txt。主机必须在出口允许列表中。 |
# Local test (safe, loopback only)
MCP_TRANSPORT=streamable-http meteoswiss-mcp
# Container / Render
MCP_TRANSPORT=streamable-http MCP_HOST=0.0.0.0 MCP_ALLOW_ANY_HOST=1 meteoswiss-mcp
Docker / Render
仓库包含一个可用于生产环境的多阶段 Dockerfile(非 root 用户、HEALTHCHECK)和一个 render.yaml 蓝图:
# Build + test locally
docker build -t meteoswiss-mcp .
docker run --rm -p 8000:8000 meteoswiss-mcp
curl http://127.0.0.1:8000/health # → {"status":"ok","service":"meteoswiss-mcp"}
在 Render 上:“New → Blueprint” → 选择仓库。默认设置(plan starter、法兰克福、单实例)已在 render.yaml 中配置。
**重要:**特意设置了 numInstances: 1 — 多副本的粘性会话路由(审计 SCALE-002/003)尚未实现。
结构化日志
所有工具调用、上游故障和出口拦截都会作为 JSON 事件输出到 stderr(兼容 stdio 传输)。示例:
{"tool": "meteo_forecast", "days": 7, "has_coords": false, "event": "tool_invoked", "level": "info", "timestamp": "2026-05-20T07:00:00Z"}
{"tool": "meteo_forecast", "endpoint": "geocoding", "error_type": "HTTPStatusError", "event": "upstream_failed", "level": "warning", "timestamp": "..."}
{"url": "https://evil.example.com/", "method": "GET", "reason": "host not in allow-list", "event": "egress_blocked", "level": "warning", "timestamp": "..."}
HTTP 模式安全性
MCP_HOST有意默认设为127.0.0.1,以避免在开发笔记本电脑上使用--http时意外暴露到本地子网(审计发现 SEC-016)。- 所有出站 HTTP 调用(包括跟随重定向)都会根据允许列表进行验证:
data.geo.admin.ch、api.open-meteo.com、geocoding-api.open-meteo.com、opendata.swiss。其他主机和 IP 字面量(尤其是169.254.169.254、RFC1918)都会被拒绝,并返回EgressBlocked(SEC-004 / SEC-021)。 - CORS:默认禁用(仅同源)。浏览器客户端(例如 claude.ai 网页版)需要设置
MCP_ALLOWED_ORIGINS=<csv>——随后Mcp-Session-Id标头会自动加入Access-Control-Expose-Headers(SDK-004)。 - API 密钥身份验证:默认禁用。在生产环境的 HTTP 配置中,务必设置
MCP_API_KEY=<random>——不带有效X-API-Key或Authorization: Bearer …的请求会被拒绝,并返回 401(SEC-009 / SEC-013)。/health仍保持开放,供容器健康探针使用。
示例:生产环境 HTTP 堆栈
# 32 bytes of randomness as the auth key
export MCP_API_KEY=$(python -c "import secrets; print(secrets.token_urlsafe(32))")
MCP_TRANSPORT=streamable-http \
MCP_HOST=0.0.0.0 \
MCP_ALLOW_ANY_HOST=1 \
MCP_ALLOWED_ORIGINS=https://app.example.com \
MCP_API_KEY="$MCP_API_KEY" \
meteoswiss-mcp
示例查询
学校规划
Which days next week are suitable for a sports day in Zürich?
→ meteo_school_check(location="Zürich", activity="Sporttag")
What will the weather be at Leutschenbach school on Friday?
→ meteo_forecast(location="Zürich Oerlikon", days=5)
Show me current readings from the nearest MeteoSwiss station to Zürich-Schwamendingen.
→ meteo_current(station="REH")
气候比较
How much rain normally falls in June in Zürich?
→ meteo_climate_normals(station="KLO")
Is Lugano really much sunnier than Zürich? Show me the annual values.
→ meteo_climate_normals(station="LUG") + meteo_climate_normals(station="SMA")
基础设施与环境
Are there currently any weather warnings for the canton of Zürich?
→ meteo_warnings(canton="ZH")
Show me a 10-day forecast for the Heerenschürli sports facility with hourly values.
→ meteo_forecast(location="Sportanlage Heerenschürli Zürich", days=10, hourly=True)
架构
Claude Desktop / AI agent
│
│ MCP (stdio / Streamable HTTP)
▼
meteoswiss-mcp (MCPServer)
│
├── meteo_stations ──────────────── [embedded: ~20 SMN stations]
│
├── meteo_current ───────────────── BGDI STAC API
│ data.geo.admin.ch/api/stac/v1
│ Collection: ch.meteoschweiz.ogd-smn
│
├── meteo_forecast ──────────────── Open-Meteo
├── meteo_school_check ──────────── api.open-meteo.com/v1/meteoswiss
│ (MeteoSwiss ICON-CH1/CH2-EPS, 1–2 km)
│
├── meteo_climate_normals ───────── [embedded: normals 1991–2020]
│
└── meteo_warnings ──────────────── app-prod-ws.meteoswiss-app.ch
(MeteoSwiss App-API) + opendata.swiss
数据源
| 来源 | URL | 许可证 |
|---|---|---|
| BGDI STAC API(MeteoSwiss OGD) | data.geo.admin.ch/api/stac/v1 | CC BY 4.0 |
| Open-Meteo(MeteoSwiss ICON) | api.open-meteo.com/v1/meteoswiss | CC BY 4.0 |
| Open-Meteo 地理编码 | geocoding-api.open-meteo.com | CC BY 4.0 |
| opendata.swiss CKAN | opendata.swiss/api/3/action | CC BY 4.0 |
| MeteoSwiss App-API(预警) | app-prod-ws.meteoswiss-app.ch/v1/plzDetail | CC BY 4.0 |
安全性与限制
| 方面 | 详情 |
|---|---|
| 访问权限 | 只读(所有工具均设有 readOnlyHint: true)——服务无法修改或删除任何数据 |
| 个人数据 | 不涉及个人数据——所有来源均为汇总的公开开放数据 |
| 速率限制 | 内置每次查询上限:每次 API 调用最多返回 50 条结果,超时时间为 30 秒 |
| 身份验证 | 无需 API 密钥——所有数据源均可公开访问 |
| 许可证 | 所有数据均采用 CC BY 4.0 许可(MeteoSwiss 开放政府数据) |
| 服务条款 | 受相应数据源的服务条款约束:MeteoSwiss OGD、Open-Meteo、opendata.swiss |
已知限制
| ID | 工具 | 说明 |
|---|---|---|
| BUG-01 | meteo_current | STAC 资源结构可能因站点而异;已实现回退到直接链接 |
| LIM-01 | meteo_climate_normals | 仅内置 5 个站点(KLO、SMA、BER、LUG、GVE);其余站点通过 opendata.swiss 链接获取 |
| LIM-02 | meteo_warnings | 实时预警来自 MeteoSwiss App-API(plzDetail)——公开且无需身份验证,但没有文档说明(移动应用后端,而非 OGD REST API)。目前没有全国范围的端点,因此全国视图会汇总每个州一个具有代表性的首府邮政编码(该邮政编码以外的区域预警可能会遗漏——可使用 plz/canton 缩小范围)。官方 OGD 预警 REST API 发布后,可通过 MCP_WARNINGS_API_URL 覆盖此接口。 |
| LIM-03 | meteo_current | 显示 UTC 时间的 10 分钟值;不会自动转换为当地时间 |
职责矩阵 — 雪与降水(与 swiss-environment-mcp 的划分)
为避免在整个产品组合中重复提供雪与降水数据,职责划分如下。meteoswiss-mcp 负责大气降水和天气;swiss-environment-mcp(SLF 领域)负责地面积雪和雪崩危险。
| 数据 | meteoswiss-mcp(MeteoSwiss) | swiss-environment-mcp(BAFU / SLF) |
|---|---|---|
| 降水量(mm):测量网络、预报、气候常值 | ✅ meteo_current / meteo_forecast / meteo_climate_normals | ❌ |
| 当前天气状况中的降雪 | ✅ meteo_current / meteo_forecast(天气代码) | ❌ |
| 天气预警(风暴、雷暴、高温) | ✅ meteo_warnings | ❌ |
地面积雪深度(HS) | ❌ | ✅ SLF IMIS / 研究样地 ¹ |
24 小时新雪量(HN_1D) | ❌ | ✅ SLF ¹ |
| 雪崩危险等级 | ❌ | ✅ SLF 雪崩公告 ¹ |
| 自然灾害预警(洪水、雪崩、野火) | ❌ | ✅ env_flood_warnings、env_hazard_*、env_wildfire_danger |
规则:大气降水(以 mm 表示的雨量/降雪量),以及天气、预报、预警和气候常值均归 meteoswiss-mcp 负责;地面积雪和雪崩危险则归 swiss-environment-mcp(SLF)负责。SLF IMIS 降水传感器在此仅用于提供雪层背景信息,不会作为降水工具公开,因此不会与 MeteoSwiss 重复。
¹ swiss-environment-mcp 中的 SLF/雪相关工具正在准备中(第一阶段实时探测已于 2026-07-19 完成,参见该仓库的 docs/probe-slf.md);现已确定职责划分,确保两个服务在实现后不会发生冲突。
产品组合协同效应
meteoswiss-mcp
│
├── swiss-environment-mcp Combine weather + air quality (NABEL)
│ "How were weather AND air at Leutschenbach school?"
│
└── zurich-opendata-mcp School locations → weather forecast
"Which schools in Zürich have sports-day weather?"
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 的升级不会悄然改变任一版本。线上也会对此进行测量:tests/test_spec_2026.py 会通过 main() 交给 uvicorn 的同一 ASGI 调用栈发送两个时期的真实请求:一个是不带握手且不带会话的 2026-07-28 工具调用,另一个是上限设为 2025-11-25 的 initialize 请求。
不使用已弃用的能力。 2026-07-28 弃用了日志记录、采样和根目录(SEP-2577)。服务不会调用其中任何一项:进行中的状态会通过 notifications/progress 发送(在两个时期中,任何发送 progressToken 的客户端都能收到),而失败信息则会直接写入工具结果。测试会确保源码中没有 ctx.info/ctx.warning 及类似调用。
请注意,SDK 的 LATEST_PROTOCOL_VERSION 是现代时期的别名,而不是握手时期的别名——仅针对它固定版本,会导致当前客户端实际协商使用的时期仍可悄然变动。
更新策略。 当检查未通过时,不要盲目修改常量:请阅读两个修订版本之间的规范变更日志,验证服务仍能正常运行,然后一并更新常量、本节、README.de.md 和 CHANGELOG.md。
测试
# Unit tests (no network)
PYTHONPATH=src pytest tests/ -m "not live" -v
# Live tests (real APIs) — also run daily at 05:17 UTC via
# .github/workflows/live-tests.yml, so a format change upstream
# surfaces even though the unit tests stay green.
PYTHONPATH=src pytest tests/ -m live -v
# Linting — install the local gates once with `pre-commit install`
# to run these (and the CI guards) before every commit.
ruff check src/ tests/ scripts/
ruff format --check src/ tests/ scripts/
开发
git clone https://github.com/malkreide/meteoswiss-mcp
cd meteoswiss-mcp
pip install -e ".[dev]"
MCP Inspector(本地测试)
PYTHONPATH=src npx @modelcontextprotocol/inspector python -m meteoswiss_mcp.server
贡献
安全
许可证
MIT License – 详见 LICENSE。
数据来源:MeteoSwiss 开放政府数据(CC BY 4.0)。 使用数据时,请注明:来源:MeteoSwiss。
作者
Hayal Oezkan · github.com/malkreide
相关服务
安装
通过 uv 的 uvx 运行,无需克隆或手动安装。将其添加到 MCP 客户端配置中(Claude Desktop、Cursor 和 Windsurf 使用 mcpServers;VS Code 在 .vscode/mcp.json 中使用顶层 servers 键):
{
"mcpServers": {
"meteoswiss-mcp": {
"command": "uvx",
"args": [
"meteoswiss-mcp"
]
}
}
}
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。