swiss-electricity-mcp
MCP server for Swiss electricity data from three official sources β production mix, consumption forecast, storage-lake fill, consumer price index, tariffs per municipality, and dataset discovery. Zero authentication.
README
swiss-electricity-mcp
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 β a coordinated set of MCP servers for Swiss public administration.
Anchor demo query
"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.
Demo
What's inside
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.
Tools (12)
dashboard_* β Energiedashboard.ch (BFE)
dashboard_get_production_mixβ Production mix by year (TWh + %): Kernkraft, Wasserkraft, PV, Wind, thermal.dashboard_get_consumption_forecastβ Current consumption forecast + 5-day outlook + 5-year envelope.dashboard_get_storage_lakesβ Speichersee fill level (CH or per region: Wallis, Tessin, GraubΓΌnden, Zentral/Ost) β critical winter-supply indicator.dashboard_get_consumer_price_indexβ Endverbraucher-Strompreis-Index (2020-01-01 = 100).
tariff_* β ElCom (via LINDAS SPARQL)
tariff_list_categoriesβ H1βH8 (households) and C1βC7 (commercial). C3 β 150'000 kWh/a is the typical reference for school buildings.tariff_get_by_municipalityβ Tariffs for a BFS-Nr + category + year range, broken into energy / grid usage / KEV / Abgaben.tariff_get_median_swissβ National median benchmark.tariff_get_median_cantonβ Cantonal median (e.g. for Kanton ZΓΌrich).tariff_compare_municipalitiesβ Compare up to 20 municipalities side-by-side.
consumption_* β opendata.swiss + Stadt ZΓΌrich OGD
consumption_search_bfe_datasetsβ CKAN search across BFE-published datasets.consumption_search_zurichβ CKAN search across Stadt ZΓΌrich OGD (includes quarter-hour NE5/NE7 consumption).
Status
electricity_check_statusβ Liveness probe across all four upstreams (HTTP status + latency + overall-healthy flag).
Installation
From PyPI
pip install swiss-electricity-mcp
From source
git clone https://github.com/malkreide/swiss-electricity-mcp.git
cd swiss-electricity-mcp
pip install -e ".[dev]"
Use with Claude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"swiss-electricity": {
"command": "swiss-electricity-mcp"
}
}
}
Cloud deployment (Streamable HTTP)
SWISS_ELECTRICITY_TRANSPORT=streamable-http \
SWISS_ELECTRICITY_HOST=0.0.0.0 \
SWISS_ELECTRICITY_PORT=8000 \
swiss-electricity-mcp
Works on Render.com, Railway, Fly.io.
Host binding (security). In HTTP mode the host defaults to
127.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).
Docker
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
Observability & configuration
| 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 |
-
Logging is structured JSON on stderr (stdout is reserved for the stdio JSON-RPC channel). Upstream failures are logged in full server-side but masked in client-facing responses.
-
Tracing is opt-in. Install the extra and point it at a collector:
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.
Architecture
βββββββββββββββββββββββββββ 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:
- Different latency profiles per source: Energiedashboard responds in ~200 ms (great live); LINDAS SPARQL is slower and occasionally returns 504 (longer timeout + 3 retries); CKAN is metadata-only and inherently safe.
- Different update cadences: Dashboard updates intraday; ElCom tariffs update once per year; OGD datasets are stable for months. Per-source TTL caching (600 s / 3600 s) reflects this.
- Domain separation from
swiss-energy-mcp: that server covers geo and infrastructure data (power plants, grid lines).swiss-electricity-mcpcovers time-series and tariffs. Both compose cleanly.
Provenance discipline
Every tool response is a Pydantic envelope carrying:
sourceβ full attribution string (e.g. "Daten: Bundesamt fΓΌr Energie (BFE)β¦").provenanceβ exactly one oflive_api/sparql/cached/weekly_dump/stale_cache_fallback.retrieved_atβ ISO-8601 UTC timestamp.
This makes accidental misattribution structurally impossible.
Resilience
- Retry: 3 attempts with exponential backoff (2 s / 4 s / 8 s).
- 5xx + 429: retried. 4xx (except 429): raised immediately (permanent client error).
- In-memory TTL cache: per-source TTLs reduce upstream load and round-trip during multi-step agent workflows.
MCP primitives β why Tools only
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.
Project phase
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.
Testing
# 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 -v
Unit 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.
MCP protocol version
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).
Known limitations
- LINDAS SPARQL 504 timeouts: the LINDAS public endpoint occasionally returns 504 under load. The 3-retry policy handles transient cases; persistent unavailability surfaces as
UpstreamUnreachableError. - No historical PV/wind detail: Energiedashboard exposes only aggregated production mix at year level. For sub-yearly PV or wind, use
consumption_search_bfe_datasets. - No FHIR or smart-meter data: out of scope. Future work may add a
swiss-prosumer-mcpor similar. - Year coverage: ElCom tariff data starts in 2009. Energiedashboard mix starts in 2014.
Portfolio synergy
This server composes naturally with other portfolio servers:
- +
swiss-energy-mcpβ combine geo/asset data (power plants) with time-series and tariffs for full energy-infrastructure analysis. - +
meteoswiss-mcpβ correlate consumption forecasts with weather (temperature drives heating/cooling load). - +
fedlex-mcpβ pair tariff data with the Stromversorgungsgesetz (StromVG) for compliance/legal context. - +
zh-education-mcpβ Schulamt-relevant queries combining tariffs, school counts, infrastructure budgets.
Data sources & licensing
All upstream data is Open Government Data Switzerland (OGD-CH):
- Energiedashboard.ch Β© Bundesamt fΓΌr Energie BFE β Open data, free to use.
- ElCom / LINDAS Β© EidgenΓΆssische ElektrizitΓ€tskommission ElCom β CC BY 4.0.
- opendata.swiss Β© Various Swiss public bodies β Mostly CC0 / CC BY 4.0.
- Stadt ZΓΌrich OGD Β© Stadt ZΓΌrich β CC0.
This MCP server is MIT-licensed (see LICENSE). Always cite the original data source β the response envelope includes the proper attribution string automatically.
Contributing
See CONTRIBUTING.md.
Security
See SECURITY.md for the security policy and how to report a vulnerability.
License
MIT License β see LICENSE. The upstream data keeps the licences listed under Data sources & licensing above.
Author
Hayal Oezkan Β· github.com/malkreide
Changelog
See CHANGELOG.md.
<!-- mcp-name: io.github.malkreide/swiss-electricity-mcp -->
<!-- BEGIN GENERATED: install -->
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": {
"swiss-electricity-mcp": {
"command": "uvx",
"args": [
"swiss-electricity-mcp"
]
}
}
}
<!-- END GENERATED: install -->
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.