Skip to main content
ClaudeWave

MCP Server for Swiss weather & climate data – MeteoSwiss SwissMetNet, ICON forecasts, school planning

MCP ServersOfficial Registry0 stars0 forksPythonMITUpdated today
ClaudeWave Trust Score
87/100
Trusted
Passed
  • Open-source license (MIT)
  • Actively maintained (<30d)
  • Clear description
  • Topics declared
Last scanned: 6/11/2026
Install in Claude Code / Claude Desktop
Method: pip / Python · meteoswiss-mcp
Claude Code CLI
claude mcp add meteoswiss-mcp -- python -m meteoswiss-mcp
claude_desktop_config.json (Claude Desktop)
{
  "mcpServers": {
    "meteoswiss-mcp": {
      "command": "python",
      "args": ["-m", "meteoswiss-mcp"],
      "env": {
        "MCP_HOST": "<mcp_host>",
        "MCP_ALLOW_ANY_HOST": "<mcp_allow_any_host>",
        "MCP_API_KEY": "<mcp_api_key>"
      }
    }
  }
}
1. Run the command above in your terminal (Claude Code), or paste the JSON config into claude_desktop_config.json (Claude Desktop).
2. Replace any <placeholder> values with your API keys or paths.
3. Restart Claude. The MCP server and its tools appear automatically.
💡 Install first: pip install meteoswiss-mcp
Detected environment variables
MCP_HOSTMCP_ALLOW_ANY_HOSTMCP_API_KEY
Use cases

MCP Servers overview

# 🌦️ meteoswiss-mcp

[![CI](https://github.com/malkreide/meteoswiss-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/malkreide/meteoswiss-mcp/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/meteoswiss-mcp)](https://pypi.org/project/meteoswiss-mcp/)
[![Python](https://img.shields.io/pypi/pyversions/meteoswiss-mcp)](https://pypi.org/project/meteoswiss-mcp/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![swiss-public-data-mcp](https://img.shields.io/badge/portfolio-swiss--public--data--mcp-blue)](https://github.com/malkreide/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](https://github.com/malkreide/swiss-public-data-mcp) portfolio.

🇩🇪 [Deutsche Version](README.de.md)

---

## Demo query (anchor example)

<img src="assets/demo.png" width="720" alt="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](https://github.com/malkreide/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](EXAMPLES.md) →

---

## Tools (6)

| Tool | Description | Data source |
|------|-------------|-------------|
| `meteo_stations` | List SwissMetNet stations (filterable by canton) | Embedded |
| `meteo_current` | Current 10-min observations for a station | BGDI STAC API |
| `meteo_forecast` | 1–16 day forecast for a place or coordinates | Open-Meteo / MeteoSwiss ICON |
| `meteo_school_check` | 🟢/🟡/🔴 traffic light for outdoor school events | Open-Meteo / MeteoSwiss ICON |
| `meteo_climate_normals` | Monthly climate normals 1991–2020 | Embedded (KLO, SMA, BER, LUG, GVE) |
| `meteo_warnings` | Active official weather warnings (storm, thunderstorm, heat, forest fire, …) — nationwide, by canton, or by PLZ | MeteoSwiss App-API + opendata.swiss |

### Tool annotations (MCP hints)

All tools carry explicit [MCP annotations](https://modelcontextprotocol.io/specification/draft/server/tools#tool-annotations) — relevant for the client approval UI and for the LLM's safety decisions.

| Tool | `readOnlyHint` | `destructiveHint` | `idempotentHint` | `openWorldHint` |
|------|---|---|---|---|
| `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

| Aspect | Value |
|---|---|
| Tested spec versions | `2024-11-05`, `2025-03-26`, `2025-06-18` (via the `mcp[cli]` SDK) |
| FastMCP SDK version | see `pyproject.toml` → `mcp[cli]>=1.0.0` |
| Update policy | Dependabot watches `mcp[cli]`; spec bumps are documented in the CHANGELOG with a "Tool Definition Changes" marker |

→ Full roadmap & update strategy: [`docs/roadmap.md`](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):

| Variable | Default | Meaning |
|---|---|---|
| `MCP_TRANSPORT` | `stdio` | `stdio` or `streamable-http` |
| `MCP_HOST` | `127.0.0.1` | Bind address — **never change locally** |
| `MCP_PORT` | `8000` | Port |
| `MCP_ALLOW_ANY_HOST` | _unset_ | Must be set to `1` to allow the server to bind to `0.0.0.0` (containers/cloud only) |
| `MCP_LOG_LEVEL` | `INFO` | `DEBUG` / `INFO` / `WARNING` / `ERROR` — structured JSON logs on stderr |
| `MCP_ALLOWED_ORIGINS` | _unset_ | Comma-separated list of allowed origins for CORS. Empty = CORS disabled (same-origin only). `Mcp-Session-Id` is exposed automatically. |
| `MCP_API_KEY` | _unset_ | If set: every request except `/health` requires `X-API-Key: <key>` or `Authorization: Bearer <key>`. Constant-time comparison. |
| `MCP_STATELESS_HTTP` | `0` | `1` enables FastMCP stateless mode → each HTTP request opens a new session. Prerequisite for multi-replica deploys without sticky sessions (SCALE-002/003). |
| `OTEL_EXPORTER_OTLP_ENDPOINT` | _unset_ | If set + `pip install meteoswiss-mcp[otel]`: OpenTelemetry spans per tool call + automatic httpx instrumentation are sent as OTLP-HTTP to the collector. |
| `OTEL_SERVICE_NAME` | `meteoswiss_mcp` | Service name in the OTel resources |
| `MCP_CACHE_ENABLED` | `1` | `0` disables the TTL cache entirely (e.g. for end-to-end tests) |
| `MCP_CACHE_TTL_STAC` | `300` | TTL in seconds for STAC SMN observations (default 5 min) |
| `MCP_CACHE_TTL_OPEN_METEO` | `600` | TTL for ICON forecasts (default 10 min) |
| `MCP_CACHE_TTL_GEOCODING` | `3600` | TTL for geocoding lookups (default 1 h) |
| `MCP_CACHE_TTL_OPENDATA` | `3600` | TTL for the opendata.swiss catalogue (default 1 h) |
| `MCP_CACHE_TTL_WARNINGS` | `300` | TTL for warnings (MeteoSwiss App-API / structured override; default 5 min) |
| `MCP_CLIMATE_NORMALS_PATH` | _unset_ | Path to a JSON file with additional climate normals — see `data/climate-normals.example.json` |
| `MCP_WARNINGS_API_URL` | _unset_ | **Override** 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_TEMPLATE` | _unset_ | URL 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 / Render
MCP_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 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"}
```

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 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
```

---

## 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 Leutschen
claudeclimate-datafastmcpicon-modelllmmcpmcp-servermeteoswissmodel-context-protocolopen-government-dataopendatapythonswiss-open-dataswiss-public-data-mcpswissmetnetswitzerlandweatherweather-api

What people ask about meteoswiss-mcp

What is malkreide/meteoswiss-mcp?

+

malkreide/meteoswiss-mcp is mcp servers for the Claude AI ecosystem. MCP Server for Swiss weather & climate data – MeteoSwiss SwissMetNet, ICON forecasts, school planning It has 0 GitHub stars and was last updated today.

How do I install meteoswiss-mcp?

+

You can install meteoswiss-mcp by cloning the repository (https://github.com/malkreide/meteoswiss-mcp) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.

Is malkreide/meteoswiss-mcp safe to use?

+

Our security agent has analyzed malkreide/meteoswiss-mcp and assigned a Trust Score of 87/100 (tier: Trusted). See the full breakdown of passed checks and flags on this page.

Who maintains malkreide/meteoswiss-mcp?

+

malkreide/meteoswiss-mcp is maintained by malkreide. The last recorded GitHub activity is from today, with 1 open issues.

Are there alternatives to meteoswiss-mcp?

+

Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.

Deploy meteoswiss-mcp to your cloud

Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.

Maintain this repo? Add a badge to your README

Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.

Featured on ClaudeWave: malkreide/meteoswiss-mcp
[![Featured on ClaudeWave](https://claudewave.com/api/badge/malkreide-meteoswiss-mcp)](https://claudewave.com/repo/malkreide-meteoswiss-mcp)
<a href="https://claudewave.com/repo/malkreide-meteoswiss-mcp"><img src="https://claudewave.com/api/badge/malkreide-meteoswiss-mcp" alt="Featured on ClaudeWave: malkreide/meteoswiss-mcp" width="320" height="64" /></a>

More MCP Servers

meteoswiss-mcp alternatives