
Swiss Electricity Mcp
io.github.malkreide由 GitHub 帳號 malkreide 發布v0.3.0更新於 Oct 25, 2026
BFE energy dashboard, ElCom tariffs, public consumption data
概覽
唯讀 MCP 伺服器,提供瑞士官方電力資料:BFE 能源儀表板指標、ElCom 各市鎮電價以及公開用電資料集。
- 可以做什麼
- 從 BFE 能源儀表板取得全國發電結構、用電預測、蓄水湖蓄水率和消費者物價指數,每個回應都附來源標註。依市鎮、類別和年份查詢 ElCom 電價,並拆分能源、電網使用、KEV 和附加費。與全國或州中位數比較,並最多並排比較 20 個市鎮。在 BFE 和蘇黎世市開放資料目錄中檢索原始用電時間序列。檢查上游資料來源的健康狀態和延遲。
- 適用情境
- 適合比較瑞士各市鎮或州歷年電價、將某市鎮與全國中位數對標,或取得附明確來源標註的全國發電、用電和蓄水資料。
- 執行需求
- 以 Python 套件在本機執行,通常用 uvx 啟動或透過 pip 安裝;不需驗證、API 金鑰或環境變數。需要連線至瑞士公開開放資料端點的網路。HTTP 傳輸模式為選用,預設僅綁定回環位址。
安裝
在 SourceWeft 中
- 開啟 儀表板中的 Swiss Electricity Mcp,將其新增到工作區。
- 為需要使用其工具的對話啟用該服務。
Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。
其他 MCP 客戶端
參照 儲存庫 中的啟動說明。
README
swiss-electricity-mcp
MCP server for Swiss electricity data — three official sources, twelve tools, zero authentication.
[CI] [PyPI] [Python] [License: MIT]
🌍 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
[Demo: Claude using tariff_get_by_municipality and tariff_get_median_swiss]
What's inside
Three official Swiss data sources combined into one MCP server, each with its own dedicated tool group:
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
From source
Use with Claude Desktop
Add to claude_desktop_config.json:
Cloud deployment (Streamable HTTP)
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.
Observability & configuration
-
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:
You 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
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: up to 3 retries, i.e. at most 4 attempts. Waits grow exponentially (base 2 s / 4 s / 8 s), each jittered to 0.5–1.5× so that clients do not return in lockstep after an outage. No single wait exceeds 20 s. A
Retry-Aftersent with 429 or 503 takes precedence (plus 0–25 %, also capped at 20 s). - Time budget: 25 s for the whole call, all attempts and waits together. A wait that would overrun the budget ends the call instead, so there may be fewer than 4 attempts.
- 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.
MCP Protocol Version
This server speaks two protocol eras over the same endpoint. The client's first request on a connection decides which one applies; a later claim from the other era is refused.
Both revisions are pinned in
tests/test_protocol_version.py and asserted
against the installed SDK, so a Dependabot bump of mcp cannot move either one
silently. The handshake ceiling is measured against a live initialize through
the assembled ASGI stack, not read off a constant name.
Note that the SDK's LATEST_PROTOCOL_VERSION is an alias for the modern
era, not for the handshake era — pinning against it alone would leave the era
that current clients actually negotiate free to drift.
Update policy. When the gate fails, do not edit the constant blindly: read
the spec changelog between the two revisions, verify the server still behaves,
then move the constant, this section, README.de.md and
CHANGELOG.md together. A spec bump is adopted only through an
explicit mcp minor/major bump, recorded in CHANGELOG.md and
verified against the tool-definition lock (tool-definitions.lock.json).
What the server sets natively for 2026-07-28
The SDK reaching a revision is not the same as a server speaking it. Two surfaces the SDK leaves to the server, and what happens when it is left alone:
2026-07-28 moved serverInfo from a once-per-connection handshake footnote to
a stamp on the running traffic, which is what makes the empty version worth a
gate rather than a shrug.
The three empty directories carry a hint on purpose. MCPServer registers
their handlers unconditionally and server/discover lists prompts and
resources among its capabilities, so the surface exists on the wire — it is
just empty. This server has no way to register a prompt or a resource at
runtime, so it stays empty for the life of the process, which makes it the
safest thing here to cache.
Both are measured off a real response rather than read back off the
constructor: tests/test_server_identity.py
checks each identity field separately on each era, and
tests/test_cache_hints.py reads the hints out of
a live client session. Each has a negative control against a bare
MCPServer("kontrolle") — without it, an assertion that the SDK one day starts
satisfying by itself would keep reading as proof that this server sets it.
Testing
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.
Auditing the ruff pin across the portfolio
scripts/pin_audit.py checks whether a server's own pin guards actually hold.
It is not a CI gate — it needs the sibling repositories on disk — but it is
worth running whenever a pin convention changes or a new server joins:
It measures black-box: prepend an ordinary second pre-commit hook with its own
rev:, run the guard, read the exit code, restore the file. Two guards in the
portfolio used to report that hook's version as the ruff pin, turning CI red
with a number nobody had written. A positive control (misconfigure the ruff
hook's own rev) separates "correctly scoped" from "never reads the file" —
without it, a guard that ignores the config looks like a clean bill of health.
Where the test data comes from
The fixtures under tests/fixtures/ are recorded from the live sources and
dated. Source, retrieval date, selection rule and SHA-256 for every file:
tests/fixtures/PROVENANCE.md.
The requests are built by the production code. The script calls
ElComSparqlClient and EnergyDashboardClient and captures the answer through
an httpx transport, rather than retyping the SPARQL alongside. A fixture that
answers a slightly different question than the server asks proves the wrong
answer — quietly, because it looks plausible. At 40 lines of SPARQL, "slightly
different" is the normal case, not the exception.
Two selection rules are deliberately more than "the first N":
- The storage-lake series runs into the future. After the last measured day
come rows with a
nullmeasurement — 94 of them on the recording day. They are kept on purpose: without them, no test could show that the tool skips them. - What counts as a measurement is named per file, not guessed. The first
version of this used "any field other than
dateis non-null", which is wrong: those future rows do carry values — the five-year reference curves — just no measurement.
Where a search is trimmed, count keeps its real value: it says how much is
not in the file.
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.
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):
來源:README.md,提交 2c4cbd6
工具
0版本歷史
2- v0.3.0最新Sep 27, 2026
- v0.2.5Sep 16, 2026
評分
已滿足適用檢查項的 50%
該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。
- 近 30 天內可連通25 分
請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。
- 已宣告認證方式10 分
請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。
- 已列出工具15 分
請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。
- 描述必需15 分
- 圖示10 分
- 文件15 分
- 授權條款10 分