@mcp-use/cli 3.1.5-canary.4 → 3.2.0-canary.10
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-auth.d.ts +4 -0
- package/dist/commands/client-auth.d.ts.map +1 -0
- package/dist/commands/client.d.ts +40 -69
- package/dist/commands/client.d.ts.map +1 -1
- package/dist/commands/deployments.d.ts.map +1 -1
- package/dist/commands/screenshot.d.ts +80 -0
- package/dist/commands/screenshot.d.ts.map +1 -0
- package/dist/commands/servers.d.ts.map +1 -1
- package/dist/commands/skills.d.ts.map +1 -1
- package/dist/index.cjs +2049 -540
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2011 -497
- package/dist/index.js.map +1 -1
- package/dist/utils/cdp-screenshot.d.ts +44 -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/format.d.ts +36 -5
- package/dist/utils/format.d.ts.map +1 -1
- package/dist/utils/oauth.d.ts +22 -0
- package/dist/utils/oauth.d.ts.map +1 -0
- package/dist/utils/parse-args.d.ts +27 -0
- package/dist/utils/parse-args.d.ts.map +1 -0
- package/dist/utils/session-storage.d.ts +13 -33
- package/dist/utils/session-storage.d.ts.map +1 -1
- package/dist/utils/session.d.ts +39 -0
- package/dist/utils/session.d.ts.map +1 -0
- package/package.json +5 -3
package/dist/index.cjs
CHANGED
|
@@ -23,7 +23,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
23
|
mod
|
|
24
24
|
));
|
|
25
25
|
|
|
26
|
-
// ../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.
|
|
26
|
+
// ../../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/cjs_shims.js
|
|
27
27
|
var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
|
|
28
28
|
var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
29
29
|
|
|
@@ -217,10 +217,10 @@ var ansi_styles_default = ansiStyles;
|
|
|
217
217
|
var import_node_process = __toESM(require("process"), 1);
|
|
218
218
|
var import_node_os = __toESM(require("os"), 1);
|
|
219
219
|
var import_node_tty = __toESM(require("tty"), 1);
|
|
220
|
-
function hasFlag(flag,
|
|
220
|
+
function hasFlag(flag, argv2 = globalThis.Deno ? globalThis.Deno.args : import_node_process.default.argv) {
|
|
221
221
|
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
|
|
222
|
-
const position =
|
|
223
|
-
const terminatorPosition =
|
|
222
|
+
const position = argv2.indexOf(prefix + flag);
|
|
223
|
+
const terminatorPosition = argv2.indexOf("--");
|
|
224
224
|
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
|
|
225
225
|
}
|
|
226
226
|
var { env } = import_node_process.default;
|
|
@@ -523,13 +523,13 @@ var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
|
523
523
|
var source_default = chalk;
|
|
524
524
|
|
|
525
525
|
// src/index.ts
|
|
526
|
-
var
|
|
526
|
+
var import_commander7 = require("commander");
|
|
527
527
|
var import_config8 = require("dotenv/config");
|
|
528
|
-
var
|
|
529
|
-
var
|
|
530
|
-
var
|
|
528
|
+
var import_node_child_process11 = require("child_process");
|
|
529
|
+
var import_node_fs14 = require("fs");
|
|
530
|
+
var import_promises8 = require("fs/promises");
|
|
531
531
|
var import_node_module2 = require("module");
|
|
532
|
-
var
|
|
532
|
+
var import_node_path12 = __toESM(require("path"), 1);
|
|
533
533
|
var import_node_url3 = require("url");
|
|
534
534
|
|
|
535
535
|
// ../../node_modules/.pnpm/open@11.0.0/node_modules/open/index.js
|
|
@@ -716,15 +716,15 @@ var wslDefaultBrowser = async () => {
|
|
|
716
716
|
const { stdout } = await executePowerShell(command, { powerShellPath: psPath });
|
|
717
717
|
return stdout.trim();
|
|
718
718
|
};
|
|
719
|
-
var convertWslPathToWindows = async (
|
|
720
|
-
if (/^[a-z]+:\/\//i.test(
|
|
721
|
-
return
|
|
719
|
+
var convertWslPathToWindows = async (path11) => {
|
|
720
|
+
if (/^[a-z]+:\/\//i.test(path11)) {
|
|
721
|
+
return path11;
|
|
722
722
|
}
|
|
723
723
|
try {
|
|
724
|
-
const { stdout } = await execFile2("wslpath", ["-aw",
|
|
724
|
+
const { stdout } = await execFile2("wslpath", ["-aw", path11], { encoding: "utf8" });
|
|
725
725
|
return stdout.trim();
|
|
726
726
|
} catch {
|
|
727
|
-
return
|
|
727
|
+
return path11;
|
|
728
728
|
}
|
|
729
729
|
};
|
|
730
730
|
|
|
@@ -1340,8 +1340,8 @@ var McpUseAPI = class _McpUseAPI {
|
|
|
1340
1340
|
// ── Organization ID resolution ──────────────────────────────────
|
|
1341
1341
|
async resolveOrganizationId() {
|
|
1342
1342
|
if (this.orgId) return this.orgId;
|
|
1343
|
-
const
|
|
1344
|
-
const id =
|
|
1343
|
+
const auth2 = await this.testAuth();
|
|
1344
|
+
const id = auth2.default_org_id;
|
|
1345
1345
|
if (!id) {
|
|
1346
1346
|
throw new Error(
|
|
1347
1347
|
"No organization set. Run `mcp-use org switch` or use --org to specify one."
|
|
@@ -1374,8 +1374,8 @@ var McpUseAPI = class _McpUseAPI {
|
|
|
1374
1374
|
return this.request(`/servers${q ? `?${q}` : ""}`);
|
|
1375
1375
|
}
|
|
1376
1376
|
async getServer(idOrSlug) {
|
|
1377
|
-
const
|
|
1378
|
-
return this.request(`/servers/${
|
|
1377
|
+
const path11 = encodeURIComponent(idOrSlug);
|
|
1378
|
+
return this.request(`/servers/${path11}`);
|
|
1379
1379
|
}
|
|
1380
1380
|
async deleteServer(id) {
|
|
1381
1381
|
await this.request(
|
|
@@ -1875,52 +1875,110 @@ async function whoamiCommand() {
|
|
|
1875
1875
|
}
|
|
1876
1876
|
|
|
1877
1877
|
// src/commands/client.ts
|
|
1878
|
-
var
|
|
1879
|
-
var
|
|
1880
|
-
var
|
|
1881
|
-
var import_node_readline = require("readline");
|
|
1878
|
+
var import_commander2 = require("commander");
|
|
1879
|
+
var import_client3 = require("mcp-use/client");
|
|
1880
|
+
var import_node_readline2 = require("readline");
|
|
1882
1881
|
|
|
1883
1882
|
// src/utils/format.ts
|
|
1884
|
-
|
|
1883
|
+
var ANSI_RE = /\x1b\[[0-9;]*m/g;
|
|
1884
|
+
var GUTTER = " ";
|
|
1885
|
+
var MIN_TRUNCATABLE_WIDTH = 8;
|
|
1886
|
+
var DEFAULT_MAX_WIDTH = 100;
|
|
1887
|
+
function stripAnsi(s) {
|
|
1888
|
+
return s.replace(ANSI_RE, "");
|
|
1889
|
+
}
|
|
1890
|
+
function visibleWidth(s) {
|
|
1891
|
+
return stripAnsi(s).length;
|
|
1892
|
+
}
|
|
1893
|
+
function padCell(s, width) {
|
|
1894
|
+
const w = visibleWidth(s);
|
|
1895
|
+
if (w >= width) return s;
|
|
1896
|
+
return s + " ".repeat(width - w);
|
|
1897
|
+
}
|
|
1898
|
+
function truncateCell(s, width) {
|
|
1899
|
+
if (width <= 0) return "";
|
|
1900
|
+
const plain = stripAnsi(s);
|
|
1901
|
+
if (plain.length <= width) return s;
|
|
1902
|
+
if (width === 1) return "\u2026";
|
|
1903
|
+
return plain.slice(0, width - 1) + "\u2026";
|
|
1904
|
+
}
|
|
1905
|
+
function formatTable(data, columns, options = {}) {
|
|
1906
|
+
const tsv = options.tsv ?? !process.stdout.isTTY;
|
|
1907
|
+
if (tsv) {
|
|
1908
|
+
return data.map(
|
|
1909
|
+
(row) => columns.map(
|
|
1910
|
+
(c) => stripAnsi(String(row[c.key] ?? "")).replace(/[\t\r\n]+/g, " ")
|
|
1911
|
+
).join(" ")
|
|
1912
|
+
).join("\n");
|
|
1913
|
+
}
|
|
1885
1914
|
if (data.length === 0) {
|
|
1886
1915
|
return source_default.gray("No items found");
|
|
1887
1916
|
}
|
|
1888
|
-
const
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
)
|
|
1892
|
-
|
|
1893
|
-
|
|
1917
|
+
const maxWidth = options.maxWidth ?? process.stdout.columns ?? DEFAULT_MAX_WIDTH;
|
|
1918
|
+
const natural = columns.map((col) => {
|
|
1919
|
+
const headerW = col.header.length;
|
|
1920
|
+
const dataW = data.reduce((m, row) => {
|
|
1921
|
+
return Math.max(m, visibleWidth(String(row[col.key] ?? "")));
|
|
1922
|
+
}, 0);
|
|
1923
|
+
return Math.max(headerW, dataW);
|
|
1894
1924
|
});
|
|
1895
|
-
const
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1925
|
+
const widths = columns.map((c, i) => c.width ?? natural[i]);
|
|
1926
|
+
const overhead = GUTTER.length * (columns.length - 1);
|
|
1927
|
+
const totalWidth = () => widths.reduce((s, w) => s + w, 0) + overhead;
|
|
1928
|
+
if (totalWidth() > maxWidth) {
|
|
1929
|
+
const truncIdxs = columns.map((c, i) => c.truncate ? i : -1).filter((i) => i >= 0);
|
|
1930
|
+
if (truncIdxs.length > 0) {
|
|
1931
|
+
const fixedSum = columns.reduce(
|
|
1932
|
+
(s, c, i) => s + (c.truncate ? 0 : widths[i]),
|
|
1933
|
+
0
|
|
1934
|
+
);
|
|
1935
|
+
const remaining = Math.max(
|
|
1936
|
+
truncIdxs.length * MIN_TRUNCATABLE_WIDTH,
|
|
1937
|
+
maxWidth - fixedSum - overhead
|
|
1938
|
+
);
|
|
1939
|
+
const truncSum = truncIdxs.reduce((s, i) => s + widths[i], 0) || 1;
|
|
1940
|
+
let used = 0;
|
|
1941
|
+
truncIdxs.forEach((i, idx) => {
|
|
1942
|
+
if (idx === truncIdxs.length - 1) {
|
|
1943
|
+
widths[i] = Math.max(MIN_TRUNCATABLE_WIDTH, remaining - used);
|
|
1944
|
+
} else {
|
|
1945
|
+
const share = Math.max(
|
|
1946
|
+
MIN_TRUNCATABLE_WIDTH,
|
|
1947
|
+
Math.floor(widths[i] / truncSum * remaining)
|
|
1948
|
+
);
|
|
1949
|
+
widths[i] = share;
|
|
1950
|
+
used += share;
|
|
1951
|
+
}
|
|
1952
|
+
});
|
|
1906
1953
|
}
|
|
1907
|
-
|
|
1908
|
-
};
|
|
1954
|
+
}
|
|
1909
1955
|
const lines = [];
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
true
|
|
1915
|
-
)
|
|
1916
|
-
);
|
|
1917
|
-
lines.push(separator("\u2500"));
|
|
1918
|
-
data.forEach((row) => {
|
|
1919
|
-
lines.push(createRow(columns.map((c) => String(row[c.key] || ""))));
|
|
1956
|
+
const headerCells = columns.map((c, i) => {
|
|
1957
|
+
const text = c.header.toUpperCase();
|
|
1958
|
+
const cell = i === columns.length - 1 ? text : padCell(text, widths[i]);
|
|
1959
|
+
return source_default.bold(cell);
|
|
1920
1960
|
});
|
|
1921
|
-
lines.push(
|
|
1961
|
+
lines.push(headerCells.join(GUTTER).trimEnd());
|
|
1962
|
+
for (const row of data) {
|
|
1963
|
+
const cells = columns.map((c, i) => {
|
|
1964
|
+
let v = String(row[c.key] ?? "");
|
|
1965
|
+
if (visibleWidth(v) > widths[i]) {
|
|
1966
|
+
v = truncateCell(v, widths[i]);
|
|
1967
|
+
}
|
|
1968
|
+
return i === columns.length - 1 ? v : padCell(v, widths[i]);
|
|
1969
|
+
});
|
|
1970
|
+
lines.push(cells.join(GUTTER).trimEnd());
|
|
1971
|
+
}
|
|
1922
1972
|
return lines.join("\n");
|
|
1923
1973
|
}
|
|
1974
|
+
function isStdoutTty() {
|
|
1975
|
+
return Boolean(process.stdout.isTTY);
|
|
1976
|
+
}
|
|
1977
|
+
function formatToolMode(annotations) {
|
|
1978
|
+
if (annotations?.readOnlyHint === true) return source_default.green("read-only");
|
|
1979
|
+
if (annotations?.destructiveHint === true) return source_default.red("destructive");
|
|
1980
|
+
return source_default.yellow("write");
|
|
1981
|
+
}
|
|
1924
1982
|
function formatJson(data, pretty = true) {
|
|
1925
1983
|
if (pretty) {
|
|
1926
1984
|
return JSON.stringify(data, null, 2);
|
|
@@ -1929,20 +1987,29 @@ function formatJson(data, pretty = true) {
|
|
|
1929
1987
|
}
|
|
1930
1988
|
function formatToolCall(result) {
|
|
1931
1989
|
const lines = [];
|
|
1932
|
-
|
|
1990
|
+
const { isError, structuredContent } = result;
|
|
1991
|
+
const hasStructured = structuredContent !== void 0 && structuredContent !== null;
|
|
1992
|
+
const visibleContent = (result.content ?? []).filter(
|
|
1993
|
+
(item) => !hasStructured || item.type !== "text"
|
|
1994
|
+
);
|
|
1995
|
+
const hasVisibleContent = visibleContent.length > 0;
|
|
1996
|
+
if (isError) {
|
|
1933
1997
|
lines.push(source_default.red("\u2717 Tool execution failed"));
|
|
1934
1998
|
lines.push("");
|
|
1935
1999
|
} else {
|
|
1936
2000
|
lines.push(source_default.green("\u2713 Tool executed successfully"));
|
|
1937
2001
|
lines.push("");
|
|
1938
2002
|
}
|
|
1939
|
-
if (
|
|
1940
|
-
|
|
1941
|
-
|
|
2003
|
+
if (hasVisibleContent) {
|
|
2004
|
+
if (isError) {
|
|
2005
|
+
lines.push(source_default.red.bold("Error details:"));
|
|
2006
|
+
}
|
|
2007
|
+
visibleContent.forEach((item, index) => {
|
|
2008
|
+
if (visibleContent.length > 1) {
|
|
1942
2009
|
lines.push(source_default.bold(`Content ${index + 1}:`));
|
|
1943
2010
|
}
|
|
1944
2011
|
if (item.type === "text") {
|
|
1945
|
-
lines.push(item.text);
|
|
2012
|
+
lines.push(isError ? source_default.red(item.text) : item.text);
|
|
1946
2013
|
} else if (item.type === "image") {
|
|
1947
2014
|
lines.push(source_default.cyan(`[Image: ${item.mimeType || "unknown type"}]`));
|
|
1948
2015
|
if (item.data) {
|
|
@@ -1959,11 +2026,20 @@ function formatToolCall(result) {
|
|
|
1959
2026
|
} else {
|
|
1960
2027
|
lines.push(source_default.gray(`[Unknown content type: ${item.type}]`));
|
|
1961
2028
|
}
|
|
1962
|
-
if (index <
|
|
2029
|
+
if (index < visibleContent.length - 1) {
|
|
1963
2030
|
lines.push("");
|
|
1964
2031
|
}
|
|
1965
2032
|
});
|
|
1966
2033
|
}
|
|
2034
|
+
if (hasStructured) {
|
|
2035
|
+
if (isError) {
|
|
2036
|
+
lines.push(source_default.bold("Structured error data:"));
|
|
2037
|
+
}
|
|
2038
|
+
lines.push(formatJson(structuredContent));
|
|
2039
|
+
}
|
|
2040
|
+
if (isError && !hasVisibleContent && !hasStructured) {
|
|
2041
|
+
lines.push(source_default.gray("(no error details provided by server)"));
|
|
2042
|
+
}
|
|
1967
2043
|
return lines.join("\n");
|
|
1968
2044
|
}
|
|
1969
2045
|
function formatResourceContent(content) {
|
|
@@ -2116,28 +2192,218 @@ function formatPromptMessages(messages) {
|
|
|
2116
2192
|
return lines.join("\n");
|
|
2117
2193
|
}
|
|
2118
2194
|
|
|
2195
|
+
// src/utils/parse-args.ts
|
|
2196
|
+
function parseToolArgs(rawArgs, inputSchema) {
|
|
2197
|
+
if (!rawArgs || rawArgs.length === 0) return {};
|
|
2198
|
+
if (rawArgs.length === 1) {
|
|
2199
|
+
const trimmed = rawArgs[0].trim();
|
|
2200
|
+
if (trimmed.startsWith("{")) {
|
|
2201
|
+
try {
|
|
2202
|
+
const parsed = JSON.parse(trimmed);
|
|
2203
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
2204
|
+
throw new Error("expected a JSON object");
|
|
2205
|
+
}
|
|
2206
|
+
return parsed;
|
|
2207
|
+
} catch (err) {
|
|
2208
|
+
throw new Error(`Invalid JSON arguments: ${err.message}`);
|
|
2209
|
+
}
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
const props = inputSchema?.properties ?? {};
|
|
2213
|
+
const result = {};
|
|
2214
|
+
for (const raw of rawArgs) {
|
|
2215
|
+
const token = raw.startsWith("--") ? raw.slice(2) : raw;
|
|
2216
|
+
const jsonIdx = token.indexOf(":=");
|
|
2217
|
+
const eqIdx = token.indexOf("=");
|
|
2218
|
+
let key;
|
|
2219
|
+
let rawValue;
|
|
2220
|
+
let forceJson = false;
|
|
2221
|
+
if (jsonIdx !== -1 && (eqIdx === -1 || jsonIdx < eqIdx)) {
|
|
2222
|
+
key = token.slice(0, jsonIdx);
|
|
2223
|
+
rawValue = token.slice(jsonIdx + 2);
|
|
2224
|
+
forceJson = true;
|
|
2225
|
+
} else if (eqIdx !== -1) {
|
|
2226
|
+
key = token.slice(0, eqIdx);
|
|
2227
|
+
rawValue = token.slice(eqIdx + 1);
|
|
2228
|
+
} else {
|
|
2229
|
+
throw new Error(
|
|
2230
|
+
`Invalid argument '${raw}'. Use key=value or key:=jsonvalue.`
|
|
2231
|
+
);
|
|
2232
|
+
}
|
|
2233
|
+
if (!key) {
|
|
2234
|
+
throw new Error(`Empty key in argument '${raw}'`);
|
|
2235
|
+
}
|
|
2236
|
+
result[key] = coerceArgValue(rawValue, props[key], forceJson, key);
|
|
2237
|
+
}
|
|
2238
|
+
return result;
|
|
2239
|
+
}
|
|
2240
|
+
function coerceArgValue(value, propSchema, forceJson, key) {
|
|
2241
|
+
if (forceJson) {
|
|
2242
|
+
try {
|
|
2243
|
+
return JSON.parse(value);
|
|
2244
|
+
} catch (err) {
|
|
2245
|
+
throw new Error(
|
|
2246
|
+
`Invalid JSON value for '${key}': ${err.message}`
|
|
2247
|
+
);
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2250
|
+
const types = Array.isArray(propSchema?.type) ? propSchema.type : propSchema?.type ? [propSchema.type] : [];
|
|
2251
|
+
if (types.includes("null") && (value === "null" || value === "")) {
|
|
2252
|
+
return null;
|
|
2253
|
+
}
|
|
2254
|
+
if (types.includes("integer")) {
|
|
2255
|
+
const n = Number(value);
|
|
2256
|
+
if (!Number.isFinite(n) || !Number.isInteger(n)) {
|
|
2257
|
+
throw new Error(`Expected integer for '${key}', got '${value}'`);
|
|
2258
|
+
}
|
|
2259
|
+
return n;
|
|
2260
|
+
}
|
|
2261
|
+
if (types.includes("number")) {
|
|
2262
|
+
const n = Number(value);
|
|
2263
|
+
if (!Number.isFinite(n)) {
|
|
2264
|
+
throw new Error(`Expected number for '${key}', got '${value}'`);
|
|
2265
|
+
}
|
|
2266
|
+
return n;
|
|
2267
|
+
}
|
|
2268
|
+
if (types.includes("boolean")) {
|
|
2269
|
+
if (value === "true" || value === "1") return true;
|
|
2270
|
+
if (value === "false" || value === "0") return false;
|
|
2271
|
+
throw new Error(
|
|
2272
|
+
`Expected boolean (true/false) for '${key}', got '${value}'`
|
|
2273
|
+
);
|
|
2274
|
+
}
|
|
2275
|
+
if (types.includes("array") || types.includes("object")) {
|
|
2276
|
+
try {
|
|
2277
|
+
return JSON.parse(value);
|
|
2278
|
+
} catch (err) {
|
|
2279
|
+
const wanted = types.includes("array") ? "array" : "object";
|
|
2280
|
+
throw new Error(
|
|
2281
|
+
`Expected JSON ${wanted} for '${key}'. Tip: use ${key}:=<json>. ${err.message}`
|
|
2282
|
+
);
|
|
2283
|
+
}
|
|
2284
|
+
}
|
|
2285
|
+
return value;
|
|
2286
|
+
}
|
|
2287
|
+
function parsePromptArgs(rawArgs) {
|
|
2288
|
+
if (!rawArgs || rawArgs.length === 0) return {};
|
|
2289
|
+
if (rawArgs.length === 1) {
|
|
2290
|
+
const trimmed = rawArgs[0].trim();
|
|
2291
|
+
if (trimmed.startsWith("{")) {
|
|
2292
|
+
try {
|
|
2293
|
+
const parsed = JSON.parse(trimmed);
|
|
2294
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
2295
|
+
throw new Error("expected a JSON object");
|
|
2296
|
+
}
|
|
2297
|
+
const out = {};
|
|
2298
|
+
for (const [k, v] of Object.entries(parsed)) {
|
|
2299
|
+
out[k] = typeof v === "string" ? v : JSON.stringify(v);
|
|
2300
|
+
}
|
|
2301
|
+
return out;
|
|
2302
|
+
} catch (err) {
|
|
2303
|
+
throw new Error(`Invalid JSON arguments: ${err.message}`);
|
|
2304
|
+
}
|
|
2305
|
+
}
|
|
2306
|
+
}
|
|
2307
|
+
const result = {};
|
|
2308
|
+
for (const raw of rawArgs) {
|
|
2309
|
+
const token = raw.startsWith("--") ? raw.slice(2) : raw;
|
|
2310
|
+
const eqIdx = token.indexOf("=");
|
|
2311
|
+
if (eqIdx === -1) {
|
|
2312
|
+
throw new Error(`Invalid argument '${raw}'. Use key=value.`);
|
|
2313
|
+
}
|
|
2314
|
+
const key = token.slice(0, eqIdx);
|
|
2315
|
+
const value = token.slice(eqIdx + 1);
|
|
2316
|
+
if (!key) {
|
|
2317
|
+
throw new Error(`Empty key in argument '${raw}'`);
|
|
2318
|
+
}
|
|
2319
|
+
result[key] = value;
|
|
2320
|
+
}
|
|
2321
|
+
return result;
|
|
2322
|
+
}
|
|
2323
|
+
|
|
2324
|
+
// src/utils/oauth.ts
|
|
2325
|
+
var import_node = require("mcp-use/auth/node");
|
|
2326
|
+
var import_node_readline = require("readline");
|
|
2327
|
+
async function buildOAuthProvider(serverUrl, options = {}) {
|
|
2328
|
+
return import_node.NodeOAuthClientProvider.create(serverUrl, {
|
|
2329
|
+
clientName: "mcp-use CLI",
|
|
2330
|
+
clientUri: "https://mcp-use.com",
|
|
2331
|
+
storageKeyPrefix: "mcp:auth",
|
|
2332
|
+
...options,
|
|
2333
|
+
openBrowser: async (url) => {
|
|
2334
|
+
console.error(`
|
|
2335
|
+
Open this URL in a browser to authenticate:`);
|
|
2336
|
+
console.error(` ${url}
|
|
2337
|
+
`);
|
|
2338
|
+
}
|
|
2339
|
+
});
|
|
2340
|
+
}
|
|
2341
|
+
async function runOAuthFlow(provider, serverUrl, print = console.error.bind(console)) {
|
|
2342
|
+
print(`\u2192 OAuth authentication required.`);
|
|
2343
|
+
print(
|
|
2344
|
+
` Listening on http://127.0.0.1:${provider.callbackPort}/callback (waiting up to 5m)`
|
|
2345
|
+
);
|
|
2346
|
+
if (!provider.hasPendingFlow) {
|
|
2347
|
+
const result = await (0, import_node.auth)(provider, { serverUrl });
|
|
2348
|
+
if (result === "AUTHORIZED") {
|
|
2349
|
+
return;
|
|
2350
|
+
}
|
|
2351
|
+
if (result !== "REDIRECT") {
|
|
2352
|
+
throw new import_node.OAuthFlowError(
|
|
2353
|
+
"unexpected_auth_result",
|
|
2354
|
+
`auth() returned ${result}`
|
|
2355
|
+
);
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
const code = await provider.getAuthorizationCode();
|
|
2359
|
+
await (0, import_node.auth)(provider, { serverUrl, authorizationCode: code });
|
|
2360
|
+
}
|
|
2361
|
+
function isUnauthorized(err) {
|
|
2362
|
+
if (err instanceof import_node.UnauthorizedError) return true;
|
|
2363
|
+
if (err instanceof Error && err.name === "UnauthorizedError") return true;
|
|
2364
|
+
if (err instanceof Error && err.code === 401) {
|
|
2365
|
+
return true;
|
|
2366
|
+
}
|
|
2367
|
+
return false;
|
|
2368
|
+
}
|
|
2369
|
+
async function promptYesNo(question, defaultYes = true) {
|
|
2370
|
+
if (!process.stdin.isTTY) return false;
|
|
2371
|
+
const rl = (0, import_node_readline.createInterface)({ input: process.stdin, output: process.stderr });
|
|
2372
|
+
try {
|
|
2373
|
+
const answer = await new Promise((resolve2) => {
|
|
2374
|
+
rl.question(`${question} ${defaultYes ? "[Y/n] " : "[y/N] "}`, resolve2);
|
|
2375
|
+
});
|
|
2376
|
+
const trimmed = answer.trim().toLowerCase();
|
|
2377
|
+
if (!trimmed) return defaultYes;
|
|
2378
|
+
return trimmed === "y" || trimmed === "yes";
|
|
2379
|
+
} finally {
|
|
2380
|
+
rl.close();
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2383
|
+
|
|
2119
2384
|
// src/utils/session-storage.ts
|
|
2120
2385
|
var import_node_os4 = require("os");
|
|
2121
2386
|
var import_node_path3 = require("path");
|
|
2122
2387
|
var import_promises4 = require("fs/promises");
|
|
2123
2388
|
var import_node_fs5 = require("fs");
|
|
2124
2389
|
var SESSION_FILE_PATH = (0, import_node_path3.join)((0, import_node_os4.homedir)(), ".mcp-use", "cli-sessions.json");
|
|
2390
|
+
var _dirEnsured = false;
|
|
2125
2391
|
async function ensureSessionDir() {
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
}
|
|
2392
|
+
if (_dirEnsured) return;
|
|
2393
|
+
await (0, import_promises4.mkdir)((0, import_node_path3.join)((0, import_node_os4.homedir)(), ".mcp-use"), { recursive: true });
|
|
2394
|
+
_dirEnsured = true;
|
|
2130
2395
|
}
|
|
2131
2396
|
async function loadSessions() {
|
|
2132
2397
|
try {
|
|
2133
2398
|
await ensureSessionDir();
|
|
2134
2399
|
if (!(0, import_node_fs5.existsSync)(SESSION_FILE_PATH)) {
|
|
2135
|
-
return {
|
|
2400
|
+
return { sessions: {} };
|
|
2136
2401
|
}
|
|
2137
2402
|
const content = await (0, import_promises4.readFile)(SESSION_FILE_PATH, "utf-8");
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2403
|
+
const parsed = JSON.parse(content);
|
|
2404
|
+
return { sessions: parsed?.sessions ?? {} };
|
|
2405
|
+
} catch {
|
|
2406
|
+
return { sessions: {} };
|
|
2141
2407
|
}
|
|
2142
2408
|
}
|
|
2143
2409
|
async function saveSessions(storage) {
|
|
@@ -2150,40 +2416,22 @@ async function saveSession(name, config) {
|
|
|
2150
2416
|
...config,
|
|
2151
2417
|
lastUsed: (/* @__PURE__ */ new Date()).toISOString()
|
|
2152
2418
|
};
|
|
2153
|
-
if (!storage.activeSession) {
|
|
2154
|
-
storage.activeSession = name;
|
|
2155
|
-
}
|
|
2156
2419
|
await saveSessions(storage);
|
|
2157
2420
|
}
|
|
2158
|
-
async function
|
|
2421
|
+
async function removeSession(name) {
|
|
2159
2422
|
const storage = await loadSessions();
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
}
|
|
2163
|
-
return {
|
|
2164
|
-
name: storage.activeSession,
|
|
2165
|
-
config: storage.sessions[storage.activeSession]
|
|
2166
|
-
};
|
|
2423
|
+
delete storage.sessions[name];
|
|
2424
|
+
await saveSessions(storage);
|
|
2167
2425
|
}
|
|
2168
2426
|
async function getSession(name) {
|
|
2169
2427
|
const storage = await loadSessions();
|
|
2170
2428
|
return storage.sessions[name] || null;
|
|
2171
2429
|
}
|
|
2172
|
-
async function setActiveSession(name) {
|
|
2173
|
-
const storage = await loadSessions();
|
|
2174
|
-
if (!storage.sessions[name]) {
|
|
2175
|
-
throw new Error(`Session '${name}' not found`);
|
|
2176
|
-
}
|
|
2177
|
-
storage.activeSession = name;
|
|
2178
|
-
storage.sessions[name].lastUsed = (/* @__PURE__ */ new Date()).toISOString();
|
|
2179
|
-
await saveSessions(storage);
|
|
2180
|
-
}
|
|
2181
2430
|
async function listAllSessions() {
|
|
2182
2431
|
const storage = await loadSessions();
|
|
2183
2432
|
return Object.entries(storage.sessions).map(([name, config]) => ({
|
|
2184
2433
|
name,
|
|
2185
|
-
config
|
|
2186
|
-
isActive: name === storage.activeSession
|
|
2434
|
+
config
|
|
2187
2435
|
}));
|
|
2188
2436
|
}
|
|
2189
2437
|
async function updateSessionInfo(name, serverInfo, capabilities) {
|
|
@@ -2196,40 +2444,68 @@ async function updateSessionInfo(name, serverInfo, capabilities) {
|
|
|
2196
2444
|
}
|
|
2197
2445
|
}
|
|
2198
2446
|
|
|
2199
|
-
// src/
|
|
2447
|
+
// src/utils/session.ts
|
|
2448
|
+
var import_client = require("mcp-use/client");
|
|
2449
|
+
var import_server = require("mcp-use/server");
|
|
2200
2450
|
var activeSessions = /* @__PURE__ */ new Map();
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2451
|
+
function getCliClientInfo() {
|
|
2452
|
+
return {
|
|
2453
|
+
name: "mcp-use CLI",
|
|
2454
|
+
title: "mcp-use CLI",
|
|
2455
|
+
version: (0, import_server.getPackageVersion)(),
|
|
2456
|
+
description: "mcp-use CLI - Command-line interface for MCP servers",
|
|
2457
|
+
icons: [
|
|
2458
|
+
{
|
|
2459
|
+
src: "https://manufact.com/logo.png"
|
|
2460
|
+
}
|
|
2461
|
+
],
|
|
2462
|
+
websiteUrl: "https://manufact.com"
|
|
2463
|
+
};
|
|
2464
|
+
}
|
|
2465
|
+
async function cleanupAndExit(code) {
|
|
2466
|
+
for (const [name, { client }] of activeSessions) {
|
|
2467
|
+
try {
|
|
2468
|
+
await client.closeAllSessions();
|
|
2469
|
+
} catch {
|
|
2212
2470
|
}
|
|
2213
|
-
|
|
2471
|
+
activeSessions.delete(name);
|
|
2214
2472
|
}
|
|
2473
|
+
process.exit(code);
|
|
2474
|
+
}
|
|
2475
|
+
async function getOrRestoreSession(sessionName) {
|
|
2215
2476
|
if (activeSessions.has(sessionName)) {
|
|
2216
2477
|
const { session } = activeSessions.get(sessionName);
|
|
2217
2478
|
return { name: sessionName, session };
|
|
2218
2479
|
}
|
|
2219
2480
|
const config = await getSession(sessionName);
|
|
2220
2481
|
if (!config) {
|
|
2221
|
-
console.error(formatError(`
|
|
2482
|
+
console.error(formatError(`Server '${sessionName}' not found`));
|
|
2483
|
+
console.error(
|
|
2484
|
+
formatInfo(
|
|
2485
|
+
`Connect with: npx mcp-use client connect ${sessionName} <url>`
|
|
2486
|
+
)
|
|
2487
|
+
);
|
|
2222
2488
|
return null;
|
|
2223
2489
|
}
|
|
2224
2490
|
try {
|
|
2225
2491
|
const client = new import_client.MCPClient();
|
|
2226
2492
|
const cliClientInfo = getCliClientInfo();
|
|
2493
|
+
let authProvider;
|
|
2227
2494
|
if (config.type === "http") {
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2495
|
+
if (config.authMode === "oauth") {
|
|
2496
|
+
authProvider = await buildOAuthProvider(config.url);
|
|
2497
|
+
client.addServer(sessionName, {
|
|
2498
|
+
url: config.url,
|
|
2499
|
+
authProvider,
|
|
2500
|
+
clientInfo: cliClientInfo
|
|
2501
|
+
});
|
|
2502
|
+
} else {
|
|
2503
|
+
client.addServer(sessionName, {
|
|
2504
|
+
url: config.url,
|
|
2505
|
+
headers: config.authToken ? { Authorization: `Bearer ${config.authToken}` } : void 0,
|
|
2506
|
+
clientInfo: cliClientInfo
|
|
2507
|
+
});
|
|
2508
|
+
}
|
|
2233
2509
|
} else if (config.type === "stdio") {
|
|
2234
2510
|
client.addServer(sessionName, {
|
|
2235
2511
|
command: config.command,
|
|
@@ -2241,37 +2517,1028 @@ async function getOrRestoreSession(sessionName) {
|
|
|
2241
2517
|
console.error(formatError(`Unknown session type: ${config.type}`));
|
|
2242
2518
|
return null;
|
|
2243
2519
|
}
|
|
2244
|
-
|
|
2520
|
+
let session;
|
|
2521
|
+
try {
|
|
2522
|
+
session = await client.createSession(sessionName);
|
|
2523
|
+
} catch (err) {
|
|
2524
|
+
if (config.type === "http" && config.authMode === "oauth" && authProvider && isUnauthorized(err)) {
|
|
2525
|
+
const reAuth = await promptYesNo(
|
|
2526
|
+
`! Tokens for server '${sessionName}' expired and could not refresh. Re-authenticate now?`,
|
|
2527
|
+
true
|
|
2528
|
+
);
|
|
2529
|
+
if (!reAuth) {
|
|
2530
|
+
console.error(formatError(`Tokens expired and could not refresh.`));
|
|
2531
|
+
console.error(
|
|
2532
|
+
formatInfo(
|
|
2533
|
+
`Run: mcp-use client connect ${sessionName} ${config.url}`
|
|
2534
|
+
)
|
|
2535
|
+
);
|
|
2536
|
+
return null;
|
|
2537
|
+
}
|
|
2538
|
+
await runOAuthFlow(authProvider, config.url);
|
|
2539
|
+
session = await client.createSession(sessionName);
|
|
2540
|
+
} else {
|
|
2541
|
+
throw err;
|
|
2542
|
+
}
|
|
2543
|
+
}
|
|
2245
2544
|
activeSessions.set(sessionName, { client, session });
|
|
2246
|
-
console.error(formatInfo(`Reconnected to session '${sessionName}'`));
|
|
2247
2545
|
return { name: sessionName, session };
|
|
2248
2546
|
} catch (error) {
|
|
2249
|
-
console.error(formatError(`Failed to restore
|
|
2547
|
+
console.error(formatError(`Failed to restore server: ${error.message}`));
|
|
2548
|
+
return null;
|
|
2549
|
+
}
|
|
2550
|
+
}
|
|
2551
|
+
|
|
2552
|
+
// src/commands/client-auth.ts
|
|
2553
|
+
async function resolveSession(name) {
|
|
2554
|
+
const config = await getSession(name);
|
|
2555
|
+
if (!config) {
|
|
2556
|
+
console.error(formatError(`Server '${name}' not found`));
|
|
2557
|
+
return null;
|
|
2558
|
+
}
|
|
2559
|
+
if (config.type !== "http") {
|
|
2560
|
+
console.error(formatError("Auth commands only apply to HTTP servers"));
|
|
2561
|
+
return null;
|
|
2562
|
+
}
|
|
2563
|
+
if (config.authMode !== "oauth") {
|
|
2564
|
+
console.error(
|
|
2565
|
+
formatError(
|
|
2566
|
+
`Server '${name}' was not authenticated via OAuth (authMode=${config.authMode ?? "bearer"})`
|
|
2567
|
+
)
|
|
2568
|
+
);
|
|
2569
|
+
return null;
|
|
2570
|
+
}
|
|
2571
|
+
return { name, url: config.url };
|
|
2572
|
+
}
|
|
2573
|
+
function formatExpiresIn(expSec) {
|
|
2574
|
+
const ms = expSec * 1e3 - Date.now();
|
|
2575
|
+
if (ms <= 0) return "expired";
|
|
2576
|
+
const mins = Math.round(ms / 6e4);
|
|
2577
|
+
if (mins < 60) return `${mins}m`;
|
|
2578
|
+
const hours = Math.floor(mins / 60);
|
|
2579
|
+
const rem = mins % 60;
|
|
2580
|
+
return rem ? `${hours}h${rem}m` : `${hours}h`;
|
|
2581
|
+
}
|
|
2582
|
+
function decodeJwtExp(token) {
|
|
2583
|
+
try {
|
|
2584
|
+
const parts = token.split(".");
|
|
2585
|
+
if (parts.length < 2) return null;
|
|
2586
|
+
const payload = JSON.parse(
|
|
2587
|
+
Buffer.from(parts[1], "base64url").toString("utf-8")
|
|
2588
|
+
);
|
|
2589
|
+
return typeof payload.exp === "number" ? payload.exp : null;
|
|
2590
|
+
} catch {
|
|
2591
|
+
return null;
|
|
2592
|
+
}
|
|
2593
|
+
}
|
|
2594
|
+
async function authStatusCommand(name) {
|
|
2595
|
+
const target = await resolveSession(name);
|
|
2596
|
+
if (!target) {
|
|
2597
|
+
process.exit(1);
|
|
2598
|
+
}
|
|
2599
|
+
const { name: serverName, url } = target;
|
|
2600
|
+
const provider = await buildOAuthProvider(url);
|
|
2601
|
+
const tokens = await provider.tokens();
|
|
2602
|
+
const fields = {
|
|
2603
|
+
server: serverName,
|
|
2604
|
+
url,
|
|
2605
|
+
tokens: tokens?.access_token ? "present" : "missing"
|
|
2606
|
+
};
|
|
2607
|
+
if (tokens?.scope) fields.scope = tokens.scope;
|
|
2608
|
+
if (tokens?.access_token) {
|
|
2609
|
+
const exp = decodeJwtExp(tokens.access_token);
|
|
2610
|
+
fields.expires_in = exp ? formatExpiresIn(exp) : "unknown (opaque token)";
|
|
2611
|
+
}
|
|
2612
|
+
fields.refresh = tokens?.refresh_token ? "available" : "missing";
|
|
2613
|
+
console.log(formatKeyValue(fields));
|
|
2614
|
+
if (!tokens?.access_token) process.exit(1);
|
|
2615
|
+
}
|
|
2616
|
+
async function authRefreshCommand(name) {
|
|
2617
|
+
const target = await resolveSession(name);
|
|
2618
|
+
if (!target) {
|
|
2619
|
+
process.exit(1);
|
|
2620
|
+
}
|
|
2621
|
+
const { name: serverName, url } = target;
|
|
2622
|
+
const provider = await buildOAuthProvider(url);
|
|
2623
|
+
const refreshed = await provider.forceRefresh();
|
|
2624
|
+
if (!refreshed) {
|
|
2625
|
+
console.error(
|
|
2626
|
+
formatError(
|
|
2627
|
+
"Refresh failed (no refresh_token, or server rejected). Re-connect to re-authenticate."
|
|
2628
|
+
)
|
|
2629
|
+
);
|
|
2630
|
+
console.error(
|
|
2631
|
+
formatInfo(`Run: mcp-use client connect ${serverName} ${url}`)
|
|
2632
|
+
);
|
|
2633
|
+
process.exit(1);
|
|
2634
|
+
}
|
|
2635
|
+
const exp = refreshed.access_token ? decodeJwtExp(refreshed.access_token) : null;
|
|
2636
|
+
console.log(
|
|
2637
|
+
formatSuccess(
|
|
2638
|
+
`Refreshed access token${exp ? ` (expires in ${formatExpiresIn(exp)})` : ""}`
|
|
2639
|
+
)
|
|
2640
|
+
);
|
|
2641
|
+
}
|
|
2642
|
+
async function authLogoutCommand(name) {
|
|
2643
|
+
const target = await resolveSession(name);
|
|
2644
|
+
if (!target) {
|
|
2645
|
+
process.exit(1);
|
|
2646
|
+
}
|
|
2647
|
+
const { name: serverName, url } = target;
|
|
2648
|
+
const provider = await buildOAuthProvider(url);
|
|
2649
|
+
await provider.invalidateCredentials("all");
|
|
2650
|
+
console.log(formatSuccess(`Removed tokens for ${url}`));
|
|
2651
|
+
console.log(
|
|
2652
|
+
formatInfo(
|
|
2653
|
+
`Server '${serverName}' kept; reconnect with \`mcp-use client connect\`.`
|
|
2654
|
+
)
|
|
2655
|
+
);
|
|
2656
|
+
}
|
|
2657
|
+
|
|
2658
|
+
// src/commands/screenshot.ts
|
|
2659
|
+
var import_commander = require("commander");
|
|
2660
|
+
var import_client2 = require("mcp-use/client");
|
|
2661
|
+
var import_node_child_process9 = require("child_process");
|
|
2662
|
+
var import_node_fs8 = require("fs");
|
|
2663
|
+
var import_promises5 = require("fs/promises");
|
|
2664
|
+
var import_node_net = require("net");
|
|
2665
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
2666
|
+
|
|
2667
|
+
// src/utils/cdp-screenshot.ts
|
|
2668
|
+
var import_node_child_process8 = require("child_process");
|
|
2669
|
+
var import_node_fs6 = require("fs");
|
|
2670
|
+
var import_node_os5 = __toESM(require("os"), 1);
|
|
2671
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
2672
|
+
var import_ws = __toESM(require("ws"), 1);
|
|
2673
|
+
var CdpClient = class {
|
|
2674
|
+
constructor(ws) {
|
|
2675
|
+
this.ws = ws;
|
|
2676
|
+
ws.on("message", (data) => {
|
|
2677
|
+
let msg;
|
|
2678
|
+
try {
|
|
2679
|
+
msg = JSON.parse(data.toString());
|
|
2680
|
+
} catch {
|
|
2681
|
+
return;
|
|
2682
|
+
}
|
|
2683
|
+
if (typeof msg.id !== "number") return;
|
|
2684
|
+
const cb = this.pending.get(msg.id);
|
|
2685
|
+
if (!cb) return;
|
|
2686
|
+
this.pending.delete(msg.id);
|
|
2687
|
+
if (msg.error) {
|
|
2688
|
+
cb.reject(new Error(msg.error.message ?? "CDP error"));
|
|
2689
|
+
} else {
|
|
2690
|
+
cb.resolve(msg.result ?? {});
|
|
2691
|
+
}
|
|
2692
|
+
});
|
|
2693
|
+
ws.on("close", () => {
|
|
2694
|
+
for (const cb of this.pending.values()) {
|
|
2695
|
+
cb.reject(new Error("CDP WebSocket closed"));
|
|
2696
|
+
}
|
|
2697
|
+
this.pending.clear();
|
|
2698
|
+
});
|
|
2699
|
+
ws.on("error", (err) => {
|
|
2700
|
+
for (const cb of this.pending.values()) {
|
|
2701
|
+
cb.reject(err);
|
|
2702
|
+
}
|
|
2703
|
+
this.pending.clear();
|
|
2704
|
+
});
|
|
2705
|
+
}
|
|
2706
|
+
nextId = 0;
|
|
2707
|
+
pending = /* @__PURE__ */ new Map();
|
|
2708
|
+
send(method, params = {}, sessionId) {
|
|
2709
|
+
const id = ++this.nextId;
|
|
2710
|
+
const payload = { id, method, params };
|
|
2711
|
+
if (sessionId) payload.sessionId = sessionId;
|
|
2712
|
+
return new Promise((resolve2, reject) => {
|
|
2713
|
+
this.pending.set(id, {
|
|
2714
|
+
resolve: (r) => resolve2(r),
|
|
2715
|
+
reject
|
|
2716
|
+
});
|
|
2717
|
+
this.ws.send(JSON.stringify(payload));
|
|
2718
|
+
});
|
|
2719
|
+
}
|
|
2720
|
+
close() {
|
|
2721
|
+
try {
|
|
2722
|
+
this.ws.close();
|
|
2723
|
+
} catch {
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2726
|
+
};
|
|
2727
|
+
function waitForDevToolsUrl(child, timeoutMs = 5e3) {
|
|
2728
|
+
return new Promise((resolve2, reject) => {
|
|
2729
|
+
let buf = "";
|
|
2730
|
+
const onData = (d) => {
|
|
2731
|
+
buf += d.toString();
|
|
2732
|
+
const m = buf.match(/DevTools listening on (ws:\/\/\S+)/);
|
|
2733
|
+
if (m) {
|
|
2734
|
+
cleanup();
|
|
2735
|
+
resolve2(m[1]);
|
|
2736
|
+
}
|
|
2737
|
+
};
|
|
2738
|
+
const onExit = (code) => {
|
|
2739
|
+
cleanup();
|
|
2740
|
+
reject(
|
|
2741
|
+
new Error(
|
|
2742
|
+
`Chrome exited (code ${code}) before exposing a DevTools port. Last stderr: ${buf.slice(-500)}`
|
|
2743
|
+
)
|
|
2744
|
+
);
|
|
2745
|
+
};
|
|
2746
|
+
const cleanup = () => {
|
|
2747
|
+
child.stderr?.off("data", onData);
|
|
2748
|
+
child.off("exit", onExit);
|
|
2749
|
+
clearTimeout(timer);
|
|
2750
|
+
};
|
|
2751
|
+
const timer = setTimeout(() => {
|
|
2752
|
+
cleanup();
|
|
2753
|
+
reject(
|
|
2754
|
+
new Error(`Chrome did not expose a DevTools port within ${timeoutMs}ms`)
|
|
2755
|
+
);
|
|
2756
|
+
}, timeoutMs);
|
|
2757
|
+
child.stderr?.on("data", onData);
|
|
2758
|
+
child.on("exit", onExit);
|
|
2759
|
+
});
|
|
2760
|
+
}
|
|
2761
|
+
async function captureScreenshot(opts) {
|
|
2762
|
+
let userDataDir;
|
|
2763
|
+
let child;
|
|
2764
|
+
let cdp;
|
|
2765
|
+
let cleanedUp = false;
|
|
2766
|
+
const cleanup = () => {
|
|
2767
|
+
if (cleanedUp) return;
|
|
2768
|
+
cleanedUp = true;
|
|
2769
|
+
cdp?.close();
|
|
2770
|
+
if (child && !child.killed) {
|
|
2771
|
+
try {
|
|
2772
|
+
child.kill("SIGTERM");
|
|
2773
|
+
} catch {
|
|
2774
|
+
}
|
|
2775
|
+
const localChild = child;
|
|
2776
|
+
const killTimer = setTimeout(() => {
|
|
2777
|
+
if (!localChild.killed) {
|
|
2778
|
+
try {
|
|
2779
|
+
localChild.kill("SIGKILL");
|
|
2780
|
+
} catch {
|
|
2781
|
+
}
|
|
2782
|
+
}
|
|
2783
|
+
}, 2e3);
|
|
2784
|
+
killTimer.unref();
|
|
2785
|
+
}
|
|
2786
|
+
if (userDataDir) {
|
|
2787
|
+
try {
|
|
2788
|
+
(0, import_node_fs6.rmSync)(userDataDir, { recursive: true, force: true });
|
|
2789
|
+
} catch {
|
|
2790
|
+
}
|
|
2791
|
+
}
|
|
2792
|
+
};
|
|
2793
|
+
try {
|
|
2794
|
+
let wsUrl;
|
|
2795
|
+
if (opts.cdpUrl) {
|
|
2796
|
+
wsUrl = opts.cdpUrl;
|
|
2797
|
+
} else {
|
|
2798
|
+
if (!opts.chromePath) {
|
|
2799
|
+
throw new Error(
|
|
2800
|
+
"captureScreenshot requires either `cdpUrl` or `chromePath`"
|
|
2801
|
+
);
|
|
2802
|
+
}
|
|
2803
|
+
userDataDir = (0, import_node_fs6.mkdtempSync)(import_node_path4.default.join(import_node_os5.default.tmpdir(), "mcp-use-chrome-"));
|
|
2804
|
+
const chromeArgs = [
|
|
2805
|
+
"--headless=new",
|
|
2806
|
+
"--remote-debugging-port=0",
|
|
2807
|
+
`--user-data-dir=${userDataDir}`,
|
|
2808
|
+
"--no-first-run",
|
|
2809
|
+
"--no-default-browser-check",
|
|
2810
|
+
"--disable-extensions",
|
|
2811
|
+
"--disable-gpu",
|
|
2812
|
+
"--hide-scrollbars",
|
|
2813
|
+
"--mute-audio",
|
|
2814
|
+
`--window-size=${opts.width},${opts.height}`,
|
|
2815
|
+
"about:blank"
|
|
2816
|
+
];
|
|
2817
|
+
child = (0, import_node_child_process8.spawn)(opts.chromePath, chromeArgs, {
|
|
2818
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
2819
|
+
});
|
|
2820
|
+
child.stdout?.resume();
|
|
2821
|
+
wsUrl = await waitForDevToolsUrl(child);
|
|
2822
|
+
}
|
|
2823
|
+
const ws = new import_ws.default(wsUrl);
|
|
2824
|
+
await new Promise((resolve2, reject) => {
|
|
2825
|
+
const onOpen = () => {
|
|
2826
|
+
ws.off("error", onError);
|
|
2827
|
+
resolve2();
|
|
2828
|
+
};
|
|
2829
|
+
const onError = (err) => {
|
|
2830
|
+
ws.off("open", onOpen);
|
|
2831
|
+
reject(err);
|
|
2832
|
+
};
|
|
2833
|
+
ws.once("open", onOpen);
|
|
2834
|
+
ws.once("error", onError);
|
|
2835
|
+
});
|
|
2836
|
+
cdp = new CdpClient(ws);
|
|
2837
|
+
let sessionId;
|
|
2838
|
+
if (opts.cdpUrl) {
|
|
2839
|
+
const attachPromise = new Promise((resolve2, reject) => {
|
|
2840
|
+
const timer = setTimeout(
|
|
2841
|
+
() => reject(
|
|
2842
|
+
new Error(
|
|
2843
|
+
"Timed out waiting for Target.attachedToTarget event from remote CDP"
|
|
2844
|
+
)
|
|
2845
|
+
),
|
|
2846
|
+
1e4
|
|
2847
|
+
);
|
|
2848
|
+
const onMessage = (data) => {
|
|
2849
|
+
try {
|
|
2850
|
+
const msg = JSON.parse(data.toString());
|
|
2851
|
+
if (msg.method === "Target.attachedToTarget" && msg.params?.targetInfo?.type === "page" && typeof msg.params.sessionId === "string") {
|
|
2852
|
+
clearTimeout(timer);
|
|
2853
|
+
ws.off("message", onMessage);
|
|
2854
|
+
resolve2(msg.params.sessionId);
|
|
2855
|
+
}
|
|
2856
|
+
} catch {
|
|
2857
|
+
}
|
|
2858
|
+
};
|
|
2859
|
+
ws.on("message", onMessage);
|
|
2860
|
+
});
|
|
2861
|
+
await cdp.send("Target.setAutoAttach", {
|
|
2862
|
+
autoAttach: true,
|
|
2863
|
+
waitForDebuggerOnStart: false,
|
|
2864
|
+
flatten: true
|
|
2865
|
+
});
|
|
2866
|
+
sessionId = await attachPromise;
|
|
2867
|
+
} else {
|
|
2868
|
+
const { targetId } = await cdp.send(
|
|
2869
|
+
"Target.createTarget",
|
|
2870
|
+
{ url: "about:blank" }
|
|
2871
|
+
);
|
|
2872
|
+
const attach = await cdp.send(
|
|
2873
|
+
"Target.attachToTarget",
|
|
2874
|
+
{ targetId, flatten: true }
|
|
2875
|
+
);
|
|
2876
|
+
sessionId = attach.sessionId;
|
|
2877
|
+
}
|
|
2878
|
+
await cdp.send("Page.enable", {}, sessionId);
|
|
2879
|
+
await cdp.send(
|
|
2880
|
+
"Emulation.setDeviceMetricsOverride",
|
|
2881
|
+
{
|
|
2882
|
+
width: opts.width,
|
|
2883
|
+
height: opts.height,
|
|
2884
|
+
deviceScaleFactor: 1,
|
|
2885
|
+
mobile: false
|
|
2886
|
+
},
|
|
2887
|
+
sessionId
|
|
2888
|
+
);
|
|
2889
|
+
await cdp.send(
|
|
2890
|
+
"Emulation.setEmulatedMedia",
|
|
2891
|
+
{
|
|
2892
|
+
features: [
|
|
2893
|
+
{ name: "prefers-color-scheme", value: opts.theme },
|
|
2894
|
+
{ name: "prefers-reduced-motion", value: "reduce" }
|
|
2895
|
+
]
|
|
2896
|
+
},
|
|
2897
|
+
sessionId
|
|
2898
|
+
);
|
|
2899
|
+
if (opts.bundle !== void 0) {
|
|
2900
|
+
const payload = JSON.stringify(JSON.stringify(opts.bundle));
|
|
2901
|
+
await cdp.send(
|
|
2902
|
+
"Page.addScriptToEvaluateOnNewDocument",
|
|
2903
|
+
{
|
|
2904
|
+
source: `globalThis.__mcpUsePreviewBundle = JSON.parse(${payload});`,
|
|
2905
|
+
runImmediately: true
|
|
2906
|
+
},
|
|
2907
|
+
sessionId
|
|
2908
|
+
);
|
|
2909
|
+
}
|
|
2910
|
+
await cdp.send("Page.navigate", { url: opts.url }, sessionId);
|
|
2911
|
+
const start = Date.now();
|
|
2912
|
+
const exprSelector = JSON.stringify(opts.waitForSelector);
|
|
2913
|
+
while (true) {
|
|
2914
|
+
const r = await cdp.send(
|
|
2915
|
+
"Runtime.evaluate",
|
|
2916
|
+
{
|
|
2917
|
+
expression: `!!document.querySelector(${exprSelector})`,
|
|
2918
|
+
returnByValue: true
|
|
2919
|
+
},
|
|
2920
|
+
sessionId
|
|
2921
|
+
);
|
|
2922
|
+
if (r.result?.value === true) break;
|
|
2923
|
+
if (Date.now() - start > opts.timeoutMs) {
|
|
2924
|
+
throw new Error(
|
|
2925
|
+
`Timed out after ${opts.timeoutMs}ms waiting for selector "${opts.waitForSelector}"`
|
|
2926
|
+
);
|
|
2927
|
+
}
|
|
2928
|
+
await new Promise((res) => setTimeout(res, 100));
|
|
2929
|
+
}
|
|
2930
|
+
if (opts.delayMs && opts.delayMs > 0) {
|
|
2931
|
+
await new Promise((res) => setTimeout(res, opts.delayMs));
|
|
2932
|
+
}
|
|
2933
|
+
const shot = await cdp.send(
|
|
2934
|
+
"Page.captureScreenshot",
|
|
2935
|
+
{
|
|
2936
|
+
format: "png",
|
|
2937
|
+
clip: {
|
|
2938
|
+
x: 0,
|
|
2939
|
+
y: 0,
|
|
2940
|
+
width: opts.width,
|
|
2941
|
+
height: opts.height,
|
|
2942
|
+
scale: 1
|
|
2943
|
+
}
|
|
2944
|
+
},
|
|
2945
|
+
sessionId
|
|
2946
|
+
);
|
|
2947
|
+
(0, import_node_fs6.writeFileSync)(opts.outputPath, Buffer.from(shot.data, "base64"));
|
|
2948
|
+
} finally {
|
|
2949
|
+
cleanup();
|
|
2950
|
+
}
|
|
2951
|
+
}
|
|
2952
|
+
|
|
2953
|
+
// src/utils/chrome-path.ts
|
|
2954
|
+
var import_node_fs7 = require("fs");
|
|
2955
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
2956
|
+
var ENV_VAR_NAMES = [
|
|
2957
|
+
"MCP_USE_CHROME_PATH",
|
|
2958
|
+
"PUPPETEER_EXECUTABLE_PATH",
|
|
2959
|
+
"CHROME_PATH"
|
|
2960
|
+
];
|
|
2961
|
+
var DARWIN_PATHS = [
|
|
2962
|
+
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
2963
|
+
"/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary",
|
|
2964
|
+
"/Applications/Chromium.app/Contents/MacOS/Chromium",
|
|
2965
|
+
"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
|
|
2966
|
+
"/Applications/Brave Browser.app/Contents/MacOS/Brave Browser"
|
|
2967
|
+
];
|
|
2968
|
+
var LINUX_BINARIES = [
|
|
2969
|
+
"google-chrome-stable",
|
|
2970
|
+
"google-chrome",
|
|
2971
|
+
"chromium",
|
|
2972
|
+
"chromium-browser",
|
|
2973
|
+
"microsoft-edge",
|
|
2974
|
+
"microsoft-edge-stable",
|
|
2975
|
+
"brave-browser"
|
|
2976
|
+
];
|
|
2977
|
+
var WIN_SUBPATHS = [
|
|
2978
|
+
"Google\\Chrome\\Application\\chrome.exe",
|
|
2979
|
+
"Microsoft\\Edge\\Application\\msedge.exe",
|
|
2980
|
+
"BraveSoftware\\Brave-Browser\\Application\\brave.exe",
|
|
2981
|
+
"Chromium\\Application\\chrome.exe"
|
|
2982
|
+
];
|
|
2983
|
+
function isAccessible(p) {
|
|
2984
|
+
try {
|
|
2985
|
+
(0, import_node_fs7.accessSync)(p, import_node_fs7.constants.F_OK);
|
|
2986
|
+
return true;
|
|
2987
|
+
} catch {
|
|
2988
|
+
return false;
|
|
2989
|
+
}
|
|
2990
|
+
}
|
|
2991
|
+
function findOnPath(binary) {
|
|
2992
|
+
const PATH = process.env.PATH ?? "";
|
|
2993
|
+
for (const dir of PATH.split(":")) {
|
|
2994
|
+
if (!dir) continue;
|
|
2995
|
+
const candidate = import_node_path5.default.posix.join(dir, binary);
|
|
2996
|
+
if (isAccessible(candidate)) return candidate;
|
|
2997
|
+
}
|
|
2998
|
+
return null;
|
|
2999
|
+
}
|
|
3000
|
+
function findChrome() {
|
|
3001
|
+
for (const name of ENV_VAR_NAMES) {
|
|
3002
|
+
const v = process.env[name];
|
|
3003
|
+
if (v && isAccessible(v)) return v;
|
|
3004
|
+
}
|
|
3005
|
+
if (process.platform === "darwin") {
|
|
3006
|
+
for (const p of DARWIN_PATHS) {
|
|
3007
|
+
if (isAccessible(p)) return p;
|
|
3008
|
+
}
|
|
3009
|
+
return null;
|
|
3010
|
+
}
|
|
3011
|
+
if (process.platform === "linux") {
|
|
3012
|
+
for (const bin of LINUX_BINARIES) {
|
|
3013
|
+
const p = findOnPath(bin);
|
|
3014
|
+
if (p) return p;
|
|
3015
|
+
}
|
|
2250
3016
|
return null;
|
|
2251
3017
|
}
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
}
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
}
|
|
2266
|
-
|
|
2267
|
-
|
|
3018
|
+
if (process.platform === "win32") {
|
|
3019
|
+
const dirs = [
|
|
3020
|
+
process.env["ProgramFiles"],
|
|
3021
|
+
process.env["ProgramFiles(x86)"],
|
|
3022
|
+
process.env["LocalAppData"]
|
|
3023
|
+
].filter((d) => Boolean(d));
|
|
3024
|
+
for (const dir of dirs) {
|
|
3025
|
+
for (const sub of WIN_SUBPATHS) {
|
|
3026
|
+
const candidate = import_node_path5.default.join(dir, sub);
|
|
3027
|
+
if (isAccessible(candidate)) return candidate;
|
|
3028
|
+
}
|
|
3029
|
+
}
|
|
3030
|
+
return null;
|
|
3031
|
+
}
|
|
3032
|
+
return null;
|
|
3033
|
+
}
|
|
3034
|
+
function resolveChromePath() {
|
|
3035
|
+
const found = findChrome();
|
|
3036
|
+
if (found) return found;
|
|
3037
|
+
throw new Error(
|
|
3038
|
+
"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."
|
|
3039
|
+
);
|
|
3040
|
+
}
|
|
3041
|
+
|
|
3042
|
+
// src/commands/screenshot.ts
|
|
3043
|
+
function parseHeaderArg(raw) {
|
|
3044
|
+
const idx = raw.indexOf(":");
|
|
3045
|
+
if (idx === -1) {
|
|
3046
|
+
throw new Error(
|
|
3047
|
+
`Invalid --header value "${raw}". Expected "Key: Value" (e.g. "Authorization: Bearer xyz").`
|
|
3048
|
+
);
|
|
3049
|
+
}
|
|
3050
|
+
const key = raw.slice(0, idx).trim();
|
|
3051
|
+
const value = raw.slice(idx + 1).trim();
|
|
3052
|
+
if (!key) {
|
|
3053
|
+
throw new Error(`Invalid --header value "${raw}". Header name is empty.`);
|
|
3054
|
+
}
|
|
3055
|
+
return [key, value];
|
|
3056
|
+
}
|
|
3057
|
+
function parseHeaderArgs(args) {
|
|
3058
|
+
const headers = {};
|
|
3059
|
+
for (const raw of args) {
|
|
3060
|
+
const [key, value] = parseHeaderArg(raw);
|
|
3061
|
+
headers[key] = value;
|
|
3062
|
+
}
|
|
3063
|
+
return headers;
|
|
3064
|
+
}
|
|
3065
|
+
function collectHeader(value, previous = []) {
|
|
3066
|
+
return previous.concat([value]);
|
|
3067
|
+
}
|
|
3068
|
+
function detectToolResourceUri(tool) {
|
|
3069
|
+
if (!tool) return null;
|
|
3070
|
+
const meta = tool._meta;
|
|
3071
|
+
if (!meta) return null;
|
|
3072
|
+
const uiMeta = meta.ui ?? void 0;
|
|
3073
|
+
return uiMeta?.resourceUri ?? meta["openai/outputTemplate"] ?? null;
|
|
3074
|
+
}
|
|
3075
|
+
async function captureToolScreenshot(inputs, options = {}) {
|
|
3076
|
+
const width = options.width ?? 800;
|
|
3077
|
+
const height = options.height ?? 600;
|
|
3078
|
+
const theme = options.theme ?? "light";
|
|
3079
|
+
const timeoutMs = options.timeoutMs ?? 3e4;
|
|
3080
|
+
const delayMs = options.delayMs ?? 0;
|
|
3081
|
+
const chromePath = options.cdpUrl ? void 0 : resolveChromePath();
|
|
3082
|
+
const view = extractViewName(inputs.resourceUri);
|
|
3083
|
+
const devOptions = {
|
|
3084
|
+
width: String(width),
|
|
3085
|
+
height: String(height),
|
|
3086
|
+
theme,
|
|
3087
|
+
timeout: String(timeoutMs),
|
|
3088
|
+
inspector: options.inspector,
|
|
3089
|
+
quiet: options.quiet
|
|
3090
|
+
};
|
|
3091
|
+
let devHandle;
|
|
3092
|
+
try {
|
|
3093
|
+
devHandle = await ensureDevServer(devOptions);
|
|
3094
|
+
const resourceContents = await inputs.session.readResource(
|
|
3095
|
+
inputs.resourceUri
|
|
3096
|
+
);
|
|
3097
|
+
const bundle = {
|
|
3098
|
+
resourceUri: inputs.resourceUri,
|
|
3099
|
+
resourceContents,
|
|
3100
|
+
toolInput: inputs.toolArgs,
|
|
3101
|
+
toolOutput: inputs.toolOutput
|
|
3102
|
+
};
|
|
3103
|
+
const previewUrl = new URL(`/inspector/preview/${view}`, devHandle.url);
|
|
3104
|
+
previewUrl.searchParams.set("theme", theme);
|
|
3105
|
+
const ts = timestampSuffix();
|
|
3106
|
+
const outputPath = import_node_path6.default.resolve(options.output ?? `./${view}-${ts}.png`);
|
|
3107
|
+
await (0, import_promises5.mkdir)(import_node_path6.default.dirname(outputPath), { recursive: true });
|
|
3108
|
+
await captureScreenshot({
|
|
3109
|
+
url: previewUrl.toString(),
|
|
3110
|
+
width,
|
|
3111
|
+
height,
|
|
3112
|
+
theme,
|
|
3113
|
+
waitForSelector: options.waitFor ?? 'body[data-view-ready="true"]',
|
|
3114
|
+
timeoutMs,
|
|
3115
|
+
outputPath,
|
|
3116
|
+
chromePath,
|
|
3117
|
+
cdpUrl: options.cdpUrl,
|
|
3118
|
+
delayMs: Number.isFinite(delayMs) && delayMs > 0 ? delayMs : 0,
|
|
3119
|
+
bundle
|
|
3120
|
+
});
|
|
3121
|
+
return { outputPath, width, height, view };
|
|
3122
|
+
} finally {
|
|
3123
|
+
killChild(devHandle?.child);
|
|
3124
|
+
}
|
|
3125
|
+
}
|
|
3126
|
+
function getFreePort() {
|
|
3127
|
+
return new Promise((resolve2, reject) => {
|
|
3128
|
+
const srv = (0, import_node_net.createServer)();
|
|
3129
|
+
srv.unref();
|
|
3130
|
+
srv.on("error", reject);
|
|
3131
|
+
srv.listen(0, () => {
|
|
3132
|
+
const addr = srv.address();
|
|
3133
|
+
if (typeof addr === "object" && addr) {
|
|
3134
|
+
const port = addr.port;
|
|
3135
|
+
srv.close(() => resolve2(port));
|
|
3136
|
+
} else {
|
|
3137
|
+
srv.close(() => reject(new Error("Failed to allocate free port")));
|
|
3138
|
+
}
|
|
3139
|
+
});
|
|
3140
|
+
});
|
|
3141
|
+
}
|
|
3142
|
+
async function probeServer(url, timeoutMs = 1500) {
|
|
3143
|
+
const controller = new AbortController();
|
|
3144
|
+
const t = setTimeout(() => controller.abort(), timeoutMs);
|
|
3145
|
+
try {
|
|
3146
|
+
const u = new URL("/inspector/health", url);
|
|
3147
|
+
const res = await fetch(u, { signal: controller.signal });
|
|
3148
|
+
if (!res.ok) return false;
|
|
3149
|
+
const ct = res.headers.get("content-type") ?? "";
|
|
3150
|
+
if (!ct.includes("application/json")) return false;
|
|
3151
|
+
const body = await res.json();
|
|
3152
|
+
return body?.status === "ok";
|
|
3153
|
+
} catch {
|
|
3154
|
+
return false;
|
|
3155
|
+
} finally {
|
|
3156
|
+
clearTimeout(t);
|
|
3157
|
+
}
|
|
3158
|
+
}
|
|
3159
|
+
async function waitForHealth(url, timeoutMs = 15e3) {
|
|
3160
|
+
const deadline = Date.now() + timeoutMs;
|
|
3161
|
+
while (Date.now() < deadline) {
|
|
3162
|
+
if (await probeServer(url)) return true;
|
|
3163
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
3164
|
+
}
|
|
3165
|
+
return false;
|
|
3166
|
+
}
|
|
3167
|
+
function resolveInspectorCli() {
|
|
3168
|
+
const candidateRoots = /* @__PURE__ */ new Set();
|
|
3169
|
+
const moduleDir = typeof __dirname !== "undefined" ? __dirname : import_node_path6.default.dirname(new URL(importMetaUrl).pathname);
|
|
3170
|
+
candidateRoots.add(moduleDir);
|
|
3171
|
+
candidateRoots.add(process.cwd());
|
|
3172
|
+
for (const start of candidateRoots) {
|
|
3173
|
+
let dir = start;
|
|
3174
|
+
while (true) {
|
|
3175
|
+
const candidate = import_node_path6.default.join(
|
|
3176
|
+
dir,
|
|
3177
|
+
"node_modules",
|
|
3178
|
+
"@mcp-use",
|
|
3179
|
+
"inspector",
|
|
3180
|
+
"dist",
|
|
3181
|
+
"cli.js"
|
|
3182
|
+
);
|
|
3183
|
+
if ((0, import_node_fs8.existsSync)(candidate)) return candidate;
|
|
3184
|
+
const parent = import_node_path6.default.dirname(dir);
|
|
3185
|
+
if (parent === dir) break;
|
|
3186
|
+
dir = parent;
|
|
3187
|
+
}
|
|
3188
|
+
}
|
|
3189
|
+
throw new Error(
|
|
3190
|
+
"Could not locate `@mcp-use/inspector` in node_modules. Install the inspector package or pass --inspector <url> to use an existing instance."
|
|
3191
|
+
);
|
|
3192
|
+
}
|
|
3193
|
+
async function ensureDevServer(options) {
|
|
3194
|
+
if (options.inspector) {
|
|
3195
|
+
const ok = await probeServer(options.inspector);
|
|
3196
|
+
if (!ok) {
|
|
3197
|
+
throw new Error(
|
|
3198
|
+
`Inspector at ${options.inspector} did not respond on /inspector/health with status:"ok"`
|
|
3199
|
+
);
|
|
3200
|
+
}
|
|
3201
|
+
return { url: options.inspector };
|
|
3202
|
+
}
|
|
3203
|
+
const port = await getFreePort();
|
|
3204
|
+
const url = `http://localhost:${port}`;
|
|
3205
|
+
if (!options.quiet) {
|
|
3206
|
+
console.error(formatInfo(`Starting inspector on port ${port}\u2026`));
|
|
3207
|
+
}
|
|
3208
|
+
const inspectorCli = resolveInspectorCli();
|
|
3209
|
+
const child = (0, import_node_child_process9.spawn)(
|
|
3210
|
+
process.execPath,
|
|
3211
|
+
[inspectorCli, "--port", String(port), "--no-open"],
|
|
3212
|
+
{
|
|
3213
|
+
cwd: process.cwd(),
|
|
3214
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
3215
|
+
env: { ...process.env, MCP_INSPECTOR_MODE: "standalone" }
|
|
3216
|
+
}
|
|
3217
|
+
);
|
|
3218
|
+
const prefix = source_default.gray("[inspector]");
|
|
3219
|
+
if (!options.quiet) {
|
|
3220
|
+
child.stdout?.on("data", (d) => {
|
|
3221
|
+
process.stderr.write(`${prefix} ${d}`);
|
|
3222
|
+
});
|
|
3223
|
+
child.stderr?.on("data", (d) => {
|
|
3224
|
+
process.stderr.write(`${prefix} ${d}`);
|
|
3225
|
+
});
|
|
3226
|
+
} else {
|
|
3227
|
+
child.stdout?.resume();
|
|
3228
|
+
child.stderr?.resume();
|
|
3229
|
+
}
|
|
3230
|
+
const ready = await waitForHealth(url);
|
|
3231
|
+
if (!ready) {
|
|
3232
|
+
child.kill("SIGTERM");
|
|
3233
|
+
throw new Error(`Inspector failed to come up on ${url} within 15s.`);
|
|
3234
|
+
}
|
|
3235
|
+
return { url, child };
|
|
3236
|
+
}
|
|
3237
|
+
function killChild(child) {
|
|
3238
|
+
if (!child || child.killed) return;
|
|
3239
|
+
try {
|
|
3240
|
+
child.kill("SIGTERM");
|
|
3241
|
+
} catch {
|
|
3242
|
+
}
|
|
3243
|
+
}
|
|
3244
|
+
function timestampSuffix(date = /* @__PURE__ */ new Date()) {
|
|
3245
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
3246
|
+
const datePart = `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
|
|
3247
|
+
const timePart = `${pad(date.getHours())}-${pad(date.getMinutes())}-${pad(date.getSeconds())}`;
|
|
3248
|
+
return `${datePart}_${timePart}`;
|
|
3249
|
+
}
|
|
3250
|
+
function extractViewName(resourceUri) {
|
|
3251
|
+
const m = resourceUri.match(/^ui:\/\/widget\/(.+)$/);
|
|
3252
|
+
if (!m) return resourceUri;
|
|
3253
|
+
return m[1].replace(/\.html$/, "").replace(/\.[0-9a-f]+$/i, "");
|
|
3254
|
+
}
|
|
3255
|
+
function parseDimension(raw, name) {
|
|
3256
|
+
const n = parseInt(raw, 10);
|
|
3257
|
+
if (!Number.isFinite(n) || n <= 0) {
|
|
3258
|
+
throw new Error(`--${name} must be a positive integer (got "${raw}")`);
|
|
3259
|
+
}
|
|
3260
|
+
return n;
|
|
3261
|
+
}
|
|
3262
|
+
var AD_HOC_SESSION_NAME = "__screenshot_ad_hoc__";
|
|
3263
|
+
async function resolveSessionForScreenshot(options, headers) {
|
|
3264
|
+
if (options.session) {
|
|
3265
|
+
const result = await getOrRestoreSession(options.session);
|
|
3266
|
+
return result?.session ?? null;
|
|
3267
|
+
}
|
|
3268
|
+
if (options.mcp) {
|
|
3269
|
+
const client = new import_client2.MCPClient();
|
|
3270
|
+
client.addServer(AD_HOC_SESSION_NAME, {
|
|
3271
|
+
url: options.mcp,
|
|
3272
|
+
...headers ? { headers } : {},
|
|
3273
|
+
clientInfo: getCliClientInfo()
|
|
3274
|
+
});
|
|
3275
|
+
try {
|
|
3276
|
+
const session = await client.createSession(AD_HOC_SESSION_NAME);
|
|
3277
|
+
activeSessions.set(AD_HOC_SESSION_NAME, { client, session });
|
|
3278
|
+
return session;
|
|
3279
|
+
} catch (err) {
|
|
3280
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
3281
|
+
console.error(formatError(`Failed to connect to ${options.mcp}: ${msg}`));
|
|
3282
|
+
return null;
|
|
3283
|
+
}
|
|
3284
|
+
}
|
|
3285
|
+
console.error(
|
|
3286
|
+
formatError(
|
|
3287
|
+
"No MCP target. Pass --session <name> (a saved server) or --mcp <url> (ad-hoc)."
|
|
3288
|
+
)
|
|
3289
|
+
);
|
|
3290
|
+
return null;
|
|
3291
|
+
}
|
|
3292
|
+
async function screenshotCommand(options, argsList) {
|
|
3293
|
+
let exitCode = 0;
|
|
3294
|
+
try {
|
|
3295
|
+
if (!options.tool) {
|
|
3296
|
+
console.error(
|
|
3297
|
+
formatError(
|
|
3298
|
+
"--tool <name> is required (optionally with key=value args)."
|
|
3299
|
+
)
|
|
3300
|
+
);
|
|
3301
|
+
exitCode = 1;
|
|
3302
|
+
return;
|
|
3303
|
+
}
|
|
3304
|
+
let headers;
|
|
3305
|
+
if (options.header && options.header.length > 0) {
|
|
3306
|
+
if (!options.mcp) {
|
|
3307
|
+
console.error(
|
|
3308
|
+
formatError(
|
|
3309
|
+
"--header is only supported with --mcp <url>. Saved sessions (use --session) carry their own auth from `mcp-use client connect`."
|
|
3310
|
+
)
|
|
3311
|
+
);
|
|
3312
|
+
exitCode = 1;
|
|
3313
|
+
return;
|
|
3314
|
+
}
|
|
3315
|
+
try {
|
|
3316
|
+
headers = parseHeaderArgs(options.header);
|
|
3317
|
+
} catch (err) {
|
|
3318
|
+
console.error(
|
|
3319
|
+
formatError(err instanceof Error ? err.message : String(err))
|
|
3320
|
+
);
|
|
3321
|
+
exitCode = 1;
|
|
3322
|
+
return;
|
|
3323
|
+
}
|
|
3324
|
+
}
|
|
3325
|
+
try {
|
|
3326
|
+
resolveChromePath();
|
|
3327
|
+
} catch (err) {
|
|
3328
|
+
console.error(
|
|
3329
|
+
formatError(err instanceof Error ? err.message : String(err))
|
|
3330
|
+
);
|
|
3331
|
+
exitCode = 1;
|
|
3332
|
+
return;
|
|
3333
|
+
}
|
|
3334
|
+
const width = parseDimension(options.width, "width");
|
|
3335
|
+
const height = parseDimension(options.height, "height");
|
|
3336
|
+
const navTimeout = parseInt(options.timeout, 10) || 3e4;
|
|
3337
|
+
const delayMs = options.delay ? parseInt(options.delay, 10) : 0;
|
|
3338
|
+
const session = await resolveSessionForScreenshot(options, headers);
|
|
3339
|
+
if (!session) {
|
|
3340
|
+
exitCode = 1;
|
|
3341
|
+
return;
|
|
3342
|
+
}
|
|
3343
|
+
const tool = session.tools.find((t) => t.name === options.tool);
|
|
3344
|
+
if (!tool) {
|
|
3345
|
+
throw new Error(
|
|
3346
|
+
`Tool "${options.tool}" not found. Available: ${session.tools.map((t) => t.name).join(", ")}`
|
|
3347
|
+
);
|
|
3348
|
+
}
|
|
3349
|
+
const resourceUri = detectToolResourceUri(tool);
|
|
3350
|
+
if (!resourceUri) {
|
|
3351
|
+
throw new Error(
|
|
3352
|
+
`Tool "${options.tool}" does not declare a UI resource (expected _meta.ui.resourceUri or openai/outputTemplate).`
|
|
3353
|
+
);
|
|
3354
|
+
}
|
|
3355
|
+
let toolArgs = {};
|
|
3356
|
+
if (argsList && argsList.length > 0) {
|
|
3357
|
+
try {
|
|
3358
|
+
toolArgs = parseToolArgs(
|
|
3359
|
+
argsList,
|
|
3360
|
+
tool.inputSchema
|
|
3361
|
+
);
|
|
3362
|
+
} catch (err) {
|
|
3363
|
+
console.error(
|
|
3364
|
+
formatError(err instanceof Error ? err.message : String(err))
|
|
3365
|
+
);
|
|
3366
|
+
console.log("");
|
|
3367
|
+
console.log(formatInfo("Usage:"));
|
|
3368
|
+
console.log(
|
|
3369
|
+
` npx mcp-use screenshot --tool ${options.tool} key=value [key2=value2 ...]`
|
|
3370
|
+
);
|
|
3371
|
+
console.log(
|
|
3372
|
+
` npx mcp-use screenshot --tool ${options.tool} nested:='{"a":1}' # JSON value`
|
|
3373
|
+
);
|
|
3374
|
+
console.log(
|
|
3375
|
+
` npx mcp-use screenshot --tool ${options.tool} '{"key":"value"}' # full JSON object`
|
|
3376
|
+
);
|
|
3377
|
+
if (tool.inputSchema) {
|
|
3378
|
+
console.log("");
|
|
3379
|
+
console.log(formatInfo("Tool schema:"));
|
|
3380
|
+
console.log(formatSchema(tool.inputSchema));
|
|
3381
|
+
}
|
|
3382
|
+
exitCode = 1;
|
|
3383
|
+
return;
|
|
3384
|
+
}
|
|
3385
|
+
}
|
|
3386
|
+
const toolOutput = await session.callTool(options.tool, toolArgs);
|
|
3387
|
+
const result = await captureToolScreenshot(
|
|
3388
|
+
{
|
|
3389
|
+
session,
|
|
3390
|
+
toolName: options.tool,
|
|
3391
|
+
toolArgs,
|
|
3392
|
+
toolOutput,
|
|
3393
|
+
resourceUri
|
|
3394
|
+
},
|
|
3395
|
+
{
|
|
3396
|
+
width,
|
|
3397
|
+
height,
|
|
3398
|
+
theme: options.theme,
|
|
3399
|
+
output: options.output,
|
|
3400
|
+
waitFor: options.waitFor,
|
|
3401
|
+
delayMs,
|
|
3402
|
+
timeoutMs: navTimeout,
|
|
3403
|
+
inspector: options.inspector,
|
|
3404
|
+
quiet: options.quiet,
|
|
3405
|
+
cdpUrl: options.cdpUrl
|
|
3406
|
+
}
|
|
3407
|
+
);
|
|
3408
|
+
console.log(
|
|
3409
|
+
`Saved screenshot: ${result.outputPath} (${result.width}\xD7${result.height})`
|
|
3410
|
+
);
|
|
3411
|
+
} catch (err) {
|
|
3412
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
3413
|
+
console.error(formatError(`Screenshot failed: ${msg}`));
|
|
3414
|
+
exitCode = 1;
|
|
3415
|
+
} finally {
|
|
3416
|
+
await cleanupAndExit(exitCode);
|
|
3417
|
+
}
|
|
3418
|
+
}
|
|
3419
|
+
function createScreenshotCommand() {
|
|
3420
|
+
return new import_commander.Command("screenshot").description(
|
|
3421
|
+
"Render an MCP Apps view headlessly and save a PNG by calling a tool and rendering its UI resource with the result."
|
|
3422
|
+
).argument(
|
|
3423
|
+
"[args...]",
|
|
3424
|
+
"Tool args as key=value pairs (use key:=<json> for nested values, or pass a single JSON object)."
|
|
3425
|
+
).option(
|
|
3426
|
+
"--tool <name>",
|
|
3427
|
+
"Tool to call. Its UI resource is rendered with the result."
|
|
3428
|
+
).option("--width <px>", "Browser viewport width in pixels.", "800").option("--height <px>", "Browser viewport height in pixels.", "600").option(
|
|
3429
|
+
"--inspector <url>",
|
|
3430
|
+
"Inspector host that serves /inspector/preview/:view. When omitted, probes localhost:3000 then auto-spawns `mcp-use dev`."
|
|
3431
|
+
).option(
|
|
3432
|
+
"--session <name>",
|
|
3433
|
+
"Saved server name (from `mcp-use client connect <name> <url>`)."
|
|
3434
|
+
).option(
|
|
3435
|
+
"--mcp <url>",
|
|
3436
|
+
"Ad-hoc MCP server URL (escape hatch). Use when you don't have a saved server. No authentication unless --header is supplied."
|
|
3437
|
+
).option(
|
|
3438
|
+
"-H, --header <header>",
|
|
3439
|
+
'HTTP header to send to the --mcp <url> server, formatted "Key: Value". Repeatable. Use to pass an Authorization bearer token or other auth headers when screenshotting an authenticated MCP server.',
|
|
3440
|
+
collectHeader,
|
|
3441
|
+
[]
|
|
3442
|
+
).option(
|
|
3443
|
+
"--theme <light|dark>",
|
|
3444
|
+
"Color scheme to render the view in.",
|
|
3445
|
+
"light"
|
|
3446
|
+
).option(
|
|
3447
|
+
"--output <path>",
|
|
3448
|
+
"Output PNG path. Defaults to ./<view>-<timestamp>.png in cwd."
|
|
3449
|
+
).option(
|
|
3450
|
+
"--wait-for <selector>",
|
|
3451
|
+
'Override readiness selector (default: body[data-view-ready="true"]).'
|
|
3452
|
+
).option(
|
|
3453
|
+
"--delay <ms>",
|
|
3454
|
+
"Extra wait after readiness, to let chart animations / async layouts settle.",
|
|
3455
|
+
"0"
|
|
3456
|
+
).option("--timeout <ms>", "Navigation + readiness timeout in ms.", "30000").option(
|
|
3457
|
+
"--cdp-url <url>",
|
|
3458
|
+
"Connect to an existing CDP WebSocket (ws:// or wss://) instead of spawning local Chrome. Useful for hosted browsers like Notte."
|
|
3459
|
+
).option("--quiet", "Suppress dev-server output.").action(async (args, opts) => {
|
|
3460
|
+
await screenshotCommand(opts, args);
|
|
3461
|
+
});
|
|
3462
|
+
}
|
|
3463
|
+
|
|
3464
|
+
// src/commands/client.ts
|
|
3465
|
+
var RESERVED_CLIENT_SUBCOMMANDS = /* @__PURE__ */ new Set([
|
|
3466
|
+
"connect",
|
|
3467
|
+
"list",
|
|
3468
|
+
"remove",
|
|
3469
|
+
"help"
|
|
3470
|
+
]);
|
|
3471
|
+
var PER_CLIENT_SCOPES = /* @__PURE__ */ new Set([
|
|
3472
|
+
"tools",
|
|
3473
|
+
"resources",
|
|
3474
|
+
"prompts",
|
|
3475
|
+
"auth",
|
|
3476
|
+
"disconnect",
|
|
3477
|
+
"interactive"
|
|
3478
|
+
]);
|
|
3479
|
+
async function connectCommand(name, urlOrCommand, options) {
|
|
3480
|
+
if (!name || !urlOrCommand) {
|
|
3481
|
+
const looksLikeUrl = !!name && /^https?:\/\//i.test(name);
|
|
3482
|
+
if (looksLikeUrl && !urlOrCommand && !options.stdio) {
|
|
3483
|
+
console.error(formatError("Missing server name."));
|
|
3484
|
+
console.error("");
|
|
3485
|
+
console.error(
|
|
3486
|
+
formatInfo(
|
|
3487
|
+
"Each saved server needs a short name you'll use to address it later."
|
|
3488
|
+
)
|
|
3489
|
+
);
|
|
3490
|
+
console.error("");
|
|
3491
|
+
console.error("Try:");
|
|
3492
|
+
console.error(` mcp-use client connect <name> ${name}`);
|
|
3493
|
+
console.error("");
|
|
3494
|
+
console.error("Example:");
|
|
3495
|
+
console.error(` mcp-use client connect my-server ${name}`);
|
|
3496
|
+
console.error(" mcp-use client my-server tools list");
|
|
3497
|
+
} else if (name && !urlOrCommand) {
|
|
3498
|
+
console.error(
|
|
3499
|
+
formatError(options.stdio ? "Missing <command>." : "Missing <url>.")
|
|
3500
|
+
);
|
|
3501
|
+
console.error("");
|
|
3502
|
+
console.error(formatInfo("Usage:"));
|
|
3503
|
+
console.error(
|
|
3504
|
+
options.stdio ? ` mcp-use client connect ${name} "<command>" --stdio` : ` mcp-use client connect ${name} <url>`
|
|
3505
|
+
);
|
|
3506
|
+
} else {
|
|
3507
|
+
console.error(formatError("Missing required arguments: <name> <url>."));
|
|
3508
|
+
console.error("");
|
|
3509
|
+
console.error(formatInfo("Usage:"));
|
|
3510
|
+
console.error(" mcp-use client connect <name> <url>");
|
|
3511
|
+
console.error("");
|
|
3512
|
+
console.error("Example:");
|
|
3513
|
+
console.error(
|
|
3514
|
+
" mcp-use client connect manufact https://mcp.manufact.com/mcp"
|
|
3515
|
+
);
|
|
3516
|
+
}
|
|
3517
|
+
await cleanupAndExit(1);
|
|
3518
|
+
}
|
|
3519
|
+
const sessionName = name;
|
|
3520
|
+
const target = urlOrCommand;
|
|
3521
|
+
if (PER_CLIENT_SCOPES.has(sessionName)) {
|
|
3522
|
+
console.error(
|
|
3523
|
+
formatError(
|
|
3524
|
+
`'${sessionName}' is a reserved name and can't be used for a saved server.`
|
|
3525
|
+
)
|
|
3526
|
+
);
|
|
3527
|
+
console.error("");
|
|
3528
|
+
console.error(
|
|
3529
|
+
`Reserved names: ${Array.from(PER_CLIENT_SCOPES).sort().join(", ")}`
|
|
3530
|
+
);
|
|
3531
|
+
console.error("");
|
|
3532
|
+
console.error("Pick a different name, e.g.:");
|
|
3533
|
+
console.error(` mcp-use client connect my-${sessionName} ${target}`);
|
|
3534
|
+
await cleanupAndExit(1);
|
|
3535
|
+
}
|
|
2268
3536
|
try {
|
|
2269
|
-
const
|
|
2270
|
-
const client = new import_client.MCPClient();
|
|
3537
|
+
const client = new import_client3.MCPClient();
|
|
2271
3538
|
let session;
|
|
2272
3539
|
const cliClientInfo = getCliClientInfo();
|
|
2273
3540
|
if (options.stdio) {
|
|
2274
|
-
const parts =
|
|
3541
|
+
const parts = target.split(" ");
|
|
2275
3542
|
const command = parts[0];
|
|
2276
3543
|
const args = parts.slice(1);
|
|
2277
3544
|
console.error(
|
|
@@ -2290,17 +3557,41 @@ async function connectCommand(urlOrCommand, options) {
|
|
|
2290
3557
|
lastUsed: (/* @__PURE__ */ new Date()).toISOString()
|
|
2291
3558
|
});
|
|
2292
3559
|
} else {
|
|
2293
|
-
console.error(formatInfo(`Connecting to ${
|
|
3560
|
+
console.error(formatInfo(`Connecting to ${target}...`));
|
|
3561
|
+
const wantOAuth = !options.auth && options.oauth !== false;
|
|
3562
|
+
let authProvider;
|
|
3563
|
+
if (wantOAuth) {
|
|
3564
|
+
const authTimeoutMs = options.authTimeout ? Number.parseInt(options.authTimeout, 10) : void 0;
|
|
3565
|
+
authProvider = await buildOAuthProvider(target, {
|
|
3566
|
+
...authTimeoutMs ? { authTimeoutMs } : {}
|
|
3567
|
+
});
|
|
3568
|
+
}
|
|
2294
3569
|
client.addServer(sessionName, {
|
|
2295
|
-
url:
|
|
2296
|
-
|
|
3570
|
+
url: target,
|
|
3571
|
+
...authProvider ? { authProvider } : options.auth ? { headers: { Authorization: `Bearer ${options.auth}` } } : {},
|
|
2297
3572
|
clientInfo: cliClientInfo
|
|
2298
3573
|
});
|
|
2299
|
-
|
|
3574
|
+
try {
|
|
3575
|
+
session = await client.createSession(sessionName);
|
|
3576
|
+
} catch (err) {
|
|
3577
|
+
if (authProvider && isUnauthorized(err)) {
|
|
3578
|
+
console.error(
|
|
3579
|
+
formatWarning(
|
|
3580
|
+
"Server requires authentication. Starting OAuth flow."
|
|
3581
|
+
)
|
|
3582
|
+
);
|
|
3583
|
+
await runOAuthFlow(authProvider, target);
|
|
3584
|
+
console.error(formatSuccess("Authentication successful"));
|
|
3585
|
+
session = await client.createSession(sessionName);
|
|
3586
|
+
} else {
|
|
3587
|
+
throw err;
|
|
3588
|
+
}
|
|
3589
|
+
}
|
|
2300
3590
|
await saveSession(sessionName, {
|
|
2301
3591
|
type: "http",
|
|
2302
|
-
url:
|
|
2303
|
-
|
|
3592
|
+
url: target,
|
|
3593
|
+
authMode: authProvider ? "oauth" : options.auth ? "bearer" : void 0,
|
|
3594
|
+
authToken: authProvider ? void 0 : options.auth,
|
|
2304
3595
|
lastUsed: (/* @__PURE__ */ new Date()).toISOString()
|
|
2305
3596
|
});
|
|
2306
3597
|
}
|
|
@@ -2310,7 +3601,7 @@ async function connectCommand(urlOrCommand, options) {
|
|
|
2310
3601
|
if (serverInfo) {
|
|
2311
3602
|
await updateSessionInfo(sessionName, serverInfo, capabilities);
|
|
2312
3603
|
}
|
|
2313
|
-
console.log(formatSuccess(`Connected
|
|
3604
|
+
console.log(formatSuccess(`Connected as '${sessionName}'`));
|
|
2314
3605
|
if (serverInfo) {
|
|
2315
3606
|
console.log("");
|
|
2316
3607
|
console.log(formatHeader("Server Information:"));
|
|
@@ -2336,119 +3627,173 @@ async function connectCommand(urlOrCommand, options) {
|
|
|
2336
3627
|
);
|
|
2337
3628
|
} catch (error) {
|
|
2338
3629
|
console.error(formatError(`Connection failed: ${error.message}`));
|
|
2339
|
-
|
|
3630
|
+
await cleanupAndExit(1);
|
|
2340
3631
|
}
|
|
3632
|
+
await cleanupAndExit(0);
|
|
2341
3633
|
}
|
|
2342
|
-
async function disconnectCommand(
|
|
3634
|
+
async function disconnectCommand(name) {
|
|
2343
3635
|
try {
|
|
2344
|
-
|
|
2345
|
-
for (const [name, { client }] of activeSessions.entries()) {
|
|
2346
|
-
await client.closeAllSessions();
|
|
2347
|
-
activeSessions.delete(name);
|
|
2348
|
-
console.log(formatSuccess(`Disconnected from ${name}`));
|
|
2349
|
-
}
|
|
2350
|
-
return;
|
|
2351
|
-
}
|
|
2352
|
-
if (!sessionName) {
|
|
2353
|
-
const active = await getActiveSession();
|
|
2354
|
-
if (!active) {
|
|
2355
|
-
console.error(formatError("No active session to disconnect"));
|
|
2356
|
-
return;
|
|
2357
|
-
}
|
|
2358
|
-
sessionName = active.name;
|
|
2359
|
-
}
|
|
2360
|
-
const sessionData = activeSessions.get(sessionName);
|
|
3636
|
+
const sessionData = activeSessions.get(name);
|
|
2361
3637
|
if (sessionData) {
|
|
2362
3638
|
await sessionData.client.closeAllSessions();
|
|
2363
|
-
activeSessions.delete(
|
|
2364
|
-
console.log(formatSuccess(`Disconnected from ${
|
|
3639
|
+
activeSessions.delete(name);
|
|
3640
|
+
console.log(formatSuccess(`Disconnected from ${name}`));
|
|
2365
3641
|
} else {
|
|
2366
|
-
console.log(formatInfo(`
|
|
3642
|
+
console.log(formatInfo(`Server '${name}' is not connected`));
|
|
2367
3643
|
}
|
|
2368
3644
|
} catch (error) {
|
|
2369
3645
|
console.error(formatError(`Failed to disconnect: ${error.message}`));
|
|
2370
|
-
|
|
3646
|
+
await cleanupAndExit(1);
|
|
3647
|
+
}
|
|
3648
|
+
await cleanupAndExit(0);
|
|
3649
|
+
}
|
|
3650
|
+
async function removeClientCommand(name) {
|
|
3651
|
+
try {
|
|
3652
|
+
const config = await getSession(name);
|
|
3653
|
+
if (!config) {
|
|
3654
|
+
console.error(formatError(`Server '${name}' not found`));
|
|
3655
|
+
console.error("");
|
|
3656
|
+
console.error("See your saved servers with:");
|
|
3657
|
+
console.error(" mcp-use client list");
|
|
3658
|
+
await cleanupAndExit(1);
|
|
3659
|
+
}
|
|
3660
|
+
const sessionData = activeSessions.get(name);
|
|
3661
|
+
if (sessionData) {
|
|
3662
|
+
await sessionData.client.closeAllSessions();
|
|
3663
|
+
activeSessions.delete(name);
|
|
3664
|
+
}
|
|
3665
|
+
const isOAuthHttp = config.type === "http" && config.authMode === "oauth" && typeof config.url === "string";
|
|
3666
|
+
const sharedUrlSibling = isOAuthHttp ? (await listAllSessions()).find(
|
|
3667
|
+
(s) => s.name !== name && s.config.type === "http" && s.config.url === config.url
|
|
3668
|
+
) : void 0;
|
|
3669
|
+
await removeSession(name);
|
|
3670
|
+
console.log(formatSuccess(`Removed saved server '${name}'`));
|
|
3671
|
+
if (isOAuthHttp) {
|
|
3672
|
+
if (sharedUrlSibling) {
|
|
3673
|
+
console.log(
|
|
3674
|
+
formatInfo(
|
|
3675
|
+
`OAuth tokens for ${config.url} were kept because saved server '${sharedUrlSibling.name}' still uses that URL.`
|
|
3676
|
+
)
|
|
3677
|
+
);
|
|
3678
|
+
} else {
|
|
3679
|
+
try {
|
|
3680
|
+
const provider = await buildOAuthProvider(config.url);
|
|
3681
|
+
await provider.invalidateCredentials("all");
|
|
3682
|
+
console.log(formatInfo(`Removed OAuth tokens for ${config.url}`));
|
|
3683
|
+
} catch (error) {
|
|
3684
|
+
console.error(
|
|
3685
|
+
formatWarning(
|
|
3686
|
+
`Saved entry removed, but failed to clear OAuth tokens for ${config.url}: ${error.message}`
|
|
3687
|
+
)
|
|
3688
|
+
);
|
|
3689
|
+
}
|
|
3690
|
+
}
|
|
3691
|
+
}
|
|
3692
|
+
} catch (error) {
|
|
3693
|
+
console.error(formatError(`Failed to remove server: ${error.message}`));
|
|
3694
|
+
await cleanupAndExit(1);
|
|
2371
3695
|
}
|
|
3696
|
+
await cleanupAndExit(0);
|
|
2372
3697
|
}
|
|
2373
|
-
async function
|
|
3698
|
+
async function listClientsCommand() {
|
|
2374
3699
|
try {
|
|
2375
3700
|
const sessions = await listAllSessions();
|
|
2376
3701
|
if (sessions.length === 0) {
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
3702
|
+
if (isStdoutTty()) {
|
|
3703
|
+
console.log(formatInfo("No saved servers"));
|
|
3704
|
+
console.log(
|
|
3705
|
+
formatInfo(
|
|
3706
|
+
"Connect to a server with: npx mcp-use client connect <name> <url>"
|
|
3707
|
+
)
|
|
3708
|
+
);
|
|
3709
|
+
}
|
|
2381
3710
|
return;
|
|
2382
3711
|
}
|
|
2383
|
-
|
|
2384
|
-
|
|
3712
|
+
const tty2 = isStdoutTty();
|
|
3713
|
+
if (tty2) {
|
|
3714
|
+
console.log(formatHeader("Saved Servers:"));
|
|
3715
|
+
console.log("");
|
|
3716
|
+
}
|
|
2385
3717
|
const tableData = sessions.map((s) => ({
|
|
2386
|
-
name: s.
|
|
3718
|
+
name: s.name,
|
|
2387
3719
|
type: s.config.type,
|
|
2388
3720
|
target: s.config.type === "http" ? s.config.url || "" : `${s.config.command} ${(s.config.args || []).join(" ")}`,
|
|
2389
|
-
server: s.config.serverInfo?.name || "unknown"
|
|
2390
|
-
status: activeSessions.has(s.name) ? source_default.green("connected") : source_default.gray("disconnected")
|
|
3721
|
+
server: s.config.serverInfo?.name || "unknown"
|
|
2391
3722
|
}));
|
|
2392
3723
|
console.log(
|
|
2393
3724
|
formatTable(tableData, [
|
|
2394
3725
|
{ key: "name", header: "Name" },
|
|
2395
3726
|
{ key: "type", header: "Type" },
|
|
2396
|
-
{ key: "target", header: "Target",
|
|
2397
|
-
{ key: "server", header: "Server" }
|
|
2398
|
-
{ key: "status", header: "Status" }
|
|
3727
|
+
{ key: "target", header: "Target", truncate: true },
|
|
3728
|
+
{ key: "server", header: "Server" }
|
|
2399
3729
|
])
|
|
2400
3730
|
);
|
|
2401
|
-
console.log("");
|
|
2402
|
-
console.log(source_default.gray("* = active session"));
|
|
2403
|
-
} catch (error) {
|
|
2404
|
-
console.error(formatError(`Failed to list sessions: ${error.message}`));
|
|
2405
|
-
process.exit(1);
|
|
2406
|
-
}
|
|
2407
|
-
}
|
|
2408
|
-
async function switchSessionCommand(name) {
|
|
2409
|
-
try {
|
|
2410
|
-
await setActiveSession(name);
|
|
2411
|
-
console.log(formatSuccess(`Switched to session '${name}'`));
|
|
2412
3731
|
} catch (error) {
|
|
2413
|
-
console.error(formatError(`Failed to
|
|
2414
|
-
|
|
3732
|
+
console.error(formatError(`Failed to list servers: ${error.message}`));
|
|
3733
|
+
await cleanupAndExit(1);
|
|
2415
3734
|
}
|
|
3735
|
+
await cleanupAndExit(0);
|
|
2416
3736
|
}
|
|
2417
|
-
async function listToolsCommand(options) {
|
|
3737
|
+
async function listToolsCommand(name, options) {
|
|
2418
3738
|
try {
|
|
2419
|
-
const result = await getOrRestoreSession(
|
|
2420
|
-
if (!result)
|
|
3739
|
+
const result = await getOrRestoreSession(name);
|
|
3740
|
+
if (!result) {
|
|
3741
|
+
await cleanupAndExit(1);
|
|
3742
|
+
}
|
|
2421
3743
|
const { session } = result;
|
|
2422
3744
|
const tools = await session.listTools();
|
|
2423
3745
|
if (options.json) {
|
|
2424
3746
|
console.log(formatJson(tools));
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
3747
|
+
} else if (tools.length === 0) {
|
|
3748
|
+
if (isStdoutTty()) console.log(formatInfo("No tools available"));
|
|
3749
|
+
} else {
|
|
3750
|
+
const tty2 = isStdoutTty();
|
|
3751
|
+
if (tty2) {
|
|
3752
|
+
console.log(formatHeader(`Available Tools (${tools.length}):`));
|
|
3753
|
+
console.log("");
|
|
3754
|
+
}
|
|
3755
|
+
const tableData = tools.map((tool) => {
|
|
3756
|
+
const props = tool.inputSchema?.properties ?? {};
|
|
3757
|
+
const required = tool.inputSchema?.required ?? [];
|
|
3758
|
+
const total = Object.keys(props).length;
|
|
3759
|
+
const reqCount = Array.isArray(required) ? required.length : 0;
|
|
3760
|
+
const argsCell = total === 0 ? source_default.gray("\u2014") : `${reqCount}/${total}`;
|
|
3761
|
+
return {
|
|
3762
|
+
name: source_default.bold(tool.name),
|
|
3763
|
+
mode: formatToolMode(tool.annotations),
|
|
3764
|
+
args: argsCell,
|
|
3765
|
+
description: tool.description || source_default.gray("(no description)")
|
|
3766
|
+
};
|
|
3767
|
+
});
|
|
3768
|
+
console.log(
|
|
3769
|
+
formatTable(tableData, [
|
|
3770
|
+
{ key: "name", header: "Tool" },
|
|
3771
|
+
{ key: "mode", header: "Mode" },
|
|
3772
|
+
{ key: "args", header: "Args" },
|
|
3773
|
+
{ key: "description", header: "Description", truncate: true }
|
|
3774
|
+
])
|
|
3775
|
+
);
|
|
3776
|
+
if (tty2) {
|
|
3777
|
+
console.log("");
|
|
3778
|
+
console.log(
|
|
3779
|
+
source_default.gray(
|
|
3780
|
+
"ARGS shows required/total. Modes: read-only \xB7 write \xB7 destructive."
|
|
3781
|
+
)
|
|
3782
|
+
);
|
|
3783
|
+
}
|
|
2430
3784
|
}
|
|
2431
|
-
console.log(formatHeader(`Available Tools (${tools.length}):`));
|
|
2432
|
-
console.log("");
|
|
2433
|
-
const tableData = tools.map((tool) => ({
|
|
2434
|
-
name: source_default.bold(tool.name),
|
|
2435
|
-
description: tool.description || source_default.gray("No description")
|
|
2436
|
-
}));
|
|
2437
|
-
console.log(
|
|
2438
|
-
formatTable(tableData, [
|
|
2439
|
-
{ key: "name", header: "Tool", width: 25 },
|
|
2440
|
-
{ key: "description", header: "Description", width: 50 }
|
|
2441
|
-
])
|
|
2442
|
-
);
|
|
2443
3785
|
} catch (error) {
|
|
2444
3786
|
console.error(formatError(`Failed to list tools: ${error.message}`));
|
|
2445
|
-
|
|
3787
|
+
await cleanupAndExit(1);
|
|
2446
3788
|
}
|
|
3789
|
+
await cleanupAndExit(0);
|
|
2447
3790
|
}
|
|
2448
|
-
async function describeToolCommand(
|
|
3791
|
+
async function describeToolCommand(name, toolName) {
|
|
2449
3792
|
try {
|
|
2450
|
-
const result = await getOrRestoreSession(
|
|
2451
|
-
if (!result)
|
|
3793
|
+
const result = await getOrRestoreSession(name);
|
|
3794
|
+
if (!result) {
|
|
3795
|
+
await cleanupAndExit(1);
|
|
3796
|
+
}
|
|
2452
3797
|
const { session } = result;
|
|
2453
3798
|
const tools = session.tools;
|
|
2454
3799
|
const tool = tools.find((t) => t.name === toolName);
|
|
@@ -2457,7 +3802,7 @@ async function describeToolCommand(toolName, options) {
|
|
|
2457
3802
|
console.log("");
|
|
2458
3803
|
console.log(formatInfo("Available tools:"));
|
|
2459
3804
|
tools.forEach((t) => console.log(` \u2022 ${t.name}`));
|
|
2460
|
-
|
|
3805
|
+
await cleanupAndExit(1);
|
|
2461
3806
|
}
|
|
2462
3807
|
console.log(formatHeader(`Tool: ${tool.name}`));
|
|
2463
3808
|
console.log("");
|
|
@@ -2471,94 +3816,167 @@ async function describeToolCommand(toolName, options) {
|
|
|
2471
3816
|
}
|
|
2472
3817
|
} catch (error) {
|
|
2473
3818
|
console.error(formatError(`Failed to describe tool: ${error.message}`));
|
|
2474
|
-
|
|
3819
|
+
await cleanupAndExit(1);
|
|
2475
3820
|
}
|
|
3821
|
+
await cleanupAndExit(0);
|
|
2476
3822
|
}
|
|
2477
|
-
async function callToolCommand(toolName,
|
|
3823
|
+
async function callToolCommand(name, toolName, argsList, options) {
|
|
2478
3824
|
try {
|
|
2479
|
-
const result = await getOrRestoreSession(
|
|
2480
|
-
if (!result)
|
|
3825
|
+
const result = await getOrRestoreSession(name);
|
|
3826
|
+
if (!result) {
|
|
3827
|
+
await cleanupAndExit(1);
|
|
3828
|
+
}
|
|
2481
3829
|
const { session } = result;
|
|
3830
|
+
const tools = session.tools;
|
|
3831
|
+
const tool = tools.find((t) => t.name === toolName);
|
|
2482
3832
|
let args = {};
|
|
2483
|
-
if (
|
|
3833
|
+
if (argsList && argsList.length > 0) {
|
|
2484
3834
|
try {
|
|
2485
|
-
args =
|
|
3835
|
+
args = parseToolArgs(argsList, tool?.inputSchema);
|
|
2486
3836
|
} catch (error) {
|
|
2487
|
-
console.error(formatError(
|
|
2488
|
-
return;
|
|
2489
|
-
}
|
|
2490
|
-
} else {
|
|
2491
|
-
const tools = session.tools;
|
|
2492
|
-
const tool = tools.find((t) => t.name === toolName);
|
|
2493
|
-
if (tool?.inputSchema?.required && tool.inputSchema.required.length > 0) {
|
|
2494
|
-
console.error(
|
|
2495
|
-
formatError(
|
|
2496
|
-
"This tool requires arguments. Provide them as a JSON string."
|
|
2497
|
-
)
|
|
2498
|
-
);
|
|
3837
|
+
console.error(formatError(error.message));
|
|
2499
3838
|
console.log("");
|
|
2500
|
-
console.log(formatInfo("
|
|
3839
|
+
console.log(formatInfo("Usage:"));
|
|
2501
3840
|
console.log(
|
|
2502
|
-
` npx mcp-use client tools call ${toolName}
|
|
3841
|
+
` npx mcp-use client ${name} tools call ${toolName} key=value [key2=value2 ...]`
|
|
2503
3842
|
);
|
|
2504
|
-
console.log(
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
3843
|
+
console.log(
|
|
3844
|
+
` npx mcp-use client ${name} tools call ${toolName} nested:='{"a":1}' # JSON value`
|
|
3845
|
+
);
|
|
3846
|
+
console.log(
|
|
3847
|
+
` npx mcp-use client ${name} tools call ${toolName} '{"key":"value"}' # full JSON object`
|
|
3848
|
+
);
|
|
3849
|
+
if (tool?.inputSchema) {
|
|
3850
|
+
console.log("");
|
|
3851
|
+
console.log(formatInfo("Tool schema:"));
|
|
3852
|
+
console.log(formatSchema(tool.inputSchema));
|
|
3853
|
+
}
|
|
3854
|
+
await cleanupAndExit(1);
|
|
2508
3855
|
}
|
|
3856
|
+
} else if (tool?.inputSchema?.required && tool.inputSchema.required.length > 0) {
|
|
3857
|
+
console.error(formatError("This tool requires arguments."));
|
|
3858
|
+
console.log("");
|
|
3859
|
+
console.log(formatInfo("Provide arguments as key=value pairs:"));
|
|
3860
|
+
console.log(
|
|
3861
|
+
` npx mcp-use client ${name} tools call ${toolName} key=value [key2=value2 ...]`
|
|
3862
|
+
);
|
|
3863
|
+
console.log("");
|
|
3864
|
+
console.log(formatInfo("Tool schema:"));
|
|
3865
|
+
console.log(formatSchema(tool.inputSchema));
|
|
3866
|
+
await cleanupAndExit(1);
|
|
2509
3867
|
}
|
|
2510
3868
|
console.error(formatInfo(`Calling tool '${toolName}'...`));
|
|
2511
3869
|
const callResult = await session.callTool(toolName, args, {
|
|
2512
3870
|
timeout: options?.timeout
|
|
2513
3871
|
});
|
|
3872
|
+
let screenshot = null;
|
|
3873
|
+
let screenshotError = null;
|
|
3874
|
+
if (options?.screenshot !== false) {
|
|
3875
|
+
const tool2 = session.tools.find((t) => t.name === toolName);
|
|
3876
|
+
const resourceUri = detectToolResourceUri(tool2);
|
|
3877
|
+
if (resourceUri) {
|
|
3878
|
+
console.error(
|
|
3879
|
+
formatInfo(`Capturing widget screenshot (${resourceUri})...`)
|
|
3880
|
+
);
|
|
3881
|
+
try {
|
|
3882
|
+
const shot = await captureToolScreenshot(
|
|
3883
|
+
{
|
|
3884
|
+
session,
|
|
3885
|
+
toolName,
|
|
3886
|
+
toolArgs: args,
|
|
3887
|
+
toolOutput: callResult,
|
|
3888
|
+
resourceUri
|
|
3889
|
+
},
|
|
3890
|
+
options?.screenshotOutput ? { output: options.screenshotOutput } : {}
|
|
3891
|
+
);
|
|
3892
|
+
screenshot = {
|
|
3893
|
+
path: shot.outputPath,
|
|
3894
|
+
width: shot.width,
|
|
3895
|
+
height: shot.height,
|
|
3896
|
+
view: shot.view
|
|
3897
|
+
};
|
|
3898
|
+
} catch (err) {
|
|
3899
|
+
screenshotError = err?.message ?? String(err);
|
|
3900
|
+
}
|
|
3901
|
+
}
|
|
3902
|
+
}
|
|
2514
3903
|
if (options?.json) {
|
|
2515
3904
|
console.log(formatJson(callResult));
|
|
2516
3905
|
} else {
|
|
2517
3906
|
console.log(formatToolCall(callResult));
|
|
2518
3907
|
}
|
|
3908
|
+
if (screenshot) {
|
|
3909
|
+
console.error(
|
|
3910
|
+
formatSuccess(
|
|
3911
|
+
`Saved widget screenshot: ${screenshot.path} (${screenshot.width}\xD7${screenshot.height})`
|
|
3912
|
+
)
|
|
3913
|
+
);
|
|
3914
|
+
}
|
|
3915
|
+
if (screenshotError) {
|
|
3916
|
+
console.error(
|
|
3917
|
+
formatWarning(`Skipped widget screenshot: ${screenshotError}`)
|
|
3918
|
+
);
|
|
3919
|
+
}
|
|
3920
|
+
if (callResult.isError) {
|
|
3921
|
+
await cleanupAndExit(1);
|
|
3922
|
+
}
|
|
2519
3923
|
} catch (error) {
|
|
2520
3924
|
console.error(formatError(`Failed to call tool: ${error.message}`));
|
|
2521
|
-
|
|
3925
|
+
if (error?.data !== void 0) {
|
|
3926
|
+
console.error(
|
|
3927
|
+
source_default.gray(
|
|
3928
|
+
typeof error.data === "string" ? error.data : formatJson(error.data)
|
|
3929
|
+
)
|
|
3930
|
+
);
|
|
3931
|
+
}
|
|
3932
|
+
await cleanupAndExit(1);
|
|
2522
3933
|
}
|
|
3934
|
+
await cleanupAndExit(0);
|
|
2523
3935
|
}
|
|
2524
|
-
async function listResourcesCommand(options) {
|
|
3936
|
+
async function listResourcesCommand(name, options) {
|
|
2525
3937
|
try {
|
|
2526
|
-
const result = await getOrRestoreSession(
|
|
2527
|
-
if (!result)
|
|
3938
|
+
const result = await getOrRestoreSession(name);
|
|
3939
|
+
if (!result) {
|
|
3940
|
+
await cleanupAndExit(1);
|
|
3941
|
+
}
|
|
2528
3942
|
const { session } = result;
|
|
2529
3943
|
const resourcesResult = await session.listAllResources();
|
|
2530
3944
|
const resources = resourcesResult.resources;
|
|
2531
3945
|
if (options.json) {
|
|
2532
3946
|
console.log(formatJson(resources));
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
3947
|
+
} else if (resources.length === 0) {
|
|
3948
|
+
if (isStdoutTty()) console.log(formatInfo("No resources available"));
|
|
3949
|
+
} else {
|
|
3950
|
+
const tty2 = isStdoutTty();
|
|
3951
|
+
if (tty2) {
|
|
3952
|
+
console.log(formatHeader(`Available Resources (${resources.length}):`));
|
|
3953
|
+
console.log("");
|
|
3954
|
+
}
|
|
3955
|
+
const tableData = resources.map((resource) => ({
|
|
3956
|
+
name: source_default.bold(resource.name || "(no name)"),
|
|
3957
|
+
type: resource.mimeType || source_default.gray("unknown"),
|
|
3958
|
+
uri: resource.uri
|
|
3959
|
+
}));
|
|
3960
|
+
console.log(
|
|
3961
|
+
formatTable(tableData, [
|
|
3962
|
+
{ key: "name", header: "Name" },
|
|
3963
|
+
{ key: "type", header: "Type" },
|
|
3964
|
+
{ key: "uri", header: "URI", truncate: true }
|
|
3965
|
+
])
|
|
3966
|
+
);
|
|
2538
3967
|
}
|
|
2539
|
-
console.log(formatHeader(`Available Resources (${resources.length}):`));
|
|
2540
|
-
console.log("");
|
|
2541
|
-
const tableData = resources.map((resource) => ({
|
|
2542
|
-
uri: resource.uri,
|
|
2543
|
-
name: resource.name || source_default.gray("(no name)"),
|
|
2544
|
-
type: resource.mimeType || source_default.gray("unknown")
|
|
2545
|
-
}));
|
|
2546
|
-
console.log(
|
|
2547
|
-
formatTable(tableData, [
|
|
2548
|
-
{ key: "uri", header: "URI", width: 40 },
|
|
2549
|
-
{ key: "name", header: "Name", width: 20 },
|
|
2550
|
-
{ key: "type", header: "Type", width: 15 }
|
|
2551
|
-
])
|
|
2552
|
-
);
|
|
2553
3968
|
} catch (error) {
|
|
2554
3969
|
console.error(formatError(`Failed to list resources: ${error.message}`));
|
|
2555
|
-
|
|
3970
|
+
await cleanupAndExit(1);
|
|
2556
3971
|
}
|
|
3972
|
+
await cleanupAndExit(0);
|
|
2557
3973
|
}
|
|
2558
|
-
async function readResourceCommand(uri, options) {
|
|
3974
|
+
async function readResourceCommand(name, uri, options) {
|
|
2559
3975
|
try {
|
|
2560
|
-
const result = await getOrRestoreSession(
|
|
2561
|
-
if (!result)
|
|
3976
|
+
const result = await getOrRestoreSession(name);
|
|
3977
|
+
if (!result) {
|
|
3978
|
+
await cleanupAndExit(1);
|
|
3979
|
+
}
|
|
2562
3980
|
const { session } = result;
|
|
2563
3981
|
console.error(formatInfo(`Reading resource: ${uri}`));
|
|
2564
3982
|
const resource = await session.readResource(uri);
|
|
@@ -2569,13 +3987,16 @@ async function readResourceCommand(uri, options) {
|
|
|
2569
3987
|
}
|
|
2570
3988
|
} catch (error) {
|
|
2571
3989
|
console.error(formatError(`Failed to read resource: ${error.message}`));
|
|
2572
|
-
|
|
3990
|
+
await cleanupAndExit(1);
|
|
2573
3991
|
}
|
|
3992
|
+
await cleanupAndExit(0);
|
|
2574
3993
|
}
|
|
2575
|
-
async function subscribeResourceCommand(
|
|
3994
|
+
async function subscribeResourceCommand(name, uri) {
|
|
2576
3995
|
try {
|
|
2577
|
-
const result = await getOrRestoreSession(
|
|
2578
|
-
if (!result)
|
|
3996
|
+
const result = await getOrRestoreSession(name);
|
|
3997
|
+
if (!result) {
|
|
3998
|
+
await cleanupAndExit(1);
|
|
3999
|
+
}
|
|
2579
4000
|
const { session } = result;
|
|
2580
4001
|
await session.subscribeToResource(uri);
|
|
2581
4002
|
console.log(formatSuccess(`Subscribed to resource: ${uri}`));
|
|
@@ -2593,13 +4014,15 @@ async function subscribeResourceCommand(uri, options) {
|
|
|
2593
4014
|
console.error(
|
|
2594
4015
|
formatError(`Failed to subscribe to resource: ${error.message}`)
|
|
2595
4016
|
);
|
|
2596
|
-
|
|
4017
|
+
await cleanupAndExit(1);
|
|
2597
4018
|
}
|
|
2598
4019
|
}
|
|
2599
|
-
async function unsubscribeResourceCommand(
|
|
4020
|
+
async function unsubscribeResourceCommand(name, uri) {
|
|
2600
4021
|
try {
|
|
2601
|
-
const result = await getOrRestoreSession(
|
|
2602
|
-
if (!result)
|
|
4022
|
+
const result = await getOrRestoreSession(name);
|
|
4023
|
+
if (!result) {
|
|
4024
|
+
await cleanupAndExit(1);
|
|
4025
|
+
}
|
|
2603
4026
|
const { session } = result;
|
|
2604
4027
|
await session.unsubscribeFromResource(uri);
|
|
2605
4028
|
console.log(formatSuccess(`Unsubscribed from resource: ${uri}`));
|
|
@@ -2607,53 +4030,76 @@ async function unsubscribeResourceCommand(uri, options) {
|
|
|
2607
4030
|
console.error(
|
|
2608
4031
|
formatError(`Failed to unsubscribe from resource: ${error.message}`)
|
|
2609
4032
|
);
|
|
2610
|
-
|
|
4033
|
+
await cleanupAndExit(1);
|
|
2611
4034
|
}
|
|
4035
|
+
await cleanupAndExit(0);
|
|
2612
4036
|
}
|
|
2613
|
-
async function listPromptsCommand(options) {
|
|
4037
|
+
async function listPromptsCommand(name, options) {
|
|
2614
4038
|
try {
|
|
2615
|
-
const result = await getOrRestoreSession(
|
|
2616
|
-
if (!result)
|
|
4039
|
+
const result = await getOrRestoreSession(name);
|
|
4040
|
+
if (!result) {
|
|
4041
|
+
await cleanupAndExit(1);
|
|
4042
|
+
}
|
|
2617
4043
|
const { session } = result;
|
|
2618
4044
|
const promptsResult = await session.listPrompts();
|
|
2619
4045
|
const prompts = promptsResult.prompts;
|
|
2620
4046
|
if (options.json) {
|
|
2621
4047
|
console.log(formatJson(prompts));
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
4048
|
+
} else if (prompts.length === 0) {
|
|
4049
|
+
if (isStdoutTty()) console.log(formatInfo("No prompts available"));
|
|
4050
|
+
} else {
|
|
4051
|
+
const tty2 = isStdoutTty();
|
|
4052
|
+
if (tty2) {
|
|
4053
|
+
console.log(formatHeader(`Available Prompts (${prompts.length}):`));
|
|
4054
|
+
console.log("");
|
|
4055
|
+
}
|
|
4056
|
+
const tableData = prompts.map((prompt4) => {
|
|
4057
|
+
const args = prompt4.arguments ?? [];
|
|
4058
|
+
const reqCount = Array.isArray(args) ? args.filter((a) => a?.required).length : 0;
|
|
4059
|
+
const total = Array.isArray(args) ? args.length : 0;
|
|
4060
|
+
const argsCell = total === 0 ? source_default.gray("\u2014") : `${reqCount}/${total}`;
|
|
4061
|
+
return {
|
|
4062
|
+
name: source_default.bold(prompt4.name),
|
|
4063
|
+
args: argsCell,
|
|
4064
|
+
description: prompt4.description || source_default.gray("(no description)")
|
|
4065
|
+
};
|
|
4066
|
+
});
|
|
4067
|
+
console.log(
|
|
4068
|
+
formatTable(tableData, [
|
|
4069
|
+
{ key: "name", header: "Prompt" },
|
|
4070
|
+
{ key: "args", header: "Args" },
|
|
4071
|
+
{ key: "description", header: "Description", truncate: true }
|
|
4072
|
+
])
|
|
4073
|
+
);
|
|
2627
4074
|
}
|
|
2628
|
-
console.log(formatHeader(`Available Prompts (${prompts.length}):`));
|
|
2629
|
-
console.log("");
|
|
2630
|
-
const tableData = prompts.map((prompt4) => ({
|
|
2631
|
-
name: source_default.bold(prompt4.name),
|
|
2632
|
-
description: prompt4.description || source_default.gray("No description")
|
|
2633
|
-
}));
|
|
2634
|
-
console.log(
|
|
2635
|
-
formatTable(tableData, [
|
|
2636
|
-
{ key: "name", header: "Prompt", width: 25 },
|
|
2637
|
-
{ key: "description", header: "Description", width: 50 }
|
|
2638
|
-
])
|
|
2639
|
-
);
|
|
2640
4075
|
} catch (error) {
|
|
2641
4076
|
console.error(formatError(`Failed to list prompts: ${error.message}`));
|
|
2642
|
-
|
|
4077
|
+
await cleanupAndExit(1);
|
|
2643
4078
|
}
|
|
4079
|
+
await cleanupAndExit(0);
|
|
2644
4080
|
}
|
|
2645
|
-
async function getPromptCommand(promptName,
|
|
4081
|
+
async function getPromptCommand(name, promptName, argsList, options) {
|
|
2646
4082
|
try {
|
|
2647
|
-
const result = await getOrRestoreSession(
|
|
2648
|
-
if (!result)
|
|
4083
|
+
const result = await getOrRestoreSession(name);
|
|
4084
|
+
if (!result) {
|
|
4085
|
+
await cleanupAndExit(1);
|
|
4086
|
+
}
|
|
2649
4087
|
const { session } = result;
|
|
2650
4088
|
let args = {};
|
|
2651
|
-
if (
|
|
4089
|
+
if (argsList && argsList.length > 0) {
|
|
2652
4090
|
try {
|
|
2653
|
-
args =
|
|
4091
|
+
args = parsePromptArgs(argsList);
|
|
2654
4092
|
} catch (error) {
|
|
2655
|
-
console.error(formatError(
|
|
2656
|
-
|
|
4093
|
+
console.error(formatError(error.message));
|
|
4094
|
+
console.log("");
|
|
4095
|
+
console.log(formatInfo("Usage:"));
|
|
4096
|
+
console.log(
|
|
4097
|
+
` npx mcp-use client ${name} prompts get ${promptName} key=value [key2=value2 ...]`
|
|
4098
|
+
);
|
|
4099
|
+
console.log(
|
|
4100
|
+
` npx mcp-use client ${name} prompts get ${promptName} '{"key":"value"}' # full JSON object`
|
|
4101
|
+
);
|
|
4102
|
+
await cleanupAndExit(1);
|
|
2657
4103
|
}
|
|
2658
4104
|
}
|
|
2659
4105
|
console.error(formatInfo(`Getting prompt '${promptName}'...`));
|
|
@@ -2675,12 +4121,13 @@ async function getPromptCommand(promptName, argsJson, options) {
|
|
|
2675
4121
|
}
|
|
2676
4122
|
} catch (error) {
|
|
2677
4123
|
console.error(formatError(`Failed to get prompt: ${error.message}`));
|
|
2678
|
-
|
|
4124
|
+
await cleanupAndExit(1);
|
|
2679
4125
|
}
|
|
4126
|
+
await cleanupAndExit(0);
|
|
2680
4127
|
}
|
|
2681
|
-
async function interactiveCommand(
|
|
4128
|
+
async function interactiveCommand(name) {
|
|
2682
4129
|
try {
|
|
2683
|
-
const result = await getOrRestoreSession(
|
|
4130
|
+
const result = await getOrRestoreSession(name);
|
|
2684
4131
|
if (!result) return;
|
|
2685
4132
|
const { name: sessionName, session } = result;
|
|
2686
4133
|
console.log(formatHeader("MCP Interactive Mode"));
|
|
@@ -2703,15 +4150,11 @@ async function interactiveCommand(options) {
|
|
|
2703
4150
|
source_default.gray(" prompts list - List available prompts")
|
|
2704
4151
|
);
|
|
2705
4152
|
console.log(source_default.gray(" prompts get <name> - Get a prompt"));
|
|
2706
|
-
console.log(source_default.gray(" sessions list - List all sessions"));
|
|
2707
|
-
console.log(
|
|
2708
|
-
source_default.gray(" sessions switch <name> - Switch to another session")
|
|
2709
|
-
);
|
|
2710
4153
|
console.log(
|
|
2711
4154
|
source_default.gray(" exit, quit - Exit interactive mode")
|
|
2712
4155
|
);
|
|
2713
4156
|
console.log("");
|
|
2714
|
-
const rl = (0,
|
|
4157
|
+
const rl = (0, import_node_readline2.createInterface)({
|
|
2715
4158
|
input: process.stdin,
|
|
2716
4159
|
output: process.stdout,
|
|
2717
4160
|
prompt: source_default.cyan("mcp> ")
|
|
@@ -2726,7 +4169,7 @@ async function interactiveCommand(options) {
|
|
|
2726
4169
|
if (trimmed === "exit" || trimmed === "quit") {
|
|
2727
4170
|
console.log(formatInfo("Goodbye!"));
|
|
2728
4171
|
rl.close();
|
|
2729
|
-
|
|
4172
|
+
await cleanupAndExit(0);
|
|
2730
4173
|
}
|
|
2731
4174
|
const parts = trimmed.split(" ");
|
|
2732
4175
|
const scope = parts[0];
|
|
@@ -2826,22 +4269,10 @@ async function interactiveCommand(options) {
|
|
|
2826
4269
|
)
|
|
2827
4270
|
);
|
|
2828
4271
|
}
|
|
2829
|
-
} else if (scope === "sessions") {
|
|
2830
|
-
if (command === "list") {
|
|
2831
|
-
await listSessionsCommand();
|
|
2832
|
-
} else if (command === "switch" && arg) {
|
|
2833
|
-
console.log(
|
|
2834
|
-
formatWarning(
|
|
2835
|
-
"Session switching in interactive mode will be available in a future version"
|
|
2836
|
-
)
|
|
2837
|
-
);
|
|
2838
|
-
} else {
|
|
2839
|
-
console.error(formatError("Invalid command. Try: sessions list"));
|
|
2840
|
-
}
|
|
2841
4272
|
} else {
|
|
2842
4273
|
console.error(
|
|
2843
4274
|
formatError(
|
|
2844
|
-
"Unknown command. Type a valid scope: tools, resources, prompts
|
|
4275
|
+
"Unknown command. Type a valid scope: tools, resources, prompts"
|
|
2845
4276
|
)
|
|
2846
4277
|
);
|
|
2847
4278
|
}
|
|
@@ -2850,63 +4281,98 @@ async function interactiveCommand(options) {
|
|
|
2850
4281
|
}
|
|
2851
4282
|
rl.prompt();
|
|
2852
4283
|
});
|
|
2853
|
-
rl.on("close", () => {
|
|
4284
|
+
rl.on("close", async () => {
|
|
2854
4285
|
console.log("");
|
|
2855
4286
|
console.log(formatInfo("Goodbye!"));
|
|
2856
|
-
|
|
4287
|
+
await cleanupAndExit(0);
|
|
2857
4288
|
});
|
|
2858
4289
|
} catch (error) {
|
|
2859
4290
|
console.error(
|
|
2860
4291
|
formatError(`Failed to start interactive mode: ${error.message}`)
|
|
2861
4292
|
);
|
|
2862
|
-
|
|
4293
|
+
await cleanupAndExit(1);
|
|
2863
4294
|
}
|
|
2864
4295
|
}
|
|
2865
4296
|
function createClientCommand() {
|
|
2866
|
-
const clientCommand = new
|
|
2867
|
-
"Interactive MCP client for terminal usage"
|
|
4297
|
+
const clientCommand = new import_commander2.Command("client").description(
|
|
4298
|
+
"Interactive MCP client for terminal usage. Use `mcp-use client <name> ...` to run commands against a saved server."
|
|
4299
|
+
).showHelpAfterError(
|
|
4300
|
+
"(Run `mcp-use client --help` to see available commands)"
|
|
4301
|
+
);
|
|
4302
|
+
clientCommand.command("connect [name] [url]").description(
|
|
4303
|
+
"Connect to an MCP server and save it under a short name. Use the name to address it in later commands (e.g. `mcp-use client <name> tools list`)."
|
|
4304
|
+
).option("--stdio", "Use stdio connector instead of HTTP").option("--auth <token>", "Static Bearer token (skips OAuth)").option(
|
|
4305
|
+
"--no-oauth",
|
|
4306
|
+
"Don't auto-trigger OAuth on 401; fail with the 401 instead"
|
|
4307
|
+
).option(
|
|
4308
|
+
"--auth-timeout <ms>",
|
|
4309
|
+
"OAuth loopback wait timeout in ms (default 300000)"
|
|
4310
|
+
).action(connectCommand);
|
|
4311
|
+
clientCommand.command("list").description("List saved servers").action(listClientsCommand);
|
|
4312
|
+
clientCommand.command("remove <name>").description(
|
|
4313
|
+
"Remove a saved server. Also clears any OAuth tokens for that URL, unless another saved server still uses it."
|
|
4314
|
+
).action(removeClientCommand);
|
|
4315
|
+
return clientCommand;
|
|
4316
|
+
}
|
|
4317
|
+
function createPerClientCommand(name) {
|
|
4318
|
+
const cmd = new import_commander2.Command(`mcp-use client ${name}`).description(`Commands for server '${name}'`).showHelpAfterError(
|
|
4319
|
+
`(Run \`mcp-use client ${name} --help\` to see available commands)`
|
|
2868
4320
|
);
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
const
|
|
2872
|
-
|
|
4321
|
+
cmd.command("disconnect").description("Disconnect from this server").action(() => disconnectCommand(name));
|
|
4322
|
+
cmd.command("interactive").description("Start interactive REPL mode for this server").action(() => interactiveCommand(name));
|
|
4323
|
+
const toolsCommand = new import_commander2.Command("tools").description("Interact with MCP tools").showHelpAfterError(
|
|
4324
|
+
`(Run \`mcp-use client ${name} tools --help\` to see available actions)`
|
|
2873
4325
|
);
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
"
|
|
4326
|
+
toolsCommand.command("list").description("List available tools").option("--json", "Output as JSON").action((options) => listToolsCommand(name, options));
|
|
4327
|
+
toolsCommand.command("call <tool> [args...]").description(
|
|
4328
|
+
"Call a tool. Args as key=value pairs (use key:=<json> for nested values, or pass a JSON object)"
|
|
4329
|
+
).option("--timeout <ms>", "Request timeout in milliseconds", parseInt).option("--json", "Output as JSON").option(
|
|
4330
|
+
"--no-screenshot",
|
|
4331
|
+
"Skip the auto-screenshot for tools that render a widget"
|
|
4332
|
+
).option(
|
|
4333
|
+
"--screenshot-output <path>",
|
|
4334
|
+
"Output PNG path for the widget screenshot (defaults to ./<view>-<timestamp>.png)"
|
|
4335
|
+
).action(
|
|
4336
|
+
(tool, args, options) => callToolCommand(name, tool, args, options)
|
|
2879
4337
|
);
|
|
2880
|
-
toolsCommand.command("
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
const resourcesCommand = new import_commander.Command("resources").description(
|
|
2885
|
-
"Interact with MCP resources"
|
|
4338
|
+
toolsCommand.command("describe <tool>").description("Show tool details and schema").action((tool) => describeToolCommand(name, tool));
|
|
4339
|
+
cmd.addCommand(toolsCommand);
|
|
4340
|
+
const resourcesCommand = new import_commander2.Command("resources").description("Interact with MCP resources").showHelpAfterError(
|
|
4341
|
+
`(Run \`mcp-use client ${name} resources --help\` to see available actions)`
|
|
2886
4342
|
);
|
|
2887
|
-
resourcesCommand.command("list").description("List available resources").option("--
|
|
2888
|
-
resourcesCommand.command("read <uri>").description("Read a resource by URI").option("--
|
|
2889
|
-
resourcesCommand.command("subscribe <uri>").description("Subscribe to resource updates").
|
|
2890
|
-
resourcesCommand.command("unsubscribe <uri>").description("Unsubscribe from resource updates").
|
|
2891
|
-
|
|
2892
|
-
const promptsCommand = new
|
|
2893
|
-
|
|
4343
|
+
resourcesCommand.command("list").description("List available resources").option("--json", "Output as JSON").action((options) => listResourcesCommand(name, options));
|
|
4344
|
+
resourcesCommand.command("read <uri>").description("Read a resource by URI").option("--json", "Output as JSON").action((uri, options) => readResourceCommand(name, uri, options));
|
|
4345
|
+
resourcesCommand.command("subscribe <uri>").description("Subscribe to resource updates").action((uri) => subscribeResourceCommand(name, uri));
|
|
4346
|
+
resourcesCommand.command("unsubscribe <uri>").description("Unsubscribe from resource updates").action((uri) => unsubscribeResourceCommand(name, uri));
|
|
4347
|
+
cmd.addCommand(resourcesCommand);
|
|
4348
|
+
const promptsCommand = new import_commander2.Command("prompts").description("Interact with MCP prompts").showHelpAfterError(
|
|
4349
|
+
`(Run \`mcp-use client ${name} prompts --help\` to see available actions)`
|
|
2894
4350
|
);
|
|
2895
|
-
promptsCommand.command("list").description("List available prompts").option("--
|
|
2896
|
-
promptsCommand.command("get <
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
4351
|
+
promptsCommand.command("list").description("List available prompts").option("--json", "Output as JSON").action((options) => listPromptsCommand(name, options));
|
|
4352
|
+
promptsCommand.command("get <prompt> [args...]").description(
|
|
4353
|
+
"Get a prompt. Args as key=value pairs (or pass a JSON object)"
|
|
4354
|
+
).option("--json", "Output as JSON").action(
|
|
4355
|
+
(prompt4, args, options) => getPromptCommand(name, prompt4, args, options)
|
|
4356
|
+
);
|
|
4357
|
+
cmd.addCommand(promptsCommand);
|
|
4358
|
+
const authCommand = new import_commander2.Command("auth").description("Manage OAuth tokens for HTTP servers").showHelpAfterError(
|
|
4359
|
+
`(Run \`mcp-use client ${name} auth --help\` to see available actions)`
|
|
4360
|
+
);
|
|
4361
|
+
authCommand.command("status").description("Show OAuth token status for this server").action(() => authStatusCommand(name));
|
|
4362
|
+
authCommand.command("refresh").description("Force-refresh the OAuth access token").action(() => authRefreshCommand(name));
|
|
4363
|
+
authCommand.command("logout").description("Remove stored OAuth tokens for this server's URL").action(() => authLogoutCommand(name));
|
|
4364
|
+
cmd.addCommand(authCommand);
|
|
4365
|
+
return cmd;
|
|
2900
4366
|
}
|
|
2901
4367
|
|
|
2902
4368
|
// src/commands/deploy.ts
|
|
2903
|
-
var
|
|
2904
|
-
var
|
|
4369
|
+
var import_node_fs10 = require("fs");
|
|
4370
|
+
var import_node_path8 = __toESM(require("path"), 1);
|
|
2905
4371
|
|
|
2906
4372
|
// src/utils/git.ts
|
|
2907
|
-
var
|
|
4373
|
+
var import_node_child_process10 = require("child_process");
|
|
2908
4374
|
var import_node_util7 = require("util");
|
|
2909
|
-
var execFileAsync5 = (0, import_node_util7.promisify)(
|
|
4375
|
+
var execFileAsync5 = (0, import_node_util7.promisify)(import_node_child_process10.execFile);
|
|
2910
4376
|
async function gitCommand(args, cwd = process.cwd()) {
|
|
2911
4377
|
try {
|
|
2912
4378
|
const { stdout } = await execFileAsync5("git", args, { cwd });
|
|
@@ -3055,17 +4521,17 @@ function getMcpServerUrlForCloudServer(server) {
|
|
|
3055
4521
|
}
|
|
3056
4522
|
|
|
3057
4523
|
// src/utils/project-link.ts
|
|
3058
|
-
var
|
|
3059
|
-
var
|
|
4524
|
+
var import_node_fs9 = require("fs");
|
|
4525
|
+
var import_node_path7 = __toESM(require("path"), 1);
|
|
3060
4526
|
var MCP_USE_DIR = ".mcp-use";
|
|
3061
4527
|
var MCP_USE_DIR_PROJECT = "project.json";
|
|
3062
4528
|
function getMcpUseDirectory(cwd) {
|
|
3063
|
-
return
|
|
4529
|
+
return import_node_path7.default.join(cwd, MCP_USE_DIR);
|
|
3064
4530
|
}
|
|
3065
4531
|
async function getProjectLink(cwd) {
|
|
3066
4532
|
try {
|
|
3067
|
-
const linkPath =
|
|
3068
|
-
const content = await
|
|
4533
|
+
const linkPath = import_node_path7.default.join(getMcpUseDirectory(cwd), MCP_USE_DIR_PROJECT);
|
|
4534
|
+
const content = await import_node_fs9.promises.readFile(linkPath, "utf-8");
|
|
3069
4535
|
return JSON.parse(content);
|
|
3070
4536
|
} catch (err) {
|
|
3071
4537
|
if (err.code === "ENOENT") return null;
|
|
@@ -3074,17 +4540,17 @@ async function getProjectLink(cwd) {
|
|
|
3074
4540
|
}
|
|
3075
4541
|
async function saveProjectLink(cwd, link) {
|
|
3076
4542
|
const mcpUseDir = getMcpUseDirectory(cwd);
|
|
3077
|
-
await
|
|
3078
|
-
const linkPath =
|
|
3079
|
-
await
|
|
4543
|
+
await import_node_fs9.promises.mkdir(mcpUseDir, { recursive: true });
|
|
4544
|
+
const linkPath = import_node_path7.default.join(mcpUseDir, MCP_USE_DIR_PROJECT);
|
|
4545
|
+
await import_node_fs9.promises.writeFile(linkPath, JSON.stringify(link, null, 2), "utf-8");
|
|
3080
4546
|
await addToGitIgnore(cwd);
|
|
3081
4547
|
}
|
|
3082
4548
|
async function addToGitIgnore(cwd) {
|
|
3083
|
-
const gitignorePath =
|
|
4549
|
+
const gitignorePath = import_node_path7.default.join(cwd, ".gitignore");
|
|
3084
4550
|
try {
|
|
3085
4551
|
let content = "";
|
|
3086
4552
|
try {
|
|
3087
|
-
content = await
|
|
4553
|
+
content = await import_node_fs9.promises.readFile(gitignorePath, "utf-8");
|
|
3088
4554
|
} catch (err) {
|
|
3089
4555
|
if (err.code !== "ENOENT") throw err;
|
|
3090
4556
|
}
|
|
@@ -3093,7 +4559,7 @@ async function addToGitIgnore(cwd) {
|
|
|
3093
4559
|
# mcp-use deployment
|
|
3094
4560
|
${MCP_USE_DIR}
|
|
3095
4561
|
`;
|
|
3096
|
-
await
|
|
4562
|
+
await import_node_fs9.promises.writeFile(gitignorePath, newContent, "utf-8");
|
|
3097
4563
|
}
|
|
3098
4564
|
} catch (err) {
|
|
3099
4565
|
}
|
|
@@ -3102,7 +4568,7 @@ ${MCP_USE_DIR}
|
|
|
3102
4568
|
// src/commands/deploy.ts
|
|
3103
4569
|
async function parseEnvFile(filePath) {
|
|
3104
4570
|
try {
|
|
3105
|
-
const content = await
|
|
4571
|
+
const content = await import_node_fs10.promises.readFile(filePath, "utf-8");
|
|
3106
4572
|
const envVars = {};
|
|
3107
4573
|
const lines = content.split("\n");
|
|
3108
4574
|
let currentKey = null;
|
|
@@ -3221,7 +4687,7 @@ async function buildEnvVars(options) {
|
|
|
3221
4687
|
}
|
|
3222
4688
|
async function isMcpProject(cwd = process.cwd()) {
|
|
3223
4689
|
try {
|
|
3224
|
-
const content = await
|
|
4690
|
+
const content = await import_node_fs10.promises.readFile(import_node_path8.default.join(cwd, "package.json"), "utf-8");
|
|
3225
4691
|
const pkg = JSON.parse(content);
|
|
3226
4692
|
return !!(pkg.dependencies?.["mcp-use"] || pkg.dependencies?.["@modelcontextprotocol/sdk"] || pkg.devDependencies?.["mcp-use"] || pkg.devDependencies?.["@modelcontextprotocol/sdk"]);
|
|
3227
4693
|
} catch {
|
|
@@ -3230,16 +4696,16 @@ async function isMcpProject(cwd = process.cwd()) {
|
|
|
3230
4696
|
}
|
|
3231
4697
|
async function getProjectName(cwd = process.cwd()) {
|
|
3232
4698
|
try {
|
|
3233
|
-
const content = await
|
|
4699
|
+
const content = await import_node_fs10.promises.readFile(import_node_path8.default.join(cwd, "package.json"), "utf-8");
|
|
3234
4700
|
const pkg = JSON.parse(content);
|
|
3235
4701
|
if (pkg.name) return pkg.name;
|
|
3236
4702
|
} catch {
|
|
3237
4703
|
}
|
|
3238
|
-
return
|
|
4704
|
+
return import_node_path8.default.basename(cwd);
|
|
3239
4705
|
}
|
|
3240
4706
|
async function detectBuildCommand(cwd) {
|
|
3241
4707
|
try {
|
|
3242
|
-
const content = await
|
|
4708
|
+
const content = await import_node_fs10.promises.readFile(import_node_path8.default.join(cwd, "package.json"), "utf-8");
|
|
3243
4709
|
if (JSON.parse(content).scripts?.build) return "npm run build";
|
|
3244
4710
|
} catch {
|
|
3245
4711
|
}
|
|
@@ -3247,7 +4713,7 @@ async function detectBuildCommand(cwd) {
|
|
|
3247
4713
|
}
|
|
3248
4714
|
async function detectStartCommand(cwd) {
|
|
3249
4715
|
try {
|
|
3250
|
-
const content = await
|
|
4716
|
+
const content = await import_node_fs10.promises.readFile(import_node_path8.default.join(cwd, "package.json"), "utf-8");
|
|
3251
4717
|
const pkg = JSON.parse(content);
|
|
3252
4718
|
if (pkg.scripts?.start) return "npm start";
|
|
3253
4719
|
if (pkg.main) return `node ${pkg.main}`;
|
|
@@ -3258,7 +4724,7 @@ async function detectStartCommand(cwd) {
|
|
|
3258
4724
|
async function detectRuntime(cwd) {
|
|
3259
4725
|
for (const f of ["requirements.txt", "pyproject.toml", "setup.py"]) {
|
|
3260
4726
|
try {
|
|
3261
|
-
await
|
|
4727
|
+
await import_node_fs10.promises.access(import_node_path8.default.join(cwd, f));
|
|
3262
4728
|
return "python";
|
|
3263
4729
|
} catch {
|
|
3264
4730
|
continue;
|
|
@@ -3305,17 +4771,17 @@ var REQUIRED_IGNORES = [
|
|
|
3305
4771
|
".mcp-use"
|
|
3306
4772
|
];
|
|
3307
4773
|
async function ensureGitignore(cwd) {
|
|
3308
|
-
const gitignorePath =
|
|
4774
|
+
const gitignorePath = import_node_path8.default.join(cwd, ".gitignore");
|
|
3309
4775
|
let content = "";
|
|
3310
4776
|
try {
|
|
3311
|
-
content = await
|
|
4777
|
+
content = await import_node_fs10.promises.readFile(gitignorePath, "utf-8");
|
|
3312
4778
|
} catch {
|
|
3313
4779
|
}
|
|
3314
4780
|
const missing = REQUIRED_IGNORES.filter((entry) => !content.includes(entry));
|
|
3315
4781
|
if (missing.length > 0) {
|
|
3316
4782
|
const additions = missing.join("\n");
|
|
3317
4783
|
const newContent = content + (content.endsWith("\n") ? "" : "\n") + additions + "\n";
|
|
3318
|
-
await
|
|
4784
|
+
await import_node_fs10.promises.writeFile(gitignorePath, newContent, "utf-8");
|
|
3319
4785
|
}
|
|
3320
4786
|
}
|
|
3321
4787
|
async function displayDeploymentProgress(api, deploymentId, progressOptions) {
|
|
@@ -3765,10 +5231,10 @@ async function deployCommand(options) {
|
|
|
3765
5231
|
console.log(source_default.green("\u2713 GitHub connected\n"));
|
|
3766
5232
|
let installationDbId;
|
|
3767
5233
|
let githubInstallationId;
|
|
3768
|
-
const projectDir = options.rootDir ?
|
|
5234
|
+
const projectDir = options.rootDir ? import_node_path8.default.resolve(cwd, options.rootDir) : cwd;
|
|
3769
5235
|
if (options.rootDir) {
|
|
3770
5236
|
try {
|
|
3771
|
-
await
|
|
5237
|
+
await import_node_fs10.promises.access(projectDir);
|
|
3772
5238
|
} catch {
|
|
3773
5239
|
console.log(
|
|
3774
5240
|
source_default.red(`\u2717 Root directory not found: ${options.rootDir}`)
|
|
@@ -4277,7 +5743,7 @@ async function deployCommand(options) {
|
|
|
4277
5743
|
}
|
|
4278
5744
|
|
|
4279
5745
|
// src/commands/deployments.ts
|
|
4280
|
-
var
|
|
5746
|
+
var import_commander3 = require("commander");
|
|
4281
5747
|
async function prompt2(question) {
|
|
4282
5748
|
const readline = await import("readline");
|
|
4283
5749
|
const rl = readline.createInterface({
|
|
@@ -4689,8 +6155,8 @@ async function startDeploymentCommand(deploymentId) {
|
|
|
4689
6155
|
}
|
|
4690
6156
|
}
|
|
4691
6157
|
function createDeploymentsCommand() {
|
|
4692
|
-
const deploymentsCommand = new
|
|
4693
|
-
"
|
|
6158
|
+
const deploymentsCommand = new import_commander3.Command("deployments").description("Manage cloud deployments").showHelpAfterError(
|
|
6159
|
+
"(Run `mcp-use deployments --help` to see available commands)"
|
|
4694
6160
|
);
|
|
4695
6161
|
deploymentsCommand.command("list").alias("ls").description("List all deployments").action(listDeploymentsCommand);
|
|
4696
6162
|
deploymentsCommand.command("get").argument("<deployment-id>", "Deployment ID").description("Get deployment details").action(getDeploymentCommand);
|
|
@@ -4705,10 +6171,10 @@ function createDeploymentsCommand() {
|
|
|
4705
6171
|
}
|
|
4706
6172
|
|
|
4707
6173
|
// src/commands/servers.ts
|
|
4708
|
-
var
|
|
6174
|
+
var import_commander5 = require("commander");
|
|
4709
6175
|
|
|
4710
6176
|
// src/commands/env.ts
|
|
4711
|
-
var
|
|
6177
|
+
var import_commander4 = require("commander");
|
|
4712
6178
|
var ALL_ENVS = ["production", "preview", "development"];
|
|
4713
6179
|
function parseEnvironments(raw) {
|
|
4714
6180
|
const parts = raw.split(",").map((s) => s.trim().toLowerCase()).filter(Boolean);
|
|
@@ -4853,9 +6319,7 @@ async function removeEnvCommand(varId, options) {
|
|
|
4853
6319
|
}
|
|
4854
6320
|
}
|
|
4855
6321
|
function createEnvCommand() {
|
|
4856
|
-
const envCommand = new
|
|
4857
|
-
"Manage environment variables for a server"
|
|
4858
|
-
);
|
|
6322
|
+
const envCommand = new import_commander4.Command("env").description("Manage environment variables for a server").showHelpAfterError("(Run `mcp-use env --help` to see available commands)");
|
|
4859
6323
|
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);
|
|
4860
6324
|
envCommand.command("add").argument("<KEY=VALUE>", "Variable assignment, e.g. API_KEY=abc123").description("Add an environment variable to a server").requiredOption("--server <id>", "Server UUID").option(
|
|
4861
6325
|
"--env <environments>",
|
|
@@ -5137,8 +6601,8 @@ async function deleteServerCommand(serverId, options) {
|
|
|
5137
6601
|
}
|
|
5138
6602
|
}
|
|
5139
6603
|
function createServersCommand() {
|
|
5140
|
-
const serversCommand = new
|
|
5141
|
-
"
|
|
6604
|
+
const serversCommand = new import_commander5.Command("servers").description("Manage cloud servers (Git-backed deploy targets)").showHelpAfterError(
|
|
6605
|
+
"(Run `mcp-use servers --help` to see available commands)"
|
|
5142
6606
|
);
|
|
5143
6607
|
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);
|
|
5144
6608
|
serversCommand.command("get").argument("<id-or-slug>", "Server UUID or slug").option("--org <slug-or-id>", "Resolve org context before fetch").description("Show server details and recent deployments").action(getServerCommand);
|
|
@@ -5255,12 +6719,12 @@ async function orgCurrentCommand() {
|
|
|
5255
6719
|
}
|
|
5256
6720
|
|
|
5257
6721
|
// src/commands/skills.ts
|
|
5258
|
-
var
|
|
5259
|
-
var
|
|
5260
|
-
var
|
|
5261
|
-
var
|
|
6722
|
+
var import_commander6 = require("commander");
|
|
6723
|
+
var import_node_fs11 = require("fs");
|
|
6724
|
+
var import_node_os6 = require("os");
|
|
6725
|
+
var import_node_path9 = require("path");
|
|
5262
6726
|
var import_node_stream = require("stream");
|
|
5263
|
-
var
|
|
6727
|
+
var import_promises6 = require("stream/promises");
|
|
5264
6728
|
var import_tar = require("tar");
|
|
5265
6729
|
var REPO_OWNER = "mcp-use";
|
|
5266
6730
|
var REPO_NAME = "mcp-use";
|
|
@@ -5295,42 +6759,42 @@ function sendInstallTelemetryEvent(agents, skills) {
|
|
|
5295
6759
|
}
|
|
5296
6760
|
async function addSkillsToProject(projectPath) {
|
|
5297
6761
|
const tarballUrl = `https://codeload.github.com/${REPO_OWNER}/${REPO_NAME}/tar.gz/${REPO_BRANCH}`;
|
|
5298
|
-
const tempDir = (0,
|
|
6762
|
+
const tempDir = (0, import_node_fs11.mkdtempSync)((0, import_node_path9.join)((0, import_node_os6.tmpdir)(), "mcp-use-skills-"));
|
|
5299
6763
|
try {
|
|
5300
6764
|
const response = await fetch(tarballUrl);
|
|
5301
6765
|
if (!response.ok) {
|
|
5302
6766
|
throw new Error(`Failed to download tarball: ${response.statusText}`);
|
|
5303
6767
|
}
|
|
5304
|
-
await (0,
|
|
6768
|
+
await (0, import_promises6.pipeline)(
|
|
5305
6769
|
import_node_stream.Readable.fromWeb(response.body),
|
|
5306
6770
|
(0, import_tar.extract)({
|
|
5307
6771
|
cwd: tempDir,
|
|
5308
|
-
filter: (
|
|
6772
|
+
filter: (path11) => path11.includes("/skills/"),
|
|
5309
6773
|
strip: 1
|
|
5310
6774
|
})
|
|
5311
6775
|
);
|
|
5312
|
-
const skillsPath = (0,
|
|
5313
|
-
if (!(0,
|
|
6776
|
+
const skillsPath = (0, import_node_path9.join)(tempDir, "skills");
|
|
6777
|
+
if (!(0, import_node_fs11.existsSync)(skillsPath)) {
|
|
5314
6778
|
throw new Error("Skills folder not found in repository");
|
|
5315
6779
|
}
|
|
5316
6780
|
for (const preset of ALL_PRESETS) {
|
|
5317
6781
|
const folderName = AGENT_PRESET_FOLDERS[preset];
|
|
5318
|
-
const outputPath = (0,
|
|
5319
|
-
(0,
|
|
6782
|
+
const outputPath = (0, import_node_path9.join)(projectPath, folderName, "skills");
|
|
6783
|
+
(0, import_node_fs11.cpSync)(skillsPath, outputPath, { recursive: true });
|
|
5320
6784
|
}
|
|
5321
|
-
const skillNames = (0,
|
|
6785
|
+
const skillNames = (0, import_node_fs11.readdirSync)(skillsPath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
5322
6786
|
sendInstallTelemetryEvent(ALL_PRESETS.join(","), skillNames.join(","));
|
|
5323
6787
|
} finally {
|
|
5324
|
-
(0,
|
|
6788
|
+
(0, import_node_fs11.rmSync)(tempDir, { recursive: true, force: true });
|
|
5325
6789
|
}
|
|
5326
6790
|
}
|
|
5327
6791
|
function createSkillsCommand() {
|
|
5328
|
-
const skills = new
|
|
5329
|
-
"
|
|
6792
|
+
const skills = new import_commander6.Command("skills").description("Manage mcp-use AI agent skills").showHelpAfterError(
|
|
6793
|
+
"(Run `mcp-use skills --help` to see available commands)"
|
|
5330
6794
|
);
|
|
5331
6795
|
const installAction = async (options) => {
|
|
5332
|
-
const projectPath = (0,
|
|
5333
|
-
if (!(0,
|
|
6796
|
+
const projectPath = (0, import_node_path9.resolve)(options.path);
|
|
6797
|
+
if (!(0, import_node_fs11.existsSync)(projectPath)) {
|
|
5334
6798
|
console.error(source_default.red(`Directory not found: ${projectPath}`));
|
|
5335
6799
|
process.exit(1);
|
|
5336
6800
|
}
|
|
@@ -5371,13 +6835,13 @@ function createSkillsCommand() {
|
|
|
5371
6835
|
}
|
|
5372
6836
|
|
|
5373
6837
|
// src/utils/next-shims.ts
|
|
5374
|
-
var
|
|
5375
|
-
var
|
|
6838
|
+
var import_node_fs12 = require("fs");
|
|
6839
|
+
var import_node_path10 = __toESM(require("path"), 1);
|
|
5376
6840
|
var import_node_url2 = require("url");
|
|
5377
6841
|
async function detectNextJsProject(projectPath) {
|
|
5378
6842
|
try {
|
|
5379
|
-
const pkgPath =
|
|
5380
|
-
const content = await
|
|
6843
|
+
const pkgPath = import_node_path10.default.join(projectPath, "package.json");
|
|
6844
|
+
const content = await import_node_fs12.promises.readFile(pkgPath, "utf-8");
|
|
5381
6845
|
const pkg = JSON.parse(content);
|
|
5382
6846
|
const deps = pkg.dependencies ?? {};
|
|
5383
6847
|
const devDeps = pkg.devDependencies ?? {};
|
|
@@ -5395,9 +6859,9 @@ async function loadNextJsEnvFiles(projectPath) {
|
|
|
5395
6859
|
];
|
|
5396
6860
|
const dotenv = await import("dotenv");
|
|
5397
6861
|
for (const file of files) {
|
|
5398
|
-
const abs =
|
|
6862
|
+
const abs = import_node_path10.default.join(projectPath, file);
|
|
5399
6863
|
try {
|
|
5400
|
-
await
|
|
6864
|
+
await import_node_fs12.promises.access(abs);
|
|
5401
6865
|
} catch {
|
|
5402
6866
|
continue;
|
|
5403
6867
|
}
|
|
@@ -5407,20 +6871,20 @@ async function loadNextJsEnvFiles(projectPath) {
|
|
|
5407
6871
|
function getThisDir() {
|
|
5408
6872
|
if (typeof __dirname === "string") return __dirname;
|
|
5409
6873
|
const url = importMetaUrl;
|
|
5410
|
-
return
|
|
6874
|
+
return import_node_path10.default.dirname((0, import_node_url2.fileURLToPath)(url));
|
|
5411
6875
|
}
|
|
5412
6876
|
function resolveShimPath(filename) {
|
|
5413
6877
|
const thisDir = getThisDir();
|
|
5414
6878
|
const candidates = [
|
|
5415
6879
|
// Production: `dist/` next to this module
|
|
5416
|
-
|
|
6880
|
+
import_node_path10.default.join(thisDir, "shims", filename),
|
|
5417
6881
|
// Test / dev: one level up (e.g., from `dist/utils/` back to `src/shims/`)
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
6882
|
+
import_node_path10.default.join(thisDir, "..", "shims", filename),
|
|
6883
|
+
import_node_path10.default.join(thisDir, "..", "..", "src", "shims", filename),
|
|
6884
|
+
import_node_path10.default.join(thisDir, "..", "src", "shims", filename)
|
|
5421
6885
|
];
|
|
5422
6886
|
for (const candidate of candidates) {
|
|
5423
|
-
if ((0,
|
|
6887
|
+
if ((0, import_node_fs12.existsSync)(candidate)) return candidate;
|
|
5424
6888
|
}
|
|
5425
6889
|
return void 0;
|
|
5426
6890
|
}
|
|
@@ -5438,7 +6902,7 @@ async function registerNextShimsInProcess() {
|
|
|
5438
6902
|
const cjsPath = getShimCjsPreloadPath();
|
|
5439
6903
|
if (cjsPath) {
|
|
5440
6904
|
const { createRequire: createRequire3 } = await import("module");
|
|
5441
|
-
const req = createRequire3((0, import_node_url2.pathToFileURL)(getThisDir() +
|
|
6905
|
+
const req = createRequire3((0, import_node_url2.pathToFileURL)(getThisDir() + import_node_path10.default.sep).href);
|
|
5442
6906
|
req(cjsPath);
|
|
5443
6907
|
anyRegistered = true;
|
|
5444
6908
|
}
|
|
@@ -5446,7 +6910,7 @@ async function registerNextShimsInProcess() {
|
|
|
5446
6910
|
if (loaderPath) {
|
|
5447
6911
|
const { register } = await import("module");
|
|
5448
6912
|
const loaderUrl = (0, import_node_url2.pathToFileURL)(loaderPath).href;
|
|
5449
|
-
register(loaderUrl, (0, import_node_url2.pathToFileURL)(getThisDir() +
|
|
6913
|
+
register(loaderUrl, (0, import_node_url2.pathToFileURL)(getThisDir() + import_node_path10.default.sep).href);
|
|
5450
6914
|
anyRegistered = true;
|
|
5451
6915
|
}
|
|
5452
6916
|
return anyRegistered;
|
|
@@ -5471,13 +6935,13 @@ function quoteNodeOption(value) {
|
|
|
5471
6935
|
}
|
|
5472
6936
|
|
|
5473
6937
|
// src/utils/update-check.ts
|
|
5474
|
-
var
|
|
5475
|
-
var
|
|
6938
|
+
var import_node_fs13 = require("fs");
|
|
6939
|
+
var import_promises7 = require("fs/promises");
|
|
5476
6940
|
var import_node_module = require("module");
|
|
5477
|
-
var
|
|
5478
|
-
var
|
|
5479
|
-
var CACHE_DIR =
|
|
5480
|
-
var CACHE_FILE =
|
|
6941
|
+
var import_node_os7 = __toESM(require("os"), 1);
|
|
6942
|
+
var import_node_path11 = __toESM(require("path"), 1);
|
|
6943
|
+
var CACHE_DIR = import_node_path11.default.join(import_node_os7.default.homedir(), ".mcp-use");
|
|
6944
|
+
var CACHE_FILE = import_node_path11.default.join(CACHE_DIR, "update-check.json");
|
|
5481
6945
|
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
5482
6946
|
var FETCH_TIMEOUT_MS = 3e3;
|
|
5483
6947
|
var PACKAGE_NAME = "mcp-use";
|
|
@@ -5502,7 +6966,7 @@ function isNewer(current, candidate) {
|
|
|
5502
6966
|
}
|
|
5503
6967
|
async function readCache() {
|
|
5504
6968
|
try {
|
|
5505
|
-
const content = await (0,
|
|
6969
|
+
const content = await (0, import_promises7.readFile)(CACHE_FILE, "utf-8");
|
|
5506
6970
|
return JSON.parse(content);
|
|
5507
6971
|
} catch {
|
|
5508
6972
|
return null;
|
|
@@ -5510,12 +6974,12 @@ async function readCache() {
|
|
|
5510
6974
|
}
|
|
5511
6975
|
async function writeCache(latestVersion) {
|
|
5512
6976
|
try {
|
|
5513
|
-
await (0,
|
|
6977
|
+
await (0, import_promises7.mkdir)(CACHE_DIR, { recursive: true });
|
|
5514
6978
|
const cache = {
|
|
5515
6979
|
lastChecked: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5516
6980
|
latestVersion
|
|
5517
6981
|
};
|
|
5518
|
-
await (0,
|
|
6982
|
+
await (0, import_promises7.writeFile)(CACHE_FILE, JSON.stringify(cache, null, 2), "utf-8");
|
|
5519
6983
|
} catch {
|
|
5520
6984
|
}
|
|
5521
6985
|
}
|
|
@@ -5560,16 +7024,16 @@ function resolveInstalledVersion(projectPath) {
|
|
|
5560
7024
|
if (projectPath) {
|
|
5561
7025
|
attempts.push(() => {
|
|
5562
7026
|
const projectRequire = (0, import_node_module.createRequire)(
|
|
5563
|
-
|
|
7027
|
+
import_node_path11.default.join(projectPath, "package.json")
|
|
5564
7028
|
);
|
|
5565
7029
|
return projectRequire.resolve(`${PACKAGE_NAME}/package.json`);
|
|
5566
7030
|
});
|
|
5567
7031
|
}
|
|
5568
|
-
attempts.push(() =>
|
|
7032
|
+
attempts.push(() => import_node_path11.default.join(__dirname, "../../mcp-use/package.json"));
|
|
5569
7033
|
for (const attempt of attempts) {
|
|
5570
7034
|
try {
|
|
5571
7035
|
const pkgPath = attempt();
|
|
5572
|
-
const json = JSON.parse((0,
|
|
7036
|
+
const json = JSON.parse((0, import_node_fs13.readFileSync)(pkgPath, "utf-8"));
|
|
5573
7037
|
if (typeof json.version === "string") return json.version;
|
|
5574
7038
|
} catch {
|
|
5575
7039
|
}
|
|
@@ -5601,14 +7065,14 @@ A new release of ${source_default.bold(PACKAGE_NAME)} is available: ${source_def
|
|
|
5601
7065
|
}
|
|
5602
7066
|
|
|
5603
7067
|
// src/index.ts
|
|
5604
|
-
var program = new
|
|
5605
|
-
var packageContent = (0,
|
|
5606
|
-
|
|
7068
|
+
var program = new import_commander7.Command();
|
|
7069
|
+
var packageContent = (0, import_node_fs14.readFileSync)(
|
|
7070
|
+
import_node_path12.default.join(__dirname, "../package.json"),
|
|
5607
7071
|
"utf-8"
|
|
5608
7072
|
);
|
|
5609
7073
|
var packageJson = JSON.parse(packageContent);
|
|
5610
7074
|
var packageVersion = packageJson.version || "unknown";
|
|
5611
|
-
program.name("mcp-use").description("Create and run MCP servers with ui resources widgets").version(packageVersion);
|
|
7075
|
+
program.name("mcp-use").description("Create and run MCP servers with ui resources widgets").version(packageVersion).showHelpAfterError("(Run `mcp-use --help` to see available commands)");
|
|
5612
7076
|
function displayPackageVersions(projectPath) {
|
|
5613
7077
|
const packages = [
|
|
5614
7078
|
{ name: "@mcp-use/cli", relativePath: "../package.json" },
|
|
@@ -5634,16 +7098,16 @@ function displayPackageVersions(projectPath) {
|
|
|
5634
7098
|
if (projectPath) {
|
|
5635
7099
|
try {
|
|
5636
7100
|
const projectRequire = (0, import_node_module2.createRequire)(
|
|
5637
|
-
|
|
7101
|
+
import_node_path12.default.join(projectPath, "package.json")
|
|
5638
7102
|
);
|
|
5639
7103
|
pkgPath = projectRequire.resolve(`${pkg.name}/package.json`);
|
|
5640
7104
|
} catch (resolveError) {
|
|
5641
|
-
pkgPath =
|
|
7105
|
+
pkgPath = import_node_path12.default.join(__dirname, pkg.relativePath);
|
|
5642
7106
|
}
|
|
5643
7107
|
} else {
|
|
5644
|
-
pkgPath =
|
|
7108
|
+
pkgPath = import_node_path12.default.join(__dirname, pkg.relativePath);
|
|
5645
7109
|
}
|
|
5646
|
-
const pkgContent = (0,
|
|
7110
|
+
const pkgContent = (0, import_node_fs14.readFileSync)(pkgPath, "utf-8");
|
|
5647
7111
|
const pkgJson = JSON.parse(pkgContent);
|
|
5648
7112
|
const version = pkgJson.version || "unknown";
|
|
5649
7113
|
if (pkg.highlight) {
|
|
@@ -5698,7 +7162,7 @@ function normalizeBrowserHost(host) {
|
|
|
5698
7162
|
return host === "0.0.0.0" ? "localhost" : host;
|
|
5699
7163
|
}
|
|
5700
7164
|
function runCommand(command, args, cwd, env2, filterStderr = false) {
|
|
5701
|
-
const proc = (0,
|
|
7165
|
+
const proc = (0, import_node_child_process11.spawn)(command, args, {
|
|
5702
7166
|
cwd,
|
|
5703
7167
|
stdio: filterStderr ? ["inherit", "inherit", "pipe"] : "inherit",
|
|
5704
7168
|
shell: process.platform === "win32",
|
|
@@ -5731,7 +7195,7 @@ async function startTunnel(port, subdomain) {
|
|
|
5731
7195
|
if (subdomain) {
|
|
5732
7196
|
tunnelArgs.push("--subdomain", subdomain);
|
|
5733
7197
|
}
|
|
5734
|
-
const proc = (0,
|
|
7198
|
+
const proc = (0, import_node_child_process11.spawn)("npx", tunnelArgs, {
|
|
5735
7199
|
stdio: ["ignore", "pipe", "pipe"],
|
|
5736
7200
|
shell: process.platform === "win32"
|
|
5737
7201
|
});
|
|
@@ -5795,21 +7259,21 @@ async function startTunnel(port, subdomain) {
|
|
|
5795
7259
|
}
|
|
5796
7260
|
async function resolveEntryFile(projectPath, cliEntry, mcpDir) {
|
|
5797
7261
|
if (cliEntry) {
|
|
5798
|
-
await (0,
|
|
7262
|
+
await (0, import_promises8.access)(import_node_path12.default.join(projectPath, cliEntry)).catch(() => {
|
|
5799
7263
|
throw new Error(`File not found: ${cliEntry}`);
|
|
5800
7264
|
});
|
|
5801
7265
|
return cliEntry;
|
|
5802
7266
|
}
|
|
5803
7267
|
if (mcpDir) {
|
|
5804
7268
|
const mcpCandidates = [
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
|
|
7269
|
+
import_node_path12.default.join(mcpDir, "index.ts"),
|
|
7270
|
+
import_node_path12.default.join(mcpDir, "index.tsx"),
|
|
7271
|
+
import_node_path12.default.join(mcpDir, "server.ts"),
|
|
7272
|
+
import_node_path12.default.join(mcpDir, "server.tsx")
|
|
5809
7273
|
];
|
|
5810
7274
|
for (const candidate of mcpCandidates) {
|
|
5811
7275
|
try {
|
|
5812
|
-
await (0,
|
|
7276
|
+
await (0, import_promises8.access)(import_node_path12.default.join(projectPath, candidate));
|
|
5813
7277
|
return candidate;
|
|
5814
7278
|
} catch {
|
|
5815
7279
|
continue;
|
|
@@ -5818,17 +7282,17 @@ async function resolveEntryFile(projectPath, cliEntry, mcpDir) {
|
|
|
5818
7282
|
throw new Error(
|
|
5819
7283
|
`No entry file found inside ${mcpDir}.
|
|
5820
7284
|
|
|
5821
|
-
Expected one of: ${mcpCandidates.map((c) =>
|
|
7285
|
+
Expected one of: ${mcpCandidates.map((c) => import_node_path12.default.relative(projectPath, import_node_path12.default.join(projectPath, c))).join(", ")}
|
|
5822
7286
|
|
|
5823
7287
|
Fix this by either:
|
|
5824
|
-
1. Creating ${
|
|
7288
|
+
1. Creating ${import_node_path12.default.join(mcpDir, "index.ts")}, or
|
|
5825
7289
|
2. Passing --entry <file> on the command line`
|
|
5826
7290
|
);
|
|
5827
7291
|
}
|
|
5828
7292
|
const candidates = ["index.ts", "src/index.ts", "server.ts", "src/server.ts"];
|
|
5829
7293
|
for (const candidate of candidates) {
|
|
5830
7294
|
try {
|
|
5831
|
-
await (0,
|
|
7295
|
+
await (0, import_promises8.access)(import_node_path12.default.join(projectPath, candidate));
|
|
5832
7296
|
return candidate;
|
|
5833
7297
|
} catch {
|
|
5834
7298
|
continue;
|
|
@@ -5846,7 +7310,7 @@ Fix this by either:
|
|
|
5846
7310
|
}
|
|
5847
7311
|
function resolveWidgetsDir(cliWidgetsDir, mcpDir) {
|
|
5848
7312
|
if (cliWidgetsDir) return cliWidgetsDir;
|
|
5849
|
-
if (mcpDir) return
|
|
7313
|
+
if (mcpDir) return import_node_path12.default.join(mcpDir, "resources");
|
|
5850
7314
|
return "resources";
|
|
5851
7315
|
}
|
|
5852
7316
|
function makeWidgetServerOnlyGuard(widgetName) {
|
|
@@ -5881,8 +7345,8 @@ function isBunRuntime() {
|
|
|
5881
7345
|
return typeof globalThis.Bun !== "undefined" || typeof process.versions.bun === "string";
|
|
5882
7346
|
}
|
|
5883
7347
|
async function generateToolRegistryTypesForServer(projectPath, serverFileRelative) {
|
|
5884
|
-
const serverFile =
|
|
5885
|
-
const serverFileExists = await (0,
|
|
7348
|
+
const serverFile = import_node_path12.default.join(projectPath, serverFileRelative);
|
|
7349
|
+
const serverFileExists = await (0, import_promises8.access)(serverFile).then(() => true).catch(() => false);
|
|
5886
7350
|
if (!serverFileExists) {
|
|
5887
7351
|
throw new Error(`Server file not found: ${serverFile}`);
|
|
5888
7352
|
}
|
|
@@ -5907,8 +7371,8 @@ async function generateToolRegistryTypesForServer(projectPath, serverFileRelativ
|
|
|
5907
7371
|
await loadNextJsEnvFiles(projectPath);
|
|
5908
7372
|
await registerNextShimsInProcess();
|
|
5909
7373
|
}
|
|
5910
|
-
const projectTsconfigPath =
|
|
5911
|
-
const hasTsconfig = await (0,
|
|
7374
|
+
const projectTsconfigPath = import_node_path12.default.join(projectPath, "tsconfig.json");
|
|
7375
|
+
const hasTsconfig = await (0, import_promises8.access)(projectTsconfigPath).then(() => true).catch(() => false);
|
|
5912
7376
|
if (hasTsconfig) {
|
|
5913
7377
|
process.env.TSX_TSCONFIG_PATH = projectTsconfigPath;
|
|
5914
7378
|
}
|
|
@@ -5916,7 +7380,7 @@ async function generateToolRegistryTypesForServer(projectPath, serverFileRelativ
|
|
|
5916
7380
|
if (previousCwd !== projectPath) process.chdir(projectPath);
|
|
5917
7381
|
try {
|
|
5918
7382
|
const projectRequire = (0, import_node_module2.createRequire)(
|
|
5919
|
-
|
|
7383
|
+
import_node_path12.default.join(projectPath, "package.json")
|
|
5920
7384
|
);
|
|
5921
7385
|
const tsxEsmApiPath = projectRequire.resolve("tsx/esm/api");
|
|
5922
7386
|
const tsxEsmApi = await import((0, import_node_url3.pathToFileURL)(tsxEsmApiPath).href);
|
|
@@ -5943,8 +7407,8 @@ async function generateToolRegistryTypesForServer(projectPath, serverFileRelativ
|
|
|
5943
7407
|
"No MCPServer instance found. Make sure your server file creates an MCPServer instance."
|
|
5944
7408
|
);
|
|
5945
7409
|
}
|
|
5946
|
-
const mcpUsePath =
|
|
5947
|
-
const { generateToolRegistryTypes } = await import((0, import_node_url3.pathToFileURL)(
|
|
7410
|
+
const mcpUsePath = import_node_path12.default.join(projectPath, "node_modules", "mcp-use");
|
|
7411
|
+
const { generateToolRegistryTypes } = await import((0, import_node_url3.pathToFileURL)(import_node_path12.default.join(mcpUsePath, "dist", "src", "server", "index.js")).href).then((mod) => mod);
|
|
5948
7412
|
if (!generateToolRegistryTypes) {
|
|
5949
7413
|
throw new Error("generateToolRegistryTypes not found in mcp-use package");
|
|
5950
7414
|
}
|
|
@@ -5962,10 +7426,10 @@ async function buildWidgets(projectPath, options = {}) {
|
|
|
5962
7426
|
const { promises: fs11 } = await import("fs");
|
|
5963
7427
|
const { build } = await import("vite");
|
|
5964
7428
|
const widgetsDirRelative = options.widgetsDir ?? "resources";
|
|
5965
|
-
const resourcesDir =
|
|
7429
|
+
const resourcesDir = import_node_path12.default.resolve(projectPath, widgetsDirRelative);
|
|
5966
7430
|
const mcpUrl = process.env.MCP_URL;
|
|
5967
7431
|
try {
|
|
5968
|
-
await (0,
|
|
7432
|
+
await (0, import_promises8.access)(resourcesDir);
|
|
5969
7433
|
} catch {
|
|
5970
7434
|
console.log(
|
|
5971
7435
|
source_default.gray(
|
|
@@ -5984,10 +7448,10 @@ async function buildWidgets(projectPath, options = {}) {
|
|
|
5984
7448
|
if (dirent.isFile() && (dirent.name.endsWith(".tsx") || dirent.name.endsWith(".ts"))) {
|
|
5985
7449
|
entries.push({
|
|
5986
7450
|
name: dirent.name.replace(/\.tsx?$/, ""),
|
|
5987
|
-
path:
|
|
7451
|
+
path: import_node_path12.default.join(resourcesDir, dirent.name)
|
|
5988
7452
|
});
|
|
5989
7453
|
} else if (dirent.isDirectory()) {
|
|
5990
|
-
const widgetPath =
|
|
7454
|
+
const widgetPath = import_node_path12.default.join(resourcesDir, dirent.name, "widget.tsx");
|
|
5991
7455
|
try {
|
|
5992
7456
|
await fs11.access(widgetPath);
|
|
5993
7457
|
entries.push({
|
|
@@ -6017,14 +7481,14 @@ async function buildWidgets(projectPath, options = {}) {
|
|
|
6017
7481
|
);
|
|
6018
7482
|
const react = (await import("@vitejs/plugin-react")).default;
|
|
6019
7483
|
const tailwindcss = (await import("@tailwindcss/vite")).default;
|
|
6020
|
-
const projectTsconfigPath =
|
|
7484
|
+
const projectTsconfigPath = import_node_path12.default.join(projectPath, "tsconfig.json");
|
|
6021
7485
|
let hasProjectTsconfig = false;
|
|
6022
7486
|
try {
|
|
6023
|
-
await (0,
|
|
7487
|
+
await (0, import_promises8.access)(projectTsconfigPath);
|
|
6024
7488
|
hasProjectTsconfig = true;
|
|
6025
7489
|
} catch {
|
|
6026
7490
|
}
|
|
6027
|
-
const packageJsonPath =
|
|
7491
|
+
const packageJsonPath = import_node_path12.default.join(projectPath, "package.json");
|
|
6028
7492
|
let favicon = "";
|
|
6029
7493
|
try {
|
|
6030
7494
|
const pkgContent = await fs11.readFile(packageJsonPath, "utf-8");
|
|
@@ -6036,16 +7500,16 @@ async function buildWidgets(projectPath, options = {}) {
|
|
|
6036
7500
|
const widgetName = entry.name;
|
|
6037
7501
|
const entryPath = entry.path.replace(/\\/g, "/");
|
|
6038
7502
|
console.log(source_default.gray(` - Building ${widgetName}...`));
|
|
6039
|
-
const tempDir =
|
|
7503
|
+
const tempDir = import_node_path12.default.join(projectPath, ".mcp-use", widgetName);
|
|
6040
7504
|
await fs11.mkdir(tempDir, { recursive: true });
|
|
6041
|
-
const relativeResourcesPath =
|
|
6042
|
-
const mcpUsePath =
|
|
6043
|
-
const relativeMcpUsePath =
|
|
6044
|
-
const projectSrcDir =
|
|
7505
|
+
const relativeResourcesPath = import_node_path12.default.relative(tempDir, resourcesDir).replace(/\\/g, "/");
|
|
7506
|
+
const mcpUsePath = import_node_path12.default.join(projectPath, "node_modules", "mcp-use");
|
|
7507
|
+
const relativeMcpUsePath = import_node_path12.default.relative(tempDir, mcpUsePath).replace(/\\/g, "/");
|
|
7508
|
+
const projectSrcDir = import_node_path12.default.join(projectPath, "src");
|
|
6045
7509
|
let projectSrcSourceLine = "";
|
|
6046
7510
|
try {
|
|
6047
|
-
await (0,
|
|
6048
|
-
const relativeProjectSrcPath =
|
|
7511
|
+
await (0, import_promises8.access)(projectSrcDir);
|
|
7512
|
+
const relativeProjectSrcPath = import_node_path12.default.relative(tempDir, projectSrcDir).replace(/\\/g, "/");
|
|
6049
7513
|
projectSrcSourceLine = `@source "${relativeProjectSrcPath}";
|
|
6050
7514
|
`;
|
|
6051
7515
|
} catch {
|
|
@@ -6056,7 +7520,7 @@ async function buildWidgets(projectPath, options = {}) {
|
|
|
6056
7520
|
@source "${relativeResourcesPath}";
|
|
6057
7521
|
@source "${relativeMcpUsePath}/**/*.{ts,tsx,js,jsx}";
|
|
6058
7522
|
${projectSrcSourceLine}`;
|
|
6059
|
-
await fs11.writeFile(
|
|
7523
|
+
await fs11.writeFile(import_node_path12.default.join(tempDir, "styles.css"), cssContent, "utf8");
|
|
6060
7524
|
const entryContent = `import React from 'react'
|
|
6061
7525
|
import { createRoot } from 'react-dom/client'
|
|
6062
7526
|
import './styles.css'
|
|
@@ -6081,9 +7545,9 @@ if (container && Component) {
|
|
|
6081
7545
|
<script type="module" src="/entry.tsx"></script>
|
|
6082
7546
|
</body>
|
|
6083
7547
|
</html>`;
|
|
6084
|
-
await fs11.writeFile(
|
|
6085
|
-
await fs11.writeFile(
|
|
6086
|
-
const outDir =
|
|
7548
|
+
await fs11.writeFile(import_node_path12.default.join(tempDir, "entry.tsx"), entryContent, "utf8");
|
|
7549
|
+
await fs11.writeFile(import_node_path12.default.join(tempDir, "index.html"), htmlContent, "utf8");
|
|
7550
|
+
const outDir = import_node_path12.default.join(
|
|
6087
7551
|
projectPath,
|
|
6088
7552
|
"dist",
|
|
6089
7553
|
"resources",
|
|
@@ -6093,13 +7557,13 @@ if (container && Component) {
|
|
|
6093
7557
|
const baseUrl = mcpUrl ? `${mcpUrl}/${widgetName}/` : `/mcp-use/widgets/${widgetName}/`;
|
|
6094
7558
|
let widgetMetadata = {};
|
|
6095
7559
|
try {
|
|
6096
|
-
const metadataTempDir =
|
|
7560
|
+
const metadataTempDir = import_node_path12.default.join(
|
|
6097
7561
|
projectPath,
|
|
6098
7562
|
".mcp-use",
|
|
6099
7563
|
`${widgetName}-metadata`
|
|
6100
7564
|
);
|
|
6101
7565
|
await fs11.mkdir(metadataTempDir, { recursive: true });
|
|
6102
|
-
const { createServer } = await import("vite");
|
|
7566
|
+
const { createServer: createServer2 } = await import("vite");
|
|
6103
7567
|
const nodeStubsPlugin = {
|
|
6104
7568
|
name: "node-stubs",
|
|
6105
7569
|
enforce: "pre",
|
|
@@ -6127,9 +7591,9 @@ export default PostHog;
|
|
|
6127
7591
|
}
|
|
6128
7592
|
};
|
|
6129
7593
|
const serverOnlyGuard = makeWidgetServerOnlyGuard(widgetName);
|
|
6130
|
-
const metadataServer = await
|
|
7594
|
+
const metadataServer = await createServer2({
|
|
6131
7595
|
root: metadataTempDir,
|
|
6132
|
-
cacheDir:
|
|
7596
|
+
cacheDir: import_node_path12.default.join(metadataTempDir, ".vite-cache"),
|
|
6133
7597
|
plugins: [serverOnlyGuard, nodeStubsPlugin, tailwindcss(), react()],
|
|
6134
7598
|
// When the project has a tsconfig, enable Vite's native tsconfig-paths
|
|
6135
7599
|
// resolver so `@/*` (or any custom alias) resolves through the
|
|
@@ -6360,7 +7824,7 @@ export default {
|
|
|
6360
7824
|
// Inline all assets under 100MB (effectively all)
|
|
6361
7825
|
} : {},
|
|
6362
7826
|
rolldownOptions: {
|
|
6363
|
-
input:
|
|
7827
|
+
input: import_node_path12.default.join(tempDir, "index.html"),
|
|
6364
7828
|
external: (id) => {
|
|
6365
7829
|
return false;
|
|
6366
7830
|
}
|
|
@@ -6368,11 +7832,11 @@ export default {
|
|
|
6368
7832
|
}
|
|
6369
7833
|
});
|
|
6370
7834
|
try {
|
|
6371
|
-
const assetsDir =
|
|
7835
|
+
const assetsDir = import_node_path12.default.join(outDir, "assets");
|
|
6372
7836
|
const assetFiles = await fs11.readdir(assetsDir);
|
|
6373
7837
|
const jsFiles = assetFiles.filter((f) => f.endsWith(".js"));
|
|
6374
7838
|
for (const jsFile of jsFiles) {
|
|
6375
|
-
const jsPath =
|
|
7839
|
+
const jsPath = import_node_path12.default.join(assetsDir, jsFile);
|
|
6376
7840
|
let content = await fs11.readFile(jsPath, "utf8");
|
|
6377
7841
|
const zodConfigPatterns = [
|
|
6378
7842
|
// Non-minified: export const globalConfig = {}
|
|
@@ -6404,7 +7868,7 @@ export default {
|
|
|
6404
7868
|
const mcpServerUrl = process.env.MCP_SERVER_URL;
|
|
6405
7869
|
if (mcpServerUrl) {
|
|
6406
7870
|
try {
|
|
6407
|
-
const htmlPath =
|
|
7871
|
+
const htmlPath = import_node_path12.default.join(outDir, "index.html");
|
|
6408
7872
|
let html = await fs11.readFile(htmlPath, "utf8");
|
|
6409
7873
|
const injectionScript = `<script>window.__getFile = (filename) => { return "${mcpUrl}/${widgetName}/"+filename }; window.__mcpPublicUrl = "${mcpServerUrl}/mcp-use/public"; window.__mcpPublicAssetsUrl = "${mcpUrl}/public";</script>`;
|
|
6410
7874
|
if (!html.includes("window.__mcpPublicUrl")) {
|
|
@@ -6480,7 +7944,7 @@ async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
|
|
|
6480
7944
|
for (const file of literalFiles) {
|
|
6481
7945
|
if (/\.tsx?$/.test(file) && !file.endsWith(".d.ts")) {
|
|
6482
7946
|
try {
|
|
6483
|
-
await (0,
|
|
7947
|
+
await (0, import_promises8.access)(import_node_path12.default.join(projectPath, file));
|
|
6484
7948
|
files.push(file);
|
|
6485
7949
|
} catch {
|
|
6486
7950
|
}
|
|
@@ -6488,13 +7952,13 @@ async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
|
|
|
6488
7952
|
}
|
|
6489
7953
|
const excludeSet = new Set(excludePatterns.map((e) => e.replace(/\*+/g, "")));
|
|
6490
7954
|
for (const prefix of dirPrefixes) {
|
|
6491
|
-
const dirPath =
|
|
7955
|
+
const dirPath = import_node_path12.default.join(projectPath, prefix);
|
|
6492
7956
|
try {
|
|
6493
7957
|
const entries = await fs11.readdir(dirPath, { recursive: true });
|
|
6494
7958
|
for (const entry of entries) {
|
|
6495
7959
|
const entryStr = String(entry);
|
|
6496
|
-
const rel =
|
|
6497
|
-
if (/\.tsx?$/.test(entryStr) && !entryStr.endsWith(".d.ts") && !excludeSet.has(rel.split(
|
|
7960
|
+
const rel = import_node_path12.default.join(prefix, entryStr);
|
|
7961
|
+
if (/\.tsx?$/.test(entryStr) && !entryStr.endsWith(".d.ts") && !excludeSet.has(rel.split(import_node_path12.default.sep)[0])) {
|
|
6498
7962
|
files.push(rel);
|
|
6499
7963
|
}
|
|
6500
7964
|
}
|
|
@@ -6506,7 +7970,7 @@ async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
|
|
|
6506
7970
|
async function transpileWithEsbuild(projectPath) {
|
|
6507
7971
|
const esbuild = await import("esbuild");
|
|
6508
7972
|
const { promises: fs11 } = await import("fs");
|
|
6509
|
-
const tsconfigPath =
|
|
7973
|
+
const tsconfigPath = import_node_path12.default.join(projectPath, "tsconfig.json");
|
|
6510
7974
|
let tsconfig = {};
|
|
6511
7975
|
try {
|
|
6512
7976
|
const raw = await fs11.readFile(tsconfigPath, "utf-8");
|
|
@@ -6536,10 +8000,10 @@ async function transpileWithEsbuild(projectPath) {
|
|
|
6536
8000
|
const target = (compilerOptions.target || "ES2022").toLowerCase();
|
|
6537
8001
|
const moduleStr = (compilerOptions.module || "ESNext").toLowerCase();
|
|
6538
8002
|
const format = moduleStr.includes("commonjs") ? "cjs" : "esm";
|
|
6539
|
-
const outbase = compilerOptions.rootDir ?
|
|
8003
|
+
const outbase = compilerOptions.rootDir ? import_node_path12.default.resolve(projectPath, compilerOptions.rootDir) : projectPath;
|
|
6540
8004
|
await esbuild.build({
|
|
6541
|
-
entryPoints: files.map((f) =>
|
|
6542
|
-
outdir:
|
|
8005
|
+
entryPoints: files.map((f) => import_node_path12.default.join(projectPath, f)),
|
|
8006
|
+
outdir: import_node_path12.default.join(projectPath, outDir),
|
|
6543
8007
|
outbase,
|
|
6544
8008
|
bundle: true,
|
|
6545
8009
|
packages: "external",
|
|
@@ -6566,7 +8030,7 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
6566
8030
|
"Inline all JS/CSS into HTML (required for VS Code MCP Apps)"
|
|
6567
8031
|
).option("--no-inline", "Keep JS/CSS as separate files (default)").option("--no-typecheck", "Skip TypeScript type checking (faster builds)").action(async (options) => {
|
|
6568
8032
|
try {
|
|
6569
|
-
const projectPath =
|
|
8033
|
+
const projectPath = import_node_path12.default.resolve(options.path);
|
|
6570
8034
|
const { promises: fs11 } = await import("fs");
|
|
6571
8035
|
displayPackageVersions(projectPath);
|
|
6572
8036
|
const mcpDir = options.mcpDir;
|
|
@@ -6626,7 +8090,7 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
6626
8090
|
}
|
|
6627
8091
|
if (options.typecheck !== false && !mcpDir) {
|
|
6628
8092
|
console.log(source_default.gray("Type checking..."));
|
|
6629
|
-
const tscBin =
|
|
8093
|
+
const tscBin = import_node_path12.default.join(
|
|
6630
8094
|
projectPath,
|
|
6631
8095
|
"node_modules",
|
|
6632
8096
|
"typescript",
|
|
@@ -6649,7 +8113,7 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
6649
8113
|
if (mcpDir) {
|
|
6650
8114
|
entryPoint = sourceServerFile;
|
|
6651
8115
|
} else {
|
|
6652
|
-
const baseName =
|
|
8116
|
+
const baseName = import_node_path12.default.basename(sourceServerFile, ".ts") + ".js";
|
|
6653
8117
|
const possibleOutputs = [
|
|
6654
8118
|
`dist/${baseName}`,
|
|
6655
8119
|
// rootDir set to project root or src
|
|
@@ -6660,7 +8124,7 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
6660
8124
|
];
|
|
6661
8125
|
for (const candidate of possibleOutputs) {
|
|
6662
8126
|
try {
|
|
6663
|
-
await (0,
|
|
8127
|
+
await (0, import_promises8.access)(import_node_path12.default.join(projectPath, candidate));
|
|
6664
8128
|
entryPoint = candidate;
|
|
6665
8129
|
break;
|
|
6666
8130
|
} catch {
|
|
@@ -6669,17 +8133,17 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
6669
8133
|
}
|
|
6670
8134
|
}
|
|
6671
8135
|
}
|
|
6672
|
-
const publicDir =
|
|
8136
|
+
const publicDir = import_node_path12.default.join(projectPath, "public");
|
|
6673
8137
|
try {
|
|
6674
8138
|
await fs11.access(publicDir);
|
|
6675
8139
|
console.log(source_default.gray("Copying public assets..."));
|
|
6676
|
-
await fs11.cp(publicDir,
|
|
8140
|
+
await fs11.cp(publicDir, import_node_path12.default.join(projectPath, "dist", "public"), {
|
|
6677
8141
|
recursive: true
|
|
6678
8142
|
});
|
|
6679
8143
|
console.log(source_default.green("\u2713 Public assets copied"));
|
|
6680
8144
|
} catch {
|
|
6681
8145
|
}
|
|
6682
|
-
const manifestPath =
|
|
8146
|
+
const manifestPath = import_node_path12.default.join(projectPath, "dist", "mcp-use.json");
|
|
6683
8147
|
let existingManifest = {};
|
|
6684
8148
|
try {
|
|
6685
8149
|
const existingContent = await fs11.readFile(manifestPath, "utf-8");
|
|
@@ -6704,7 +8168,7 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
6704
8168
|
// Server entry point for `mcp-use start`
|
|
6705
8169
|
widgets: widgetsData
|
|
6706
8170
|
};
|
|
6707
|
-
await fs11.mkdir(
|
|
8171
|
+
await fs11.mkdir(import_node_path12.default.dirname(manifestPath), { recursive: true });
|
|
6708
8172
|
await fs11.writeFile(
|
|
6709
8173
|
manifestPath,
|
|
6710
8174
|
JSON.stringify(manifest, null, 2),
|
|
@@ -6741,7 +8205,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6741
8205
|
).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) => {
|
|
6742
8206
|
try {
|
|
6743
8207
|
process.env.MCP_USE_CLI_DEV = "1";
|
|
6744
|
-
const projectPath =
|
|
8208
|
+
const projectPath = import_node_path12.default.resolve(options.path);
|
|
6745
8209
|
let port = parseInt(options.port, 10);
|
|
6746
8210
|
const host = options.host;
|
|
6747
8211
|
const useHmr = options.hmr !== false;
|
|
@@ -6769,10 +8233,10 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6769
8233
|
let tunnelUrl = void 0;
|
|
6770
8234
|
if (options.tunnel) {
|
|
6771
8235
|
try {
|
|
6772
|
-
const manifestPath =
|
|
8236
|
+
const manifestPath = import_node_path12.default.join(projectPath, "dist", "mcp-use.json");
|
|
6773
8237
|
let existingSubdomain;
|
|
6774
8238
|
try {
|
|
6775
|
-
const manifestContent = await (0,
|
|
8239
|
+
const manifestContent = await (0, import_promises8.readFile)(manifestPath, "utf-8");
|
|
6776
8240
|
const manifest = JSON.parse(manifestContent);
|
|
6777
8241
|
existingSubdomain = manifest.tunnel?.subdomain;
|
|
6778
8242
|
if (existingSubdomain) {
|
|
@@ -6810,7 +8274,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6810
8274
|
try {
|
|
6811
8275
|
let manifest = {};
|
|
6812
8276
|
try {
|
|
6813
|
-
const manifestContent = await (0,
|
|
8277
|
+
const manifestContent = await (0, import_promises8.readFile)(manifestPath, "utf-8");
|
|
6814
8278
|
manifest = JSON.parse(manifestContent);
|
|
6815
8279
|
} catch {
|
|
6816
8280
|
}
|
|
@@ -6818,8 +8282,8 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6818
8282
|
manifest.tunnel = {};
|
|
6819
8283
|
}
|
|
6820
8284
|
manifest.tunnel.subdomain = tunnelSubdomain;
|
|
6821
|
-
await (0,
|
|
6822
|
-
await (0,
|
|
8285
|
+
await (0, import_promises8.mkdir)(import_node_path12.default.dirname(manifestPath), { recursive: true });
|
|
8286
|
+
await (0, import_promises8.writeFile)(
|
|
6823
8287
|
manifestPath,
|
|
6824
8288
|
JSON.stringify(manifest, null, 2),
|
|
6825
8289
|
"utf-8"
|
|
@@ -6873,10 +8337,10 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6873
8337
|
let args;
|
|
6874
8338
|
try {
|
|
6875
8339
|
const projectRequire = createRequire4(
|
|
6876
|
-
|
|
8340
|
+
import_node_path12.default.join(projectPath, "package.json")
|
|
6877
8341
|
);
|
|
6878
8342
|
const tsxPkgPath = projectRequire.resolve("tsx/package.json");
|
|
6879
|
-
const tsxPkg = JSON.parse(await (0,
|
|
8343
|
+
const tsxPkg = JSON.parse(await (0, import_promises8.readFile)(tsxPkgPath, "utf-8"));
|
|
6880
8344
|
let binPath;
|
|
6881
8345
|
if (typeof tsxPkg.bin === "string") {
|
|
6882
8346
|
binPath = tsxPkg.bin;
|
|
@@ -6885,7 +8349,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6885
8349
|
} else {
|
|
6886
8350
|
throw new Error("No bin field found in tsx package.json");
|
|
6887
8351
|
}
|
|
6888
|
-
const tsxBin =
|
|
8352
|
+
const tsxBin = import_node_path12.default.resolve(import_node_path12.default.dirname(tsxPkgPath), binPath);
|
|
6889
8353
|
cmd = "node";
|
|
6890
8354
|
args = [tsxBin, "watch", serverFile];
|
|
6891
8355
|
} catch (error) {
|
|
@@ -6974,10 +8438,10 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6974
8438
|
const chokidar = chokidarModule.default || chokidarModule;
|
|
6975
8439
|
const { fileURLToPath: fileURLToPath3 } = await import("url");
|
|
6976
8440
|
const { createRequire: createRequire3 } = await import("module");
|
|
6977
|
-
const projectTsconfigPath =
|
|
8441
|
+
const projectTsconfigPath = import_node_path12.default.join(projectPath, "tsconfig.json");
|
|
6978
8442
|
let tsconfigAvailable = false;
|
|
6979
8443
|
try {
|
|
6980
|
-
await (0,
|
|
8444
|
+
await (0, import_promises8.access)(projectTsconfigPath);
|
|
6981
8445
|
tsconfigAvailable = true;
|
|
6982
8446
|
process.env.TSX_TSCONFIG_PATH = projectTsconfigPath;
|
|
6983
8447
|
if (process.cwd() !== projectPath) process.chdir(projectPath);
|
|
@@ -6986,7 +8450,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6986
8450
|
let tsxLoaderActive = false;
|
|
6987
8451
|
try {
|
|
6988
8452
|
const projectRequire = createRequire3(
|
|
6989
|
-
|
|
8453
|
+
import_node_path12.default.join(projectPath, "package.json")
|
|
6990
8454
|
);
|
|
6991
8455
|
const tsxEsmApiPath = projectRequire.resolve("tsx/esm/api");
|
|
6992
8456
|
const tsxEsmApi = await import((0, import_node_url3.pathToFileURL)(tsxEsmApiPath).href);
|
|
@@ -7017,7 +8481,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
7017
8481
|
)
|
|
7018
8482
|
);
|
|
7019
8483
|
}
|
|
7020
|
-
const serverFilePath =
|
|
8484
|
+
const serverFilePath = import_node_path12.default.join(projectPath, serverFile);
|
|
7021
8485
|
const serverFileUrl = (0, import_node_url3.pathToFileURL)(serverFilePath).href;
|
|
7022
8486
|
globalThis.__mcpUseHmrMode = true;
|
|
7023
8487
|
const importServerModule = async () => {
|
|
@@ -7114,8 +8578,8 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
7114
8578
|
}
|
|
7115
8579
|
let watcher = chokidar.watch(".", {
|
|
7116
8580
|
cwd: projectPath,
|
|
7117
|
-
ignored: (
|
|
7118
|
-
const normalizedPath =
|
|
8581
|
+
ignored: (path11, stats) => {
|
|
8582
|
+
const normalizedPath = path11.replace(/\\/g, "/");
|
|
7119
8583
|
if (/(^|\/)\.[^/]/.test(normalizedPath)) {
|
|
7120
8584
|
return true;
|
|
7121
8585
|
}
|
|
@@ -7289,10 +8753,10 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
7289
8753
|
}
|
|
7290
8754
|
tunnelUrl = void 0;
|
|
7291
8755
|
if (withTunnel) {
|
|
7292
|
-
const manifestPath =
|
|
8756
|
+
const manifestPath = import_node_path12.default.join(projectPath, "dist", "mcp-use.json");
|
|
7293
8757
|
let existingSubdomain;
|
|
7294
8758
|
try {
|
|
7295
|
-
const manifestContent = await (0,
|
|
8759
|
+
const manifestContent = await (0, import_promises8.readFile)(manifestPath, "utf-8");
|
|
7296
8760
|
const manifest = JSON.parse(manifestContent);
|
|
7297
8761
|
existingSubdomain = manifest.tunnel?.subdomain;
|
|
7298
8762
|
if (existingSubdomain) {
|
|
@@ -7326,16 +8790,16 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
7326
8790
|
tunnelSubdomain = tunnelInfo.subdomain;
|
|
7327
8791
|
process.env.MCP_URL = tunnelUrl;
|
|
7328
8792
|
try {
|
|
7329
|
-
const mPath =
|
|
8793
|
+
const mPath = import_node_path12.default.join(projectPath, "dist", "mcp-use.json");
|
|
7330
8794
|
let manifest = {};
|
|
7331
8795
|
try {
|
|
7332
|
-
manifest = JSON.parse(await (0,
|
|
8796
|
+
manifest = JSON.parse(await (0, import_promises8.readFile)(mPath, "utf-8"));
|
|
7333
8797
|
} catch {
|
|
7334
8798
|
}
|
|
7335
8799
|
if (!manifest.tunnel) manifest.tunnel = {};
|
|
7336
8800
|
manifest.tunnel.subdomain = tunnelSubdomain;
|
|
7337
|
-
await (0,
|
|
7338
|
-
await (0,
|
|
8801
|
+
await (0, import_promises8.mkdir)(import_node_path12.default.dirname(mPath), { recursive: true });
|
|
8802
|
+
await (0, import_promises8.writeFile)(mPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
7339
8803
|
} catch {
|
|
7340
8804
|
}
|
|
7341
8805
|
} else {
|
|
@@ -7438,7 +8902,7 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
7438
8902
|
"Folder holding the MCP entry + resources (e.g. 'src/mcp' for Next.js apps)"
|
|
7439
8903
|
).option("--port <port>", "Server port", "3000").option("--tunnel", "Expose server through a tunnel").action(async (options) => {
|
|
7440
8904
|
try {
|
|
7441
|
-
const projectPath =
|
|
8905
|
+
const projectPath = import_node_path12.default.resolve(options.path);
|
|
7442
8906
|
const portFlagProvided = process.argv.includes("--port") || process.argv.includes("-p") || process.argv.some((arg) => arg.startsWith("--port=")) || process.argv.some((arg) => arg.startsWith("-p="));
|
|
7443
8907
|
let port = portFlagProvided ? parseInt(options.port, 10) : parseInt(process.env.PORT || options.port || "3000", 10);
|
|
7444
8908
|
if (!await isPortAvailable(port)) {
|
|
@@ -7456,10 +8920,10 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
7456
8920
|
let tunnelSubdomain = void 0;
|
|
7457
8921
|
if (options.tunnel) {
|
|
7458
8922
|
try {
|
|
7459
|
-
const manifestPath2 =
|
|
8923
|
+
const manifestPath2 = import_node_path12.default.join(projectPath, "dist", "mcp-use.json");
|
|
7460
8924
|
let existingSubdomain;
|
|
7461
8925
|
try {
|
|
7462
|
-
const manifestContent = await (0,
|
|
8926
|
+
const manifestContent = await (0, import_promises8.readFile)(manifestPath2, "utf-8");
|
|
7463
8927
|
const manifest = JSON.parse(manifestContent);
|
|
7464
8928
|
existingSubdomain = manifest.tunnel?.subdomain;
|
|
7465
8929
|
if (existingSubdomain) {
|
|
@@ -7503,7 +8967,7 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
7503
8967
|
try {
|
|
7504
8968
|
let manifest = {};
|
|
7505
8969
|
try {
|
|
7506
|
-
const manifestContent = await (0,
|
|
8970
|
+
const manifestContent = await (0, import_promises8.readFile)(manifestPath2, "utf-8");
|
|
7507
8971
|
manifest = JSON.parse(manifestContent);
|
|
7508
8972
|
} catch {
|
|
7509
8973
|
}
|
|
@@ -7511,8 +8975,8 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
7511
8975
|
manifest.tunnel = {};
|
|
7512
8976
|
}
|
|
7513
8977
|
manifest.tunnel.subdomain = subdomain;
|
|
7514
|
-
await (0,
|
|
7515
|
-
await (0,
|
|
8978
|
+
await (0, import_promises8.mkdir)(import_node_path12.default.dirname(manifestPath2), { recursive: true });
|
|
8979
|
+
await (0, import_promises8.writeFile)(
|
|
7516
8980
|
manifestPath2,
|
|
7517
8981
|
JSON.stringify(manifest, null, 2),
|
|
7518
8982
|
"utf-8"
|
|
@@ -7530,12 +8994,12 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
7530
8994
|
}
|
|
7531
8995
|
}
|
|
7532
8996
|
let serverFile;
|
|
7533
|
-
const manifestPath =
|
|
8997
|
+
const manifestPath = import_node_path12.default.join(projectPath, "dist", "mcp-use.json");
|
|
7534
8998
|
try {
|
|
7535
|
-
const manifestContent = await (0,
|
|
8999
|
+
const manifestContent = await (0, import_promises8.readFile)(manifestPath, "utf-8");
|
|
7536
9000
|
const manifest = JSON.parse(manifestContent);
|
|
7537
9001
|
if (manifest.entryPoint) {
|
|
7538
|
-
await (0,
|
|
9002
|
+
await (0, import_promises8.access)(import_node_path12.default.join(projectPath, manifest.entryPoint));
|
|
7539
9003
|
serverFile = manifest.entryPoint;
|
|
7540
9004
|
}
|
|
7541
9005
|
} catch {
|
|
@@ -7556,7 +9020,7 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
7556
9020
|
];
|
|
7557
9021
|
for (const candidate of serverCandidates) {
|
|
7558
9022
|
try {
|
|
7559
|
-
await (0,
|
|
9023
|
+
await (0, import_promises8.access)(import_node_path12.default.join(projectPath, candidate));
|
|
7560
9024
|
serverFile = candidate;
|
|
7561
9025
|
break;
|
|
7562
9026
|
} catch {
|
|
@@ -7607,13 +9071,13 @@ Looked for:
|
|
|
7607
9071
|
if (isTsEntry) {
|
|
7608
9072
|
try {
|
|
7609
9073
|
const projectRequire = (0, import_node_module2.createRequire)(
|
|
7610
|
-
|
|
9074
|
+
import_node_path12.default.join(projectPath, "package.json")
|
|
7611
9075
|
);
|
|
7612
9076
|
const tsxPkgPath = projectRequire.resolve("tsx/package.json");
|
|
7613
|
-
const tsxPkg = JSON.parse(await (0,
|
|
9077
|
+
const tsxPkg = JSON.parse(await (0, import_promises8.readFile)(tsxPkgPath, "utf-8"));
|
|
7614
9078
|
const binField = typeof tsxPkg.bin === "string" ? tsxPkg.bin : tsxPkg.bin?.tsx ?? Object.values(tsxPkg.bin ?? {})[0];
|
|
7615
9079
|
if (!binField) throw new Error("tsx bin entry not found");
|
|
7616
|
-
const tsxBin =
|
|
9080
|
+
const tsxBin = import_node_path12.default.resolve(import_node_path12.default.dirname(tsxPkgPath), binField);
|
|
7617
9081
|
spawnCmd = "node";
|
|
7618
9082
|
spawnArgs = [tsxBin, serverFile];
|
|
7619
9083
|
} catch (error) {
|
|
@@ -7626,7 +9090,7 @@ Looked for:
|
|
|
7626
9090
|
spawnArgs = ["tsx", serverFile];
|
|
7627
9091
|
}
|
|
7628
9092
|
}
|
|
7629
|
-
const serverProc = (0,
|
|
9093
|
+
const serverProc = (0, import_node_child_process11.spawn)(spawnCmd, spawnArgs, {
|
|
7630
9094
|
cwd: projectPath,
|
|
7631
9095
|
stdio: "inherit",
|
|
7632
9096
|
env: env2
|
|
@@ -7759,10 +9223,11 @@ program.addCommand(createClientCommand());
|
|
|
7759
9223
|
program.addCommand(createDeploymentsCommand());
|
|
7760
9224
|
program.addCommand(createServersCommand());
|
|
7761
9225
|
program.addCommand(createSkillsCommand());
|
|
9226
|
+
program.addCommand(createScreenshotCommand());
|
|
7762
9227
|
program.command("generate-types").description(
|
|
7763
9228
|
"Generate TypeScript type definitions for tools (writes .mcp-use/tool-registry.d.ts)"
|
|
7764
9229
|
).option("-p, --path <path>", "Path to project directory", process.cwd()).option("--server <file>", "Server entry file", "index.ts").action(async (options) => {
|
|
7765
|
-
const projectPath =
|
|
9230
|
+
const projectPath = import_node_path12.default.resolve(options.path);
|
|
7766
9231
|
try {
|
|
7767
9232
|
console.log(source_default.blue("Generating tool registry types..."));
|
|
7768
9233
|
const result = await generateToolRegistryTypesForServer(
|
|
@@ -7792,5 +9257,49 @@ program.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
|
7792
9257
|
const projectPath = actionCommand.opts().path;
|
|
7793
9258
|
await notifyIfUpdateAvailable(projectPath);
|
|
7794
9259
|
});
|
|
7795
|
-
|
|
9260
|
+
var argv = process.argv;
|
|
9261
|
+
var clientIdx = argv[2] === "client" ? 2 : -1;
|
|
9262
|
+
var perClientName = clientIdx !== -1 && argv.length > clientIdx + 1 && !argv[clientIdx + 1].startsWith("-") && !RESERVED_CLIENT_SUBCOMMANDS.has(argv[clientIdx + 1]) ? argv[clientIdx + 1] : null;
|
|
9263
|
+
if (perClientName) {
|
|
9264
|
+
if (PER_CLIENT_SCOPES.has(perClientName)) {
|
|
9265
|
+
const rest2 = argv.slice(clientIdx + 1).join(" ");
|
|
9266
|
+
console.error(formatError("Missing server name."));
|
|
9267
|
+
console.error("");
|
|
9268
|
+
console.error(
|
|
9269
|
+
`'${perClientName}' is a per-server subcommand, not a server name. Address it through a saved server:`
|
|
9270
|
+
);
|
|
9271
|
+
console.error("");
|
|
9272
|
+
console.error(` mcp-use client <name> ${rest2}`);
|
|
9273
|
+
console.error("");
|
|
9274
|
+
console.error("See your saved servers with:");
|
|
9275
|
+
console.error(" mcp-use client list");
|
|
9276
|
+
process.exit(1);
|
|
9277
|
+
}
|
|
9278
|
+
const rest = argv.slice(clientIdx + 2);
|
|
9279
|
+
const isHelpOnly = rest.length === 0 || rest.length === 1 && (rest[0] === "--help" || rest[0] === "-h");
|
|
9280
|
+
(async () => {
|
|
9281
|
+
if (isHelpOnly) {
|
|
9282
|
+
const config = await getSession(perClientName);
|
|
9283
|
+
if (!config) {
|
|
9284
|
+
console.error(formatError(`Server '${perClientName}' not found.`));
|
|
9285
|
+
console.error("");
|
|
9286
|
+
console.error("Connect to an MCP server and save it under this name:");
|
|
9287
|
+
console.error(` mcp-use client connect ${perClientName} <url>`);
|
|
9288
|
+
console.error("");
|
|
9289
|
+
console.error("See your saved servers with:");
|
|
9290
|
+
console.error(" mcp-use client list");
|
|
9291
|
+
process.exit(1);
|
|
9292
|
+
}
|
|
9293
|
+
}
|
|
9294
|
+
await createPerClientCommand(perClientName).parseAsync(rest, {
|
|
9295
|
+
from: "user"
|
|
9296
|
+
});
|
|
9297
|
+
})().catch((err) => {
|
|
9298
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
9299
|
+
console.error(formatError(message));
|
|
9300
|
+
process.exit(1);
|
|
9301
|
+
});
|
|
9302
|
+
} else {
|
|
9303
|
+
program.parse();
|
|
9304
|
+
}
|
|
7796
9305
|
//# sourceMappingURL=index.cjs.map
|