Skip to content

v0.4.16

Choose a tag to compare

@github-actions github-actions released this 08 May 11:37

Two-track release: (1) the pre-1.0 hardening backlog from the
v0.4.15 audit, plus (2) two installer bugs surfaced when a
maintainer test run showed stale legacy configs were not migrating.

Three of the hardening items are secure-by-default flips that
break existing deployments
which relied on the previous lax
defaults — read each before upgrading. The installer fixes are
non-breaking for anyone whose configs were already correct;
they make the canonical migration path (mcp-aemps install)
actually work for users with legacy entries.

Security

  • BREAKING — uvicorn_host default 0.0.0.0127.0.0.1
    (loopback only).
    Pre-0.4.16 the server bound to all interfaces
    by default, exposing the listener to anyone on the same LAN /
    shared Docker network. CIMA data is public so the residual risk
    was low, but secure-by-default is the right posture. Migration:
    add --bind-all (CLI) — Docker / reverse-proxy use cases — or
    set UVICORN_HOST=0.0.0.0 (env). The shipped Dockerfile and
    docker-compose.yml stack already pass --bind-all, so
    containerised deployments are unaffected. Bare-metal / systemd
    deployments that previously relied on the wildcard bind must
    add the flag explicitly.
  • BREAKING — MCP_AEMPS_DNS_REBINDING_PROTECTION default
    falsetrue.
    Pre-0.4.16 the FastMCP transport accepted
    any Host / Origin header on /mcp by default. The default
    allowed_hosts list covers localhost, 127.0.0.1, [::1]
    and FastAPI TestClient's testserver synthetic host, so dev /
    test workflows are unaffected. Reverse-proxy deployments must
    extend MCP_AEMPS_ALLOWED_HOSTS (and optionally
    MCP_AEMPS_ALLOWED_ORIGINS) to whitelist their public hostname,
    or set MCP_AEMPS_DNS_REBINDING_PROTECTION=false to opt out
    (not recommended).
  • BREAKING — /internal/metrics is fail-closed when
    METRICS_KEY is unset.
    Pre-0.4.16 the endpoint logged a
    startup WARNING and stayed publicly readable. The warning was
    routinely missed in noisy log streams. Now: if METRICS_KEY is
    unset, the endpoint returns 503 metrics disabled: METRICS_KEY is not configured. Migration: set METRICS_KEY in any
    deployment that scrapes /internal/metrics; Prometheus must
    send the matching X-Metrics-Key header. Scrapers that
    previously hit the endpoint anonymously will receive 503 until
    reconfigured — that is intentional.
  • JWT algorithm whitelist documented in CONTRIBUTING.md for
    contributors auditing the verifier.
    Public SECURITY.md keeps
    the threat model generic ("asymmetric-only, no HS256, no
    none") without listing the exact algorithm names + file:line
    of the jwt.decode call. Auditors / forks need that detail —
    it now lives in CONTRIBUTING.md § "Security-relevant code
    (auditor pointers)".

Added

  • mcp-aemps up --bind-all and mcp-aemps dev --bind-all
    flags. Convenience over --uvicorn-host 0.0.0.0 for the Docker
    / reverse-proxy use case. Overrides --uvicorn-host when both
    are passed.
  • CLI nudge: outdated mcp-aemps configs detected. mcp-aemps up/dev now scan installed MCP-client configs for legacy
    default URLs (specifically localhost:8000, the pre-v0.2 default
    port that some users still have in their client configs from
    pre-v0.4 installs) inside our own mcp-aemps entry. When
    detected, prints a yellow advisory panel pointing at
    mcp-aemps install for migration. Read-only — never rewrites
    any file. Detection scoped to our entry, so unrelated legacy
    aliases under the same mcpServers map (e.g. a pre-rename
    aemps-cima) do not produce false positives.
  • CLI nudge: outdated mcp-aemps package. mcp-aemps up/dev
    also pings PyPI synchronously (2-second timeout) and prints a
    yellow advisory panel if the running version is behind the
    latest release. The pre-existing async lifespan check stays for
    background-deployment paths (Docker, systemd) where the CLI
    banner is not visible. Respects MCP_AEMPS_SKIP_UPDATE_CHECK=1.

Fixed

  • Every JSON / TOML installer now purges legacy server-key
    aliases on install.
    Pre-rename releases shipped under
    aemps-cima and mcp-aemps-cima; users who installed during
    the rename window ended up with two stale entries (a working
    mcp-aemps plus a dead alias pointing at localhost:8000).
    Re-running mcp-aemps install (or any per-client subcommand)
    now drops every alias listed in LEGACY_SERVER_KEYS from the
    same write — across Claude Desktop, Claude Code, Cursor,
    Windsurf, JetBrains Junie, Antigravity, VS Code, Zed, and Codex
    CLI. Continue.dev's sentinel-fenced YAML block was already
    isolated and is unaffected. Unrelated entries the user added
    manually (e.g. a personal weather server) are preserved
    exactly as written.
  • Stale-config nudge in mcp-aemps up/dev also detects
    legacy aliases.
    The pre-existing detector only flagged a
    legacy URL inside the mcp-aemps entry; it now also flags any
    config that has a legacy alias key (aemps-cima,
    mcp-aemps-cima) in the relevant servers map. Both signals
    remediate the same way — re-run mcp-aemps install.
  • Claude Code installer no longer reports unchanged without
    comparing content.
    Pre-0.4.16 the installer trusted Claude
    CLI's "already exists" stderr and returned unchanged
    blocking users with stale legacy entries (e.g. the user-reported
    http://localhost:8000/mcp from years-old installs) from
    self-recovering by re-running mcp-aemps install. The CLI path
    now only short-circuits on a clean (exit-zero) add; any other
    exit falls through to the JSON-direct path which reads
    ~/.claude.json, compares against the desired block, and
    correctly reports unchanged vs updated.
  • Tighter installer detection — drop the config-dir heuristic.
    Pre-0.4.16 _check_client_installed treated the existence of a
    client's user-config directory (e.g. %APPDATA%\Claude\,
    ~/.cursor/) as evidence the client was installed. But
    pre-v0.4.13 mcp-aemps installers themselves created those
    directories when writing the config — so the dir survived even
    when the user never installed (or had uninstalled) the client,
    producing systematic false-positive "client detected" reports.
    Detection now requires either a binary on $PATH or one of the
    application's own install paths (per-OS) to exist:
    • Claude Desktop: %LOCALAPPDATA%\AnthropicClaude\ /
      /Applications/Claude.app / /snap/claude-desktop.
    • VS Code, Cursor, Windsurf, Zed, Antigravity: per-OS
      Programs\<App>\<App>.exe / /Applications/<App>.app /
      /snap/bin/<app> etc.
    • Continue.dev: requires the host VS Code / Cursor / Windsurf
      extension dir.
    • JetBrains Junie: requires the JetBrains IDE config root.
      The config_dirs parameter on _check_client_installed and
      _client_not_detected_skip stays for back-compat with downstream
      installers in private repos but is ignored.