@tmcp/transport-http 0.8.2 → 0.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -212,11 +212,24 @@ interface HttpTransportOptions {
212
212
  streams?: StreamSessionManager;
213
213
  info?: InfoSessionManager;
214
214
  }; // Provide custom managers; defaults to in-memory implementations
215
+ disableSse?: boolean; // Disable SSE stream endpoint (GET returns 405)
215
216
  }
216
217
  ```
217
218
 
218
219
  If you omit `sessionManager` the transport creates `InMemoryStreamSessionManager` and `InMemoryInfoSessionManager` instances for you. You can override either field independently (for example, Redis streams with in-memory metadata during development).
219
220
 
221
+ ### Disabling SSE Streams
222
+
223
+ If your deployment doesn't support long-lived SSE connections (e.g., some serverless environments), you can disable the GET endpoint:
224
+
225
+ ```javascript
226
+ const transport = new HttpTransport(server, {
227
+ disableSse: true,
228
+ });
229
+ ```
230
+
231
+ When `disableSse` is `true`, GET requests to the MCP endpoint will return a `405 Method Not Allowed` response. Clients can still communicate via POST requests, but won't receive server-initiated notifications.
232
+
220
233
  #### Methods
221
234
 
222
235
  ##### `respond(request: Request, customContext?: T): Promise<Response | null>`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tmcp/transport-http",
3
- "version": "0.8.2",
3
+ "version": "0.8.4",
4
4
  "description": "Transport for TMCP using HTTP",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -40,7 +40,7 @@
40
40
  },
41
41
  "devDependencies": {
42
42
  "@modelcontextprotocol/sdk": "^1.17.1",
43
- "@remix-run/node-fetch-server": "^0.12.0",
43
+ "@remix-run/node-fetch-server": "^0.13.0",
44
44
  "@types/node": "^24.0.15",
45
45
  "dts-buddy": "^0.6.2",
46
46
  "publint": "^0.3.12",
@@ -48,7 +48,7 @@
48
48
  "vitest": "^4.0.0",
49
49
  "@tmcp/adapter-valibot": "^0.1.5",
50
50
  "@tmcp/auth": "^0.4.0",
51
- "tmcp": "^1.18.0"
51
+ "tmcp": "^1.19.0"
52
52
  },
53
53
  "publishConfig": {
54
54
  "access": "public"
package/src/index.js CHANGED
@@ -23,6 +23,7 @@
23
23
  * oauth?: OAuth<"built">
24
24
  * cors?: CorsConfig | boolean,
25
25
  * sessionManager?: { streams?: StreamSessionManager, info?: OptionalizeSessionManager<InfoSessionManager> }
26
+ * disableSse?: boolean
26
27
  * }} HttpTransportOptions
27
28
  */
28
29
 
@@ -47,7 +48,7 @@ export class HttpTransport {
47
48
  #server;
48
49
 
49
50
  /**
50
- * @type {Required<Omit<HttpTransportOptions, 'oauth' | 'cors' | 'sessionManager'>> & { cors?: CorsConfig | boolean, sessionManager: SessionManager }}
51
+ * @type {Required<Omit<HttpTransportOptions, 'oauth' | 'cors' | 'sessionManager' | 'disableSse'>> & { cors?: CorsConfig | boolean, sessionManager: SessionManager, disableSse?: boolean }}
51
52
  */
52
53
  #options;
53
54
 
@@ -85,6 +86,7 @@ export class HttpTransport {
85
86
  path = '/mcp',
86
87
  oauth,
87
88
  cors,
89
+ disableSse,
88
90
  sessionManager: _sessionManager = {
89
91
  streams: new InMemoryStreamSessionManager(),
90
92
  info: new InMemoryInfoSessionManager(),
@@ -113,7 +115,13 @@ export class HttpTransport {
113
115
  this.#oauth = oauth;
114
116
  }
115
117
 
116
- this.#options = { getSessionId, path, cors, sessionManager };
118
+ this.#options = {
119
+ getSessionId,
120
+ path,
121
+ cors,
122
+ sessionManager,
123
+ disableSse,
124
+ };
117
125
  this.#path = path;
118
126
 
119
127
  this.#server.on('initialize', ({ capabilities, clientInfo }) => {
@@ -161,7 +169,7 @@ export class HttpTransport {
161
169
  }
162
170
  await this.#options.sessionManager.streams.send(
163
171
  sessions,
164
- 'data: ' + JSON.stringify(request) + '\n\n',
172
+ 'event: message\ndata: ' + JSON.stringify(request) + '\n\n',
165
173
  );
166
174
  });
167
175
 
@@ -172,7 +180,7 @@ export class HttpTransport {
172
180
 
173
181
  controller.enqueue(
174
182
  this.#text_encoder.encode(
175
- 'data: ' + JSON.stringify(request) + '\n\n',
183
+ 'event: message\ndata: ' + JSON.stringify(request) + '\n\n',
176
184
  ),
177
185
  );
178
186
  });
@@ -281,6 +289,15 @@ export class HttpTransport {
281
289
  * @returns
282
290
  */
283
291
  async #handle_get(session_id) {
292
+ if (this.#options.disableSse) {
293
+ return new Response(null, {
294
+ status: 405,
295
+ headers: {
296
+ Allow: 'POST, DELETE, OPTIONS',
297
+ },
298
+ });
299
+ }
300
+
284
301
  const sessions = this.#options.sessionManager;
285
302
  const text_encoder = this.#text_encoder;
286
303
  // If session already exists, return error
@@ -407,7 +424,9 @@ export class HttpTransport {
407
424
 
408
425
  controller?.enqueue(
409
426
  this.#text_encoder.encode(
410
- 'data: ' + JSON.stringify(response) + '\n\n',
427
+ 'event: message\ndata: ' +
428
+ JSON.stringify(response) +
429
+ '\n\n',
411
430
  ),
412
431
  );
413
432
  controller?.close();
@@ -26,6 +26,7 @@ declare module '@tmcp/transport-http' {
26
26
  streams?: StreamSessionManager;
27
27
  info?: OptionalizeSessionManager<InfoSessionManager>;
28
28
  };
29
+ disableSse?: boolean;
29
30
  };
30
31
  type ToOmit = 'removeSubscription';
31
32
 
@@ -14,6 +14,6 @@
14
14
  null,
15
15
  null
16
16
  ],
17
- "mappings": ";;;;cAsCaA,aAAaA;;;;;;;;;;;;;;;;;;;;;;;;;MCnCrBC,MAAMA;;MAECC,yBAAyBA",
17
+ "mappings": ";;;;cAuCaA,aAAaA;;;;;;;;;;;;;;;;;;;;;;;;;;MCpCrBC,MAAMA;;MAECC,yBAAyBA",
18
18
  "ignoreList": []
19
19
  }