DeployStack Docs

Session Management

The DeployStack Gateway implements a robust session management system that provides cryptographically secure session handling for both persistent SSE connections and optional Streamable HTTP sessions while ensuring automatic cleanup and resource management.

Architecture Overview

The session management system consists of multiple components working together to provide secure connections across different transport protocols:

  • SessionManager: Handles session lifecycle, validation, and SSE stream management
  • SSEHandler: Manages Server-Sent Events connections and message routing
  • StreamableHTTPHandler: Manages Streamable HTTP connections with optional session support
  • Transport Layer: Intelligent routing between SSE and Streamable HTTP based on client capabilities

Core Components

Cryptographic Security

256-bit entropy session IDs with base64url encoding for maximum security

Lifecycle Management

Automatic session creation, validation, activity tracking, and timeout handling

Connection Validation

Session-bound SSE streams with comprehensive validation and error handling

Automatic Cleanup

Resource cleanup on disconnect, timeout, or error conditions

Session ID Generation

Cryptographic Properties

  • Algorithm: Node.js crypto.randomBytes(32)
  • Entropy: 256 bits (32 bytes) of cryptographically secure randomness
  • Encoding: Base64url for URL safety and compatibility
  • Format: L8B-xaw3HBZEftyo-JCrHoGWb_iikRZiwGfp9B71-GA

Security Features

  • Unpredictability: Cryptographically secure random number generation
  • Collision Resistance: 2^256 possible values make collisions virtually impossible
  • URL Safety: Base64url encoding ensures compatibility in query parameters
  • No Sequential Patterns: Each session ID is completely independent

Validation Process

private validateSessionId(sessionId: string): boolean {
  if (!sessionId || typeof sessionId !== 'string') return false;
  if (sessionId.length < 32) return false;
  if (!/^[A-Za-z0-9_-]+$/.test(sessionId)) return false;
  return true;
}

Session Lifecycle

1. Creation Phase

Triggers:

  • SSE connection establishment via GET /sse
  • Optional session creation for Streamable HTTP via POST /mcp with session headers

Process:

  1. Generate cryptographically secure session ID
  2. Create session object with metadata
  3. Associate with SSE stream (for SSE transport) or track session state (for Streamable HTTP)
  4. Schedule automatic cleanup timer
  5. Send endpoint event to client (SSE) or return session headers (Streamable HTTP)

Session Object:

interface SessionInfo {
  id: string;
  createdAt: number;
  lastActivity: number;
  sseStream: ServerResponse;
  clientInfo?: { name: string; version: string };
  mcpInitialized: boolean;
  requestCount: number;
  errorCount: number;
}

2. Active Phase

Duration: Until timeout or disconnect

Activities:

  • Activity Tracking: Updated on every JSON-RPC request
  • Request Counting: Incremented for each message processed
  • Error Tracking: Incremented on processing failures
  • Client Info Storage: MCP client metadata stored during initialization

3. Cleanup Phase

Triggers:

  • Client disconnect (close event)
  • Connection error (error event)
  • Stream finish (finish event)
  • 30-minute inactivity timeout

Process:

  1. Close SSE stream if still open
  2. Remove session from active sessions map
  3. Log cleanup completion
  4. Free associated resources

Connection Management

SSE Stream Handling

The session manager maintains direct references to SSE streams for efficient message delivery:

sendToSession(sessionId: string, event: { id?: string; event?: string; data: string }): boolean {
  const session = this.sessions.get(sessionId);
  if (!session || session.sseStream.destroyed) {
    return false;
  }

  try {
    let sseData = '';
    if (event.id) sseData += `id: ${event.id}\n`;
    if (event.event) sseData += `event: ${event.event}\n`;
    sseData += `data: ${event.data}\n\n`;

    session.sseStream.write(sseData);
    return true;
  } catch (error) {
    this.cleanupSession(sessionId);
    return false;
  }
}

Connection State Tracking

  • Stream Health: Monitors SSE stream status and handles disconnects
  • Activity Monitoring: Tracks last activity timestamp for timeout detection
  • Error Handling: Graceful handling of connection failures and cleanup
  • Resource Management: Prevents memory leaks through automatic cleanup

Security Considerations

Session Security

  • Unpredictable IDs: Impossible to guess or enumerate session IDs
  • Time-Limited: Automatic expiration prevents indefinite access
  • Connection-Bound: Sessions tied to specific SSE connections
  • Validation: Comprehensive validation on every request

Timeout Management

  • Inactivity Timeout: 30 minutes of inactivity triggers cleanup
  • Automatic Scheduling: Cleanup scheduled at session creation
  • Activity Extension: Timeout reset on each valid request
  • Resource Protection: Prevents accumulation of stale sessions

Error Handling

  • Graceful Degradation: Connection errors don't crash the system
  • Automatic Recovery: Failed connections cleaned up automatically
  • Error Isolation: Session errors don't affect other sessions
  • Logging: Comprehensive error logging for debugging

Performance Optimization

Memory Management

  • Efficient Storage: Sessions stored in Map for O(1) lookup
  • Automatic Cleanup: Prevents memory leaks through timeout handling
  • Resource Tracking: Monitors session count and resource usage
  • Garbage Collection: Proper cleanup enables efficient garbage collection

Connection Efficiency

  • Persistent Connections: SSE streams maintained for duration of session
  • Minimal Overhead: Lightweight session objects with essential data only
  • Fast Lookup: Session validation and retrieval optimized for speed
  • Batch Operations: Efficient handling of multiple concurrent sessions

Monitoring and Debugging

Session Statistics

The session manager provides comprehensive statistics for monitoring:

getStatus() {
  return {
    activeCount: this.sessions.size,
    sessions: Array.from(this.sessions.values()).map(session => ({
      id: session.id,
      createdAt: session.createdAt,
      lastActivity: session.lastActivity,
      uptime: Date.now() - session.createdAt,
      requestCount: session.requestCount,
      errorCount: session.errorCount,
      clientInfo: session.clientInfo,
      mcpInitialized: session.mcpInitialized
    }))
  };
}

Logging and Observability

  • Session Creation: Logged with session ID for tracking
  • Activity Updates: Request and error counts tracked
  • Cleanup Events: Cleanup reasons and timing logged
  • Error Conditions: Detailed error logging for troubleshooting

Transport-Specific Session Handling

SSE Transport Sessions

SSE transport requires persistent sessions for connection management:

  • Mandatory Sessions: All SSE connections must have associated sessions
  • Stream Binding: Sessions are bound to specific SSE streams
  • Real-time Communication: Messages sent via SSE events in real-time
  • Connection Lifecycle: Session lifecycle tied to SSE connection state

Streamable HTTP Transport Sessions

Streamable HTTP transport supports optional sessions for enhanced functionality:

  • Optional Sessions: Sessions can be used but are not required
  • Stateless Operation: Supports both stateless and session-based operation
  • Header-Based: Session IDs passed via Mcp-Session-Id header
  • Flexible Lifecycle: Sessions can span multiple HTTP requests

Integration Points

SSE Handler Integration

The session manager works closely with the SSE handler:

// Session creation during SSE establishment
const sessionId = this.sessionManager.createSession(reply.raw);

// Message routing through sessions
this.sseHandler.sendMessage(sessionId, response);

// Error handling via sessions
this.sseHandler.sendError(sessionId, errorResponse);

Streamable HTTP Handler Integration

The session manager provides optional session support for Streamable HTTP:

// Optional session validation for Streamable HTTP
const sessionId = request.headers['mcp-session-id'];
if (sessionId) {
  const session = this.sessionManager.getSession(sessionId);
  if (session) {
    this.sessionManager.updateActivity(sessionId);
  }
}

// Stateless operation when no session provided
if (!sessionId) {
  // Handle request without session context
}

HTTP Proxy Integration

Session validation across both transports in the HTTP proxy:

// Transport-aware session handling
if (isSSETransport) {
  // SSE requires session validation
  const session = this.sessionManager.getSession(sessionId);
  if (!session) {
    throw new Error('Invalid session for SSE transport');
  }
  this.sessionManager.updateActivity(sessionId);
} else if (isStreamableHTTP && sessionId) {
  // Streamable HTTP optional session support
  const session = this.sessionManager.getSession(sessionId);
  if (session) {
    this.sessionManager.updateActivity(sessionId);
  }
}

Best Practices

Session Lifecycle

  • Immediate Creation: Sessions created immediately on SSE connection
  • Activity Tracking: Update activity on every valid request
  • Graceful Cleanup: Always clean up resources on session end
  • Error Handling: Handle all error conditions gracefully

Security Practices

  • Validate Always: Validate session ID on every request
  • Time Limits: Enforce reasonable session timeouts
  • Resource Limits: Monitor and limit concurrent sessions if needed
  • Audit Trail: Log session activities for security monitoring

Performance Practices

  • Efficient Lookup: Use Map for O(1) session lookup
  • Minimal Data: Store only essential session data
  • Cleanup Scheduling: Schedule cleanup to prevent resource leaks
  • Error Recovery: Implement robust error recovery mechanisms

The session management system provides a secure, efficient, and robust foundation for persistent SSE connections while maintaining enterprise-grade security and operational requirements.