You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
Upgrade notes
Per-server retry/timeout/cache knobs now hot-reload (#660): max_retries, call_timeout_seconds, overall_deadline_seconds, reconnect delays, cache, and cache_ttl_seconds previously froze at connect time; they are
now read per call from the hot-reloaded config. Connection-affecting edits
(transport/url/headers/command/args/env) reconnect live on the
next uncached call. prefix and circuit_* stay restart-only.
connect_timeout_seconds is now an end-to-end connect/discovery
deadline (#660): one shared budget over transport entry, MCP initialize(), and tools/list — previously only initialize() was
bounded, so a hung connect or stalled discovery blocked forever.
One-time response-cache wipe on first start after upgrading (#659, #655): the cache narrows to envelope-safe rows (successful, text-only, no structuredContent/_meta) and the key gains the call's _context_query
plus a compression-config fingerprint; both changes bump the cache schema,
purging existing rows once (entries repopulate on use).
Non-text upstream errors now surface as tool errors (#659): previously
they were returned as successful non-text responses.
New config files write "tool_annotation_policy": "strict" (#658):
fresh setups cache only tools declaring readOnlyHint: true. Existing
configs keep the conservative default and are never retro-migrated;
loading one logs a migration advisory.
mms add rejects a duplicate --prefix (#654): exit 1 with the config
file untouched, instead of warning and saving a config the runtime
validator then refuses to load.
Registration aborts on a corrupt .mcp.json (#653): mms init / mms register now fail with exit 1 and leave the file byte-identical,
instead of "succeeding" by overwriting it with only the memtomem-stm entry.
Added
mms doctor — one read-only diagnostic pass over the whole setup:
config file presence, JSON validity, schema validation, per-transport
required fields, prefix conflicts (same shared validators the server's
load path enforces), a staged connection probe per upstream, the
cache-policy advisory, and the LTM probe. Each check prints PASS/WARN/FAIL with a runnable next: command; exit code is 1 on
any FAIL and 0 on WARN-only, making doctor the scriptable success gate
for a fresh install. The LTM check never FAILs — an unconfigured or
unreachable LTM only disables memory surfacing, not the proxy core. (#661)
Staged probe results in mms health / mms add --validate: a failing
upstream now reports the last stage that completed (configured → transport connected → MCP initialized → tools discovered) instead of a
bare boolean, so a dead binary, a broken MCP handshake, and a failing tools/list are distinguishable. health --json server entries gain
additive stage / failed_stage / transport keys (existing connected / tools / overflowing / error fields unchanged). (#661)
Live reconnect for connection-affecting per-server config edits.
Hot-reloaded changes to transport / url / headers / command / args / env (and connect_timeout_seconds on network transports) are
now applied on the next uncached call to that upstream: the replacement
connection is fully established first, then swapped in and the old one
closed. If the edited config can't connect, the old connection keeps
serving and the failed edit is attempted once — not per call — until the
config changes again. Reconnects (including failure-triggered ones) now
read the current config snapshot instead of the connect-time one. Behavior change: per-server retry/timeout/cache knobs (max_retries, call_timeout_seconds, overall_deadline_seconds, reconnect delays, cache, cache_ttl_seconds) previously froze at connect time; they are
now read per call from the hot-reloaded config, as the docs' hot-reload
table already promised. A successful config-change reconnect also closes
the upstream's circuit breaker, so a fixed url isn't fast-failed by the
old config's failure streak. prefix and circuit_* stay restart-only.
(#660)
Behavior change: connect_timeout_seconds is now an end-to-end
connect/discovery deadline — one shared budget over transport entry
(process spawn / HTTP connect), MCP initialize(), and the tools/list
discovery call, applied identically at first connect and every reconnect.
Previously only initialize() was bounded, so a hung TCP connect or a
stalled tools/list blocked forever; a slow phase also no longer grants
later phases a fresh window. For sse / streamable_http the value is
additionally passed to the SDK client factory as its HTTP connect timeout= (the stream read timeout stays at the SDK default). The
per-upstream timeout contract (connect/discovery vs per-attempt call_timeout_seconds vs overall_deadline_seconds) is now documented
in docs/configuration.md. (#660)
MCP result-envelope preservation through the proxy. tools/list now
advertises the upstream tool's outputSchema and _meta; call results
carrying structuredContent or result-level _meta return them verbatim
(text content is still compressed — clients consuming structuredContent
get full fidelity), and content-block order is preserved (the processed
text is reinserted at the upstream's first-text position instead of
always leading). Behavior change: the response cache narrows to
envelope-safe rows — only successful, text-only responses without structuredContent/_meta are stored (errors and non-text responses
were already uncached) — and the cache schema bump wipes existing rows
once on first start after upgrading (one-time cold start; entries
repopulate on use). (#659)
Behavior change: new config files are created with an explicit "cache": {"tool_annotation_policy": "strict"} — mms init, mms add
against a missing config, and mms add --from-clients all write it, so
fresh setups cache only tools that declare readOnlyHint: true. The
schema default stays conservative: existing configs without the key
keep their behavior and are never retro-migrated, but loading one now
logs a one-line migration advisory (also shown by mms config validate;
suppressed when the cache is disabled or an env override sets the
policy). The per-tool / per-server cache: true override is the
strict-mode allowlist for un-annotated read-only tools — no new setting.
(#658)
mms add --header KEY=VALUE (repeatable) registers HTTP headers for sse / streamable_http upstreams. Headers now also flow through --from-clients / mms init import discovery and the mms add --validate / mms health probes — previously the CLI dropped them
everywhere even though the config schema and runtime transport already
supported them, so header-authenticated servers failed import and probe.
Header values are stored in plaintext in the config file (0600 perms); --json outputs mask them. --header with --transport stdio is
rejected (header_requires_http). (#656)
Fixed
Probe failure messages no longer echo configured secrets. Upstream and
LTM probe errors rendered by mms health / mms doctor / mms add --validate / import flows are sanitized against the server's
own env and headers values and URL credentials (longest-first,
empty-safe replacement) before display — previously an upstream
exception that embedded an Authorization header (e.g. a 401 body)
reached the terminal and --json output verbatim. (#661)
Behavior change: a non-text-only (or empty-content) upstream error
now surfaces as a tool error. Previously the no-text passthrough
early-return ran before the isError check, so such an error was
returned to the client as a successful non-text response; it now raises
with a [upstream error: non-text error content] placeholder message
and is recorded as an upstream error in the metrics. (#659)
mms add's invalid_env diagnostics no longer echo the raw --env
argument: a malformed pair (--env =tok, or a bare token missing KEY=)
is likely a stray credential, and both stderr and the --json error
payload are routinely piped to CI logs. The messages now name the 1-based
argument position instead. The dangerous-key diagnostic still names the
offending KEY (keys are not secret-bearing). Mirrors the --header
diagnostics in #656. (#657)
Behavior change: the response-cache key now includes the call's _context_query and a fingerprint of the resolved compression settings.
The cache stores the compressed body, and compression is query-aware
(BM25 relevance budgets) and config-dependent — previously the same
tool+args under a different query context, or after a compression-setting
hot reload, was served a body compressed for another query / under old
settings. Consequences: a one-time full cache purge on first start after
upgrade (key schema v2, tracked via SQLite user_version); callers passing
a per-turn-varying _context_query re-fetch instead of hitting the cache;
compression-config changes immediately stop old rows from being served.
(#655)
Behavior change: mms add now rejects a duplicate --prefix (exit 1, duplicate_prefix in --json mode, config file untouched) instead of
warning and saving a config the proxy's runtime validator then refuses to
load. The interactive prefix prompts (mms init, add --from-clients)
re-prompt on a colliding prefix. Prefix format/uniqueness rules now live in
one shared module (proxy/prefixes.py) used by both the CLI pre-save
checks and the runtime ProxyConfig validators, so the two sides cannot
diverge again. (#654)
Behavior change: client registration (mms init / mms register) now
aborts when the target directory's .mcp.json cannot be parsed or merged,
instead of overwriting it. The writer fell back to {} when the existing
file was unreadable or invalid JSON — the subsequent write silently
discarded every registration already in the file — and replaced a
valid-but-wrong-shape top level or mcpServers wholesale. Registration now
fails with exit 1 and leaves the file byte-identical, reporting the JSON
parse position and a recovery hint; a missing file still creates a fresh
one, and a valid file still merges, preserving sibling registrations and
unknown top-level fields. (#653)