Releases: malkreide/swiss-efv-mcp
Release list
v0.3.2
[0.3.2] - 2026-08-02
Fixed
-
structlogcarried no upper bound, and the index already serves a major past
the floor. The declared range wasstructlog>=24.1; 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,<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.3.1
[0.3.1] - 2026-07-31
Geaendert
-
Der Server gibt sich nicht mehr als Chrome aus. Bis 0.3.0 sendete er
Mozilla/5.0 (X11; Linux x86_64) ... Chrome/124.0 Safari/537.36, mit dem
Vermerk, die Endpunkte wiesen alles andere mit 403 ab (gemessen 2026-07-24).Am 2026-07-31 nachgemessen: alle drei Datensatz-URLs auf beiden Hosts, je
vier User-Agents — Chrome, die ehrliche Kennung,curl/8.5.0und ganz ohne
UA-Header. Jede Anfrage antwortete 200/206; die ehrliche Kennung anschliessend
dreimal ueber alle drei Datensaetze wiederholt, neun von neun erfolgreich.
Die Einschraenkung besteht nicht mehr.Neu sendet der Server
swiss-efv-mcp/<version> (+github.com/...)aus den
Paket-Metadaten. Eine gefaelschte Kennung kostet den Betreiber die
Moeglichkeit, uns in seinen Logs zu erkennen und uns bei Fehlverhalten zu
erreichen — das ist nur fuer eine Sperre zu zahlen, die es tatsaechlich gibt.
Sollte die EFV wieder filtern, gehoert zum Zurueckdrehen die Aktualisierung
des Vermerks: eine veraltete Begruendung ist der Grund, warum diese hier so
lange unhinterfragt blieb.
v0.3.0
[0.3.0] - 2026-07-25
Medium-findings audit backlog worked through — 0 failing checks; the three remaining findings are accepted-risk ADR-documented deferrals (SCALE-002, SCALE-003, SEC-005). See the audit runs under audits/.
Added
ARCH-012: the MCP protocol baseline (2025-11-25) is pinned as MCP_PROTOCOL_VERSION in server.py, with a regression test that fails CI if a SDK bump changes the negotiated version.
SEC-022: dump_status renamed to fiscal_status so every tool shares the fiscal_ server-identity namespace; dump_status is kept as a documented deprecated alias (removed in a future minor). Tool-hash pinning is documented as a gateway responsibility in SECURITY.md.
SCALE-003: ADR 0002 gains a concrete Mcp-Session-Id sticky-session example (nginx / Ingress / Traefik) for the multi-replica case.
SEC-005: docs/network-egress.md prescribes the network-layer egress mitigation (default-deny NetworkPolicy / egress-proxy allow-list) that supersedes application-level DNS pinning.
SDK-002: tools now return typed Pydantic models, so FastMCP exposes an output schema and structured content for every tool.
SDK-003: Context injection — tools emit debug logs and fiscal_list_dimensions reports progress while loading the dumps.
ARCH-002: tool descriptions carry explicit use-case context.
ARCH-003: empty results return a guidance note (pointing at fiscal_list_dimensions or a different level) instead of a silent empty.
OBS-006: optional OpenTelemetry tracing via the otel extra, gated by EFV_MCP_OTEL_ENABLED (off by default; src/swiss_efv_mcp/_otel.py).
SCALE-006 / SEC-007: compose.yaml with CPU/memory limits, read-only root filesystem, dropped capabilities and no-new-privileges.
OPS-001: per-tool live tests (fiscal_by_institution, dump_status) and a scheduled/manual live-test workflow (.github/workflows/live.yml).
OPS-003: docs/roadmap.md documenting the phase architecture and the audit backlog.
Security
SEC-004: the egress guard now rejects IP-literal hosts and re-asserts the allow-list on the final URL after redirects.
v0.2.0
v0.1.0 — Swiss federal finances (EFV)
[0.1.0] - 2026-07-24
Added
Initial release: MCP server for Swiss federal finances (EFV), Architecture C (Dump-first).
Tools: fiscal_headline, fiscal_budget_breakdown, fiscal_by_institution, fiscal_list_dimensions, dump_status.
Dual transport (stdio / SSE), retry with exponential backoff, 24 h TTL cache, Pydantic v2 envelopes with source + provenance.
respx mock tests (Happy / Retry-on-503 / Timeout / Graceful degradation) plus @pytest.mark.live tests against the real endpoints.
Known findings (from live probe 2026-07-24)
403 without UA: data.finance.admin.ch and efv.admin.ch reject the default httpx/curl User-Agent; a browser UA is injected in client.py.
Landing-page trap: opendata.swiss lists two datasets as "CSV" but the URL serves HTML; real files resolved to DAM paths (/dam/de/sd-web/{id}/{name}_de.csv) whose opaque id may rotate on re-upload.
NA-as-string: hh / model / source use the literal "NA" for missing; centralised clean() maps null-ish tokens to None.
Projection is not one label: the Bund labels future years "Budget/financial plans"; the aggregate state (staat) uses "Forecasts". is_projection abstracts over both so agents need not know the taxonomy.
Accounting-model seam 2022/2023: budget topics split into "bis 2022" and "ab 2023"; a note flags affected breakdowns.
Detail cubes deferred: standardauswertung.csv (157 MB) and fir_art_funk.csv (1.23 GB) are out of scope for v0.1.0 (Phase 2: pre-process to SQLite/Parquet).