@leanmcp/core 0.4.0 → 0.4.2

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