Skip to content

v0.1.33

Choose a tag to compare

@pandas-studio pandas-studio released this 11 Jul 03:30
fda3561

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)