-
Notifications
You must be signed in to change notification settings - Fork 198
[vMCP] Implement SessionManager and wire up behind feature flag (Phase 2) #3866
Description
Depends on #3865
Implement SessionManager and wire it into the vMCP server behind a sessionManagementV2 feature flag (default false). The old code path must remain fully functional when the flag is disabled.
SessionManager bridges domain logic (Session/SessionFactory) to the MCP SDK protocol by implementing the SDK's SessionIdManager interface. It delegates all session storage to transportsession.Manager, avoiding a parallel storage path and automatically inheriting pluggable backend support (LocalStorage today, RedisStorage in future).
New files:
pkg/vmcp/server/session_manager.go—SessionManagerimplementationpkg/vmcp/config/config.go— addsessionManagementV2flag (defaultfalse)
Key methods (implements SDK's SessionIdManager):
Generate() string— phase 1 of the two-phase creation pattern: creates a unique session ID, stores an empty placeholder viasessionStorage.AddSession(), returns the ID to the SDK. No context available at this point.CreateSession(ctx, identity, backends) (string, error)— phase 2: called from theOnRegisterSessionhook once context is available; callsSessionFactory.MakeSession()to build the fully-formed session and replaces the placeholder in storage.Validate(sessionID string) (isTerminated bool, err error)— checks whether a session exists and is active viasessionStorage.Get().Terminate(sessionID string) (isTerminated bool, err error)— loads the session, callsClose()to release all backend clients, then removes it from storage viasessionStorage.Delete().GetAdaptedTools(sessionID string) []mcp.Tool— loads the session, converts its domainTooltypes to SDK format, and attaches handlers that delegate tosession.CallTool().
Files to modify: pkg/vmcp/server/server.go, pkg/vmcp/server/hooks.go
Dual-layer storage model: SessionManager must preserve the separation between the serializable metadata layer (stored via transportsession.Manager) and the non-serializable runtime layer (MCP clients, routing table, held in-process only). When RedisStorage is plugged in, session metadata must persist automatically without any changes to SessionManager. Runtime state is always recreated on demand.
Acceptance Criteria
-
SessionManageris implemented and delegates all storage totransportsession.Manager(no separatesync.Mapor parallel storage) -
SessionManagercorrectly implements the SDK'sSessionIdManagerinterface -
sessionManagementV2config flag exists and defaults tofalse - When flag is
false, existing behaviour is completely unchanged and all existing tests pass - When flag is
true,SessionManagerhandles session creation, tool routing, validation, and termination -
Generate()stores an empty placeholder and returns a unique ID without requiring context -
CreateSession()is invoked from theOnRegisterSessionhook, builds a fully-formed session viaSessionFactory, and replaces the placeholder in storage -
Validate()returnsisTerminated = truefor unknown or expired session IDs -
Terminate()callsClose()on the session before removing it from storage, ensuring backend clients are released -
GetAdaptedTools()returns tool handlers that delegate tosession.CallTool() - Plugging in
RedisStorageinstead ofLocalStoragerequires no changes toSessionManager— the storage interface is the only coupling point - Integration tests cover: session creation via
POST /mcp initialize, tool call routing to correct backend, session termination releasing clients,Validate()on valid and expired sessions, old code path unaffected when flag is disabled