@tmcp/transport-http 0.6.3 → 0.7.1
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 +6 -3
- package/package.json +7 -6
- package/src/index.js +27 -13
- package/src/types/index.d.ts +1 -1
- package/src/types/index.d.ts.map +1 -1
package/README.md
CHANGED
|
@@ -72,13 +72,16 @@ httpServer.listen(3000, () => {
|
|
|
72
72
|
|
|
73
73
|
```javascript
|
|
74
74
|
const transport = new HttpTransport(server, {
|
|
75
|
-
// Custom MCP endpoint path (default: '/mcp')
|
|
75
|
+
// Custom MCP endpoint path (default: '/mcp', use null to respond on every path)
|
|
76
76
|
path: '/api/mcp',
|
|
77
77
|
// Custom session ID generation
|
|
78
78
|
getSessionId: () => {
|
|
79
79
|
return `session-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
80
80
|
},
|
|
81
81
|
});
|
|
82
|
+
|
|
83
|
+
> [!NOTE]
|
|
84
|
+
> When the transport runs in development mode and you omit the `path` option, a warning is emitted. Future releases will treat an `undefined` path as "respond on every path", so set the property explicitly (for example `path: '/mcp'` or `path: null`) to lock in the behavior you want today.
|
|
82
85
|
```
|
|
83
86
|
|
|
84
87
|
### With Custom Context
|
|
@@ -162,7 +165,7 @@ const transport = new HttpTransport(server, {
|
|
|
162
165
|
- **🌐 HTTP/SSE Communication**: Uses Server-Sent Events for real-time bidirectional communication
|
|
163
166
|
- **🔄 Session Management**: Maintains client sessions with automatic session ID generation
|
|
164
167
|
- **📡 Streaming Responses**: Supports streaming responses through SSE
|
|
165
|
-
- **🛤️ Configurable Path**: Customizable MCP endpoint path with automatic filtering
|
|
168
|
+
- **🛤️ Configurable Path**: Customizable MCP endpoint path with automatic filtering (set `path` to `null` to respond everywhere)
|
|
166
169
|
- **🔧 Framework Agnostic**: Works with any HTTP server framework (Fastify, Bun, Deno, etc.)
|
|
167
170
|
- **⚡ Real-time Updates**: Server can push notifications and updates to connected clients
|
|
168
171
|
- **🛡️ Error Handling**: Graceful error handling for malformed requests
|
|
@@ -190,7 +193,7 @@ Creates a new HTTP transport instance.
|
|
|
190
193
|
```typescript
|
|
191
194
|
interface HttpTransportOptions {
|
|
192
195
|
getSessionId: () => string; // Custom session ID generator
|
|
193
|
-
path?: string; // MCP endpoint path (default: '/mcp')
|
|
196
|
+
path?: string | null; // MCP endpoint path (default: '/mcp', null responds on every path)
|
|
194
197
|
oauth?: OAuth; // an oauth provider generated from @tmcp/auth
|
|
195
198
|
sessionManager?: SessionManager; // Custom session manager (default: InMemorySessionManager)
|
|
196
199
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tmcp/transport-http",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "Transport for TMCP using HTTP",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"src/**/*"
|
|
17
17
|
],
|
|
18
18
|
"peerDependencies": {
|
|
19
|
-
"tmcp": "^1.
|
|
19
|
+
"tmcp": "^1.15.3"
|
|
20
20
|
},
|
|
21
21
|
"keywords": [
|
|
22
22
|
"tmcp",
|
|
@@ -29,19 +29,20 @@
|
|
|
29
29
|
"directory": "packages/transport-http"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
+
"esm-env": "^1.2.2",
|
|
32
33
|
"@tmcp/session-manager": "^0.1.2"
|
|
33
34
|
},
|
|
34
35
|
"devDependencies": {
|
|
35
36
|
"@modelcontextprotocol/sdk": "^1.17.1",
|
|
36
|
-
"@remix-run/node-fetch-server": "^0.
|
|
37
|
+
"@remix-run/node-fetch-server": "^0.11.0",
|
|
37
38
|
"@types/node": "^24.0.15",
|
|
38
39
|
"dts-buddy": "^0.6.2",
|
|
39
40
|
"publint": "^0.3.12",
|
|
40
41
|
"valibot": "^1.1.0",
|
|
41
|
-
"vitest": "^
|
|
42
|
+
"vitest": "^4.0.0",
|
|
43
|
+
"@tmcp/adapter-valibot": "^0.1.4",
|
|
42
44
|
"@tmcp/auth": "^0.3.3",
|
|
43
|
-
"tmcp": "^1.
|
|
44
|
-
"@tmcp/adapter-valibot": "^0.1.4"
|
|
45
|
+
"tmcp": "^1.15.3"
|
|
45
46
|
},
|
|
46
47
|
"publishConfig": {
|
|
47
48
|
"access": "public"
|
package/src/index.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
/**
|
|
19
19
|
* @typedef {{
|
|
20
20
|
* getSessionId?: () => string
|
|
21
|
-
* path?: string
|
|
21
|
+
* path?: string | null
|
|
22
22
|
* oauth?: OAuth<"built">
|
|
23
23
|
* cors?: CorsConfig | boolean,
|
|
24
24
|
* sessionManager?: SessionManager
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
|
|
28
28
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
29
29
|
import { InMemorySessionManager } from '@tmcp/session-manager';
|
|
30
|
+
import { DEV } from 'esm-env';
|
|
30
31
|
|
|
31
32
|
/**
|
|
32
33
|
* @template {Record<string, unknown> | undefined} [TCustom=undefined]
|
|
@@ -43,7 +44,7 @@ export class HttpTransport {
|
|
|
43
44
|
#options;
|
|
44
45
|
|
|
45
46
|
/**
|
|
46
|
-
* @type {string}
|
|
47
|
+
* @type {string | null}
|
|
47
48
|
*/
|
|
48
49
|
#path;
|
|
49
50
|
|
|
@@ -76,6 +77,13 @@ export class HttpTransport {
|
|
|
76
77
|
getSessionId: () => crypto.randomUUID(),
|
|
77
78
|
};
|
|
78
79
|
|
|
80
|
+
if (options?.path === undefined && DEV) {
|
|
81
|
+
// TODO: remove on 1.0.0 release
|
|
82
|
+
console.warn(
|
|
83
|
+
"[tmcp][transport-http] `options.path` is undefined, in future versions passing `undefined` will default to respond on all paths. To keep the current behavior, explicitly set `path` to '/mcp' or your desired path.",
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
79
87
|
if (oauth) {
|
|
80
88
|
this.#oauth = oauth;
|
|
81
89
|
}
|
|
@@ -205,6 +213,7 @@ export class HttpTransport {
|
|
|
205
213
|
*/
|
|
206
214
|
async #handle_get(session_id) {
|
|
207
215
|
const sessions = this.#options.sessionManager;
|
|
216
|
+
const text_encoder = this.#text_encoder;
|
|
208
217
|
// If session already exists, return error
|
|
209
218
|
const existing_session = await sessions.has(session_id);
|
|
210
219
|
if (existing_session) {
|
|
@@ -232,6 +241,8 @@ export class HttpTransport {
|
|
|
232
241
|
const stream = new ReadableStream({
|
|
233
242
|
async start(controller) {
|
|
234
243
|
await sessions.create(session_id, controller);
|
|
244
|
+
// send a comment to flush the headers immediately
|
|
245
|
+
controller.enqueue(text_encoder.encode(': connected\n\n'));
|
|
235
246
|
},
|
|
236
247
|
async cancel() {
|
|
237
248
|
await sessions.delete(session_id);
|
|
@@ -317,18 +328,21 @@ export class HttpTransport {
|
|
|
317
328
|
|
|
318
329
|
const messages = Array.isArray(body) ? body : [body];
|
|
319
330
|
|
|
331
|
+
const has_request = messages.some((message) => message.id != null);
|
|
332
|
+
|
|
320
333
|
// Determine status code based on response type
|
|
321
334
|
// 202 Accepted for notifications/responses, 200 OK for standard requests
|
|
322
|
-
const status = !
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
335
|
+
const status = !has_request ? 202 : 200;
|
|
336
|
+
|
|
337
|
+
return new Response(has_request ? stream : null, {
|
|
338
|
+
headers: has_request
|
|
339
|
+
? {
|
|
340
|
+
'Content-Type': 'text/event-stream',
|
|
341
|
+
'Cache-Control': 'no-cache',
|
|
342
|
+
connection: 'keep-alive',
|
|
343
|
+
'mcp-session-id': session_id,
|
|
344
|
+
}
|
|
345
|
+
: undefined,
|
|
332
346
|
status,
|
|
333
347
|
});
|
|
334
348
|
} catch (error) {
|
|
@@ -415,7 +429,7 @@ export class HttpTransport {
|
|
|
415
429
|
}
|
|
416
430
|
|
|
417
431
|
// Check if the request path matches the configured MCP path
|
|
418
|
-
if (url.pathname !== this.#path) {
|
|
432
|
+
if (url.pathname !== this.#path && this.#path !== null) {
|
|
419
433
|
return null;
|
|
420
434
|
}
|
|
421
435
|
|
package/src/types/index.d.ts
CHANGED