Skip to content

design(mcpx): honour upstream ttlMs and cacheScope — the pool catalogue cache gets a freshness deadline and a scope #1601

Closed
3 of 3 issues completed

Description

@dezren39

Summary

mcpx's server half honours the 2026-07-28 caching contract; its client half never did. The client drops ttlMs/cacheScope on the floor, the pool's catalogue cache has a timestamp and no expiry, and the on-disk schema cache persists private catalogues and re-serves them after a restart as if they were public and eternally fresh. This design gives the pool cache a freshness deadline and a scope, era-scoped the way the spec is.

Design doc: files/designs/code-mcpx-client-cache-hints.md in the keep-the-four-repos-healthy goal workspace (full audit, alternatives, risks, open questions).

Current state (verified on main 33a4e67, 2026-10-28)

  • Server side landed: internal/mcpserver/server.go stamps ttlMs + cacheScope on complete cacheable results for modern peers (scope table ~L690-706; envelope ~L730-740; values from protoMessages.listMaxAge / readMaxAge settings).
  • Client side missing: list result types in internal/mcpclient/client.go (toolsListResult ~L183, resourcesListResult ~L204, resourceTemplatesListResult ~L209, promptsListResult ~L1117) carry no hint fields; ListTools/ListResources/ListPrompts return bare slices.
  • Pool: Pool.Schemas (internal/pool/pool.go ~L815) serves the cache forever once schemaAt is set; only Invalidate() (list_changed, via internal/daemon/hooks.go) or manual refresh re-reads.
  • Disk: Registry.loadCache/SaveCache (internal/daemon/registry.go ~L249-285) persist and re-seed every catalogue with no TTL applied to FetchedAt and no scope check.
  • The conformance register says it nine times (internal/conformance/coverage_stateful.go:113-121, client gaps under mcpx client: cannot reach a conformant 2026-07-28 server dezren39/darwin-nix#200): "the client ignores ttlMs and cacheScope; the pool keeps upstream lists until list_changed or restart" — plus caching-notification-invalidates (CI: nix flake check intermittently dies with 'No space left on device' in id-test/id-ci #257) unverified.

Proposal (decisions recorded in the design doc)

  • Freshness is era-scoped. Modern upstream: hints rule — absent/zero/negative ttlMs = immediately stale; positive = hard deadline. Legacy upstream: unchanged (cache until list_changed / refresh / restart) — the TTL rules exist only in 2026-07-28, and legacy's invalidation channel is its notifications.
  • Aggregated hints. A list's TTL is the minimum across its pages; its scope is private if any page says so. The pool cache expires at the earliest of its three lists' deadlines.
  • Private never persists. SaveCache skips private catalogues; public disk entries carry deadline + scope (cacheVersion bump) and seed expired if their deadline passed.
  • Stale on error only. A failed refetch of an expired entry serves the stale entry and records the error; a failed first fetch behaves exactly as today.

Phases (each independently landable; filed as sub-issues)

  1. Client hints + pool TTL (modern era) — hint fields/aggregation in internal/mcpclient (incl. templates nextCursor → *string + paging), hint-returning list variants with existing signatures kept as wrappers; pool deadline + Schemas() expiry; five caching-* gaps retired.
  2. Scope, disk persistence, stale-on-error — scope plumbing, private-never-persisted, expired-on-load seeding, stale-on-refetch-failure; caching-private-no-cross-auth retired. Gated on Phase 1.
  3. Truth-up + notification verification + origin note — the missing list_changed-invalidates-cache test; docs/compare/register/pagination-caching.md PG-08..PG-13 rewritten as-built; remaining gaps retired with reasons; roadmap row updated; evidence comment on mcpx client: cannot reach a conformant 2026-07-28 server dezren39/darwin-nix#200 (comment, not close — that umbrella tracks other rows). Gated on Phases 1–2.

Open questions stay in the design doc (resources/read client caching, discover/era TTL, a legacy default TTL knob, per-kind deadlines, background revalidation) — they are questions, not issues.

Related

Acceptance criteria

Activity

  1. added
    priority/normalOrdinary priority (the default)
    app/mcpxPackage/app: mcpx (pkgs/ or apps/ in this repo)
    epicMeta-issue grouping multiple items (org Project Type=Epic)
    effort/lLarge: multi-day or open-ended; expect staged check-ins
    kind/designA design proposal (design-architect): multi-step, phased, decision-bearing
    on Oct 28, 2026
  2. developing-today commented on Oct 28, 2026

    @developing-today
    Contributor
  3. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

  4. added
    meta/enrichedIntake review done: acceptance criteria, links, and normalized labels added
    on Oct 28, 2026
  5. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    Intake review

    Related: phase issues #1602 (Phase 1, PR #1608 in CI), #1603 (Phase 2), #1604 (Phase 3) carry the implementation; dezren39/darwin-nix#200 holds the conformance-register evidence. No merged PR resolves this design issue (checked this run).
    Notes: the server half already landed on main; this epic closes when its three phases merge and the register is truthed up. Labels were already complete (kind/design, source/design-architect, priority/normal, effort/l, app/mcpx) — this pass adds only the standard acceptance section and meta/enriched.
    Risks: era-scoping is the sharp edge — applying modern TTL rules to a legacy upstream would thrash the catalogue cache; the phase issues carry that boundary.
    Suggested approach: let the phases land in order (#1602 → #1603 → #1604); close this epic from the #1604 completion note with the register diff linked.


    🤖 Agent note · filed

    • Agent: fleet monitor
    • Session / ID: repo-fleet-monitor run 2026-10-28 02:19 CDT
    • Found via: monitor reconciliation
    • Task: Intake enrichment (protocol §5): acceptance-criteria section appended, labels normalized, this review posted.
    • Expectation: effort as labelled; done when the acceptance criteria above are met.
  6. 1 remaining item

  7. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    Phase 3 landed — the pagination-caching slice is complete (PR #2181)

    #1604 was the last phase of this design. Merged as PR #2181 (318ca58a17f944d47759a75c094e4ab090e83f47, 2026-10-29), closing #1604.

    • New test: daemon.TestListChangedInvalidatesPoolCache — a modern list_changed notification (tools, resources, prompts) empties the pool catalogue cache (timestamp + deadline forgotten), so the next read re-lists instead of serving the stale catalogue. This retires the caching-notification-invalidates gap, which was the last unverified one.
    • Gaps retired with recorded reasons (nothing silently dropped): caching-may-refetch-early-serve-stale (a MAY mcpx does not take — refresh is synchronous on read, the decision recorded here), caching-page-refetch and caching-key-method-params (not applicable by construction — one aggregated catalogue per configured server; resources/read is not pool-cached). Reasons live in overrides/stateful.json and the register, and flow into the regenerated requirements.json.
    • Register truth-up: docs/compare/register/pagination-caching.md PG-08..PG-13 now describe the post-Phase-1-2 as-built state with code evidence instead of the pre-fix "none of the six carry them" text.
    • Roadmap: the "Legacy client robustness" row in planning/roadmaps/mcpx.md names the caching slice as landed.
    • No new caching behaviour was added — that stays out of scope per the open questions in this design.

    With Phases 1 (#1602 / PR #1608), 2 (#1603 / PR #1705) and 3 (#1604 / PR #2181) merged, the ttlMs/cacheScope freshness-deadline slice of this design is delivered. Remaining items in the body are the ones explicitly deferred (e.g. resources/read result caching, discover TTL, a legacy default TTL) and remain open design questions, not implementation gaps in the conformance register.

  8. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    Program tending — all sub-issues closed, proposing closure

    Program-tender check (2026-10-29): all 3 sub-issues of this design epic are now closed — #1602 (closed 2026-10-28T11:26Z), #1603 (2026-10-28T22:03Z), #1604 (2026-10-29T08:45Z) — and the Phase 3 landed comment above already records the slice as complete (PR #2181).

    Proposing this epic be closed as complete, so the epic list only carries designs with work still owed.

  9. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed on Nov 1, 2026
  10. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  11. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · triage verdict — ALREADY DONE; closing with evidence (task 2613)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/mcpxPackage/app: mcpx (pkgs/ or apps/ in this repo)effort/lLarge: multi-day or open-ended; expect staged check-insepicMeta-issue grouping multiple items (org Project Type=Epic)kind/designA design proposal (design-architect): multi-step, phased, decision-bearingmeta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedpriority/normalOrdinary priority (the default)source/design-architectFiled by the repo design architect job

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions