Swiss Electricity Mcp — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Swiss Electricity Mcp (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
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.
MCP server for Swiss electricity data — three official sources, twelve tools, zero authentication.
🌍 Read this in your language: 🇩🇪 Deutsch
Part of the [Swiss Public Data MCP Portfolio](https://github.com/malkreide/swiss-public-data-mcp) — a coordinated set of MCP servers for Swiss public administration.
"How have ewz electricity tariffs for a typical school building (consumption category C3, ≈150'000 kWh/a) developed since 2019, and how do they compare to the Swiss median?"
A single conversation calls tariff_get_by_municipality (bfs_nr=261, category="C3") + tariff_get_median_swiss and returns a year-by-year comparison with full provenance — ready for a Geschäftsleitung slide.
Three official Swiss data sources combined into one MCP server, each with its own dedicated tool group:
| Source | What it provides | Provenance |
|---|---|---|
| Energiedashboard.ch (Bundesamt für Energie) | National production mix, consumption forecast, storage-lake fill, consumer price index | live_api |
| ElCom electricity-price cubes (via LINDAS SPARQL) | Tariffs per municipality, category, year, with full breakdown (energy + grid usage + KEV + Abgaben) | sparql |
| opendata.swiss + Stadt Zürich OGD (CKAN) | Dataset discovery for raw time series (e.g. quarter-hour NE5/NE7 consumption) | live_api |
No authentication required. All endpoints are public Swiss OGD.
dashboard_* — Energiedashboard.ch (BFE)tariff_* — ElCom (via LINDAS SPARQL)consumption_* — opendata.swiss + Stadt Zürich OGDpip install swiss-electricity-mcpgit clone https://github.com/malkreide/swiss-electricity-mcp.git
cd swiss-electricity-mcp
pip install -e ".[dev]"Add to claude_desktop_config.json:
{
"mcpServers": {
"swiss-electricity": {
"command": "swiss-electricity-mcp"
}
}
}SWISS_ELECTRICITY_TRANSPORT=streamable-http \
SWISS_ELECTRICITY_HOST=0.0.0.0 \
SWISS_ELECTRICITY_PORT=8000 \
swiss-electricity-mcpWorks on Render.com, Railway, Fly.io.
Host binding (security). In HTTP mode the host defaults to127.0.0.1(loopback only). Bind to all interfaces withSWISS_ELECTRICITY_HOST=0.0.0.0only inside a container, where the network boundary is the container, not the host. Setting0.0.0.0on a developer machine exposes the server to the local network (NeighborJack).
A multi-stage Dockerfile is provided. It runs as a non-root user (UID 10001) and sets SWISS_ELECTRICITY_HOST=0.0.0.0 explicitly for the containerised case.
docker build -t swiss-electricity-mcp .
docker run --rm -p 8000:8000 swiss-electricity-mcp| Env var | Default | Purpose |
|---|---|---|
SWISS_ELECTRICITY_TRANSPORT | stdio | stdio or streamable-http |
SWISS_ELECTRICITY_HOST | 127.0.0.1 | HTTP bind host (0.0.0.0 in containers only) |
SWISS_ELECTRICITY_PORT | 8000 | HTTP port |
SWISS_ELECTRICITY_LOG_LEVEL | INFO | Log level (DEBUG/INFO/WARNING/ERROR) |
SWISS_ELECTRICITY_CORS_ORIGINS | _(empty)_ | Comma-separated allowed CORS origins (browser clients); never * |
OTEL_EXPORTER_OTLP_ENDPOINT | _(unset)_ | Enables OpenTelemetry tracing when set |
SWISS_ELECTRICITY_ENV | unknown | deployment.environment resource attribute for traces |
JSON-RPC channel). Upstream failures are logged in full server-side but masked in client-facing responses.
pip install "swiss-electricity-mcp[otel]"
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 swiss-electricity-mcpYou get one span per tool call (mcp.tool.<name>) plus automatic httpx child spans for each upstream request. No argument values or PII are recorded.
┌────────────────────────── MCP client (Claude etc.) ──────────────────────────┐
│ stdio or Streamable HTTP │
└───────────────────────────────────────┬──────────────────────────────────────┘
│ 12 read-only tools (annotated)
┌────────▼─────────┐
│ FastMCP server │ egress allow-list + HTTPS gate
│ + structlog/OTel │ per-source TTL cache + retry
└───┬────────┬───┬──┘
dashboard_* │ tariff_* │ │ │ consumption_*
▼ ▼ ▼ ▼
┌───────────────────┐ ┌───────────┐ ┌──────────────┐ ┌─────────────────────┐
│ Energiedashboard │ │ LINDAS │ │ opendata.swiss│ │ data.stadt-zuerich.ch│
│ .admin.ch (BFE) │ │ SPARQL │ │ CKAN │ │ CKAN (OGD) │
└───────────────────┘ └───────────┘ └──────────────┘ └─────────────────────┘Hybrid (live API + SPARQL + CKAN discovery), no authentication. Three reasons this is the right shape:
swiss-electricity-mcp covers time-series and tariffs. Both compose cleanly.Every tool response is a Pydantic envelope carrying:
source — full attribution string (e.g. "Daten: Bundesamt für Energie (BFE)…").provenance — exactly one of live_api / sparql / cached / weekly_dump / stale_cache_fallback.retrieved_at — ISO-8601 UTC timestamp.This makes accidental misattribution structurally impossible.
This server intentionally exposes only Tools, not Resources or Prompts. The data is parametric and query-driven (a municipality BFS number, a category, a year), which maps naturally to tool calls; there is no stable, enumerable set of documents to expose as Resources, and no curated prompt templates to ship. If a future use case needs, say, a fixed "national production mix" document, the read-only dashboard_* tools are the obvious Resource-migration candidates.
Phase 1 — read-only. All 12 tools are read-only (readOnlyHint=true) with no write or destructive operations. Phase-transition criteria and the longer-term plan live in docs/roadmap.md. Security posture (egress, supply-chain, lethal-trifecta assessment) is documented in docs/security-posture.md.
# Unit tests (mocked, fast, CI default) — tests/test_unit.py + tests/test_security.py
PYTHONPATH=src pytest -m "not live" -v
# Live tests (hits real upstreams) — tests/test_live.py
PYTHONPATH=src pytest -m live -vUnit tests cover the contract layers: Happy (response parsing), Retry (5xx, 429, 4xx), Timeout (network errors → clean UpstreamUnreachableError), envelope/attribution invariants, plus security (egress allow-list, SPARQL escaping, tool-definition lock). CI runs ruff + pytest -m "not live" on Python 3.11–3.13.
This server is built on the official MCP Python SDK (mcp[cli]), pinned to >=1.2.0,<2.0.0. The MCP protocol version is negotiated by the SDK at the initialize handshake; the supported spec version tracks the pinned SDK (currently MCP spec 2025-11-25).
Update policy: SDK updates arrive as weekly Dependabot PRs. A protocol-spec bump is only adopted via an explicit SDK minor/major bump, recorded in CHANGELOG.md, and verified against the tool-definition lock (tool-definitions.lock.json).
UpstreamUnreachableError.consumption_search_bfe_datasets.swiss-prosumer-mcp or similar.This server composes naturally with other portfolio servers:
All upstream data is Open Government Data Switzerland (OGD-CH):
This MCP server is MIT-licensed (see LICENSE). Always cite the original data source — the response envelope includes the proper attribution string automatically.
See CONTRIBUTING.md.
See SECURITY.md for the security policy and how to report a vulnerability.
See CHANGELOG.md.
<!-- mcp-name: io.github.malkreide/swiss-electricity-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-electricity-mcp": {
"command": "uvx",
"args": [
"swiss-electricity-mcp"
]
}
}
}<!-- END GENERATED: install -->
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.