Skip to main content

MCP Server für Schweizer Umweltdaten des BAFU – Luft, Wasser, Naturgefahren und Umweltindikatoren

Project description

🇨🇭 Part of the Swiss Public Data MCP Portfolio

🌿 swiss-environment-mcp

Version License: MIT Python 3.11+ MCP CI Data Source

MCP server connecting AI models to Swiss environmental data from BAFU – air quality, hydrology, natural hazards, wildfire danger and open environmental datasets.

🇩🇪 Deutsche Version

Demo: Claude queries NABEL air quality via a swiss-environment-mcp tool call and gets a WHO 2021 compliance check


Overview

swiss-environment-mcp gives AI assistants like Claude direct access to real-time environmental data from Swiss federal authorities – no API keys required. Air quality readings from the national NABEL monitoring network, hydrological gauging stations, natural hazard bulletins, and the full BAFU dataset catalogue are all accessible through a single standardised MCP interface.

The server covers four thematic clusters: air quality (NABEL), hydrology, natural hazards, and the BAFU open data catalogue. Each cluster maps to a group of purpose-built tools that translate raw agency data into clean JSON responses.

Anchor demo query: "What is the current air quality at the NABEL station Zürich-Kaserne – and does it comply with WHO 2021 guidelines?"More use cases by audience


Features

  • 🌬️ Air quality monitoring – 16 NABEL stations, NO₂/O₃/PM10/PM2.5/SO₂/CO, Swiss LRV + WHO 2021 limit checks
  • 💧 Hydrology – water levels, flow rates, temperatures across Swiss gauging stations
  • 🚨 Flood warnings – active alerts filtered by danger level and canton
  • 🏔️ Natural hazard bulletin – SLF/BAFU bulletin in DE/FR/IT/EN, region-specific warnings
  • 🔥 Wildfire danger – canton- and region-level fire danger index
  • 📦 BAFU open data catalogue – search and retrieve environmental datasets via CKAN
  • 🔑 No authentication required – all data sources are publicly accessible
  • ☁️ Dual transport – stdio for Claude Desktop, Streamable HTTP/SSE for cloud deployment

Prerequisites

  • Python 3.11+
  • No API keys needed – all endpoints are publicly accessible without authentication

Installation

# Clone the repository
git clone https://github.com/malkreide/swiss-environment-mcp.git
cd swiss-environment-mcp

# Install
pip install -e .

Or with uvx (no permanent installation):

uvx swiss-environment-mcp

Or via pip:

pip install swiss-environment-mcp

Quickstart

# Start the server (stdio mode for Claude Desktop)
swiss-environment-mcp

Try it immediately in Claude Desktop:

"What is the current air quality at NABEL station Zürich-Kaserne?" "Are there any active flood warnings in Switzerland right now?" "What is the wildfire danger level in Canton Valais?"


Configuration

Claude Desktop

Minimal (recommended):

{
  "mcpServers": {
    "swiss-environment": {
      "command": "uvx",
      "args": ["swiss-environment-mcp"],
      "env": {}
    }
  }
}

Config file locations:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json

After saving, restart Claude Desktop completely.

Cloud Deployment (SSE for browser access)

For use via claude.ai in the browser (e.g. on managed workstations without local software):

Render.com (recommended):

  1. Push/fork the repository to GitHub
  2. On render.com: New Web Service → connect GitHub repo
  3. Render detects render.yaml automatically
  4. In claude.ai under Settings → MCP Servers, add: https://your-app.onrender.com/sse

Docker:

docker build -t swiss-environment-mcp .
docker run -p 8000:8000 swiss-environment-mcp

💡 "stdio for the developer laptop, SSE for the browser."


Available Tools

🌬️ Air Quality / NABEL (3 tools)

Tool Description Data Source
env_nabel_stations List all 16 NABEL monitoring stations with location type and canton NABEL / BAFU
env_nabel_current Current air quality data for a station (NO₂, O₃, PM10, PM2.5, SO₂, CO) NABEL / BAFU
env_air_limits_check Compare a measurement against Swiss LRV limits and WHO 2021 guidelines Built-in

💧 Hydrology (4 tools)

Tool Description Data Source
env_hydro_stations Filter hydrological gauging stations by canton or water body hydrodaten.admin.ch
env_hydro_current Current water level, flow rate and temperature at a station hydrodaten.admin.ch
env_hydro_history Historical hourly values (up to 30 days) with download links ⚠️ hydrodaten.admin.ch
env_flood_warnings Active flood warnings filtered by danger level and canton hydrodaten.admin.ch

🏔️ Natural Hazards (3 tools)

Tool Description Data Source
env_hazard_overview Current natural hazard bulletin (SLF/BAFU) in DE/FR/IT/EN naturgefahren.ch
env_hazard_regions Region-specific warnings (floods, avalanches, rockfall) naturgefahren.ch
env_wildfire_danger Wildfire danger index by canton and region waldbrandgefahr.ch

📊 Environmental Data Catalogue (2 tools)

Tool Description Data Source
env_bafu_datasets Search BAFU datasets on opendata.swiss (CKAN API) opendata.swiss
env_bafu_dataset_detail Full metadata and download URLs for a specific dataset opendata.swiss

Example Use Cases

Query Tool
"Air quality at Zürich-Kaserne right now?" env_nabel_current
"Does 45 µg/m³ NO₂ exceed the Swiss limit?" env_air_limits_check
"Current water level of the Limmat in Zurich?" env_hydro_current
"Active flood warnings in Switzerland?" env_flood_warnings
"Natural hazard bulletin for Graubünden?" env_hazard_overview
"Wildfire danger in Canton Valais?" env_wildfire_danger
"BAFU biodiversity datasets on opendata.swiss?" env_bafu_datasets

🛡️ Safety & Limits

Aspect Details
Access Read-only (readOnlyHint: true) — the server cannot modify or delete any data
Personal data No personal data — all sources are aggregated, public environmental measurements
Rate limits Built-in per-query caps (e.g. max 30 days hydrology history, 50 dataset search results)
Timeout 30 seconds per API call
Authentication No API keys required — all BAFU endpoints are publicly accessible
Licenses BAFU Open Government Data (OGD) — free reuse with mandatory attribution
Terms of Service Subject to ToS of the respective data sources: BAFU / opendata.swiss, hydrodaten.admin.ch, naturgefahren.ch, waldbrandgefahr.ch

Architecture

┌─────────────────┐     ┌───────────────────────────┐     ┌──────────────────────────┐
│   Claude / AI   │────▶│   Swiss Environment MCP   │────▶│  BAFU / Swiss Agencies   │
│   (MCP Host)    │◀────│   (MCP Server)            │◀────│                          │
└─────────────────┘     │                           │     │  hydrodaten.admin.ch     │
                        │  12 Tools · 3 Resources   │     │  naturgefahren.ch        │
                        │  Stdio | SSE              │     │  waldbrandgefahr.ch      │
                        │                           │     │  opendata.swiss (CKAN)   │
                        │  api_client.py            │     └──────────────────────────┘
                        │  server.py (FastMCP)      │
                        └───────────────────────────┘

Data Sources

Source Data Licence
hydrodaten.admin.ch Water levels, flow rates, temperatures (10-min intervals) BAFU OGD
naturgefahren.ch Natural hazard bulletin (SLF/BAFU) BAFU/SLF
waldbrandgefahr.ch Wildfire danger index BAFU
opendata.swiss BAFU data catalogue (CKAN API) OGD

All data: publicly accessible, no authentication required.
Attribution required: BAFU must be cited as the source when using their data.


Project Structure

swiss-environment-mcp/
├── src/swiss_environment_mcp/
│   ├── __init__.py          # Package
│   ├── server.py            # FastMCP server: 12 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)

Single-module layout (rationale, audit ARCH-011): the 12 tools live in one server.py rather than a tools/ package. They are thin, uniform wrappers over api_client.py sharing the same input/response patterns, so a single well-sectioned module stays more navigable than 4 near-identical files. This is a deliberate, documented deviation; a split is revisited if tool logic grows non-uniform.


MCP Protocol Version & Maintenance

  • MCP protocol: negotiated at initialize time and handled by the pinned MCP SDK (mcp[cli]). The SDK version is the canonical pin; SDK/protocol updates land via Dependabot PRs (.github/dependabot.yml, monthly).
  • Tool-definition stability (audit SEC-022): any change to a tool's name, description or parameters changes tool-snapshot.json; CI fails until the snapshot is regenerated and a CHANGELOG entry + version bump are added.
  • Update policy: review Dependabot PRs monthly; bump the version (semver) on any tool-definition or behaviour change.

Lifecycle Phase

This server is in Phase 1 (read-only) — all tools read-only, no auth, no side effects. The phase model and prerequisites for Phase 2 (write/auth) are in docs/roadmap.md. Security architecture (SSRF/egress, secret management, lethal-trifecta assessment): docs/security.md. Scaling/session strategy: docs/scaling.md.


Known Limitations

  • env_hydro_history: The historical hourly data endpoint is currently returning 404 errors from hydrodaten.admin.ch (BUG-01 – under investigation). The tool will return download links as a fallback.
  • NABEL: Near-real-time data only; no historical time series via this server.
  • Natural hazards: Bulletin availability depends on SLF/BAFU publication schedule.
  • Wildfire danger: Regional granularity varies by season and data availability.

Testing

# 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

See CONTRIBUTING.md


Changelog

See CHANGELOG.md


License

MIT License — see LICENSE

Source data is subject to BAFU terms of use. Attribution to BAFU is required when using their data.


Author

Hayal Oezkan · github.com/malkreide


Credits & Related Projects

Server Description
zurich-opendata-mcp City of Zurich open data (OSTLUFT air quality, weather, parking, geodata)
swiss-transport-mcp Swiss public transport – OJP 2.0 journey planning, SIRI-SX disruptions
swiss-road-mobility-mcp GBFS shared mobility, EV charging, DATEX II traffic
swiss-statistics-mcp BFS STAT-TAB – 682 statistical datasets

Synergy example: "What was the air quality at Schulhaus Leutschenbach today – and how does it compare to the national NABEL average?"
zurich-opendata-mcp (OSTLUFT, local) + swiss-environment-mcp (NABEL, national)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

swiss_environment_mcp-0.2.0.tar.gz (141.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

swiss_environment_mcp-0.2.0-py3-none-any.whl (31.6 kB view details)

Uploaded Python 3

File details

Details for the file swiss_environment_mcp-0.2.0.tar.gz.

File metadata

  • Download URL: swiss_environment_mcp-0.2.0.tar.gz
  • Upload date:
  • Size: 141.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for swiss_environment_mcp-0.2.0.tar.gz
Algorithm Hash digest
SHA256 aa6c5bbab908f8ffdc8b6404042bc5e5416b00ecd223459e7495ca30a5c2df8e
MD5 046f951e9f607c429ae17fc449f2dc9f
BLAKE2b-256 a616c5652fe623befc651d9fda1363e6b50e5fe06cdb101eee971cd68909cf3f

See more details on using hashes here.

Provenance

The following attestation bundles were made for swiss_environment_mcp-0.2.0.tar.gz:

Publisher: publish.yml on malkreide/swiss-environment-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file swiss_environment_mcp-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for swiss_environment_mcp-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ed58cc54618bf0836eae9a340eecde398db0abecf9ad681f1ab4e23a8f2e5e52
MD5 ba362431230588cf228f3d51c6316f4a
BLAKE2b-256 84a08d9b937bafaf89c0dd68d34e30f6d8d55f325581b2d177e4d2aa3542f2df

See more details on using hashes here.

Provenance

The following attestation bundles were made for swiss_environment_mcp-0.2.0-py3-none-any.whl:

Publisher: publish.yml on malkreide/swiss-environment-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page