@@ -7,7 +7,7 @@ import type {
77import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js" ;
88import type { LoggerBase } from "../common/logging/index.js" ;
99import { CompositeLogger , LogId } from "../common/logging/index.js" ;
10- import { SessionStore } from "../common/sessionStore.js" ;
10+ import { type ISessionStore , type CreateSessionStoreFn , createDefaultSessionStore } from "../common/sessionStore.js" ;
1111import {
1212 TransportRunnerBase ,
1313 type TransportRunnerConfig ,
@@ -31,34 +31,6 @@ export type MonitoringServerConfig = {
3131 monitoringServerFeatures : MonitoringServerFeature [ ] ;
3232} ;
3333
34- /**
35- * Constructor arguments for creating a MonitoringServer instance.
36- */
37- export type MonitoringServerConstructorArgs < TMetrics extends DefaultMetrics = DefaultMetrics > = {
38- host : string ;
39- port : number ;
40- features : MonitoringServerFeature [ ] ;
41- logger : LoggerBase ;
42- metrics : Metrics < TMetrics > ;
43- } ;
44-
45- /**
46- * A function to create a custom MonitoringServer instance.
47- * When provided, the runner will use this function instead of the default MonitoringServer constructor.
48- */
49- export type CreateMonitoringServerFn < TMetrics extends DefaultMetrics = DefaultMetrics > = (
50- args : MonitoringServerConstructorArgs < TMetrics >
51- ) => MonitoringServer < TMetrics > | undefined ;
52-
53- /**
54- * Creates a default MonitoringServer instance from the provided constructor arguments.
55- */
56- export const createDefaultMonitoringServer : < TMetrics extends DefaultMetrics = DefaultMetrics > (
57- args : MonitoringServerConstructorArgs < TMetrics >
58- ) => MonitoringServer < TMetrics > = < TMetrics extends DefaultMetrics = DefaultMetrics > (
59- args : MonitoringServerConstructorArgs < TMetrics >
60- ) => new MonitoringServer < TMetrics > ( args ) ;
61-
6234/**
6335 * Configuration options for the StreamableHttpRunner.
6436 * Extends the base TransportRunnerConfig with HTTP-transport-specific options.
@@ -77,6 +49,15 @@ export type StreamableHttpTransportRunnerConfig<
7749 * receiving the constructor arguments that would normally be used.
7850 */
7951 createMonitoringServer ?: CreateMonitoringServerFn < TMetrics > ;
52+
53+ /**
54+ * When provided, the runner will use this function to create the session store
55+ * instead of using the default SessionStore constructor. This allows for
56+ * customizing session storage (e.g., Redis-backed storage, custom timeout behavior,
57+ * or shared session state across instances) while still receiving the constructor
58+ * arguments that would normally be used.
59+ */
60+ createSessionStore ?: CreateSessionStoreFn < StreamableHTTPServerTransport , TMetrics > ;
8061} ;
8162
8263const JSON_RPC_ERROR_CODE_PROCESSING_REQUEST_FAILED = - 32000 ;
@@ -93,23 +74,30 @@ export class StreamableHttpRunner<
9374> extends TransportRunnerBase < TUserConfig , TContext , TMetrics > {
9475 private mcpServer : MCPHttpServer < TUserConfig , TContext > | undefined ;
9576 private readonly monitoringServer : MonitoringServer < TMetrics > | undefined ;
77+ private readonly sessionStore : ISessionStore < StreamableHTTPServerTransport > ;
9678
9779 constructor ( config : StreamableHttpTransportRunnerConfig < TUserConfig , TMetrics > ) {
9880 super ( config ) ;
81+
82+ this . sessionStore = ( config . createSessionStore ?? createDefaultSessionStore < StreamableHTTPServerTransport > ) ( {
83+ options : {
84+ idleTimeoutMS : this . userConfig . idleTimeoutMs ,
85+ notificationTimeoutMS : this . userConfig . notificationTimeoutMs ,
86+ } ,
87+ logger : this . logger ,
88+ metrics : this . metrics ,
89+ } ) ;
9990 // Create monitoring server if host/port are configured
10091 const host = config . userConfig . monitoringServerHost ?? config . userConfig . healthCheckHost ;
10192 const port = config . userConfig . monitoringServerPort ?? config . userConfig . healthCheckPort ;
10293 if ( host !== undefined && port !== undefined ) {
103- const args : MonitoringServerConstructorArgs < TMetrics > = {
94+ this . monitoringServer = ( config . createMonitoringServer ?? createDefaultMonitoringServer ) ( {
10495 host,
10596 port,
10697 features : config . userConfig . monitoringServerFeatures ,
10798 logger : this . logger ,
10899 metrics : this . metrics ,
109- } ;
110- this . monitoringServer = ( config . createMonitoringServer ?? createDefaultMonitoringServer ) ( args ) ;
111- } else {
112- this . monitoringServer = undefined ;
100+ } ) ;
113101 }
114102 }
115103
@@ -131,6 +119,7 @@ export class StreamableHttpRunner<
131119 this . createServerForRequest ( { request, serverOptions, sessionOptions } ) ,
132120 logger : this . logger ,
133121 metrics : this . metrics ,
122+ sessionStore : this . sessionStore ,
134123 } ) ;
135124 await this . mcpServer . start ( ) ;
136125
@@ -340,7 +329,7 @@ abstract class ExpressBasedHttpServer {
340329}
341330
342331class MCPHttpServer < TUserConfig extends UserConfig = UserConfig , TContext = unknown > extends ExpressBasedHttpServer {
343- private sessionStore ! : SessionStore < StreamableHTTPServerTransport > ;
332+ private readonly sessionStore : ISessionStore < StreamableHTTPServerTransport > ;
344333 private readonly serverOptions ?: CustomizableServerOptions < TUserConfig , TContext > ;
345334 private readonly sessionOptions ?: CustomizableSessionOptions < TUserConfig > ;
346335 private readonly userConfig : UserConfig ;
@@ -359,6 +348,7 @@ class MCPHttpServer<TUserConfig extends UserConfig = UserConfig, TContext = unkn
359348 sessionOptions,
360349 logger,
361350 metrics,
351+ sessionStore,
362352 } : {
363353 userConfig : TUserConfig ;
364354 createServerForRequest : ( createParams : {
@@ -370,6 +360,7 @@ class MCPHttpServer<TUserConfig extends UserConfig = UserConfig, TContext = unkn
370360 serverOptions ?: CustomizableServerOptions < TUserConfig , TContext > ;
371361 sessionOptions ?: CustomizableSessionOptions < TUserConfig > ;
372362 metrics : Metrics < DefaultMetrics > ;
363+ sessionStore : ISessionStore < StreamableHTTPServerTransport > ;
373364 } ) {
374365 super ( {
375366 port : userConfig . httpPort ,
@@ -382,6 +373,7 @@ class MCPHttpServer<TUserConfig extends UserConfig = UserConfig, TContext = unkn
382373 this . createServerForRequest = createServerForRequest ;
383374 this . userConfig = userConfig ;
384375 this . metrics = metrics ;
376+ this . sessionStore = sessionStore ;
385377 }
386378
387379 public async stop ( ) : Promise < void > {
@@ -472,13 +464,6 @@ class MCPHttpServer<TUserConfig extends UserConfig = UserConfig, TContext = unkn
472464 protected override async setupRoutes ( ) : Promise < void > {
473465 const { StreamableHTTPServerTransport } = await import ( "@modelcontextprotocol/sdk/server/streamableHttp.js" ) ;
474466
475- this . sessionStore = new SessionStore (
476- this . userConfig . idleTimeoutMs ,
477- this . userConfig . notificationTimeoutMs ,
478- this . logger ,
479- this . metrics
480- ) ;
481-
482467 this . app . use ( express . json ( { limit : this . userConfig . httpBodyLimit } ) ) ;
483468 this . app . use ( ( req , res , next ) => {
484469 for ( const [ key , value ] of Object . entries ( this . userConfig . httpHeaders ) ) {
@@ -589,7 +574,7 @@ class MCPHttpServer<TUserConfig extends UserConfig = UserConfig, TContext = unkn
589574 // reuse it. This may cause issues if server.connect fails as we'll try to use a transport that's
590575 // not fully set up.
591576 server . session . logger . setAttribute ( "sessionId" , sessionId ) ;
592- this . sessionStore . setSession ( sessionId , transport , server . session . logger ) ;
577+ this . sessionStore . addSession ( { sessionId, transport, logger : server . session . logger } ) ;
593578
594579 const keepAliveLoop = this . startKeepAliveLoop ( transport , server ) ;
595580 transport . onclose = ( ) : void => {
@@ -677,6 +662,34 @@ class MCPHttpServer<TUserConfig extends UserConfig = UserConfig, TContext = unkn
677662 }
678663}
679664
665+ /**
666+ * Constructor arguments for creating a MonitoringServer instance.
667+ */
668+ export type MonitoringServerConstructorArgs < TMetrics extends DefaultMetrics = DefaultMetrics > = {
669+ host : string ;
670+ port : number ;
671+ features : MonitoringServerFeature [ ] ;
672+ logger : LoggerBase ;
673+ metrics : Metrics < TMetrics > ;
674+ } ;
675+
676+ /**
677+ * A function to create a custom MonitoringServer instance.
678+ * When provided, the runner will use this function instead of the default MonitoringServer constructor.
679+ */
680+ export type CreateMonitoringServerFn < TMetrics extends DefaultMetrics = DefaultMetrics > = (
681+ args : MonitoringServerConstructorArgs < TMetrics >
682+ ) => MonitoringServer < TMetrics > | undefined ;
683+
684+ /**
685+ * Creates a default MonitoringServer instance from the provided constructor arguments.
686+ */
687+ export const createDefaultMonitoringServer : < TMetrics extends DefaultMetrics = DefaultMetrics > (
688+ args : MonitoringServerConstructorArgs < TMetrics >
689+ ) => MonitoringServer < TMetrics > = < TMetrics extends DefaultMetrics = DefaultMetrics > (
690+ args : MonitoringServerConstructorArgs < TMetrics >
691+ ) => new MonitoringServer < TMetrics > ( args ) ;
692+
680693export class MonitoringServer < TMetrics extends DefaultMetrics = DefaultMetrics > extends ExpressBasedHttpServer {
681694 private readonly features : MonitoringServerFeature [ ] ;
682695 private readonly metrics : Metrics < TMetrics > ;
0 commit comments