Part of #5756. Design: RFC THV-0083 (D2, D4, Phase 2, Configuration Changes); arch doc §"Server side", §"server/discover", §"Rollback / kill switch". Security-critical.
Serve Modern (2026-07-28) stateless requests through vMCP by bypassing the Serve session layer and dispatching straight to the already-stateless core.
Changes
- Replace
var mcpHandler http.Handler = streamableServer (server.go:607) with a classifying handler: Modern → hand-rolled dispatcher, everything else → SDK server unchanged.
- Direct core dispatch for
tools/list/tools/call/resources/read/prompts/get.
- From-scratch JSON-RPC/
resultType envelope — v1.6.1 has no Modern wire shapes and v1.7's resultType is unexported, so it cannot be lifted. Reuse mcpcompat's dispatch/successResponse/errorResponse skeleton and error-code mapping; match v1.7 wire shape byte-for-byte so the eventual v1.7 swap is delete-and-repoint. Validate against the v1.7.0-pre.1 conformance testdata.
404/-32601 for unimplemented methods; notifications (no id) → 202/drop; reject JSON-RPC batches with a defined error.
- Re-home what the bypassed SDK server owned: re-invoke
authzCallGate and translate Denial→HTTP 403 (preserving audit outcome:"denied", not a 200 tool-error); apply header-forward from context on the outgoing backend call.
- Serve
server/discover as a post-admission capability-flags envelope (no descriptor arrays), computed through the same admission seam as core.List*; add its authz-map entry together with that filtered response. Emit required CacheableResult fields (ttlMs:0, cacheScope:"private" interim).
- Dedicated startup kill-switch flag, Modern-off by default.
Composite tools work in this phase with the pod-local in-memory store (composites run synchronously within one tools/call, so state is request-local).
Dependencies
#5909 (Phase 1 classifier wiring). Independent of the go-sdk v1.7 bump (#5754).
Verification
- Per-method dispatch; envelope matches v1.7 conformance testdata;
404/-32601; notification 202/drop; batch rejection.
- Denied
tools/call → HTTP 403 and audit outcome:"denied" (not a 200 tool-error).
server/discover carries no descriptors; flags reflect admission (empty admitted set → no advertised flag); authz-map entry gated on the post-admission envelope.
- Legacy path untouched.
Notes
Split into PRs: (a) dispatcher + envelope + re-homing + kill switch, (b) server/discover post-admission envelope + authz-map entry. The envelope is the main new-code and correctness surface.
Watch-item (not a blocker): computing discover flags post-admission runs the same fan-out as tools/list on a probe the spec expects to be cheap/cacheable — a short-TTL per-identity capability cache is the measure-first mitigation, tied to #5761.
Part of #5756. Design: RFC THV-0083 (D2, D4, Phase 2, Configuration Changes); arch doc §"Server side", §"server/discover", §"Rollback / kill switch". Security-critical.
Serve Modern (2026-07-28) stateless requests through vMCP by bypassing the Serve session layer and dispatching straight to the already-stateless core.
Changes
var mcpHandler http.Handler = streamableServer(server.go:607) with a classifying handler: Modern → hand-rolled dispatcher, everything else → SDK server unchanged.tools/list/tools/call/resources/read/prompts/get.resultTypeenvelope — v1.6.1 has no Modern wire shapes and v1.7'sresultTypeis unexported, so it cannot be lifted. Reusemcpcompat'sdispatch/successResponse/errorResponseskeleton and error-code mapping; match v1.7 wire shape byte-for-byte so the eventual v1.7 swap is delete-and-repoint. Validate against thev1.7.0-pre.1conformance testdata.404/-32601for unimplemented methods; notifications (noid) →202/drop; reject JSON-RPC batches with a defined error.authzCallGateand translateDenial→HTTP 403 (preserving auditoutcome:"denied", not a 200 tool-error); apply header-forward from context on the outgoing backend call.server/discoveras a post-admission capability-flags envelope (no descriptor arrays), computed through the same admission seam ascore.List*; add its authz-map entry together with that filtered response. Emit requiredCacheableResultfields (ttlMs:0,cacheScope:"private"interim).Composite tools work in this phase with the pod-local in-memory store (composites run synchronously within one
tools/call, so state is request-local).Dependencies
#5909 (Phase 1 classifier wiring). Independent of the go-sdk v1.7 bump (#5754).
Verification
404/-32601; notification202/drop; batch rejection.tools/call→ HTTP 403 and auditoutcome:"denied"(not a 200 tool-error).server/discovercarries no descriptors; flags reflect admission (empty admitted set → no advertised flag); authz-map entry gated on the post-admission envelope.Notes
Split into PRs: (a) dispatcher + envelope + re-homing + kill switch, (b)
server/discoverpost-admission envelope + authz-map entry. The envelope is the main new-code and correctness surface.Watch-item (not a blocker): computing discover flags post-admission runs the same fan-out as
tools/liston a probe the spec expects to be cheap/cacheable — a short-TTL per-identity capability cache is the measure-first mitigation, tied to #5761.