@@ -34,11 +34,18 @@ export interface StreamableHTTPServerTransportOptions {
34
34
/**
35
35
* Function that generates a session ID for the transport.
36
36
* The session ID SHOULD be globally unique and cryptographically secure (e.g., a securely generated UUID, a JWT, or a cryptographic hash)
37
- *
38
- * Return undefined to disable session management .
37
+ *
38
+ * Not used in stateless mode .
39
39
*/
40
40
sessionIdGenerator : ( ( ) => string ) | undefined ;
41
41
42
+ /**
43
+ * Whether to run in stateless mode (no session management).
44
+ * In stateless mode, no initialization is required and there's no session tracking.
45
+ * Default is false (stateful mode).
46
+ */
47
+ statelessMode ?: boolean ;
48
+
42
49
/**
43
50
* A callback for session initialization events
44
51
* This is called when the server initializes a new session.
@@ -64,37 +71,39 @@ export interface StreamableHTTPServerTransportOptions {
64
71
65
72
/**
66
73
* Server transport for Streamable HTTP: this implements the MCP Streamable HTTP transport specification.
67
- * It supports both SSE streaming and direct HTTP responses.
68
- *
74
+ * It supports both SSE streaming and direct HTTP responses.r
75
+ *
69
76
* Usage example:
70
- *
77
+ *
71
78
* ```typescript
72
79
* // Stateful mode - server sets the session ID
73
80
* const statefulTransport = new StreamableHTTPServerTransport({
74
- * sessionId: randomUUID(),
81
+ * sessionIdGenerator: () => randomUUID(),
75
82
* });
76
- *
77
- * // Stateless mode - explicitly set session ID to undefined
83
+ *
84
+ * // Stateless mode - explicitly enable stateless mode
78
85
* const statelessTransport = new StreamableHTTPServerTransport({
79
- * sessionId: undefined,
86
+ * statelessMode: true,
87
+ * enableJsonResponse: true, // Optional
80
88
* });
81
- *
89
+ *
82
90
* // Using with pre-parsed request body
83
91
* app.post('/mcp', (req, res) => {
84
92
* transport.handleRequest(req, res, req.body);
85
93
* });
86
94
* ```
87
- *
95
+ *
88
96
* In stateful mode:
89
97
* - Session ID is generated and included in response headers
90
98
* - Session ID is always included in initialization responses
91
99
* - Requests with invalid session IDs are rejected with 404 Not Found
92
100
* - Non-initialization requests without a session ID are rejected with 400 Bad Request
93
101
* - State is maintained in-memory (connections, message history)
94
- *
102
+ *
95
103
* In stateless mode:
96
- * - Session ID is only included in initialization responses
104
+ * - No initialization is required before handling requests
97
105
* - No session validation is performed
106
+ * - No state is maintained between requests
98
107
*/
99
108
export class StreamableHTTPServerTransport implements Transport {
100
109
// when sessionId is not set (undefined), it means the transport is in stateless mode
@@ -108,6 +117,7 @@ export class StreamableHTTPServerTransport implements Transport {
108
117
private _standaloneSseStreamId : string = '_GET_stream' ;
109
118
private _eventStore ?: EventStore ;
110
119
private _onsessioninitialized ?: ( sessionId : string ) => void ;
120
+ private _statelessMode : boolean = false ;
111
121
112
122
sessionId ?: string | undefined ;
113
123
onclose ?: ( ) => void ;
@@ -119,6 +129,12 @@ export class StreamableHTTPServerTransport implements Transport {
119
129
this . _enableJsonResponse = options . enableJsonResponse ?? false ;
120
130
this . _eventStore = options . eventStore ;
121
131
this . _onsessioninitialized = options . onsessioninitialized ;
132
+ this . _statelessMode = options . statelessMode ?? false ;
133
+
134
+ // In stateless mode, no initialization is required
135
+ if ( this . _statelessMode ) {
136
+ this . _initialized = true ;
137
+ }
122
138
}
123
139
124
140
/**
@@ -166,7 +182,7 @@ export class StreamableHTTPServerTransport implements Transport {
166
182
}
167
183
168
184
// If an Mcp-Session-Id is returned by the server during initialization,
169
- // clients using the Streamable HTTP transport MUST include it
185
+ // clients using the Streamable HTTP transport MUST include it
170
186
// in the Mcp-Session-Id header on all of their subsequent HTTP requests.
171
187
if ( ! this . validateSession ( req , res ) ) {
172
188
return ;
@@ -180,7 +196,7 @@ export class StreamableHTTPServerTransport implements Transport {
180
196
}
181
197
}
182
198
183
- // The server MUST either return Content-Type: text/event-stream in response to this HTTP GET,
199
+ // The server MUST either return Content-Type: text/event-stream in response to this HTTP GET,
184
200
// or else return HTTP 405 Method Not Allowed
185
201
const headers : Record < string , string > = {
186
202
"Content-Type" : "text/event-stream" ,
@@ -376,7 +392,7 @@ export class StreamableHTTPServerTransport implements Transport {
376
392
377
393
}
378
394
// If an Mcp-Session-Id is returned by the server during initialization,
379
- // clients using the Streamable HTTP transport MUST include it
395
+ // clients using the Streamable HTTP transport MUST include it
380
396
// in the Mcp-Session-Id header on all of their subsequent HTTP requests.
381
397
if ( ! isInitializationRequest && ! this . validateSession ( req , res ) ) {
382
398
return ;
@@ -475,11 +491,12 @@ export class StreamableHTTPServerTransport implements Transport {
475
491
} ) ) ;
476
492
return false ;
477
493
}
478
- if ( this . sessionId === undefined ) {
479
- // If the session ID is not set, the session management is disabled
480
- // and we don't need to validate the session ID
494
+
495
+ // If in stateless mode or the session ID is undefined, no session validation is needed
496
+ if ( this . _statelessMode || this . sessionId === undefined ) {
481
497
return true ;
482
498
}
499
+
483
500
const sessionId = req . headers [ "mcp-session-id" ] ;
484
501
485
502
if ( ! sessionId ) {
0 commit comments