@leanmcp/core 0.3.6 → 0.3.8

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
@@ -252,6 +252,7 @@ interface HTTPServerOptions {
252
252
  logger?: Logger;
253
253
  sessionTimeout?: number;
254
254
  stateless?: boolean;
255
+ dashboard?: boolean;
255
256
  }
256
257
  interface MCPServerFactory {
257
258
  (): Server | Promise<Server>;
package/dist/index.d.ts CHANGED
@@ -252,6 +252,7 @@ interface HTTPServerOptions {
252
252
  logger?: Logger;
253
253
  sessionTimeout?: number;
254
254
  stateless?: boolean;
255
+ dashboard?: boolean;
255
256
  }
256
257
  interface MCPServerFactory {
257
258
  (): Server | Promise<Server>;
package/dist/index.js CHANGED
@@ -550,7 +550,8 @@ async function createHTTPServer(serverInput, options) {
550
550
  cors: serverOptions.cors,
551
551
  logging: serverOptions.logging,
552
552
  sessionTimeout: serverOptions.sessionTimeout,
553
- stateless: serverOptions.stateless
553
+ stateless: serverOptions.stateless,
554
+ dashboard: serverOptions.dashboard
554
555
  };
555
556
  }
556
557
  const [express, { StreamableHTTPServerTransport }, cors] = await Promise.all([
@@ -668,6 +669,42 @@ async function createHTTPServer(serverInput, options) {
668
669
  app.use(express.json());
669
670
  const isStateless = httpOptions.stateless !== false;
670
671
  console.log(`Starting LeanMCP HTTP Server (${isStateless ? "STATELESS" : "STATEFUL"})...`);
672
+ const DASHBOARD_URL = process.env.DASHBOARD_URL || "https://s3-dashboard-build.s3.us-west-2.amazonaws.com/out/index.html";
673
+ let cachedDashboard = null;
674
+ let cacheTimestamp = 0;
675
+ const CACHE_DURATION = 5 * 60 * 1e3;
676
+ async function fetchDashboard() {
677
+ const now = Date.now();
678
+ if (cachedDashboard && now - cacheTimestamp < CACHE_DURATION) {
679
+ return cachedDashboard;
680
+ }
681
+ try {
682
+ const response = await fetch(DASHBOARD_URL);
683
+ if (!response.ok) {
684
+ throw new Error(`Failed to fetch dashboard: ${response.status}`);
685
+ }
686
+ const html = await response.text();
687
+ cachedDashboard = html;
688
+ cacheTimestamp = now;
689
+ return html;
690
+ } catch (error) {
691
+ logger.error("Error fetching dashboard from S3:", error);
692
+ throw error;
693
+ }
694
+ }
695
+ __name(fetchDashboard, "fetchDashboard");
696
+ const isDashboardEnabled = httpOptions.dashboard !== false;
697
+ if (isDashboardEnabled) {
698
+ app.get("/", async (req, res) => {
699
+ try {
700
+ const html = await fetchDashboard();
701
+ res.setHeader("Content-Type", "text/html");
702
+ res.send(html);
703
+ } catch (error) {
704
+ res.status(500).send("<h1>Dashboard temporarily unavailable</h1><p>Please try again later.</p>");
705
+ }
706
+ });
707
+ }
671
708
  app.get("/health", (req, res) => {
672
709
  res.json({
673
710
  status: "ok",
@@ -775,18 +812,44 @@ async function createHTTPServer(serverInput, options) {
775
812
  }
776
813
  }
777
814
  }, "handleMCPRequestStateless");
778
- if (isStateless) {
779
- app.post("/mcp", handleMCPRequestStateless);
780
- app.get("/mcp", (_req, res) => {
815
+ app.get("/mcp", async (req, res) => {
816
+ const acceptHeader = req.headers["accept"] || "";
817
+ if (acceptHeader.includes("text/event-stream")) {
818
+ if (!isStateless) {
819
+ const sessionId = req.headers["mcp-session-id"];
820
+ if (sessionId && transports[sessionId]) {
821
+ const transport = transports[sessionId];
822
+ logger.info(`GET /mcp SSE request (session: ${sessionId.substring(0, 8)}...)`);
823
+ await transport.handleRequest(req, res);
824
+ return;
825
+ }
826
+ }
781
827
  res.status(405).json({
782
828
  jsonrpc: "2.0",
783
829
  error: {
784
830
  code: -32e3,
785
- message: "Method not allowed (stateless mode)"
831
+ message: "SSE streaming not supported in stateless mode or invalid session"
786
832
  },
787
833
  id: null
788
834
  });
789
- });
835
+ return;
836
+ }
837
+ if (isDashboardEnabled) {
838
+ try {
839
+ const html = await fetchDashboard();
840
+ res.setHeader("Content-Type", "text/html");
841
+ res.send(html);
842
+ } catch (error) {
843
+ res.status(500).send("<h1>Dashboard temporarily unavailable</h1><p>Please try again later.</p>");
844
+ }
845
+ } else {
846
+ res.status(404).json({
847
+ error: "Dashboard disabled"
848
+ });
849
+ }
850
+ });
851
+ if (isStateless) {
852
+ app.post("/mcp", handleMCPRequestStateless);
790
853
  app.delete("/mcp", (_req, res) => {
791
854
  res.status(405).json({
792
855
  jsonrpc: "2.0",
package/dist/index.mjs CHANGED
@@ -512,7 +512,8 @@ async function createHTTPServer(serverInput, options) {
512
512
  cors: serverOptions.cors,
513
513
  logging: serverOptions.logging,
514
514
  sessionTimeout: serverOptions.sessionTimeout,
515
- stateless: serverOptions.stateless
515
+ stateless: serverOptions.stateless,
516
+ dashboard: serverOptions.dashboard
516
517
  };
517
518
  }
518
519
  const [express, { StreamableHTTPServerTransport }, cors] = await Promise.all([
@@ -630,6 +631,42 @@ async function createHTTPServer(serverInput, options) {
630
631
  app.use(express.json());
631
632
  const isStateless = httpOptions.stateless !== false;
632
633
  console.log(`Starting LeanMCP HTTP Server (${isStateless ? "STATELESS" : "STATEFUL"})...`);
634
+ const DASHBOARD_URL = process.env.DASHBOARD_URL || "https://s3-dashboard-build.s3.us-west-2.amazonaws.com/out/index.html";
635
+ let cachedDashboard = null;
636
+ let cacheTimestamp = 0;
637
+ const CACHE_DURATION = 5 * 60 * 1e3;
638
+ async function fetchDashboard() {
639
+ const now = Date.now();
640
+ if (cachedDashboard && now - cacheTimestamp < CACHE_DURATION) {
641
+ return cachedDashboard;
642
+ }
643
+ try {
644
+ const response = await fetch(DASHBOARD_URL);
645
+ if (!response.ok) {
646
+ throw new Error(`Failed to fetch dashboard: ${response.status}`);
647
+ }
648
+ const html = await response.text();
649
+ cachedDashboard = html;
650
+ cacheTimestamp = now;
651
+ return html;
652
+ } catch (error) {
653
+ logger.error("Error fetching dashboard from S3:", error);
654
+ throw error;
655
+ }
656
+ }
657
+ __name(fetchDashboard, "fetchDashboard");
658
+ const isDashboardEnabled = httpOptions.dashboard !== false;
659
+ if (isDashboardEnabled) {
660
+ app.get("/", async (req, res) => {
661
+ try {
662
+ const html = await fetchDashboard();
663
+ res.setHeader("Content-Type", "text/html");
664
+ res.send(html);
665
+ } catch (error) {
666
+ res.status(500).send("<h1>Dashboard temporarily unavailable</h1><p>Please try again later.</p>");
667
+ }
668
+ });
669
+ }
633
670
  app.get("/health", (req, res) => {
634
671
  res.json({
635
672
  status: "ok",
@@ -737,18 +774,44 @@ async function createHTTPServer(serverInput, options) {
737
774
  }
738
775
  }
739
776
  }, "handleMCPRequestStateless");
740
- if (isStateless) {
741
- app.post("/mcp", handleMCPRequestStateless);
742
- app.get("/mcp", (_req, res) => {
777
+ app.get("/mcp", async (req, res) => {
778
+ const acceptHeader = req.headers["accept"] || "";
779
+ if (acceptHeader.includes("text/event-stream")) {
780
+ if (!isStateless) {
781
+ const sessionId = req.headers["mcp-session-id"];
782
+ if (sessionId && transports[sessionId]) {
783
+ const transport = transports[sessionId];
784
+ logger.info(`GET /mcp SSE request (session: ${sessionId.substring(0, 8)}...)`);
785
+ await transport.handleRequest(req, res);
786
+ return;
787
+ }
788
+ }
743
789
  res.status(405).json({
744
790
  jsonrpc: "2.0",
745
791
  error: {
746
792
  code: -32e3,
747
- message: "Method not allowed (stateless mode)"
793
+ message: "SSE streaming not supported in stateless mode or invalid session"
748
794
  },
749
795
  id: null
750
796
  });
751
- });
797
+ return;
798
+ }
799
+ if (isDashboardEnabled) {
800
+ try {
801
+ const html = await fetchDashboard();
802
+ res.setHeader("Content-Type", "text/html");
803
+ res.send(html);
804
+ } catch (error) {
805
+ res.status(500).send("<h1>Dashboard temporarily unavailable</h1><p>Please try again later.</p>");
806
+ }
807
+ } else {
808
+ res.status(404).json({
809
+ error: "Dashboard disabled"
810
+ });
811
+ }
812
+ });
813
+ if (isStateless) {
814
+ app.post("/mcp", handleMCPRequestStateless);
752
815
  app.delete("/mcp", (_req, res) => {
753
816
  res.status(405).json({
754
817
  jsonrpc: "2.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leanmcp/core",
3
- "version": "0.3.6",
3
+ "version": "0.3.8",
4
4
  "description": "Core library implementing decorators, reflection, and MCP runtime server",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",