Skip to content

Release v0.5.0

Choose a tag to compare

@github-actions github-actions released this 11 Jun 20:10
cd71f7f

Security

  • A malicious Gemini server can no longer hang the client with an unbounded
    status-44 (SLOW_DOWN) backoff. The server-supplied wait is now sanitized and
    clamped (a non-finite value such as inf is rejected/capped), so a single
    44 inf response can no longer make every later fetch to that host sleep
    forever while holding a concurrency-semaphore slot.
  • The Gemini TLS close handshake is now time-bounded, so a peer that withholds
    close_notify can no longer tack the OS TCP timeout onto each request after
    the read deadline has already been met.

Fixed

  • Gopher menu items using the hURL web-link convention (a URL:<target>
    selector, typically on a type-h item) now expose the real destination as
    next_url instead of a gopher:// URL pointing back at the gopher host, so
    web/gemini links on real-world menus are followable.
  • Gopher text-mode un-dot-stuffing (...) is now applied only when the
    RFC 1436 . terminator is actually present. An unframed document (no
    terminator) is returned verbatim, so a literal leading .. is no longer
    corrupted to ..
  • A server-side Gemini protocol fault (missing CRLF, over-long meta, bad status
    line, empty response) now returns a distinct PROTOCOL_ERROR instead of
    INVALID_REQUEST, so the model is told the server misbehaved rather than that
    its own URL was malformed.
  • A spec-valid comma-separated lang parameter (e.g. lang=en,fr) is no longer
    rejected; rejecting it previously discarded the whole MIME type, including the
    declared charset, producing mojibake or gemtext misclassification.
  • A stray unprefixed GOPHER / GEMINI / SERVER environment variable set by
    unrelated tooling no longer crashes startup (it was misread as the nested
    config object).

Changed

  • Gemini binary success responses now return metadata only (size + detected
    MIME type) as a new binary result kind, instead of base64-inlining the full
    body into the model's context. This matches the Gopher binary path and the
    server's documented "binary bodies are returned as metadata only" contract; a
    1 MB body previously shipped ~1.4M base64 characters. Re-fetch the resource
    directly if the raw bytes are needed.
  • Gemtext preformat (code-block) content lines no longer repeat a per-line
    metadata dict (plus duplicated alt_text/language); block-level metadata is
    kept on the opening ``` toggle line only. This roughly thirded the
    serialized size of code blocks sent to the model. Attribute access is
    unchanged; only the serialized output is leaner.
  • The Gopher menu parser now stops once the item cap (max_menu_items) is
    reached instead of building the entire directory before slicing, so a 1 MB
    directory no longer materialises tens of thousands of model objects to keep a
    small slice. Truncation is still flagged on the result.
  • Client-certificate Gemini requests now reuse a per-certificate TLS client
    (and its SSL context) instead of rebuilding it on every request, so the system
    CA bundle load and cert/key PEM reads — blocking work that ran on the event
    loop — happen once per certificate rather than per fetch.
  • Release/CI hygiene: prepare-release.py now bumps the version with an anchored
    match (no longer corrupting target-version / python_version / minversion
    in pyproject.toml) and also updates server.json; GitHub release notes no
    longer drop the last line of each changelog section; all CI/release/publish
    jobs run uv sync --locked so a stale lockfile fails loudly; the
    manual-publish workflow no longer offers a no-op pypi target; Dependabot now
    covers the Docker base image; and the docs site redeploys on src/** changes
    so the mkdocstrings API reference can't drift.

Release Information:

Installation:

pip install gopher-mcp==0.5.0

Verification:
All packages are signed and can be verified using Sigstore.