1
1
import { IncomingMessage , ServerResponse } from "node:http" ;
2
2
import { Transport } from "../shared/transport.js" ;
3
- import { isJSONRPCRequest , isJSONRPCResponse , JSONRPCMessage , JSONRPCMessageSchema , RequestId } from "../types.js" ;
3
+ import { isInitializeRequest , isJSONRPCRequest , isJSONRPCResponse , JSONRPCMessage , JSONRPCMessageSchema , RequestId } from "../types.js" ;
4
4
import getRawBody from "raw-body" ;
5
5
import contentType from "content-type" ;
6
6
import { randomUUID } from "node:crypto" ;
@@ -39,6 +39,15 @@ export interface StreamableHTTPServerTransportOptions {
39
39
*/
40
40
sessionIdGenerator : ( ) => string | undefined ;
41
41
42
+ /**
43
+ * A callback for session initialization events
44
+ * This is called when the server initializes a new session.
45
+ * Usefult in cases when you need to register multiple mcp sessions
46
+ * and need to keep track of them.
47
+ * @param sessionId The generated session ID
48
+ */
49
+ onsessioninitialized ?: ( sessionId : string ) => void ;
50
+
42
51
/**
43
52
* If true, the server will return JSON responses instead of starting an SSE stream.
44
53
* This can be useful for simple request/response scenarios without streaming.
@@ -98,6 +107,7 @@ export class StreamableHTTPServerTransport implements Transport {
98
107
private _enableJsonResponse : boolean = false ;
99
108
private _standaloneSseStreamId : string = '_GET_stream' ;
100
109
private _eventStore ?: EventStore ;
110
+ private _onsessioninitialized ?: ( sessionId : string ) => void ;
101
111
102
112
sessionId ?: string | undefined ;
103
113
onclose ?: ( ) => void ;
@@ -108,6 +118,7 @@ export class StreamableHTTPServerTransport implements Transport {
108
118
this . sessionIdGenerator = options . sessionIdGenerator ;
109
119
this . _enableJsonResponse = options . enableJsonResponse ?? false ;
110
120
this . _eventStore = options . eventStore ;
121
+ this . _onsessioninitialized = options . onsessioninitialized ;
111
122
}
112
123
113
124
/**
@@ -328,9 +339,7 @@ export class StreamableHTTPServerTransport implements Transport {
328
339
329
340
// Check if this is an initialization request
330
341
// https://spec.modelcontextprotocol.io/specification/2025-03-26/basic/lifecycle/
331
- const isInitializationRequest = messages . some (
332
- msg => 'method' in msg && msg . method === 'initialize'
333
- ) ;
342
+ const isInitializationRequest = messages . some ( isInitializeRequest ) ;
334
343
if ( isInitializationRequest ) {
335
344
// If it's a server with session management and the session ID is already set we should reject the request
336
345
// to avoid re-initialization.
@@ -359,6 +368,12 @@ export class StreamableHTTPServerTransport implements Transport {
359
368
this . sessionId = this . sessionIdGenerator ( ) ;
360
369
this . _initialized = true ;
361
370
371
+ // If we have a session ID and an onsessioninitialized handler, call it immediately
372
+ // This is needed in cases where the server needs to keep track of multiple sessions
373
+ if ( this . sessionId && this . _onsessioninitialized ) {
374
+ this . _onsessioninitialized ( this . sessionId ) ;
375
+ }
376
+
362
377
}
363
378
// If an Mcp-Session-Id is returned by the server during initialization,
364
379
// clients using the Streamable HTTP transport MUST include it
0 commit comments