Skip to content

docs(058): implementation plan for the MCP 2026-07-28 upgrade - #1202

Merged
Dumbris merged 4 commits into
mainfrom
058-mcp-2026-upgrade
Sep 3, 2026
Merged

Dumbris merged 4 commits into
mainfrom
058-mcp-2026-upgrade

Conversation

@Dumbris

@Dumbris Dumbris commented Sep 3, 2026

Copy link
Copy Markdown
Member

Related #532

Phase 0 and Phase 1 artifacts for spec 058, written from a verified probe of mark3labs/mcp-go v1.0.0 stable rather than from the beta-era spec text. Docs only, no code change.

What the probe established

  • Production code compiles unchanged on both editions. The only break is a test symbol: NewTestStreamableHTTPServer moved to server/servertest (32 call sites, 6 files).
  • The full internal/server suite under v1.0.0 fails on exactly the two known profile tests and nothing else, which closes the SC-008 question for that package.
  • Two statements in the spec's Dependency Gate are stale for stable: the v1.0.0 client is modern-first rather than capped at 2025-11-25, and "zero compile errors" no longer holds.

Decisions recorded

Spec-057 conflict → Option A, plus two mandatory grafts. The /mcp/p/<slug> URL path is already request-carried identity, so it survives the stateless era with no routing changes. The grafts: gate resolver tier 3 on the era, because stdio session ids are the constant "stdio" and the empty-id guard alone would let modern stdio requests persist a selection; and add a list-only resolver, which also fixes a pre-existing FR-012 violation where prompts/list varies by connection after set_profile.

The bump alone flips the upstream-facing default. connection_lifecycle.go:19 sends mcp.LATEST_PROTOCOL_VERSION, now 2026-07-28, so bumping the library makes mcpproxy speak the new protocol to every capable upstream before any of this work lands. The plan pins both directions in the bump PR and lifts them separately.

FR-015/FR-016 cannot be satisfied through the v1.0.0 public client API. CallTool hard-wires the multi-round-trip loop and the single-shot entry points are unexported, so a proxy cannot relay MRTR at all. The plan proposes detect-and-frame plus a spec amendment and stops for your ratification rather than implementing around an unratified MUST. FR-018/SC-005 are separately vacuous: mcpproxy proxies no resources.

Two findings worth separate attention

  • Security. mcp-go keys in-flight cancellations as "<sessionID>:<requestID>", and every modern request has an empty session id, so two clients that pick the same JSON-RPC id can cancel each other's calls. The FR-028 pin masks this today; it must be resolved before the pin lifts, and reported upstream.
  • Spec-032 tool hashes are computed from the library-decoded schema, so a decoder change can re-flag unchanged tools as rug-pulls. Measured against a real 1096-tool database: zero exposure, because no upstream in that sample emits draft-07 local refs. Mitigation is a three-line normalizer fix plus a four-fixture guard test, not a migration.

What I need from you

Ratify (or reject) the FR-015/FR-016 and FR-018 amendments. speckit.tasks is blocked on that decision.

Related #532

Phase 0 + Phase 1 artifacts for spec 058, written from a verified probe of
mark3labs/mcp-go v1.0.0 stable rather than from the beta-era spec text.

## What the probe established

- Production code compiles unchanged on both editions. The only break is a
  test symbol: NewTestStreamableHTTPServer moved to server/servertest
  (32 call sites, 6 files).
- The full internal/server suite under v1.0.0 fails on exactly the two known
  profile tests and nothing else, which closes the SC-008 question for that
  package.
- Two statements in the spec's Dependency Gate are now stale: the v1.0.0
  client is modern-first, not capped at 2025-11-25, and "zero compile errors"
  no longer holds for stable.

## Decisions recorded

- Spec-057 conflict: Option A (the /mcp/p/<slug> URL path is already
  request-carried identity) plus two mandatory grafts — gate resolver tier 3
  on the era, because stdio session ids are the constant "stdio" and the
  empty-id guard alone would let modern stdio requests persist a selection;
  and a list-only resolver, which also fixes a pre-existing FR-012 violation
  where prompts/list varies by connection after set_profile.
- The library bump alone flips the upstream-facing default to 2026-07-28,
  so the plan pins both directions in the bump PR and lifts them separately.
- FR-015/FR-016 cannot be satisfied through the v1.0.0 public client API:
  CallTool hard-wires the multi-round-trip loop and the single-shot entry
  points are unexported. The plan proposes detect-and-frame plus a spec
  amendment, and stops for ratification rather than implementing around it.
- FR-018/SC-005 are vacuous today: mcpproxy proxies no resources.

## Two findings worth separate attention

- Security: mcp-go keys in-flight cancellations as "<sessionID>:<requestID>",
  and every modern request has an empty session id, so two clients using the
  same JSON-RPC id can cancel each other's calls. Masked by the FR-028 pin;
  must be resolved before that pin lifts.
- Spec-032 tool hashes are computed from the library-decoded schema, so a
  decoder change can re-flag unchanged tools as rug-pulls. Measured against a
  real 1096-tool database: zero exposure. Mitigation is a normalizer fix plus
  a guard test, not a migration.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 3, 2026 •

Copy link
Copy Markdown

Deploying mcpproxy-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: 56bbe22
Status: ✅  Deploy successful!
Preview URL: https://fd589cf0.mcpproxy-docs.pages.dev
Branch Preview URL: https://058-mcp-2026-upgrade.mcpproxy-docs.pages.dev

View logs

@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@github-actions

github-actions Bot commented Sep 3, 2026 •

Copy link
Copy Markdown
Contributor

📦 Build Artifacts

Workflow Run: View Run
Branch: 058-mcp-2026-upgrade

Available Artifacts

  • archive-darwin-amd64 (29 MB)
  • archive-darwin-arm64 (26 MB)
  • archive-linux-amd64 (17 MB)
  • archive-linux-arm64 (15 MB)
  • archive-windows-amd64 (29 MB)
  • archive-windows-arm64 (26 MB)
  • frontend-dist-pr (0 MB)
  • installer-dmg-darwin-amd64 (23 MB)
  • installer-dmg-darwin-arm64 (21 MB)

How to Download

Option 1: GitHub Web UI (easiest)

  1. Go to the workflow run page linked above
  2. Scroll to the bottom "Artifacts" section
  3. Click on the artifact you want to download

Option 2: GitHub CLI

gh run download 33781692949 --repo smart-mcp-proxy/mcpproxy-go

Note: Artifacts expire in 14 days.

… breakdown

Related #532

Applies the spec amendments the v1.0.0 probe made necessary, and turns the
plan into 79 dependency-ordered tasks.

## Amendments (decided under the zero-interruption policy, rationale inline)

- FR-015/FR-016: detect-and-frame. MRTR relay cannot be built on the v1.0.0
  public client API — CallTool hard-wires the round-trip loop and the
  single-shot entry points are unexported — so the original text had no
  satisfying implementation. True relay becomes FR-016a, gated on upstream
  library changes, with a sealed-envelope design of record.
- FR-016b (new): stop copying the upstream result envelope wholesale, or an
  upstream input_required marker reaches clients as mcpproxy's own.
- FR-007: scoped to requests. No header path exists for notifications and
  mcpproxy originates none, so the original wording was untestable.
- FR-018/SC-005: vacuous today; mcpproxy proxies no resources. Kept for
  future resource proxying rather than implemented as dead code.
- FR-027: now names both hops. Under the original single-default reading the
  library bump alone would have violated it.
- SC-006: the fetch-reduction clause is withdrawn as unmeasurable from
  mcpproxy's side; the hints-present half stands.
- Dependency Gate: corrected the two claims the stable probe falsified.

## Task ordering

Two constraints override raw priority. Both hops are pinned in Phase 2
before anything else, and US3 (stateless readiness) fully lands before US1
lifts the client-facing pin — lifting first would expose the cross-client
cancellation collision to real users rather than to tests.

The MVP is Phases 1-2: library current, wire provably unchanged, and two
latent defects fixed. Increment 2 (US3) pays down FR-012/FR-013 debt that
exists on main today, independent of ever serving the new protocol.
…jected

Related #532

The amendments were cross-reviewed as the repo convention requires. The
review confirmed two and rejected the reasoning behind three, plus one factual
detail. Corrected here with the original claim and its withdrawal both left
visible, so a later reader can see what was believed and why it was wrong.

- FR-015/FR-016: the claim that MRTR relay "cannot be built on the public
  client API" was WRONG. SendRequest is exported on the transport interface,
  mcpproxy constructs that transport itself, and GetTransport returns it, so
  relay is buildable today. The decision to defer stands, but on cost — a
  second dispatch path bypassing everything internal/upstream/core layers on
  CallTool — not on impossibility. FR-016a now names the concrete starting
  point instead of a nonexistent blocker.
- FR-007: both stated reasons were wrong. Static and func headers DO reach
  notifications through sendHTTP, and mcpproxy does originate one
  (notifications/initialized, sent by the library during the handshake). Only
  the per-method half is genuinely out of reach, because WithHTTPHeaderFunc
  takes a context and cannot know the method it is stamping.
- SC-006: "unmeasurable from mcpproxy's side" was overstated. The existing
  AddBeforeAny hook sees every method and resolves a session, so a per-client
  tools/list counter would measure it. The counter and a baseline are missing,
  not the possibility.
- FR-018: there are two AddResource call sites, not one. Both are schema
  compiler registrations, so the conclusion is unchanged.

Confirmed unchanged: FR-027 (the constant really was redefined) and the
FR-016b design (an empty ResultType is filled with "complete" by the
decorator).

Also recorded, because it cost a full review cycle: the first cross-review
returned a FALSE CLEAN. It exited having auto-rejected its own reads of the
module cache, so it verified nothing and its silence was indistinguishable
from approval. Evidence had to be staged inside the repo before it could see
anything. A cross-review that produced no verdict text has not run.
Related #532

The Phase 1-2 implementation review confirmed four findings. Two were fixed in
the code; the other two are real but out of scope for a wire-inert bump, so
they become US3 tasks rather than claims that they are "tracked" somewhere.

- T036a: the era pin covers Streamable HTTP only. mcp-go has no stdio
  equivalent and the era is chosen per request by the shared handler, so a
  stdio client can opt into 2026-07-28 today. Not reachable by default, since
  config validation rewrites an empty listen address to the HTTP default.
- T036b: nothing asserts the direct-mode handler calls proxyResultEnvelope, so
  FR-016b on /mcp/all rests on the call site staying as written. Reaching that
  handler needs the wired-proxy harness US3 builds.

research.md gains D10 with the full outcome, including two things worth
remembering about the review itself: the stdio gap was raised by four of six
lenses at "major" before verification settled it at minor, and three verify
agents died on API errors, so the confirmed set is a floor rather than a
ceiling.
@Dumbris
Dumbris merged commit ca66fbf into main Sep 3, 2026
50 checks passed
@Dumbris Dumbris mentioned this pull request Sep 7, 2026
2 of 3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants