Skip to content

v0.2.4

Choose a tag to compare

@malkreide malkreide released this 31 Jul 15:33
6438565

[v0.2.4] — 2026-07-30

Fixed

  • The User-Agent reports the actual package version again. The published
    0.2.3 sent openlex-mcp/0.2.0 to 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() rief mcp.streamable_http_app() ohne host auf. Unter
    mcp 2.x ist das kein neutraler Default: das SDK leitet daraus eine Allow-List
    ab und aktiviert bei loopback-artigem Wert automatisch 127.0.0.1:*. Da der
    Default 127.0.0.1 ist, galt das auch für den MCP_HOST=0.0.0.0-Bind des
    Containers. Nachgemessen an der echten ASGI-App vor dem Fix:

    Host 127.0.0.1:8000        -> 200
    Host mcp.example.ch        -> 421
    Host openlex.example.com   -> 421
    

    /healthz antwortete weiter mit 200 und verdeckte es, weshalb ein
    Readiness-Probe nichts gemerkt hätte.

    Der Bind reist jetzt in die App, und eine explizite Allow-List wird aus dem
    neuen MCP_ALLOWED_HOSTS gebaut. Ohne diese Variable bleibt der Schutz auf
    einem Nicht-Loopback-Bind bewusst aus und der Aufrufer warnt — eine geratene
    Liste würde genau das 421-Problem reproduzieren. Konfigurierte CORS-Origins
    werden mit aufgenommen, sonst weist der Transport genau die Browser-Clients
    ab, die CORS erlaubt.

    13 neue Tests, davon der tragende „richtiger Hostname, falscher Port": nur er
    unterscheidet eine portgenaue Allow-List von einer, die alles durchlässt —
    evil.example.com allein würde auch ein zurückfallender Loopback-Default
    abweisen. Mutationsgetestet: nimmt man den host-Kwarg wieder weg,
    reproduziert der Test das 421 exakt.

    Geprüft mit dem wörtlichen CI-Kommando: 111 passed, 8 deselected;
    ruff check src/ tests/ clean.

Added

  • Security policySECURITY.md (English) and SECURITY.de.md (German),
    linked from both READMEs and CONTRIBUTING.md.
  • German contribution guideCONTRIBUTING.de.md, linked from
    CONTRIBUTING.md.

Fixed

  • Capped mcp at <2. mcp 2.0.0, published 2026-07-28, removed
    mcp.server.fastmcp — the module this server imports. With the previous
    unbounded >=1.28.1 every fresh resolve picked 2.0.0 and failed at import
    with ModuleNotFoundError, in CI and for anyone running pip install alike.
    Verified in both directions: 2.0.0 fails, <2 resolves to 1.29.0 and imports
    cleanly. Migrating to the 2.x API (mcp.server.mcpserver) stays a separate,
    deliberate piece of work.

  • zhlaw_get_law_metadata permalink — the legacy
    http://www.zhlex.zh.ch/Erlass.html?Open&Ordnr=<ordnr> permalink was replaced
    upstream and now returns 404 (it redirected to a lawcollection-directlink
    endpoint that 404s over HTTP). Metadata now resolves via the current
    https://www.zhlex.zh.ch/bin/zhweb/publish/lawcollection-directlink?Open&Ordnr=<ordnr>
    endpoint, which 302-redirects to the consolidated version on www.zh.ch.

  • Live tests — repaired three nightly live-test regressions caused by upstream
    drift:

    • zhlaw_get_article returned empty content for single-line PDF extracts
      (e.g. VSG § 1): the article parser captured the whole running text into the
      title. The parser now derives the marginal-note title and the body separately
      so content is never empty for run-on lines. Offline regression tests added.
    • zhlaw_get_law_metadata no longer resolved on zh.ch — the undated
      erlass-<ordnr>.html landing URL was removed upstream (returns 404). Live
      metadata now uses the stable per-ordinance permalink
      http://www.zhlex.zh.ch/Erlass.html?Open&Ordnr=<ordnr>, which redirects to
      the current consolidated version on www.zh.ch.
    • test_live_list_laws asserted a brittle SR-prefix that does not hold for the
      first page (laws are sorted ascending by ordinance number); it now checks the
      real invariant (non-empty, ascending sr_numbers).

Changed

  • Egress allow-list (SEC-021 / SEC-004) — added www.zhlex.zh.ch to
    EGRESS_ALLOWLIST and introduced HTTP_ALLOWED_HOSTS so that this single
    legacy permalink host may be reached over HTTP (it has no HTTPS endpoint).
    HTTPS remains mandatory for every other host; the allow-list, SSRF IP-block,
    DNS-pinning, and per-hop redirect gate are unchanged. See
    docs/network-egress.md.
  • Documentation consistency — re-synced README.de.md with the English
    README.md (Development Phase, network binding, expanded cloud config, design
    decision, scaling constraints, MCP protocol version, tool output format,
    security rows, updated project tree). Updated LICENSE copyright year to 2026.