Releases: malkreide/swiss-electricity-mcp
Release list
v0.2.5
[0.2.5] - 2026-08-02
Fixed
-
structlogcarried no upper bound, and the index already serves a major past
the floor. The declared range wasstructlog>=24.1.0; PyPI has been serving
26.1.0. The artefact does not change — the resolver's answer to the next
fresh install does, and that is exactly howswiss-energy-mcp0.3.3 became
uninstallable whenmcp2.0.0 removed the module it imported.Now
structlog>=24.1.0,<27. The bound is measured rather than guessed: this package
installs and imports againststructlog 26.1.0today, so the cap admits what
demonstrably works and stops only the next, unknown major.
A dependency range only reaches users through a new release, hence the
version bump. No code changed.
v0.2.4
[0.2.4] - 2026-07-30
Fixed
-
The User-Agent reports the actual package version again. The published
0.2.3sentswiss-electricity-mcp/0.2.0to every upstream — the version string was
hardcoded and had been left behind by earlier bumps. The version now comes
from the package metadata, so it can no longer drift from the package. -
HTTP-Modus wies unter jedem echten Hostnamen mit 421 ab (SEC-005).
build_http_app()riefmcp.streamable_http_app()ohnehostauf. Unter
mcp 2.x ist das kein neutraler Default: das SDK leitet daraus seine
Host-Allow-List ab und aktiviert bei loopback-artigem Wert automatisch
127.0.0.1:*. Da das Argument selbst auf127.0.0.1defaultet, galt das auch
für denSWISS_ELECTRICITY_HOST=0.0.0.0-Bind, den dieses Modul für Container
dokumentiert. Vor der Migration ginghostan denFastMCP-Konstruktor, wo
dieselbe Logik den echten Bind sah und den Schutz korrekt ausliess.Der Bind reist jetzt in die App, und eine echte Allow-List wird aus dem neuen
SWISS_ELECTRICITY_ALLOWED_HOSTSgebaut. Ohne diese Variable bleibt der
Schutz auf einem Nicht-Loopback-Bind bewusst aus und der Aufrufer warnt — eine
geratene Liste wäre genau der 421-Fall. -
SWISS_ELECTRICITY_CORS_ORIGINSfunktionierte nie in der dokumentierten
Form. Vorbestehender Fehler, den das zweite Listen-Feld sichtbar gemacht
hat: pydantic-settings JSON-dekodiert komplex typisierte Felder aus der
Umgebung, bevor einmode="before"-Validator läuft. Eine kommagetrennte
Liste löste damitSettingsErroraus, und_split_csvwar für Env-Eingaben
unerreichbar — toter Code. Beide Felder tragen jetztNoDecode.14 neue Tests, darunter der tragende Fall „richtiger Hostname, falscher Port":
nur er unterscheidet eine portgenaue Allow-List von einer, die alles
durchlässt. Mutationsgetestet in beide Richtungen —NoDecodeentfernen bricht
die CSV-Tests, denhost-Kwarg entfernen reproduziert das 421.Geprüft mit dem wörtlichen CI-Kommando (
pytest -m "not live" -q):
58 passed, 3 deselected;ruff check src/ tests/clean.
v0.2.0 — Audit remediation (production-ready)
Audit-remediation release. Closes all critical/high findings from the
mcp-audit-skill audit. The
re-audit reports production-ready: 36 pass · 0 fail · 2 partial · 6 todo
(catalog hash 091f446b, run-id 2026-06-03T191138-Z-swiss-electricity-mcp).
🔒 Security
- SEC-016 — HTTP host defaults to
127.0.0.1;0.0.0.0only explicitly (containers). - SEC-007 — Multi-stage
Dockerfile, non-root user (UID 10001),HEALTHCHECK. - SEC-018 — SPARQL-injection closed:
categorywhitelist +cantonescaping + string bounds. - SEC-004/005/021 — HTTPS-only, host-allow-listed egress gate (
assert_url_allowed); seedocs/network-egress.md. - SEC-022 — Tool definitions pinned in
tool-definitions.lock.jsonwith a drift test. - SEC-019/013/008 — Security posture documented (
docs/security-posture.md): lethal-trifecta, secrets, supply chain.
🔭 Observability
- OBS-003/004 — Structured JSON logging via
structlogto stderr. - OBS-006 — Opt-in OpenTelemetry tracing (per-tool spans + httpx auto-instrumentation).
- OBS-002 — Upstream errors logged server-side, masked in client responses.
- OBS-001 — Execution- and protocol-error-path tests.
🧩 SDK & architecture
- SDK-001 — Shared HTTP clients owned by a FastMCP
lifespan. - SDK-003 —
ctx: Contexton SPARQL tools; progress reporting in compare. - SDK-004 — CORS middleware exposes/allows
Mcp-Session-Id. - ARCH-004 — Configuration centralised in a Pydantic-Settings object; clients via lifespan context.
- ARCH-009 — All 12 tools declare explicit MCP annotations (
readOnlyHint/openWorldHint). - ARCH-007 —
tariff_compare_municipalitiesfetches concurrently (asyncio.gather). - ARCH-003 — Search tools return
match_type+ actionablesuggestionon zero hits.
⚙️ CI / infrastructure
- ARCH-011/OPS-001 — CI (
test.yml: ruff + pytest on 3.11–3.13) andpublish.yml(PyPI OIDC). - ARCH-005 — Gitleaks secret scan on every push/PR.
- ARCH-012 — Dependabot;
mcp[cli]pinned>=1.2.0,<2.0.0; MCP protocol-version policy in README. - OPS-002/003 — ASCII architecture diagram; Phase-1 declaration +
docs/roadmap.md.
Full changelog: CHANGELOG.md · compare v0.1.0...v0.2.0