Documentation
¶
Overview ¶
Package session provides vMCP-specific session types that extend transport sessions with domain logic.
Index ¶
Constants ¶
const ( // MetadataKeyIdentitySubject is the transport-session metadata key that // holds the subject claim of the authenticated caller (identity.Subject). // Set at session creation; empty for anonymous callers. MetadataKeyIdentitySubject = "vmcp.identity.subject" // MetadataKeyBackendIDs is the transport-session metadata key that holds // a comma-separated, sorted list of successfully-connected backend IDs. // The key is omitted entirely when no backends connected. MetadataKeyBackendIDs = "vmcp.backend.ids" )
Variables ¶
var ( // ErrSessionClosed is returned when an operation is attempted on a closed session. ErrSessionClosed = errors.New("session is closed") // ErrToolNotFound is returned when the requested tool is not in the routing table. ErrToolNotFound = errors.New("tool not found in session routing table") // ErrResourceNotFound is returned when the requested resource is not in the routing table. ErrResourceNotFound = errors.New("resource not found in session routing table") // ErrPromptNotFound is returned when the requested prompt is not in the routing table. ErrPromptNotFound = errors.New("prompt not found in session routing table") // ErrNoBackendClient is returned when the routing table references a backend // that has no entry in the connections map. This indicates an internal // invariant violation: under normal operation MakeSession always populates // both maps together, so this error should never be seen at runtime. ErrNoBackendClient = errors.New("no client available for backend") )
Sentinel errors returned by defaultMultiSession methods.
Functions ¶
func VMCPSessionFactory ¶
func VMCPSessionFactory() transportsession.Factory
VMCPSessionFactory creates a factory function for the session manager.
Types ¶
type AdmissionQueue ¶ added in v0.10.1
type AdmissionQueue interface {
// TryAdmit attempts to admit a request. If the queue is open, it returns
// (true, done) where done must be called when the request completes.
// If the queue is already closed, it returns (false, nil).
TryAdmit() (bool, func())
// CloseAndDrain closes the queue so that subsequent TryAdmit calls return
// false, then blocks until all currently-admitted requests have called
// their done function. Idempotent.
CloseAndDrain()
}
AdmissionQueue controls admission of concurrent requests to a shared resource that can be closed. Once closed, no further requests are admitted and CloseAndDrain blocks until all previously-admitted requests complete.
type MultiSession ¶ added in v0.10.1
type MultiSession interface {
transportsession.Session
sessiontypes.Caller
// Tools returns the resolved tools available in this session.
// The list is built once at session creation and is read-only thereafter.
Tools() []vmcp.Tool
// Resources returns the resolved resources available in this session.
Resources() []vmcp.Resource
// Prompts returns the resolved prompts available in this session.
Prompts() []vmcp.Prompt
// BackendSessions returns a snapshot of the backend-assigned session IDs,
// keyed by backend workload ID. The backend session ID is assigned by the
// backend MCP server and is used to correlate vMCP sessions with backend
// sessions for debugging and auditing.
BackendSessions() map[string]string
}
MultiSession is the vMCP domain session interface. It extends the transport-layer Session with behaviour: capability access and session-scoped backend routing across multiple backend connections.
A MultiSession is a "session of sessions": each backend contributes its own persistent connection (see backend.Session in pkg/vmcp/session/internal/backend), and the MultiSession aggregates them behind a single routing table.
Distributed deployment note ¶
Because MCP clients cannot be serialised, horizontal scaling requires sticky sessions (session affinity at the load balancer). Without sticky sessions, a request routed to a different vMCP instance must recreate backend clients (one-time cost per re-route). This is a known trade-off documented in RFC THV-0038: https://github.com/stacklok/toolhive-rfcs/blob/main/rfcs/THV-0038-session-scoped-client-lifecycle.md
Dual-layer storage model ¶
A MultiSession separates two layers with different lifecycles:
Metadata layer (serialisable): session ID, timestamps, identity reference, backend ID list. Stored via the transportsession.Storage interface and can persist across restarts.
Runtime layer (non-serialisable): MCP client objects, routing table, capabilities, backend session ID map, closed flag. Lives only in-process.
All session metadata goes through the same Storage interface — no parallel storage path is introduced.
type MultiSessionFactory ¶ added in v0.10.1
type MultiSessionFactory interface {
// MakeSession creates a new MultiSession for the given identity against the
// provided set of backends. Backend clients are initialised in parallel
// with bounded concurrency (see WithMaxBackendInitConcurrency).
//
// Partial initialisation: if a backend fails to initialise, a warning is
// logged and the session continues with the remaining backends. The caller
// receives a valid session as long as at least one backend succeeded.
//
// If all backends fail, MakeSession still returns a valid (empty) session
// rather than an error, allowing clients to connect even when all backends
// are temporarily unavailable.
MakeSession(ctx context.Context, identity *auth.Identity, backends []*vmcp.Backend) (MultiSession, error)
}
MultiSessionFactory creates new MultiSessions for connecting clients.
func NewSessionFactory ¶ added in v0.10.1
func NewSessionFactory(registry vmcpauth.OutgoingAuthRegistry, opts ...MultiSessionFactoryOption) MultiSessionFactory
NewSessionFactory creates a MultiSessionFactory that connects to backends over HTTP using the given outgoing auth registry.
type MultiSessionFactoryOption ¶ added in v0.10.1
type MultiSessionFactoryOption func(*defaultMultiSessionFactory)
MultiSessionFactoryOption configures a defaultMultiSessionFactory.
func WithBackendInitTimeout ¶ added in v0.10.1
func WithBackendInitTimeout(d time.Duration) MultiSessionFactoryOption
WithBackendInitTimeout sets the per-backend timeout during MakeSession. Defaults to 30 s.
func WithMaxBackendInitConcurrency ¶ added in v0.10.1
func WithMaxBackendInitConcurrency(n int) MultiSessionFactoryOption
WithMaxBackendInitConcurrency sets the maximum number of backends that are initialised concurrently during MakeSession. Defaults to 10.
type VMCPSession ¶
type VMCPSession struct {
*transportsession.StreamableSession
// contains filtered or unexported fields
}
VMCPSession extends StreamableSession with domain-specific routing data. This keeps routing table state in the application layer (pkg/vmcp/server) rather than polluting the transport layer (pkg/transport/session) with domain concerns.
Design Rationale:
- Embeds StreamableSession to inherit Session interface and streamable HTTP behavior
- Adds routing table for per-session capability routing
- Stores tool list with InputSchema for type coercion in composite tool workflows
- Maintains lifecycle synchronization with underlying transport session
- Provides type-safe access to routing table (vs. interface{} casting)
Lifecycle:
- Created by VMCPSessionFactory during sessionIDAdapter.Generate()
- Routing table and tools populated in AfterInitialize hook
- Retrieved by middleware on subsequent requests via type assertion
- Cleaned up automatically by session.Manager TTL worker
TODO: VMCPSession is a transitional type. Once the server layer is wired to use MultiSession (Phase 2 of RFC THV-0038), VMCPSession will be removed. Tracked in https://github.com/stacklok/toolhive/issues/3865
func GetVMCPSession ¶
func GetVMCPSession(sessionID string, mgr *transportsession.Manager) (*VMCPSession, error)
GetVMCPSession retrieves and validates a VMCPSession from the session manager.
This helper abstracts the common pattern of:
- Retrieving a session from the manager
- Type-asserting to *VMCPSession
- Handling errors with clear messages
func NewVMCPSession ¶
func NewVMCPSession(id string) *VMCPSession
NewVMCPSession creates a VMCPSession with initialized StreamableSession. The routing table is initially nil and will be populated during AfterInitialize hook.
This function panics if NewStreamableSession returns an unexpected type. This is intentional fail-fast behavior for programming errors that should be caught during development/testing. The type assertion should always succeed since NewStreamableSession is under our control and always returns *StreamableSession. A panic here indicates a bug in the transport layer that needs to be fixed, not a runtime condition to handle gracefully.
func (*VMCPSession) GetRoutingTable ¶
func (s *VMCPSession) GetRoutingTable() *vmcp.RoutingTable
GetRoutingTable retrieves the routing table for this session. Returns nil if capabilities have not been initialized yet.
func (*VMCPSession) GetTools ¶ added in v0.6.17
func (s *VMCPSession) GetTools() []vmcp.Tool
GetTools retrieves the tools list for this session. Returns nil if capabilities have not been initialized yet.
func (*VMCPSession) SetRoutingTable ¶
func (s *VMCPSession) SetRoutingTable(rt *vmcp.RoutingTable)
SetRoutingTable sets the routing table for this session. Called during AfterInitialize hook after capability discovery.
func (*VMCPSession) SetTools ¶ added in v0.6.17
func (s *VMCPSession) SetTools(tools []vmcp.Tool)
SetTools sets the tools list for this session. Called during AfterInitialize hook after capability discovery. The tools list includes InputSchema needed for type coercion in composite tool workflows.
func (*VMCPSession) Type ¶
func (*VMCPSession) Type() transportsession.SessionType
Type identifies this as a streamable vMCP session.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
internal
|
|
|
backend
Package backend defines the Session interface for a single persistent backend connection and provides the HTTP-based implementation used in production.
|
Package backend defines the Session interface for a single persistent backend connection and provides the HTTP-based implementation used in production. |
|
Package types defines shared session interfaces for the vmcp/session package hierarchy.
|
Package types defines shared session interfaces for the vmcp/session package hierarchy. |