@leanmcp/core 0.4.0 → 0.4.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/dist/index.js CHANGED
@@ -985,6 +985,62 @@ async function createHTTPServer(serverInput, options) {
985
985
  if (sessionId && transports[sessionId]) {
986
986
  transport = transports[sessionId];
987
987
  logger.debug(`Reusing session: ${sessionId}`);
988
+ } else if (sessionId && isInitializeRequest(req.body)) {
989
+ logger.info(`Initialize request with session ${sessionId} - checking for session restoration...`);
990
+ if (httpOptions.sessionStore) {
991
+ const exists = await httpOptions.sessionStore.sessionExists(sessionId);
992
+ if (exists) {
993
+ logger.info(`Restoring session: ${sessionId}`);
994
+ transport = new StreamableHTTPServerTransport2({
995
+ sessionIdGenerator: /* @__PURE__ */ __name(() => sessionId, "sessionIdGenerator"),
996
+ onsessioninitialized: /* @__PURE__ */ __name((sid) => {
997
+ transports[sid] = transport;
998
+ logger.info(`Session restored: ${sid}`);
999
+ }, "onsessioninitialized")
1000
+ });
1001
+ transport.onclose = async () => {
1002
+ if (transport.sessionId) {
1003
+ delete transports[transport.sessionId];
1004
+ logger.debug(`Session cleaned up: ${transport.sessionId}`);
1005
+ if (httpOptions.sessionStore) {
1006
+ await httpOptions.sessionStore.deleteSession(transport.sessionId);
1007
+ }
1008
+ }
1009
+ };
1010
+ const freshServer = await serverFactory();
1011
+ if (freshServer && typeof freshServer.waitForInit === "function") {
1012
+ await freshServer.waitForInit();
1013
+ }
1014
+ await freshServer.connect(transport);
1015
+ } else {
1016
+ logger.info(`Session ${sessionId} not found in store, creating new session`);
1017
+ }
1018
+ }
1019
+ if (!transport) {
1020
+ transport = new StreamableHTTPServerTransport2({
1021
+ sessionIdGenerator: /* @__PURE__ */ __name(() => (0, import_node_crypto.randomUUID)(), "sessionIdGenerator"),
1022
+ onsessioninitialized: /* @__PURE__ */ __name(async (newSessionId) => {
1023
+ transports[newSessionId] = transport;
1024
+ logger.info(`Session initialized: ${newSessionId}`);
1025
+ if (httpOptions.sessionStore) {
1026
+ await httpOptions.sessionStore.createSession(newSessionId);
1027
+ }
1028
+ }, "onsessioninitialized")
1029
+ });
1030
+ transport.onclose = async () => {
1031
+ if (transport.sessionId) {
1032
+ delete transports[transport.sessionId];
1033
+ logger.debug(`Session cleaned up: ${transport.sessionId}`);
1034
+ if (httpOptions.sessionStore) {
1035
+ await httpOptions.sessionStore.deleteSession(transport.sessionId);
1036
+ }
1037
+ }
1038
+ };
1039
+ if (!mcpServer) {
1040
+ throw new Error("MCP server not initialized");
1041
+ }
1042
+ await mcpServer.connect(transport);
1043
+ }
988
1044
  } else if (sessionId && !isInitializeRequest(req.body)) {
989
1045
  logger.info(`Transport missing for session ${sessionId}, checking session store...`);
990
1046
  if (httpOptions.sessionStore) {
@@ -1000,11 +1056,12 @@ async function createHTTPServer(serverInput, options) {
1000
1056
  });
1001
1057
  return;
1002
1058
  }
1059
+ logger.info(`Auto-restoring session: ${sessionId}`);
1003
1060
  transport = new StreamableHTTPServerTransport2({
1004
1061
  sessionIdGenerator: /* @__PURE__ */ __name(() => sessionId, "sessionIdGenerator"),
1005
1062
  onsessioninitialized: /* @__PURE__ */ __name((sid) => {
1006
1063
  transports[sid] = transport;
1007
- logger.info(`Transport recreated for session: ${sid}`);
1064
+ logger.info(`Session auto-restored: ${sid}`);
1008
1065
  }, "onsessioninitialized")
1009
1066
  });
1010
1067
  transport.onclose = async () => {
@@ -1822,14 +1879,14 @@ var init_index = __esm({
1822
1879
  /**
1823
1880
  * Auto-register all services from the mcp directory
1824
1881
  * Scans the directory recursively and registers all exported classes
1825
- *
1882
+ *
1826
1883
  * @param mcpDir - Path to the mcp directory containing service files
1827
1884
  * @param serviceFactories - Optional map of service class names to factory functions for dependency injection
1828
- *
1885
+ *
1829
1886
  * @example
1830
1887
  * // Auto-register services with no dependencies
1831
1888
  * await server.autoRegisterServices('./mcp');
1832
- *
1889
+ *
1833
1890
  * @example
1834
1891
  * // Auto-register with dependency injection
1835
1892
  * await server.autoRegisterServices('./mcp', {
@@ -1982,7 +2039,7 @@ var init_index = __esm({
1982
2039
  }
1983
2040
  /**
1984
2041
  * Watch UI manifest for changes and reload resources dynamically
1985
- *
2042
+ *
1986
2043
  * CRITICAL: Only for stateful mode. In stateless mode, each request
1987
2044
  * creates a fresh server that reads the manifest directly, making
1988
2045
  * watchers both unnecessary and a memory leak source.
package/dist/index.mjs CHANGED
@@ -683,6 +683,62 @@ async function createHTTPServer(serverInput, options) {
683
683
  if (sessionId && transports[sessionId]) {
684
684
  transport = transports[sessionId];
685
685
  logger.debug(`Reusing session: ${sessionId}`);
686
+ } else if (sessionId && isInitializeRequest(req.body)) {
687
+ logger.info(`Initialize request with session ${sessionId} - checking for session restoration...`);
688
+ if (httpOptions.sessionStore) {
689
+ const exists = await httpOptions.sessionStore.sessionExists(sessionId);
690
+ if (exists) {
691
+ logger.info(`Restoring session: ${sessionId}`);
692
+ transport = new StreamableHTTPServerTransport2({
693
+ sessionIdGenerator: /* @__PURE__ */ __name(() => sessionId, "sessionIdGenerator"),
694
+ onsessioninitialized: /* @__PURE__ */ __name((sid) => {
695
+ transports[sid] = transport;
696
+ logger.info(`Session restored: ${sid}`);
697
+ }, "onsessioninitialized")
698
+ });
699
+ transport.onclose = async () => {
700
+ if (transport.sessionId) {
701
+ delete transports[transport.sessionId];
702
+ logger.debug(`Session cleaned up: ${transport.sessionId}`);
703
+ if (httpOptions.sessionStore) {
704
+ await httpOptions.sessionStore.deleteSession(transport.sessionId);
705
+ }
706
+ }
707
+ };
708
+ const freshServer = await serverFactory();
709
+ if (freshServer && typeof freshServer.waitForInit === "function") {
710
+ await freshServer.waitForInit();
711
+ }
712
+ await freshServer.connect(transport);
713
+ } else {
714
+ logger.info(`Session ${sessionId} not found in store, creating new session`);
715
+ }
716
+ }
717
+ if (!transport) {
718
+ transport = new StreamableHTTPServerTransport2({
719
+ sessionIdGenerator: /* @__PURE__ */ __name(() => randomUUID(), "sessionIdGenerator"),
720
+ onsessioninitialized: /* @__PURE__ */ __name(async (newSessionId) => {
721
+ transports[newSessionId] = transport;
722
+ logger.info(`Session initialized: ${newSessionId}`);
723
+ if (httpOptions.sessionStore) {
724
+ await httpOptions.sessionStore.createSession(newSessionId);
725
+ }
726
+ }, "onsessioninitialized")
727
+ });
728
+ transport.onclose = async () => {
729
+ if (transport.sessionId) {
730
+ delete transports[transport.sessionId];
731
+ logger.debug(`Session cleaned up: ${transport.sessionId}`);
732
+ if (httpOptions.sessionStore) {
733
+ await httpOptions.sessionStore.deleteSession(transport.sessionId);
734
+ }
735
+ }
736
+ };
737
+ if (!mcpServer) {
738
+ throw new Error("MCP server not initialized");
739
+ }
740
+ await mcpServer.connect(transport);
741
+ }
686
742
  } else if (sessionId && !isInitializeRequest(req.body)) {
687
743
  logger.info(`Transport missing for session ${sessionId}, checking session store...`);
688
744
  if (httpOptions.sessionStore) {
@@ -698,11 +754,12 @@ async function createHTTPServer(serverInput, options) {
698
754
  });
699
755
  return;
700
756
  }
757
+ logger.info(`Auto-restoring session: ${sessionId}`);
701
758
  transport = new StreamableHTTPServerTransport2({
702
759
  sessionIdGenerator: /* @__PURE__ */ __name(() => sessionId, "sessionIdGenerator"),
703
760
  onsessioninitialized: /* @__PURE__ */ __name((sid) => {
704
761
  transports[sid] = transport;
705
- logger.info(`Transport recreated for session: ${sid}`);
762
+ logger.info(`Session auto-restored: ${sid}`);
706
763
  }, "onsessioninitialized")
707
764
  });
708
765
  transport.onclose = async () => {
@@ -1424,14 +1481,14 @@ var MCPServer = class {
1424
1481
  /**
1425
1482
  * Auto-register all services from the mcp directory
1426
1483
  * Scans the directory recursively and registers all exported classes
1427
- *
1484
+ *
1428
1485
  * @param mcpDir - Path to the mcp directory containing service files
1429
1486
  * @param serviceFactories - Optional map of service class names to factory functions for dependency injection
1430
- *
1487
+ *
1431
1488
  * @example
1432
1489
  * // Auto-register services with no dependencies
1433
1490
  * await server.autoRegisterServices('./mcp');
1434
- *
1491
+ *
1435
1492
  * @example
1436
1493
  * // Auto-register with dependency injection
1437
1494
  * await server.autoRegisterServices('./mcp', {
@@ -1584,7 +1641,7 @@ var MCPServer = class {
1584
1641
  }
1585
1642
  /**
1586
1643
  * Watch UI manifest for changes and reload resources dynamically
1587
- *
1644
+ *
1588
1645
  * CRITICAL: Only for stateful mode. In stateless mode, each request
1589
1646
  * creates a fresh server that reads the manifest directly, making
1590
1647
  * watchers both unnecessary and a memory leak source.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leanmcp/core",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Core library implementing decorators, reflection, and MCP runtime server",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",