You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
const transport =newNodeStreamableHTTPServerTransport({
34
-
sessionIdGenerator: () =>randomUUID()
33
+
app.post('/mcp', async (req, res) => {
34
+
const server =newMcpServer({ name: 'my-server', version: '1.0.0' });
35
+
const transport =newNodeStreamableHTTPServerTransport({
36
+
sessionIdGenerator: undefined// stateless
37
+
});
38
+
awaitserver.connect(transport);
39
+
awaittransport.handleRequest(req, res, req.body);
35
40
});
36
41
37
-
awaitserver.connect(transport);
42
+
app.listen(3000, '127.0.0.1');
38
43
```
39
44
45
+
For stateful servers with session management, see [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts).
46
+
40
47
> [!NOTE]
41
48
> For full runnable examples, see [`simpleStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/simpleStreamableHttp.ts) (sessions, logging, tasks, elicitation, auth hooks), [`jsonResponseStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/jsonResponseStreamableHttp.ts) (`enableJsonResponse: true`, no SSE), and [`standaloneSseWithGetStreamableHttp.ts`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/examples/server/src/standaloneSseWithGetStreamableHttp.ts) (notifications with Streamable HTTP GET + SSE).
42
49
>
43
50
> For protocol details, see [Transports](https://modelcontextprotocol.io/specification/latest/basic/transports) in the MCP specification.
44
51
52
+
> [!WARNING]
53
+
> If your server listens on localhost, use [`createMcpExpressApp()`](#dns-rebinding-protection) or [`createMcpHonoApp()`](#dns-rebinding-protection) instead of using `NodeStreamableHTTPServerTransport` directly — they include [DNS rebinding protection](#dns-rebinding-protection) by default.
54
+
45
55
#### Stateless vs stateful sessions
46
56
47
57
Streamable HTTP can run:
@@ -438,7 +448,9 @@ Task-based execution enables "call-now, fetch-later" patterns for long-running o
438
448
439
449
### DNS rebinding protection
440
450
441
-
MCP servers running on localhost are vulnerable to DNS rebinding attacks. Use `createMcpExpressApp()` from `@modelcontextprotocol/express` to create an Express app with DNS rebinding protection enabled by default:
451
+
Under normal circumstances, cross-origin browser restrictions limit what a malicious website can do to your localhost server. [DNS rebinding attacks](https://en.wikipedia.org/wiki/DNS_rebinding) get around those restrictions entirely by making the requests appear as same-origin, since the attacking domain resolves to localhost. Validating the host header on the server side protects against this scenario. **All localhost MCP servers should use DNS rebinding protection.**
452
+
453
+
The recommended approach is to use `createMcpExpressApp()` (from `@modelcontextprotocol/express`) or `createMcpHonoApp()` (from `@modelcontextprotocol/hono`), which enable Host header validation by default:
`createMcpHonoApp()` from `@modelcontextprotocol/hono` provides the same protection for Hono-based servers and Web Standard runtimes (Cloudflare Workers, Deno, Bun).
476
+
477
+
If you use `NodeStreamableHTTPServerTransport` directly with your own HTTP framework, you must implement Host header validation yourself. See the [`hostHeaderValidation`](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/packages/middleware/express/src/express.ts) middleware source for reference.
478
+
463
479
## More server features
464
480
465
481
The sections above cover the essentials. The table below links to additional capabilities demonstrated in the runnable examples.
0 commit comments