Skip to content

feat: add McpSessionStore SPI for pluggable session storage#914

Open
vlin529 wants to merge 1 commit intomodelcontextprotocol:mainfrom
vlin529:feature/session-store-spi
Open

feat: add McpSessionStore SPI for pluggable session storage#914
vlin529 wants to merge 1 commit intomodelcontextprotocol:mainfrom
vlin529:feature/session-store-spi

Conversation

@vlin529
Copy link
Copy Markdown

@vlin529 vlin529 commented Apr 9, 2026

Summary

Introduce a McpSessionStore interface that abstracts session storage in HttpServletStreamableServerTransportProvider, enabling custom implementations (e.g., Redis, JDBC, Hazelcast) for distributed and multi-instance MCP server deployments.

Problem

Currently, HttpServletStreamableServerTransportProvider stores sessions in a hardcoded ConcurrentHashMap. This causes:

  • Sessions lost on restart — clients get "Session not found" errors after server restart
  • No multi-instance support — sessions created on Pod A are invisible to Pod B behind a load balancer
  • No extension point — the sessions field is private final, methods are private, Builder has no sessionStore() option

Related issues: #274, #107, #738, #376

Changes

  • McpSessionStore — new interface with save/get/remove/values/isEmpty/size/clear operations
  • InMemoryMcpSessionStore — default ConcurrentHashMap-backed implementation (preserves existing behavior)
  • HttpServletStreamableServerTransportProvider — refactored to use McpSessionStore instead of hardcoded ConcurrentHashMap
  • Builder — added sessionStore(McpSessionStore) method for custom store injection; defaults to InMemoryMcpSessionStore when not set

Usage

// Default (backward compatible — no changes needed)
HttpServletStreamableServerTransportProvider.builder()
    .jsonMapper(mapper)
    .build();

// Custom Redis-backed store
HttpServletStreamableServerTransportProvider.builder()
    .jsonMapper(mapper)
    .sessionStore(new RedisSessionStore(redisTemplate))
    .build();

Non-breaking

This is a fully backward-compatible change. Existing code continues to work without modification — the default InMemoryMcpSessionStore is used when no custom store is provided.

Test

All 274 existing mcp-core tests pass.


Note: This PR only addresses HttpServletStreamableServerTransportProvider in mcp-core. The same pattern should be applied to the Spring WebMvc/WebFlux transport providers as a follow-up.

Closes #274
Relates to #107, #738, #376

Introduce a `McpSessionStore` interface that abstracts session storage,
enabling custom implementations (e.g., Redis, JDBC) for distributed and
multi-instance MCP server deployments.

Changes:
- Add `McpSessionStore` interface with save/get/remove/values/clear ops
- Add `InMemoryMcpSessionStore` as the default ConcurrentHashMap-backed
  implementation (preserving existing behavior)
- Refactor `HttpServletStreamableServerTransportProvider` to use
  `McpSessionStore` instead of a hardcoded ConcurrentHashMap
- Add `sessionStore()` method to the Builder for custom store injection
- Default to `InMemoryMcpSessionStore` when no custom store is provided

This is a non-breaking change: existing code continues to work without
modification as the default in-memory store is used automatically.

Closes modelcontextprotocol#274
Relates to modelcontextprotocol#107, modelcontextprotocol#738, modelcontextprotocol#376
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.

McpServerSession lifecycle doesn't support distributed services

2 participants