mcp-use 1.2.4 → 1.2.5-dev.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/.tsbuildinfo +1 -1
- package/dist/index.cjs +0 -38
- package/dist/index.js +15 -15
- package/dist/src/agents/index.cjs +0 -6
- package/dist/src/browser.cjs +0 -20
- package/dist/src/browser.js +7 -7
- package/dist/src/react/index.cjs +0 -9
- package/dist/src/server/index.cjs +525 -152
- package/dist/src/server/index.js +523 -141
- package/dist/src/server/logging.d.ts +4 -5
- package/dist/src/server/logging.d.ts.map +1 -1
- package/dist/src/server/mcp-server.d.ts +41 -9
- package/dist/src/server/mcp-server.d.ts.map +1 -1
- package/dist/tsup.config.d.ts.map +1 -1
- package/package.json +8 -12
|
@@ -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
|
|
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
|
|
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
|
|
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 =
|
|
223
|
-
this.app.use(import_express.default.json());
|
|
297
|
+
this.app = new import_hono.Hono();
|
|
224
298
|
this.app.use(
|
|
225
|
-
|
|
299
|
+
"*",
|
|
300
|
+
(0, import_cors.cors)({
|
|
226
301
|
origin: "*",
|
|
227
|
-
|
|
228
|
-
|
|
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
|
|
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 =
|
|
786
|
-
|
|
860
|
+
const manifestPath = pathHelpers.join(
|
|
861
|
+
getCwd(),
|
|
787
862
|
"dist",
|
|
788
863
|
".mcp-use-manifest.json"
|
|
789
864
|
);
|
|
790
|
-
const content =
|
|
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 =
|
|
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) =>
|
|
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 =
|
|
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 =
|
|
948
|
+
const widgetTempDir = pathHelpers.join(tempDir, widget.name);
|
|
869
949
|
await fs.mkdir(widgetTempDir, { recursive: true });
|
|
870
|
-
const resourcesPath =
|
|
871
|
-
const
|
|
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(
|
|
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
|
-
|
|
985
|
+
pathHelpers.join(widgetTempDir, "entry.tsx"),
|
|
907
986
|
entryContent,
|
|
908
987
|
"utf8"
|
|
909
988
|
);
|
|
910
989
|
await fs.writeFile(
|
|
911
|
-
|
|
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
|
|
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
|
-
"@":
|
|
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
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
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
|
-
|
|
943
|
-
|
|
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
|
|
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 =
|
|
986
|
-
|
|
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 =
|
|
1087
|
-
if (!
|
|
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
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
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 =
|
|
1110
|
-
const indexPath =
|
|
1111
|
-
const metadataPath =
|
|
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 =
|
|
1115
|
-
const mcpUrl =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
1251
|
-
|
|
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(
|
|
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 (
|
|
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
|
-
|
|
1538
|
+
c.req.raw.signal?.addEventListener("abort", () => {
|
|
1262
1539
|
transport.close();
|
|
1263
1540
|
});
|
|
1264
1541
|
await this.server.connect(transport);
|
|
1265
|
-
await transport.handleRequest(
|
|
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 (
|
|
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
|
-
|
|
1556
|
+
c.req.raw.signal?.addEventListener("abort", () => {
|
|
1273
1557
|
transport.close();
|
|
1274
1558
|
});
|
|
1275
1559
|
await this.server.connect(transport);
|
|
1276
|
-
await transport.handleRequest(
|
|
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
|
|
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
|
|
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
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
}
|
|
1362
|
-
}
|
|
1719
|
+
} catch {
|
|
1720
|
+
}
|
|
1363
1721
|
}
|
|
1364
1722
|
/**
|
|
1365
1723
|
* Setup default widget serving routes
|
|
1366
1724
|
*
|
|
1367
|
-
* Configures
|
|
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/*", (
|
|
1387
|
-
const widget = req.
|
|
1388
|
-
const assetFile = req.
|
|
1389
|
-
const assetPath =
|
|
1390
|
-
|
|
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
|
-
|
|
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/*", (
|
|
1401
|
-
const assetFile = req.
|
|
1402
|
-
const widgetsDir =
|
|
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 =
|
|
1775
|
+
const widgets = await fsHelpers.readdirSync(widgetsDir);
|
|
1405
1776
|
for (const widget of widgets) {
|
|
1406
|
-
const assetPath =
|
|
1407
|
-
if (
|
|
1408
|
-
|
|
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
|
-
|
|
1788
|
+
return c.notFound();
|
|
1412
1789
|
} catch {
|
|
1413
|
-
|
|
1790
|
+
return c.notFound();
|
|
1414
1791
|
}
|
|
1415
1792
|
});
|
|
1416
|
-
this.app.get("/mcp-use/widgets/:widget", (
|
|
1417
|
-
const
|
|
1418
|
-
|
|
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
|
-
|
|
1800
|
+
widget,
|
|
1423
1801
|
"index.html"
|
|
1424
1802
|
);
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
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
|
-
});
|