Skip to content

Conversation

@stefanskiasan
Copy link

Summary

This PR adds native support for distributed session storage in the MCP SDK, enabling multi-pod/multi-node deployments where session state must be shared across server instances.

The Problem

The official @modelcontextprotocol/sdk stores session state in-memory:

// Original SDK - sessions are local to each process
private _initialized: boolean = false;
sessionId?: string;

This means:

  • Sessions cannot be shared across multiple pods/containers
  • Load balancers routing requests to different instances will fail
  • Sessions are lost on server restart

The Solution

This PR introduces:

  1. SessionStore interface - Abstract interface for external session storage
  2. SessionData interface - Session metadata structure
  3. SessionStorageMode type - Explicit mode selection ('memory' | 'external')
  4. RedisSessionStore - Production-ready Redis implementation
  5. InMemorySessionStore - For development/testing

Usage

// Single-pod mode (default) - sessions in memory
const singlePodTransport = new StreamableHTTPServerTransport({
    sessionIdGenerator: () => randomUUID(),
    sessionStorageMode: 'memory'  // This is the default
});

// Multi-pod mode - sessions in Redis
const multiPodTransport = new StreamableHTTPServerTransport({
    sessionIdGenerator: () => randomUUID(),
    sessionStorageMode: 'external',  // Explicit mode selection
    sessionStore: new RedisSessionStore({
        redis: new Redis(),
        ttlSeconds: 3600
    })
});

Key Features

  • Backward compatible - Default behavior unchanged when no sessionStore provided
  • Explicit mode configuration - Clear distinction between memory and external modes
  • Cross-pod session recovery - Sessions automatically recovered from external store
  • Automatic TTL refresh - Session activity updates refresh TTL
  • Type-safe - Full TypeScript support with exported interfaces
  • Comprehensive tests - Unit and integration tests for all new functionality

Files Changed

  • src/server/streamableHttp.ts - Core SessionStore integration
  • src/server/index.ts - Export new types and classes
  • src/server/session-stores/redis.ts - Redis and InMemory implementations
  • src/server/session-stores/index.ts - Re-exports
  • src/server/streamableHttp.test.ts - Integration tests
  • src/server/session-stores/redis.test.ts - Unit tests

Test plan

  • All 1458 existing SDK tests pass
  • New unit tests for RedisSessionStore (19 tests)
  • New unit tests for InMemorySessionStore (included in above)
  • New integration tests for SessionStore with StreamableHTTPServerTransport
  • Cross-pod session recovery simulation test
  • Build succeeds for both ESM and CJS

🤖 Generated with Claude Code

stefanskiasan and others added 2 commits November 30, 2025 14:48
This adds native support for external session storage in StreamableHTTPServerTransport,
enabling multi-pod/multi-node deployments where session state must be shared.

Changes:
- Add SessionStore interface with store/get/update/delete/exists methods
- Add SessionData interface for session metadata
- Add SessionStorageMode type ('memory' | 'external')
- Add sessionStorageMode option to transport options (default: 'memory')
- Add sessionStore option for external session storage implementation
- Add RedisSessionStore implementation example
- Add InMemorySessionStore for development/testing
- Add runtime getters: sessionStorageMode, isUsingExternalSessionStore
- Validation: throws error if mode='external' without sessionStore

Usage:
```typescript
// Memory mode (default)
new StreamableHTTPServerTransport({
    sessionIdGenerator: () => randomUUID(),
    sessionStorageMode: 'memory'
});

// External mode (Redis)
new StreamableHTTPServerTransport({
    sessionIdGenerator: () => randomUUID(),
    sessionStorageMode: 'external',
    sessionStore: new RedisSessionStore({ redis, ttlSeconds: 3600 })
});
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add unit tests for RedisSessionStore and InMemorySessionStore
  - Store/retrieve session data
  - TTL handling and expiry
  - Activity updates
  - Custom key prefix
  - Logging callbacks

- Add integration tests for StreamableHTTPServerTransport with SessionStore
  - SessionStorageMode configuration (memory/external)
  - External session storage integration
  - Session lifecycle (store, validate, update, delete)
  - Cross-pod session recovery simulation
  - Error handling for invalid sessions
  - InMemorySessionStore integration for development

All 1458 SDK tests pass with no regressions.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@stefanskiasan stefanskiasan requested a review from a team as a code owner November 30, 2025 13:56
Include pre-built distribution files (ESM and CJS) in the repository
to enable direct npm installation from GitHub without requiring
a build step.

This allows consuming projects to install via:
npm install github:stefanskiasan/typescript-sdk#feature/session-store-interface

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@pkg-pr-new
Copy link

pkg-pr-new bot commented Nov 30, 2025

Open in StackBlitz

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@anthropic-advisori/mcp-sdk@1193

commit: c258d9f

- Call onsessioninitialized handler BEFORE storing session data
- Merge existing session data (including metadata) when updating
- Prevents overwrites of custom metadata (e.g., serverId) set by handlers

This fix ensures that applications using external session storage can
store additional metadata (like serverId for cross-pod recovery) via
the onsessioninitialized callback without it being overwritten by the
SDK's internal storeSession call.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant