Meteoswiss Mcp

io.github.malkreide由 GitHub 帳號 malkreide 發布v0.7.0更新於 Oct 24, 2026

MeteoSwiss Open Data for weather, climate normals, warnings

已驗證STDIO僅桌面位置與生活資料與分析

概覽

AI 產生的概覽

讓助理取得瑞士天氣與氣候資料:測站觀測、ICON 預報、氣候常年值與官方警報。

可以做什麼
以六個唯讀工具包裝 MeteoSwiss 開放資料:meteo_stations 依邦列出 SwissMetNet 測站,meteo_current 回傳 10 分鐘觀測值,meteo_forecast 依地點或座標提供 1 至 16 天預報,meteo_school_check 為戶外學校活動給出綠/黃/紅適宜度,meteo_climate_normals 回傳 1991-2020 年月度氣候常年值,meteo_warnings 依全國、邦或郵遞區號回報生效中的官方警報。
適用情境
適合涉及瑞士天氣、預報、氣候比較或官方警報的問題,例如安排戶外活動或查詢某地天氣狀況。資料範圍限於瑞士及其資料來源。
執行需求
透過 stdio 在本機執行,通常以 uvx meteoswiss-mcp 啟動,因此需要 Python/uv 執行環境。不需要帳號或 API 金鑰,資料來源皆為公開資料。取得即時資料需要連線至所列上游主機。選用的 HTTP 模式會用到 MCP_TRANSPORT、MCP_HOST、MCP_PORT、MCP_API_KEY 等環境變數。
安裝前請注意
所有工具皆為唯讀且非破壞性,不會寫入或刪除資料。即時類工具在不同時間會回傳不同結果。HTTP 模式下伺服器預設只綁定回送位址;對外暴露需設定 MCP_ALLOW_ANY_HOST,正式環境還應設定 MCP_API_KEY,因為缺少有效 X-API-Key 或 Authorization Bearer 的請求會被拒絕。對外請求被限制在上游主機允許清單內。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Meteoswiss Mcp,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

🌦️ meteoswiss-mcp

[CI] [PyPI] [Python] [License: MIT] [swiss-public-data-mcp]

MCP server for Swiss weather and climate data from MeteoSwiss.

Connects AI models to the SwissMetNet measurement network (160+ stations, 10-minute interval), MeteoSwiss ICON-CH1/CH2-EPS forecasts and climate normals 1991–2020. Part of the swiss-public-data-mcp portfolio.

🇩🇪 Deutsche Version


Demo query (anchor example)

[Demo: Claude asks about sports-day suitability → meteo_school_check tool call → structured weather traffic-light response]
How suitable is next Wednesday for the sports day at Leutschenbach school?

→ meteo_school_check(location="Zürich Oerlikon", activity="Sporttag") returns a 🟢/🟡/🔴 traffic light for each day of the coming week — straight from the MeteoSwiss ICON model.

Combined with swiss-environment-mcp:

How were air quality and weather at Leutschenbach school yesterday?

→ meteo_current(station='REH') + env_nabel_current(station='ZUE') = a complete environmental picture. → More use cases by audience →


Tools (6)

ToolDescriptionData source
meteo_stationsList SwissMetNet stations (filterable by canton)Embedded
meteo_currentCurrent 10-min observations for a stationBGDI STAC API
meteo_forecast1–16 day forecast for a place or coordinatesOpen-Meteo / MeteoSwiss ICON
meteo_school_check🟢/🟡/🔴 traffic light for outdoor school eventsOpen-Meteo / MeteoSwiss ICON
meteo_climate_normalsMonthly climate normals 1991–2020Embedded (KLO, SMA, BER, LUG, GVE)
meteo_warningsActive official weather warnings (storm, thunderstorm, heat, forest fire, …) — nationwide, by canton, or by PLZMeteoSwiss App-API + opendata.swiss

Tool annotations (MCP hints)

All tools carry explicit MCP annotations — relevant for the client approval UI and for the LLM's safety decisions.

ToolreadOnlyHintdestructiveHintidempotentHintopenWorldHint
meteo_stations✅✗✅✗ (curated list)
meteo_current✅✗✗ (live data)✅ (upstream STAC)
meteo_forecast✅✗✗ (live data)✅ (upstream Open-Meteo)
meteo_school_check✅✗✗ (live data)✅ (geocoding + forecast)
meteo_climate_normals✅✗✅✗ (embedded normals)
meteo_warnings✅✗✗ (live data)✅ (MeteoSwiss App-API)

Read rules: all 6 tools are readOnly + non-destructive — the server fundamentally cannot write or delete anything. idempotentHint=False marks tools that return different values depending on when they are called.

MCP protocol version

AspectValue
Tested spec versions2024-11-05, 2025-03-26, 2025-06-18 (via the mcp[cli] SDK)
MCP SDK versionsee pyproject.toml → mcp[cli]>=2.0.0,<3 (the MCPServer API from mcp.server.mcpserver)
Update policyDependabot watches mcp[cli]; spec bumps are documented in the CHANGELOG with a "Tool Definition Changes" marker

→ Full roadmap & update strategy: docs/roadmap.md


Quick start

Claude Desktop

json
{  "mcpServers": {    "meteoswiss": {      "command": "uvx",      "args": ["meteoswiss-mcp"]    }  }}

Claude Desktop (local development)

json
{  "mcpServers": {    "meteoswiss": {      "command": "uv",      "args": ["run", "--directory", "/path/to/meteoswiss-mcp", "meteoswiss-mcp"]    }  }}

Cloud / Render.com (Streamable HTTP)

Configuration via ENV variables (the CLI flags --http / --port N still work as an override):

VariableDefaultMeaning
MCP_TRANSPORTstdiostdio or streamable-http
MCP_HOST127.0.0.1Bind address — never change locally
MCP_PORT8000Port
MCP_ALLOW_ANY_HOSTunsetMust be set to 1 to allow the server to bind to 0.0.0.0 (containers/cloud only)
MCP_LOG_LEVELINFODEBUG / INFO / WARNING / ERROR — structured JSON logs on stderr
MCP_ALLOWED_ORIGINSunsetComma-separated list of allowed origins for CORS. Empty = CORS disabled (same-origin only). Mcp-Session-Id is exposed automatically.
MCP_API_KEYunsetIf set: every request except /health requires X-API-Key: <key> or Authorization: Bearer <key>. Constant-time comparison.
MCP_STATELESS_HTTP01 enables the SDK's stateless mode → each HTTP request opens a new session. Prerequisite for multi-replica deploys without sticky sessions (SCALE-002/003).
OTEL_EXPORTER_OTLP_ENDPOINTunsetIf set + pip install meteoswiss-mcp[otel]: OpenTelemetry spans per tool call + automatic httpx instrumentation are sent as OTLP-HTTP to the collector.
OTEL_SERVICE_NAMEmeteoswiss_mcpService name in the OTel resources
MCP_CACHE_ENABLED10 disables the TTL cache entirely (e.g. for end-to-end tests)
MCP_CACHE_TTL_STAC300TTL in seconds for STAC SMN observations (default 5 min)
MCP_CACHE_TTL_OPEN_METEO600TTL for ICON forecasts (default 10 min)
MCP_CACHE_TTL_GEOCODING3600TTL for geocoding lookups (default 1 h)
MCP_CACHE_TTL_OPENDATA3600TTL for the opendata.swiss catalogue (default 1 h)
MCP_CACHE_TTL_WARNINGS300TTL for warnings (MeteoSwiss App-API / structured override; default 5 min)
MCP_CLIMATE_NORMALS_PATHunsetPath to a JSON file with additional climate normals — see data/climate-normals.example.json
MCP_WARNINGS_API_URLunsetOverride for the default MeteoSwiss App-API source: URL of a structured MeteoSwiss warnings API (e.g. the future OGD warnings REST endpoint). The host must be on the egress allow-list. Schema-tolerant (GeoJSON features, a warnings array or items). Unset → live App-API.
MCP_CLIMATE_NORMALS_URL_TEMPLATEunsetURL template for runtime lookup of climate normals (for stations without embedded or JSON values). Tokens: {station} (lowercase), {STATION} (uppercase), {param} (MeteoSwiss code tre200m0/rre150m0/sre000m0). Example: https://data.geo.admin.ch/.../{station}/{param}.txt. The host must be on the egress allow-list.
bash
# Local test (safe, loopback only)MCP_TRANSPORT=streamable-http meteoswiss-mcp
# Container / RenderMCP_TRANSPORT=streamable-http MCP_HOST=0.0.0.0 MCP_ALLOW_ANY_HOST=1 meteoswiss-mcp
Docker / Render

The repo includes a production-ready multi-stage Dockerfile (non-root user, HEALTHCHECK) and a render.yaml blueprint:

bash
# Build + test locallydocker build -t meteoswiss-mcp .docker run --rm -p 8000:8000 meteoswiss-mcpcurl http://127.0.0.1:8000/health   # → {"status":"ok","service":"meteoswiss-mcp"}

On Render: "New → Blueprint" → select the repo. Defaults (plan starter, Frankfurt, single instance) are set in render.yaml.

Important: numInstances: 1 is set deliberately — sticky-session routing for multi-replica (audit SCALE-002/003) is not yet implemented.

Structured logging

All tool invocations, upstream failures and egress blocks are emitted as JSON events on stderr (stdio-transport safe). Example:

json
{"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-mode security
  • MCP_HOST deliberately defaults to 127.0.0.1 so that --http on a dev laptop is not accidentally exposed to the local subnet (audit finding SEC-016).
  • All outgoing HTTP calls (including redirect follows) are validated against an allow-list: data.geo.admin.ch, api.open-meteo.com, geocoding-api.open-meteo.com, opendata.swiss. Other hosts and IP literals (in particular 169.254.169.254, RFC1918) are rejected with EgressBlocked (SEC-004 / SEC-021).
  • CORS: disabled by default (same-origin only). Browser clients (e.g. claude.ai web) need MCP_ALLOWED_ORIGINS=<csv> — the Mcp-Session-Id header is then automatically in Access-Control-Expose-Headers (SDK-004).
  • API-key auth: disabled by default. In a production HTTP setup, always set MCP_API_KEY=<random> — requests without a valid X-API-Key or Authorization: Bearer … are rejected with 401 (SEC-009 / SEC-013). /health stays open for container health probes.
Example: production HTTP stack
bash
# 32 bytes of randomness as the auth keyexport 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

Example queries

School planning

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")

Climate comparison

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")

Infrastructure & environment

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)

Architecture

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

Data sources

SourceURLLicense
BGDI STAC API (MeteoSwiss OGD)data.geo.admin.ch/api/stac/v1CC BY 4.0
Open-Meteo (MeteoSwiss ICON)api.open-meteo.com/v1/meteoswissCC BY 4.0
Open-Meteo Geocodinggeocoding-api.open-meteo.comCC BY 4.0
opendata.swiss CKANopendata.swiss/api/3/actionCC BY 4.0
MeteoSwiss App-API (warnings)app-prod-ws.meteoswiss-app.ch/v1/plzDetailCC BY 4.0

Safety & limits

AspectDetails
AccessRead-only (readOnlyHint: true on all tools) — the server cannot modify or delete any data
Personal dataNo personal data — all sources are aggregated, publicly available open data
Rate limitsBuilt-in per-query caps: max 50 results per API call, 30 s timeout
AuthenticationNo API keys required — all data sources are publicly accessible
LicensesAll data under CC BY 4.0 (MeteoSwiss Open Government Data)
Terms of ServiceSubject to the ToS of the respective data sources: MeteoSwiss OGD, Open-Meteo, opendata.swiss

Known limitations

IDToolDescription
BUG-01meteo_currentSTAC asset structure can vary per station; fallback to a direct link is implemented
LIM-01meteo_climate_normalsOnly 5 stations embedded (KLO, SMA, BER, LUG, GVE); the rest via an opendata.swiss link
LIM-02meteo_warningsLive warnings come from the MeteoSwiss App-API (plzDetail) — public and unauthenticated, but undocumented (mobile-app backend, not the OGD REST API). There is no nationwide endpoint, so the countrywide view aggregates one representative capital PLZ per canton (sub-regional warnings outside that PLZ may be missed — narrow with plz/canton). MCP_WARNINGS_API_URL overrides it once the official OGD warnings REST API ships.
LIM-03meteo_currentShows 10-min values in UTC; no automatic conversion to local time

Responsibility matrix — snow & precipitation (delineation vs. swiss-environment-mcp)

To avoid duplicating snow and precipitation data across the portfolio, responsibilities are split as follows. meteoswiss-mcp owns atmospheric precipitation and weather; swiss-environment-mcp (SLF domain) owns snow on the ground and avalanche danger.

Datameteoswiss-mcp (MeteoSwiss)swiss-environment-mcp (BAFU / SLF)
Precipitation amount (mm): measurement network, forecast, climate normals✅ meteo_current / meteo_forecast / meteo_climate_normals❌
Snowfall as a current weather condition✅ meteo_current / meteo_forecast (weather code)❌
Weather warnings (storm, thunderstorm, heat)✅ meteo_warnings❌
Snow depth on the ground (HS)❌✅ SLF IMIS / study-plot ¹
Fresh snow 24 h (HN_1D)❌✅ SLF ¹
Avalanche danger level❌✅ SLF avalanche bulletin ¹
Natural-hazard warnings (flood, avalanche, wildfire)❌✅ env_flood_warnings, env_hazard_*, env_wildfire_danger

Rule: atmospheric precipitation (rain/snowfall as mm) plus weather, forecast, warnings and climate normals belong to meteoswiss-mcp; snow on the ground and avalanche danger belong to swiss-environment-mcp (SLF). The SLF IMIS precipitation sensor is used there only as context for the snowpack and is never exposed as a precipitation tool, so it does not duplicate MeteoSwiss.

¹ SLF/snow tools in swiss-environment-mcp are in preparation (Phase-1 live-probe completed 2026-07-19, see that repo's docs/probe-slf.md); the demarcation is fixed now so the two servers do not collide once implemented.


Portfolio synergies

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 Protocol Version

This server speaks two protocol eras over the same endpoint. The client's first request on a connection decides which one applies; a later claim from the other era is refused.

EraRevisionWho reaches it
initialize handshake2024-11-05 … 2025-11-25What today's clients speak. The server answers with the revision asked for, or with the 2025-11-25 ceiling when the request asks for something newer.
Per-request envelope2026-07-28A request carrying the 2026-07-28 _meta envelope opens a modern connection.

Both revisions are pinned in tests/test_protocol_version.py and asserted against the installed SDK, so a Dependabot bump of mcp cannot move either one silently. It is also measured on the wire: tests/test_spec_2026.py sends real requests of both eras through the same ASGI stack main() hands to uvicorn — a 2026-07-28 tool call with no handshake and no session, and an initialize that is capped at 2025-11-25.

No deprecated capability. 2026-07-28 deprecates logging, sampling and roots (SEP-2577). The server calls none of them: in-flight status goes out as notifications/progress (reaching any client that sends a progressToken, in both eras), and failures are stated in the tool result itself. A test keeps the source free of ctx.info/ctx.warning and friends.

Note that the SDK's LATEST_PROTOCOL_VERSION is an alias for the modern era, not for the handshake era — pinning against it alone would leave the era that current clients actually negotiate free to drift.

Update policy. When the gate fails, do not edit the constant blindly: read the spec changelog between the two revisions, verify the server still behaves, then move the constant, this section, README.de.md and CHANGELOG.md together.


Testing

bash
# 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/

Development

bash
git clone https://github.com/malkreide/meteoswiss-mcpcd meteoswiss-mcppip install -e ".[dev]"

MCP Inspector (local test)

bash
PYTHONPATH=src npx @modelcontextprotocol/inspector python -m meteoswiss_mcp.server

Contributing

See the contributing guidelines (Deutsch).


Security

See the security policy (Deutsch) for the security posture and how to report a vulnerability.


License

MIT License – see LICENSE.

Source data: MeteoSwiss Open Government Data (CC BY 4.0). When using the data, cite: Source: MeteoSwiss.


Author

Hayal Oezkan · github.com/malkreide


Related servers

[swiss-environment-mcp] [zurich-opendata-mcp] [swiss-transport-mcp]

Installation

Run via uv's uvx — no clone or manual install needed. Add to your MCP client config (mcpServers for Claude Desktop, Cursor and Windsurf; use a top-level servers key for VS Code in .vscode/mcp.json):

json
{  "mcpServers": {    "meteoswiss-mcp": {      "command": "uvx",      "args": [        "meteoswiss-mcp"      ]    }  }}

來源:README.md,提交 19aca71

工具

0
SourceWeft 尚未在沙箱中啟動過該軟體包,因此其工具未知。

版本歷史

2
  1. v0.7.0最新Sep 27, 2026
  2. v0.6.1Sep 16, 2026

評分

已滿足適用檢查項的 50%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分

    請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。

  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具15 分

    請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。

  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分