meteoswiss-mcp
This server provides access to Swiss weather and climate data from MeteoSwiss, enabling AI agents to query real-time observations, forecasts, climate normals, and weather warnings.
List weather stations: Browse the SwissMetNet (SMN) measurement station list, filterable by canton, to find station codes for use with other tools.
Get current observations: Retrieve live 10-minute interval weather readings (temperature, precipitation, sunshine, wind, humidity, pressure) for any SwissMetNet station.
Get weather forecasts: Fetch 1β16 day forecasts for any location (by name or coordinates) using the MeteoSwiss ICON-CH1/CH2-EPS model, with optional hourly breakdown.
Check suitability for outdoor school events: Get a π’/π‘/π΄ traffic-light assessment for outdoor activities (e.g., sports days, field trips) based on temperature, precipitation, wind, and UV thresholds β for the next 7 days or a specific date.
Retrieve climate normals: Access monthly 30-year climate averages (1991β2020) for temperature, precipitation, and sunshine hours at key Swiss stations.
Check weather warnings: Retrieve current MeteoSwiss weather warnings (storms, heavy rain, thunder, snow, heat, frost, etc.) with official warning maps and MeteoAlarm links, filterable by canton.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@meteoswiss-mcpWhat's the current weather in Zurich?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
π¦οΈ meteoswiss-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)
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 β
Related MCP server: Open-Meteo MCP Server
Tools (6)
Tool | Description | Data source |
| List SwissMetNet stations (filterable by canton) | Embedded |
| Current 10-min observations for a station | BGDI STAC API |
| 1β16 day forecast for a place or coordinates | Open-Meteo / MeteoSwiss ICON |
| π’/π‘/π΄ traffic light for outdoor school events | Open-Meteo / MeteoSwiss ICON |
| Monthly climate normals 1991β2020 | Embedded (KLO, SMA, BER, LUG, GVE) |
| Current weather warnings & links | opendata.swiss + links |
Tool annotations (MCP hints)
All tools carry explicit MCP annotations β relevant for the client approval UI and for the LLM's safety decisions.
Tool |
|
|
|
|
| β | β | β | β (curated list) |
| β | β | β (live data) | β (upstream STAC) |
| β | β | β (live data) | β (upstream Open-Meteo) |
| β | β | β (live data) | β (geocoding + forecast) |
| β | β | β | β (embedded normals) |
| β | β | β (live data) | β (opendata.swiss) |
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 |
|
FastMCP SDK version | see |
Update policy | Dependabot watches |
β Full roadmap & update strategy: docs/roadmap.md
Quick start
Claude Desktop
{
"mcpServers": {
"meteoswiss": {
"command": "uvx",
"args": ["meteoswiss-mcp"]
}
}
}Claude Desktop (local development)
{
"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 |
|
|
|
|
| Bind address β never change locally |
|
| Port |
| unset | Must be set to |
|
|
|
| unset | Comma-separated list of allowed origins for CORS. Empty = CORS disabled (same-origin only). |
| unset | If set: every request except |
|
|
|
| unset | If set + |
|
| Service name in the OTel resources |
|
|
|
|
| TTL in seconds for STAC SMN observations (default 5 min) |
|
| TTL for ICON forecasts (default 10 min) |
|
| TTL for geocoding lookups (default 1 h) |
|
| TTL for the opendata.swiss catalogue (default 1 h) |
|
| TTL for the structured warnings API (default 5 min) |
| unset | Path to a JSON file with additional climate normals β see |
| unset | URL of a structured MeteoSwiss warnings API. The host must be on the egress allow-list. Schema-tolerant (GeoJSON |
| unset | URL template for runtime lookup of climate normals (for stations without embedded or JSON values). Tokens: |
# 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-mcpDocker / Render
The repo includes a production-ready multi-stage Dockerfile (non-root user, HEALTHCHECK) and a render.yaml blueprint:
# 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:
{"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_HOSTdeliberately defaults to127.0.0.1so that--httpon 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 particular169.254.169.254, RFC1918) are rejected withEgressBlocked(SEC-004 / SEC-021).CORS: disabled by default (same-origin only). Browser clients (e.g. claude.ai web) need
MCP_ALLOWED_ORIGINS=<csv>β theMcp-Session-Idheader is then automatically inAccess-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 validX-API-KeyorAuthorization: Bearer β¦are rejected with 401 (SEC-009 / SEC-013)./healthstays open for container health probes.
Example: production HTTP stack
# 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-mcpExample 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 (FastMCP)
β
βββ 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 ββββββββββββββββ opendata.swiss CKAN + linksData sources
Source | URL | License |
BGDI STAC API (MeteoSwiss OGD) |
| CC BY 4.0 |
Open-Meteo (MeteoSwiss ICON) |
| CC BY 4.0 |
Open-Meteo Geocoding |
| CC BY 4.0 |
opendata.swiss CKAN |
| CC BY 4.0 |
Safety & limits
Aspect | Details |
Access | Read-only ( |
Personal data | No personal data β all sources are aggregated, publicly available open data |
Rate limits | Built-in per-query caps: max 50 results per API call, 30 s timeout |
Authentication | No API keys required β all data sources are publicly accessible |
Licenses | All data under CC BY 4.0 (MeteoSwiss Open Government Data) |
Terms of Service | Subject to the ToS of the respective data sources: MeteoSwiss OGD, Open-Meteo, opendata.swiss |
Known limitations
ID | Tool | Description |
BUG-01 |
| STAC asset structure can vary per station; fallback to a direct link is implemented |
LIM-01 |
| Only 5 stations embedded (KLO, SMA, BER, LUG, GVE); the rest via an opendata.swiss link |
LIM-02 |
| A direct warnings REST API is planned from Q2 2026 (MeteoSwiss OGD phase 2); currently links + CAP |
LIM-03 |
| Shows 10-min values in UTC; no automatic conversion to local time |
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?"Testing
# Unit tests (no network)
PYTHONPATH=src pytest tests/ -m "not live" -v
# Live tests (real APIs)
PYTHONPATH=src pytest tests/ -m live -v
# Linting
ruff check src/ tests/Development
git clone https://github.com/malkreide/meteoswiss-mcp
cd meteoswiss-mcp
pip install -e ".[dev]"MCP Inspector (local test)
PYTHONPATH=src npx @modelcontextprotocol/inspector python -m meteoswiss_mcp.serverContributing & Security
License
MIT License β see LICENSE.
Source data: MeteoSwiss Open Government Data (CC BY 4.0). When using the data, cite: Source: MeteoSwiss.
Related servers
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):
{
"mcpServers": {
"meteoswiss-mcp": {
"command": "uvx",
"args": [
"meteoswiss-mcp"
]
}
}
}Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/malkreide/meteoswiss-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server