Part of #5743. Follow-up to #5953.
Context
#5953 serves MCP 2026-07-28 ("Modern") stateless requests through vMCP behind a default-off startup kill-switch (TOOLHIVE_VMCP_MODERN_STATELESS). When off, well-formed Modern requests fall through to the SDK path (safe version-downgrade) instead of the hand-rolled Modern dispatcher.
The switch exists as a temporary safety lever, not a permanent feature gate. The Modern wire envelope is hand-rolled to mirror go-sdk v1.7.0-pre.3, a version ToolHive does not import (the module is on v1.6.1 via mcpcompat). So:
- there is no compile-time check that the envelope shapes match the real SDK, and
- the envelope tests assert against hand-written expected JSON, not real SDK bytes.
Until that's independently validated, a config-only lever to fall back to the SDK path (rather than revert-and-redeploy) is cheap insurance. See the discussion on #5953.
What to do
Remove the kill-switch and serve well-formed Modern requests unconditionally:
Config.ModernDispatchEnabled and its plumbing (server.Config / ServerConfig, derive.go, serve.go, pkg/vmcp/cli/serve.go env read).
- The
if !s.config.ModernDispatchEnabled branch in classifyingHandler (pkg/vmcp/server/classification.go).
- The
TOOLHIVE_VMCP_MODERN_STATELESS env var and its docs.
- The kill-switch-off tests / the
newRealModernTestServer vs newRealTestServer split introduced to keep the switch on for Modern tests.
(Classification precision already guarantees zero Legacy impact — non-Modern requests never reach the dispatcher regardless — so removal only affects whether Modern is served, not Legacy.)
Blocked on / done when
Do this once Modern serving is validated against the real wire contract, i.e. either:
Must not ship to production/GA with the kill-switch still present.
Part of #5743. Follow-up to #5953.
Context
#5953 serves MCP 2026-07-28 ("Modern") stateless requests through vMCP behind a default-off startup kill-switch (
TOOLHIVE_VMCP_MODERN_STATELESS). When off, well-formed Modern requests fall through to the SDK path (safe version-downgrade) instead of the hand-rolled Modern dispatcher.The switch exists as a temporary safety lever, not a permanent feature gate. The Modern wire envelope is hand-rolled to mirror
go-sdk v1.7.0-pre.3, a version ToolHive does not import (the module is on v1.6.1 viamcpcompat). So:Until that's independently validated, a config-only lever to fall back to the SDK path (rather than revert-and-redeploy) is cheap insurance. See the discussion on #5953.
What to do
Remove the kill-switch and serve well-formed Modern requests unconditionally:
Config.ModernDispatchEnabledand its plumbing (server.Config/ServerConfig,derive.go,serve.go,pkg/vmcp/cli/serve.goenv read).if !s.config.ModernDispatchEnabledbranch inclassifyingHandler(pkg/vmcp/server/classification.go).TOOLHIVE_VMCP_MODERN_STATELESSenv var and its docs.newRealModernTestServervsnewRealTestServersplit introduced to keep the switch on for Modern tests.(Classification precision already guarantees zero Legacy impact — non-Modern requests never reach the dispatcher regardless — so removal only affects whether Modern is served, not Legacy.)
Blocked on / done when
Do this once Modern serving is validated against the real wire contract, i.e. either:
mcpcompatadopts go-sdk v1.7 (Adopt go-sdk v1.7 for MCP 2026-07-28 stateless support #5754) so the Modern shapes are compile-checked and the hand-rolled envelope can be swapped for real SDK types.Must not ship to production/GA with the kill-switch still present.