v0.4.16
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_hostdefault0.0.0.0→127.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
setUVICORN_HOST=0.0.0.0(env). The shippedDockerfileand
docker-compose.ymlstack 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_PROTECTIONdefault
false→true. Pre-0.4.16 the FastMCP transport accepted
anyHost/Originheader on/mcpby default. The default
allowed_hostslist coverslocalhost,127.0.0.1,[::1]
and FastAPI TestClient'stestserversynthetic host, so dev /
test workflows are unaffected. Reverse-proxy deployments must
extendMCP_AEMPS_ALLOWED_HOSTS(and optionally
MCP_AEMPS_ALLOWED_ORIGINS) to whitelist their public hostname,
or setMCP_AEMPS_DNS_REBINDING_PROTECTION=falseto opt out
(not recommended). - BREAKING —
/internal/metricsis fail-closed when
METRICS_KEYis unset. Pre-0.4.16 the endpoint logged a
startupWARNINGand stayed publicly readable. The warning was
routinely missed in noisy log streams. Now: ifMETRICS_KEYis
unset, the endpoint returns503 metrics disabled: METRICS_KEY is not configured. Migration: setMETRICS_KEYin any
deployment that scrapes/internal/metrics; Prometheus must
send the matchingX-Metrics-Keyheader. Scrapers that
previously hit the endpoint anonymously will receive 503 until
reconfigured — that is intentional. - JWT algorithm whitelist documented in
CONTRIBUTING.mdfor
contributors auditing the verifier. PublicSECURITY.mdkeeps
the threat model generic ("asymmetric-only, noHS256, no
none") without listing the exact algorithm names + file:line
of thejwt.decodecall. Auditors / forks need that detail —
it now lives inCONTRIBUTING.md§ "Security-relevant code
(auditor pointers)".
Added
mcp-aemps up --bind-allandmcp-aemps dev --bind-all
flags. Convenience over--uvicorn-host 0.0.0.0for the Docker
/ reverse-proxy use case. Overrides--uvicorn-hostwhen both
are passed.- CLI nudge: outdated mcp-aemps configs detected.
mcp-aemps up/devnow scan installed MCP-client configs for legacy
default URLs (specificallylocalhost:8000, the pre-v0.2 default
port that some users still have in their client configs from
pre-v0.4 installs) inside our ownmcp-aempsentry. When
detected, prints a yellow advisory panel pointing at
mcp-aemps installfor migration. Read-only — never rewrites
any file. Detection scoped to our entry, so unrelated legacy
aliases under the samemcpServersmap (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. RespectsMCP_AEMPS_SKIP_UPDATE_CHECK=1.
Fixed
- Every JSON / TOML installer now purges legacy server-key
aliases on install. Pre-rename releases shipped under
aemps-cimaandmcp-aemps-cima; users who installed during
the rename window ended up with two stale entries (a working
mcp-aempsplus a dead alias pointing atlocalhost:8000).
Re-runningmcp-aemps install(or any per-client subcommand)
now drops every alias listed inLEGACY_SERVER_KEYSfrom 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 personalweatherserver) are preserved
exactly as written. - Stale-config nudge in
mcp-aemps up/devalso detects
legacy aliases. The pre-existing detector only flagged a
legacy URL inside themcp-aempsentry; 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-runmcp-aemps install. - Claude Code installer no longer reports
unchangedwithout
comparing content. Pre-0.4.16 the installer trusted Claude
CLI's"already exists"stderr and returnedunchanged—
blocking users with stale legacy entries (e.g. the user-reported
http://localhost:8000/mcpfrom years-old installs) from
self-recovering by re-runningmcp-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 reportsunchangedvsupdated. - Tighter installer detection — drop the config-dir heuristic.
Pre-0.4.16_check_client_installedtreated 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$PATHor 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.
Theconfig_dirsparameter on_check_client_installedand
_client_not_detected_skipstays for back-compat with downstream
installers in private repos but is ignored.
- Claude Desktop: