mcp-use 1.2.4-canary.1 → 1.2.5-dev.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.
@@ -42,42 +42,9 @@ module.exports = __toCommonJS(server_exports);
42
42
 
43
43
  // src/server/mcp-server.ts
44
44
  var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
45
+ var import_hono = require("hono");
46
+ var import_cors = require("hono/cors");
45
47
  var import_zod = require("zod");
46
- var import_express = __toESM(require("express"), 1);
47
- var import_cors = __toESM(require("cors"), 1);
48
- var import_node_fs = require("fs");
49
- var import_node_path = require("path");
50
- var import_node_fs2 = require("fs");
51
-
52
- // src/server/logging.ts
53
- function requestLogger(req, res, next) {
54
- const timestamp = (/* @__PURE__ */ new Date()).toISOString().substring(11, 23);
55
- const method = req.method;
56
- const url = req.url;
57
- const originalEnd = res.end.bind(res);
58
- res.end = function(chunk, encoding, cb) {
59
- const statusCode = res.statusCode;
60
- let statusColor = "";
61
- if (statusCode >= 200 && statusCode < 300) {
62
- statusColor = "\x1B[32m";
63
- } else if (statusCode >= 300 && statusCode < 400) {
64
- statusColor = "\x1B[33m";
65
- } else if (statusCode >= 400 && statusCode < 500) {
66
- statusColor = "\x1B[31m";
67
- } else if (statusCode >= 500) {
68
- statusColor = "\x1B[35m";
69
- }
70
- let logMessage = `[${timestamp}] ${method} \x1B[1m${url}\x1B[0m`;
71
- if (method === "POST" && url === "/mcp" && req.body?.method) {
72
- logMessage += ` \x1B[1m[${req.body.method}]\x1B[0m`;
73
- }
74
- logMessage += ` ${statusColor}${statusCode}\x1B[0m`;
75
- console.log(logMessage);
76
- return originalEnd(chunk, encoding, cb);
77
- };
78
- next();
79
- }
80
- __name(requestLogger, "requestLogger");
81
48
 
82
49
  // src/server/adapters/mcp-ui-adapter.ts
83
50
  var import_server = require("@mcp-ui/server");
@@ -186,9 +153,117 @@ function createUIResourceFromDefinition(definition, params, config) {
186
153
  }
187
154
  __name(createUIResourceFromDefinition, "createUIResourceFromDefinition");
188
155
 
156
+ // src/server/logging.ts
157
+ async function requestLogger(c, next) {
158
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().substring(11, 23);
159
+ const method = c.req.method;
160
+ const url = c.req.url;
161
+ let body = null;
162
+ if (method === "POST" && url.includes("/mcp")) {
163
+ try {
164
+ body = await c.req.json().catch(() => null);
165
+ } catch {
166
+ }
167
+ }
168
+ await next();
169
+ const statusCode = c.res.status;
170
+ let statusColor = "";
171
+ if (statusCode >= 200 && statusCode < 300) {
172
+ statusColor = "\x1B[32m";
173
+ } else if (statusCode >= 300 && statusCode < 400) {
174
+ statusColor = "\x1B[33m";
175
+ } else if (statusCode >= 400 && statusCode < 500) {
176
+ statusColor = "\x1B[31m";
177
+ } else if (statusCode >= 500) {
178
+ statusColor = "\x1B[35m";
179
+ }
180
+ let logMessage = `[${timestamp}] ${method} \x1B[1m${new URL(url).pathname}\x1B[0m`;
181
+ if (method === "POST" && url.includes("/mcp") && body?.method) {
182
+ logMessage += ` \x1B[1m[${body.method}]\x1B[0m`;
183
+ }
184
+ logMessage += ` ${statusColor}${statusCode}\x1B[0m`;
185
+ console.log(logMessage);
186
+ }
187
+ __name(requestLogger, "requestLogger");
188
+
189
189
  // src/server/mcp-server.ts
190
- var import_vite = require("vite");
191
190
  var TMP_MCP_USE_DIR = ".mcp-use";
191
+ var isDeno = typeof globalThis.Deno !== "undefined";
192
+ function getEnv(key) {
193
+ if (isDeno) {
194
+ return globalThis.Deno.env.get(key);
195
+ }
196
+ return process.env[key];
197
+ }
198
+ __name(getEnv, "getEnv");
199
+ function getCwd() {
200
+ if (isDeno) {
201
+ return globalThis.Deno.cwd();
202
+ }
203
+ return process.cwd();
204
+ }
205
+ __name(getCwd, "getCwd");
206
+ var fsHelpers = {
207
+ async readFileSync(path, encoding = "utf8") {
208
+ if (isDeno) {
209
+ return await globalThis.Deno.readTextFile(path);
210
+ }
211
+ const { readFileSync } = await import("fs");
212
+ const result = readFileSync(path, encoding);
213
+ return typeof result === "string" ? result : result.toString(encoding);
214
+ },
215
+ async readFile(path) {
216
+ if (isDeno) {
217
+ const data = await globalThis.Deno.readFile(path);
218
+ return data.buffer;
219
+ }
220
+ const { readFileSync } = await import("fs");
221
+ const buffer = readFileSync(path);
222
+ return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
223
+ },
224
+ async existsSync(path) {
225
+ if (isDeno) {
226
+ try {
227
+ await globalThis.Deno.stat(path);
228
+ return true;
229
+ } catch {
230
+ return false;
231
+ }
232
+ }
233
+ const { existsSync } = await import("fs");
234
+ return existsSync(path);
235
+ },
236
+ async readdirSync(path) {
237
+ if (isDeno) {
238
+ const entries = [];
239
+ for await (const entry of globalThis.Deno.readDir(path)) {
240
+ entries.push(entry.name);
241
+ }
242
+ return entries;
243
+ }
244
+ const { readdirSync } = await import("fs");
245
+ return readdirSync(path);
246
+ }
247
+ };
248
+ var pathHelpers = {
249
+ join(...paths) {
250
+ if (isDeno) {
251
+ return paths.join("/").replace(/\/+/g, "/");
252
+ }
253
+ return paths.join("/").replace(/\/+/g, "/");
254
+ },
255
+ relative(from, to) {
256
+ const fromParts = from.split("/").filter((p) => p);
257
+ const toParts = to.split("/").filter((p) => p);
258
+ let i = 0;
259
+ while (i < fromParts.length && i < toParts.length && fromParts[i] === toParts[i]) {
260
+ i++;
261
+ }
262
+ const upCount = fromParts.length - i;
263
+ const relativeParts = [...Array(upCount).fill(".."), ...toParts.slice(i)];
264
+ return relativeParts.join("/");
265
+ }
266
+ };
192
267
  var McpServer = class {
193
268
  static {
194
269
  __name(this, "McpServer");
@@ -202,14 +277,14 @@ var McpServer = class {
202
277
  serverHost;
203
278
  serverBaseUrl;
204
279
  /**
205
- * Creates a new MCP server instance with Express integration
280
+ * Creates a new MCP server instance with Hono integration
206
281
  *
207
282
  * Initializes the server with the provided configuration, sets up CORS headers,
208
283
  * configures widget serving routes, and creates a proxy that allows direct
209
- * access to Express methods while preserving MCP server functionality.
284
+ * access to Hono methods while preserving MCP server functionality.
210
285
  *
211
286
  * @param config - Server configuration including name, version, and description
212
- * @returns A proxied McpServer instance that supports both MCP and Express methods
287
+ * @returns A proxied McpServer instance that supports both MCP and Hono methods
213
288
  */
214
289
  constructor(config) {
215
290
  this.config = config;
@@ -219,13 +294,13 @@ var McpServer = class {
219
294
  name: config.name,
220
295
  version: config.version
221
296
  });
222
- this.app = (0, import_express.default)();
223
- this.app.use(import_express.default.json());
297
+ this.app = new import_hono.Hono();
224
298
  this.app.use(
225
- (0, import_cors.default)({
299
+ "*",
300
+ (0, import_cors.cors)({
226
301
  origin: "*",
227
- methods: ["GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS"],
228
- allowedHeaders: [
302
+ allowMethods: ["GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS"],
303
+ allowHeaders: [
229
304
  "Content-Type",
230
305
  "Accept",
231
306
  "Authorization",
@@ -236,7 +311,7 @@ var McpServer = class {
236
311
  ]
237
312
  })
238
313
  );
239
- this.app.use(requestLogger);
314
+ this.app.use("*", requestLogger);
240
315
  return new Proxy(this, {
241
316
  get(target, prop) {
242
317
  if (prop in target) {
@@ -772,7 +847,7 @@ var McpServer = class {
772
847
  * @returns true if in production mode, false otherwise
773
848
  */
774
849
  isProductionMode() {
775
- return process.env.NODE_ENV === "production";
850
+ return getEnv("NODE_ENV") === "production";
776
851
  }
777
852
  /**
778
853
  * Read build manifest file
@@ -780,14 +855,14 @@ var McpServer = class {
780
855
  * @private
781
856
  * @returns Build manifest or null if not found
782
857
  */
783
- readBuildManifest() {
858
+ async readBuildManifest() {
784
859
  try {
785
- const manifestPath = (0, import_node_path.join)(
786
- process.cwd(),
860
+ const manifestPath = pathHelpers.join(
861
+ getCwd(),
787
862
  "dist",
788
863
  ".mcp-use-manifest.json"
789
864
  );
790
- const content = (0, import_node_fs2.readFileSync)(manifestPath, "utf8");
865
+ const content = await fsHelpers.readFileSync(manifestPath, "utf8");
791
866
  return JSON.parse(content);
792
867
  } catch {
793
868
  return null;
@@ -808,6 +883,10 @@ var McpServer = class {
808
883
  if (this.isProductionMode()) {
809
884
  await this.mountWidgetsProduction(options);
810
885
  } else {
886
+ if (isDeno) {
887
+ console.log("[WIDGETS] Skipping dev mode widget mounting in Deno runtime (use production build)");
888
+ return;
889
+ }
811
890
  await this.mountWidgetsDev(options);
812
891
  }
813
892
  }
@@ -828,7 +907,7 @@ var McpServer = class {
828
907
  const { promises: fs } = await import("fs");
829
908
  const baseRoute = options?.baseRoute || "/mcp-use/widgets";
830
909
  const resourcesDir = options?.resourcesDir || "resources";
831
- const srcDir = (0, import_node_path.join)(process.cwd(), resourcesDir);
910
+ const srcDir = pathHelpers.join(getCwd(), resourcesDir);
832
911
  try {
833
912
  await fs.access(srcDir);
834
913
  } catch (error) {
@@ -840,7 +919,7 @@ var McpServer = class {
840
919
  let entries = [];
841
920
  try {
842
921
  const files = await fs.readdir(srcDir);
843
- entries = files.filter((f) => f.endsWith(".tsx") || f.endsWith(".ts")).map((f) => (0, import_node_path.join)(srcDir, f));
922
+ entries = files.filter((f) => f.endsWith(".tsx") || f.endsWith(".ts")).map((f) => pathHelpers.join(srcDir, f));
844
923
  } catch (error) {
845
924
  console.log(`[WIDGETS] No widgets found in ${resourcesDir}/ directory`);
846
925
  return;
@@ -849,9 +928,10 @@ var McpServer = class {
849
928
  console.log(`[WIDGETS] No widgets found in ${resourcesDir}/ directory`);
850
929
  return;
851
930
  }
852
- const tempDir = (0, import_node_path.join)(process.cwd(), TMP_MCP_USE_DIR);
931
+ const tempDir = pathHelpers.join(getCwd(), TMP_MCP_USE_DIR);
853
932
  await fs.mkdir(tempDir, { recursive: true }).catch(() => {
854
933
  });
934
+ const { createServer } = await import("vite");
855
935
  const react = (await import("@vitejs/plugin-react")).default;
856
936
  const tailwindcss = (await import("@tailwindcss/vite")).default;
857
937
  console.log(react, tailwindcss);
@@ -865,11 +945,10 @@ var McpServer = class {
865
945
  };
866
946
  });
867
947
  for (const widget of widgets) {
868
- const widgetTempDir = (0, import_node_path.join)(tempDir, widget.name);
948
+ const widgetTempDir = pathHelpers.join(tempDir, widget.name);
869
949
  await fs.mkdir(widgetTempDir, { recursive: true });
870
- const resourcesPath = (0, import_node_path.join)(process.cwd(), resourcesDir);
871
- const { relative } = await import("path");
872
- const relativeResourcesPath = relative(
950
+ const resourcesPath = pathHelpers.join(getCwd(), resourcesDir);
951
+ const relativeResourcesPath = pathHelpers.relative(
873
952
  widgetTempDir,
874
953
  resourcesPath
875
954
  ).replace(/\\/g, "/");
@@ -878,7 +957,7 @@ var McpServer = class {
878
957
  /* Configure Tailwind to scan the resources directory */
879
958
  @source "${relativeResourcesPath}";
880
959
  `;
881
- await fs.writeFile((0, import_node_path.join)(widgetTempDir, "styles.css"), cssContent, "utf8");
960
+ await fs.writeFile(pathHelpers.join(widgetTempDir, "styles.css"), cssContent, "utf8");
882
961
  const entryContent = `import React from 'react'
883
962
  import { createRoot } from 'react-dom/client'
884
963
  import './styles.css'
@@ -903,12 +982,12 @@ if (container && Component) {
903
982
  </body>
904
983
  </html>`;
905
984
  await fs.writeFile(
906
- (0, import_node_path.join)(widgetTempDir, "entry.tsx"),
985
+ pathHelpers.join(widgetTempDir, "entry.tsx"),
907
986
  entryContent,
908
987
  "utf8"
909
988
  );
910
989
  await fs.writeFile(
911
- (0, import_node_path.join)(widgetTempDir, "index.html"),
990
+ pathHelpers.join(widgetTempDir, "index.html"),
912
991
  htmlContent,
913
992
  "utf8"
914
993
  );
@@ -917,13 +996,13 @@ if (container && Component) {
917
996
  console.log(
918
997
  `[WIDGETS] Serving ${entries.length} widget(s) with shared Vite dev server and HMR`
919
998
  );
920
- const viteServer = await (0, import_vite.createServer)({
999
+ const viteServer = await createServer({
921
1000
  root: tempDir,
922
1001
  base: baseRoute + "/",
923
1002
  plugins: [tailwindcss(), react()],
924
1003
  resolve: {
925
1004
  alias: {
926
- "@": (0, import_node_path.join)(process.cwd(), resourcesDir)
1005
+ "@": pathHelpers.join(getCwd(), resourcesDir)
927
1006
  }
928
1007
  },
929
1008
  server: {
@@ -931,22 +1010,95 @@ if (container && Component) {
931
1010
  origin: serverOrigin
932
1011
  }
933
1012
  });
934
- this.app.use(baseRoute, (req, res, next) => {
935
- const urlPath = req.url || "";
936
- const [pathname, queryString] = urlPath.split("?");
937
- const widgetMatch = pathname.match(/^\/([^/]+)/);
1013
+ const adaptExpressMiddleware = /* @__PURE__ */ __name((middleware) => {
1014
+ return async (c, next) => {
1015
+ const req = c.req.raw;
1016
+ let handled = false;
1017
+ const responseBody = [];
1018
+ let statusCode = 200;
1019
+ const headers = {};
1020
+ const res = {
1021
+ statusCode: 200,
1022
+ status: /* @__PURE__ */ __name((code) => {
1023
+ statusCode = code;
1024
+ res.statusCode = code;
1025
+ return res;
1026
+ }, "status"),
1027
+ setHeader: /* @__PURE__ */ __name((name, value) => {
1028
+ headers[name] = value;
1029
+ }, "setHeader"),
1030
+ getHeader: /* @__PURE__ */ __name((name) => headers[name], "getHeader"),
1031
+ write: /* @__PURE__ */ __name((chunk) => {
1032
+ responseBody.push(typeof chunk === "string" ? new TextEncoder().encode(chunk) : chunk);
1033
+ }, "write"),
1034
+ end: /* @__PURE__ */ __name((chunk) => {
1035
+ if (chunk) {
1036
+ responseBody.push(typeof chunk === "string" ? new TextEncoder().encode(chunk) : chunk);
1037
+ }
1038
+ handled = true;
1039
+ }, "end"),
1040
+ on: /* @__PURE__ */ __name(() => {
1041
+ }, "on"),
1042
+ once: /* @__PURE__ */ __name(() => {
1043
+ }, "once"),
1044
+ removeListener: /* @__PURE__ */ __name(() => {
1045
+ }, "removeListener")
1046
+ };
1047
+ const expressReq = {
1048
+ ...req,
1049
+ url: new URL(req.url).pathname + new URL(req.url).search,
1050
+ originalUrl: req.url,
1051
+ baseUrl: "",
1052
+ path: new URL(req.url).pathname,
1053
+ query: Object.fromEntries(new URL(req.url).searchParams),
1054
+ params: {},
1055
+ body: {},
1056
+ headers: Object.fromEntries(req.headers.entries())
1057
+ };
1058
+ await new Promise((resolve, reject) => {
1059
+ middleware(expressReq, res, (err) => {
1060
+ if (err) reject(err);
1061
+ else resolve();
1062
+ });
1063
+ });
1064
+ if (handled) {
1065
+ const body = Buffer.concat(responseBody);
1066
+ return new Response(body, {
1067
+ status: statusCode,
1068
+ headers
1069
+ });
1070
+ }
1071
+ return next();
1072
+ };
1073
+ }, "adaptExpressMiddleware");
1074
+ this.app.use(`${baseRoute}/*`, async (c, next) => {
1075
+ const url = new URL(c.req.url);
1076
+ const pathname = url.pathname;
1077
+ const widgetMatch = pathname.replace(baseRoute, "").match(/^\/([^/]+)/);
938
1078
  if (widgetMatch) {
939
1079
  const widgetName = widgetMatch[1];
940
1080
  const widget = widgets.find((w) => w.name === widgetName);
941
1081
  if (widget) {
942
- if (pathname === `/${widgetName}` || pathname === `/${widgetName}/`) {
943
- req.url = `/${widgetName}/index.html${queryString ? "?" + queryString : ""}`;
1082
+ const relativePath = pathname.replace(baseRoute, "");
1083
+ if (relativePath === `/${widgetName}` || relativePath === `/${widgetName}/`) {
1084
+ const newUrl = new URL(c.req.url);
1085
+ newUrl.pathname = `${baseRoute}/${widgetName}/index.html`;
1086
+ const newRequest = new Request(newUrl.toString(), c.req.raw);
1087
+ Object.defineProperty(c, "req", {
1088
+ value: {
1089
+ ...c.req,
1090
+ url: newUrl.toString(),
1091
+ raw: newRequest
1092
+ },
1093
+ writable: false,
1094
+ configurable: true
1095
+ });
944
1096
  }
945
1097
  }
946
1098
  }
947
- next();
1099
+ await next();
948
1100
  });
949
- this.app.use(baseRoute, viteServer.middlewares);
1101
+ this.app.use(`${baseRoute}/*`, adaptExpressMiddleware(viteServer.middlewares));
950
1102
  widgets.forEach((widget) => {
951
1103
  console.log(
952
1104
  `[WIDGET] ${widget.name} mounted at ${baseRoute}/${widget.name}`
@@ -982,8 +1134,11 @@ if (container && Component) {
982
1134
  console.log("[WIDGET dev] Metadata:", metadata);
983
1135
  let html = "";
984
1136
  try {
985
- html = (0, import_node_fs2.readFileSync)((0, import_node_path.join)(tempDir, widget.name, "index.html"), "utf8");
986
- const mcpUrl = process.env.MCP_URL || "/";
1137
+ html = await fsHelpers.readFileSync(
1138
+ pathHelpers.join(tempDir, widget.name, "index.html"),
1139
+ "utf8"
1140
+ );
1141
+ const mcpUrl = getEnv("MCP_URL") || "/";
987
1142
  if (mcpUrl && html) {
988
1143
  const htmlWithoutComments = html.replace(/<!--[\s\S]*?-->/g, "");
989
1144
  const baseTagRegex = /<base\s+[^>]*\/?>/i;
@@ -1083,19 +1238,23 @@ if (container && Component) {
1083
1238
  */
1084
1239
  async mountWidgetsProduction(options) {
1085
1240
  const baseRoute = options?.baseRoute || "/mcp-use/widgets";
1086
- const widgetsDir = (0, import_node_path.join)(process.cwd(), "dist", "resources", "widgets");
1087
- if (!(0, import_node_fs.existsSync)(widgetsDir)) {
1241
+ const widgetsDir = pathHelpers.join(getCwd(), "dist", "resources", "widgets");
1242
+ if (!await fsHelpers.existsSync(widgetsDir)) {
1088
1243
  console.log(
1089
1244
  "[WIDGETS] No dist/resources/widgets/ directory found - skipping widget serving"
1090
1245
  );
1091
1246
  return;
1092
1247
  }
1093
1248
  this.setupWidgetRoutes();
1094
- const widgets = (0, import_node_fs.readdirSync)(widgetsDir).filter((name) => {
1095
- const widgetPath = (0, import_node_path.join)(widgetsDir, name);
1096
- const indexPath = (0, import_node_path.join)(widgetPath, "index.html");
1097
- return (0, import_node_fs.existsSync)(indexPath);
1098
- });
1249
+ const allEntries = await fsHelpers.readdirSync(widgetsDir);
1250
+ const widgets = [];
1251
+ for (const name of allEntries) {
1252
+ const widgetPath = pathHelpers.join(widgetsDir, name);
1253
+ const indexPath = pathHelpers.join(widgetPath, "index.html");
1254
+ if (await fsHelpers.existsSync(indexPath)) {
1255
+ widgets.push(name);
1256
+ }
1257
+ }
1099
1258
  if (widgets.length === 0) {
1100
1259
  console.log(
1101
1260
  "[WIDGETS] No built widgets found in dist/resources/widgets/"
@@ -1106,13 +1265,13 @@ if (container && Component) {
1106
1265
  `[WIDGETS] Serving ${widgets.length} pre-built widget(s) from dist/resources/widgets/`
1107
1266
  );
1108
1267
  for (const widgetName of widgets) {
1109
- const widgetPath = (0, import_node_path.join)(widgetsDir, widgetName);
1110
- const indexPath = (0, import_node_path.join)(widgetPath, "index.html");
1111
- const metadataPath = (0, import_node_path.join)(widgetPath, "metadata.json");
1268
+ const widgetPath = pathHelpers.join(widgetsDir, widgetName);
1269
+ const indexPath = pathHelpers.join(widgetPath, "index.html");
1270
+ const metadataPath = pathHelpers.join(widgetPath, "metadata.json");
1112
1271
  let html = "";
1113
1272
  try {
1114
- html = (0, import_node_fs2.readFileSync)(indexPath, "utf8");
1115
- const mcpUrl = process.env.MCP_URL || "/";
1273
+ html = await fsHelpers.readFileSync(indexPath, "utf8");
1274
+ const mcpUrl = getEnv("MCP_URL") || "/";
1116
1275
  if (mcpUrl && html) {
1117
1276
  const htmlWithoutComments = html.replace(/<!--[\s\S]*?-->/g, "");
1118
1277
  const baseTagRegex = /<base\s+[^>]*\/?>/i;
@@ -1159,7 +1318,7 @@ if (container && Component) {
1159
1318
  let props = {};
1160
1319
  let description = `Widget: ${widgetName}`;
1161
1320
  try {
1162
- const metadataContent = (0, import_node_fs2.readFileSync)(metadataPath, "utf8");
1321
+ const metadataContent = await fsHelpers.readFileSync(metadataPath, "utf8");
1163
1322
  metadata = JSON.parse(metadataContent);
1164
1323
  if (metadata.description) {
1165
1324
  description = metadata.description;
@@ -1242,47 +1401,178 @@ if (container && Component) {
1242
1401
  if (this.mcpMounted) return;
1243
1402
  const { StreamableHTTPServerTransport } = await import("@modelcontextprotocol/sdk/server/streamableHttp.js");
1244
1403
  const endpoint = "/mcp";
1245
- this.app.post(endpoint, import_express.default.json(), async (req, res) => {
1404
+ const createExpressLikeObjects = /* @__PURE__ */ __name((c) => {
1405
+ const req = c.req.raw;
1406
+ const responseBody = [];
1407
+ let statusCode = 200;
1408
+ const headers = {};
1409
+ let ended = false;
1410
+ let headersSent = false;
1411
+ const expressReq = {
1412
+ ...req,
1413
+ url: new URL(req.url).pathname + new URL(req.url).search,
1414
+ originalUrl: req.url,
1415
+ baseUrl: "",
1416
+ path: new URL(req.url).pathname,
1417
+ query: Object.fromEntries(new URL(req.url).searchParams),
1418
+ params: {},
1419
+ body: {},
1420
+ headers: Object.fromEntries(req.headers.entries()),
1421
+ method: req.method
1422
+ };
1423
+ const expressRes = {
1424
+ statusCode: 200,
1425
+ headersSent: false,
1426
+ status: /* @__PURE__ */ __name((code) => {
1427
+ statusCode = code;
1428
+ expressRes.statusCode = code;
1429
+ return expressRes;
1430
+ }, "status"),
1431
+ setHeader: /* @__PURE__ */ __name((name, value) => {
1432
+ if (!headersSent) {
1433
+ headers[name] = Array.isArray(value) ? value.join(", ") : value;
1434
+ }
1435
+ }, "setHeader"),
1436
+ getHeader: /* @__PURE__ */ __name((name) => headers[name], "getHeader"),
1437
+ write: /* @__PURE__ */ __name((chunk, encoding, callback) => {
1438
+ if (!ended) {
1439
+ const data = typeof chunk === "string" ? new TextEncoder().encode(chunk) : chunk instanceof Uint8Array ? chunk : Buffer.from(chunk);
1440
+ responseBody.push(data);
1441
+ }
1442
+ if (typeof encoding === "function") {
1443
+ encoding();
1444
+ } else if (callback) {
1445
+ callback();
1446
+ }
1447
+ return true;
1448
+ }, "write"),
1449
+ end: /* @__PURE__ */ __name((chunk, encoding, callback) => {
1450
+ if (chunk && !ended) {
1451
+ const data = typeof chunk === "string" ? new TextEncoder().encode(chunk) : chunk instanceof Uint8Array ? chunk : Buffer.from(chunk);
1452
+ responseBody.push(data);
1453
+ }
1454
+ ended = true;
1455
+ if (typeof encoding === "function") {
1456
+ encoding();
1457
+ } else if (callback) {
1458
+ callback();
1459
+ }
1460
+ }, "end"),
1461
+ on: /* @__PURE__ */ __name((event, handler) => {
1462
+ if (event === "close") {
1463
+ expressRes._closeHandler = handler;
1464
+ }
1465
+ }, "on"),
1466
+ once: /* @__PURE__ */ __name(() => {
1467
+ }, "once"),
1468
+ removeListener: /* @__PURE__ */ __name(() => {
1469
+ }, "removeListener"),
1470
+ writeHead: /* @__PURE__ */ __name((code, _headers) => {
1471
+ statusCode = code;
1472
+ expressRes.statusCode = code;
1473
+ headersSent = true;
1474
+ if (_headers) {
1475
+ Object.assign(headers, _headers);
1476
+ }
1477
+ return expressRes;
1478
+ }, "writeHead"),
1479
+ flushHeaders: /* @__PURE__ */ __name(() => {
1480
+ headersSent = true;
1481
+ }, "flushHeaders"),
1482
+ send: /* @__PURE__ */ __name((body) => {
1483
+ if (!ended) {
1484
+ expressRes.write(body);
1485
+ expressRes.end();
1486
+ }
1487
+ }, "send")
1488
+ };
1489
+ return { expressReq, expressRes, getResponse: /* @__PURE__ */ __name(() => {
1490
+ if (ended) {
1491
+ if (responseBody.length > 0) {
1492
+ const body = isDeno ? Buffer.concat(responseBody) : Buffer.concat(responseBody);
1493
+ return new Response(body, {
1494
+ status: statusCode,
1495
+ headers
1496
+ });
1497
+ } else {
1498
+ return new Response(null, {
1499
+ status: statusCode,
1500
+ headers
1501
+ });
1502
+ }
1503
+ }
1504
+ return null;
1505
+ }, "getResponse") };
1506
+ }, "createExpressLikeObjects");
1507
+ this.app.post(endpoint, async (c) => {
1508
+ const { expressReq, expressRes, getResponse } = createExpressLikeObjects(c);
1509
+ try {
1510
+ expressReq.body = await c.req.json();
1511
+ } catch {
1512
+ expressReq.body = {};
1513
+ }
1246
1514
  const transport = new StreamableHTTPServerTransport({
1247
1515
  sessionIdGenerator: void 0,
1248
1516
  enableJsonResponse: true
1249
1517
  });
1250
- res.on("close", () => {
1251
- transport.close();
1252
- });
1518
+ if (expressRes._closeHandler) {
1519
+ c.req.raw.signal?.addEventListener("abort", () => {
1520
+ transport.close();
1521
+ });
1522
+ }
1253
1523
  await this.server.connect(transport);
1254
- await transport.handleRequest(req, res, req.body);
1524
+ await transport.handleRequest(expressReq, expressRes, expressReq.body);
1525
+ await new Promise((resolve) => setTimeout(resolve, 10));
1526
+ const response = getResponse();
1527
+ if (response) {
1528
+ return response;
1529
+ }
1530
+ return c.text("", 200);
1255
1531
  });
1256
- this.app.get(endpoint, async (req, res) => {
1532
+ this.app.get(endpoint, async (c) => {
1533
+ const { expressReq, expressRes, getResponse } = createExpressLikeObjects(c);
1257
1534
  const transport = new StreamableHTTPServerTransport({
1258
1535
  sessionIdGenerator: void 0,
1259
1536
  enableJsonResponse: true
1260
1537
  });
1261
- res.on("close", () => {
1538
+ c.req.raw.signal?.addEventListener("abort", () => {
1262
1539
  transport.close();
1263
1540
  });
1264
1541
  await this.server.connect(transport);
1265
- await transport.handleRequest(req, res);
1542
+ await transport.handleRequest(expressReq, expressRes);
1543
+ await new Promise((resolve) => setTimeout(resolve, 10));
1544
+ const response = getResponse();
1545
+ if (response) {
1546
+ return response;
1547
+ }
1548
+ return c.text("", 200);
1266
1549
  });
1267
- this.app.delete(endpoint, async (req, res) => {
1550
+ this.app.delete(endpoint, async (c) => {
1551
+ const { expressReq, expressRes, getResponse } = createExpressLikeObjects(c);
1268
1552
  const transport = new StreamableHTTPServerTransport({
1269
1553
  sessionIdGenerator: void 0,
1270
1554
  enableJsonResponse: true
1271
1555
  });
1272
- res.on("close", () => {
1556
+ c.req.raw.signal?.addEventListener("abort", () => {
1273
1557
  transport.close();
1274
1558
  });
1275
1559
  await this.server.connect(transport);
1276
- await transport.handleRequest(req, res);
1560
+ await transport.handleRequest(expressReq, expressRes);
1561
+ await new Promise((resolve) => setTimeout(resolve, 10));
1562
+ const response = getResponse();
1563
+ if (response) {
1564
+ return response;
1565
+ }
1566
+ return c.text("", 200);
1277
1567
  });
1278
1568
  this.mcpMounted = true;
1279
1569
  console.log(`[MCP] Server mounted at ${endpoint}`);
1280
1570
  }
1281
1571
  /**
1282
- * Start the Express server with MCP endpoints
1572
+ * Start the Hono server with MCP endpoints
1283
1573
  *
1284
1574
  * Initiates the server startup process by mounting MCP endpoints, configuring
1285
- * the inspector UI (if available), and starting the Express server to listen
1575
+ * the inspector UI (if available), and starting the server to listen
1286
1576
  * for incoming connections. This is the main entry point for running the server.
1287
1577
  *
1288
1578
  * The server will be accessible at the specified port with MCP endpoints at /mcp
@@ -1300,24 +1590,91 @@ if (container && Component) {
1300
1590
  * ```
1301
1591
  */
1302
1592
  async listen(port) {
1303
- this.serverPort = port || (process.env.PORT ? parseInt(process.env.PORT, 10) : 3001);
1304
- if (process.env.HOST) {
1305
- this.serverHost = process.env.HOST;
1593
+ const portEnv = getEnv("PORT");
1594
+ this.serverPort = port || (portEnv ? parseInt(portEnv, 10) : 3001);
1595
+ const hostEnv = getEnv("HOST");
1596
+ if (hostEnv) {
1597
+ this.serverHost = hostEnv;
1306
1598
  }
1307
1599
  await this.mountWidgets({
1308
1600
  baseRoute: "/mcp-use/widgets",
1309
1601
  resourcesDir: "resources"
1310
1602
  });
1311
1603
  await this.mountMcp();
1312
- this.mountInspector();
1313
- this.app.listen(this.serverPort, () => {
1604
+ await this.mountInspector();
1605
+ if (isDeno) {
1606
+ globalThis.Deno.serve(
1607
+ { port: this.serverPort, hostname: this.serverHost },
1608
+ this.app.fetch
1609
+ );
1314
1610
  console.log(
1315
1611
  `[SERVER] Listening on http://${this.serverHost}:${this.serverPort}`
1316
1612
  );
1317
1613
  console.log(
1318
1614
  `[MCP] Endpoints: http://${this.serverHost}:${this.serverPort}/mcp`
1319
1615
  );
1616
+ } else {
1617
+ const { serve } = await import("@hono/node-server");
1618
+ serve(
1619
+ {
1620
+ fetch: this.app.fetch,
1621
+ port: this.serverPort,
1622
+ hostname: this.serverHost
1623
+ },
1624
+ (_info) => {
1625
+ console.log(
1626
+ `[SERVER] Listening on http://${this.serverHost}:${this.serverPort}`
1627
+ );
1628
+ console.log(
1629
+ `[MCP] Endpoints: http://${this.serverHost}:${this.serverPort}/mcp`
1630
+ );
1631
+ }
1632
+ );
1633
+ }
1634
+ }
1635
+ /**
1636
+ * Get the fetch handler for the server after mounting all endpoints
1637
+ *
1638
+ * This method prepares the server by mounting MCP endpoints, widgets, and inspector
1639
+ * (if available), then returns the fetch handler. This is useful for integrating
1640
+ * with external server frameworks like Supabase Edge Functions, Cloudflare Workers,
1641
+ * or other platforms that handle the server lifecycle themselves.
1642
+ *
1643
+ * Unlike `listen()`, this method does not start a server - it only prepares the
1644
+ * routes and returns the handler function that can be used with external servers.
1645
+ *
1646
+ * @returns Promise that resolves to the fetch handler function
1647
+ *
1648
+ * @example
1649
+ * ```typescript
1650
+ * // For Supabase Edge Functions
1651
+ * const server = createMCPServer('my-server');
1652
+ * server.tool({ ... });
1653
+ * const handler = await server.getHandler();
1654
+ * Deno.serve(handler);
1655
+ * ```
1656
+ *
1657
+ * @example
1658
+ * ```typescript
1659
+ * // For Cloudflare Workers
1660
+ * const server = createMCPServer('my-server');
1661
+ * server.tool({ ... });
1662
+ * const handler = await server.getHandler();
1663
+ * export default { fetch: handler };
1664
+ * ```
1665
+ */
1666
+ async getHandler() {
1667
+ await this.mountWidgets({
1668
+ baseRoute: "/mcp-use/widgets",
1669
+ resourcesDir: "resources"
1320
1670
  });
1671
+ await this.mountMcp();
1672
+ await this.mountInspector();
1673
+ const fetchHandler = this.app.fetch.bind(this.app);
1674
+ return async (req) => {
1675
+ const result = await fetchHandler(req);
1676
+ return result;
1677
+ };
1321
1678
  }
1322
1679
  /**
1323
1680
  * Mount MCP Inspector UI at /inspector
@@ -1341,10 +1698,10 @@ if (container && Component) {
1341
1698
  * - Server continues to function normally
1342
1699
  * - No inspector UI available
1343
1700
  */
1344
- mountInspector() {
1701
+ async mountInspector() {
1345
1702
  if (this.inspectorMounted) return;
1346
1703
  if (this.isProductionMode()) {
1347
- const manifest = this.readBuildManifest();
1704
+ const manifest = await this.readBuildManifest();
1348
1705
  if (!manifest?.includeInspector) {
1349
1706
  console.log(
1350
1707
  "[INSPECTOR] Skipped in production (use --with-inspector flag during build)"
@@ -1352,19 +1709,20 @@ if (container && Component) {
1352
1709
  return;
1353
1710
  }
1354
1711
  }
1355
- import("@mcp-use/inspector").then(({ mountInspector }) => {
1712
+ try {
1713
+ const { mountInspector } = await import("@mcp-use/inspector");
1356
1714
  mountInspector(this.app);
1357
1715
  this.inspectorMounted = true;
1358
1716
  console.log(
1359
1717
  `[INSPECTOR] UI available at http://${this.serverHost}:${this.serverPort}/inspector`
1360
1718
  );
1361
- }).catch(() => {
1362
- });
1719
+ } catch {
1720
+ }
1363
1721
  }
1364
1722
  /**
1365
1723
  * Setup default widget serving routes
1366
1724
  *
1367
- * Configures Express routes to serve MCP UI widgets and their static assets.
1725
+ * Configures Hono routes to serve MCP UI widgets and their static assets.
1368
1726
  * Widgets are served from the dist/resources/widgets directory and can
1369
1727
  * be accessed via HTTP endpoints for embedding in web applications.
1370
1728
  *
@@ -1383,11 +1741,11 @@ if (container && Component) {
1383
1741
  * - http://localhost:3001/mcp-use/widgets/assets/script.js (auto-discovered)
1384
1742
  */
1385
1743
  setupWidgetRoutes() {
1386
- this.app.get("/mcp-use/widgets/:widget/assets/*", (req, res, next) => {
1387
- const widget = req.params.widget;
1388
- const assetFile = req.params[0];
1389
- const assetPath = (0, import_node_path.join)(
1390
- process.cwd(),
1744
+ this.app.get("/mcp-use/widgets/:widget/assets/*", async (c) => {
1745
+ const widget = c.req.param("widget");
1746
+ const assetFile = c.req.path.split("/assets/")[1];
1747
+ const assetPath = pathHelpers.join(
1748
+ getCwd(),
1391
1749
  "dist",
1392
1750
  "resources",
1393
1751
  "widgets",
@@ -1395,48 +1753,72 @@ if (container && Component) {
1395
1753
  "assets",
1396
1754
  assetFile
1397
1755
  );
1398
- res.sendFile(assetPath, (err) => err ? next() : void 0);
1756
+ try {
1757
+ if (await fsHelpers.existsSync(assetPath)) {
1758
+ const content = await fsHelpers.readFile(assetPath);
1759
+ const ext = assetFile.split(".").pop()?.toLowerCase();
1760
+ const contentType = ext === "js" ? "application/javascript" : ext === "css" ? "text/css" : ext === "png" ? "image/png" : ext === "jpg" || ext === "jpeg" ? "image/jpeg" : ext === "svg" ? "image/svg+xml" : "application/octet-stream";
1761
+ return new Response(content, {
1762
+ status: 200,
1763
+ headers: { "Content-Type": contentType }
1764
+ });
1765
+ }
1766
+ return c.notFound();
1767
+ } catch {
1768
+ return c.notFound();
1769
+ }
1399
1770
  });
1400
- this.app.get("/mcp-use/widgets/assets/*", (req, res, next) => {
1401
- const assetFile = req.params[0];
1402
- const widgetsDir = (0, import_node_path.join)(process.cwd(), "dist", "resources", "widgets");
1771
+ this.app.get("/mcp-use/widgets/assets/*", async (c) => {
1772
+ const assetFile = c.req.path.split("/assets/")[1];
1773
+ const widgetsDir = pathHelpers.join(getCwd(), "dist", "resources", "widgets");
1403
1774
  try {
1404
- const widgets = (0, import_node_fs.readdirSync)(widgetsDir);
1775
+ const widgets = await fsHelpers.readdirSync(widgetsDir);
1405
1776
  for (const widget of widgets) {
1406
- const assetPath = (0, import_node_path.join)(widgetsDir, widget, "assets", assetFile);
1407
- if ((0, import_node_fs.existsSync)(assetPath)) {
1408
- return res.sendFile(assetPath);
1777
+ const assetPath = pathHelpers.join(widgetsDir, widget, "assets", assetFile);
1778
+ if (await fsHelpers.existsSync(assetPath)) {
1779
+ const content = await fsHelpers.readFile(assetPath);
1780
+ const ext = assetFile.split(".").pop()?.toLowerCase();
1781
+ const contentType = ext === "js" ? "application/javascript" : ext === "css" ? "text/css" : ext === "png" ? "image/png" : ext === "jpg" || ext === "jpeg" ? "image/jpeg" : ext === "svg" ? "image/svg+xml" : "application/octet-stream";
1782
+ return new Response(content, {
1783
+ status: 200,
1784
+ headers: { "Content-Type": contentType }
1785
+ });
1409
1786
  }
1410
1787
  }
1411
- next();
1788
+ return c.notFound();
1412
1789
  } catch {
1413
- next();
1790
+ return c.notFound();
1414
1791
  }
1415
1792
  });
1416
- this.app.get("/mcp-use/widgets/:widget", (req, res, next) => {
1417
- const filePath = (0, import_node_path.join)(
1418
- process.cwd(),
1793
+ this.app.get("/mcp-use/widgets/:widget", async (c) => {
1794
+ const widget = c.req.param("widget");
1795
+ const filePath = pathHelpers.join(
1796
+ getCwd(),
1419
1797
  "dist",
1420
1798
  "resources",
1421
1799
  "widgets",
1422
- req.params.widget,
1800
+ widget,
1423
1801
  "index.html"
1424
1802
  );
1425
- let html = (0, import_node_fs2.readFileSync)(filePath, "utf8");
1426
- html = html.replace(
1427
- /src="\/mcp-use\/widgets\/([^"]+)"/g,
1428
- `src="${this.serverBaseUrl}/mcp-use/widgets/$1"`
1429
- );
1430
- html = html.replace(
1431
- /href="\/mcp-use\/widgets\/([^"]+)"/g,
1432
- `href="${this.serverBaseUrl}/mcp-use/widgets/$1"`
1433
- );
1434
- html = html.replace(
1435
- /<head[^>]*>/i,
1436
- `<head>
1437
- <script>window.__getFile = (filename) => { return "${this.serverBaseUrl}/mcp-use/widgets/${req.params.widget}/"+filename }</script>`
1438
- );
1439
- res.send(html);
1803
+ try {
1804
+ let html = await fsHelpers.readFileSync(filePath, "utf8");
1805
+ html = html.replace(
1806
+ /src="\/mcp-use\/widgets\/([^"]+)"/g,
1807
+ `src="${this.serverBaseUrl}/mcp-use/widgets/$1"`
1808
+ );
1809
+ html = html.replace(
1810
+ /href="\/mcp-use\/widgets\/([^"]+)"/g,
1811
+ `href="${this.serverBaseUrl}/mcp-use/widgets/$1"`
1812
+ );
1813
+ html = html.replace(
1814
+ /<head[^>]*>/i,
1815
+ `<head>
1816
+ <script>window.__getFile = (filename) => { return "${this.serverBaseUrl}/mcp-use/widgets/${widget}/"+filename }</script>`
1817
+ );
1818
+ return c.html(html);
1819
+ } catch {
1820
+ return c.notFound();
1821
+ }
1440
1822
  });
1441
1823
  }
1442
1824
  /**
@@ -1629,12 +2011,3 @@ function createMCPServer(name, config = {}) {
1629
2011
  return instance;
1630
2012
  }
1631
2013
  __name(createMCPServer, "createMCPServer");
1632
- // Annotate the CommonJS export names for ESM import in node:
1633
- 0 && (module.exports = {
1634
- buildWidgetUrl,
1635
- createExternalUrlResource,
1636
- createMCPServer,
1637
- createRawHtmlResource,
1638
- createRemoteDomResource,
1639
- createUIResourceFromDefinition
1640
- });