@mcp-use/cli 3.2.0-canary.5 → 3.2.0-canary.6
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/commands/client.d.ts +2 -0
- package/dist/commands/client.d.ts.map +1 -1
- package/dist/commands/screenshot.d.ts +65 -0
- package/dist/commands/screenshot.d.ts.map +1 -0
- package/dist/index.cjs +1044 -290
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +995 -241
- package/dist/index.js.map +1 -1
- package/dist/utils/cdp-screenshot.d.ts +33 -0
- package/dist/utils/cdp-screenshot.d.ts.map +1 -0
- package/dist/utils/chrome-path.d.ts +14 -0
- package/dist/utils/chrome-path.d.ts.map +1 -0
- package/dist/utils/session.d.ts +37 -0
- package/dist/utils/session.d.ts.map +1 -0
- package/package.json +5 -3
package/dist/index.js
CHANGED
|
@@ -9,12 +9,12 @@ var __export = (target, all) => {
|
|
|
9
9
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
-
// ../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.
|
|
12
|
+
// ../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.9_tsx@4.21.0_typescript@5.9.3_yaml@2.8.3/node_modules/tsup/assets/esm_shims.js
|
|
13
13
|
import path from "path";
|
|
14
14
|
import { fileURLToPath } from "url";
|
|
15
15
|
var getFilename, getDirname, __dirname;
|
|
16
16
|
var init_esm_shims = __esm({
|
|
17
|
-
"../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.
|
|
17
|
+
"../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.9_tsx@4.21.0_typescript@5.9.3_yaml@2.8.3/node_modules/tsup/assets/esm_shims.js"() {
|
|
18
18
|
"use strict";
|
|
19
19
|
getFilename = () => fileURLToPath(import.meta.url);
|
|
20
20
|
getDirname = () => path.dirname(getFilename());
|
|
@@ -235,15 +235,15 @@ var init_wsl_utils = __esm({
|
|
|
235
235
|
const { stdout } = await executePowerShell(command, { powerShellPath: psPath });
|
|
236
236
|
return stdout.trim();
|
|
237
237
|
};
|
|
238
|
-
convertWslPathToWindows = async (
|
|
239
|
-
if (/^[a-z]+:\/\//i.test(
|
|
240
|
-
return
|
|
238
|
+
convertWslPathToWindows = async (path12) => {
|
|
239
|
+
if (/^[a-z]+:\/\//i.test(path12)) {
|
|
240
|
+
return path12;
|
|
241
241
|
}
|
|
242
242
|
try {
|
|
243
|
-
const { stdout } = await execFile2("wslpath", ["-aw",
|
|
243
|
+
const { stdout } = await execFile2("wslpath", ["-aw", path12], { encoding: "utf8" });
|
|
244
244
|
return stdout.trim();
|
|
245
245
|
} catch {
|
|
246
|
-
return
|
|
246
|
+
return path12;
|
|
247
247
|
}
|
|
248
248
|
};
|
|
249
249
|
}
|
|
@@ -1263,13 +1263,13 @@ var source_default = chalk;
|
|
|
1263
1263
|
|
|
1264
1264
|
// src/index.ts
|
|
1265
1265
|
init_open();
|
|
1266
|
-
import { Command as
|
|
1266
|
+
import { Command as Command7 } from "commander";
|
|
1267
1267
|
import "dotenv/config";
|
|
1268
|
-
import { spawn } from "child_process";
|
|
1268
|
+
import { spawn as spawn3 } from "child_process";
|
|
1269
1269
|
import { readFileSync as readFileSync2 } from "fs";
|
|
1270
|
-
import { access, mkdir as
|
|
1270
|
+
import { access, mkdir as mkdir4, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
1271
1271
|
import { createRequire as createRequire2 } from "module";
|
|
1272
|
-
import
|
|
1272
|
+
import path11 from "path";
|
|
1273
1273
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
1274
1274
|
import { viteSingleFile } from "vite-plugin-singlefile";
|
|
1275
1275
|
import { toJSONSchema } from "zod";
|
|
@@ -1506,8 +1506,8 @@ var McpUseAPI = class _McpUseAPI {
|
|
|
1506
1506
|
return this.request(`/servers${q ? `?${q}` : ""}`);
|
|
1507
1507
|
}
|
|
1508
1508
|
async getServer(idOrSlug) {
|
|
1509
|
-
const
|
|
1510
|
-
return this.request(`/servers/${
|
|
1509
|
+
const path12 = encodeURIComponent(idOrSlug);
|
|
1510
|
+
return this.request(`/servers/${path12}`);
|
|
1511
1511
|
}
|
|
1512
1512
|
async deleteServer(id) {
|
|
1513
1513
|
await this.request(
|
|
@@ -2009,9 +2009,8 @@ async function whoamiCommand() {
|
|
|
2009
2009
|
|
|
2010
2010
|
// src/commands/client.ts
|
|
2011
2011
|
init_esm_shims();
|
|
2012
|
-
import { Command } from "commander";
|
|
2013
|
-
import { MCPClient } from "mcp-use/client";
|
|
2014
|
-
import { getPackageVersion } from "mcp-use/server";
|
|
2012
|
+
import { Command as Command2 } from "commander";
|
|
2013
|
+
import { MCPClient as MCPClient3 } from "mcp-use/client";
|
|
2015
2014
|
import { createInterface as createInterface2 } from "readline";
|
|
2016
2015
|
|
|
2017
2016
|
// src/utils/format.ts
|
|
@@ -2610,6 +2609,121 @@ async function updateSessionInfo(name, serverInfo, capabilities) {
|
|
|
2610
2609
|
}
|
|
2611
2610
|
}
|
|
2612
2611
|
|
|
2612
|
+
// src/utils/session.ts
|
|
2613
|
+
init_esm_shims();
|
|
2614
|
+
import { MCPClient } from "mcp-use/client";
|
|
2615
|
+
import { getPackageVersion } from "mcp-use/server";
|
|
2616
|
+
var activeSessions = /* @__PURE__ */ new Map();
|
|
2617
|
+
function getCliClientInfo() {
|
|
2618
|
+
return {
|
|
2619
|
+
name: "mcp-use CLI",
|
|
2620
|
+
title: "mcp-use CLI",
|
|
2621
|
+
version: getPackageVersion(),
|
|
2622
|
+
description: "mcp-use CLI - Command-line interface for MCP servers",
|
|
2623
|
+
icons: [
|
|
2624
|
+
{
|
|
2625
|
+
src: "https://manufact.com/logo.png"
|
|
2626
|
+
}
|
|
2627
|
+
],
|
|
2628
|
+
websiteUrl: "https://manufact.com"
|
|
2629
|
+
};
|
|
2630
|
+
}
|
|
2631
|
+
async function cleanupAndExit(code) {
|
|
2632
|
+
for (const [name, { client }] of activeSessions) {
|
|
2633
|
+
try {
|
|
2634
|
+
await client.closeAllSessions();
|
|
2635
|
+
} catch {
|
|
2636
|
+
}
|
|
2637
|
+
activeSessions.delete(name);
|
|
2638
|
+
}
|
|
2639
|
+
process.exit(code);
|
|
2640
|
+
}
|
|
2641
|
+
async function getOrRestoreSession(sessionName) {
|
|
2642
|
+
if (!sessionName) {
|
|
2643
|
+
const active = await getActiveSession();
|
|
2644
|
+
if (!active) {
|
|
2645
|
+
console.error(
|
|
2646
|
+
formatError("No active session. Connect to a server first.")
|
|
2647
|
+
);
|
|
2648
|
+
console.error(
|
|
2649
|
+
formatInfo("Use: npx mcp-use client connect <url> --name <name>")
|
|
2650
|
+
);
|
|
2651
|
+
return null;
|
|
2652
|
+
}
|
|
2653
|
+
sessionName = active.name;
|
|
2654
|
+
}
|
|
2655
|
+
if (activeSessions.has(sessionName)) {
|
|
2656
|
+
const { session } = activeSessions.get(sessionName);
|
|
2657
|
+
return { name: sessionName, session };
|
|
2658
|
+
}
|
|
2659
|
+
const config = await getSession(sessionName);
|
|
2660
|
+
if (!config) {
|
|
2661
|
+
console.error(formatError(`Session '${sessionName}' not found`));
|
|
2662
|
+
return null;
|
|
2663
|
+
}
|
|
2664
|
+
try {
|
|
2665
|
+
const client = new MCPClient();
|
|
2666
|
+
const cliClientInfo = getCliClientInfo();
|
|
2667
|
+
let authProvider;
|
|
2668
|
+
if (config.type === "http") {
|
|
2669
|
+
if (config.authMode === "oauth") {
|
|
2670
|
+
authProvider = await buildOAuthProvider(config.url);
|
|
2671
|
+
client.addServer(sessionName, {
|
|
2672
|
+
url: config.url,
|
|
2673
|
+
authProvider,
|
|
2674
|
+
clientInfo: cliClientInfo
|
|
2675
|
+
});
|
|
2676
|
+
} else {
|
|
2677
|
+
client.addServer(sessionName, {
|
|
2678
|
+
url: config.url,
|
|
2679
|
+
headers: config.authToken ? { Authorization: `Bearer ${config.authToken}` } : void 0,
|
|
2680
|
+
clientInfo: cliClientInfo
|
|
2681
|
+
});
|
|
2682
|
+
}
|
|
2683
|
+
} else if (config.type === "stdio") {
|
|
2684
|
+
client.addServer(sessionName, {
|
|
2685
|
+
command: config.command,
|
|
2686
|
+
args: config.args || [],
|
|
2687
|
+
env: config.env,
|
|
2688
|
+
clientInfo: cliClientInfo
|
|
2689
|
+
});
|
|
2690
|
+
} else {
|
|
2691
|
+
console.error(formatError(`Unknown session type: ${config.type}`));
|
|
2692
|
+
return null;
|
|
2693
|
+
}
|
|
2694
|
+
let session;
|
|
2695
|
+
try {
|
|
2696
|
+
session = await client.createSession(sessionName);
|
|
2697
|
+
} catch (err) {
|
|
2698
|
+
if (config.type === "http" && config.authMode === "oauth" && authProvider && isUnauthorized(err)) {
|
|
2699
|
+
const reAuth = await promptYesNo(
|
|
2700
|
+
`! Tokens for session '${sessionName}' expired and could not refresh. Re-authenticate now?`,
|
|
2701
|
+
true
|
|
2702
|
+
);
|
|
2703
|
+
if (!reAuth) {
|
|
2704
|
+
console.error(formatError(`Tokens expired and could not refresh.`));
|
|
2705
|
+
console.error(
|
|
2706
|
+
formatInfo(
|
|
2707
|
+
`Run: mcp-use client connect ${config.url} --name ${sessionName}`
|
|
2708
|
+
)
|
|
2709
|
+
);
|
|
2710
|
+
return null;
|
|
2711
|
+
}
|
|
2712
|
+
await runOAuthFlow(authProvider, config.url);
|
|
2713
|
+
session = await client.createSession(sessionName);
|
|
2714
|
+
} else {
|
|
2715
|
+
throw err;
|
|
2716
|
+
}
|
|
2717
|
+
}
|
|
2718
|
+
activeSessions.set(sessionName, { client, session });
|
|
2719
|
+
console.error(formatInfo(`Reconnected to session '${sessionName}'`));
|
|
2720
|
+
return { name: sessionName, session };
|
|
2721
|
+
} catch (error) {
|
|
2722
|
+
console.error(formatError(`Failed to restore session: ${error.message}`));
|
|
2723
|
+
return null;
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2726
|
+
|
|
2613
2727
|
// src/commands/client-auth.ts
|
|
2614
2728
|
init_esm_shims();
|
|
2615
2729
|
async function resolveSession(sessionArg) {
|
|
@@ -2725,121 +2839,711 @@ async function authLogoutCommand(sessionArg) {
|
|
|
2725
2839
|
);
|
|
2726
2840
|
}
|
|
2727
2841
|
|
|
2728
|
-
// src/commands/
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2842
|
+
// src/commands/screenshot.ts
|
|
2843
|
+
init_esm_shims();
|
|
2844
|
+
import { Command } from "commander";
|
|
2845
|
+
import { MCPClient as MCPClient2 } from "mcp-use/client";
|
|
2846
|
+
import { spawn as spawn2 } from "child_process";
|
|
2847
|
+
import { existsSync as existsSync2 } from "fs";
|
|
2848
|
+
import { mkdir as mkdir2 } from "fs/promises";
|
|
2849
|
+
import { createServer } from "net";
|
|
2850
|
+
import path6 from "path";
|
|
2851
|
+
|
|
2852
|
+
// src/utils/cdp-screenshot.ts
|
|
2853
|
+
init_esm_shims();
|
|
2854
|
+
import { spawn } from "child_process";
|
|
2855
|
+
import { mkdtempSync, rmSync, writeFileSync } from "fs";
|
|
2856
|
+
import os4 from "os";
|
|
2857
|
+
import path4 from "path";
|
|
2858
|
+
import WebSocket from "ws";
|
|
2859
|
+
var CdpClient = class {
|
|
2860
|
+
constructor(ws) {
|
|
2861
|
+
this.ws = ws;
|
|
2862
|
+
ws.on("message", (data) => {
|
|
2863
|
+
let msg;
|
|
2864
|
+
try {
|
|
2865
|
+
msg = JSON.parse(data.toString());
|
|
2866
|
+
} catch {
|
|
2867
|
+
return;
|
|
2868
|
+
}
|
|
2869
|
+
if (typeof msg.id !== "number") return;
|
|
2870
|
+
const cb = this.pending.get(msg.id);
|
|
2871
|
+
if (!cb) return;
|
|
2872
|
+
this.pending.delete(msg.id);
|
|
2873
|
+
if (msg.error) {
|
|
2874
|
+
cb.reject(new Error(msg.error.message ?? "CDP error"));
|
|
2875
|
+
} else {
|
|
2876
|
+
cb.resolve(msg.result ?? {});
|
|
2877
|
+
}
|
|
2878
|
+
});
|
|
2879
|
+
ws.on("close", () => {
|
|
2880
|
+
for (const cb of this.pending.values()) {
|
|
2881
|
+
cb.reject(new Error("CDP WebSocket closed"));
|
|
2882
|
+
}
|
|
2883
|
+
this.pending.clear();
|
|
2884
|
+
});
|
|
2885
|
+
ws.on("error", (err) => {
|
|
2886
|
+
for (const cb of this.pending.values()) {
|
|
2887
|
+
cb.reject(err);
|
|
2888
|
+
}
|
|
2889
|
+
this.pending.clear();
|
|
2890
|
+
});
|
|
2891
|
+
}
|
|
2892
|
+
nextId = 0;
|
|
2893
|
+
pending = /* @__PURE__ */ new Map();
|
|
2894
|
+
send(method, params = {}, sessionId) {
|
|
2895
|
+
const id = ++this.nextId;
|
|
2896
|
+
const payload = { id, method, params };
|
|
2897
|
+
if (sessionId) payload.sessionId = sessionId;
|
|
2898
|
+
return new Promise((resolve2, reject) => {
|
|
2899
|
+
this.pending.set(id, {
|
|
2900
|
+
resolve: (r) => resolve2(r),
|
|
2901
|
+
reject
|
|
2902
|
+
});
|
|
2903
|
+
this.ws.send(JSON.stringify(payload));
|
|
2904
|
+
});
|
|
2905
|
+
}
|
|
2906
|
+
close() {
|
|
2732
2907
|
try {
|
|
2733
|
-
|
|
2908
|
+
this.ws.close();
|
|
2734
2909
|
} catch {
|
|
2735
2910
|
}
|
|
2736
|
-
activeSessions.delete(name);
|
|
2737
2911
|
}
|
|
2738
|
-
|
|
2912
|
+
};
|
|
2913
|
+
function waitForDevToolsUrl(child, timeoutMs = 5e3) {
|
|
2914
|
+
return new Promise((resolve2, reject) => {
|
|
2915
|
+
let buf = "";
|
|
2916
|
+
const onData = (d) => {
|
|
2917
|
+
buf += d.toString();
|
|
2918
|
+
const m = buf.match(/DevTools listening on (ws:\/\/\S+)/);
|
|
2919
|
+
if (m) {
|
|
2920
|
+
cleanup();
|
|
2921
|
+
resolve2(m[1]);
|
|
2922
|
+
}
|
|
2923
|
+
};
|
|
2924
|
+
const onExit = (code) => {
|
|
2925
|
+
cleanup();
|
|
2926
|
+
reject(
|
|
2927
|
+
new Error(
|
|
2928
|
+
`Chrome exited (code ${code}) before exposing a DevTools port. Last stderr: ${buf.slice(-500)}`
|
|
2929
|
+
)
|
|
2930
|
+
);
|
|
2931
|
+
};
|
|
2932
|
+
const cleanup = () => {
|
|
2933
|
+
child.stderr?.off("data", onData);
|
|
2934
|
+
child.off("exit", onExit);
|
|
2935
|
+
clearTimeout(timer);
|
|
2936
|
+
};
|
|
2937
|
+
const timer = setTimeout(() => {
|
|
2938
|
+
cleanup();
|
|
2939
|
+
reject(
|
|
2940
|
+
new Error(`Chrome did not expose a DevTools port within ${timeoutMs}ms`)
|
|
2941
|
+
);
|
|
2942
|
+
}, timeoutMs);
|
|
2943
|
+
child.stderr?.on("data", onData);
|
|
2944
|
+
child.on("exit", onExit);
|
|
2945
|
+
});
|
|
2739
2946
|
}
|
|
2740
|
-
async function
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2947
|
+
async function captureScreenshot(opts) {
|
|
2948
|
+
const userDataDir = mkdtempSync(path4.join(os4.tmpdir(), "mcp-use-chrome-"));
|
|
2949
|
+
const chromeArgs = [
|
|
2950
|
+
"--headless=new",
|
|
2951
|
+
"--remote-debugging-port=0",
|
|
2952
|
+
`--user-data-dir=${userDataDir}`,
|
|
2953
|
+
"--no-first-run",
|
|
2954
|
+
"--no-default-browser-check",
|
|
2955
|
+
"--disable-extensions",
|
|
2956
|
+
"--disable-gpu",
|
|
2957
|
+
"--hide-scrollbars",
|
|
2958
|
+
"--mute-audio",
|
|
2959
|
+
`--window-size=${opts.width},${opts.height}`,
|
|
2960
|
+
"about:blank"
|
|
2961
|
+
];
|
|
2962
|
+
const child = spawn(opts.chromePath, chromeArgs, {
|
|
2963
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
2964
|
+
});
|
|
2965
|
+
child.stdout?.resume();
|
|
2966
|
+
let cdp;
|
|
2967
|
+
let cleanedUp = false;
|
|
2968
|
+
const cleanup = () => {
|
|
2969
|
+
if (cleanedUp) return;
|
|
2970
|
+
cleanedUp = true;
|
|
2971
|
+
cdp?.close();
|
|
2972
|
+
if (!child.killed) {
|
|
2973
|
+
try {
|
|
2974
|
+
child.kill("SIGTERM");
|
|
2975
|
+
} catch {
|
|
2976
|
+
}
|
|
2977
|
+
const killTimer = setTimeout(() => {
|
|
2978
|
+
if (!child.killed) {
|
|
2979
|
+
try {
|
|
2980
|
+
child.kill("SIGKILL");
|
|
2981
|
+
} catch {
|
|
2982
|
+
}
|
|
2983
|
+
}
|
|
2984
|
+
}, 2e3);
|
|
2985
|
+
killTimer.unref();
|
|
2986
|
+
}
|
|
2987
|
+
try {
|
|
2988
|
+
rmSync(userDataDir, { recursive: true, force: true });
|
|
2989
|
+
} catch {
|
|
2990
|
+
}
|
|
2991
|
+
};
|
|
2992
|
+
try {
|
|
2993
|
+
const wsUrl = await waitForDevToolsUrl(child);
|
|
2994
|
+
const ws = new WebSocket(wsUrl);
|
|
2995
|
+
await new Promise((resolve2, reject) => {
|
|
2996
|
+
const onOpen = () => {
|
|
2997
|
+
ws.off("error", onError);
|
|
2998
|
+
resolve2();
|
|
2999
|
+
};
|
|
3000
|
+
const onError = (err) => {
|
|
3001
|
+
ws.off("open", onOpen);
|
|
3002
|
+
reject(err);
|
|
3003
|
+
};
|
|
3004
|
+
ws.once("open", onOpen);
|
|
3005
|
+
ws.once("error", onError);
|
|
3006
|
+
});
|
|
3007
|
+
cdp = new CdpClient(ws);
|
|
3008
|
+
const { targetId } = await cdp.send(
|
|
3009
|
+
"Target.createTarget",
|
|
3010
|
+
{ url: "about:blank" }
|
|
3011
|
+
);
|
|
3012
|
+
const { sessionId } = await cdp.send(
|
|
3013
|
+
"Target.attachToTarget",
|
|
3014
|
+
{ targetId, flatten: true }
|
|
3015
|
+
);
|
|
3016
|
+
await cdp.send("Page.enable", {}, sessionId);
|
|
3017
|
+
await cdp.send(
|
|
3018
|
+
"Emulation.setDeviceMetricsOverride",
|
|
3019
|
+
{
|
|
3020
|
+
width: opts.width,
|
|
3021
|
+
height: opts.height,
|
|
3022
|
+
deviceScaleFactor: 1,
|
|
3023
|
+
mobile: false
|
|
3024
|
+
},
|
|
3025
|
+
sessionId
|
|
3026
|
+
);
|
|
3027
|
+
await cdp.send(
|
|
3028
|
+
"Emulation.setEmulatedMedia",
|
|
3029
|
+
{
|
|
3030
|
+
features: [
|
|
3031
|
+
{ name: "prefers-color-scheme", value: opts.theme },
|
|
3032
|
+
{ name: "prefers-reduced-motion", value: "reduce" }
|
|
3033
|
+
]
|
|
3034
|
+
},
|
|
3035
|
+
sessionId
|
|
3036
|
+
);
|
|
3037
|
+
if (opts.bundle !== void 0) {
|
|
3038
|
+
const payload = JSON.stringify(JSON.stringify(opts.bundle));
|
|
3039
|
+
await cdp.send(
|
|
3040
|
+
"Page.addScriptToEvaluateOnNewDocument",
|
|
3041
|
+
{
|
|
3042
|
+
source: `globalThis.__mcpUsePreviewBundle = JSON.parse(${payload});`,
|
|
3043
|
+
runImmediately: true
|
|
3044
|
+
},
|
|
3045
|
+
sessionId
|
|
2746
3046
|
);
|
|
2747
|
-
|
|
2748
|
-
|
|
3047
|
+
}
|
|
3048
|
+
await cdp.send("Page.navigate", { url: opts.url }, sessionId);
|
|
3049
|
+
const start = Date.now();
|
|
3050
|
+
const exprSelector = JSON.stringify(opts.waitForSelector);
|
|
3051
|
+
while (true) {
|
|
3052
|
+
const r = await cdp.send(
|
|
3053
|
+
"Runtime.evaluate",
|
|
3054
|
+
{
|
|
3055
|
+
expression: `!!document.querySelector(${exprSelector})`,
|
|
3056
|
+
returnByValue: true
|
|
3057
|
+
},
|
|
3058
|
+
sessionId
|
|
2749
3059
|
);
|
|
2750
|
-
|
|
3060
|
+
if (r.result?.value === true) break;
|
|
3061
|
+
if (Date.now() - start > opts.timeoutMs) {
|
|
3062
|
+
throw new Error(
|
|
3063
|
+
`Timed out after ${opts.timeoutMs}ms waiting for selector "${opts.waitForSelector}"`
|
|
3064
|
+
);
|
|
3065
|
+
}
|
|
3066
|
+
await new Promise((res) => setTimeout(res, 100));
|
|
2751
3067
|
}
|
|
2752
|
-
|
|
3068
|
+
if (opts.delayMs && opts.delayMs > 0) {
|
|
3069
|
+
await new Promise((res) => setTimeout(res, opts.delayMs));
|
|
3070
|
+
}
|
|
3071
|
+
const shot = await cdp.send(
|
|
3072
|
+
"Page.captureScreenshot",
|
|
3073
|
+
{
|
|
3074
|
+
format: "png",
|
|
3075
|
+
clip: {
|
|
3076
|
+
x: 0,
|
|
3077
|
+
y: 0,
|
|
3078
|
+
width: opts.width,
|
|
3079
|
+
height: opts.height,
|
|
3080
|
+
scale: 1
|
|
3081
|
+
}
|
|
3082
|
+
},
|
|
3083
|
+
sessionId
|
|
3084
|
+
);
|
|
3085
|
+
writeFileSync(opts.outputPath, Buffer.from(shot.data, "base64"));
|
|
3086
|
+
} finally {
|
|
3087
|
+
cleanup();
|
|
2753
3088
|
}
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
3089
|
+
}
|
|
3090
|
+
|
|
3091
|
+
// src/utils/chrome-path.ts
|
|
3092
|
+
init_esm_shims();
|
|
3093
|
+
import { accessSync, constants } from "fs";
|
|
3094
|
+
import path5 from "path";
|
|
3095
|
+
var ENV_VAR_NAMES = [
|
|
3096
|
+
"MCP_USE_CHROME_PATH",
|
|
3097
|
+
"PUPPETEER_EXECUTABLE_PATH",
|
|
3098
|
+
"CHROME_PATH"
|
|
3099
|
+
];
|
|
3100
|
+
var DARWIN_PATHS = [
|
|
3101
|
+
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
3102
|
+
"/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary",
|
|
3103
|
+
"/Applications/Chromium.app/Contents/MacOS/Chromium",
|
|
3104
|
+
"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
|
|
3105
|
+
"/Applications/Brave Browser.app/Contents/MacOS/Brave Browser"
|
|
3106
|
+
];
|
|
3107
|
+
var LINUX_BINARIES = [
|
|
3108
|
+
"google-chrome-stable",
|
|
3109
|
+
"google-chrome",
|
|
3110
|
+
"chromium",
|
|
3111
|
+
"chromium-browser",
|
|
3112
|
+
"microsoft-edge",
|
|
3113
|
+
"microsoft-edge-stable",
|
|
3114
|
+
"brave-browser"
|
|
3115
|
+
];
|
|
3116
|
+
var WIN_SUBPATHS = [
|
|
3117
|
+
"Google\\Chrome\\Application\\chrome.exe",
|
|
3118
|
+
"Microsoft\\Edge\\Application\\msedge.exe",
|
|
3119
|
+
"BraveSoftware\\Brave-Browser\\Application\\brave.exe",
|
|
3120
|
+
"Chromium\\Application\\chrome.exe"
|
|
3121
|
+
];
|
|
3122
|
+
function isAccessible(p) {
|
|
3123
|
+
try {
|
|
3124
|
+
accessSync(p, constants.F_OK);
|
|
3125
|
+
return true;
|
|
3126
|
+
} catch {
|
|
3127
|
+
return false;
|
|
2757
3128
|
}
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
3129
|
+
}
|
|
3130
|
+
function findOnPath(binary) {
|
|
3131
|
+
const PATH = process.env.PATH ?? "";
|
|
3132
|
+
for (const dir of PATH.split(":")) {
|
|
3133
|
+
if (!dir) continue;
|
|
3134
|
+
const candidate = path5.posix.join(dir, binary);
|
|
3135
|
+
if (isAccessible(candidate)) return candidate;
|
|
3136
|
+
}
|
|
3137
|
+
return null;
|
|
3138
|
+
}
|
|
3139
|
+
function findChrome() {
|
|
3140
|
+
for (const name of ENV_VAR_NAMES) {
|
|
3141
|
+
const v = process.env[name];
|
|
3142
|
+
if (v && isAccessible(v)) return v;
|
|
3143
|
+
}
|
|
3144
|
+
if (process.platform === "darwin") {
|
|
3145
|
+
for (const p of DARWIN_PATHS) {
|
|
3146
|
+
if (isAccessible(p)) return p;
|
|
3147
|
+
}
|
|
3148
|
+
return null;
|
|
3149
|
+
}
|
|
3150
|
+
if (process.platform === "linux") {
|
|
3151
|
+
for (const bin of LINUX_BINARIES) {
|
|
3152
|
+
const p = findOnPath(bin);
|
|
3153
|
+
if (p) return p;
|
|
3154
|
+
}
|
|
3155
|
+
return null;
|
|
3156
|
+
}
|
|
3157
|
+
if (process.platform === "win32") {
|
|
3158
|
+
const dirs = [
|
|
3159
|
+
process.env["ProgramFiles"],
|
|
3160
|
+
process.env["ProgramFiles(x86)"],
|
|
3161
|
+
process.env["LocalAppData"]
|
|
3162
|
+
].filter((d) => Boolean(d));
|
|
3163
|
+
for (const dir of dirs) {
|
|
3164
|
+
for (const sub of WIN_SUBPATHS) {
|
|
3165
|
+
const candidate = path5.join(dir, sub);
|
|
3166
|
+
if (isAccessible(candidate)) return candidate;
|
|
3167
|
+
}
|
|
3168
|
+
}
|
|
2761
3169
|
return null;
|
|
2762
3170
|
}
|
|
3171
|
+
return null;
|
|
3172
|
+
}
|
|
3173
|
+
function resolveChromePath() {
|
|
3174
|
+
const found = findChrome();
|
|
3175
|
+
if (found) return found;
|
|
3176
|
+
throw new Error(
|
|
3177
|
+
"Could not find Chrome, Chromium, Edge, or Brave on this system. Install Chrome from https://google.com/chrome, or set MCP_USE_CHROME_PATH (or PUPPETEER_EXECUTABLE_PATH / CHROME_PATH) to a browser executable."
|
|
3178
|
+
);
|
|
3179
|
+
}
|
|
3180
|
+
|
|
3181
|
+
// src/commands/screenshot.ts
|
|
3182
|
+
function detectToolResourceUri(tool) {
|
|
3183
|
+
if (!tool) return null;
|
|
3184
|
+
const meta = tool._meta;
|
|
3185
|
+
if (!meta) return null;
|
|
3186
|
+
const uiMeta = meta.ui ?? void 0;
|
|
3187
|
+
return uiMeta?.resourceUri ?? meta["openai/outputTemplate"] ?? null;
|
|
3188
|
+
}
|
|
3189
|
+
async function captureToolScreenshot(inputs, options = {}) {
|
|
3190
|
+
const width = options.width ?? 800;
|
|
3191
|
+
const height = options.height ?? 600;
|
|
3192
|
+
const theme = options.theme ?? "light";
|
|
3193
|
+
const timeoutMs = options.timeoutMs ?? 3e4;
|
|
3194
|
+
const delayMs = options.delayMs ?? 0;
|
|
3195
|
+
const chromePath = resolveChromePath();
|
|
3196
|
+
const view = extractViewName(inputs.resourceUri);
|
|
3197
|
+
const devOptions = {
|
|
3198
|
+
width: String(width),
|
|
3199
|
+
height: String(height),
|
|
3200
|
+
theme,
|
|
3201
|
+
timeout: String(timeoutMs),
|
|
3202
|
+
inspector: options.inspector,
|
|
3203
|
+
quiet: options.quiet
|
|
3204
|
+
};
|
|
3205
|
+
let devHandle;
|
|
2763
3206
|
try {
|
|
2764
|
-
|
|
2765
|
-
const
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
3207
|
+
devHandle = await ensureDevServer(devOptions);
|
|
3208
|
+
const resourceContents = await inputs.session.readResource(
|
|
3209
|
+
inputs.resourceUri
|
|
3210
|
+
);
|
|
3211
|
+
const bundle = {
|
|
3212
|
+
resourceUri: inputs.resourceUri,
|
|
3213
|
+
resourceContents,
|
|
3214
|
+
toolInput: inputs.toolArgs,
|
|
3215
|
+
toolOutput: inputs.toolOutput
|
|
3216
|
+
};
|
|
3217
|
+
const previewUrl = new URL(`/inspector/preview/${view}`, devHandle.url);
|
|
3218
|
+
previewUrl.searchParams.set("theme", theme);
|
|
3219
|
+
const ts = timestampSuffix();
|
|
3220
|
+
const outputPath = path6.resolve(options.output ?? `./${view}-${ts}.png`);
|
|
3221
|
+
await mkdir2(path6.dirname(outputPath), { recursive: true });
|
|
3222
|
+
await captureScreenshot({
|
|
3223
|
+
url: previewUrl.toString(),
|
|
3224
|
+
width,
|
|
3225
|
+
height,
|
|
3226
|
+
theme,
|
|
3227
|
+
waitForSelector: options.waitFor ?? 'body[data-view-ready="true"]',
|
|
3228
|
+
timeoutMs,
|
|
3229
|
+
outputPath,
|
|
3230
|
+
chromePath,
|
|
3231
|
+
delayMs: Number.isFinite(delayMs) && delayMs > 0 ? delayMs : 0,
|
|
3232
|
+
bundle
|
|
3233
|
+
});
|
|
3234
|
+
return { outputPath, width, height, view };
|
|
3235
|
+
} finally {
|
|
3236
|
+
killChild(devHandle?.child);
|
|
3237
|
+
}
|
|
3238
|
+
}
|
|
3239
|
+
function getFreePort() {
|
|
3240
|
+
return new Promise((resolve2, reject) => {
|
|
3241
|
+
const srv = createServer();
|
|
3242
|
+
srv.unref();
|
|
3243
|
+
srv.on("error", reject);
|
|
3244
|
+
srv.listen(0, () => {
|
|
3245
|
+
const addr = srv.address();
|
|
3246
|
+
if (typeof addr === "object" && addr) {
|
|
3247
|
+
const port = addr.port;
|
|
3248
|
+
srv.close(() => resolve2(port));
|
|
2775
3249
|
} else {
|
|
2776
|
-
|
|
2777
|
-
url: config.url,
|
|
2778
|
-
headers: config.authToken ? { Authorization: `Bearer ${config.authToken}` } : void 0,
|
|
2779
|
-
clientInfo: cliClientInfo
|
|
2780
|
-
});
|
|
3250
|
+
srv.close(() => reject(new Error("Failed to allocate free port")));
|
|
2781
3251
|
}
|
|
2782
|
-
}
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
3252
|
+
});
|
|
3253
|
+
});
|
|
3254
|
+
}
|
|
3255
|
+
async function probeServer(url, timeoutMs = 1500) {
|
|
3256
|
+
const controller = new AbortController();
|
|
3257
|
+
const t = setTimeout(() => controller.abort(), timeoutMs);
|
|
3258
|
+
try {
|
|
3259
|
+
const u = new URL("/inspector/health", url);
|
|
3260
|
+
const res = await fetch(u, { signal: controller.signal });
|
|
3261
|
+
if (!res.ok) return false;
|
|
3262
|
+
const ct = res.headers.get("content-type") ?? "";
|
|
3263
|
+
if (!ct.includes("application/json")) return false;
|
|
3264
|
+
const body = await res.json();
|
|
3265
|
+
return body?.status === "ok";
|
|
3266
|
+
} catch {
|
|
3267
|
+
return false;
|
|
3268
|
+
} finally {
|
|
3269
|
+
clearTimeout(t);
|
|
3270
|
+
}
|
|
3271
|
+
}
|
|
3272
|
+
async function waitForHealth(url, timeoutMs = 15e3) {
|
|
3273
|
+
const deadline = Date.now() + timeoutMs;
|
|
3274
|
+
while (Date.now() < deadline) {
|
|
3275
|
+
if (await probeServer(url)) return true;
|
|
3276
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
3277
|
+
}
|
|
3278
|
+
return false;
|
|
3279
|
+
}
|
|
3280
|
+
function resolveInspectorCli() {
|
|
3281
|
+
const candidateRoots = /* @__PURE__ */ new Set();
|
|
3282
|
+
const moduleDir = typeof __dirname !== "undefined" ? __dirname : path6.dirname(new URL(import.meta.url).pathname);
|
|
3283
|
+
candidateRoots.add(moduleDir);
|
|
3284
|
+
candidateRoots.add(process.cwd());
|
|
3285
|
+
for (const start of candidateRoots) {
|
|
3286
|
+
let dir = start;
|
|
3287
|
+
while (true) {
|
|
3288
|
+
const candidate = path6.join(
|
|
3289
|
+
dir,
|
|
3290
|
+
"node_modules",
|
|
3291
|
+
"@mcp-use",
|
|
3292
|
+
"inspector",
|
|
3293
|
+
"dist",
|
|
3294
|
+
"cli.js"
|
|
3295
|
+
);
|
|
3296
|
+
if (existsSync2(candidate)) return candidate;
|
|
3297
|
+
const parent = path6.dirname(dir);
|
|
3298
|
+
if (parent === dir) break;
|
|
3299
|
+
dir = parent;
|
|
3300
|
+
}
|
|
3301
|
+
}
|
|
3302
|
+
throw new Error(
|
|
3303
|
+
"Could not locate `@mcp-use/inspector` in node_modules. Install the inspector package or pass --inspector <url> to use an existing instance."
|
|
3304
|
+
);
|
|
3305
|
+
}
|
|
3306
|
+
async function ensureDevServer(options) {
|
|
3307
|
+
if (options.inspector) {
|
|
3308
|
+
const ok = await probeServer(options.inspector);
|
|
3309
|
+
if (!ok) {
|
|
3310
|
+
throw new Error(
|
|
3311
|
+
`Inspector at ${options.inspector} did not respond on /inspector/health with status:"ok"`
|
|
3312
|
+
);
|
|
3313
|
+
}
|
|
3314
|
+
return { url: options.inspector };
|
|
3315
|
+
}
|
|
3316
|
+
const port = await getFreePort();
|
|
3317
|
+
const url = `http://localhost:${port}`;
|
|
3318
|
+
if (!options.quiet) {
|
|
3319
|
+
console.error(formatInfo(`Starting inspector on port ${port}\u2026`));
|
|
3320
|
+
}
|
|
3321
|
+
const inspectorCli = resolveInspectorCli();
|
|
3322
|
+
const child = spawn2(
|
|
3323
|
+
process.execPath,
|
|
3324
|
+
[inspectorCli, "--port", String(port), "--no-open"],
|
|
3325
|
+
{
|
|
3326
|
+
cwd: process.cwd(),
|
|
3327
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
3328
|
+
env: { ...process.env, MCP_INSPECTOR_MODE: "standalone" }
|
|
3329
|
+
}
|
|
3330
|
+
);
|
|
3331
|
+
const prefix = source_default.gray("[inspector]");
|
|
3332
|
+
if (!options.quiet) {
|
|
3333
|
+
child.stdout?.on("data", (d) => {
|
|
3334
|
+
process.stderr.write(`${prefix} ${d}`);
|
|
3335
|
+
});
|
|
3336
|
+
child.stderr?.on("data", (d) => {
|
|
3337
|
+
process.stderr.write(`${prefix} ${d}`);
|
|
3338
|
+
});
|
|
3339
|
+
} else {
|
|
3340
|
+
child.stdout?.resume();
|
|
3341
|
+
child.stderr?.resume();
|
|
3342
|
+
}
|
|
3343
|
+
const ready = await waitForHealth(url);
|
|
3344
|
+
if (!ready) {
|
|
3345
|
+
child.kill("SIGTERM");
|
|
3346
|
+
throw new Error(`Inspector failed to come up on ${url} within 15s.`);
|
|
3347
|
+
}
|
|
3348
|
+
return { url, child };
|
|
3349
|
+
}
|
|
3350
|
+
function killChild(child) {
|
|
3351
|
+
if (!child || child.killed) return;
|
|
3352
|
+
try {
|
|
3353
|
+
child.kill("SIGTERM");
|
|
3354
|
+
} catch {
|
|
3355
|
+
}
|
|
3356
|
+
}
|
|
3357
|
+
function timestampSuffix(date = /* @__PURE__ */ new Date()) {
|
|
3358
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
3359
|
+
const datePart = `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
|
|
3360
|
+
const timePart = `${pad(date.getHours())}-${pad(date.getMinutes())}-${pad(date.getSeconds())}`;
|
|
3361
|
+
return `${datePart}_${timePart}`;
|
|
3362
|
+
}
|
|
3363
|
+
function extractViewName(resourceUri) {
|
|
3364
|
+
const m = resourceUri.match(/^ui:\/\/widget\/(.+)$/);
|
|
3365
|
+
if (!m) return resourceUri;
|
|
3366
|
+
return m[1].replace(/\.html$/, "").replace(/\.[0-9a-f]+$/i, "");
|
|
3367
|
+
}
|
|
3368
|
+
function parseDimension(raw, name) {
|
|
3369
|
+
const n = parseInt(raw, 10);
|
|
3370
|
+
if (!Number.isFinite(n) || n <= 0) {
|
|
3371
|
+
throw new Error(`--${name} must be a positive integer (got "${raw}")`);
|
|
3372
|
+
}
|
|
3373
|
+
return n;
|
|
3374
|
+
}
|
|
3375
|
+
var AD_HOC_SESSION_NAME = "__screenshot_ad_hoc__";
|
|
3376
|
+
async function resolveSessionForScreenshot(options) {
|
|
3377
|
+
if (options.session) {
|
|
3378
|
+
const result2 = await getOrRestoreSession(options.session);
|
|
3379
|
+
return result2?.session ?? null;
|
|
3380
|
+
}
|
|
3381
|
+
if (options.mcp) {
|
|
3382
|
+
const client = new MCPClient2();
|
|
3383
|
+
client.addServer(AD_HOC_SESSION_NAME, {
|
|
3384
|
+
url: options.mcp,
|
|
3385
|
+
clientInfo: getCliClientInfo()
|
|
3386
|
+
});
|
|
3387
|
+
try {
|
|
3388
|
+
const session = await client.createSession(AD_HOC_SESSION_NAME);
|
|
3389
|
+
activeSessions.set(AD_HOC_SESSION_NAME, { client, session });
|
|
3390
|
+
return session;
|
|
3391
|
+
} catch (err) {
|
|
3392
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
3393
|
+
console.error(formatError(`Failed to connect to ${options.mcp}: ${msg}`));
|
|
2791
3394
|
return null;
|
|
2792
3395
|
}
|
|
2793
|
-
|
|
3396
|
+
}
|
|
3397
|
+
const result = await getOrRestoreSession(null);
|
|
3398
|
+
return result?.session ?? null;
|
|
3399
|
+
}
|
|
3400
|
+
async function screenshotCommand(options, argsList) {
|
|
3401
|
+
let exitCode = 0;
|
|
3402
|
+
try {
|
|
3403
|
+
if (!options.tool) {
|
|
3404
|
+
console.error(
|
|
3405
|
+
formatError(
|
|
3406
|
+
"--tool <name> is required (optionally with key=value args)."
|
|
3407
|
+
)
|
|
3408
|
+
);
|
|
3409
|
+
exitCode = 1;
|
|
3410
|
+
return;
|
|
3411
|
+
}
|
|
2794
3412
|
try {
|
|
2795
|
-
|
|
3413
|
+
resolveChromePath();
|
|
2796
3414
|
} catch (err) {
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
3415
|
+
console.error(
|
|
3416
|
+
formatError(err instanceof Error ? err.message : String(err))
|
|
3417
|
+
);
|
|
3418
|
+
exitCode = 1;
|
|
3419
|
+
return;
|
|
3420
|
+
}
|
|
3421
|
+
const width = parseDimension(options.width, "width");
|
|
3422
|
+
const height = parseDimension(options.height, "height");
|
|
3423
|
+
const navTimeout = parseInt(options.timeout, 10) || 3e4;
|
|
3424
|
+
const delayMs = options.delay ? parseInt(options.delay, 10) : 0;
|
|
3425
|
+
const session = await resolveSessionForScreenshot(options);
|
|
3426
|
+
if (!session) {
|
|
3427
|
+
exitCode = 1;
|
|
3428
|
+
return;
|
|
3429
|
+
}
|
|
3430
|
+
const tool = session.tools.find((t) => t.name === options.tool);
|
|
3431
|
+
if (!tool) {
|
|
3432
|
+
throw new Error(
|
|
3433
|
+
`Tool "${options.tool}" not found. Available: ${session.tools.map((t) => t.name).join(", ")}`
|
|
3434
|
+
);
|
|
3435
|
+
}
|
|
3436
|
+
const resourceUri = detectToolResourceUri(tool);
|
|
3437
|
+
if (!resourceUri) {
|
|
3438
|
+
throw new Error(
|
|
3439
|
+
`Tool "${options.tool}" does not declare a UI resource (expected _meta.ui.resourceUri or openai/outputTemplate).`
|
|
3440
|
+
);
|
|
3441
|
+
}
|
|
3442
|
+
let toolArgs = {};
|
|
3443
|
+
if (argsList && argsList.length > 0) {
|
|
3444
|
+
try {
|
|
3445
|
+
toolArgs = parseToolArgs(
|
|
3446
|
+
argsList,
|
|
3447
|
+
tool.inputSchema
|
|
2801
3448
|
);
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
3449
|
+
} catch (err) {
|
|
3450
|
+
console.error(
|
|
3451
|
+
formatError(err instanceof Error ? err.message : String(err))
|
|
3452
|
+
);
|
|
3453
|
+
console.log("");
|
|
3454
|
+
console.log(formatInfo("Usage:"));
|
|
3455
|
+
console.log(
|
|
3456
|
+
` npx mcp-use screenshot --tool ${options.tool} key=value [key2=value2 ...]`
|
|
3457
|
+
);
|
|
3458
|
+
console.log(
|
|
3459
|
+
` npx mcp-use screenshot --tool ${options.tool} nested:='{"a":1}' # JSON value`
|
|
3460
|
+
);
|
|
3461
|
+
console.log(
|
|
3462
|
+
` npx mcp-use screenshot --tool ${options.tool} '{"key":"value"}' # full JSON object`
|
|
3463
|
+
);
|
|
3464
|
+
if (tool.inputSchema) {
|
|
3465
|
+
console.log("");
|
|
3466
|
+
console.log(formatInfo("Tool schema:"));
|
|
3467
|
+
console.log(formatSchema(tool.inputSchema));
|
|
2810
3468
|
}
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
} else {
|
|
2814
|
-
throw err;
|
|
3469
|
+
exitCode = 1;
|
|
3470
|
+
return;
|
|
2815
3471
|
}
|
|
2816
3472
|
}
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
return { name: sessionName, session };
|
|
2820
|
-
} catch (error) {
|
|
2821
|
-
console.error(formatError(`Failed to restore session: ${error.message}`));
|
|
2822
|
-
return null;
|
|
2823
|
-
}
|
|
2824
|
-
}
|
|
2825
|
-
function getCliClientInfo() {
|
|
2826
|
-
return {
|
|
2827
|
-
name: "mcp-use CLI",
|
|
2828
|
-
title: "mcp-use CLI",
|
|
2829
|
-
version: getPackageVersion(),
|
|
2830
|
-
description: "mcp-use CLI - Command-line interface for MCP servers",
|
|
2831
|
-
icons: [
|
|
3473
|
+
const toolOutput = await session.callTool(options.tool, toolArgs);
|
|
3474
|
+
const result = await captureToolScreenshot(
|
|
2832
3475
|
{
|
|
2833
|
-
|
|
3476
|
+
session,
|
|
3477
|
+
toolName: options.tool,
|
|
3478
|
+
toolArgs,
|
|
3479
|
+
toolOutput,
|
|
3480
|
+
resourceUri
|
|
3481
|
+
},
|
|
3482
|
+
{
|
|
3483
|
+
width,
|
|
3484
|
+
height,
|
|
3485
|
+
theme: options.theme,
|
|
3486
|
+
output: options.output,
|
|
3487
|
+
waitFor: options.waitFor,
|
|
3488
|
+
delayMs,
|
|
3489
|
+
timeoutMs: navTimeout,
|
|
3490
|
+
inspector: options.inspector,
|
|
3491
|
+
quiet: options.quiet
|
|
2834
3492
|
}
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
3493
|
+
);
|
|
3494
|
+
console.log(
|
|
3495
|
+
`Saved screenshot: ${result.outputPath} (${result.width}\xD7${result.height})`
|
|
3496
|
+
);
|
|
3497
|
+
} catch (err) {
|
|
3498
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
3499
|
+
console.error(formatError(`Screenshot failed: ${msg}`));
|
|
3500
|
+
exitCode = 1;
|
|
3501
|
+
} finally {
|
|
3502
|
+
await cleanupAndExit(exitCode);
|
|
3503
|
+
}
|
|
2838
3504
|
}
|
|
3505
|
+
function createScreenshotCommand() {
|
|
3506
|
+
return new Command("screenshot").description(
|
|
3507
|
+
"Render an MCP Apps view headlessly and save a PNG by calling a tool and rendering its UI resource with the result."
|
|
3508
|
+
).argument(
|
|
3509
|
+
"[args...]",
|
|
3510
|
+
"Tool args as key=value pairs (use key:=<json> for nested values, or pass a single JSON object)."
|
|
3511
|
+
).option(
|
|
3512
|
+
"--tool <name>",
|
|
3513
|
+
"Tool to call. Its UI resource is rendered with the result."
|
|
3514
|
+
).option("--width <px>", "Browser viewport width in pixels.", "800").option("--height <px>", "Browser viewport height in pixels.", "600").option(
|
|
3515
|
+
"--inspector <url>",
|
|
3516
|
+
"Inspector host that serves /inspector/preview/:view. When omitted, probes localhost:3000 then auto-spawns `mcp-use dev`."
|
|
3517
|
+
).option(
|
|
3518
|
+
"--session <name>",
|
|
3519
|
+
"Saved session name (from `mcp-use client connect`). Defaults to the active session."
|
|
3520
|
+
).option(
|
|
3521
|
+
"--mcp <url>",
|
|
3522
|
+
"Ad-hoc MCP server URL (escape hatch). Used only when no --session and no active saved session. No authentication."
|
|
3523
|
+
).option(
|
|
3524
|
+
"--theme <light|dark>",
|
|
3525
|
+
"Color scheme to render the view in.",
|
|
3526
|
+
"light"
|
|
3527
|
+
).option(
|
|
3528
|
+
"--output <path>",
|
|
3529
|
+
"Output PNG path. Defaults to ./<view>-<timestamp>.png in cwd."
|
|
3530
|
+
).option(
|
|
3531
|
+
"--wait-for <selector>",
|
|
3532
|
+
'Override readiness selector (default: body[data-view-ready="true"]).'
|
|
3533
|
+
).option(
|
|
3534
|
+
"--delay <ms>",
|
|
3535
|
+
"Extra wait after readiness, to let chart animations / async layouts settle.",
|
|
3536
|
+
"0"
|
|
3537
|
+
).option("--timeout <ms>", "Navigation + readiness timeout in ms.", "30000").option("--quiet", "Suppress dev-server output.").action(async (args, opts) => {
|
|
3538
|
+
await screenshotCommand(opts, args);
|
|
3539
|
+
});
|
|
3540
|
+
}
|
|
3541
|
+
|
|
3542
|
+
// src/commands/client.ts
|
|
2839
3543
|
async function connectCommand(urlOrCommand, options) {
|
|
2840
3544
|
try {
|
|
2841
3545
|
const sessionName = options.name || `session-${Date.now()}`;
|
|
2842
|
-
const client = new
|
|
3546
|
+
const client = new MCPClient3();
|
|
2843
3547
|
let session;
|
|
2844
3548
|
const cliClientInfo = getCliClientInfo();
|
|
2845
3549
|
if (options.stdio) {
|
|
@@ -3156,11 +3860,54 @@ async function callToolCommand(toolName, argsList, options) {
|
|
|
3156
3860
|
const callResult = await session.callTool(toolName, args, {
|
|
3157
3861
|
timeout: options?.timeout
|
|
3158
3862
|
});
|
|
3863
|
+
let screenshot = null;
|
|
3864
|
+
let screenshotError = null;
|
|
3865
|
+
if (options?.screenshot !== false) {
|
|
3866
|
+
const tool2 = session.tools.find((t) => t.name === toolName);
|
|
3867
|
+
const resourceUri = detectToolResourceUri(tool2);
|
|
3868
|
+
if (resourceUri) {
|
|
3869
|
+
console.error(
|
|
3870
|
+
formatInfo(`Capturing widget screenshot (${resourceUri})...`)
|
|
3871
|
+
);
|
|
3872
|
+
try {
|
|
3873
|
+
const shot = await captureToolScreenshot(
|
|
3874
|
+
{
|
|
3875
|
+
session,
|
|
3876
|
+
toolName,
|
|
3877
|
+
toolArgs: args,
|
|
3878
|
+
toolOutput: callResult,
|
|
3879
|
+
resourceUri
|
|
3880
|
+
},
|
|
3881
|
+
options?.screenshotOutput ? { output: options.screenshotOutput } : {}
|
|
3882
|
+
);
|
|
3883
|
+
screenshot = {
|
|
3884
|
+
path: shot.outputPath,
|
|
3885
|
+
width: shot.width,
|
|
3886
|
+
height: shot.height,
|
|
3887
|
+
view: shot.view
|
|
3888
|
+
};
|
|
3889
|
+
} catch (err) {
|
|
3890
|
+
screenshotError = err?.message ?? String(err);
|
|
3891
|
+
}
|
|
3892
|
+
}
|
|
3893
|
+
}
|
|
3159
3894
|
if (options?.json) {
|
|
3160
3895
|
console.log(formatJson(callResult));
|
|
3161
3896
|
} else {
|
|
3162
3897
|
console.log(formatToolCall(callResult));
|
|
3163
3898
|
}
|
|
3899
|
+
if (screenshot) {
|
|
3900
|
+
console.error(
|
|
3901
|
+
formatSuccess(
|
|
3902
|
+
`Saved widget screenshot: ${screenshot.path} (${screenshot.width}\xD7${screenshot.height})`
|
|
3903
|
+
)
|
|
3904
|
+
);
|
|
3905
|
+
}
|
|
3906
|
+
if (screenshotError) {
|
|
3907
|
+
console.error(
|
|
3908
|
+
formatWarning(`Skipped widget screenshot: ${screenshotError}`)
|
|
3909
|
+
);
|
|
3910
|
+
}
|
|
3164
3911
|
if (callResult.isError) {
|
|
3165
3912
|
await cleanupAndExit(1);
|
|
3166
3913
|
}
|
|
@@ -3554,7 +4301,7 @@ async function interactiveCommand(options) {
|
|
|
3554
4301
|
}
|
|
3555
4302
|
}
|
|
3556
4303
|
function createClientCommand() {
|
|
3557
|
-
const clientCommand = new
|
|
4304
|
+
const clientCommand = new Command2("client").description(
|
|
3558
4305
|
"Interactive MCP client for terminal usage"
|
|
3559
4306
|
);
|
|
3560
4307
|
clientCommand.command("connect <url>").description("Connect to an MCP server").option("--name <name>", "Session name").option("--stdio", "Use stdio connector instead of HTTP").option("--auth <token>", "Static Bearer token (skips OAuth)").option(
|
|
@@ -3565,22 +4312,28 @@ function createClientCommand() {
|
|
|
3565
4312
|
"OAuth loopback wait timeout in ms (default 300000)"
|
|
3566
4313
|
).action(connectCommand);
|
|
3567
4314
|
clientCommand.command("disconnect [session]").description("Disconnect from a session").option("--all", "Disconnect all sessions").action(disconnectCommand);
|
|
3568
|
-
const sessionsCommand = new
|
|
4315
|
+
const sessionsCommand = new Command2("sessions").description(
|
|
3569
4316
|
"Manage CLI sessions"
|
|
3570
4317
|
);
|
|
3571
4318
|
sessionsCommand.command("list").description("List all saved sessions").action(listSessionsCommand);
|
|
3572
4319
|
sessionsCommand.command("switch <name>").description("Switch to a different session").action(switchSessionCommand);
|
|
3573
4320
|
clientCommand.addCommand(sessionsCommand);
|
|
3574
|
-
const toolsCommand = new
|
|
4321
|
+
const toolsCommand = new Command2("tools").description(
|
|
3575
4322
|
"Interact with MCP tools"
|
|
3576
4323
|
);
|
|
3577
4324
|
toolsCommand.command("list").description("List available tools").option("--session <name>", "Use specific session").option("--json", "Output as JSON").action(listToolsCommand);
|
|
3578
4325
|
toolsCommand.command("call <name> [args...]").description(
|
|
3579
4326
|
"Call a tool. Args as key=value pairs (use key:=<json> for nested values, or pass a JSON object)"
|
|
3580
|
-
).option("--session <name>", "Use specific session").option("--timeout <ms>", "Request timeout in milliseconds", parseInt).option("--json", "Output as JSON").
|
|
4327
|
+
).option("--session <name>", "Use specific session").option("--timeout <ms>", "Request timeout in milliseconds", parseInt).option("--json", "Output as JSON").option(
|
|
4328
|
+
"--no-screenshot",
|
|
4329
|
+
"Skip the auto-screenshot for tools that render a widget"
|
|
4330
|
+
).option(
|
|
4331
|
+
"--screenshot-output <path>",
|
|
4332
|
+
"Output PNG path for the widget screenshot (defaults to ./<view>-<timestamp>.png)"
|
|
4333
|
+
).action((name, args, opts) => callToolCommand(name, args, opts));
|
|
3581
4334
|
toolsCommand.command("describe <name>").description("Show tool details and schema").option("--session <name>", "Use specific session").action(describeToolCommand);
|
|
3582
4335
|
clientCommand.addCommand(toolsCommand);
|
|
3583
|
-
const resourcesCommand = new
|
|
4336
|
+
const resourcesCommand = new Command2("resources").description(
|
|
3584
4337
|
"Interact with MCP resources"
|
|
3585
4338
|
);
|
|
3586
4339
|
resourcesCommand.command("list").description("List available resources").option("--session <name>", "Use specific session").option("--json", "Output as JSON").action(listResourcesCommand);
|
|
@@ -3588,7 +4341,7 @@ function createClientCommand() {
|
|
|
3588
4341
|
resourcesCommand.command("subscribe <uri>").description("Subscribe to resource updates").option("--session <name>", "Use specific session").action(subscribeResourceCommand);
|
|
3589
4342
|
resourcesCommand.command("unsubscribe <uri>").description("Unsubscribe from resource updates").option("--session <name>", "Use specific session").action(unsubscribeResourceCommand);
|
|
3590
4343
|
clientCommand.addCommand(resourcesCommand);
|
|
3591
|
-
const promptsCommand = new
|
|
4344
|
+
const promptsCommand = new Command2("prompts").description(
|
|
3592
4345
|
"Interact with MCP prompts"
|
|
3593
4346
|
);
|
|
3594
4347
|
promptsCommand.command("list").description("List available prompts").option("--session <name>", "Use specific session").option("--json", "Output as JSON").action(listPromptsCommand);
|
|
@@ -3597,7 +4350,7 @@ function createClientCommand() {
|
|
|
3597
4350
|
).option("--session <name>", "Use specific session").option("--json", "Output as JSON").action(getPromptCommand);
|
|
3598
4351
|
clientCommand.addCommand(promptsCommand);
|
|
3599
4352
|
clientCommand.command("interactive").description("Start interactive REPL mode").option("--session <name>", "Use specific session").action(interactiveCommand);
|
|
3600
|
-
const authCommand = new
|
|
4353
|
+
const authCommand = new Command2("auth").description(
|
|
3601
4354
|
"Manage OAuth tokens for HTTP sessions"
|
|
3602
4355
|
);
|
|
3603
4356
|
authCommand.command("status [session]").description("Show OAuth token status for a session").action(authStatusCommand);
|
|
@@ -3611,7 +4364,7 @@ function createClientCommand() {
|
|
|
3611
4364
|
init_esm_shims();
|
|
3612
4365
|
init_open();
|
|
3613
4366
|
import { promises as fs9 } from "fs";
|
|
3614
|
-
import
|
|
4367
|
+
import path8 from "path";
|
|
3615
4368
|
|
|
3616
4369
|
// src/utils/git.ts
|
|
3617
4370
|
init_esm_shims();
|
|
@@ -3769,15 +4522,15 @@ function getMcpServerUrlForCloudServer(server) {
|
|
|
3769
4522
|
// src/utils/project-link.ts
|
|
3770
4523
|
init_esm_shims();
|
|
3771
4524
|
import { promises as fs8 } from "fs";
|
|
3772
|
-
import
|
|
4525
|
+
import path7 from "path";
|
|
3773
4526
|
var MCP_USE_DIR = ".mcp-use";
|
|
3774
4527
|
var MCP_USE_DIR_PROJECT = "project.json";
|
|
3775
4528
|
function getMcpUseDirectory(cwd) {
|
|
3776
|
-
return
|
|
4529
|
+
return path7.join(cwd, MCP_USE_DIR);
|
|
3777
4530
|
}
|
|
3778
4531
|
async function getProjectLink(cwd) {
|
|
3779
4532
|
try {
|
|
3780
|
-
const linkPath =
|
|
4533
|
+
const linkPath = path7.join(getMcpUseDirectory(cwd), MCP_USE_DIR_PROJECT);
|
|
3781
4534
|
const content = await fs8.readFile(linkPath, "utf-8");
|
|
3782
4535
|
return JSON.parse(content);
|
|
3783
4536
|
} catch (err) {
|
|
@@ -3788,12 +4541,12 @@ async function getProjectLink(cwd) {
|
|
|
3788
4541
|
async function saveProjectLink(cwd, link) {
|
|
3789
4542
|
const mcpUseDir = getMcpUseDirectory(cwd);
|
|
3790
4543
|
await fs8.mkdir(mcpUseDir, { recursive: true });
|
|
3791
|
-
const linkPath =
|
|
4544
|
+
const linkPath = path7.join(mcpUseDir, MCP_USE_DIR_PROJECT);
|
|
3792
4545
|
await fs8.writeFile(linkPath, JSON.stringify(link, null, 2), "utf-8");
|
|
3793
4546
|
await addToGitIgnore(cwd);
|
|
3794
4547
|
}
|
|
3795
4548
|
async function addToGitIgnore(cwd) {
|
|
3796
|
-
const gitignorePath =
|
|
4549
|
+
const gitignorePath = path7.join(cwd, ".gitignore");
|
|
3797
4550
|
try {
|
|
3798
4551
|
let content = "";
|
|
3799
4552
|
try {
|
|
@@ -3934,7 +4687,7 @@ async function buildEnvVars(options) {
|
|
|
3934
4687
|
}
|
|
3935
4688
|
async function isMcpProject(cwd = process.cwd()) {
|
|
3936
4689
|
try {
|
|
3937
|
-
const content = await fs9.readFile(
|
|
4690
|
+
const content = await fs9.readFile(path8.join(cwd, "package.json"), "utf-8");
|
|
3938
4691
|
const pkg = JSON.parse(content);
|
|
3939
4692
|
return !!(pkg.dependencies?.["mcp-use"] || pkg.dependencies?.["@modelcontextprotocol/sdk"] || pkg.devDependencies?.["mcp-use"] || pkg.devDependencies?.["@modelcontextprotocol/sdk"]);
|
|
3940
4693
|
} catch {
|
|
@@ -3943,16 +4696,16 @@ async function isMcpProject(cwd = process.cwd()) {
|
|
|
3943
4696
|
}
|
|
3944
4697
|
async function getProjectName(cwd = process.cwd()) {
|
|
3945
4698
|
try {
|
|
3946
|
-
const content = await fs9.readFile(
|
|
4699
|
+
const content = await fs9.readFile(path8.join(cwd, "package.json"), "utf-8");
|
|
3947
4700
|
const pkg = JSON.parse(content);
|
|
3948
4701
|
if (pkg.name) return pkg.name;
|
|
3949
4702
|
} catch {
|
|
3950
4703
|
}
|
|
3951
|
-
return
|
|
4704
|
+
return path8.basename(cwd);
|
|
3952
4705
|
}
|
|
3953
4706
|
async function detectBuildCommand(cwd) {
|
|
3954
4707
|
try {
|
|
3955
|
-
const content = await fs9.readFile(
|
|
4708
|
+
const content = await fs9.readFile(path8.join(cwd, "package.json"), "utf-8");
|
|
3956
4709
|
if (JSON.parse(content).scripts?.build) return "npm run build";
|
|
3957
4710
|
} catch {
|
|
3958
4711
|
}
|
|
@@ -3960,7 +4713,7 @@ async function detectBuildCommand(cwd) {
|
|
|
3960
4713
|
}
|
|
3961
4714
|
async function detectStartCommand(cwd) {
|
|
3962
4715
|
try {
|
|
3963
|
-
const content = await fs9.readFile(
|
|
4716
|
+
const content = await fs9.readFile(path8.join(cwd, "package.json"), "utf-8");
|
|
3964
4717
|
const pkg = JSON.parse(content);
|
|
3965
4718
|
if (pkg.scripts?.start) return "npm start";
|
|
3966
4719
|
if (pkg.main) return `node ${pkg.main}`;
|
|
@@ -3971,7 +4724,7 @@ async function detectStartCommand(cwd) {
|
|
|
3971
4724
|
async function detectRuntime(cwd) {
|
|
3972
4725
|
for (const f of ["requirements.txt", "pyproject.toml", "setup.py"]) {
|
|
3973
4726
|
try {
|
|
3974
|
-
await fs9.access(
|
|
4727
|
+
await fs9.access(path8.join(cwd, f));
|
|
3975
4728
|
return "python";
|
|
3976
4729
|
} catch {
|
|
3977
4730
|
continue;
|
|
@@ -4018,7 +4771,7 @@ var REQUIRED_IGNORES = [
|
|
|
4018
4771
|
".mcp-use"
|
|
4019
4772
|
];
|
|
4020
4773
|
async function ensureGitignore(cwd) {
|
|
4021
|
-
const gitignorePath =
|
|
4774
|
+
const gitignorePath = path8.join(cwd, ".gitignore");
|
|
4022
4775
|
let content = "";
|
|
4023
4776
|
try {
|
|
4024
4777
|
content = await fs9.readFile(gitignorePath, "utf-8");
|
|
@@ -4478,7 +5231,7 @@ async function deployCommand(options) {
|
|
|
4478
5231
|
console.log(source_default.green("\u2713 GitHub connected\n"));
|
|
4479
5232
|
let installationDbId;
|
|
4480
5233
|
let githubInstallationId;
|
|
4481
|
-
const projectDir = options.rootDir ?
|
|
5234
|
+
const projectDir = options.rootDir ? path8.resolve(cwd, options.rootDir) : cwd;
|
|
4482
5235
|
if (options.rootDir) {
|
|
4483
5236
|
try {
|
|
4484
5237
|
await fs9.access(projectDir);
|
|
@@ -4991,7 +5744,7 @@ async function deployCommand(options) {
|
|
|
4991
5744
|
|
|
4992
5745
|
// src/commands/deployments.ts
|
|
4993
5746
|
init_esm_shims();
|
|
4994
|
-
import { Command as
|
|
5747
|
+
import { Command as Command3 } from "commander";
|
|
4995
5748
|
async function prompt2(question) {
|
|
4996
5749
|
const readline = await import("readline");
|
|
4997
5750
|
const rl = readline.createInterface({
|
|
@@ -5403,7 +6156,7 @@ async function startDeploymentCommand(deploymentId) {
|
|
|
5403
6156
|
}
|
|
5404
6157
|
}
|
|
5405
6158
|
function createDeploymentsCommand() {
|
|
5406
|
-
const deploymentsCommand = new
|
|
6159
|
+
const deploymentsCommand = new Command3("deployments").description(
|
|
5407
6160
|
"Manage cloud deployments"
|
|
5408
6161
|
);
|
|
5409
6162
|
deploymentsCommand.command("list").alias("ls").description("List all deployments").action(listDeploymentsCommand);
|
|
@@ -5420,11 +6173,11 @@ function createDeploymentsCommand() {
|
|
|
5420
6173
|
|
|
5421
6174
|
// src/commands/servers.ts
|
|
5422
6175
|
init_esm_shims();
|
|
5423
|
-
import { Command as
|
|
6176
|
+
import { Command as Command5 } from "commander";
|
|
5424
6177
|
|
|
5425
6178
|
// src/commands/env.ts
|
|
5426
6179
|
init_esm_shims();
|
|
5427
|
-
import { Command as
|
|
6180
|
+
import { Command as Command4 } from "commander";
|
|
5428
6181
|
var ALL_ENVS = ["production", "preview", "development"];
|
|
5429
6182
|
function parseEnvironments(raw) {
|
|
5430
6183
|
const parts = raw.split(",").map((s) => s.trim().toLowerCase()).filter(Boolean);
|
|
@@ -5569,7 +6322,7 @@ async function removeEnvCommand(varId, options) {
|
|
|
5569
6322
|
}
|
|
5570
6323
|
}
|
|
5571
6324
|
function createEnvCommand() {
|
|
5572
|
-
const envCommand = new
|
|
6325
|
+
const envCommand = new Command4("env").description(
|
|
5573
6326
|
"Manage environment variables for a server"
|
|
5574
6327
|
);
|
|
5575
6328
|
envCommand.command("list").alias("ls").description("List environment variables for a server").requiredOption("--server <id>", "Server UUID").option("--show-values", "Reveal non-sensitive values in output").action(listEnvCommand);
|
|
@@ -5853,7 +6606,7 @@ async function deleteServerCommand(serverId, options) {
|
|
|
5853
6606
|
}
|
|
5854
6607
|
}
|
|
5855
6608
|
function createServersCommand() {
|
|
5856
|
-
const serversCommand = new
|
|
6609
|
+
const serversCommand = new Command5("servers").description(
|
|
5857
6610
|
"Manage cloud servers (Git-backed deploy targets)"
|
|
5858
6611
|
);
|
|
5859
6612
|
serversCommand.command("list").alias("ls").description("List servers for the current organization").option("--org <slug-or-id>", "Target organization (slug, id, or name)").option("--limit <n>", "Page size (1\u2013100, default 50)").option("--skip <n>", "Offset for pagination").option("--sort <field:asc|desc>", "Sort (e.g. updatedAt:desc)").action(listServersCommand);
|
|
@@ -5973,8 +6726,8 @@ async function orgCurrentCommand() {
|
|
|
5973
6726
|
|
|
5974
6727
|
// src/commands/skills.ts
|
|
5975
6728
|
init_esm_shims();
|
|
5976
|
-
import { Command as
|
|
5977
|
-
import { cpSync, existsSync as
|
|
6729
|
+
import { Command as Command6 } from "commander";
|
|
6730
|
+
import { cpSync, existsSync as existsSync3, mkdtempSync as mkdtempSync2, readdirSync, rmSync as rmSync2 } from "fs";
|
|
5978
6731
|
import { tmpdir } from "os";
|
|
5979
6732
|
import { join as join2, resolve } from "path";
|
|
5980
6733
|
import { Readable } from "stream";
|
|
@@ -6013,7 +6766,7 @@ function sendInstallTelemetryEvent(agents, skills) {
|
|
|
6013
6766
|
}
|
|
6014
6767
|
async function addSkillsToProject(projectPath) {
|
|
6015
6768
|
const tarballUrl = `https://codeload.github.com/${REPO_OWNER}/${REPO_NAME}/tar.gz/${REPO_BRANCH}`;
|
|
6016
|
-
const tempDir =
|
|
6769
|
+
const tempDir = mkdtempSync2(join2(tmpdir(), "mcp-use-skills-"));
|
|
6017
6770
|
try {
|
|
6018
6771
|
const response = await fetch(tarballUrl);
|
|
6019
6772
|
if (!response.ok) {
|
|
@@ -6023,12 +6776,12 @@ async function addSkillsToProject(projectPath) {
|
|
|
6023
6776
|
Readable.fromWeb(response.body),
|
|
6024
6777
|
extract({
|
|
6025
6778
|
cwd: tempDir,
|
|
6026
|
-
filter: (
|
|
6779
|
+
filter: (path12) => path12.includes("/skills/"),
|
|
6027
6780
|
strip: 1
|
|
6028
6781
|
})
|
|
6029
6782
|
);
|
|
6030
6783
|
const skillsPath = join2(tempDir, "skills");
|
|
6031
|
-
if (!
|
|
6784
|
+
if (!existsSync3(skillsPath)) {
|
|
6032
6785
|
throw new Error("Skills folder not found in repository");
|
|
6033
6786
|
}
|
|
6034
6787
|
for (const preset of ALL_PRESETS) {
|
|
@@ -6039,16 +6792,16 @@ async function addSkillsToProject(projectPath) {
|
|
|
6039
6792
|
const skillNames = readdirSync(skillsPath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
6040
6793
|
sendInstallTelemetryEvent(ALL_PRESETS.join(","), skillNames.join(","));
|
|
6041
6794
|
} finally {
|
|
6042
|
-
|
|
6795
|
+
rmSync2(tempDir, { recursive: true, force: true });
|
|
6043
6796
|
}
|
|
6044
6797
|
}
|
|
6045
6798
|
function createSkillsCommand() {
|
|
6046
|
-
const skills = new
|
|
6799
|
+
const skills = new Command6("skills").description(
|
|
6047
6800
|
"Manage mcp-use AI agent skills"
|
|
6048
6801
|
);
|
|
6049
6802
|
const installAction = async (options) => {
|
|
6050
6803
|
const projectPath = resolve(options.path);
|
|
6051
|
-
if (!
|
|
6804
|
+
if (!existsSync3(projectPath)) {
|
|
6052
6805
|
console.error(source_default.red(`Directory not found: ${projectPath}`));
|
|
6053
6806
|
process.exit(1);
|
|
6054
6807
|
}
|
|
@@ -6090,12 +6843,12 @@ function createSkillsCommand() {
|
|
|
6090
6843
|
|
|
6091
6844
|
// src/utils/next-shims.ts
|
|
6092
6845
|
init_esm_shims();
|
|
6093
|
-
import { existsSync as
|
|
6094
|
-
import
|
|
6846
|
+
import { existsSync as existsSync4, promises as fs10 } from "fs";
|
|
6847
|
+
import path9 from "path";
|
|
6095
6848
|
import { fileURLToPath as fileURLToPath3, pathToFileURL } from "url";
|
|
6096
6849
|
async function detectNextJsProject(projectPath) {
|
|
6097
6850
|
try {
|
|
6098
|
-
const pkgPath =
|
|
6851
|
+
const pkgPath = path9.join(projectPath, "package.json");
|
|
6099
6852
|
const content = await fs10.readFile(pkgPath, "utf-8");
|
|
6100
6853
|
const pkg = JSON.parse(content);
|
|
6101
6854
|
const deps = pkg.dependencies ?? {};
|
|
@@ -6114,7 +6867,7 @@ async function loadNextJsEnvFiles(projectPath) {
|
|
|
6114
6867
|
];
|
|
6115
6868
|
const dotenv = await import("dotenv");
|
|
6116
6869
|
for (const file of files) {
|
|
6117
|
-
const abs =
|
|
6870
|
+
const abs = path9.join(projectPath, file);
|
|
6118
6871
|
try {
|
|
6119
6872
|
await fs10.access(abs);
|
|
6120
6873
|
} catch {
|
|
@@ -6126,20 +6879,20 @@ async function loadNextJsEnvFiles(projectPath) {
|
|
|
6126
6879
|
function getThisDir() {
|
|
6127
6880
|
if (typeof __dirname === "string") return __dirname;
|
|
6128
6881
|
const url = import.meta.url;
|
|
6129
|
-
return
|
|
6882
|
+
return path9.dirname(fileURLToPath3(url));
|
|
6130
6883
|
}
|
|
6131
6884
|
function resolveShimPath(filename) {
|
|
6132
6885
|
const thisDir = getThisDir();
|
|
6133
6886
|
const candidates = [
|
|
6134
6887
|
// Production: `dist/` next to this module
|
|
6135
|
-
|
|
6888
|
+
path9.join(thisDir, "shims", filename),
|
|
6136
6889
|
// Test / dev: one level up (e.g., from `dist/utils/` back to `src/shims/`)
|
|
6137
|
-
|
|
6138
|
-
|
|
6139
|
-
|
|
6890
|
+
path9.join(thisDir, "..", "shims", filename),
|
|
6891
|
+
path9.join(thisDir, "..", "..", "src", "shims", filename),
|
|
6892
|
+
path9.join(thisDir, "..", "src", "shims", filename)
|
|
6140
6893
|
];
|
|
6141
6894
|
for (const candidate of candidates) {
|
|
6142
|
-
if (
|
|
6895
|
+
if (existsSync4(candidate)) return candidate;
|
|
6143
6896
|
}
|
|
6144
6897
|
return void 0;
|
|
6145
6898
|
}
|
|
@@ -6157,7 +6910,7 @@ async function registerNextShimsInProcess() {
|
|
|
6157
6910
|
const cjsPath = getShimCjsPreloadPath();
|
|
6158
6911
|
if (cjsPath) {
|
|
6159
6912
|
const { createRequire: createRequire3 } = await import("module");
|
|
6160
|
-
const req = createRequire3(pathToFileURL(getThisDir() +
|
|
6913
|
+
const req = createRequire3(pathToFileURL(getThisDir() + path9.sep).href);
|
|
6161
6914
|
req(cjsPath);
|
|
6162
6915
|
anyRegistered = true;
|
|
6163
6916
|
}
|
|
@@ -6165,7 +6918,7 @@ async function registerNextShimsInProcess() {
|
|
|
6165
6918
|
if (loaderPath) {
|
|
6166
6919
|
const { register } = await import("module");
|
|
6167
6920
|
const loaderUrl = pathToFileURL(loaderPath).href;
|
|
6168
|
-
register(loaderUrl, pathToFileURL(getThisDir() +
|
|
6921
|
+
register(loaderUrl, pathToFileURL(getThisDir() + path9.sep).href);
|
|
6169
6922
|
anyRegistered = true;
|
|
6170
6923
|
}
|
|
6171
6924
|
return anyRegistered;
|
|
@@ -6192,12 +6945,12 @@ function quoteNodeOption(value) {
|
|
|
6192
6945
|
// src/utils/update-check.ts
|
|
6193
6946
|
init_esm_shims();
|
|
6194
6947
|
import { readFileSync } from "fs";
|
|
6195
|
-
import { mkdir as
|
|
6948
|
+
import { mkdir as mkdir3, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
6196
6949
|
import { createRequire } from "module";
|
|
6197
|
-
import
|
|
6198
|
-
import
|
|
6199
|
-
var CACHE_DIR =
|
|
6200
|
-
var CACHE_FILE =
|
|
6950
|
+
import os5 from "os";
|
|
6951
|
+
import path10 from "path";
|
|
6952
|
+
var CACHE_DIR = path10.join(os5.homedir(), ".mcp-use");
|
|
6953
|
+
var CACHE_FILE = path10.join(CACHE_DIR, "update-check.json");
|
|
6201
6954
|
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
6202
6955
|
var FETCH_TIMEOUT_MS = 3e3;
|
|
6203
6956
|
var PACKAGE_NAME = "mcp-use";
|
|
@@ -6230,7 +6983,7 @@ async function readCache() {
|
|
|
6230
6983
|
}
|
|
6231
6984
|
async function writeCache(latestVersion) {
|
|
6232
6985
|
try {
|
|
6233
|
-
await
|
|
6986
|
+
await mkdir3(CACHE_DIR, { recursive: true });
|
|
6234
6987
|
const cache = {
|
|
6235
6988
|
lastChecked: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6236
6989
|
latestVersion
|
|
@@ -6280,12 +7033,12 @@ function resolveInstalledVersion(projectPath) {
|
|
|
6280
7033
|
if (projectPath) {
|
|
6281
7034
|
attempts.push(() => {
|
|
6282
7035
|
const projectRequire = createRequire(
|
|
6283
|
-
|
|
7036
|
+
path10.join(projectPath, "package.json")
|
|
6284
7037
|
);
|
|
6285
7038
|
return projectRequire.resolve(`${PACKAGE_NAME}/package.json`);
|
|
6286
7039
|
});
|
|
6287
7040
|
}
|
|
6288
|
-
attempts.push(() =>
|
|
7041
|
+
attempts.push(() => path10.join(__dirname, "../../mcp-use/package.json"));
|
|
6289
7042
|
for (const attempt of attempts) {
|
|
6290
7043
|
try {
|
|
6291
7044
|
const pkgPath = attempt();
|
|
@@ -6321,9 +7074,9 @@ A new release of ${source_default.bold(PACKAGE_NAME)} is available: ${source_def
|
|
|
6321
7074
|
}
|
|
6322
7075
|
|
|
6323
7076
|
// src/index.ts
|
|
6324
|
-
var program = new
|
|
7077
|
+
var program = new Command7();
|
|
6325
7078
|
var packageContent = readFileSync2(
|
|
6326
|
-
|
|
7079
|
+
path11.join(__dirname, "../package.json"),
|
|
6327
7080
|
"utf-8"
|
|
6328
7081
|
);
|
|
6329
7082
|
var packageJson = JSON.parse(packageContent);
|
|
@@ -6354,14 +7107,14 @@ function displayPackageVersions(projectPath) {
|
|
|
6354
7107
|
if (projectPath) {
|
|
6355
7108
|
try {
|
|
6356
7109
|
const projectRequire = createRequire2(
|
|
6357
|
-
|
|
7110
|
+
path11.join(projectPath, "package.json")
|
|
6358
7111
|
);
|
|
6359
7112
|
pkgPath = projectRequire.resolve(`${pkg.name}/package.json`);
|
|
6360
7113
|
} catch (resolveError) {
|
|
6361
|
-
pkgPath =
|
|
7114
|
+
pkgPath = path11.join(__dirname, pkg.relativePath);
|
|
6362
7115
|
}
|
|
6363
7116
|
} else {
|
|
6364
|
-
pkgPath =
|
|
7117
|
+
pkgPath = path11.join(__dirname, pkg.relativePath);
|
|
6365
7118
|
}
|
|
6366
7119
|
const pkgContent = readFileSync2(pkgPath, "utf-8");
|
|
6367
7120
|
const pkgJson = JSON.parse(pkgContent);
|
|
@@ -6418,7 +7171,7 @@ function normalizeBrowserHost(host) {
|
|
|
6418
7171
|
return host === "0.0.0.0" ? "localhost" : host;
|
|
6419
7172
|
}
|
|
6420
7173
|
function runCommand(command, args, cwd, env2, filterStderr = false) {
|
|
6421
|
-
const proc =
|
|
7174
|
+
const proc = spawn3(command, args, {
|
|
6422
7175
|
cwd,
|
|
6423
7176
|
stdio: filterStderr ? ["inherit", "inherit", "pipe"] : "inherit",
|
|
6424
7177
|
shell: process.platform === "win32",
|
|
@@ -6451,7 +7204,7 @@ async function startTunnel(port, subdomain) {
|
|
|
6451
7204
|
if (subdomain) {
|
|
6452
7205
|
tunnelArgs.push("--subdomain", subdomain);
|
|
6453
7206
|
}
|
|
6454
|
-
const proc =
|
|
7207
|
+
const proc = spawn3("npx", tunnelArgs, {
|
|
6455
7208
|
stdio: ["ignore", "pipe", "pipe"],
|
|
6456
7209
|
shell: process.platform === "win32"
|
|
6457
7210
|
});
|
|
@@ -6515,21 +7268,21 @@ async function startTunnel(port, subdomain) {
|
|
|
6515
7268
|
}
|
|
6516
7269
|
async function resolveEntryFile(projectPath, cliEntry, mcpDir) {
|
|
6517
7270
|
if (cliEntry) {
|
|
6518
|
-
await access(
|
|
7271
|
+
await access(path11.join(projectPath, cliEntry)).catch(() => {
|
|
6519
7272
|
throw new Error(`File not found: ${cliEntry}`);
|
|
6520
7273
|
});
|
|
6521
7274
|
return cliEntry;
|
|
6522
7275
|
}
|
|
6523
7276
|
if (mcpDir) {
|
|
6524
7277
|
const mcpCandidates = [
|
|
6525
|
-
|
|
6526
|
-
|
|
6527
|
-
|
|
6528
|
-
|
|
7278
|
+
path11.join(mcpDir, "index.ts"),
|
|
7279
|
+
path11.join(mcpDir, "index.tsx"),
|
|
7280
|
+
path11.join(mcpDir, "server.ts"),
|
|
7281
|
+
path11.join(mcpDir, "server.tsx")
|
|
6529
7282
|
];
|
|
6530
7283
|
for (const candidate of mcpCandidates) {
|
|
6531
7284
|
try {
|
|
6532
|
-
await access(
|
|
7285
|
+
await access(path11.join(projectPath, candidate));
|
|
6533
7286
|
return candidate;
|
|
6534
7287
|
} catch {
|
|
6535
7288
|
continue;
|
|
@@ -6538,17 +7291,17 @@ async function resolveEntryFile(projectPath, cliEntry, mcpDir) {
|
|
|
6538
7291
|
throw new Error(
|
|
6539
7292
|
`No entry file found inside ${mcpDir}.
|
|
6540
7293
|
|
|
6541
|
-
Expected one of: ${mcpCandidates.map((c) =>
|
|
7294
|
+
Expected one of: ${mcpCandidates.map((c) => path11.relative(projectPath, path11.join(projectPath, c))).join(", ")}
|
|
6542
7295
|
|
|
6543
7296
|
Fix this by either:
|
|
6544
|
-
1. Creating ${
|
|
7297
|
+
1. Creating ${path11.join(mcpDir, "index.ts")}, or
|
|
6545
7298
|
2. Passing --entry <file> on the command line`
|
|
6546
7299
|
);
|
|
6547
7300
|
}
|
|
6548
7301
|
const candidates = ["index.ts", "src/index.ts", "server.ts", "src/server.ts"];
|
|
6549
7302
|
for (const candidate of candidates) {
|
|
6550
7303
|
try {
|
|
6551
|
-
await access(
|
|
7304
|
+
await access(path11.join(projectPath, candidate));
|
|
6552
7305
|
return candidate;
|
|
6553
7306
|
} catch {
|
|
6554
7307
|
continue;
|
|
@@ -6566,7 +7319,7 @@ Fix this by either:
|
|
|
6566
7319
|
}
|
|
6567
7320
|
function resolveWidgetsDir(cliWidgetsDir, mcpDir) {
|
|
6568
7321
|
if (cliWidgetsDir) return cliWidgetsDir;
|
|
6569
|
-
if (mcpDir) return
|
|
7322
|
+
if (mcpDir) return path11.join(mcpDir, "resources");
|
|
6570
7323
|
return "resources";
|
|
6571
7324
|
}
|
|
6572
7325
|
function makeWidgetServerOnlyGuard(widgetName) {
|
|
@@ -6601,7 +7354,7 @@ function isBunRuntime() {
|
|
|
6601
7354
|
return typeof globalThis.Bun !== "undefined" || typeof process.versions.bun === "string";
|
|
6602
7355
|
}
|
|
6603
7356
|
async function generateToolRegistryTypesForServer(projectPath, serverFileRelative) {
|
|
6604
|
-
const serverFile =
|
|
7357
|
+
const serverFile = path11.join(projectPath, serverFileRelative);
|
|
6605
7358
|
const serverFileExists = await access(serverFile).then(() => true).catch(() => false);
|
|
6606
7359
|
if (!serverFileExists) {
|
|
6607
7360
|
throw new Error(`Server file not found: ${serverFile}`);
|
|
@@ -6627,7 +7380,7 @@ async function generateToolRegistryTypesForServer(projectPath, serverFileRelativ
|
|
|
6627
7380
|
await loadNextJsEnvFiles(projectPath);
|
|
6628
7381
|
await registerNextShimsInProcess();
|
|
6629
7382
|
}
|
|
6630
|
-
const projectTsconfigPath =
|
|
7383
|
+
const projectTsconfigPath = path11.join(projectPath, "tsconfig.json");
|
|
6631
7384
|
const hasTsconfig = await access(projectTsconfigPath).then(() => true).catch(() => false);
|
|
6632
7385
|
if (hasTsconfig) {
|
|
6633
7386
|
process.env.TSX_TSCONFIG_PATH = projectTsconfigPath;
|
|
@@ -6636,7 +7389,7 @@ async function generateToolRegistryTypesForServer(projectPath, serverFileRelativ
|
|
|
6636
7389
|
if (previousCwd !== projectPath) process.chdir(projectPath);
|
|
6637
7390
|
try {
|
|
6638
7391
|
const projectRequire = createRequire2(
|
|
6639
|
-
|
|
7392
|
+
path11.join(projectPath, "package.json")
|
|
6640
7393
|
);
|
|
6641
7394
|
const tsxEsmApiPath = projectRequire.resolve("tsx/esm/api");
|
|
6642
7395
|
const tsxEsmApi = await import(pathToFileURL2(tsxEsmApiPath).href);
|
|
@@ -6663,8 +7416,8 @@ async function generateToolRegistryTypesForServer(projectPath, serverFileRelativ
|
|
|
6663
7416
|
"No MCPServer instance found. Make sure your server file creates an MCPServer instance."
|
|
6664
7417
|
);
|
|
6665
7418
|
}
|
|
6666
|
-
const mcpUsePath =
|
|
6667
|
-
const { generateToolRegistryTypes } = await import(pathToFileURL2(
|
|
7419
|
+
const mcpUsePath = path11.join(projectPath, "node_modules", "mcp-use");
|
|
7420
|
+
const { generateToolRegistryTypes } = await import(pathToFileURL2(path11.join(mcpUsePath, "dist", "src", "server", "index.js")).href).then((mod) => mod);
|
|
6668
7421
|
if (!generateToolRegistryTypes) {
|
|
6669
7422
|
throw new Error("generateToolRegistryTypes not found in mcp-use package");
|
|
6670
7423
|
}
|
|
@@ -6682,7 +7435,7 @@ async function buildWidgets(projectPath, options = {}) {
|
|
|
6682
7435
|
const { promises: fs11 } = await import("fs");
|
|
6683
7436
|
const { build } = await import("vite");
|
|
6684
7437
|
const widgetsDirRelative = options.widgetsDir ?? "resources";
|
|
6685
|
-
const resourcesDir =
|
|
7438
|
+
const resourcesDir = path11.resolve(projectPath, widgetsDirRelative);
|
|
6686
7439
|
const mcpUrl = process.env.MCP_URL;
|
|
6687
7440
|
try {
|
|
6688
7441
|
await access(resourcesDir);
|
|
@@ -6704,10 +7457,10 @@ async function buildWidgets(projectPath, options = {}) {
|
|
|
6704
7457
|
if (dirent.isFile() && (dirent.name.endsWith(".tsx") || dirent.name.endsWith(".ts"))) {
|
|
6705
7458
|
entries.push({
|
|
6706
7459
|
name: dirent.name.replace(/\.tsx?$/, ""),
|
|
6707
|
-
path:
|
|
7460
|
+
path: path11.join(resourcesDir, dirent.name)
|
|
6708
7461
|
});
|
|
6709
7462
|
} else if (dirent.isDirectory()) {
|
|
6710
|
-
const widgetPath =
|
|
7463
|
+
const widgetPath = path11.join(resourcesDir, dirent.name, "widget.tsx");
|
|
6711
7464
|
try {
|
|
6712
7465
|
await fs11.access(widgetPath);
|
|
6713
7466
|
entries.push({
|
|
@@ -6737,14 +7490,14 @@ async function buildWidgets(projectPath, options = {}) {
|
|
|
6737
7490
|
);
|
|
6738
7491
|
const react = (await import("@vitejs/plugin-react")).default;
|
|
6739
7492
|
const tailwindcss = (await import("@tailwindcss/vite")).default;
|
|
6740
|
-
const projectTsconfigPath =
|
|
7493
|
+
const projectTsconfigPath = path11.join(projectPath, "tsconfig.json");
|
|
6741
7494
|
let hasProjectTsconfig = false;
|
|
6742
7495
|
try {
|
|
6743
7496
|
await access(projectTsconfigPath);
|
|
6744
7497
|
hasProjectTsconfig = true;
|
|
6745
7498
|
} catch {
|
|
6746
7499
|
}
|
|
6747
|
-
const packageJsonPath =
|
|
7500
|
+
const packageJsonPath = path11.join(projectPath, "package.json");
|
|
6748
7501
|
let favicon = "";
|
|
6749
7502
|
try {
|
|
6750
7503
|
const pkgContent = await fs11.readFile(packageJsonPath, "utf-8");
|
|
@@ -6756,16 +7509,16 @@ async function buildWidgets(projectPath, options = {}) {
|
|
|
6756
7509
|
const widgetName = entry.name;
|
|
6757
7510
|
const entryPath = entry.path.replace(/\\/g, "/");
|
|
6758
7511
|
console.log(source_default.gray(` - Building ${widgetName}...`));
|
|
6759
|
-
const tempDir =
|
|
7512
|
+
const tempDir = path11.join(projectPath, ".mcp-use", widgetName);
|
|
6760
7513
|
await fs11.mkdir(tempDir, { recursive: true });
|
|
6761
|
-
const relativeResourcesPath =
|
|
6762
|
-
const mcpUsePath =
|
|
6763
|
-
const relativeMcpUsePath =
|
|
6764
|
-
const projectSrcDir =
|
|
7514
|
+
const relativeResourcesPath = path11.relative(tempDir, resourcesDir).replace(/\\/g, "/");
|
|
7515
|
+
const mcpUsePath = path11.join(projectPath, "node_modules", "mcp-use");
|
|
7516
|
+
const relativeMcpUsePath = path11.relative(tempDir, mcpUsePath).replace(/\\/g, "/");
|
|
7517
|
+
const projectSrcDir = path11.join(projectPath, "src");
|
|
6765
7518
|
let projectSrcSourceLine = "";
|
|
6766
7519
|
try {
|
|
6767
7520
|
await access(projectSrcDir);
|
|
6768
|
-
const relativeProjectSrcPath =
|
|
7521
|
+
const relativeProjectSrcPath = path11.relative(tempDir, projectSrcDir).replace(/\\/g, "/");
|
|
6769
7522
|
projectSrcSourceLine = `@source "${relativeProjectSrcPath}";
|
|
6770
7523
|
`;
|
|
6771
7524
|
} catch {
|
|
@@ -6776,7 +7529,7 @@ async function buildWidgets(projectPath, options = {}) {
|
|
|
6776
7529
|
@source "${relativeResourcesPath}";
|
|
6777
7530
|
@source "${relativeMcpUsePath}/**/*.{ts,tsx,js,jsx}";
|
|
6778
7531
|
${projectSrcSourceLine}`;
|
|
6779
|
-
await fs11.writeFile(
|
|
7532
|
+
await fs11.writeFile(path11.join(tempDir, "styles.css"), cssContent, "utf8");
|
|
6780
7533
|
const entryContent = `import React from 'react'
|
|
6781
7534
|
import { createRoot } from 'react-dom/client'
|
|
6782
7535
|
import './styles.css'
|
|
@@ -6801,9 +7554,9 @@ if (container && Component) {
|
|
|
6801
7554
|
<script type="module" src="/entry.tsx"></script>
|
|
6802
7555
|
</body>
|
|
6803
7556
|
</html>`;
|
|
6804
|
-
await fs11.writeFile(
|
|
6805
|
-
await fs11.writeFile(
|
|
6806
|
-
const outDir =
|
|
7557
|
+
await fs11.writeFile(path11.join(tempDir, "entry.tsx"), entryContent, "utf8");
|
|
7558
|
+
await fs11.writeFile(path11.join(tempDir, "index.html"), htmlContent, "utf8");
|
|
7559
|
+
const outDir = path11.join(
|
|
6807
7560
|
projectPath,
|
|
6808
7561
|
"dist",
|
|
6809
7562
|
"resources",
|
|
@@ -6813,13 +7566,13 @@ if (container && Component) {
|
|
|
6813
7566
|
const baseUrl = mcpUrl ? `${mcpUrl}/${widgetName}/` : `/mcp-use/widgets/${widgetName}/`;
|
|
6814
7567
|
let widgetMetadata = {};
|
|
6815
7568
|
try {
|
|
6816
|
-
const metadataTempDir =
|
|
7569
|
+
const metadataTempDir = path11.join(
|
|
6817
7570
|
projectPath,
|
|
6818
7571
|
".mcp-use",
|
|
6819
7572
|
`${widgetName}-metadata`
|
|
6820
7573
|
);
|
|
6821
7574
|
await fs11.mkdir(metadataTempDir, { recursive: true });
|
|
6822
|
-
const { createServer } = await import("vite");
|
|
7575
|
+
const { createServer: createServer2 } = await import("vite");
|
|
6823
7576
|
const nodeStubsPlugin = {
|
|
6824
7577
|
name: "node-stubs",
|
|
6825
7578
|
enforce: "pre",
|
|
@@ -6847,9 +7600,9 @@ export default PostHog;
|
|
|
6847
7600
|
}
|
|
6848
7601
|
};
|
|
6849
7602
|
const serverOnlyGuard = makeWidgetServerOnlyGuard(widgetName);
|
|
6850
|
-
const metadataServer = await
|
|
7603
|
+
const metadataServer = await createServer2({
|
|
6851
7604
|
root: metadataTempDir,
|
|
6852
|
-
cacheDir:
|
|
7605
|
+
cacheDir: path11.join(metadataTempDir, ".vite-cache"),
|
|
6853
7606
|
plugins: [serverOnlyGuard, nodeStubsPlugin, tailwindcss(), react()],
|
|
6854
7607
|
// When the project has a tsconfig, enable Vite's native tsconfig-paths
|
|
6855
7608
|
// resolver so `@/*` (or any custom alias) resolves through the
|
|
@@ -7080,7 +7833,7 @@ export default {
|
|
|
7080
7833
|
// Inline all assets under 100MB (effectively all)
|
|
7081
7834
|
} : {},
|
|
7082
7835
|
rolldownOptions: {
|
|
7083
|
-
input:
|
|
7836
|
+
input: path11.join(tempDir, "index.html"),
|
|
7084
7837
|
external: (id) => {
|
|
7085
7838
|
return false;
|
|
7086
7839
|
}
|
|
@@ -7088,11 +7841,11 @@ export default {
|
|
|
7088
7841
|
}
|
|
7089
7842
|
});
|
|
7090
7843
|
try {
|
|
7091
|
-
const assetsDir =
|
|
7844
|
+
const assetsDir = path11.join(outDir, "assets");
|
|
7092
7845
|
const assetFiles = await fs11.readdir(assetsDir);
|
|
7093
7846
|
const jsFiles = assetFiles.filter((f) => f.endsWith(".js"));
|
|
7094
7847
|
for (const jsFile of jsFiles) {
|
|
7095
|
-
const jsPath =
|
|
7848
|
+
const jsPath = path11.join(assetsDir, jsFile);
|
|
7096
7849
|
let content = await fs11.readFile(jsPath, "utf8");
|
|
7097
7850
|
const zodConfigPatterns = [
|
|
7098
7851
|
// Non-minified: export const globalConfig = {}
|
|
@@ -7124,7 +7877,7 @@ export default {
|
|
|
7124
7877
|
const mcpServerUrl = process.env.MCP_SERVER_URL;
|
|
7125
7878
|
if (mcpServerUrl) {
|
|
7126
7879
|
try {
|
|
7127
|
-
const htmlPath =
|
|
7880
|
+
const htmlPath = path11.join(outDir, "index.html");
|
|
7128
7881
|
let html = await fs11.readFile(htmlPath, "utf8");
|
|
7129
7882
|
const injectionScript = `<script>window.__getFile = (filename) => { return "${mcpUrl}/${widgetName}/"+filename }; window.__mcpPublicUrl = "${mcpServerUrl}/mcp-use/public"; window.__mcpPublicAssetsUrl = "${mcpUrl}/public";</script>`;
|
|
7130
7883
|
if (!html.includes("window.__mcpPublicUrl")) {
|
|
@@ -7200,7 +7953,7 @@ async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
|
|
|
7200
7953
|
for (const file of literalFiles) {
|
|
7201
7954
|
if (/\.tsx?$/.test(file) && !file.endsWith(".d.ts")) {
|
|
7202
7955
|
try {
|
|
7203
|
-
await access(
|
|
7956
|
+
await access(path11.join(projectPath, file));
|
|
7204
7957
|
files.push(file);
|
|
7205
7958
|
} catch {
|
|
7206
7959
|
}
|
|
@@ -7208,13 +7961,13 @@ async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
|
|
|
7208
7961
|
}
|
|
7209
7962
|
const excludeSet = new Set(excludePatterns.map((e) => e.replace(/\*+/g, "")));
|
|
7210
7963
|
for (const prefix of dirPrefixes) {
|
|
7211
|
-
const dirPath =
|
|
7964
|
+
const dirPath = path11.join(projectPath, prefix);
|
|
7212
7965
|
try {
|
|
7213
7966
|
const entries = await fs11.readdir(dirPath, { recursive: true });
|
|
7214
7967
|
for (const entry of entries) {
|
|
7215
7968
|
const entryStr = String(entry);
|
|
7216
|
-
const rel =
|
|
7217
|
-
if (/\.tsx?$/.test(entryStr) && !entryStr.endsWith(".d.ts") && !excludeSet.has(rel.split(
|
|
7969
|
+
const rel = path11.join(prefix, entryStr);
|
|
7970
|
+
if (/\.tsx?$/.test(entryStr) && !entryStr.endsWith(".d.ts") && !excludeSet.has(rel.split(path11.sep)[0])) {
|
|
7218
7971
|
files.push(rel);
|
|
7219
7972
|
}
|
|
7220
7973
|
}
|
|
@@ -7226,7 +7979,7 @@ async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
|
|
|
7226
7979
|
async function transpileWithEsbuild(projectPath) {
|
|
7227
7980
|
const esbuild = await import("esbuild");
|
|
7228
7981
|
const { promises: fs11 } = await import("fs");
|
|
7229
|
-
const tsconfigPath =
|
|
7982
|
+
const tsconfigPath = path11.join(projectPath, "tsconfig.json");
|
|
7230
7983
|
let tsconfig = {};
|
|
7231
7984
|
try {
|
|
7232
7985
|
const raw = await fs11.readFile(tsconfigPath, "utf-8");
|
|
@@ -7256,10 +8009,10 @@ async function transpileWithEsbuild(projectPath) {
|
|
|
7256
8009
|
const target = (compilerOptions.target || "ES2022").toLowerCase();
|
|
7257
8010
|
const moduleStr = (compilerOptions.module || "ESNext").toLowerCase();
|
|
7258
8011
|
const format = moduleStr.includes("commonjs") ? "cjs" : "esm";
|
|
7259
|
-
const outbase = compilerOptions.rootDir ?
|
|
8012
|
+
const outbase = compilerOptions.rootDir ? path11.resolve(projectPath, compilerOptions.rootDir) : projectPath;
|
|
7260
8013
|
await esbuild.build({
|
|
7261
|
-
entryPoints: files.map((f) =>
|
|
7262
|
-
outdir:
|
|
8014
|
+
entryPoints: files.map((f) => path11.join(projectPath, f)),
|
|
8015
|
+
outdir: path11.join(projectPath, outDir),
|
|
7263
8016
|
outbase,
|
|
7264
8017
|
bundle: true,
|
|
7265
8018
|
packages: "external",
|
|
@@ -7286,7 +8039,7 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
7286
8039
|
"Inline all JS/CSS into HTML (required for VS Code MCP Apps)"
|
|
7287
8040
|
).option("--no-inline", "Keep JS/CSS as separate files (default)").option("--no-typecheck", "Skip TypeScript type checking (faster builds)").action(async (options) => {
|
|
7288
8041
|
try {
|
|
7289
|
-
const projectPath =
|
|
8042
|
+
const projectPath = path11.resolve(options.path);
|
|
7290
8043
|
const { promises: fs11 } = await import("fs");
|
|
7291
8044
|
displayPackageVersions(projectPath);
|
|
7292
8045
|
const mcpDir = options.mcpDir;
|
|
@@ -7346,7 +8099,7 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
7346
8099
|
}
|
|
7347
8100
|
if (options.typecheck !== false && !mcpDir) {
|
|
7348
8101
|
console.log(source_default.gray("Type checking..."));
|
|
7349
|
-
const tscBin =
|
|
8102
|
+
const tscBin = path11.join(
|
|
7350
8103
|
projectPath,
|
|
7351
8104
|
"node_modules",
|
|
7352
8105
|
"typescript",
|
|
@@ -7369,7 +8122,7 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
7369
8122
|
if (mcpDir) {
|
|
7370
8123
|
entryPoint = sourceServerFile;
|
|
7371
8124
|
} else {
|
|
7372
|
-
const baseName =
|
|
8125
|
+
const baseName = path11.basename(sourceServerFile, ".ts") + ".js";
|
|
7373
8126
|
const possibleOutputs = [
|
|
7374
8127
|
`dist/${baseName}`,
|
|
7375
8128
|
// rootDir set to project root or src
|
|
@@ -7380,7 +8133,7 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
7380
8133
|
];
|
|
7381
8134
|
for (const candidate of possibleOutputs) {
|
|
7382
8135
|
try {
|
|
7383
|
-
await access(
|
|
8136
|
+
await access(path11.join(projectPath, candidate));
|
|
7384
8137
|
entryPoint = candidate;
|
|
7385
8138
|
break;
|
|
7386
8139
|
} catch {
|
|
@@ -7389,17 +8142,17 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
7389
8142
|
}
|
|
7390
8143
|
}
|
|
7391
8144
|
}
|
|
7392
|
-
const publicDir =
|
|
8145
|
+
const publicDir = path11.join(projectPath, "public");
|
|
7393
8146
|
try {
|
|
7394
8147
|
await fs11.access(publicDir);
|
|
7395
8148
|
console.log(source_default.gray("Copying public assets..."));
|
|
7396
|
-
await fs11.cp(publicDir,
|
|
8149
|
+
await fs11.cp(publicDir, path11.join(projectPath, "dist", "public"), {
|
|
7397
8150
|
recursive: true
|
|
7398
8151
|
});
|
|
7399
8152
|
console.log(source_default.green("\u2713 Public assets copied"));
|
|
7400
8153
|
} catch {
|
|
7401
8154
|
}
|
|
7402
|
-
const manifestPath =
|
|
8155
|
+
const manifestPath = path11.join(projectPath, "dist", "mcp-use.json");
|
|
7403
8156
|
let existingManifest = {};
|
|
7404
8157
|
try {
|
|
7405
8158
|
const existingContent = await fs11.readFile(manifestPath, "utf-8");
|
|
@@ -7424,7 +8177,7 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
7424
8177
|
// Server entry point for `mcp-use start`
|
|
7425
8178
|
widgets: widgetsData
|
|
7426
8179
|
};
|
|
7427
|
-
await fs11.mkdir(
|
|
8180
|
+
await fs11.mkdir(path11.dirname(manifestPath), { recursive: true });
|
|
7428
8181
|
await fs11.writeFile(
|
|
7429
8182
|
manifestPath,
|
|
7430
8183
|
JSON.stringify(manifest, null, 2),
|
|
@@ -7461,7 +8214,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
7461
8214
|
).option("--no-open", "Do not auto-open inspector").option("--no-hmr", "Disable hot module reloading (use tsx watch instead)").option("--tunnel", "Expose server through a tunnel").action(async (options) => {
|
|
7462
8215
|
try {
|
|
7463
8216
|
process.env.MCP_USE_CLI_DEV = "1";
|
|
7464
|
-
const projectPath =
|
|
8217
|
+
const projectPath = path11.resolve(options.path);
|
|
7465
8218
|
let port = parseInt(options.port, 10);
|
|
7466
8219
|
const host = options.host;
|
|
7467
8220
|
const useHmr = options.hmr !== false;
|
|
@@ -7489,7 +8242,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
7489
8242
|
let tunnelUrl = void 0;
|
|
7490
8243
|
if (options.tunnel) {
|
|
7491
8244
|
try {
|
|
7492
|
-
const manifestPath =
|
|
8245
|
+
const manifestPath = path11.join(projectPath, "dist", "mcp-use.json");
|
|
7493
8246
|
let existingSubdomain;
|
|
7494
8247
|
try {
|
|
7495
8248
|
const manifestContent = await readFile3(manifestPath, "utf-8");
|
|
@@ -7538,7 +8291,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
7538
8291
|
manifest.tunnel = {};
|
|
7539
8292
|
}
|
|
7540
8293
|
manifest.tunnel.subdomain = tunnelSubdomain;
|
|
7541
|
-
await
|
|
8294
|
+
await mkdir4(path11.dirname(manifestPath), { recursive: true });
|
|
7542
8295
|
await writeFile3(
|
|
7543
8296
|
manifestPath,
|
|
7544
8297
|
JSON.stringify(manifest, null, 2),
|
|
@@ -7593,7 +8346,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
7593
8346
|
let args;
|
|
7594
8347
|
try {
|
|
7595
8348
|
const projectRequire = createRequire4(
|
|
7596
|
-
|
|
8349
|
+
path11.join(projectPath, "package.json")
|
|
7597
8350
|
);
|
|
7598
8351
|
const tsxPkgPath = projectRequire.resolve("tsx/package.json");
|
|
7599
8352
|
const tsxPkg = JSON.parse(await readFile3(tsxPkgPath, "utf-8"));
|
|
@@ -7605,7 +8358,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
7605
8358
|
} else {
|
|
7606
8359
|
throw new Error("No bin field found in tsx package.json");
|
|
7607
8360
|
}
|
|
7608
|
-
const tsxBin =
|
|
8361
|
+
const tsxBin = path11.resolve(path11.dirname(tsxPkgPath), binPath);
|
|
7609
8362
|
cmd = "node";
|
|
7610
8363
|
args = [tsxBin, "watch", serverFile];
|
|
7611
8364
|
} catch (error) {
|
|
@@ -7694,7 +8447,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
7694
8447
|
const chokidar = chokidarModule.default || chokidarModule;
|
|
7695
8448
|
const { fileURLToPath: fileURLToPath4 } = await import("url");
|
|
7696
8449
|
const { createRequire: createRequire3 } = await import("module");
|
|
7697
|
-
const projectTsconfigPath =
|
|
8450
|
+
const projectTsconfigPath = path11.join(projectPath, "tsconfig.json");
|
|
7698
8451
|
let tsconfigAvailable = false;
|
|
7699
8452
|
try {
|
|
7700
8453
|
await access(projectTsconfigPath);
|
|
@@ -7706,7 +8459,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
7706
8459
|
let tsxLoaderActive = false;
|
|
7707
8460
|
try {
|
|
7708
8461
|
const projectRequire = createRequire3(
|
|
7709
|
-
|
|
8462
|
+
path11.join(projectPath, "package.json")
|
|
7710
8463
|
);
|
|
7711
8464
|
const tsxEsmApiPath = projectRequire.resolve("tsx/esm/api");
|
|
7712
8465
|
const tsxEsmApi = await import(pathToFileURL2(tsxEsmApiPath).href);
|
|
@@ -7737,7 +8490,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
7737
8490
|
)
|
|
7738
8491
|
);
|
|
7739
8492
|
}
|
|
7740
|
-
const serverFilePath =
|
|
8493
|
+
const serverFilePath = path11.join(projectPath, serverFile);
|
|
7741
8494
|
const serverFileUrl = pathToFileURL2(serverFilePath).href;
|
|
7742
8495
|
globalThis.__mcpUseHmrMode = true;
|
|
7743
8496
|
const importServerModule = async () => {
|
|
@@ -7834,8 +8587,8 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
7834
8587
|
}
|
|
7835
8588
|
let watcher = chokidar.watch(".", {
|
|
7836
8589
|
cwd: projectPath,
|
|
7837
|
-
ignored: (
|
|
7838
|
-
const normalizedPath =
|
|
8590
|
+
ignored: (path12, stats) => {
|
|
8591
|
+
const normalizedPath = path12.replace(/\\/g, "/");
|
|
7839
8592
|
if (/(^|\/)\.[^/]/.test(normalizedPath)) {
|
|
7840
8593
|
return true;
|
|
7841
8594
|
}
|
|
@@ -8009,7 +8762,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
8009
8762
|
}
|
|
8010
8763
|
tunnelUrl = void 0;
|
|
8011
8764
|
if (withTunnel) {
|
|
8012
|
-
const manifestPath =
|
|
8765
|
+
const manifestPath = path11.join(projectPath, "dist", "mcp-use.json");
|
|
8013
8766
|
let existingSubdomain;
|
|
8014
8767
|
try {
|
|
8015
8768
|
const manifestContent = await readFile3(manifestPath, "utf-8");
|
|
@@ -8046,7 +8799,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
8046
8799
|
tunnelSubdomain = tunnelInfo.subdomain;
|
|
8047
8800
|
process.env.MCP_URL = tunnelUrl;
|
|
8048
8801
|
try {
|
|
8049
|
-
const mPath =
|
|
8802
|
+
const mPath = path11.join(projectPath, "dist", "mcp-use.json");
|
|
8050
8803
|
let manifest = {};
|
|
8051
8804
|
try {
|
|
8052
8805
|
manifest = JSON.parse(await readFile3(mPath, "utf-8"));
|
|
@@ -8054,7 +8807,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
8054
8807
|
}
|
|
8055
8808
|
if (!manifest.tunnel) manifest.tunnel = {};
|
|
8056
8809
|
manifest.tunnel.subdomain = tunnelSubdomain;
|
|
8057
|
-
await
|
|
8810
|
+
await mkdir4(path11.dirname(mPath), { recursive: true });
|
|
8058
8811
|
await writeFile3(mPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
8059
8812
|
} catch {
|
|
8060
8813
|
}
|
|
@@ -8158,7 +8911,7 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
8158
8911
|
"Folder holding the MCP entry + resources (e.g. 'src/mcp' for Next.js apps)"
|
|
8159
8912
|
).option("--port <port>", "Server port", "3000").option("--tunnel", "Expose server through a tunnel").action(async (options) => {
|
|
8160
8913
|
try {
|
|
8161
|
-
const projectPath =
|
|
8914
|
+
const projectPath = path11.resolve(options.path);
|
|
8162
8915
|
const portFlagProvided = process.argv.includes("--port") || process.argv.includes("-p") || process.argv.some((arg) => arg.startsWith("--port=")) || process.argv.some((arg) => arg.startsWith("-p="));
|
|
8163
8916
|
let port = portFlagProvided ? parseInt(options.port, 10) : parseInt(process.env.PORT || options.port || "3000", 10);
|
|
8164
8917
|
if (!await isPortAvailable(port)) {
|
|
@@ -8176,7 +8929,7 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
8176
8929
|
let tunnelSubdomain = void 0;
|
|
8177
8930
|
if (options.tunnel) {
|
|
8178
8931
|
try {
|
|
8179
|
-
const manifestPath2 =
|
|
8932
|
+
const manifestPath2 = path11.join(projectPath, "dist", "mcp-use.json");
|
|
8180
8933
|
let existingSubdomain;
|
|
8181
8934
|
try {
|
|
8182
8935
|
const manifestContent = await readFile3(manifestPath2, "utf-8");
|
|
@@ -8231,7 +8984,7 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
8231
8984
|
manifest.tunnel = {};
|
|
8232
8985
|
}
|
|
8233
8986
|
manifest.tunnel.subdomain = subdomain;
|
|
8234
|
-
await
|
|
8987
|
+
await mkdir4(path11.dirname(manifestPath2), { recursive: true });
|
|
8235
8988
|
await writeFile3(
|
|
8236
8989
|
manifestPath2,
|
|
8237
8990
|
JSON.stringify(manifest, null, 2),
|
|
@@ -8250,12 +9003,12 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
8250
9003
|
}
|
|
8251
9004
|
}
|
|
8252
9005
|
let serverFile;
|
|
8253
|
-
const manifestPath =
|
|
9006
|
+
const manifestPath = path11.join(projectPath, "dist", "mcp-use.json");
|
|
8254
9007
|
try {
|
|
8255
9008
|
const manifestContent = await readFile3(manifestPath, "utf-8");
|
|
8256
9009
|
const manifest = JSON.parse(manifestContent);
|
|
8257
9010
|
if (manifest.entryPoint) {
|
|
8258
|
-
await access(
|
|
9011
|
+
await access(path11.join(projectPath, manifest.entryPoint));
|
|
8259
9012
|
serverFile = manifest.entryPoint;
|
|
8260
9013
|
}
|
|
8261
9014
|
} catch {
|
|
@@ -8276,7 +9029,7 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
8276
9029
|
];
|
|
8277
9030
|
for (const candidate of serverCandidates) {
|
|
8278
9031
|
try {
|
|
8279
|
-
await access(
|
|
9032
|
+
await access(path11.join(projectPath, candidate));
|
|
8280
9033
|
serverFile = candidate;
|
|
8281
9034
|
break;
|
|
8282
9035
|
} catch {
|
|
@@ -8327,13 +9080,13 @@ Looked for:
|
|
|
8327
9080
|
if (isTsEntry) {
|
|
8328
9081
|
try {
|
|
8329
9082
|
const projectRequire = createRequire2(
|
|
8330
|
-
|
|
9083
|
+
path11.join(projectPath, "package.json")
|
|
8331
9084
|
);
|
|
8332
9085
|
const tsxPkgPath = projectRequire.resolve("tsx/package.json");
|
|
8333
9086
|
const tsxPkg = JSON.parse(await readFile3(tsxPkgPath, "utf-8"));
|
|
8334
9087
|
const binField = typeof tsxPkg.bin === "string" ? tsxPkg.bin : tsxPkg.bin?.tsx ?? Object.values(tsxPkg.bin ?? {})[0];
|
|
8335
9088
|
if (!binField) throw new Error("tsx bin entry not found");
|
|
8336
|
-
const tsxBin =
|
|
9089
|
+
const tsxBin = path11.resolve(path11.dirname(tsxPkgPath), binField);
|
|
8337
9090
|
spawnCmd = "node";
|
|
8338
9091
|
spawnArgs = [tsxBin, serverFile];
|
|
8339
9092
|
} catch (error) {
|
|
@@ -8346,7 +9099,7 @@ Looked for:
|
|
|
8346
9099
|
spawnArgs = ["tsx", serverFile];
|
|
8347
9100
|
}
|
|
8348
9101
|
}
|
|
8349
|
-
const serverProc =
|
|
9102
|
+
const serverProc = spawn3(spawnCmd, spawnArgs, {
|
|
8350
9103
|
cwd: projectPath,
|
|
8351
9104
|
stdio: "inherit",
|
|
8352
9105
|
env: env2
|
|
@@ -8479,10 +9232,11 @@ program.addCommand(createClientCommand());
|
|
|
8479
9232
|
program.addCommand(createDeploymentsCommand());
|
|
8480
9233
|
program.addCommand(createServersCommand());
|
|
8481
9234
|
program.addCommand(createSkillsCommand());
|
|
9235
|
+
program.addCommand(createScreenshotCommand());
|
|
8482
9236
|
program.command("generate-types").description(
|
|
8483
9237
|
"Generate TypeScript type definitions for tools (writes .mcp-use/tool-registry.d.ts)"
|
|
8484
9238
|
).option("-p, --path <path>", "Path to project directory", process.cwd()).option("--server <file>", "Server entry file", "index.ts").action(async (options) => {
|
|
8485
|
-
const projectPath =
|
|
9239
|
+
const projectPath = path11.resolve(options.path);
|
|
8486
9240
|
try {
|
|
8487
9241
|
console.log(source_default.blue("Generating tool registry types..."));
|
|
8488
9242
|
const result = await generateToolRegistryTypesForServer(
|