@leanmcp/core 0.3.1 → 0.3.3

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.d.mts CHANGED
@@ -434,9 +434,18 @@ declare class MCPServer {
434
434
  method: string;
435
435
  params?: {
436
436
  [x: string]: unknown;
437
+ task?: {
438
+ [x: string]: unknown;
439
+ ttl?: number | null | undefined;
440
+ pollInterval?: number | undefined;
441
+ } | undefined;
437
442
  _meta?: {
438
443
  [x: string]: unknown;
439
444
  progressToken?: string | number | undefined;
445
+ "io.modelcontextprotocol/related-task"?: {
446
+ [x: string]: unknown;
447
+ taskId: string;
448
+ } | undefined;
440
449
  } | undefined;
441
450
  } | undefined;
442
451
  }, {
@@ -445,12 +454,20 @@ declare class MCPServer {
445
454
  [x: string]: unknown;
446
455
  _meta?: {
447
456
  [x: string]: unknown;
457
+ "io.modelcontextprotocol/related-task"?: {
458
+ [x: string]: unknown;
459
+ taskId: string;
460
+ } | undefined;
448
461
  } | undefined;
449
462
  } | undefined;
450
463
  }, {
451
464
  [x: string]: unknown;
452
465
  _meta?: {
453
466
  [x: string]: unknown;
467
+ "io.modelcontextprotocol/related-task"?: {
468
+ [x: string]: unknown;
469
+ taskId: string;
470
+ } | undefined;
454
471
  } | undefined;
455
472
  }>;
456
473
  }
@@ -469,9 +486,18 @@ declare class MCPServerRuntime {
469
486
  method: string;
470
487
  params?: {
471
488
  [x: string]: unknown;
489
+ task?: {
490
+ [x: string]: unknown;
491
+ ttl?: number | null | undefined;
492
+ pollInterval?: number | undefined;
493
+ } | undefined;
472
494
  _meta?: {
473
495
  [x: string]: unknown;
474
496
  progressToken?: string | number | undefined;
497
+ "io.modelcontextprotocol/related-task"?: {
498
+ [x: string]: unknown;
499
+ taskId: string;
500
+ } | undefined;
475
501
  } | undefined;
476
502
  } | undefined;
477
503
  }, {
@@ -480,12 +506,20 @@ declare class MCPServerRuntime {
480
506
  [x: string]: unknown;
481
507
  _meta?: {
482
508
  [x: string]: unknown;
509
+ "io.modelcontextprotocol/related-task"?: {
510
+ [x: string]: unknown;
511
+ taskId: string;
512
+ } | undefined;
483
513
  } | undefined;
484
514
  } | undefined;
485
515
  }, {
486
516
  [x: string]: unknown;
487
517
  _meta?: {
488
518
  [x: string]: unknown;
519
+ "io.modelcontextprotocol/related-task"?: {
520
+ [x: string]: unknown;
521
+ taskId: string;
522
+ } | undefined;
489
523
  } | undefined;
490
524
  }>;
491
525
  getTools(): RegisteredTool[];
package/dist/index.d.ts CHANGED
@@ -434,9 +434,18 @@ declare class MCPServer {
434
434
  method: string;
435
435
  params?: {
436
436
  [x: string]: unknown;
437
+ task?: {
438
+ [x: string]: unknown;
439
+ ttl?: number | null | undefined;
440
+ pollInterval?: number | undefined;
441
+ } | undefined;
437
442
  _meta?: {
438
443
  [x: string]: unknown;
439
444
  progressToken?: string | number | undefined;
445
+ "io.modelcontextprotocol/related-task"?: {
446
+ [x: string]: unknown;
447
+ taskId: string;
448
+ } | undefined;
440
449
  } | undefined;
441
450
  } | undefined;
442
451
  }, {
@@ -445,12 +454,20 @@ declare class MCPServer {
445
454
  [x: string]: unknown;
446
455
  _meta?: {
447
456
  [x: string]: unknown;
457
+ "io.modelcontextprotocol/related-task"?: {
458
+ [x: string]: unknown;
459
+ taskId: string;
460
+ } | undefined;
448
461
  } | undefined;
449
462
  } | undefined;
450
463
  }, {
451
464
  [x: string]: unknown;
452
465
  _meta?: {
453
466
  [x: string]: unknown;
467
+ "io.modelcontextprotocol/related-task"?: {
468
+ [x: string]: unknown;
469
+ taskId: string;
470
+ } | undefined;
454
471
  } | undefined;
455
472
  }>;
456
473
  }
@@ -469,9 +486,18 @@ declare class MCPServerRuntime {
469
486
  method: string;
470
487
  params?: {
471
488
  [x: string]: unknown;
489
+ task?: {
490
+ [x: string]: unknown;
491
+ ttl?: number | null | undefined;
492
+ pollInterval?: number | undefined;
493
+ } | undefined;
472
494
  _meta?: {
473
495
  [x: string]: unknown;
474
496
  progressToken?: string | number | undefined;
497
+ "io.modelcontextprotocol/related-task"?: {
498
+ [x: string]: unknown;
499
+ taskId: string;
500
+ } | undefined;
475
501
  } | undefined;
476
502
  } | undefined;
477
503
  }, {
@@ -480,12 +506,20 @@ declare class MCPServerRuntime {
480
506
  [x: string]: unknown;
481
507
  _meta?: {
482
508
  [x: string]: unknown;
509
+ "io.modelcontextprotocol/related-task"?: {
510
+ [x: string]: unknown;
511
+ taskId: string;
512
+ } | undefined;
483
513
  } | undefined;
484
514
  } | undefined;
485
515
  }, {
486
516
  [x: string]: unknown;
487
517
  _meta?: {
488
518
  [x: string]: unknown;
519
+ "io.modelcontextprotocol/related-task"?: {
520
+ [x: string]: unknown;
521
+ taskId: string;
522
+ } | undefined;
489
523
  } | undefined;
490
524
  }>;
491
525
  getTools(): RegisteredTool[];
package/dist/index.js CHANGED
@@ -464,14 +464,61 @@ async function createHTTPServer(serverInput, options) {
464
464
  httpOptions.cors ? import("cors").catch(() => null) : Promise.resolve(null)
465
465
  ]);
466
466
  const app = express.default();
467
- const port = httpOptions.port || 3001;
468
- validatePort(port);
467
+ const basePort = httpOptions.port || 3001;
468
+ validatePort(basePort);
469
469
  const transports = {};
470
470
  let mcpServer = null;
471
471
  const logger = httpOptions.logger || new Logger({
472
472
  level: httpOptions.logging ? LogLevel.INFO : LogLevel.NONE,
473
473
  prefix: "HTTP"
474
474
  });
475
+ const logPrimary = /* @__PURE__ */ __name((message) => {
476
+ if (httpOptions.logging) {
477
+ logger.info?.(message);
478
+ } else {
479
+ console.log(message);
480
+ }
481
+ }, "logPrimary");
482
+ const warnPrimary = /* @__PURE__ */ __name((message) => {
483
+ if (httpOptions.logging) {
484
+ logger.warn?.(message);
485
+ } else {
486
+ console.warn(message);
487
+ }
488
+ }, "warnPrimary");
489
+ const startServerWithPortRetry = /* @__PURE__ */ __name(async () => {
490
+ const maxAttempts = 20;
491
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
492
+ const portToTry = basePort + attempt;
493
+ const listener = await new Promise((resolve, reject) => {
494
+ const server = app.listen(portToTry);
495
+ const onListening = /* @__PURE__ */ __name(() => {
496
+ server.off("error", onError);
497
+ resolve(server);
498
+ }, "onListening");
499
+ const onError = /* @__PURE__ */ __name((error) => {
500
+ server.off("listening", onListening);
501
+ server.close();
502
+ reject(error);
503
+ }, "onError");
504
+ server.once("listening", onListening);
505
+ server.once("error", onError);
506
+ }).catch((error) => {
507
+ if (error?.code === "EADDRINUSE" && attempt < maxAttempts - 1) {
508
+ warnPrimary(`Port ${portToTry} in use, trying ${portToTry + 1}...`);
509
+ return null;
510
+ }
511
+ throw error;
512
+ });
513
+ if (listener) {
514
+ return {
515
+ listener,
516
+ port: portToTry
517
+ };
518
+ }
519
+ }
520
+ throw new Error(`No available port found in range ${basePort}-${basePort + maxAttempts - 1}`);
521
+ }, "startServerWithPortRetry");
475
522
  if (cors && httpOptions.cors) {
476
523
  const corsOptions = typeof httpOptions.cors === "object" ? {
477
524
  origin: httpOptions.cors.origin || false,
@@ -498,7 +545,7 @@ async function createHTTPServer(serverInput, options) {
498
545
  }
499
546
  }
500
547
  app.use(express.json());
501
- logger.info("Starting LeanMCP HTTP Server...");
548
+ console.log("Starting LeanMCP HTTP Server...");
502
549
  app.get("/health", (req, res) => {
503
550
  res.json({
504
551
  status: "ok",
@@ -573,16 +620,22 @@ async function createHTTPServer(serverInput, options) {
573
620
  app.post("/mcp", handleMCPRequest);
574
621
  app.delete("/mcp", handleMCPRequest);
575
622
  return new Promise(async (resolve, reject) => {
623
+ let activeListener;
576
624
  try {
577
625
  mcpServer = await serverFactory();
578
626
  if (mcpServer && typeof mcpServer.waitForInit === "function") {
579
627
  await mcpServer.waitForInit();
580
628
  }
581
- const listener = app.listen(port, () => {
582
- logger.info(`Server running on http://localhost:${port}`);
583
- logger.info(`MCP endpoint: http://localhost:${port}/mcp`);
584
- logger.info(`Health check: http://localhost:${port}/health`);
585
- resolve(listener);
629
+ const { listener, port } = await startServerWithPortRetry();
630
+ activeListener = listener;
631
+ process.env.PORT = String(port);
632
+ listener.port = port;
633
+ console.log(`Server running on http://localhost:${port}`);
634
+ console.log(`MCP endpoint: http://localhost:${port}/mcp`);
635
+ console.log(`Health check: http://localhost:${port}/health`);
636
+ resolve({
637
+ listener,
638
+ port
586
639
  });
587
640
  listener.on("error", (error) => {
588
641
  logger.error(`Server error: ${error.message}`);
@@ -591,7 +644,7 @@ async function createHTTPServer(serverInput, options) {
591
644
  const cleanup = /* @__PURE__ */ __name(() => {
592
645
  logger.info("\nShutting down server...");
593
646
  Object.values(transports).forEach((t) => t.close?.());
594
- listener.close(() => {
647
+ activeListener?.close(() => {
595
648
  logger.info("Server closed");
596
649
  process.exit(0);
597
650
  });
@@ -769,24 +822,29 @@ var init_index = __esm({
769
822
  const stack = err.stack;
770
823
  for (let i = 0; i < stack.length; i++) {
771
824
  let fileName = stack[i].getFileName();
772
- if (fileName && !fileName.includes("@leanmcp") && !fileName.includes("leanmcp-sdk\\packages\\core") && !fileName.includes("leanmcp-sdk/packages/core") && (fileName.endsWith(".ts") || fileName.endsWith(".js") || fileName.endsWith(".mjs"))) {
773
- if (fileName.startsWith("file://")) {
774
- try {
775
- const url = new URL(fileName);
776
- fileName = decodeURIComponent(url.pathname);
777
- if (process.platform === "win32" && fileName.startsWith("/")) {
778
- fileName = fileName.substring(1);
779
- }
780
- } catch (e) {
781
- fileName = fileName.replace("file://", "");
782
- if (process.platform === "win32" && fileName.startsWith("/")) {
783
- fileName = fileName.substring(1);
784
- }
825
+ if (!fileName) continue;
826
+ if (fileName.startsWith("file://")) {
827
+ try {
828
+ const url = new URL(fileName);
829
+ fileName = decodeURIComponent(url.pathname);
830
+ if (process.platform === "win32" && fileName.startsWith("/")) {
831
+ fileName = fileName.substring(1);
832
+ }
833
+ } catch (e) {
834
+ fileName = fileName.replace("file://", "");
835
+ if (process.platform === "win32" && fileName.startsWith("/")) {
836
+ fileName = fileName.substring(1);
785
837
  }
786
838
  }
839
+ }
840
+ const normalizedPath = fileName.replace(/\\/g, "/");
841
+ const isLeanMCPCore = normalizedPath.includes("@leanmcp/core") || normalizedPath.includes("leanmcp-sdk/packages/core");
842
+ const isValidExtension = fileName.endsWith(".ts") || fileName.endsWith(".js") || fileName.endsWith(".mjs");
843
+ if (!isLeanMCPCore && isValidExtension) {
787
844
  return fileName;
788
845
  }
789
846
  }
847
+ this.logger.debug("No suitable caller file found in stack trace");
790
848
  return null;
791
849
  } finally {
792
850
  Error.prepareStackTrace = originalPrepareStackTrace;
package/dist/index.mjs CHANGED
@@ -425,14 +425,61 @@ async function createHTTPServer(serverInput, options) {
425
425
  httpOptions.cors ? import("cors").catch(() => null) : Promise.resolve(null)
426
426
  ]);
427
427
  const app = express.default();
428
- const port = httpOptions.port || 3001;
429
- validatePort(port);
428
+ const basePort = httpOptions.port || 3001;
429
+ validatePort(basePort);
430
430
  const transports = {};
431
431
  let mcpServer = null;
432
432
  const logger = httpOptions.logger || new Logger({
433
433
  level: httpOptions.logging ? LogLevel.INFO : LogLevel.NONE,
434
434
  prefix: "HTTP"
435
435
  });
436
+ const logPrimary = /* @__PURE__ */ __name((message) => {
437
+ if (httpOptions.logging) {
438
+ logger.info?.(message);
439
+ } else {
440
+ console.log(message);
441
+ }
442
+ }, "logPrimary");
443
+ const warnPrimary = /* @__PURE__ */ __name((message) => {
444
+ if (httpOptions.logging) {
445
+ logger.warn?.(message);
446
+ } else {
447
+ console.warn(message);
448
+ }
449
+ }, "warnPrimary");
450
+ const startServerWithPortRetry = /* @__PURE__ */ __name(async () => {
451
+ const maxAttempts = 20;
452
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
453
+ const portToTry = basePort + attempt;
454
+ const listener = await new Promise((resolve, reject) => {
455
+ const server = app.listen(portToTry);
456
+ const onListening = /* @__PURE__ */ __name(() => {
457
+ server.off("error", onError);
458
+ resolve(server);
459
+ }, "onListening");
460
+ const onError = /* @__PURE__ */ __name((error) => {
461
+ server.off("listening", onListening);
462
+ server.close();
463
+ reject(error);
464
+ }, "onError");
465
+ server.once("listening", onListening);
466
+ server.once("error", onError);
467
+ }).catch((error) => {
468
+ if (error?.code === "EADDRINUSE" && attempt < maxAttempts - 1) {
469
+ warnPrimary(`Port ${portToTry} in use, trying ${portToTry + 1}...`);
470
+ return null;
471
+ }
472
+ throw error;
473
+ });
474
+ if (listener) {
475
+ return {
476
+ listener,
477
+ port: portToTry
478
+ };
479
+ }
480
+ }
481
+ throw new Error(`No available port found in range ${basePort}-${basePort + maxAttempts - 1}`);
482
+ }, "startServerWithPortRetry");
436
483
  if (cors && httpOptions.cors) {
437
484
  const corsOptions = typeof httpOptions.cors === "object" ? {
438
485
  origin: httpOptions.cors.origin || false,
@@ -459,7 +506,7 @@ async function createHTTPServer(serverInput, options) {
459
506
  }
460
507
  }
461
508
  app.use(express.json());
462
- logger.info("Starting LeanMCP HTTP Server...");
509
+ console.log("Starting LeanMCP HTTP Server...");
463
510
  app.get("/health", (req, res) => {
464
511
  res.json({
465
512
  status: "ok",
@@ -534,16 +581,22 @@ async function createHTTPServer(serverInput, options) {
534
581
  app.post("/mcp", handleMCPRequest);
535
582
  app.delete("/mcp", handleMCPRequest);
536
583
  return new Promise(async (resolve, reject) => {
584
+ let activeListener;
537
585
  try {
538
586
  mcpServer = await serverFactory();
539
587
  if (mcpServer && typeof mcpServer.waitForInit === "function") {
540
588
  await mcpServer.waitForInit();
541
589
  }
542
- const listener = app.listen(port, () => {
543
- logger.info(`Server running on http://localhost:${port}`);
544
- logger.info(`MCP endpoint: http://localhost:${port}/mcp`);
545
- logger.info(`Health check: http://localhost:${port}/health`);
546
- resolve(listener);
590
+ const { listener, port } = await startServerWithPortRetry();
591
+ activeListener = listener;
592
+ process.env.PORT = String(port);
593
+ listener.port = port;
594
+ console.log(`Server running on http://localhost:${port}`);
595
+ console.log(`MCP endpoint: http://localhost:${port}/mcp`);
596
+ console.log(`Health check: http://localhost:${port}/health`);
597
+ resolve({
598
+ listener,
599
+ port
547
600
  });
548
601
  listener.on("error", (error) => {
549
602
  logger.error(`Server error: ${error.message}`);
@@ -552,7 +605,7 @@ async function createHTTPServer(serverInput, options) {
552
605
  const cleanup = /* @__PURE__ */ __name(() => {
553
606
  logger.info("\nShutting down server...");
554
607
  Object.values(transports).forEach((t) => t.close?.());
555
- listener.close(() => {
608
+ activeListener?.close(() => {
556
609
  logger.info("Server closed");
557
610
  process.exit(0);
558
611
  });
@@ -666,24 +719,29 @@ var MCPServer = class {
666
719
  const stack = err.stack;
667
720
  for (let i = 0; i < stack.length; i++) {
668
721
  let fileName = stack[i].getFileName();
669
- if (fileName && !fileName.includes("@leanmcp") && !fileName.includes("leanmcp-sdk\\packages\\core") && !fileName.includes("leanmcp-sdk/packages/core") && (fileName.endsWith(".ts") || fileName.endsWith(".js") || fileName.endsWith(".mjs"))) {
670
- if (fileName.startsWith("file://")) {
671
- try {
672
- const url = new URL(fileName);
673
- fileName = decodeURIComponent(url.pathname);
674
- if (process.platform === "win32" && fileName.startsWith("/")) {
675
- fileName = fileName.substring(1);
676
- }
677
- } catch (e) {
678
- fileName = fileName.replace("file://", "");
679
- if (process.platform === "win32" && fileName.startsWith("/")) {
680
- fileName = fileName.substring(1);
681
- }
722
+ if (!fileName) continue;
723
+ if (fileName.startsWith("file://")) {
724
+ try {
725
+ const url = new URL(fileName);
726
+ fileName = decodeURIComponent(url.pathname);
727
+ if (process.platform === "win32" && fileName.startsWith("/")) {
728
+ fileName = fileName.substring(1);
729
+ }
730
+ } catch (e) {
731
+ fileName = fileName.replace("file://", "");
732
+ if (process.platform === "win32" && fileName.startsWith("/")) {
733
+ fileName = fileName.substring(1);
682
734
  }
683
735
  }
736
+ }
737
+ const normalizedPath = fileName.replace(/\\/g, "/");
738
+ const isLeanMCPCore = normalizedPath.includes("@leanmcp/core") || normalizedPath.includes("leanmcp-sdk/packages/core");
739
+ const isValidExtension = fileName.endsWith(".ts") || fileName.endsWith(".js") || fileName.endsWith(".mjs");
740
+ if (!isLeanMCPCore && isValidExtension) {
684
741
  return fileName;
685
742
  }
686
743
  }
744
+ this.logger.debug("No suitable caller file found in stack trace");
687
745
  return null;
688
746
  } finally {
689
747
  Error.prepareStackTrace = originalPrepareStackTrace;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leanmcp/core",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "Core library implementing decorators, reflection, and MCP runtime server",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",