@ttoss/http-server-mcp 0.28.0 → 0.28.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/MIGRATIONS.md CHANGED
@@ -1,5 +1,40 @@
1
1
  # Migrations
2
2
 
3
+ ## The `2026-07-28` revision needs `createMcpServer`
4
+
5
+ That revision is served only when `createMcpRouter` is given a
6
+ `createMcpServer` factory.
7
+
8
+ ```diff
9
+ +const buildServer = () => {
10
+ + const mcpServer = new McpServer({ name: 'my-server', version: '1.0.0' });
11
+ + registerEverything(mcpServer);
12
+ + return mcpServer;
13
+ +};
14
+ +
15
+ -createMcpRouter(mcpServer, {
16
+ +createMcpRouter(buildServer(), {
17
+ + createMcpServer: buildServer,
18
+ auth: { ... },
19
+ });
20
+ ```
21
+
22
+ **Why it cannot default to the server you already pass.** The negotiated
23
+ revision is instance state: serving one `2026-07-28` request marks that
24
+ `McpServer` modern for good, and it then validates every later message against
25
+ that revision. One instance serving both eras is pinned by the first client to
26
+ speak the newer one, after which every 2025-era request is answered
27
+ `-32602 Request is missing the required _meta envelope for protocol revision
28
+ 2026-07-28` at **HTTP 200** for the life of the process — a status and body a
29
+ client reads as "no tools" rather than as a fault. The SDK's own serving
30
+ entries take a factory and call it once per request for this reason.
31
+
32
+ **What you will observe if you miss this.** A client speaking `2026-07-28` gets
33
+ `400` with `-32022 Unsupported protocol version` and `data.supported` listing
34
+ the 2025-era revisions, which it can renegotiate from. Only deployments
35
+ actually receiving that traffic are affected; every client without the
36
+ per-request envelope is served exactly as before.
37
+
3
38
  ## `tools/list` is no longer public by default
4
39
 
5
40
  `auth.publicMethods` now defaults to `['initialize']` instead of
package/README.md CHANGED
@@ -906,7 +906,27 @@ app.listen(3000);
906
906
 
907
907
  This package implements the [Model Context Protocol](https://spec.modelcontextprotocol.io/) over HTTP using JSON responses (no SSE streaming), and serves each request over the protocol revision it actually speaks.
908
908
 
909
- Requests are classified once at the boundary. Traffic from today's MCP clients is served over `NodeStreamableHTTPServerTransport` with `enableJsonResponse: true`, adapting Koa's context-based middleware to the SDK's Node.js request/response expectations. Requests carrying the `2026-07-28` revision's per-request envelope are served by that revision's stateless core (`createMcpHandler`) instead. Both paths are served from the same `McpServer` instance and the same registered tools, so supporting the newer revision requires no configuration.
909
+ Requests are classified once at the boundary, and the classifier's answer is three-way. Traffic from today's MCP clients is served over `NodeStreamableHTTPServerTransport` with `enableJsonResponse: true`, adapting Koa's context-based middleware to the SDK's Node.js request/response expectations. Requests carrying the `2026-07-28` revision's per-request envelope are served by that revision's stateless core (`createMcpHandler`). Requests the classifier refuses outright are answered with its own rejection — the status, code, message and data it chose — rather than passed to either era's handler.
910
+
911
+ ### Serving the `2026-07-28` revision
912
+
913
+ Set `createMcpServer` to a factory returning an `McpServer` with the same tools registered:
914
+
915
+ ```typescript
916
+ const buildServer = () => {
917
+ const mcpServer = new McpServer({ name: 'my-server', version: '1.0.0' });
918
+ registerEverything(mcpServer);
919
+ return mcpServer;
920
+ };
921
+
922
+ const mcpRouter = createMcpRouter(buildServer(), {
923
+ createMcpServer: buildServer,
924
+ });
925
+ ```
926
+
927
+ It has to be a factory, and cannot default to the server the router was given, because the negotiated revision is instance state: serving one `2026-07-28` request marks that `McpServer` modern for good, and it then validates every later message against that revision. One instance serving both eras is pinned by the first client to speak the newer one, after which every 2025-era request is answered `-32602 Request is missing the required _meta envelope…` at HTTP 200 for the life of the process. The SDK's own serving entries take a factory and call it once per request for the same reason.
928
+
929
+ Without `createMcpServer`, `2026-07-28` requests get the unsupported-protocol-version error listing the revisions this endpoint does serve, so that client renegotiates and no other client is affected.
910
930
 
911
931
  **Supported HTTP methods:**
912
932
 
package/dist/index.cjs CHANGED
@@ -36,41 +36,88 @@ var header = (ctx, name) => {
36
36
  const value = ctx.get(name);
37
37
  return value === "" ? void 0 : value;
38
38
  };
39
+ /** The id to echo in an error answer, by the SDK's own rule. */
40
+ var echoableRequestId = body => {
41
+ if (body === null || typeof body !== "object" || Array.isArray(body)) return null;
42
+ const {
43
+ id,
44
+ method
45
+ } = body;
46
+ if (typeof method !== "string") return null;
47
+ return typeof id === "string" || typeof id === "number" ? id : null;
48
+ };
49
+ /**
50
+ * Writes a JSON-RPC error straight to the Node response: `createMcpRouter` sets
51
+ * `ctx.respond = false` after serving, so Koa never writes `ctx.body`.
52
+ */
53
+ var emitJsonRpcError = (ctx, answer, body) => {
54
+ ctx.res.writeHead(answer.httpStatus, {
55
+ "content-type": "application/json"
56
+ });
57
+ ctx.res.end(JSON.stringify({
58
+ jsonrpc: "2.0",
59
+ error: {
60
+ code: answer.code,
61
+ message: answer.message,
62
+ ...(answer.data !== void 0 && {
63
+ data: answer.data
64
+ })
65
+ },
66
+ id: echoableRequestId(body)
67
+ }));
68
+ };
69
+ /** The SDK's own ladder rejection, emitted with the status the SDK chose. */
70
+ var rejectionAnswer = rejection => {
71
+ return {
72
+ httpStatus: rejection.httpStatus,
73
+ code: rejection.code,
74
+ message: rejection.message,
75
+ ...(rejection.data !== void 0 && {
76
+ data: rejection.data
77
+ })
78
+ };
79
+ };
80
+ /**
81
+ * The answer to `2026-07-28` traffic without `createMcpServer`. `data.supported`
82
+ * is what lets the client renegotiate onto a revision this endpoint serves.
83
+ */
84
+ var REVISION_NOT_SERVED_ANSWER = {
85
+ httpStatus: 400,
86
+ code: _modelcontextprotocol_server.ProtocolErrorCode.UnsupportedProtocolVersion,
87
+ message: "Unsupported protocol version: this endpoint serves the 2025-era MCP revisions only. Pass createMcpServer to createMcpRouter to serve protocol revision 2026-07-28.",
88
+ data: {
89
+ supported: [..._modelcontextprotocol_server.SUPPORTED_PROTOCOL_VERSIONS]
90
+ }
91
+ };
39
92
  /**
40
93
  * Builds the per-request serving function used by `createMcpRouter`, routing
41
- * each request to the protocol revision it actually speaks.
42
- *
43
- * Requests are classified once at the boundary with the SDK's own
44
- * `classifyInboundRequest`:
45
- *
46
- * - **2025-era traffic** (everything without a `2026-07-28` per-request
47
- * envelope — which is all traffic from today's MCP clients) is served over
48
- * `NodeStreamableHTTPServerTransport` with `enableJsonResponse: true`, the
49
- * same wiring and the same plain-JSON responses this package has always
50
- * produced.
51
- * - **`2026-07-28` traffic** is served by `createMcpHandler` with
52
- * `legacy: 'reject'`, so the modern revision is handled by the SDK's
53
- * stateless core rather than the transport above. Malformed requests are
54
- * routed here too, so the SDK emits its own spec-defined rejection instead of
55
- * this package inventing one.
56
- *
57
- * Splitting on the classifier — instead of letting `createMcpHandler` serve
58
- * both eras through its built-in legacy fallback — is what keeps 2025-era
59
- * responses byte-compatible. That fallback constructs its transport with only
60
- * `sessionIdGenerator: undefined` and no way to pass `enableJsonResponse`, so
61
- * every response it produces is SSE-framed (`text/event-stream`) regardless of
62
- * the handler's `responseMode`. Owning the legacy branch keeps `application/json`.
94
+ * each request by the SDK's three-way `classifyInboundRequest` outcome.
95
+ *
96
+ * **Why the modern era needs `createMcpServer` rather than the `server` above.**
97
+ * The negotiated revision is *instance* state: the SDK marks an instance modern
98
+ * when it serves one modern request, and it then validates every later message
99
+ * against `2026-07-28` — there is no per-request era consult. One instance
100
+ * serving both eras is therefore pinned by the first client to speak the newer
101
+ * revision, after which every 2025-era request is answered `-32602 Request is
102
+ * missing the required _meta envelope…` at HTTP 200 for the life of the
103
+ * process. The SDK's own entries take a factory and call it per request for
104
+ * this reason (they also `close()` the instance, which a shared one cannot
105
+ * survive). Without the factory, `2026-07-28` traffic gets
106
+ * {@link REVISION_NOT_SERVED_ANSWER} and no other client is affected.
107
+ *
108
+ * **Why not `createMcpHandler`'s built-in legacy fallback.** It constructs its
109
+ * transport with no way to pass `enableJsonResponse`, so every response it
110
+ * produces is SSE-framed. Owning the legacy branch keeps `application/json`.
63
111
  */
64
112
  var createMcpRequestServer = ({
113
+ createMcpServer,
65
114
  server,
66
115
  sessionIdGenerator
67
116
  }) => {
68
117
  const isStateful = sessionIdGenerator !== void 0;
69
- const modernHandler = (0, _modelcontextprotocol_node.toNodeHandler)((0, _modelcontextprotocol_server.createMcpHandler)(() => {
70
- return server;
71
- }, {
118
+ const modernHandler = createMcpServer ? (0, _modelcontextprotocol_node.toNodeHandler)((0, _modelcontextprotocol_server.createMcpHandler)(createMcpServer, {
72
119
  legacy: "reject"
73
- }));
120
+ })) : void 0;
74
121
  let sharedTransport;
75
122
  if (isStateful) {
76
123
  sharedTransport = new _modelcontextprotocol_node.NodeStreamableHTTPServerTransport({
@@ -87,17 +134,23 @@ var createMcpRequestServer = ({
87
134
  statelessQueue = result.catch(() => {});
88
135
  return result;
89
136
  };
90
- const isLegacy = (ctx, body) => {
91
- return (0, _modelcontextprotocol_server.classifyInboundRequest)({
137
+ return async (ctx, body) => {
138
+ const outcome = (0, _modelcontextprotocol_server.classifyInboundRequest)({
92
139
  httpMethod: ctx.method,
93
140
  protocolVersionHeader: header(ctx, "mcp-protocol-version"),
94
141
  mcpMethodHeader: header(ctx, "mcp-method"),
95
142
  mcpNameHeader: header(ctx, "mcp-name"),
96
143
  body
97
- }).kind === "legacy";
98
- };
99
- return async (ctx, body) => {
100
- if (!isLegacy(ctx, body)) {
144
+ });
145
+ if (outcome.kind === "reject") {
146
+ emitJsonRpcError(ctx, rejectionAnswer(outcome), body);
147
+ return;
148
+ }
149
+ if (outcome.kind === "modern") {
150
+ if (modernHandler === void 0) {
151
+ emitJsonRpcError(ctx, REVISION_NOT_SERVED_ANSWER, body);
152
+ return;
153
+ }
101
154
  await modernHandler(ctx.req, ctx.res, body);
102
155
  return;
103
156
  }
@@ -692,6 +745,7 @@ var createMcpRouter = (server, options = {}) => {
692
745
  path = "/mcp",
693
746
  aliases = [],
694
747
  sessionIdGenerator,
748
+ createMcpServer,
695
749
  apiBaseUrl,
696
750
  getApiHeaders,
697
751
  auth
@@ -699,7 +753,8 @@ var createMcpRouter = (server, options = {}) => {
699
753
  const needsContext = apiBaseUrl !== void 0 || getApiHeaders !== void 0 || auth !== void 0;
700
754
  const serveRequest = createMcpRequestServer({
701
755
  server,
702
- sessionIdGenerator
756
+ sessionIdGenerator,
757
+ createMcpServer
703
758
  });
704
759
  const router = new _ttoss_http_server.Router();
705
760
  let authCheck;
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
 
2
2
  /// <reference types="node" />
3
- import { CallToolResult, McpServer, McpServer as McpServer$1, RegisteredResource } from "@modelcontextprotocol/server";
3
+ import { CallToolResult, McpServer, McpServer as McpServer$1, McpServerFactory, RegisteredResource } from "@modelcontextprotocol/server";
4
4
  import { Router } from "@ttoss/http-server";
5
5
  import accepts from "accepts";
6
6
  import { AsyncLocalStorage } from "async_hooks";
@@ -1310,6 +1310,31 @@ interface McpRouterOptions {
1310
1310
  * served statelessly regardless of this option.
1311
1311
  */
1312
1312
  sessionIdGenerator?: () => string;
1313
+ /**
1314
+ * Per-request factory for the `McpServer` serving one `2026-07-28` request.
1315
+ * Set it to serve that revision; without it, requests carrying its
1316
+ * per-request envelope get the unsupported-protocol-version error naming the
1317
+ * 2025-era revisions this endpoint does serve. Register the same tools here
1318
+ * as on `server`, so the two eras cannot drift apart.
1319
+ *
1320
+ * It cannot default to `server`: the negotiated revision is instance state,
1321
+ * so one instance serving both eras is pinned to `2026-07-28` by the first
1322
+ * client to speak it, and every 2025-era request after that is answered
1323
+ * `-32602 … missing the required _meta envelope` at HTTP 200. The SDK's own
1324
+ * serving entries take a factory and call it once per request.
1325
+ *
1326
+ * @example
1327
+ * ```typescript
1328
+ * const buildServer = () => {
1329
+ * const mcpServer = new McpServer({ name: 'my-server', version: '1.0.0' });
1330
+ * registerEverything(mcpServer);
1331
+ * return mcpServer;
1332
+ * };
1333
+ *
1334
+ * createMcpRouter(buildServer(), { createMcpServer: buildServer });
1335
+ * ```
1336
+ */
1337
+ createMcpServer?: McpServerFactory;
1313
1338
  /**
1314
1339
  * Base URL prepended to relative paths passed to `apiCall` (paths starting
1315
1340
  * with `/`). Tool handlers can then call `apiCall('GET', '/resource')` without
package/dist/index.d.mts CHANGED
@@ -2,7 +2,7 @@
2
2
  /// <reference types="node" />
3
3
  import { Router } from "@ttoss/http-server";
4
4
  import { AsyncLocalStorage } from "node:async_hooks";
5
- import { CallToolResult, McpServer, McpServer as McpServer$1, RegisteredResource } from "@modelcontextprotocol/server";
5
+ import { CallToolResult, McpServer, McpServer as McpServer$1, McpServerFactory, RegisteredResource } from "@modelcontextprotocol/server";
6
6
  import { z } from "zod";
7
7
  import accepts from "accepts";
8
8
  import { AsyncLocalStorage as AsyncLocalStorage$1 } from "async_hooks";
@@ -1311,6 +1311,31 @@ interface McpRouterOptions {
1311
1311
  * served statelessly regardless of this option.
1312
1312
  */
1313
1313
  sessionIdGenerator?: () => string;
1314
+ /**
1315
+ * Per-request factory for the `McpServer` serving one `2026-07-28` request.
1316
+ * Set it to serve that revision; without it, requests carrying its
1317
+ * per-request envelope get the unsupported-protocol-version error naming the
1318
+ * 2025-era revisions this endpoint does serve. Register the same tools here
1319
+ * as on `server`, so the two eras cannot drift apart.
1320
+ *
1321
+ * It cannot default to `server`: the negotiated revision is instance state,
1322
+ * so one instance serving both eras is pinned to `2026-07-28` by the first
1323
+ * client to speak it, and every 2025-era request after that is answered
1324
+ * `-32602 … missing the required _meta envelope` at HTTP 200. The SDK's own
1325
+ * serving entries take a factory and call it once per request.
1326
+ *
1327
+ * @example
1328
+ * ```typescript
1329
+ * const buildServer = () => {
1330
+ * const mcpServer = new McpServer({ name: 'my-server', version: '1.0.0' });
1331
+ * registerEverything(mcpServer);
1332
+ * return mcpServer;
1333
+ * };
1334
+ *
1335
+ * createMcpRouter(buildServer(), { createMcpServer: buildServer });
1336
+ * ```
1337
+ */
1338
+ createMcpServer?: McpServerFactory;
1314
1339
  /**
1315
1340
  * Base URL prepended to relative paths passed to `apiCall` (paths starting
1316
1341
  * with `/`). Tool handlers can then call `apiCall('GET', '/resource')` without
package/dist/index.mjs CHANGED
@@ -5,7 +5,7 @@ import { Router } from "@ttoss/http-server";
5
5
  import { authMiddleware } from "@ttoss/http-server-auth";
6
6
  import { AsyncLocalStorage } from "node:async_hooks";
7
7
  import { NodeStreamableHTTPServerTransport, toNodeHandler } from "@modelcontextprotocol/node";
8
- import { McpServer, classifyInboundRequest, createMcpHandler, fromJsonSchema } from "@modelcontextprotocol/server";
8
+ import { McpServer, ProtocolErrorCode, SUPPORTED_PROTOCOL_VERSIONS, classifyInboundRequest, createMcpHandler, fromJsonSchema } from "@modelcontextprotocol/server";
9
9
  import { z } from "zod";
10
10
 
11
11
  //#region src/context.ts
@@ -33,41 +33,88 @@ var header = (ctx, name) => {
33
33
  const value = ctx.get(name);
34
34
  return value === "" ? void 0 : value;
35
35
  };
36
+ /** The id to echo in an error answer, by the SDK's own rule. */
37
+ var echoableRequestId = body => {
38
+ if (body === null || typeof body !== "object" || Array.isArray(body)) return null;
39
+ const {
40
+ id,
41
+ method
42
+ } = body;
43
+ if (typeof method !== "string") return null;
44
+ return typeof id === "string" || typeof id === "number" ? id : null;
45
+ };
46
+ /**
47
+ * Writes a JSON-RPC error straight to the Node response: `createMcpRouter` sets
48
+ * `ctx.respond = false` after serving, so Koa never writes `ctx.body`.
49
+ */
50
+ var emitJsonRpcError = (ctx, answer, body) => {
51
+ ctx.res.writeHead(answer.httpStatus, {
52
+ "content-type": "application/json"
53
+ });
54
+ ctx.res.end(JSON.stringify({
55
+ jsonrpc: "2.0",
56
+ error: {
57
+ code: answer.code,
58
+ message: answer.message,
59
+ ...(answer.data !== void 0 && {
60
+ data: answer.data
61
+ })
62
+ },
63
+ id: echoableRequestId(body)
64
+ }));
65
+ };
66
+ /** The SDK's own ladder rejection, emitted with the status the SDK chose. */
67
+ var rejectionAnswer = rejection => {
68
+ return {
69
+ httpStatus: rejection.httpStatus,
70
+ code: rejection.code,
71
+ message: rejection.message,
72
+ ...(rejection.data !== void 0 && {
73
+ data: rejection.data
74
+ })
75
+ };
76
+ };
77
+ /**
78
+ * The answer to `2026-07-28` traffic without `createMcpServer`. `data.supported`
79
+ * is what lets the client renegotiate onto a revision this endpoint serves.
80
+ */
81
+ var REVISION_NOT_SERVED_ANSWER = {
82
+ httpStatus: 400,
83
+ code: ProtocolErrorCode.UnsupportedProtocolVersion,
84
+ message: "Unsupported protocol version: this endpoint serves the 2025-era MCP revisions only. Pass createMcpServer to createMcpRouter to serve protocol revision 2026-07-28.",
85
+ data: {
86
+ supported: [...SUPPORTED_PROTOCOL_VERSIONS]
87
+ }
88
+ };
36
89
  /**
37
90
  * Builds the per-request serving function used by `createMcpRouter`, routing
38
- * each request to the protocol revision it actually speaks.
39
- *
40
- * Requests are classified once at the boundary with the SDK's own
41
- * `classifyInboundRequest`:
42
- *
43
- * - **2025-era traffic** (everything without a `2026-07-28` per-request
44
- * envelope — which is all traffic from today's MCP clients) is served over
45
- * `NodeStreamableHTTPServerTransport` with `enableJsonResponse: true`, the
46
- * same wiring and the same plain-JSON responses this package has always
47
- * produced.
48
- * - **`2026-07-28` traffic** is served by `createMcpHandler` with
49
- * `legacy: 'reject'`, so the modern revision is handled by the SDK's
50
- * stateless core rather than the transport above. Malformed requests are
51
- * routed here too, so the SDK emits its own spec-defined rejection instead of
52
- * this package inventing one.
53
- *
54
- * Splitting on the classifier — instead of letting `createMcpHandler` serve
55
- * both eras through its built-in legacy fallback — is what keeps 2025-era
56
- * responses byte-compatible. That fallback constructs its transport with only
57
- * `sessionIdGenerator: undefined` and no way to pass `enableJsonResponse`, so
58
- * every response it produces is SSE-framed (`text/event-stream`) regardless of
59
- * the handler's `responseMode`. Owning the legacy branch keeps `application/json`.
91
+ * each request by the SDK's three-way `classifyInboundRequest` outcome.
92
+ *
93
+ * **Why the modern era needs `createMcpServer` rather than the `server` above.**
94
+ * The negotiated revision is *instance* state: the SDK marks an instance modern
95
+ * when it serves one modern request, and it then validates every later message
96
+ * against `2026-07-28` — there is no per-request era consult. One instance
97
+ * serving both eras is therefore pinned by the first client to speak the newer
98
+ * revision, after which every 2025-era request is answered `-32602 Request is
99
+ * missing the required _meta envelope…` at HTTP 200 for the life of the
100
+ * process. The SDK's own entries take a factory and call it per request for
101
+ * this reason (they also `close()` the instance, which a shared one cannot
102
+ * survive). Without the factory, `2026-07-28` traffic gets
103
+ * {@link REVISION_NOT_SERVED_ANSWER} and no other client is affected.
104
+ *
105
+ * **Why not `createMcpHandler`'s built-in legacy fallback.** It constructs its
106
+ * transport with no way to pass `enableJsonResponse`, so every response it
107
+ * produces is SSE-framed. Owning the legacy branch keeps `application/json`.
60
108
  */
61
109
  var createMcpRequestServer = ({
110
+ createMcpServer,
62
111
  server,
63
112
  sessionIdGenerator
64
113
  }) => {
65
114
  const isStateful = sessionIdGenerator !== void 0;
66
- const modernHandler = toNodeHandler(createMcpHandler(() => {
67
- return server;
68
- }, {
115
+ const modernHandler = createMcpServer ? toNodeHandler(createMcpHandler(createMcpServer, {
69
116
  legacy: "reject"
70
- }));
117
+ })) : void 0;
71
118
  let sharedTransport;
72
119
  if (isStateful) {
73
120
  sharedTransport = new NodeStreamableHTTPServerTransport({
@@ -84,17 +131,23 @@ var createMcpRequestServer = ({
84
131
  statelessQueue = result.catch(() => {});
85
132
  return result;
86
133
  };
87
- const isLegacy = (ctx, body) => {
88
- return classifyInboundRequest({
134
+ return async (ctx, body) => {
135
+ const outcome = classifyInboundRequest({
89
136
  httpMethod: ctx.method,
90
137
  protocolVersionHeader: header(ctx, "mcp-protocol-version"),
91
138
  mcpMethodHeader: header(ctx, "mcp-method"),
92
139
  mcpNameHeader: header(ctx, "mcp-name"),
93
140
  body
94
- }).kind === "legacy";
95
- };
96
- return async (ctx, body) => {
97
- if (!isLegacy(ctx, body)) {
141
+ });
142
+ if (outcome.kind === "reject") {
143
+ emitJsonRpcError(ctx, rejectionAnswer(outcome), body);
144
+ return;
145
+ }
146
+ if (outcome.kind === "modern") {
147
+ if (modernHandler === void 0) {
148
+ emitJsonRpcError(ctx, REVISION_NOT_SERVED_ANSWER, body);
149
+ return;
150
+ }
98
151
  await modernHandler(ctx.req, ctx.res, body);
99
152
  return;
100
153
  }
@@ -689,6 +742,7 @@ var createMcpRouter = (server, options = {}) => {
689
742
  path = "/mcp",
690
743
  aliases = [],
691
744
  sessionIdGenerator,
745
+ createMcpServer,
692
746
  apiBaseUrl,
693
747
  getApiHeaders,
694
748
  auth
@@ -696,7 +750,8 @@ var createMcpRouter = (server, options = {}) => {
696
750
  const needsContext = apiBaseUrl !== void 0 || getApiHeaders !== void 0 || auth !== void 0;
697
751
  const serveRequest = createMcpRequestServer({
698
752
  server,
699
- sessionIdGenerator
753
+ sessionIdGenerator,
754
+ createMcpServer
700
755
  });
701
756
  const router = new Router();
702
757
  let authCheck;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttoss/http-server-mcp",
3
- "version": "0.28.0",
3
+ "version": "0.28.1",
4
4
  "description": "Model Context Protocol (MCP) server integration for @ttoss/http-server",
5
5
  "keywords": [
6
6
  "ai",