Skip to content

[vMCP] Define Session and SessionFactory interfaces (Phase 1) #3865

@yrobla

Description

@yrobla

Introduce the core interfaces and default implementations for the new session-scoped architecture described in THV-0038. This is purely additive — no changes to existing flows or existing tests.

New files:

  • pkg/vmcp/session/session.goSession interface (domain object: CallTool, ReadResource, GetPrompt, Tools, Resources, Prompts, BackendSessions, Close)
  • pkg/vmcp/session/factory.goSessionFactory interface and defaultSessionFactory
  • pkg/vmcp/session/default_session.godefaultSession embedding transportsession.Session for metadata, owning backend clients in an internal map, tracking backend session IDs

Key requirements:

  • Factory initializes clients per backend in parallel (errgroup, bounded concurrency configurable via max_backend_init_concurrency, default 10, per-session not global)
  • Per-backend timeout so a slow backend does not block session creation
  • Partial initialization: log warnings for failed backends, continue with successful ones
  • Thread safety: sync.RWMutex protecting client map; RLock released before network I/O; sync.WaitGroup in-flight counter so Close() waits for in-flight calls before tearing down clients
  • Close() closes all owned backend clients

Dual-layer storage model:

defaultSession must cleanly separate two layers with different lifecycles:

Layer Contents Storage Lifetime
Metadata Session ID, timestamps, identity reference, backend ID list Serializable via transportsession.Storage interface (LocalStorage today, RedisStorage in future) Can persist across restarts
Runtime MCP client objects, routing table, capabilities, backend session ID map, closed flag In-process memory only — cannot be serialized (active TCP connections, goroutines) Lives only while the vMCP instance is running

The behavior-oriented Session embeds transportsession.Session (metadata layer) and owns MCP clients (runtime layer). All sessions go through the same Storage interface — no parallel storage path.

Distributed deployment note: because MCP clients cannot be serialized, horizontal scaling requires sticky sessions (session affinity at the load balancer). Without sticky sessions, a request routed to a different vMCP instance will need to recreate backend clients (one-time cost). This is a known trade-off and must be documented in the implementation.

Acceptance Criteria

  • Session interface is defined in pkg/vmcp/session/session.go with all required methods
  • SessionFactory interface and defaultSessionFactory are defined and implemented
  • defaultSession implements both transportsession.Session and the vMCP Session interface
  • defaultSession cleanly separates serializable metadata from non-serializable runtime state — no MCP client objects or routing tables are placed in the metadata layer
  • Session metadata is stored via the transportsession.Storage interface; no parallel storage path is introduced
  • The distributed deployment constraint (sticky sessions required) is documented in code comments or README
  • Backend clients are initialized in parallel with bounded concurrency
  • A slow or failing backend does not prevent the session from being created with the remaining backends
  • All reads from the client map are protected by RLock and locks are released before network I/O
  • Close() waits for all in-flight operations to complete before closing backend clients
  • No changes to existing code or tests
  • Unit tests cover: CallTool, ReadResource, Close, parallel init with timeouts, partial failure, interface composition

RFC: THV-0038 — Session-scoped client lifecycle

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestgoPull requests that update go codevmcpVirtual MCP Server related issues

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions