@ttoss/http-server-mcp 0.30.2 → 0.31.0

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
@@ -611,6 +611,9 @@ Creates a Koa router configured to handle MCP protocol requests.
611
611
  - `path` (`string`) — HTTP path for MCP endpoint (default: `'/mcp'`)
612
612
  - `aliases` (`string[]`) — Additional paths where the MCP handler is also mounted; use `['/']` to also handle requests at the bare root (default: `[]`)
613
613
  - `sessionIdGenerator` (`() => string`) — Session ID generator for stateful servers (default: `undefined` for stateless)
614
+ - `createMcpServer` (`McpServerFactory`) — Per-request factory serving the `2026-07-28` revision; see [Serving the `2026-07-28` revision](#serving-the-2026-07-28-revision)
615
+ - `bus` (`ServerEventBus`) — Change-event bus `subscriptions/listen` streams subscribe to (default: in-process); see [Change notifications and shutdown](#change-notifications-and-shutdown)
616
+ - `keepAliveMs` (`number`) — SSE keepalive interval for `2026-07-28` streams (default: `15000`)
614
617
  - `apiBaseUrl` (`string`) — Base URL prepended to relative paths in `apiCall`
615
618
  - `getApiHeaders` (`(ctx: Context) => Record<string, string>`) — Return headers to inject into every `apiCall` for this request
616
619
  - `auth` (`McpAuthOptions`) — OAuth/JWT authentication; see [Authentication](#authentication)
@@ -622,7 +625,7 @@ Creates a Koa router configured to handle MCP protocol requests.
622
625
  - `auth.resourceMetadataUrl` — URL advertised in the RFC 9728 `WWW-Authenticate: Bearer resource_metadata="…"` header on a 401. Defaults to the location derived from `resourceServerUrl` + `path` (the one this router serves), so the header cannot drift from the routes; set it only when a separate `oauthServer()` serves the document and this router is mounted without `resourceServerUrl`/`authorizationServerUrl`
623
626
  - `auth.resourceIndicator` — Expected `aud` value(s) (RFC 8707); rejects tokens minted for a different resource. See [Resource indicator validation](#resource-indicator-validation-rfc-8707)
624
627
 
625
- **Returns:** `Router` — Koa router instance
628
+ **Returns:** `McpRouter` — the Koa router, plus `notify` (publish `list_changed` notifications to open `subscriptions/listen` streams) and `close()` (announce that the lists may have changed, then end every open `2026-07-28` exchange)
626
629
 
627
630
  ### `apiCall(method, url, options?)`
628
631
 
@@ -962,7 +965,7 @@ app.listen(3000);
962
965
 
963
966
  ## Protocol Details
964
967
 
965
- 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.
968
+ This package implements the [Model Context Protocol](https://spec.modelcontextprotocol.io/) over HTTP using JSON responses — SSE only for `2026-07-28` `subscriptions/listen` streams — and serves each request over the protocol revision it actually speaks.
966
969
 
967
970
  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.
968
971
 
@@ -986,6 +989,29 @@ It has to be a factory, and cannot default to the server the router was given, b
986
989
 
987
990
  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.
988
991
 
992
+ ### Change notifications and shutdown
993
+
994
+ A `2026-07-28` client learns about a changed tool list over a `subscriptions/listen` stream it holds open. The router serves those streams; `notify` publishes to them. Call `notify.toolsChanged()` after registering or removing a tool at runtime:
995
+
996
+ ```typescript
997
+ const mcpRouter = createMcpRouter(buildServer(), {
998
+ createMcpServer: buildServer,
999
+ });
1000
+
1001
+ mcpRouter.notify.toolsChanged();
1002
+ ```
1003
+
1004
+ A deploy changes the surface too, and the new process cannot know what a client cached — so the old one says so on its way out. Call `close()` on shutdown, before the HTTP server's own `close()`. It tells every open stream that the tool, prompt and resource lists may have changed, then ends the streams. That order matters twice: a client that does not re-list on reconnect learns to, and `server.close()` — which waits for every open request — is no longer held open by streams that never finish on their own, which would otherwise make every graceful shutdown wait out its whole grace period.
1005
+
1006
+ ```typescript
1007
+ process.on('SIGTERM', async () => {
1008
+ await mcpRouter.close();
1009
+ httpServer.close();
1010
+ });
1011
+ ```
1012
+
1013
+ The default bus is in-process, so `notify` reaches the streams this process holds. Behind several replicas, pass a `bus` implementing `ServerEventBus` over a shared pub/sub. Keep `keepAliveMs` below the idle timeout of anything in front of the server, or a quiet stream is cut there. 2025-era traffic is served statelessly, so it holds no stream to notify.
1014
+
989
1015
  **Supported HTTP methods:**
990
1016
 
991
1017
  - `POST /mcp` - Send JSON-RPC requests/notifications
package/dist/index.cjs CHANGED
@@ -48,6 +48,12 @@ var getRequestLocale = () => {
48
48
 
49
49
  //#endregion
50
50
  //#region src/serveMcpRequest.ts
51
+ var NO_NOTIFIER = {
52
+ toolsChanged: () => {},
53
+ promptsChanged: () => {},
54
+ resourcesChanged: () => {},
55
+ resourceUpdated: () => {}
56
+ };
51
57
  /**
52
58
  * Reads a header as `string | undefined`. Koa's `ctx.get` returns `''` for a
53
59
  * missing header, which the classifier would read as "header present but
@@ -133,12 +139,17 @@ var REVISION_NOT_SERVED_ANSWER = {
133
139
  var createMcpRequestServer = ({
134
140
  createMcpServer,
135
141
  server,
136
- sessionIdGenerator
142
+ sessionIdGenerator,
143
+ bus,
144
+ keepAliveMs
137
145
  }) => {
138
146
  const isStateful = sessionIdGenerator !== void 0;
139
- const modernHandler = createMcpServer ? (0, _modelcontextprotocol_node.toNodeHandler)((0, _modelcontextprotocol_server.createMcpHandler)(createMcpServer, {
140
- legacy: "reject"
141
- })) : void 0;
147
+ const modern = createMcpServer ? (0, _modelcontextprotocol_server.createMcpHandler)(createMcpServer, {
148
+ legacy: "reject",
149
+ bus,
150
+ keepAliveMs
151
+ }) : void 0;
152
+ const modernHandler = modern ? (0, _modelcontextprotocol_node.toNodeHandler)(modern) : void 0;
142
153
  let sharedTransport;
143
154
  if (isStateful) {
144
155
  sharedTransport = new _modelcontextprotocol_node.NodeStreamableHTTPServerTransport({
@@ -155,7 +166,7 @@ var createMcpRequestServer = ({
155
166
  statelessQueue = result.catch(() => {});
156
167
  return result;
157
168
  };
158
- return async (ctx, body) => {
169
+ const serve = async (ctx, body) => {
159
170
  const outcome = (0, _modelcontextprotocol_server.classifyInboundRequest)({
160
171
  httpMethod: ctx.method,
161
172
  protocolVersionHeader: header(ctx, "mcp-protocol-version"),
@@ -192,6 +203,13 @@ var createMcpRequestServer = ({
192
203
  }
193
204
  });
194
205
  };
206
+ return {
207
+ serve,
208
+ notify: modern ? modern.notify : NO_NOTIFIER,
209
+ close: async () => {
210
+ await modern?.close();
211
+ }
212
+ };
195
213
  };
196
214
 
197
215
  //#endregion
@@ -849,15 +867,19 @@ var createMcpRouter = (server, options = {}) => {
849
867
  aliases = [],
850
868
  sessionIdGenerator,
851
869
  createMcpServer,
870
+ bus,
871
+ keepAliveMs,
852
872
  apiBaseUrl,
853
873
  getApiHeaders,
854
874
  auth
855
875
  } = options;
856
876
  const needsContext = apiBaseUrl !== void 0 || getApiHeaders !== void 0 || auth !== void 0;
857
- const serveRequest = createMcpRequestServer({
877
+ const requestServer = createMcpRequestServer({
858
878
  server,
859
879
  sessionIdGenerator,
860
- createMcpServer
880
+ createMcpServer,
881
+ bus,
882
+ keepAliveMs
861
883
  });
862
884
  const router = new _ttoss_http_server.Router();
863
885
  let authCheck;
@@ -906,7 +928,7 @@ var createMcpRouter = (server, options = {}) => {
906
928
  const identity = ctx.state.user;
907
929
  ctx.req.auth = identity;
908
930
  const runRequest = async () => {
909
- await serveRequest(ctx, body);
931
+ await requestServer.serve(ctx, body);
910
932
  ctx.respond = false;
911
933
  };
912
934
  const acceptLanguage = ctx.get("Accept-Language") || void 0;
@@ -949,10 +971,28 @@ var createMcpRouter = (server, options = {}) => {
949
971
  router.post(mcpPath, postHandler);
950
972
  router.delete(mcpPath, deleteHandler);
951
973
  }
952
- return router;
974
+ const close = async () => {
975
+ requestServer.notify.toolsChanged();
976
+ requestServer.notify.promptsChanged();
977
+ requestServer.notify.resourcesChanged();
978
+ await new Promise(resolve => {
979
+ setImmediate(resolve);
980
+ });
981
+ await requestServer.close();
982
+ };
983
+ return Object.assign(router, {
984
+ notify: requestServer.notify,
985
+ close
986
+ });
953
987
  };
954
988
 
955
989
  //#endregion
990
+ Object.defineProperty(exports, 'InMemoryServerEventBus', {
991
+ enumerable: true,
992
+ get: function () {
993
+ return _modelcontextprotocol_server.InMemoryServerEventBus;
994
+ }
995
+ });
956
996
  Object.defineProperty(exports, 'McpServer', {
957
997
  enumerable: true,
958
998
  get: function () {
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, McpServerFactory, RegisteredResource } from "@modelcontextprotocol/server";
3
+ import { CallToolResult, InMemoryServerEventBus, McpServer, McpServer as McpServer$1, McpServerFactory, RegisteredResource, ServerEvent, ServerEventBus, ServerEventBus as ServerEventBus$1, ServerNotifier, ServerNotifier as ServerNotifier$1 } from "@modelcontextprotocol/server";
4
4
  import { Router } from "@ttoss/http-server";
5
5
  import accepts from "accepts";
6
6
  import { AsyncLocalStorage } from "async_hooks";
@@ -1333,6 +1333,29 @@ declare const apiCall: (method: string, url: string, options?: ApiCallOptions) =
1333
1333
  * ```
1334
1334
  */
1335
1335
  declare const checkScopes: (required: string[]) => void;
1336
+ /**
1337
+ * The router {@link createMcpRouter} returns: a Koa router, plus the two
1338
+ * operations on the `2026-07-28` streams it serves.
1339
+ */
1340
+ type McpRouter = Router & {
1341
+ /**
1342
+ * Publishes the `list_changed` notifications (and `resources/updated`) to
1343
+ * every open `subscriptions/listen` stream that opted in. Call
1344
+ * `notify.toolsChanged()` after registering or removing a tool at runtime.
1345
+ * A no-op without `createMcpServer`, or with no stream open.
1346
+ */
1347
+ notify: ServerNotifier$1;
1348
+ /**
1349
+ * Tells every open `subscriptions/listen` stream that the tool, prompt and
1350
+ * resource lists may have changed, then ends every open `2026-07-28`
1351
+ * exchange. Call it on shutdown, before `server.close()`: an open stream
1352
+ * never finishes on its own, so a graceful close would otherwise wait out
1353
+ * the whole grace period, and the notification is what tells a client that
1354
+ * does not re-list on reconnect that the next process may serve a different
1355
+ * surface.
1356
+ */
1357
+ close: () => Promise<void>;
1358
+ };
1336
1359
  /**
1337
1360
  * Options for configuring the MCP router
1338
1361
  */
@@ -1389,6 +1412,21 @@ interface McpRouterOptions {
1389
1412
  * ```
1390
1413
  */
1391
1414
  createMcpServer?: McpServerFactory;
1415
+ /**
1416
+ * The change-event bus `2026-07-28` `subscriptions/listen` streams subscribe
1417
+ * to, which {@link McpRouter.notify} publishes onto. Defaults to an
1418
+ * in-process bus, which reaches only the streams this process holds: with
1419
+ * several replicas, pass one over a shared pub/sub so a change published by
1420
+ * one replica reaches every client.
1421
+ */
1422
+ bus?: ServerEventBus$1;
1423
+ /**
1424
+ * SSE keepalive interval for `2026-07-28` streams, in milliseconds. Keep it
1425
+ * below the idle timeout of whatever sits in front of the server (a CDN or
1426
+ * load balancer), or a quiet `subscriptions/listen` stream is cut there.
1427
+ * @default 15000
1428
+ */
1429
+ keepAliveMs?: number;
1392
1430
  /**
1393
1431
  * Base URL prepended to relative paths passed to `apiCall` (paths starting
1394
1432
  * with `/`). Tool handlers can then call `apiCall('GET', '/resource')` without
@@ -1496,6 +1534,6 @@ interface McpRouterOptions {
1496
1534
  * app.listen(3000);
1497
1535
  * ```
1498
1536
  */
1499
- declare const createMcpRouter: (server: McpServer$1, options?: McpRouterOptions) => Router<Application.DefaultState, Application.DefaultContext>;
1537
+ declare const createMcpRouter: (server: McpServer$1, options?: McpRouterOptions) => McpRouter;
1500
1538
  //#endregion
1501
- export { ApiCallOptions, CognitoUserPoolConfig, type CreateGatedToolRegistrarOptions, type GatedToolDef, type JsonObjectSchema, McpAuthOptions, McpRouterOptions, McpServer, type RegisterAppResourceParams, type RegisterToolFromSchemaParams, type RegisteredAppResource, type ToolCallContext, type ToolIdentity, type ToolMetaParams, UI_EXTENSION_ID, UI_RESOURCE_MIME_TYPE, type UiResourceCsp, type UiResourceMeta, type UiResourcePermissions, type UiToolVisibility, apiCall, checkScopes, createGatedToolRegistrar, createMcpRouter, errorBodyMessage, getApiHeaders, getIdentity, getRequestLocale, registerAppResource, registerToolFromSchema, z };
1539
+ export { ApiCallOptions, CognitoUserPoolConfig, type CreateGatedToolRegistrarOptions, type GatedToolDef, InMemoryServerEventBus, type JsonObjectSchema, McpAuthOptions, McpRouter, McpRouterOptions, McpServer, type RegisterAppResourceParams, type RegisterToolFromSchemaParams, type RegisteredAppResource, type ServerEvent, type ServerEventBus, type ServerNotifier, type ToolCallContext, type ToolIdentity, type ToolMetaParams, UI_EXTENSION_ID, UI_RESOURCE_MIME_TYPE, type UiResourceCsp, type UiResourceMeta, type UiResourcePermissions, type UiToolVisibility, apiCall, checkScopes, createGatedToolRegistrar, createMcpRouter, errorBodyMessage, getApiHeaders, getIdentity, getRequestLocale, registerAppResource, registerToolFromSchema, z };
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, McpServerFactory, RegisteredResource } from "@modelcontextprotocol/server";
5
+ import { CallToolResult, InMemoryServerEventBus, McpServer, McpServer as McpServer$1, McpServerFactory, RegisteredResource, ServerEvent, ServerEventBus, ServerEventBus as ServerEventBus$1, ServerNotifier, ServerNotifier as ServerNotifier$1 } 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";
@@ -1334,6 +1334,29 @@ declare const apiCall: (method: string, url: string, options?: ApiCallOptions) =
1334
1334
  * ```
1335
1335
  */
1336
1336
  declare const checkScopes: (required: string[]) => void;
1337
+ /**
1338
+ * The router {@link createMcpRouter} returns: a Koa router, plus the two
1339
+ * operations on the `2026-07-28` streams it serves.
1340
+ */
1341
+ type McpRouter = Router & {
1342
+ /**
1343
+ * Publishes the `list_changed` notifications (and `resources/updated`) to
1344
+ * every open `subscriptions/listen` stream that opted in. Call
1345
+ * `notify.toolsChanged()` after registering or removing a tool at runtime.
1346
+ * A no-op without `createMcpServer`, or with no stream open.
1347
+ */
1348
+ notify: ServerNotifier$1;
1349
+ /**
1350
+ * Tells every open `subscriptions/listen` stream that the tool, prompt and
1351
+ * resource lists may have changed, then ends every open `2026-07-28`
1352
+ * exchange. Call it on shutdown, before `server.close()`: an open stream
1353
+ * never finishes on its own, so a graceful close would otherwise wait out
1354
+ * the whole grace period, and the notification is what tells a client that
1355
+ * does not re-list on reconnect that the next process may serve a different
1356
+ * surface.
1357
+ */
1358
+ close: () => Promise<void>;
1359
+ };
1337
1360
  /**
1338
1361
  * Options for configuring the MCP router
1339
1362
  */
@@ -1390,6 +1413,21 @@ interface McpRouterOptions {
1390
1413
  * ```
1391
1414
  */
1392
1415
  createMcpServer?: McpServerFactory;
1416
+ /**
1417
+ * The change-event bus `2026-07-28` `subscriptions/listen` streams subscribe
1418
+ * to, which {@link McpRouter.notify} publishes onto. Defaults to an
1419
+ * in-process bus, which reaches only the streams this process holds: with
1420
+ * several replicas, pass one over a shared pub/sub so a change published by
1421
+ * one replica reaches every client.
1422
+ */
1423
+ bus?: ServerEventBus$1;
1424
+ /**
1425
+ * SSE keepalive interval for `2026-07-28` streams, in milliseconds. Keep it
1426
+ * below the idle timeout of whatever sits in front of the server (a CDN or
1427
+ * load balancer), or a quiet `subscriptions/listen` stream is cut there.
1428
+ * @default 15000
1429
+ */
1430
+ keepAliveMs?: number;
1393
1431
  /**
1394
1432
  * Base URL prepended to relative paths passed to `apiCall` (paths starting
1395
1433
  * with `/`). Tool handlers can then call `apiCall('GET', '/resource')` without
@@ -1497,6 +1535,6 @@ interface McpRouterOptions {
1497
1535
  * app.listen(3000);
1498
1536
  * ```
1499
1537
  */
1500
- declare const createMcpRouter: (server: McpServer$1, options?: McpRouterOptions) => Router<Application.DefaultState, Application.DefaultContext>;
1538
+ declare const createMcpRouter: (server: McpServer$1, options?: McpRouterOptions) => McpRouter;
1501
1539
  //#endregion
1502
- export { ApiCallOptions, CognitoUserPoolConfig, type CreateGatedToolRegistrarOptions, type GatedToolDef, type JsonObjectSchema, McpAuthOptions, McpRouterOptions, McpServer, type RegisterAppResourceParams, type RegisterToolFromSchemaParams, type RegisteredAppResource, type ToolCallContext, type ToolIdentity, type ToolMetaParams, UI_EXTENSION_ID, UI_RESOURCE_MIME_TYPE, type UiResourceCsp, type UiResourceMeta, type UiResourcePermissions, type UiToolVisibility, apiCall, checkScopes, createGatedToolRegistrar, createMcpRouter, errorBodyMessage, getApiHeaders, getIdentity, getRequestLocale, registerAppResource, registerToolFromSchema, z };
1540
+ export { ApiCallOptions, CognitoUserPoolConfig, type CreateGatedToolRegistrarOptions, type GatedToolDef, InMemoryServerEventBus, type JsonObjectSchema, McpAuthOptions, McpRouter, McpRouterOptions, McpServer, type RegisterAppResourceParams, type RegisterToolFromSchemaParams, type RegisteredAppResource, type ServerEvent, type ServerEventBus, type ServerNotifier, type ToolCallContext, type ToolIdentity, type ToolMetaParams, UI_EXTENSION_ID, UI_RESOURCE_MIME_TYPE, type UiResourceCsp, type UiResourceMeta, type UiResourcePermissions, type UiToolVisibility, apiCall, checkScopes, createGatedToolRegistrar, createMcpRouter, errorBodyMessage, getApiHeaders, getIdentity, getRequestLocale, registerAppResource, registerToolFromSchema, z };
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, ProtocolErrorCode, SUPPORTED_PROTOCOL_VERSIONS, classifyInboundRequest, createMcpHandler, fromJsonSchema } from "@modelcontextprotocol/server";
8
+ import { InMemoryServerEventBus, 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
@@ -45,6 +45,12 @@ var getRequestLocale = () => {
45
45
 
46
46
  //#endregion
47
47
  //#region src/serveMcpRequest.ts
48
+ var NO_NOTIFIER = {
49
+ toolsChanged: () => {},
50
+ promptsChanged: () => {},
51
+ resourcesChanged: () => {},
52
+ resourceUpdated: () => {}
53
+ };
48
54
  /**
49
55
  * Reads a header as `string | undefined`. Koa's `ctx.get` returns `''` for a
50
56
  * missing header, which the classifier would read as "header present but
@@ -130,12 +136,17 @@ var REVISION_NOT_SERVED_ANSWER = {
130
136
  var createMcpRequestServer = ({
131
137
  createMcpServer,
132
138
  server,
133
- sessionIdGenerator
139
+ sessionIdGenerator,
140
+ bus,
141
+ keepAliveMs
134
142
  }) => {
135
143
  const isStateful = sessionIdGenerator !== void 0;
136
- const modernHandler = createMcpServer ? toNodeHandler(createMcpHandler(createMcpServer, {
137
- legacy: "reject"
138
- })) : void 0;
144
+ const modern = createMcpServer ? createMcpHandler(createMcpServer, {
145
+ legacy: "reject",
146
+ bus,
147
+ keepAliveMs
148
+ }) : void 0;
149
+ const modernHandler = modern ? toNodeHandler(modern) : void 0;
139
150
  let sharedTransport;
140
151
  if (isStateful) {
141
152
  sharedTransport = new NodeStreamableHTTPServerTransport({
@@ -152,7 +163,7 @@ var createMcpRequestServer = ({
152
163
  statelessQueue = result.catch(() => {});
153
164
  return result;
154
165
  };
155
- return async (ctx, body) => {
166
+ const serve = async (ctx, body) => {
156
167
  const outcome = classifyInboundRequest({
157
168
  httpMethod: ctx.method,
158
169
  protocolVersionHeader: header(ctx, "mcp-protocol-version"),
@@ -189,6 +200,13 @@ var createMcpRequestServer = ({
189
200
  }
190
201
  });
191
202
  };
203
+ return {
204
+ serve,
205
+ notify: modern ? modern.notify : NO_NOTIFIER,
206
+ close: async () => {
207
+ await modern?.close();
208
+ }
209
+ };
192
210
  };
193
211
 
194
212
  //#endregion
@@ -846,15 +864,19 @@ var createMcpRouter = (server, options = {}) => {
846
864
  aliases = [],
847
865
  sessionIdGenerator,
848
866
  createMcpServer,
867
+ bus,
868
+ keepAliveMs,
849
869
  apiBaseUrl,
850
870
  getApiHeaders,
851
871
  auth
852
872
  } = options;
853
873
  const needsContext = apiBaseUrl !== void 0 || getApiHeaders !== void 0 || auth !== void 0;
854
- const serveRequest = createMcpRequestServer({
874
+ const requestServer = createMcpRequestServer({
855
875
  server,
856
876
  sessionIdGenerator,
857
- createMcpServer
877
+ createMcpServer,
878
+ bus,
879
+ keepAliveMs
858
880
  });
859
881
  const router = new Router();
860
882
  let authCheck;
@@ -903,7 +925,7 @@ var createMcpRouter = (server, options = {}) => {
903
925
  const identity = ctx.state.user;
904
926
  ctx.req.auth = identity;
905
927
  const runRequest = async () => {
906
- await serveRequest(ctx, body);
928
+ await requestServer.serve(ctx, body);
907
929
  ctx.respond = false;
908
930
  };
909
931
  const acceptLanguage = ctx.get("Accept-Language") || void 0;
@@ -946,8 +968,20 @@ var createMcpRouter = (server, options = {}) => {
946
968
  router.post(mcpPath, postHandler);
947
969
  router.delete(mcpPath, deleteHandler);
948
970
  }
949
- return router;
971
+ const close = async () => {
972
+ requestServer.notify.toolsChanged();
973
+ requestServer.notify.promptsChanged();
974
+ requestServer.notify.resourcesChanged();
975
+ await new Promise(resolve => {
976
+ setImmediate(resolve);
977
+ });
978
+ await requestServer.close();
979
+ };
980
+ return Object.assign(router, {
981
+ notify: requestServer.notify,
982
+ close
983
+ });
950
984
  };
951
985
 
952
986
  //#endregion
953
- export { McpServer, UI_EXTENSION_ID, UI_RESOURCE_MIME_TYPE, apiCall, checkScopes, createGatedToolRegistrar, createMcpRouter, errorBodyMessage, getApiHeaders, getIdentity, getRequestLocale, registerAppResource, registerToolFromSchema, z };
987
+ export { InMemoryServerEventBus, McpServer, UI_EXTENSION_ID, UI_RESOURCE_MIME_TYPE, apiCall, checkScopes, createGatedToolRegistrar, createMcpRouter, errorBodyMessage, getApiHeaders, getIdentity, getRequestLocale, registerAppResource, registerToolFromSchema, z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttoss/http-server-mcp",
3
- "version": "0.30.2",
3
+ "version": "0.31.0",
4
4
  "description": "Model Context Protocol (MCP) server integration for @ttoss/http-server",
5
5
  "keywords": [
6
6
  "ai",
@@ -38,9 +38,9 @@
38
38
  "@modelcontextprotocol/server": "^2.0.0",
39
39
  "zod": "^4.4.3",
40
40
  "@ttoss/auth-core": "^0.15.1",
41
- "@ttoss/http-server": "^0.10.2",
42
- "@ttoss/i18n-core": "^0.3.1",
43
- "@ttoss/http-server-auth": "^0.7.3"
41
+ "@ttoss/http-server-auth": "^0.7.4",
42
+ "@ttoss/i18n-core": "^0.4.0",
43
+ "@ttoss/http-server": "^0.10.3"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@modelcontextprotocol/client": "^2.0.0",