Swiss Environment Mcp — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Swiss Environment Mcp (Agent Skill) and scored it 82/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 2 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 2 flagged
The text {match} is the classic direct prompt-injection phrasing. Placed in a skill body that the agent reads as trusted instructions, it tries to make the agent abandon its prior rules and follow whatever comes next — a full system-prompt override.
ignore/disregard/forget … previous instructions sentence.The text {match} is the classic direct prompt-injection phrasing. Placed in a skill body that the agent reads as trusted instructions, it tries to make the agent abandon its prior rules and follow whatever comes next — a full system-prompt override.
ignore/disregard/forget … previous instructions sentence.Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
🇨🇭 Part of the [Swiss Public Data MCP Portfolio](https://github.com/malkreide)
MCP server connecting AI models to Swiss environmental data from BAFU – air quality, hydrology, natural hazards, wildfire danger and open environmental datasets.
<p align="center"> <img src="assets/demo.svg" alt="Demo: Claude queries NABEL air quality via a swiss-environment-mcp tool call and gets a WHO 2021 compliance check" width="820"> </p>
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 →
# 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-mcpOr via pip:
pip install swiss-environment-mcp# Start the server (stdio mode for Claude Desktop)
swiss-environment-mcpTry 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?"
Minimal (recommended):
{
"mcpServers": {
"swiss-environment": {
"command": "uvx",
"args": ["swiss-environment-mcp"],
"env": {}
}
}
}Config file locations:
~/Library/Application Support/Claude/claude_desktop_config.json%APPDATA%\Claude\claude_desktop_config.jsonAfter saving, restart Claude Desktop completely.
For use via claude.ai in the browser (e.g. on managed workstations without local software):
Render.com (recommended):
render.yaml automaticallyhttps://your-app.onrender.com/sseDocker:
docker build -t swiss-environment-mcp .
docker run -p 8000:8000 swiss-environment-mcp💡 "stdio for the developer laptop, SSE for the browser."
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 |
┌─────────────────┐ ┌───────────────────────────┐ ┌──────────────────────────┐
│ 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) │
└───────────────────────────┘| 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.
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 oneserver.pyrather than atools/package. They are thin, uniform wrappers overapi_client.pysharing 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.
initialize time and handled by the pinned MCPSDK (mcp[cli]). The SDK version is the canonical pin; SDK/protocol updates land via Dependabot PRs (.github/dependabot.yml, monthly).
description or parameters changes tool-snapshot.json; CI fails until the snapshot is regenerated and a CHANGELOG entry + version bump are added.
tool-definition or behaviour change.
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.
# 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/See CONTRIBUTING.md (English) · CONTRIBUTING.de.md (German)
Security policy and posture: SECURITY.md (English) · SECURITY.de.md (German). Full security architecture: docs/security.md.
See CHANGELOG.md
MIT License — see LICENSE
Source data is subject to BAFU terms of use. Attribution to BAFU is required when using their data.
Hayal Oezkan · github.com/malkreide
| 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)
<!-- mcp-name: io.github.malkreide/swiss-environment-mcp -->
<!-- BEGIN GENERATED: install -->
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": {
"swiss-environment-mcp": {
"command": "uvx",
"args": [
"swiss-environment-mcp"
]
}
}
}<!-- END GENERATED: install -->
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.