@mcp-use/cli 3.1.5-canary.4 → 3.2.0-canary.11
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 +96 -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 +2076 -540
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2038 -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,1054 @@ 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}`));
|
|
2250
2548
|
return null;
|
|
2251
2549
|
}
|
|
2252
|
-
}
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
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
|
+
}
|
|
3016
|
+
return null;
|
|
3017
|
+
}
|
|
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, sessionName, headers) {
|
|
3264
|
+
if (sessionName) {
|
|
3265
|
+
const result = await getOrRestoreSession(sessionName);
|
|
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 --mcp <url> for an ad-hoc connection, or use `mcp-use client <name> screenshot` for a saved server."
|
|
3288
|
+
)
|
|
3289
|
+
);
|
|
3290
|
+
return null;
|
|
3291
|
+
}
|
|
3292
|
+
async function screenshotCommand(options, argsList, context) {
|
|
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 servers 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(
|
|
3339
|
+
options,
|
|
3340
|
+
context.sessionName,
|
|
3341
|
+
headers
|
|
3342
|
+
);
|
|
3343
|
+
if (!session) {
|
|
3344
|
+
exitCode = 1;
|
|
3345
|
+
return;
|
|
3346
|
+
}
|
|
3347
|
+
const tool = session.tools.find((t) => t.name === options.tool);
|
|
3348
|
+
if (!tool) {
|
|
3349
|
+
throw new Error(
|
|
3350
|
+
`Tool "${options.tool}" not found. Available: ${session.tools.map((t) => t.name).join(", ")}`
|
|
3351
|
+
);
|
|
3352
|
+
}
|
|
3353
|
+
const resourceUri = detectToolResourceUri(tool);
|
|
3354
|
+
if (!resourceUri) {
|
|
3355
|
+
throw new Error(
|
|
3356
|
+
`Tool "${options.tool}" does not declare a UI resource (expected _meta.ui.resourceUri or openai/outputTemplate).`
|
|
3357
|
+
);
|
|
3358
|
+
}
|
|
3359
|
+
let toolArgs = {};
|
|
3360
|
+
if (argsList && argsList.length > 0) {
|
|
3361
|
+
try {
|
|
3362
|
+
toolArgs = parseToolArgs(
|
|
3363
|
+
argsList,
|
|
3364
|
+
tool.inputSchema
|
|
3365
|
+
);
|
|
3366
|
+
} catch (err) {
|
|
3367
|
+
console.error(
|
|
3368
|
+
formatError(err instanceof Error ? err.message : String(err))
|
|
3369
|
+
);
|
|
3370
|
+
console.log("");
|
|
3371
|
+
console.log(formatInfo("Usage:"));
|
|
3372
|
+
console.log(
|
|
3373
|
+
` npx ${context.usagePrefix} --tool ${options.tool} key=value [key2=value2 ...]`
|
|
3374
|
+
);
|
|
3375
|
+
console.log(
|
|
3376
|
+
` npx ${context.usagePrefix} --tool ${options.tool} nested:='{"a":1}' # JSON value`
|
|
3377
|
+
);
|
|
3378
|
+
console.log(
|
|
3379
|
+
` npx ${context.usagePrefix} --tool ${options.tool} '{"key":"value"}' # full JSON object`
|
|
3380
|
+
);
|
|
3381
|
+
if (tool.inputSchema) {
|
|
3382
|
+
console.log("");
|
|
3383
|
+
console.log(formatInfo("Tool schema:"));
|
|
3384
|
+
console.log(formatSchema(tool.inputSchema));
|
|
3385
|
+
}
|
|
3386
|
+
exitCode = 1;
|
|
3387
|
+
return;
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3390
|
+
const toolOutput = await session.callTool(options.tool, toolArgs);
|
|
3391
|
+
const result = await captureToolScreenshot(
|
|
3392
|
+
{
|
|
3393
|
+
session,
|
|
3394
|
+
toolName: options.tool,
|
|
3395
|
+
toolArgs,
|
|
3396
|
+
toolOutput,
|
|
3397
|
+
resourceUri
|
|
3398
|
+
},
|
|
3399
|
+
{
|
|
3400
|
+
width,
|
|
3401
|
+
height,
|
|
3402
|
+
theme: options.theme,
|
|
3403
|
+
output: options.output,
|
|
3404
|
+
waitFor: options.waitFor,
|
|
3405
|
+
delayMs,
|
|
3406
|
+
timeoutMs: navTimeout,
|
|
3407
|
+
inspector: options.inspector,
|
|
3408
|
+
quiet: options.quiet,
|
|
3409
|
+
cdpUrl: options.cdpUrl
|
|
3410
|
+
}
|
|
3411
|
+
);
|
|
3412
|
+
console.log(
|
|
3413
|
+
`Saved screenshot: ${result.outputPath} (${result.width}\xD7${result.height})`
|
|
3414
|
+
);
|
|
3415
|
+
} catch (err) {
|
|
3416
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
3417
|
+
console.error(formatError(`Screenshot failed: ${msg}`));
|
|
3418
|
+
exitCode = 1;
|
|
3419
|
+
} finally {
|
|
3420
|
+
await cleanupAndExit(exitCode);
|
|
3421
|
+
}
|
|
3422
|
+
}
|
|
3423
|
+
function withCommonScreenshotOptions(cmd) {
|
|
3424
|
+
return cmd.argument(
|
|
3425
|
+
"[args...]",
|
|
3426
|
+
"Tool args as key=value pairs (use key:=<json> for nested values, or pass a single JSON object)."
|
|
3427
|
+
).option(
|
|
3428
|
+
"--tool <name>",
|
|
3429
|
+
"Tool to call. Its UI resource is rendered with the result."
|
|
3430
|
+
).option("--width <px>", "Browser viewport width in pixels.", "800").option("--height <px>", "Browser viewport height in pixels.", "600").option(
|
|
3431
|
+
"--inspector <url>",
|
|
3432
|
+
"Inspector host that serves /inspector/preview/:view. When omitted, auto-spawns `@mcp-use/inspector` on a free port."
|
|
3433
|
+
).option(
|
|
3434
|
+
"--theme <light|dark>",
|
|
3435
|
+
"Color scheme to render the view in.",
|
|
3436
|
+
"light"
|
|
3437
|
+
).option(
|
|
3438
|
+
"--output <path>",
|
|
3439
|
+
"Output PNG path. Defaults to ./<view>-<timestamp>.png in cwd."
|
|
3440
|
+
).option(
|
|
3441
|
+
"--wait-for <selector>",
|
|
3442
|
+
'Override readiness selector (default: body[data-view-ready="true"]).'
|
|
3443
|
+
).option(
|
|
3444
|
+
"--delay <ms>",
|
|
3445
|
+
"Extra wait after readiness, to let chart animations / async layouts settle.",
|
|
3446
|
+
"0"
|
|
3447
|
+
).option("--timeout <ms>", "Navigation + readiness timeout in ms.", "30000").option(
|
|
3448
|
+
"--cdp-url <url>",
|
|
3449
|
+
"Connect to an existing CDP WebSocket (ws:// or wss://) instead of spawning local Chrome. Useful for hosted browsers like Notte."
|
|
3450
|
+
).option("--quiet", "Suppress dev-server output.");
|
|
3451
|
+
}
|
|
3452
|
+
function createClientScreenshotCommand() {
|
|
3453
|
+
const cmd = withCommonScreenshotOptions(
|
|
3454
|
+
new import_commander.Command("screenshot").description(
|
|
3455
|
+
"Render an MCP Apps view headlessly and save a PNG. Connects to an MCP server inline via --mcp; for a saved server, use `mcp-use client <name> screenshot`."
|
|
3456
|
+
)
|
|
3457
|
+
).option(
|
|
3458
|
+
"--mcp <url>",
|
|
3459
|
+
"Ad-hoc MCP server URL. Required for the top-level form. No authentication unless --header is supplied."
|
|
3460
|
+
).option(
|
|
3461
|
+
"-H, --header <header>",
|
|
3462
|
+
'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.',
|
|
3463
|
+
collectHeader,
|
|
3464
|
+
[]
|
|
3465
|
+
);
|
|
3466
|
+
cmd.action(async (args, opts) => {
|
|
3467
|
+
await screenshotCommand(opts, args, {
|
|
3468
|
+
usagePrefix: "mcp-use client screenshot"
|
|
3469
|
+
});
|
|
3470
|
+
});
|
|
3471
|
+
return cmd;
|
|
3472
|
+
}
|
|
3473
|
+
function createPerClientScreenshotCommand(name) {
|
|
3474
|
+
const cmd = withCommonScreenshotOptions(
|
|
3475
|
+
new import_commander.Command("screenshot").description(
|
|
3476
|
+
`Render an MCP Apps view headlessly using the saved server '${name}'.`
|
|
3477
|
+
)
|
|
3478
|
+
);
|
|
3479
|
+
cmd.action(async (args, opts) => {
|
|
3480
|
+
await screenshotCommand(opts, args, {
|
|
3481
|
+
sessionName: name,
|
|
3482
|
+
usagePrefix: `mcp-use client ${name} screenshot`
|
|
3483
|
+
});
|
|
3484
|
+
});
|
|
3485
|
+
return cmd;
|
|
3486
|
+
}
|
|
3487
|
+
|
|
3488
|
+
// src/commands/client.ts
|
|
3489
|
+
var RESERVED_CLIENT_SUBCOMMANDS = /* @__PURE__ */ new Set([
|
|
3490
|
+
"connect",
|
|
3491
|
+
"list",
|
|
3492
|
+
"remove",
|
|
3493
|
+
"screenshot",
|
|
3494
|
+
"help"
|
|
3495
|
+
]);
|
|
3496
|
+
var PER_CLIENT_SCOPES = /* @__PURE__ */ new Set([
|
|
3497
|
+
"tools",
|
|
3498
|
+
"resources",
|
|
3499
|
+
"prompts",
|
|
3500
|
+
"auth",
|
|
3501
|
+
"disconnect",
|
|
3502
|
+
"interactive",
|
|
3503
|
+
"screenshot"
|
|
3504
|
+
]);
|
|
3505
|
+
async function connectCommand(name, urlOrCommand, options) {
|
|
3506
|
+
if (!name || !urlOrCommand) {
|
|
3507
|
+
const looksLikeUrl = !!name && /^https?:\/\//i.test(name);
|
|
3508
|
+
if (looksLikeUrl && !urlOrCommand && !options.stdio) {
|
|
3509
|
+
console.error(formatError("Missing server name."));
|
|
3510
|
+
console.error("");
|
|
3511
|
+
console.error(
|
|
3512
|
+
formatInfo(
|
|
3513
|
+
"Each saved server needs a short name you'll use to address it later."
|
|
3514
|
+
)
|
|
3515
|
+
);
|
|
3516
|
+
console.error("");
|
|
3517
|
+
console.error("Try:");
|
|
3518
|
+
console.error(` mcp-use client connect <name> ${name}`);
|
|
3519
|
+
console.error("");
|
|
3520
|
+
console.error("Example:");
|
|
3521
|
+
console.error(` mcp-use client connect my-server ${name}`);
|
|
3522
|
+
console.error(" mcp-use client my-server tools list");
|
|
3523
|
+
} else if (name && !urlOrCommand) {
|
|
3524
|
+
console.error(
|
|
3525
|
+
formatError(options.stdio ? "Missing <command>." : "Missing <url>.")
|
|
3526
|
+
);
|
|
3527
|
+
console.error("");
|
|
3528
|
+
console.error(formatInfo("Usage:"));
|
|
3529
|
+
console.error(
|
|
3530
|
+
options.stdio ? ` mcp-use client connect ${name} "<command>" --stdio` : ` mcp-use client connect ${name} <url>`
|
|
3531
|
+
);
|
|
3532
|
+
} else {
|
|
3533
|
+
console.error(formatError("Missing required arguments: <name> <url>."));
|
|
3534
|
+
console.error("");
|
|
3535
|
+
console.error(formatInfo("Usage:"));
|
|
3536
|
+
console.error(" mcp-use client connect <name> <url>");
|
|
3537
|
+
console.error("");
|
|
3538
|
+
console.error("Example:");
|
|
3539
|
+
console.error(
|
|
3540
|
+
" mcp-use client connect manufact https://mcp.manufact.com/mcp"
|
|
3541
|
+
);
|
|
3542
|
+
}
|
|
3543
|
+
await cleanupAndExit(1);
|
|
3544
|
+
}
|
|
3545
|
+
const sessionName = name;
|
|
3546
|
+
const target = urlOrCommand;
|
|
3547
|
+
if (PER_CLIENT_SCOPES.has(sessionName)) {
|
|
3548
|
+
console.error(
|
|
3549
|
+
formatError(
|
|
3550
|
+
`'${sessionName}' is a reserved name and can't be used for a saved server.`
|
|
3551
|
+
)
|
|
3552
|
+
);
|
|
3553
|
+
console.error("");
|
|
3554
|
+
console.error(
|
|
3555
|
+
`Reserved names: ${Array.from(PER_CLIENT_SCOPES).sort().join(", ")}`
|
|
3556
|
+
);
|
|
3557
|
+
console.error("");
|
|
3558
|
+
console.error("Pick a different name, e.g.:");
|
|
3559
|
+
console.error(` mcp-use client connect my-${sessionName} ${target}`);
|
|
3560
|
+
await cleanupAndExit(1);
|
|
3561
|
+
}
|
|
2268
3562
|
try {
|
|
2269
|
-
const
|
|
2270
|
-
const client = new import_client.MCPClient();
|
|
3563
|
+
const client = new import_client3.MCPClient();
|
|
2271
3564
|
let session;
|
|
2272
3565
|
const cliClientInfo = getCliClientInfo();
|
|
2273
3566
|
if (options.stdio) {
|
|
2274
|
-
const parts =
|
|
3567
|
+
const parts = target.split(" ");
|
|
2275
3568
|
const command = parts[0];
|
|
2276
3569
|
const args = parts.slice(1);
|
|
2277
3570
|
console.error(
|
|
@@ -2290,17 +3583,41 @@ async function connectCommand(urlOrCommand, options) {
|
|
|
2290
3583
|
lastUsed: (/* @__PURE__ */ new Date()).toISOString()
|
|
2291
3584
|
});
|
|
2292
3585
|
} else {
|
|
2293
|
-
console.error(formatInfo(`Connecting to ${
|
|
3586
|
+
console.error(formatInfo(`Connecting to ${target}...`));
|
|
3587
|
+
const wantOAuth = !options.auth && options.oauth !== false;
|
|
3588
|
+
let authProvider;
|
|
3589
|
+
if (wantOAuth) {
|
|
3590
|
+
const authTimeoutMs = options.authTimeout ? Number.parseInt(options.authTimeout, 10) : void 0;
|
|
3591
|
+
authProvider = await buildOAuthProvider(target, {
|
|
3592
|
+
...authTimeoutMs ? { authTimeoutMs } : {}
|
|
3593
|
+
});
|
|
3594
|
+
}
|
|
2294
3595
|
client.addServer(sessionName, {
|
|
2295
|
-
url:
|
|
2296
|
-
|
|
3596
|
+
url: target,
|
|
3597
|
+
...authProvider ? { authProvider } : options.auth ? { headers: { Authorization: `Bearer ${options.auth}` } } : {},
|
|
2297
3598
|
clientInfo: cliClientInfo
|
|
2298
3599
|
});
|
|
2299
|
-
|
|
3600
|
+
try {
|
|
3601
|
+
session = await client.createSession(sessionName);
|
|
3602
|
+
} catch (err) {
|
|
3603
|
+
if (authProvider && isUnauthorized(err)) {
|
|
3604
|
+
console.error(
|
|
3605
|
+
formatWarning(
|
|
3606
|
+
"Server requires authentication. Starting OAuth flow."
|
|
3607
|
+
)
|
|
3608
|
+
);
|
|
3609
|
+
await runOAuthFlow(authProvider, target);
|
|
3610
|
+
console.error(formatSuccess("Authentication successful"));
|
|
3611
|
+
session = await client.createSession(sessionName);
|
|
3612
|
+
} else {
|
|
3613
|
+
throw err;
|
|
3614
|
+
}
|
|
3615
|
+
}
|
|
2300
3616
|
await saveSession(sessionName, {
|
|
2301
3617
|
type: "http",
|
|
2302
|
-
url:
|
|
2303
|
-
|
|
3618
|
+
url: target,
|
|
3619
|
+
authMode: authProvider ? "oauth" : options.auth ? "bearer" : void 0,
|
|
3620
|
+
authToken: authProvider ? void 0 : options.auth,
|
|
2304
3621
|
lastUsed: (/* @__PURE__ */ new Date()).toISOString()
|
|
2305
3622
|
});
|
|
2306
3623
|
}
|
|
@@ -2310,7 +3627,7 @@ async function connectCommand(urlOrCommand, options) {
|
|
|
2310
3627
|
if (serverInfo) {
|
|
2311
3628
|
await updateSessionInfo(sessionName, serverInfo, capabilities);
|
|
2312
3629
|
}
|
|
2313
|
-
console.log(formatSuccess(`Connected
|
|
3630
|
+
console.log(formatSuccess(`Connected as '${sessionName}'`));
|
|
2314
3631
|
if (serverInfo) {
|
|
2315
3632
|
console.log("");
|
|
2316
3633
|
console.log(formatHeader("Server Information:"));
|
|
@@ -2336,119 +3653,173 @@ async function connectCommand(urlOrCommand, options) {
|
|
|
2336
3653
|
);
|
|
2337
3654
|
} catch (error) {
|
|
2338
3655
|
console.error(formatError(`Connection failed: ${error.message}`));
|
|
2339
|
-
|
|
3656
|
+
await cleanupAndExit(1);
|
|
2340
3657
|
}
|
|
3658
|
+
await cleanupAndExit(0);
|
|
2341
3659
|
}
|
|
2342
|
-
async function disconnectCommand(
|
|
3660
|
+
async function disconnectCommand(name) {
|
|
2343
3661
|
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);
|
|
3662
|
+
const sessionData = activeSessions.get(name);
|
|
2361
3663
|
if (sessionData) {
|
|
2362
3664
|
await sessionData.client.closeAllSessions();
|
|
2363
|
-
activeSessions.delete(
|
|
2364
|
-
console.log(formatSuccess(`Disconnected from ${
|
|
3665
|
+
activeSessions.delete(name);
|
|
3666
|
+
console.log(formatSuccess(`Disconnected from ${name}`));
|
|
2365
3667
|
} else {
|
|
2366
|
-
console.log(formatInfo(`
|
|
3668
|
+
console.log(formatInfo(`Server '${name}' is not connected`));
|
|
2367
3669
|
}
|
|
2368
3670
|
} catch (error) {
|
|
2369
3671
|
console.error(formatError(`Failed to disconnect: ${error.message}`));
|
|
2370
|
-
|
|
3672
|
+
await cleanupAndExit(1);
|
|
3673
|
+
}
|
|
3674
|
+
await cleanupAndExit(0);
|
|
3675
|
+
}
|
|
3676
|
+
async function removeClientCommand(name) {
|
|
3677
|
+
try {
|
|
3678
|
+
const config = await getSession(name);
|
|
3679
|
+
if (!config) {
|
|
3680
|
+
console.error(formatError(`Server '${name}' not found`));
|
|
3681
|
+
console.error("");
|
|
3682
|
+
console.error("See your saved servers with:");
|
|
3683
|
+
console.error(" mcp-use client list");
|
|
3684
|
+
await cleanupAndExit(1);
|
|
3685
|
+
}
|
|
3686
|
+
const sessionData = activeSessions.get(name);
|
|
3687
|
+
if (sessionData) {
|
|
3688
|
+
await sessionData.client.closeAllSessions();
|
|
3689
|
+
activeSessions.delete(name);
|
|
3690
|
+
}
|
|
3691
|
+
const isOAuthHttp = config.type === "http" && config.authMode === "oauth" && typeof config.url === "string";
|
|
3692
|
+
const sharedUrlSibling = isOAuthHttp ? (await listAllSessions()).find(
|
|
3693
|
+
(s) => s.name !== name && s.config.type === "http" && s.config.url === config.url
|
|
3694
|
+
) : void 0;
|
|
3695
|
+
await removeSession(name);
|
|
3696
|
+
console.log(formatSuccess(`Removed saved server '${name}'`));
|
|
3697
|
+
if (isOAuthHttp) {
|
|
3698
|
+
if (sharedUrlSibling) {
|
|
3699
|
+
console.log(
|
|
3700
|
+
formatInfo(
|
|
3701
|
+
`OAuth tokens for ${config.url} were kept because saved server '${sharedUrlSibling.name}' still uses that URL.`
|
|
3702
|
+
)
|
|
3703
|
+
);
|
|
3704
|
+
} else {
|
|
3705
|
+
try {
|
|
3706
|
+
const provider = await buildOAuthProvider(config.url);
|
|
3707
|
+
await provider.invalidateCredentials("all");
|
|
3708
|
+
console.log(formatInfo(`Removed OAuth tokens for ${config.url}`));
|
|
3709
|
+
} catch (error) {
|
|
3710
|
+
console.error(
|
|
3711
|
+
formatWarning(
|
|
3712
|
+
`Saved entry removed, but failed to clear OAuth tokens for ${config.url}: ${error.message}`
|
|
3713
|
+
)
|
|
3714
|
+
);
|
|
3715
|
+
}
|
|
3716
|
+
}
|
|
3717
|
+
}
|
|
3718
|
+
} catch (error) {
|
|
3719
|
+
console.error(formatError(`Failed to remove server: ${error.message}`));
|
|
3720
|
+
await cleanupAndExit(1);
|
|
2371
3721
|
}
|
|
3722
|
+
await cleanupAndExit(0);
|
|
2372
3723
|
}
|
|
2373
|
-
async function
|
|
3724
|
+
async function listClientsCommand() {
|
|
2374
3725
|
try {
|
|
2375
3726
|
const sessions = await listAllSessions();
|
|
2376
3727
|
if (sessions.length === 0) {
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
3728
|
+
if (isStdoutTty()) {
|
|
3729
|
+
console.log(formatInfo("No saved servers"));
|
|
3730
|
+
console.log(
|
|
3731
|
+
formatInfo(
|
|
3732
|
+
"Connect to a server with: npx mcp-use client connect <name> <url>"
|
|
3733
|
+
)
|
|
3734
|
+
);
|
|
3735
|
+
}
|
|
2381
3736
|
return;
|
|
2382
3737
|
}
|
|
2383
|
-
|
|
2384
|
-
|
|
3738
|
+
const tty2 = isStdoutTty();
|
|
3739
|
+
if (tty2) {
|
|
3740
|
+
console.log(formatHeader("Saved Servers:"));
|
|
3741
|
+
console.log("");
|
|
3742
|
+
}
|
|
2385
3743
|
const tableData = sessions.map((s) => ({
|
|
2386
|
-
name: s.
|
|
3744
|
+
name: s.name,
|
|
2387
3745
|
type: s.config.type,
|
|
2388
3746
|
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")
|
|
3747
|
+
server: s.config.serverInfo?.name || "unknown"
|
|
2391
3748
|
}));
|
|
2392
3749
|
console.log(
|
|
2393
3750
|
formatTable(tableData, [
|
|
2394
3751
|
{ key: "name", header: "Name" },
|
|
2395
3752
|
{ key: "type", header: "Type" },
|
|
2396
|
-
{ key: "target", header: "Target",
|
|
2397
|
-
{ key: "server", header: "Server" }
|
|
2398
|
-
{ key: "status", header: "Status" }
|
|
3753
|
+
{ key: "target", header: "Target", truncate: true },
|
|
3754
|
+
{ key: "server", header: "Server" }
|
|
2399
3755
|
])
|
|
2400
3756
|
);
|
|
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
3757
|
} catch (error) {
|
|
2413
|
-
console.error(formatError(`Failed to
|
|
2414
|
-
|
|
3758
|
+
console.error(formatError(`Failed to list servers: ${error.message}`));
|
|
3759
|
+
await cleanupAndExit(1);
|
|
2415
3760
|
}
|
|
3761
|
+
await cleanupAndExit(0);
|
|
2416
3762
|
}
|
|
2417
|
-
async function listToolsCommand(options) {
|
|
3763
|
+
async function listToolsCommand(name, options) {
|
|
2418
3764
|
try {
|
|
2419
|
-
const result = await getOrRestoreSession(
|
|
2420
|
-
if (!result)
|
|
3765
|
+
const result = await getOrRestoreSession(name);
|
|
3766
|
+
if (!result) {
|
|
3767
|
+
await cleanupAndExit(1);
|
|
3768
|
+
}
|
|
2421
3769
|
const { session } = result;
|
|
2422
3770
|
const tools = await session.listTools();
|
|
2423
3771
|
if (options.json) {
|
|
2424
3772
|
console.log(formatJson(tools));
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
3773
|
+
} else if (tools.length === 0) {
|
|
3774
|
+
if (isStdoutTty()) console.log(formatInfo("No tools available"));
|
|
3775
|
+
} else {
|
|
3776
|
+
const tty2 = isStdoutTty();
|
|
3777
|
+
if (tty2) {
|
|
3778
|
+
console.log(formatHeader(`Available Tools (${tools.length}):`));
|
|
3779
|
+
console.log("");
|
|
3780
|
+
}
|
|
3781
|
+
const tableData = tools.map((tool) => {
|
|
3782
|
+
const props = tool.inputSchema?.properties ?? {};
|
|
3783
|
+
const required = tool.inputSchema?.required ?? [];
|
|
3784
|
+
const total = Object.keys(props).length;
|
|
3785
|
+
const reqCount = Array.isArray(required) ? required.length : 0;
|
|
3786
|
+
const argsCell = total === 0 ? source_default.gray("\u2014") : `${reqCount}/${total}`;
|
|
3787
|
+
return {
|
|
3788
|
+
name: source_default.bold(tool.name),
|
|
3789
|
+
mode: formatToolMode(tool.annotations),
|
|
3790
|
+
args: argsCell,
|
|
3791
|
+
description: tool.description || source_default.gray("(no description)")
|
|
3792
|
+
};
|
|
3793
|
+
});
|
|
3794
|
+
console.log(
|
|
3795
|
+
formatTable(tableData, [
|
|
3796
|
+
{ key: "name", header: "Tool" },
|
|
3797
|
+
{ key: "mode", header: "Mode" },
|
|
3798
|
+
{ key: "args", header: "Args" },
|
|
3799
|
+
{ key: "description", header: "Description", truncate: true }
|
|
3800
|
+
])
|
|
3801
|
+
);
|
|
3802
|
+
if (tty2) {
|
|
3803
|
+
console.log("");
|
|
3804
|
+
console.log(
|
|
3805
|
+
source_default.gray(
|
|
3806
|
+
"ARGS shows required/total. Modes: read-only \xB7 write \xB7 destructive."
|
|
3807
|
+
)
|
|
3808
|
+
);
|
|
3809
|
+
}
|
|
2430
3810
|
}
|
|
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
3811
|
} catch (error) {
|
|
2444
3812
|
console.error(formatError(`Failed to list tools: ${error.message}`));
|
|
2445
|
-
|
|
3813
|
+
await cleanupAndExit(1);
|
|
2446
3814
|
}
|
|
3815
|
+
await cleanupAndExit(0);
|
|
2447
3816
|
}
|
|
2448
|
-
async function describeToolCommand(
|
|
3817
|
+
async function describeToolCommand(name, toolName) {
|
|
2449
3818
|
try {
|
|
2450
|
-
const result = await getOrRestoreSession(
|
|
2451
|
-
if (!result)
|
|
3819
|
+
const result = await getOrRestoreSession(name);
|
|
3820
|
+
if (!result) {
|
|
3821
|
+
await cleanupAndExit(1);
|
|
3822
|
+
}
|
|
2452
3823
|
const { session } = result;
|
|
2453
3824
|
const tools = session.tools;
|
|
2454
3825
|
const tool = tools.find((t) => t.name === toolName);
|
|
@@ -2457,7 +3828,7 @@ async function describeToolCommand(toolName, options) {
|
|
|
2457
3828
|
console.log("");
|
|
2458
3829
|
console.log(formatInfo("Available tools:"));
|
|
2459
3830
|
tools.forEach((t) => console.log(` \u2022 ${t.name}`));
|
|
2460
|
-
|
|
3831
|
+
await cleanupAndExit(1);
|
|
2461
3832
|
}
|
|
2462
3833
|
console.log(formatHeader(`Tool: ${tool.name}`));
|
|
2463
3834
|
console.log("");
|
|
@@ -2471,94 +3842,167 @@ async function describeToolCommand(toolName, options) {
|
|
|
2471
3842
|
}
|
|
2472
3843
|
} catch (error) {
|
|
2473
3844
|
console.error(formatError(`Failed to describe tool: ${error.message}`));
|
|
2474
|
-
|
|
3845
|
+
await cleanupAndExit(1);
|
|
2475
3846
|
}
|
|
3847
|
+
await cleanupAndExit(0);
|
|
2476
3848
|
}
|
|
2477
|
-
async function callToolCommand(toolName,
|
|
3849
|
+
async function callToolCommand(name, toolName, argsList, options) {
|
|
2478
3850
|
try {
|
|
2479
|
-
const result = await getOrRestoreSession(
|
|
2480
|
-
if (!result)
|
|
3851
|
+
const result = await getOrRestoreSession(name);
|
|
3852
|
+
if (!result) {
|
|
3853
|
+
await cleanupAndExit(1);
|
|
3854
|
+
}
|
|
2481
3855
|
const { session } = result;
|
|
3856
|
+
const tools = session.tools;
|
|
3857
|
+
const tool = tools.find((t) => t.name === toolName);
|
|
2482
3858
|
let args = {};
|
|
2483
|
-
if (
|
|
3859
|
+
if (argsList && argsList.length > 0) {
|
|
2484
3860
|
try {
|
|
2485
|
-
args =
|
|
3861
|
+
args = parseToolArgs(argsList, tool?.inputSchema);
|
|
2486
3862
|
} 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
|
-
);
|
|
3863
|
+
console.error(formatError(error.message));
|
|
2499
3864
|
console.log("");
|
|
2500
|
-
console.log(formatInfo("
|
|
3865
|
+
console.log(formatInfo("Usage:"));
|
|
2501
3866
|
console.log(
|
|
2502
|
-
` npx mcp-use client tools call ${toolName}
|
|
3867
|
+
` npx mcp-use client ${name} tools call ${toolName} key=value [key2=value2 ...]`
|
|
2503
3868
|
);
|
|
2504
|
-
console.log(
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
3869
|
+
console.log(
|
|
3870
|
+
` npx mcp-use client ${name} tools call ${toolName} nested:='{"a":1}' # JSON value`
|
|
3871
|
+
);
|
|
3872
|
+
console.log(
|
|
3873
|
+
` npx mcp-use client ${name} tools call ${toolName} '{"key":"value"}' # full JSON object`
|
|
3874
|
+
);
|
|
3875
|
+
if (tool?.inputSchema) {
|
|
3876
|
+
console.log("");
|
|
3877
|
+
console.log(formatInfo("Tool schema:"));
|
|
3878
|
+
console.log(formatSchema(tool.inputSchema));
|
|
3879
|
+
}
|
|
3880
|
+
await cleanupAndExit(1);
|
|
2508
3881
|
}
|
|
3882
|
+
} else if (tool?.inputSchema?.required && tool.inputSchema.required.length > 0) {
|
|
3883
|
+
console.error(formatError("This tool requires arguments."));
|
|
3884
|
+
console.log("");
|
|
3885
|
+
console.log(formatInfo("Provide arguments as key=value pairs:"));
|
|
3886
|
+
console.log(
|
|
3887
|
+
` npx mcp-use client ${name} tools call ${toolName} key=value [key2=value2 ...]`
|
|
3888
|
+
);
|
|
3889
|
+
console.log("");
|
|
3890
|
+
console.log(formatInfo("Tool schema:"));
|
|
3891
|
+
console.log(formatSchema(tool.inputSchema));
|
|
3892
|
+
await cleanupAndExit(1);
|
|
2509
3893
|
}
|
|
2510
3894
|
console.error(formatInfo(`Calling tool '${toolName}'...`));
|
|
2511
3895
|
const callResult = await session.callTool(toolName, args, {
|
|
2512
3896
|
timeout: options?.timeout
|
|
2513
3897
|
});
|
|
3898
|
+
let screenshot = null;
|
|
3899
|
+
let screenshotError = null;
|
|
3900
|
+
if (options?.screenshot !== false) {
|
|
3901
|
+
const tool2 = session.tools.find((t) => t.name === toolName);
|
|
3902
|
+
const resourceUri = detectToolResourceUri(tool2);
|
|
3903
|
+
if (resourceUri) {
|
|
3904
|
+
console.error(
|
|
3905
|
+
formatInfo(`Capturing widget screenshot (${resourceUri})...`)
|
|
3906
|
+
);
|
|
3907
|
+
try {
|
|
3908
|
+
const shot = await captureToolScreenshot(
|
|
3909
|
+
{
|
|
3910
|
+
session,
|
|
3911
|
+
toolName,
|
|
3912
|
+
toolArgs: args,
|
|
3913
|
+
toolOutput: callResult,
|
|
3914
|
+
resourceUri
|
|
3915
|
+
},
|
|
3916
|
+
options?.screenshotOutput ? { output: options.screenshotOutput } : {}
|
|
3917
|
+
);
|
|
3918
|
+
screenshot = {
|
|
3919
|
+
path: shot.outputPath,
|
|
3920
|
+
width: shot.width,
|
|
3921
|
+
height: shot.height,
|
|
3922
|
+
view: shot.view
|
|
3923
|
+
};
|
|
3924
|
+
} catch (err) {
|
|
3925
|
+
screenshotError = err?.message ?? String(err);
|
|
3926
|
+
}
|
|
3927
|
+
}
|
|
3928
|
+
}
|
|
2514
3929
|
if (options?.json) {
|
|
2515
3930
|
console.log(formatJson(callResult));
|
|
2516
3931
|
} else {
|
|
2517
3932
|
console.log(formatToolCall(callResult));
|
|
2518
3933
|
}
|
|
3934
|
+
if (screenshot) {
|
|
3935
|
+
console.error(
|
|
3936
|
+
formatSuccess(
|
|
3937
|
+
`Saved widget screenshot: ${screenshot.path} (${screenshot.width}\xD7${screenshot.height})`
|
|
3938
|
+
)
|
|
3939
|
+
);
|
|
3940
|
+
}
|
|
3941
|
+
if (screenshotError) {
|
|
3942
|
+
console.error(
|
|
3943
|
+
formatWarning(`Skipped widget screenshot: ${screenshotError}`)
|
|
3944
|
+
);
|
|
3945
|
+
}
|
|
3946
|
+
if (callResult.isError) {
|
|
3947
|
+
await cleanupAndExit(1);
|
|
3948
|
+
}
|
|
2519
3949
|
} catch (error) {
|
|
2520
3950
|
console.error(formatError(`Failed to call tool: ${error.message}`));
|
|
2521
|
-
|
|
3951
|
+
if (error?.data !== void 0) {
|
|
3952
|
+
console.error(
|
|
3953
|
+
source_default.gray(
|
|
3954
|
+
typeof error.data === "string" ? error.data : formatJson(error.data)
|
|
3955
|
+
)
|
|
3956
|
+
);
|
|
3957
|
+
}
|
|
3958
|
+
await cleanupAndExit(1);
|
|
2522
3959
|
}
|
|
3960
|
+
await cleanupAndExit(0);
|
|
2523
3961
|
}
|
|
2524
|
-
async function listResourcesCommand(options) {
|
|
3962
|
+
async function listResourcesCommand(name, options) {
|
|
2525
3963
|
try {
|
|
2526
|
-
const result = await getOrRestoreSession(
|
|
2527
|
-
if (!result)
|
|
3964
|
+
const result = await getOrRestoreSession(name);
|
|
3965
|
+
if (!result) {
|
|
3966
|
+
await cleanupAndExit(1);
|
|
3967
|
+
}
|
|
2528
3968
|
const { session } = result;
|
|
2529
3969
|
const resourcesResult = await session.listAllResources();
|
|
2530
3970
|
const resources = resourcesResult.resources;
|
|
2531
3971
|
if (options.json) {
|
|
2532
3972
|
console.log(formatJson(resources));
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
3973
|
+
} else if (resources.length === 0) {
|
|
3974
|
+
if (isStdoutTty()) console.log(formatInfo("No resources available"));
|
|
3975
|
+
} else {
|
|
3976
|
+
const tty2 = isStdoutTty();
|
|
3977
|
+
if (tty2) {
|
|
3978
|
+
console.log(formatHeader(`Available Resources (${resources.length}):`));
|
|
3979
|
+
console.log("");
|
|
3980
|
+
}
|
|
3981
|
+
const tableData = resources.map((resource) => ({
|
|
3982
|
+
name: source_default.bold(resource.name || "(no name)"),
|
|
3983
|
+
type: resource.mimeType || source_default.gray("unknown"),
|
|
3984
|
+
uri: resource.uri
|
|
3985
|
+
}));
|
|
3986
|
+
console.log(
|
|
3987
|
+
formatTable(tableData, [
|
|
3988
|
+
{ key: "name", header: "Name" },
|
|
3989
|
+
{ key: "type", header: "Type" },
|
|
3990
|
+
{ key: "uri", header: "URI", truncate: true }
|
|
3991
|
+
])
|
|
3992
|
+
);
|
|
2538
3993
|
}
|
|
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
3994
|
} catch (error) {
|
|
2554
3995
|
console.error(formatError(`Failed to list resources: ${error.message}`));
|
|
2555
|
-
|
|
3996
|
+
await cleanupAndExit(1);
|
|
2556
3997
|
}
|
|
3998
|
+
await cleanupAndExit(0);
|
|
2557
3999
|
}
|
|
2558
|
-
async function readResourceCommand(uri, options) {
|
|
4000
|
+
async function readResourceCommand(name, uri, options) {
|
|
2559
4001
|
try {
|
|
2560
|
-
const result = await getOrRestoreSession(
|
|
2561
|
-
if (!result)
|
|
4002
|
+
const result = await getOrRestoreSession(name);
|
|
4003
|
+
if (!result) {
|
|
4004
|
+
await cleanupAndExit(1);
|
|
4005
|
+
}
|
|
2562
4006
|
const { session } = result;
|
|
2563
4007
|
console.error(formatInfo(`Reading resource: ${uri}`));
|
|
2564
4008
|
const resource = await session.readResource(uri);
|
|
@@ -2569,13 +4013,16 @@ async function readResourceCommand(uri, options) {
|
|
|
2569
4013
|
}
|
|
2570
4014
|
} catch (error) {
|
|
2571
4015
|
console.error(formatError(`Failed to read resource: ${error.message}`));
|
|
2572
|
-
|
|
4016
|
+
await cleanupAndExit(1);
|
|
2573
4017
|
}
|
|
4018
|
+
await cleanupAndExit(0);
|
|
2574
4019
|
}
|
|
2575
|
-
async function subscribeResourceCommand(
|
|
4020
|
+
async function subscribeResourceCommand(name, uri) {
|
|
2576
4021
|
try {
|
|
2577
|
-
const result = await getOrRestoreSession(
|
|
2578
|
-
if (!result)
|
|
4022
|
+
const result = await getOrRestoreSession(name);
|
|
4023
|
+
if (!result) {
|
|
4024
|
+
await cleanupAndExit(1);
|
|
4025
|
+
}
|
|
2579
4026
|
const { session } = result;
|
|
2580
4027
|
await session.subscribeToResource(uri);
|
|
2581
4028
|
console.log(formatSuccess(`Subscribed to resource: ${uri}`));
|
|
@@ -2593,13 +4040,15 @@ async function subscribeResourceCommand(uri, options) {
|
|
|
2593
4040
|
console.error(
|
|
2594
4041
|
formatError(`Failed to subscribe to resource: ${error.message}`)
|
|
2595
4042
|
);
|
|
2596
|
-
|
|
4043
|
+
await cleanupAndExit(1);
|
|
2597
4044
|
}
|
|
2598
4045
|
}
|
|
2599
|
-
async function unsubscribeResourceCommand(
|
|
4046
|
+
async function unsubscribeResourceCommand(name, uri) {
|
|
2600
4047
|
try {
|
|
2601
|
-
const result = await getOrRestoreSession(
|
|
2602
|
-
if (!result)
|
|
4048
|
+
const result = await getOrRestoreSession(name);
|
|
4049
|
+
if (!result) {
|
|
4050
|
+
await cleanupAndExit(1);
|
|
4051
|
+
}
|
|
2603
4052
|
const { session } = result;
|
|
2604
4053
|
await session.unsubscribeFromResource(uri);
|
|
2605
4054
|
console.log(formatSuccess(`Unsubscribed from resource: ${uri}`));
|
|
@@ -2607,53 +4056,76 @@ async function unsubscribeResourceCommand(uri, options) {
|
|
|
2607
4056
|
console.error(
|
|
2608
4057
|
formatError(`Failed to unsubscribe from resource: ${error.message}`)
|
|
2609
4058
|
);
|
|
2610
|
-
|
|
4059
|
+
await cleanupAndExit(1);
|
|
2611
4060
|
}
|
|
4061
|
+
await cleanupAndExit(0);
|
|
2612
4062
|
}
|
|
2613
|
-
async function listPromptsCommand(options) {
|
|
4063
|
+
async function listPromptsCommand(name, options) {
|
|
2614
4064
|
try {
|
|
2615
|
-
const result = await getOrRestoreSession(
|
|
2616
|
-
if (!result)
|
|
4065
|
+
const result = await getOrRestoreSession(name);
|
|
4066
|
+
if (!result) {
|
|
4067
|
+
await cleanupAndExit(1);
|
|
4068
|
+
}
|
|
2617
4069
|
const { session } = result;
|
|
2618
4070
|
const promptsResult = await session.listPrompts();
|
|
2619
4071
|
const prompts = promptsResult.prompts;
|
|
2620
4072
|
if (options.json) {
|
|
2621
4073
|
console.log(formatJson(prompts));
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
4074
|
+
} else if (prompts.length === 0) {
|
|
4075
|
+
if (isStdoutTty()) console.log(formatInfo("No prompts available"));
|
|
4076
|
+
} else {
|
|
4077
|
+
const tty2 = isStdoutTty();
|
|
4078
|
+
if (tty2) {
|
|
4079
|
+
console.log(formatHeader(`Available Prompts (${prompts.length}):`));
|
|
4080
|
+
console.log("");
|
|
4081
|
+
}
|
|
4082
|
+
const tableData = prompts.map((prompt4) => {
|
|
4083
|
+
const args = prompt4.arguments ?? [];
|
|
4084
|
+
const reqCount = Array.isArray(args) ? args.filter((a) => a?.required).length : 0;
|
|
4085
|
+
const total = Array.isArray(args) ? args.length : 0;
|
|
4086
|
+
const argsCell = total === 0 ? source_default.gray("\u2014") : `${reqCount}/${total}`;
|
|
4087
|
+
return {
|
|
4088
|
+
name: source_default.bold(prompt4.name),
|
|
4089
|
+
args: argsCell,
|
|
4090
|
+
description: prompt4.description || source_default.gray("(no description)")
|
|
4091
|
+
};
|
|
4092
|
+
});
|
|
4093
|
+
console.log(
|
|
4094
|
+
formatTable(tableData, [
|
|
4095
|
+
{ key: "name", header: "Prompt" },
|
|
4096
|
+
{ key: "args", header: "Args" },
|
|
4097
|
+
{ key: "description", header: "Description", truncate: true }
|
|
4098
|
+
])
|
|
4099
|
+
);
|
|
2627
4100
|
}
|
|
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
4101
|
} catch (error) {
|
|
2641
4102
|
console.error(formatError(`Failed to list prompts: ${error.message}`));
|
|
2642
|
-
|
|
4103
|
+
await cleanupAndExit(1);
|
|
2643
4104
|
}
|
|
4105
|
+
await cleanupAndExit(0);
|
|
2644
4106
|
}
|
|
2645
|
-
async function getPromptCommand(promptName,
|
|
4107
|
+
async function getPromptCommand(name, promptName, argsList, options) {
|
|
2646
4108
|
try {
|
|
2647
|
-
const result = await getOrRestoreSession(
|
|
2648
|
-
if (!result)
|
|
4109
|
+
const result = await getOrRestoreSession(name);
|
|
4110
|
+
if (!result) {
|
|
4111
|
+
await cleanupAndExit(1);
|
|
4112
|
+
}
|
|
2649
4113
|
const { session } = result;
|
|
2650
4114
|
let args = {};
|
|
2651
|
-
if (
|
|
4115
|
+
if (argsList && argsList.length > 0) {
|
|
2652
4116
|
try {
|
|
2653
|
-
args =
|
|
4117
|
+
args = parsePromptArgs(argsList);
|
|
2654
4118
|
} catch (error) {
|
|
2655
|
-
console.error(formatError(
|
|
2656
|
-
|
|
4119
|
+
console.error(formatError(error.message));
|
|
4120
|
+
console.log("");
|
|
4121
|
+
console.log(formatInfo("Usage:"));
|
|
4122
|
+
console.log(
|
|
4123
|
+
` npx mcp-use client ${name} prompts get ${promptName} key=value [key2=value2 ...]`
|
|
4124
|
+
);
|
|
4125
|
+
console.log(
|
|
4126
|
+
` npx mcp-use client ${name} prompts get ${promptName} '{"key":"value"}' # full JSON object`
|
|
4127
|
+
);
|
|
4128
|
+
await cleanupAndExit(1);
|
|
2657
4129
|
}
|
|
2658
4130
|
}
|
|
2659
4131
|
console.error(formatInfo(`Getting prompt '${promptName}'...`));
|
|
@@ -2675,12 +4147,13 @@ async function getPromptCommand(promptName, argsJson, options) {
|
|
|
2675
4147
|
}
|
|
2676
4148
|
} catch (error) {
|
|
2677
4149
|
console.error(formatError(`Failed to get prompt: ${error.message}`));
|
|
2678
|
-
|
|
4150
|
+
await cleanupAndExit(1);
|
|
2679
4151
|
}
|
|
4152
|
+
await cleanupAndExit(0);
|
|
2680
4153
|
}
|
|
2681
|
-
async function interactiveCommand(
|
|
4154
|
+
async function interactiveCommand(name) {
|
|
2682
4155
|
try {
|
|
2683
|
-
const result = await getOrRestoreSession(
|
|
4156
|
+
const result = await getOrRestoreSession(name);
|
|
2684
4157
|
if (!result) return;
|
|
2685
4158
|
const { name: sessionName, session } = result;
|
|
2686
4159
|
console.log(formatHeader("MCP Interactive Mode"));
|
|
@@ -2703,15 +4176,11 @@ async function interactiveCommand(options) {
|
|
|
2703
4176
|
source_default.gray(" prompts list - List available prompts")
|
|
2704
4177
|
);
|
|
2705
4178
|
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
4179
|
console.log(
|
|
2711
4180
|
source_default.gray(" exit, quit - Exit interactive mode")
|
|
2712
4181
|
);
|
|
2713
4182
|
console.log("");
|
|
2714
|
-
const rl = (0,
|
|
4183
|
+
const rl = (0, import_node_readline2.createInterface)({
|
|
2715
4184
|
input: process.stdin,
|
|
2716
4185
|
output: process.stdout,
|
|
2717
4186
|
prompt: source_default.cyan("mcp> ")
|
|
@@ -2726,7 +4195,7 @@ async function interactiveCommand(options) {
|
|
|
2726
4195
|
if (trimmed === "exit" || trimmed === "quit") {
|
|
2727
4196
|
console.log(formatInfo("Goodbye!"));
|
|
2728
4197
|
rl.close();
|
|
2729
|
-
|
|
4198
|
+
await cleanupAndExit(0);
|
|
2730
4199
|
}
|
|
2731
4200
|
const parts = trimmed.split(" ");
|
|
2732
4201
|
const scope = parts[0];
|
|
@@ -2826,22 +4295,10 @@ async function interactiveCommand(options) {
|
|
|
2826
4295
|
)
|
|
2827
4296
|
);
|
|
2828
4297
|
}
|
|
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
4298
|
} else {
|
|
2842
4299
|
console.error(
|
|
2843
4300
|
formatError(
|
|
2844
|
-
"Unknown command. Type a valid scope: tools, resources, prompts
|
|
4301
|
+
"Unknown command. Type a valid scope: tools, resources, prompts"
|
|
2845
4302
|
)
|
|
2846
4303
|
);
|
|
2847
4304
|
}
|
|
@@ -2850,63 +4307,100 @@ async function interactiveCommand(options) {
|
|
|
2850
4307
|
}
|
|
2851
4308
|
rl.prompt();
|
|
2852
4309
|
});
|
|
2853
|
-
rl.on("close", () => {
|
|
4310
|
+
rl.on("close", async () => {
|
|
2854
4311
|
console.log("");
|
|
2855
4312
|
console.log(formatInfo("Goodbye!"));
|
|
2856
|
-
|
|
4313
|
+
await cleanupAndExit(0);
|
|
2857
4314
|
});
|
|
2858
4315
|
} catch (error) {
|
|
2859
4316
|
console.error(
|
|
2860
4317
|
formatError(`Failed to start interactive mode: ${error.message}`)
|
|
2861
4318
|
);
|
|
2862
|
-
|
|
4319
|
+
await cleanupAndExit(1);
|
|
2863
4320
|
}
|
|
2864
4321
|
}
|
|
2865
4322
|
function createClientCommand() {
|
|
2866
|
-
const clientCommand = new
|
|
2867
|
-
"Interactive MCP client for terminal usage"
|
|
4323
|
+
const clientCommand = new import_commander2.Command("client").description(
|
|
4324
|
+
"Interactive MCP client for terminal usage. Use `mcp-use client <name> ...` to run commands against a saved server."
|
|
4325
|
+
).showHelpAfterError(
|
|
4326
|
+
"(Run `mcp-use client --help` to see available commands)"
|
|
4327
|
+
);
|
|
4328
|
+
clientCommand.command("connect [name] [url]").description(
|
|
4329
|
+
"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`)."
|
|
4330
|
+
).option("--stdio", "Use stdio connector instead of HTTP").option("--auth <token>", "Static Bearer token (skips OAuth)").option(
|
|
4331
|
+
"--no-oauth",
|
|
4332
|
+
"Don't auto-trigger OAuth on 401; fail with the 401 instead"
|
|
4333
|
+
).option(
|
|
4334
|
+
"--auth-timeout <ms>",
|
|
4335
|
+
"OAuth loopback wait timeout in ms (default 300000)"
|
|
4336
|
+
).action(connectCommand);
|
|
4337
|
+
clientCommand.command("list").description("List saved servers").action(listClientsCommand);
|
|
4338
|
+
clientCommand.command("remove <name>").description(
|
|
4339
|
+
"Remove a saved server. Also clears any OAuth tokens for that URL, unless another saved server still uses it."
|
|
4340
|
+
).action(removeClientCommand);
|
|
4341
|
+
clientCommand.addCommand(createClientScreenshotCommand());
|
|
4342
|
+
return clientCommand;
|
|
4343
|
+
}
|
|
4344
|
+
function createPerClientCommand(name) {
|
|
4345
|
+
const cmd = new import_commander2.Command(`mcp-use client ${name}`).description(`Commands for server '${name}'`).showHelpAfterError(
|
|
4346
|
+
`(Run \`mcp-use client ${name} --help\` to see available commands)`
|
|
2868
4347
|
);
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
const
|
|
2872
|
-
|
|
4348
|
+
cmd.command("disconnect").description("Disconnect from this server").action(() => disconnectCommand(name));
|
|
4349
|
+
cmd.command("interactive").description("Start interactive REPL mode for this server").action(() => interactiveCommand(name));
|
|
4350
|
+
const toolsCommand = new import_commander2.Command("tools").description("Interact with MCP tools").showHelpAfterError(
|
|
4351
|
+
`(Run \`mcp-use client ${name} tools --help\` to see available actions)`
|
|
2873
4352
|
);
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
"
|
|
4353
|
+
toolsCommand.command("list").description("List available tools").option("--json", "Output as JSON").action((options) => listToolsCommand(name, options));
|
|
4354
|
+
toolsCommand.command("call <tool> [args...]").description(
|
|
4355
|
+
"Call a tool. Args as key=value pairs (use key:=<json> for nested values, or pass a JSON object)"
|
|
4356
|
+
).option("--timeout <ms>", "Request timeout in milliseconds", parseInt).option("--json", "Output as JSON").option(
|
|
4357
|
+
"--no-screenshot",
|
|
4358
|
+
"Skip the auto-screenshot for tools that render a widget"
|
|
4359
|
+
).option(
|
|
4360
|
+
"--screenshot-output <path>",
|
|
4361
|
+
"Output PNG path for the widget screenshot (defaults to ./<view>-<timestamp>.png)"
|
|
4362
|
+
).action(
|
|
4363
|
+
(tool, args, options) => callToolCommand(name, tool, args, options)
|
|
2879
4364
|
);
|
|
2880
|
-
toolsCommand.command("
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
const resourcesCommand = new import_commander.Command("resources").description(
|
|
2885
|
-
"Interact with MCP resources"
|
|
4365
|
+
toolsCommand.command("describe <tool>").description("Show tool details and schema").action((tool) => describeToolCommand(name, tool));
|
|
4366
|
+
cmd.addCommand(toolsCommand);
|
|
4367
|
+
const resourcesCommand = new import_commander2.Command("resources").description("Interact with MCP resources").showHelpAfterError(
|
|
4368
|
+
`(Run \`mcp-use client ${name} resources --help\` to see available actions)`
|
|
2886
4369
|
);
|
|
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
|
-
|
|
4370
|
+
resourcesCommand.command("list").description("List available resources").option("--json", "Output as JSON").action((options) => listResourcesCommand(name, options));
|
|
4371
|
+
resourcesCommand.command("read <uri>").description("Read a resource by URI").option("--json", "Output as JSON").action((uri, options) => readResourceCommand(name, uri, options));
|
|
4372
|
+
resourcesCommand.command("subscribe <uri>").description("Subscribe to resource updates").action((uri) => subscribeResourceCommand(name, uri));
|
|
4373
|
+
resourcesCommand.command("unsubscribe <uri>").description("Unsubscribe from resource updates").action((uri) => unsubscribeResourceCommand(name, uri));
|
|
4374
|
+
cmd.addCommand(resourcesCommand);
|
|
4375
|
+
const promptsCommand = new import_commander2.Command("prompts").description("Interact with MCP prompts").showHelpAfterError(
|
|
4376
|
+
`(Run \`mcp-use client ${name} prompts --help\` to see available actions)`
|
|
2894
4377
|
);
|
|
2895
|
-
promptsCommand.command("list").description("List available prompts").option("--
|
|
2896
|
-
promptsCommand.command("get <
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
4378
|
+
promptsCommand.command("list").description("List available prompts").option("--json", "Output as JSON").action((options) => listPromptsCommand(name, options));
|
|
4379
|
+
promptsCommand.command("get <prompt> [args...]").description(
|
|
4380
|
+
"Get a prompt. Args as key=value pairs (or pass a JSON object)"
|
|
4381
|
+
).option("--json", "Output as JSON").action(
|
|
4382
|
+
(prompt4, args, options) => getPromptCommand(name, prompt4, args, options)
|
|
4383
|
+
);
|
|
4384
|
+
cmd.addCommand(promptsCommand);
|
|
4385
|
+
const authCommand = new import_commander2.Command("auth").description("Manage OAuth tokens for HTTP servers").showHelpAfterError(
|
|
4386
|
+
`(Run \`mcp-use client ${name} auth --help\` to see available actions)`
|
|
4387
|
+
);
|
|
4388
|
+
authCommand.command("status").description("Show OAuth token status for this server").action(() => authStatusCommand(name));
|
|
4389
|
+
authCommand.command("refresh").description("Force-refresh the OAuth access token").action(() => authRefreshCommand(name));
|
|
4390
|
+
authCommand.command("logout").description("Remove stored OAuth tokens for this server's URL").action(() => authLogoutCommand(name));
|
|
4391
|
+
cmd.addCommand(authCommand);
|
|
4392
|
+
cmd.addCommand(createPerClientScreenshotCommand(name));
|
|
4393
|
+
return cmd;
|
|
2900
4394
|
}
|
|
2901
4395
|
|
|
2902
4396
|
// src/commands/deploy.ts
|
|
2903
|
-
var
|
|
2904
|
-
var
|
|
4397
|
+
var import_node_fs10 = require("fs");
|
|
4398
|
+
var import_node_path8 = __toESM(require("path"), 1);
|
|
2905
4399
|
|
|
2906
4400
|
// src/utils/git.ts
|
|
2907
|
-
var
|
|
4401
|
+
var import_node_child_process10 = require("child_process");
|
|
2908
4402
|
var import_node_util7 = require("util");
|
|
2909
|
-
var execFileAsync5 = (0, import_node_util7.promisify)(
|
|
4403
|
+
var execFileAsync5 = (0, import_node_util7.promisify)(import_node_child_process10.execFile);
|
|
2910
4404
|
async function gitCommand(args, cwd = process.cwd()) {
|
|
2911
4405
|
try {
|
|
2912
4406
|
const { stdout } = await execFileAsync5("git", args, { cwd });
|
|
@@ -3055,17 +4549,17 @@ function getMcpServerUrlForCloudServer(server) {
|
|
|
3055
4549
|
}
|
|
3056
4550
|
|
|
3057
4551
|
// src/utils/project-link.ts
|
|
3058
|
-
var
|
|
3059
|
-
var
|
|
4552
|
+
var import_node_fs9 = require("fs");
|
|
4553
|
+
var import_node_path7 = __toESM(require("path"), 1);
|
|
3060
4554
|
var MCP_USE_DIR = ".mcp-use";
|
|
3061
4555
|
var MCP_USE_DIR_PROJECT = "project.json";
|
|
3062
4556
|
function getMcpUseDirectory(cwd) {
|
|
3063
|
-
return
|
|
4557
|
+
return import_node_path7.default.join(cwd, MCP_USE_DIR);
|
|
3064
4558
|
}
|
|
3065
4559
|
async function getProjectLink(cwd) {
|
|
3066
4560
|
try {
|
|
3067
|
-
const linkPath =
|
|
3068
|
-
const content = await
|
|
4561
|
+
const linkPath = import_node_path7.default.join(getMcpUseDirectory(cwd), MCP_USE_DIR_PROJECT);
|
|
4562
|
+
const content = await import_node_fs9.promises.readFile(linkPath, "utf-8");
|
|
3069
4563
|
return JSON.parse(content);
|
|
3070
4564
|
} catch (err) {
|
|
3071
4565
|
if (err.code === "ENOENT") return null;
|
|
@@ -3074,17 +4568,17 @@ async function getProjectLink(cwd) {
|
|
|
3074
4568
|
}
|
|
3075
4569
|
async function saveProjectLink(cwd, link) {
|
|
3076
4570
|
const mcpUseDir = getMcpUseDirectory(cwd);
|
|
3077
|
-
await
|
|
3078
|
-
const linkPath =
|
|
3079
|
-
await
|
|
4571
|
+
await import_node_fs9.promises.mkdir(mcpUseDir, { recursive: true });
|
|
4572
|
+
const linkPath = import_node_path7.default.join(mcpUseDir, MCP_USE_DIR_PROJECT);
|
|
4573
|
+
await import_node_fs9.promises.writeFile(linkPath, JSON.stringify(link, null, 2), "utf-8");
|
|
3080
4574
|
await addToGitIgnore(cwd);
|
|
3081
4575
|
}
|
|
3082
4576
|
async function addToGitIgnore(cwd) {
|
|
3083
|
-
const gitignorePath =
|
|
4577
|
+
const gitignorePath = import_node_path7.default.join(cwd, ".gitignore");
|
|
3084
4578
|
try {
|
|
3085
4579
|
let content = "";
|
|
3086
4580
|
try {
|
|
3087
|
-
content = await
|
|
4581
|
+
content = await import_node_fs9.promises.readFile(gitignorePath, "utf-8");
|
|
3088
4582
|
} catch (err) {
|
|
3089
4583
|
if (err.code !== "ENOENT") throw err;
|
|
3090
4584
|
}
|
|
@@ -3093,7 +4587,7 @@ async function addToGitIgnore(cwd) {
|
|
|
3093
4587
|
# mcp-use deployment
|
|
3094
4588
|
${MCP_USE_DIR}
|
|
3095
4589
|
`;
|
|
3096
|
-
await
|
|
4590
|
+
await import_node_fs9.promises.writeFile(gitignorePath, newContent, "utf-8");
|
|
3097
4591
|
}
|
|
3098
4592
|
} catch (err) {
|
|
3099
4593
|
}
|
|
@@ -3102,7 +4596,7 @@ ${MCP_USE_DIR}
|
|
|
3102
4596
|
// src/commands/deploy.ts
|
|
3103
4597
|
async function parseEnvFile(filePath) {
|
|
3104
4598
|
try {
|
|
3105
|
-
const content = await
|
|
4599
|
+
const content = await import_node_fs10.promises.readFile(filePath, "utf-8");
|
|
3106
4600
|
const envVars = {};
|
|
3107
4601
|
const lines = content.split("\n");
|
|
3108
4602
|
let currentKey = null;
|
|
@@ -3221,7 +4715,7 @@ async function buildEnvVars(options) {
|
|
|
3221
4715
|
}
|
|
3222
4716
|
async function isMcpProject(cwd = process.cwd()) {
|
|
3223
4717
|
try {
|
|
3224
|
-
const content = await
|
|
4718
|
+
const content = await import_node_fs10.promises.readFile(import_node_path8.default.join(cwd, "package.json"), "utf-8");
|
|
3225
4719
|
const pkg = JSON.parse(content);
|
|
3226
4720
|
return !!(pkg.dependencies?.["mcp-use"] || pkg.dependencies?.["@modelcontextprotocol/sdk"] || pkg.devDependencies?.["mcp-use"] || pkg.devDependencies?.["@modelcontextprotocol/sdk"]);
|
|
3227
4721
|
} catch {
|
|
@@ -3230,16 +4724,16 @@ async function isMcpProject(cwd = process.cwd()) {
|
|
|
3230
4724
|
}
|
|
3231
4725
|
async function getProjectName(cwd = process.cwd()) {
|
|
3232
4726
|
try {
|
|
3233
|
-
const content = await
|
|
4727
|
+
const content = await import_node_fs10.promises.readFile(import_node_path8.default.join(cwd, "package.json"), "utf-8");
|
|
3234
4728
|
const pkg = JSON.parse(content);
|
|
3235
4729
|
if (pkg.name) return pkg.name;
|
|
3236
4730
|
} catch {
|
|
3237
4731
|
}
|
|
3238
|
-
return
|
|
4732
|
+
return import_node_path8.default.basename(cwd);
|
|
3239
4733
|
}
|
|
3240
4734
|
async function detectBuildCommand(cwd) {
|
|
3241
4735
|
try {
|
|
3242
|
-
const content = await
|
|
4736
|
+
const content = await import_node_fs10.promises.readFile(import_node_path8.default.join(cwd, "package.json"), "utf-8");
|
|
3243
4737
|
if (JSON.parse(content).scripts?.build) return "npm run build";
|
|
3244
4738
|
} catch {
|
|
3245
4739
|
}
|
|
@@ -3247,7 +4741,7 @@ async function detectBuildCommand(cwd) {
|
|
|
3247
4741
|
}
|
|
3248
4742
|
async function detectStartCommand(cwd) {
|
|
3249
4743
|
try {
|
|
3250
|
-
const content = await
|
|
4744
|
+
const content = await import_node_fs10.promises.readFile(import_node_path8.default.join(cwd, "package.json"), "utf-8");
|
|
3251
4745
|
const pkg = JSON.parse(content);
|
|
3252
4746
|
if (pkg.scripts?.start) return "npm start";
|
|
3253
4747
|
if (pkg.main) return `node ${pkg.main}`;
|
|
@@ -3258,7 +4752,7 @@ async function detectStartCommand(cwd) {
|
|
|
3258
4752
|
async function detectRuntime(cwd) {
|
|
3259
4753
|
for (const f of ["requirements.txt", "pyproject.toml", "setup.py"]) {
|
|
3260
4754
|
try {
|
|
3261
|
-
await
|
|
4755
|
+
await import_node_fs10.promises.access(import_node_path8.default.join(cwd, f));
|
|
3262
4756
|
return "python";
|
|
3263
4757
|
} catch {
|
|
3264
4758
|
continue;
|
|
@@ -3305,17 +4799,17 @@ var REQUIRED_IGNORES = [
|
|
|
3305
4799
|
".mcp-use"
|
|
3306
4800
|
];
|
|
3307
4801
|
async function ensureGitignore(cwd) {
|
|
3308
|
-
const gitignorePath =
|
|
4802
|
+
const gitignorePath = import_node_path8.default.join(cwd, ".gitignore");
|
|
3309
4803
|
let content = "";
|
|
3310
4804
|
try {
|
|
3311
|
-
content = await
|
|
4805
|
+
content = await import_node_fs10.promises.readFile(gitignorePath, "utf-8");
|
|
3312
4806
|
} catch {
|
|
3313
4807
|
}
|
|
3314
4808
|
const missing = REQUIRED_IGNORES.filter((entry) => !content.includes(entry));
|
|
3315
4809
|
if (missing.length > 0) {
|
|
3316
4810
|
const additions = missing.join("\n");
|
|
3317
4811
|
const newContent = content + (content.endsWith("\n") ? "" : "\n") + additions + "\n";
|
|
3318
|
-
await
|
|
4812
|
+
await import_node_fs10.promises.writeFile(gitignorePath, newContent, "utf-8");
|
|
3319
4813
|
}
|
|
3320
4814
|
}
|
|
3321
4815
|
async function displayDeploymentProgress(api, deploymentId, progressOptions) {
|
|
@@ -3765,10 +5259,10 @@ async function deployCommand(options) {
|
|
|
3765
5259
|
console.log(source_default.green("\u2713 GitHub connected\n"));
|
|
3766
5260
|
let installationDbId;
|
|
3767
5261
|
let githubInstallationId;
|
|
3768
|
-
const projectDir = options.rootDir ?
|
|
5262
|
+
const projectDir = options.rootDir ? import_node_path8.default.resolve(cwd, options.rootDir) : cwd;
|
|
3769
5263
|
if (options.rootDir) {
|
|
3770
5264
|
try {
|
|
3771
|
-
await
|
|
5265
|
+
await import_node_fs10.promises.access(projectDir);
|
|
3772
5266
|
} catch {
|
|
3773
5267
|
console.log(
|
|
3774
5268
|
source_default.red(`\u2717 Root directory not found: ${options.rootDir}`)
|
|
@@ -4277,7 +5771,7 @@ async function deployCommand(options) {
|
|
|
4277
5771
|
}
|
|
4278
5772
|
|
|
4279
5773
|
// src/commands/deployments.ts
|
|
4280
|
-
var
|
|
5774
|
+
var import_commander3 = require("commander");
|
|
4281
5775
|
async function prompt2(question) {
|
|
4282
5776
|
const readline = await import("readline");
|
|
4283
5777
|
const rl = readline.createInterface({
|
|
@@ -4689,8 +6183,8 @@ async function startDeploymentCommand(deploymentId) {
|
|
|
4689
6183
|
}
|
|
4690
6184
|
}
|
|
4691
6185
|
function createDeploymentsCommand() {
|
|
4692
|
-
const deploymentsCommand = new
|
|
4693
|
-
"
|
|
6186
|
+
const deploymentsCommand = new import_commander3.Command("deployments").description("Manage cloud deployments").showHelpAfterError(
|
|
6187
|
+
"(Run `mcp-use deployments --help` to see available commands)"
|
|
4694
6188
|
);
|
|
4695
6189
|
deploymentsCommand.command("list").alias("ls").description("List all deployments").action(listDeploymentsCommand);
|
|
4696
6190
|
deploymentsCommand.command("get").argument("<deployment-id>", "Deployment ID").description("Get deployment details").action(getDeploymentCommand);
|
|
@@ -4705,10 +6199,10 @@ function createDeploymentsCommand() {
|
|
|
4705
6199
|
}
|
|
4706
6200
|
|
|
4707
6201
|
// src/commands/servers.ts
|
|
4708
|
-
var
|
|
6202
|
+
var import_commander5 = require("commander");
|
|
4709
6203
|
|
|
4710
6204
|
// src/commands/env.ts
|
|
4711
|
-
var
|
|
6205
|
+
var import_commander4 = require("commander");
|
|
4712
6206
|
var ALL_ENVS = ["production", "preview", "development"];
|
|
4713
6207
|
function parseEnvironments(raw) {
|
|
4714
6208
|
const parts = raw.split(",").map((s) => s.trim().toLowerCase()).filter(Boolean);
|
|
@@ -4853,9 +6347,7 @@ async function removeEnvCommand(varId, options) {
|
|
|
4853
6347
|
}
|
|
4854
6348
|
}
|
|
4855
6349
|
function createEnvCommand() {
|
|
4856
|
-
const envCommand = new
|
|
4857
|
-
"Manage environment variables for a server"
|
|
4858
|
-
);
|
|
6350
|
+
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
6351
|
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
6352
|
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
6353
|
"--env <environments>",
|
|
@@ -5137,8 +6629,8 @@ async function deleteServerCommand(serverId, options) {
|
|
|
5137
6629
|
}
|
|
5138
6630
|
}
|
|
5139
6631
|
function createServersCommand() {
|
|
5140
|
-
const serversCommand = new
|
|
5141
|
-
"
|
|
6632
|
+
const serversCommand = new import_commander5.Command("servers").description("Manage cloud servers (Git-backed deploy targets)").showHelpAfterError(
|
|
6633
|
+
"(Run `mcp-use servers --help` to see available commands)"
|
|
5142
6634
|
);
|
|
5143
6635
|
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
6636
|
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 +6747,12 @@ async function orgCurrentCommand() {
|
|
|
5255
6747
|
}
|
|
5256
6748
|
|
|
5257
6749
|
// src/commands/skills.ts
|
|
5258
|
-
var
|
|
5259
|
-
var
|
|
5260
|
-
var
|
|
5261
|
-
var
|
|
6750
|
+
var import_commander6 = require("commander");
|
|
6751
|
+
var import_node_fs11 = require("fs");
|
|
6752
|
+
var import_node_os6 = require("os");
|
|
6753
|
+
var import_node_path9 = require("path");
|
|
5262
6754
|
var import_node_stream = require("stream");
|
|
5263
|
-
var
|
|
6755
|
+
var import_promises6 = require("stream/promises");
|
|
5264
6756
|
var import_tar = require("tar");
|
|
5265
6757
|
var REPO_OWNER = "mcp-use";
|
|
5266
6758
|
var REPO_NAME = "mcp-use";
|
|
@@ -5295,42 +6787,42 @@ function sendInstallTelemetryEvent(agents, skills) {
|
|
|
5295
6787
|
}
|
|
5296
6788
|
async function addSkillsToProject(projectPath) {
|
|
5297
6789
|
const tarballUrl = `https://codeload.github.com/${REPO_OWNER}/${REPO_NAME}/tar.gz/${REPO_BRANCH}`;
|
|
5298
|
-
const tempDir = (0,
|
|
6790
|
+
const tempDir = (0, import_node_fs11.mkdtempSync)((0, import_node_path9.join)((0, import_node_os6.tmpdir)(), "mcp-use-skills-"));
|
|
5299
6791
|
try {
|
|
5300
6792
|
const response = await fetch(tarballUrl);
|
|
5301
6793
|
if (!response.ok) {
|
|
5302
6794
|
throw new Error(`Failed to download tarball: ${response.statusText}`);
|
|
5303
6795
|
}
|
|
5304
|
-
await (0,
|
|
6796
|
+
await (0, import_promises6.pipeline)(
|
|
5305
6797
|
import_node_stream.Readable.fromWeb(response.body),
|
|
5306
6798
|
(0, import_tar.extract)({
|
|
5307
6799
|
cwd: tempDir,
|
|
5308
|
-
filter: (
|
|
6800
|
+
filter: (path11) => path11.includes("/skills/"),
|
|
5309
6801
|
strip: 1
|
|
5310
6802
|
})
|
|
5311
6803
|
);
|
|
5312
|
-
const skillsPath = (0,
|
|
5313
|
-
if (!(0,
|
|
6804
|
+
const skillsPath = (0, import_node_path9.join)(tempDir, "skills");
|
|
6805
|
+
if (!(0, import_node_fs11.existsSync)(skillsPath)) {
|
|
5314
6806
|
throw new Error("Skills folder not found in repository");
|
|
5315
6807
|
}
|
|
5316
6808
|
for (const preset of ALL_PRESETS) {
|
|
5317
6809
|
const folderName = AGENT_PRESET_FOLDERS[preset];
|
|
5318
|
-
const outputPath = (0,
|
|
5319
|
-
(0,
|
|
6810
|
+
const outputPath = (0, import_node_path9.join)(projectPath, folderName, "skills");
|
|
6811
|
+
(0, import_node_fs11.cpSync)(skillsPath, outputPath, { recursive: true });
|
|
5320
6812
|
}
|
|
5321
|
-
const skillNames = (0,
|
|
6813
|
+
const skillNames = (0, import_node_fs11.readdirSync)(skillsPath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
5322
6814
|
sendInstallTelemetryEvent(ALL_PRESETS.join(","), skillNames.join(","));
|
|
5323
6815
|
} finally {
|
|
5324
|
-
(0,
|
|
6816
|
+
(0, import_node_fs11.rmSync)(tempDir, { recursive: true, force: true });
|
|
5325
6817
|
}
|
|
5326
6818
|
}
|
|
5327
6819
|
function createSkillsCommand() {
|
|
5328
|
-
const skills = new
|
|
5329
|
-
"
|
|
6820
|
+
const skills = new import_commander6.Command("skills").description("Manage mcp-use AI agent skills").showHelpAfterError(
|
|
6821
|
+
"(Run `mcp-use skills --help` to see available commands)"
|
|
5330
6822
|
);
|
|
5331
6823
|
const installAction = async (options) => {
|
|
5332
|
-
const projectPath = (0,
|
|
5333
|
-
if (!(0,
|
|
6824
|
+
const projectPath = (0, import_node_path9.resolve)(options.path);
|
|
6825
|
+
if (!(0, import_node_fs11.existsSync)(projectPath)) {
|
|
5334
6826
|
console.error(source_default.red(`Directory not found: ${projectPath}`));
|
|
5335
6827
|
process.exit(1);
|
|
5336
6828
|
}
|
|
@@ -5371,13 +6863,13 @@ function createSkillsCommand() {
|
|
|
5371
6863
|
}
|
|
5372
6864
|
|
|
5373
6865
|
// src/utils/next-shims.ts
|
|
5374
|
-
var
|
|
5375
|
-
var
|
|
6866
|
+
var import_node_fs12 = require("fs");
|
|
6867
|
+
var import_node_path10 = __toESM(require("path"), 1);
|
|
5376
6868
|
var import_node_url2 = require("url");
|
|
5377
6869
|
async function detectNextJsProject(projectPath) {
|
|
5378
6870
|
try {
|
|
5379
|
-
const pkgPath =
|
|
5380
|
-
const content = await
|
|
6871
|
+
const pkgPath = import_node_path10.default.join(projectPath, "package.json");
|
|
6872
|
+
const content = await import_node_fs12.promises.readFile(pkgPath, "utf-8");
|
|
5381
6873
|
const pkg = JSON.parse(content);
|
|
5382
6874
|
const deps = pkg.dependencies ?? {};
|
|
5383
6875
|
const devDeps = pkg.devDependencies ?? {};
|
|
@@ -5395,9 +6887,9 @@ async function loadNextJsEnvFiles(projectPath) {
|
|
|
5395
6887
|
];
|
|
5396
6888
|
const dotenv = await import("dotenv");
|
|
5397
6889
|
for (const file of files) {
|
|
5398
|
-
const abs =
|
|
6890
|
+
const abs = import_node_path10.default.join(projectPath, file);
|
|
5399
6891
|
try {
|
|
5400
|
-
await
|
|
6892
|
+
await import_node_fs12.promises.access(abs);
|
|
5401
6893
|
} catch {
|
|
5402
6894
|
continue;
|
|
5403
6895
|
}
|
|
@@ -5407,20 +6899,20 @@ async function loadNextJsEnvFiles(projectPath) {
|
|
|
5407
6899
|
function getThisDir() {
|
|
5408
6900
|
if (typeof __dirname === "string") return __dirname;
|
|
5409
6901
|
const url = importMetaUrl;
|
|
5410
|
-
return
|
|
6902
|
+
return import_node_path10.default.dirname((0, import_node_url2.fileURLToPath)(url));
|
|
5411
6903
|
}
|
|
5412
6904
|
function resolveShimPath(filename) {
|
|
5413
6905
|
const thisDir = getThisDir();
|
|
5414
6906
|
const candidates = [
|
|
5415
6907
|
// Production: `dist/` next to this module
|
|
5416
|
-
|
|
6908
|
+
import_node_path10.default.join(thisDir, "shims", filename),
|
|
5417
6909
|
// Test / dev: one level up (e.g., from `dist/utils/` back to `src/shims/`)
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
6910
|
+
import_node_path10.default.join(thisDir, "..", "shims", filename),
|
|
6911
|
+
import_node_path10.default.join(thisDir, "..", "..", "src", "shims", filename),
|
|
6912
|
+
import_node_path10.default.join(thisDir, "..", "src", "shims", filename)
|
|
5421
6913
|
];
|
|
5422
6914
|
for (const candidate of candidates) {
|
|
5423
|
-
if ((0,
|
|
6915
|
+
if ((0, import_node_fs12.existsSync)(candidate)) return candidate;
|
|
5424
6916
|
}
|
|
5425
6917
|
return void 0;
|
|
5426
6918
|
}
|
|
@@ -5438,7 +6930,7 @@ async function registerNextShimsInProcess() {
|
|
|
5438
6930
|
const cjsPath = getShimCjsPreloadPath();
|
|
5439
6931
|
if (cjsPath) {
|
|
5440
6932
|
const { createRequire: createRequire3 } = await import("module");
|
|
5441
|
-
const req = createRequire3((0, import_node_url2.pathToFileURL)(getThisDir() +
|
|
6933
|
+
const req = createRequire3((0, import_node_url2.pathToFileURL)(getThisDir() + import_node_path10.default.sep).href);
|
|
5442
6934
|
req(cjsPath);
|
|
5443
6935
|
anyRegistered = true;
|
|
5444
6936
|
}
|
|
@@ -5446,7 +6938,7 @@ async function registerNextShimsInProcess() {
|
|
|
5446
6938
|
if (loaderPath) {
|
|
5447
6939
|
const { register } = await import("module");
|
|
5448
6940
|
const loaderUrl = (0, import_node_url2.pathToFileURL)(loaderPath).href;
|
|
5449
|
-
register(loaderUrl, (0, import_node_url2.pathToFileURL)(getThisDir() +
|
|
6941
|
+
register(loaderUrl, (0, import_node_url2.pathToFileURL)(getThisDir() + import_node_path10.default.sep).href);
|
|
5450
6942
|
anyRegistered = true;
|
|
5451
6943
|
}
|
|
5452
6944
|
return anyRegistered;
|
|
@@ -5471,13 +6963,13 @@ function quoteNodeOption(value) {
|
|
|
5471
6963
|
}
|
|
5472
6964
|
|
|
5473
6965
|
// src/utils/update-check.ts
|
|
5474
|
-
var
|
|
5475
|
-
var
|
|
6966
|
+
var import_node_fs13 = require("fs");
|
|
6967
|
+
var import_promises7 = require("fs/promises");
|
|
5476
6968
|
var import_node_module = require("module");
|
|
5477
|
-
var
|
|
5478
|
-
var
|
|
5479
|
-
var CACHE_DIR =
|
|
5480
|
-
var CACHE_FILE =
|
|
6969
|
+
var import_node_os7 = __toESM(require("os"), 1);
|
|
6970
|
+
var import_node_path11 = __toESM(require("path"), 1);
|
|
6971
|
+
var CACHE_DIR = import_node_path11.default.join(import_node_os7.default.homedir(), ".mcp-use");
|
|
6972
|
+
var CACHE_FILE = import_node_path11.default.join(CACHE_DIR, "update-check.json");
|
|
5481
6973
|
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
5482
6974
|
var FETCH_TIMEOUT_MS = 3e3;
|
|
5483
6975
|
var PACKAGE_NAME = "mcp-use";
|
|
@@ -5502,7 +6994,7 @@ function isNewer(current, candidate) {
|
|
|
5502
6994
|
}
|
|
5503
6995
|
async function readCache() {
|
|
5504
6996
|
try {
|
|
5505
|
-
const content = await (0,
|
|
6997
|
+
const content = await (0, import_promises7.readFile)(CACHE_FILE, "utf-8");
|
|
5506
6998
|
return JSON.parse(content);
|
|
5507
6999
|
} catch {
|
|
5508
7000
|
return null;
|
|
@@ -5510,12 +7002,12 @@ async function readCache() {
|
|
|
5510
7002
|
}
|
|
5511
7003
|
async function writeCache(latestVersion) {
|
|
5512
7004
|
try {
|
|
5513
|
-
await (0,
|
|
7005
|
+
await (0, import_promises7.mkdir)(CACHE_DIR, { recursive: true });
|
|
5514
7006
|
const cache = {
|
|
5515
7007
|
lastChecked: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5516
7008
|
latestVersion
|
|
5517
7009
|
};
|
|
5518
|
-
await (0,
|
|
7010
|
+
await (0, import_promises7.writeFile)(CACHE_FILE, JSON.stringify(cache, null, 2), "utf-8");
|
|
5519
7011
|
} catch {
|
|
5520
7012
|
}
|
|
5521
7013
|
}
|
|
@@ -5560,16 +7052,16 @@ function resolveInstalledVersion(projectPath) {
|
|
|
5560
7052
|
if (projectPath) {
|
|
5561
7053
|
attempts.push(() => {
|
|
5562
7054
|
const projectRequire = (0, import_node_module.createRequire)(
|
|
5563
|
-
|
|
7055
|
+
import_node_path11.default.join(projectPath, "package.json")
|
|
5564
7056
|
);
|
|
5565
7057
|
return projectRequire.resolve(`${PACKAGE_NAME}/package.json`);
|
|
5566
7058
|
});
|
|
5567
7059
|
}
|
|
5568
|
-
attempts.push(() =>
|
|
7060
|
+
attempts.push(() => import_node_path11.default.join(__dirname, "../../mcp-use/package.json"));
|
|
5569
7061
|
for (const attempt of attempts) {
|
|
5570
7062
|
try {
|
|
5571
7063
|
const pkgPath = attempt();
|
|
5572
|
-
const json = JSON.parse((0,
|
|
7064
|
+
const json = JSON.parse((0, import_node_fs13.readFileSync)(pkgPath, "utf-8"));
|
|
5573
7065
|
if (typeof json.version === "string") return json.version;
|
|
5574
7066
|
} catch {
|
|
5575
7067
|
}
|
|
@@ -5601,14 +7093,14 @@ A new release of ${source_default.bold(PACKAGE_NAME)} is available: ${source_def
|
|
|
5601
7093
|
}
|
|
5602
7094
|
|
|
5603
7095
|
// src/index.ts
|
|
5604
|
-
var program = new
|
|
5605
|
-
var packageContent = (0,
|
|
5606
|
-
|
|
7096
|
+
var program = new import_commander7.Command();
|
|
7097
|
+
var packageContent = (0, import_node_fs14.readFileSync)(
|
|
7098
|
+
import_node_path12.default.join(__dirname, "../package.json"),
|
|
5607
7099
|
"utf-8"
|
|
5608
7100
|
);
|
|
5609
7101
|
var packageJson = JSON.parse(packageContent);
|
|
5610
7102
|
var packageVersion = packageJson.version || "unknown";
|
|
5611
|
-
program.name("mcp-use").description("Create and run MCP servers with ui resources widgets").version(packageVersion);
|
|
7103
|
+
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
7104
|
function displayPackageVersions(projectPath) {
|
|
5613
7105
|
const packages = [
|
|
5614
7106
|
{ name: "@mcp-use/cli", relativePath: "../package.json" },
|
|
@@ -5634,16 +7126,16 @@ function displayPackageVersions(projectPath) {
|
|
|
5634
7126
|
if (projectPath) {
|
|
5635
7127
|
try {
|
|
5636
7128
|
const projectRequire = (0, import_node_module2.createRequire)(
|
|
5637
|
-
|
|
7129
|
+
import_node_path12.default.join(projectPath, "package.json")
|
|
5638
7130
|
);
|
|
5639
7131
|
pkgPath = projectRequire.resolve(`${pkg.name}/package.json`);
|
|
5640
7132
|
} catch (resolveError) {
|
|
5641
|
-
pkgPath =
|
|
7133
|
+
pkgPath = import_node_path12.default.join(__dirname, pkg.relativePath);
|
|
5642
7134
|
}
|
|
5643
7135
|
} else {
|
|
5644
|
-
pkgPath =
|
|
7136
|
+
pkgPath = import_node_path12.default.join(__dirname, pkg.relativePath);
|
|
5645
7137
|
}
|
|
5646
|
-
const pkgContent = (0,
|
|
7138
|
+
const pkgContent = (0, import_node_fs14.readFileSync)(pkgPath, "utf-8");
|
|
5647
7139
|
const pkgJson = JSON.parse(pkgContent);
|
|
5648
7140
|
const version = pkgJson.version || "unknown";
|
|
5649
7141
|
if (pkg.highlight) {
|
|
@@ -5698,7 +7190,7 @@ function normalizeBrowserHost(host) {
|
|
|
5698
7190
|
return host === "0.0.0.0" ? "localhost" : host;
|
|
5699
7191
|
}
|
|
5700
7192
|
function runCommand(command, args, cwd, env2, filterStderr = false) {
|
|
5701
|
-
const proc = (0,
|
|
7193
|
+
const proc = (0, import_node_child_process11.spawn)(command, args, {
|
|
5702
7194
|
cwd,
|
|
5703
7195
|
stdio: filterStderr ? ["inherit", "inherit", "pipe"] : "inherit",
|
|
5704
7196
|
shell: process.platform === "win32",
|
|
@@ -5731,7 +7223,7 @@ async function startTunnel(port, subdomain) {
|
|
|
5731
7223
|
if (subdomain) {
|
|
5732
7224
|
tunnelArgs.push("--subdomain", subdomain);
|
|
5733
7225
|
}
|
|
5734
|
-
const proc = (0,
|
|
7226
|
+
const proc = (0, import_node_child_process11.spawn)("npx", tunnelArgs, {
|
|
5735
7227
|
stdio: ["ignore", "pipe", "pipe"],
|
|
5736
7228
|
shell: process.platform === "win32"
|
|
5737
7229
|
});
|
|
@@ -5795,21 +7287,21 @@ async function startTunnel(port, subdomain) {
|
|
|
5795
7287
|
}
|
|
5796
7288
|
async function resolveEntryFile(projectPath, cliEntry, mcpDir) {
|
|
5797
7289
|
if (cliEntry) {
|
|
5798
|
-
await (0,
|
|
7290
|
+
await (0, import_promises8.access)(import_node_path12.default.join(projectPath, cliEntry)).catch(() => {
|
|
5799
7291
|
throw new Error(`File not found: ${cliEntry}`);
|
|
5800
7292
|
});
|
|
5801
7293
|
return cliEntry;
|
|
5802
7294
|
}
|
|
5803
7295
|
if (mcpDir) {
|
|
5804
7296
|
const mcpCandidates = [
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
|
|
7297
|
+
import_node_path12.default.join(mcpDir, "index.ts"),
|
|
7298
|
+
import_node_path12.default.join(mcpDir, "index.tsx"),
|
|
7299
|
+
import_node_path12.default.join(mcpDir, "server.ts"),
|
|
7300
|
+
import_node_path12.default.join(mcpDir, "server.tsx")
|
|
5809
7301
|
];
|
|
5810
7302
|
for (const candidate of mcpCandidates) {
|
|
5811
7303
|
try {
|
|
5812
|
-
await (0,
|
|
7304
|
+
await (0, import_promises8.access)(import_node_path12.default.join(projectPath, candidate));
|
|
5813
7305
|
return candidate;
|
|
5814
7306
|
} catch {
|
|
5815
7307
|
continue;
|
|
@@ -5818,17 +7310,17 @@ async function resolveEntryFile(projectPath, cliEntry, mcpDir) {
|
|
|
5818
7310
|
throw new Error(
|
|
5819
7311
|
`No entry file found inside ${mcpDir}.
|
|
5820
7312
|
|
|
5821
|
-
Expected one of: ${mcpCandidates.map((c) =>
|
|
7313
|
+
Expected one of: ${mcpCandidates.map((c) => import_node_path12.default.relative(projectPath, import_node_path12.default.join(projectPath, c))).join(", ")}
|
|
5822
7314
|
|
|
5823
7315
|
Fix this by either:
|
|
5824
|
-
1. Creating ${
|
|
7316
|
+
1. Creating ${import_node_path12.default.join(mcpDir, "index.ts")}, or
|
|
5825
7317
|
2. Passing --entry <file> on the command line`
|
|
5826
7318
|
);
|
|
5827
7319
|
}
|
|
5828
7320
|
const candidates = ["index.ts", "src/index.ts", "server.ts", "src/server.ts"];
|
|
5829
7321
|
for (const candidate of candidates) {
|
|
5830
7322
|
try {
|
|
5831
|
-
await (0,
|
|
7323
|
+
await (0, import_promises8.access)(import_node_path12.default.join(projectPath, candidate));
|
|
5832
7324
|
return candidate;
|
|
5833
7325
|
} catch {
|
|
5834
7326
|
continue;
|
|
@@ -5846,7 +7338,7 @@ Fix this by either:
|
|
|
5846
7338
|
}
|
|
5847
7339
|
function resolveWidgetsDir(cliWidgetsDir, mcpDir) {
|
|
5848
7340
|
if (cliWidgetsDir) return cliWidgetsDir;
|
|
5849
|
-
if (mcpDir) return
|
|
7341
|
+
if (mcpDir) return import_node_path12.default.join(mcpDir, "resources");
|
|
5850
7342
|
return "resources";
|
|
5851
7343
|
}
|
|
5852
7344
|
function makeWidgetServerOnlyGuard(widgetName) {
|
|
@@ -5881,8 +7373,8 @@ function isBunRuntime() {
|
|
|
5881
7373
|
return typeof globalThis.Bun !== "undefined" || typeof process.versions.bun === "string";
|
|
5882
7374
|
}
|
|
5883
7375
|
async function generateToolRegistryTypesForServer(projectPath, serverFileRelative) {
|
|
5884
|
-
const serverFile =
|
|
5885
|
-
const serverFileExists = await (0,
|
|
7376
|
+
const serverFile = import_node_path12.default.join(projectPath, serverFileRelative);
|
|
7377
|
+
const serverFileExists = await (0, import_promises8.access)(serverFile).then(() => true).catch(() => false);
|
|
5886
7378
|
if (!serverFileExists) {
|
|
5887
7379
|
throw new Error(`Server file not found: ${serverFile}`);
|
|
5888
7380
|
}
|
|
@@ -5907,8 +7399,8 @@ async function generateToolRegistryTypesForServer(projectPath, serverFileRelativ
|
|
|
5907
7399
|
await loadNextJsEnvFiles(projectPath);
|
|
5908
7400
|
await registerNextShimsInProcess();
|
|
5909
7401
|
}
|
|
5910
|
-
const projectTsconfigPath =
|
|
5911
|
-
const hasTsconfig = await (0,
|
|
7402
|
+
const projectTsconfigPath = import_node_path12.default.join(projectPath, "tsconfig.json");
|
|
7403
|
+
const hasTsconfig = await (0, import_promises8.access)(projectTsconfigPath).then(() => true).catch(() => false);
|
|
5912
7404
|
if (hasTsconfig) {
|
|
5913
7405
|
process.env.TSX_TSCONFIG_PATH = projectTsconfigPath;
|
|
5914
7406
|
}
|
|
@@ -5916,7 +7408,7 @@ async function generateToolRegistryTypesForServer(projectPath, serverFileRelativ
|
|
|
5916
7408
|
if (previousCwd !== projectPath) process.chdir(projectPath);
|
|
5917
7409
|
try {
|
|
5918
7410
|
const projectRequire = (0, import_node_module2.createRequire)(
|
|
5919
|
-
|
|
7411
|
+
import_node_path12.default.join(projectPath, "package.json")
|
|
5920
7412
|
);
|
|
5921
7413
|
const tsxEsmApiPath = projectRequire.resolve("tsx/esm/api");
|
|
5922
7414
|
const tsxEsmApi = await import((0, import_node_url3.pathToFileURL)(tsxEsmApiPath).href);
|
|
@@ -5943,8 +7435,8 @@ async function generateToolRegistryTypesForServer(projectPath, serverFileRelativ
|
|
|
5943
7435
|
"No MCPServer instance found. Make sure your server file creates an MCPServer instance."
|
|
5944
7436
|
);
|
|
5945
7437
|
}
|
|
5946
|
-
const mcpUsePath =
|
|
5947
|
-
const { generateToolRegistryTypes } = await import((0, import_node_url3.pathToFileURL)(
|
|
7438
|
+
const mcpUsePath = import_node_path12.default.join(projectPath, "node_modules", "mcp-use");
|
|
7439
|
+
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
7440
|
if (!generateToolRegistryTypes) {
|
|
5949
7441
|
throw new Error("generateToolRegistryTypes not found in mcp-use package");
|
|
5950
7442
|
}
|
|
@@ -5962,10 +7454,10 @@ async function buildWidgets(projectPath, options = {}) {
|
|
|
5962
7454
|
const { promises: fs11 } = await import("fs");
|
|
5963
7455
|
const { build } = await import("vite");
|
|
5964
7456
|
const widgetsDirRelative = options.widgetsDir ?? "resources";
|
|
5965
|
-
const resourcesDir =
|
|
7457
|
+
const resourcesDir = import_node_path12.default.resolve(projectPath, widgetsDirRelative);
|
|
5966
7458
|
const mcpUrl = process.env.MCP_URL;
|
|
5967
7459
|
try {
|
|
5968
|
-
await (0,
|
|
7460
|
+
await (0, import_promises8.access)(resourcesDir);
|
|
5969
7461
|
} catch {
|
|
5970
7462
|
console.log(
|
|
5971
7463
|
source_default.gray(
|
|
@@ -5984,10 +7476,10 @@ async function buildWidgets(projectPath, options = {}) {
|
|
|
5984
7476
|
if (dirent.isFile() && (dirent.name.endsWith(".tsx") || dirent.name.endsWith(".ts"))) {
|
|
5985
7477
|
entries.push({
|
|
5986
7478
|
name: dirent.name.replace(/\.tsx?$/, ""),
|
|
5987
|
-
path:
|
|
7479
|
+
path: import_node_path12.default.join(resourcesDir, dirent.name)
|
|
5988
7480
|
});
|
|
5989
7481
|
} else if (dirent.isDirectory()) {
|
|
5990
|
-
const widgetPath =
|
|
7482
|
+
const widgetPath = import_node_path12.default.join(resourcesDir, dirent.name, "widget.tsx");
|
|
5991
7483
|
try {
|
|
5992
7484
|
await fs11.access(widgetPath);
|
|
5993
7485
|
entries.push({
|
|
@@ -6017,14 +7509,14 @@ async function buildWidgets(projectPath, options = {}) {
|
|
|
6017
7509
|
);
|
|
6018
7510
|
const react = (await import("@vitejs/plugin-react")).default;
|
|
6019
7511
|
const tailwindcss = (await import("@tailwindcss/vite")).default;
|
|
6020
|
-
const projectTsconfigPath =
|
|
7512
|
+
const projectTsconfigPath = import_node_path12.default.join(projectPath, "tsconfig.json");
|
|
6021
7513
|
let hasProjectTsconfig = false;
|
|
6022
7514
|
try {
|
|
6023
|
-
await (0,
|
|
7515
|
+
await (0, import_promises8.access)(projectTsconfigPath);
|
|
6024
7516
|
hasProjectTsconfig = true;
|
|
6025
7517
|
} catch {
|
|
6026
7518
|
}
|
|
6027
|
-
const packageJsonPath =
|
|
7519
|
+
const packageJsonPath = import_node_path12.default.join(projectPath, "package.json");
|
|
6028
7520
|
let favicon = "";
|
|
6029
7521
|
try {
|
|
6030
7522
|
const pkgContent = await fs11.readFile(packageJsonPath, "utf-8");
|
|
@@ -6036,16 +7528,16 @@ async function buildWidgets(projectPath, options = {}) {
|
|
|
6036
7528
|
const widgetName = entry.name;
|
|
6037
7529
|
const entryPath = entry.path.replace(/\\/g, "/");
|
|
6038
7530
|
console.log(source_default.gray(` - Building ${widgetName}...`));
|
|
6039
|
-
const tempDir =
|
|
7531
|
+
const tempDir = import_node_path12.default.join(projectPath, ".mcp-use", widgetName);
|
|
6040
7532
|
await fs11.mkdir(tempDir, { recursive: true });
|
|
6041
|
-
const relativeResourcesPath =
|
|
6042
|
-
const mcpUsePath =
|
|
6043
|
-
const relativeMcpUsePath =
|
|
6044
|
-
const projectSrcDir =
|
|
7533
|
+
const relativeResourcesPath = import_node_path12.default.relative(tempDir, resourcesDir).replace(/\\/g, "/");
|
|
7534
|
+
const mcpUsePath = import_node_path12.default.join(projectPath, "node_modules", "mcp-use");
|
|
7535
|
+
const relativeMcpUsePath = import_node_path12.default.relative(tempDir, mcpUsePath).replace(/\\/g, "/");
|
|
7536
|
+
const projectSrcDir = import_node_path12.default.join(projectPath, "src");
|
|
6045
7537
|
let projectSrcSourceLine = "";
|
|
6046
7538
|
try {
|
|
6047
|
-
await (0,
|
|
6048
|
-
const relativeProjectSrcPath =
|
|
7539
|
+
await (0, import_promises8.access)(projectSrcDir);
|
|
7540
|
+
const relativeProjectSrcPath = import_node_path12.default.relative(tempDir, projectSrcDir).replace(/\\/g, "/");
|
|
6049
7541
|
projectSrcSourceLine = `@source "${relativeProjectSrcPath}";
|
|
6050
7542
|
`;
|
|
6051
7543
|
} catch {
|
|
@@ -6056,7 +7548,7 @@ async function buildWidgets(projectPath, options = {}) {
|
|
|
6056
7548
|
@source "${relativeResourcesPath}";
|
|
6057
7549
|
@source "${relativeMcpUsePath}/**/*.{ts,tsx,js,jsx}";
|
|
6058
7550
|
${projectSrcSourceLine}`;
|
|
6059
|
-
await fs11.writeFile(
|
|
7551
|
+
await fs11.writeFile(import_node_path12.default.join(tempDir, "styles.css"), cssContent, "utf8");
|
|
6060
7552
|
const entryContent = `import React from 'react'
|
|
6061
7553
|
import { createRoot } from 'react-dom/client'
|
|
6062
7554
|
import './styles.css'
|
|
@@ -6081,9 +7573,9 @@ if (container && Component) {
|
|
|
6081
7573
|
<script type="module" src="/entry.tsx"></script>
|
|
6082
7574
|
</body>
|
|
6083
7575
|
</html>`;
|
|
6084
|
-
await fs11.writeFile(
|
|
6085
|
-
await fs11.writeFile(
|
|
6086
|
-
const outDir =
|
|
7576
|
+
await fs11.writeFile(import_node_path12.default.join(tempDir, "entry.tsx"), entryContent, "utf8");
|
|
7577
|
+
await fs11.writeFile(import_node_path12.default.join(tempDir, "index.html"), htmlContent, "utf8");
|
|
7578
|
+
const outDir = import_node_path12.default.join(
|
|
6087
7579
|
projectPath,
|
|
6088
7580
|
"dist",
|
|
6089
7581
|
"resources",
|
|
@@ -6093,13 +7585,13 @@ if (container && Component) {
|
|
|
6093
7585
|
const baseUrl = mcpUrl ? `${mcpUrl}/${widgetName}/` : `/mcp-use/widgets/${widgetName}/`;
|
|
6094
7586
|
let widgetMetadata = {};
|
|
6095
7587
|
try {
|
|
6096
|
-
const metadataTempDir =
|
|
7588
|
+
const metadataTempDir = import_node_path12.default.join(
|
|
6097
7589
|
projectPath,
|
|
6098
7590
|
".mcp-use",
|
|
6099
7591
|
`${widgetName}-metadata`
|
|
6100
7592
|
);
|
|
6101
7593
|
await fs11.mkdir(metadataTempDir, { recursive: true });
|
|
6102
|
-
const { createServer } = await import("vite");
|
|
7594
|
+
const { createServer: createServer2 } = await import("vite");
|
|
6103
7595
|
const nodeStubsPlugin = {
|
|
6104
7596
|
name: "node-stubs",
|
|
6105
7597
|
enforce: "pre",
|
|
@@ -6127,9 +7619,9 @@ export default PostHog;
|
|
|
6127
7619
|
}
|
|
6128
7620
|
};
|
|
6129
7621
|
const serverOnlyGuard = makeWidgetServerOnlyGuard(widgetName);
|
|
6130
|
-
const metadataServer = await
|
|
7622
|
+
const metadataServer = await createServer2({
|
|
6131
7623
|
root: metadataTempDir,
|
|
6132
|
-
cacheDir:
|
|
7624
|
+
cacheDir: import_node_path12.default.join(metadataTempDir, ".vite-cache"),
|
|
6133
7625
|
plugins: [serverOnlyGuard, nodeStubsPlugin, tailwindcss(), react()],
|
|
6134
7626
|
// When the project has a tsconfig, enable Vite's native tsconfig-paths
|
|
6135
7627
|
// resolver so `@/*` (or any custom alias) resolves through the
|
|
@@ -6360,7 +7852,7 @@ export default {
|
|
|
6360
7852
|
// Inline all assets under 100MB (effectively all)
|
|
6361
7853
|
} : {},
|
|
6362
7854
|
rolldownOptions: {
|
|
6363
|
-
input:
|
|
7855
|
+
input: import_node_path12.default.join(tempDir, "index.html"),
|
|
6364
7856
|
external: (id) => {
|
|
6365
7857
|
return false;
|
|
6366
7858
|
}
|
|
@@ -6368,11 +7860,11 @@ export default {
|
|
|
6368
7860
|
}
|
|
6369
7861
|
});
|
|
6370
7862
|
try {
|
|
6371
|
-
const assetsDir =
|
|
7863
|
+
const assetsDir = import_node_path12.default.join(outDir, "assets");
|
|
6372
7864
|
const assetFiles = await fs11.readdir(assetsDir);
|
|
6373
7865
|
const jsFiles = assetFiles.filter((f) => f.endsWith(".js"));
|
|
6374
7866
|
for (const jsFile of jsFiles) {
|
|
6375
|
-
const jsPath =
|
|
7867
|
+
const jsPath = import_node_path12.default.join(assetsDir, jsFile);
|
|
6376
7868
|
let content = await fs11.readFile(jsPath, "utf8");
|
|
6377
7869
|
const zodConfigPatterns = [
|
|
6378
7870
|
// Non-minified: export const globalConfig = {}
|
|
@@ -6404,7 +7896,7 @@ export default {
|
|
|
6404
7896
|
const mcpServerUrl = process.env.MCP_SERVER_URL;
|
|
6405
7897
|
if (mcpServerUrl) {
|
|
6406
7898
|
try {
|
|
6407
|
-
const htmlPath =
|
|
7899
|
+
const htmlPath = import_node_path12.default.join(outDir, "index.html");
|
|
6408
7900
|
let html = await fs11.readFile(htmlPath, "utf8");
|
|
6409
7901
|
const injectionScript = `<script>window.__getFile = (filename) => { return "${mcpUrl}/${widgetName}/"+filename }; window.__mcpPublicUrl = "${mcpServerUrl}/mcp-use/public"; window.__mcpPublicAssetsUrl = "${mcpUrl}/public";</script>`;
|
|
6410
7902
|
if (!html.includes("window.__mcpPublicUrl")) {
|
|
@@ -6480,7 +7972,7 @@ async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
|
|
|
6480
7972
|
for (const file of literalFiles) {
|
|
6481
7973
|
if (/\.tsx?$/.test(file) && !file.endsWith(".d.ts")) {
|
|
6482
7974
|
try {
|
|
6483
|
-
await (0,
|
|
7975
|
+
await (0, import_promises8.access)(import_node_path12.default.join(projectPath, file));
|
|
6484
7976
|
files.push(file);
|
|
6485
7977
|
} catch {
|
|
6486
7978
|
}
|
|
@@ -6488,13 +7980,13 @@ async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
|
|
|
6488
7980
|
}
|
|
6489
7981
|
const excludeSet = new Set(excludePatterns.map((e) => e.replace(/\*+/g, "")));
|
|
6490
7982
|
for (const prefix of dirPrefixes) {
|
|
6491
|
-
const dirPath =
|
|
7983
|
+
const dirPath = import_node_path12.default.join(projectPath, prefix);
|
|
6492
7984
|
try {
|
|
6493
7985
|
const entries = await fs11.readdir(dirPath, { recursive: true });
|
|
6494
7986
|
for (const entry of entries) {
|
|
6495
7987
|
const entryStr = String(entry);
|
|
6496
|
-
const rel =
|
|
6497
|
-
if (/\.tsx?$/.test(entryStr) && !entryStr.endsWith(".d.ts") && !excludeSet.has(rel.split(
|
|
7988
|
+
const rel = import_node_path12.default.join(prefix, entryStr);
|
|
7989
|
+
if (/\.tsx?$/.test(entryStr) && !entryStr.endsWith(".d.ts") && !excludeSet.has(rel.split(import_node_path12.default.sep)[0])) {
|
|
6498
7990
|
files.push(rel);
|
|
6499
7991
|
}
|
|
6500
7992
|
}
|
|
@@ -6506,7 +7998,7 @@ async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
|
|
|
6506
7998
|
async function transpileWithEsbuild(projectPath) {
|
|
6507
7999
|
const esbuild = await import("esbuild");
|
|
6508
8000
|
const { promises: fs11 } = await import("fs");
|
|
6509
|
-
const tsconfigPath =
|
|
8001
|
+
const tsconfigPath = import_node_path12.default.join(projectPath, "tsconfig.json");
|
|
6510
8002
|
let tsconfig = {};
|
|
6511
8003
|
try {
|
|
6512
8004
|
const raw = await fs11.readFile(tsconfigPath, "utf-8");
|
|
@@ -6536,10 +8028,10 @@ async function transpileWithEsbuild(projectPath) {
|
|
|
6536
8028
|
const target = (compilerOptions.target || "ES2022").toLowerCase();
|
|
6537
8029
|
const moduleStr = (compilerOptions.module || "ESNext").toLowerCase();
|
|
6538
8030
|
const format = moduleStr.includes("commonjs") ? "cjs" : "esm";
|
|
6539
|
-
const outbase = compilerOptions.rootDir ?
|
|
8031
|
+
const outbase = compilerOptions.rootDir ? import_node_path12.default.resolve(projectPath, compilerOptions.rootDir) : projectPath;
|
|
6540
8032
|
await esbuild.build({
|
|
6541
|
-
entryPoints: files.map((f) =>
|
|
6542
|
-
outdir:
|
|
8033
|
+
entryPoints: files.map((f) => import_node_path12.default.join(projectPath, f)),
|
|
8034
|
+
outdir: import_node_path12.default.join(projectPath, outDir),
|
|
6543
8035
|
outbase,
|
|
6544
8036
|
bundle: true,
|
|
6545
8037
|
packages: "external",
|
|
@@ -6566,7 +8058,7 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
6566
8058
|
"Inline all JS/CSS into HTML (required for VS Code MCP Apps)"
|
|
6567
8059
|
).option("--no-inline", "Keep JS/CSS as separate files (default)").option("--no-typecheck", "Skip TypeScript type checking (faster builds)").action(async (options) => {
|
|
6568
8060
|
try {
|
|
6569
|
-
const projectPath =
|
|
8061
|
+
const projectPath = import_node_path12.default.resolve(options.path);
|
|
6570
8062
|
const { promises: fs11 } = await import("fs");
|
|
6571
8063
|
displayPackageVersions(projectPath);
|
|
6572
8064
|
const mcpDir = options.mcpDir;
|
|
@@ -6626,7 +8118,7 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
6626
8118
|
}
|
|
6627
8119
|
if (options.typecheck !== false && !mcpDir) {
|
|
6628
8120
|
console.log(source_default.gray("Type checking..."));
|
|
6629
|
-
const tscBin =
|
|
8121
|
+
const tscBin = import_node_path12.default.join(
|
|
6630
8122
|
projectPath,
|
|
6631
8123
|
"node_modules",
|
|
6632
8124
|
"typescript",
|
|
@@ -6649,7 +8141,7 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
6649
8141
|
if (mcpDir) {
|
|
6650
8142
|
entryPoint = sourceServerFile;
|
|
6651
8143
|
} else {
|
|
6652
|
-
const baseName =
|
|
8144
|
+
const baseName = import_node_path12.default.basename(sourceServerFile, ".ts") + ".js";
|
|
6653
8145
|
const possibleOutputs = [
|
|
6654
8146
|
`dist/${baseName}`,
|
|
6655
8147
|
// rootDir set to project root or src
|
|
@@ -6660,7 +8152,7 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
6660
8152
|
];
|
|
6661
8153
|
for (const candidate of possibleOutputs) {
|
|
6662
8154
|
try {
|
|
6663
|
-
await (0,
|
|
8155
|
+
await (0, import_promises8.access)(import_node_path12.default.join(projectPath, candidate));
|
|
6664
8156
|
entryPoint = candidate;
|
|
6665
8157
|
break;
|
|
6666
8158
|
} catch {
|
|
@@ -6669,17 +8161,17 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
6669
8161
|
}
|
|
6670
8162
|
}
|
|
6671
8163
|
}
|
|
6672
|
-
const publicDir =
|
|
8164
|
+
const publicDir = import_node_path12.default.join(projectPath, "public");
|
|
6673
8165
|
try {
|
|
6674
8166
|
await fs11.access(publicDir);
|
|
6675
8167
|
console.log(source_default.gray("Copying public assets..."));
|
|
6676
|
-
await fs11.cp(publicDir,
|
|
8168
|
+
await fs11.cp(publicDir, import_node_path12.default.join(projectPath, "dist", "public"), {
|
|
6677
8169
|
recursive: true
|
|
6678
8170
|
});
|
|
6679
8171
|
console.log(source_default.green("\u2713 Public assets copied"));
|
|
6680
8172
|
} catch {
|
|
6681
8173
|
}
|
|
6682
|
-
const manifestPath =
|
|
8174
|
+
const manifestPath = import_node_path12.default.join(projectPath, "dist", "mcp-use.json");
|
|
6683
8175
|
let existingManifest = {};
|
|
6684
8176
|
try {
|
|
6685
8177
|
const existingContent = await fs11.readFile(manifestPath, "utf-8");
|
|
@@ -6704,7 +8196,7 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
6704
8196
|
// Server entry point for `mcp-use start`
|
|
6705
8197
|
widgets: widgetsData
|
|
6706
8198
|
};
|
|
6707
|
-
await fs11.mkdir(
|
|
8199
|
+
await fs11.mkdir(import_node_path12.default.dirname(manifestPath), { recursive: true });
|
|
6708
8200
|
await fs11.writeFile(
|
|
6709
8201
|
manifestPath,
|
|
6710
8202
|
JSON.stringify(manifest, null, 2),
|
|
@@ -6741,7 +8233,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6741
8233
|
).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
8234
|
try {
|
|
6743
8235
|
process.env.MCP_USE_CLI_DEV = "1";
|
|
6744
|
-
const projectPath =
|
|
8236
|
+
const projectPath = import_node_path12.default.resolve(options.path);
|
|
6745
8237
|
let port = parseInt(options.port, 10);
|
|
6746
8238
|
const host = options.host;
|
|
6747
8239
|
const useHmr = options.hmr !== false;
|
|
@@ -6769,10 +8261,10 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6769
8261
|
let tunnelUrl = void 0;
|
|
6770
8262
|
if (options.tunnel) {
|
|
6771
8263
|
try {
|
|
6772
|
-
const manifestPath =
|
|
8264
|
+
const manifestPath = import_node_path12.default.join(projectPath, "dist", "mcp-use.json");
|
|
6773
8265
|
let existingSubdomain;
|
|
6774
8266
|
try {
|
|
6775
|
-
const manifestContent = await (0,
|
|
8267
|
+
const manifestContent = await (0, import_promises8.readFile)(manifestPath, "utf-8");
|
|
6776
8268
|
const manifest = JSON.parse(manifestContent);
|
|
6777
8269
|
existingSubdomain = manifest.tunnel?.subdomain;
|
|
6778
8270
|
if (existingSubdomain) {
|
|
@@ -6810,7 +8302,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6810
8302
|
try {
|
|
6811
8303
|
let manifest = {};
|
|
6812
8304
|
try {
|
|
6813
|
-
const manifestContent = await (0,
|
|
8305
|
+
const manifestContent = await (0, import_promises8.readFile)(manifestPath, "utf-8");
|
|
6814
8306
|
manifest = JSON.parse(manifestContent);
|
|
6815
8307
|
} catch {
|
|
6816
8308
|
}
|
|
@@ -6818,8 +8310,8 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6818
8310
|
manifest.tunnel = {};
|
|
6819
8311
|
}
|
|
6820
8312
|
manifest.tunnel.subdomain = tunnelSubdomain;
|
|
6821
|
-
await (0,
|
|
6822
|
-
await (0,
|
|
8313
|
+
await (0, import_promises8.mkdir)(import_node_path12.default.dirname(manifestPath), { recursive: true });
|
|
8314
|
+
await (0, import_promises8.writeFile)(
|
|
6823
8315
|
manifestPath,
|
|
6824
8316
|
JSON.stringify(manifest, null, 2),
|
|
6825
8317
|
"utf-8"
|
|
@@ -6873,10 +8365,10 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6873
8365
|
let args;
|
|
6874
8366
|
try {
|
|
6875
8367
|
const projectRequire = createRequire4(
|
|
6876
|
-
|
|
8368
|
+
import_node_path12.default.join(projectPath, "package.json")
|
|
6877
8369
|
);
|
|
6878
8370
|
const tsxPkgPath = projectRequire.resolve("tsx/package.json");
|
|
6879
|
-
const tsxPkg = JSON.parse(await (0,
|
|
8371
|
+
const tsxPkg = JSON.parse(await (0, import_promises8.readFile)(tsxPkgPath, "utf-8"));
|
|
6880
8372
|
let binPath;
|
|
6881
8373
|
if (typeof tsxPkg.bin === "string") {
|
|
6882
8374
|
binPath = tsxPkg.bin;
|
|
@@ -6885,7 +8377,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6885
8377
|
} else {
|
|
6886
8378
|
throw new Error("No bin field found in tsx package.json");
|
|
6887
8379
|
}
|
|
6888
|
-
const tsxBin =
|
|
8380
|
+
const tsxBin = import_node_path12.default.resolve(import_node_path12.default.dirname(tsxPkgPath), binPath);
|
|
6889
8381
|
cmd = "node";
|
|
6890
8382
|
args = [tsxBin, "watch", serverFile];
|
|
6891
8383
|
} catch (error) {
|
|
@@ -6974,10 +8466,10 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6974
8466
|
const chokidar = chokidarModule.default || chokidarModule;
|
|
6975
8467
|
const { fileURLToPath: fileURLToPath3 } = await import("url");
|
|
6976
8468
|
const { createRequire: createRequire3 } = await import("module");
|
|
6977
|
-
const projectTsconfigPath =
|
|
8469
|
+
const projectTsconfigPath = import_node_path12.default.join(projectPath, "tsconfig.json");
|
|
6978
8470
|
let tsconfigAvailable = false;
|
|
6979
8471
|
try {
|
|
6980
|
-
await (0,
|
|
8472
|
+
await (0, import_promises8.access)(projectTsconfigPath);
|
|
6981
8473
|
tsconfigAvailable = true;
|
|
6982
8474
|
process.env.TSX_TSCONFIG_PATH = projectTsconfigPath;
|
|
6983
8475
|
if (process.cwd() !== projectPath) process.chdir(projectPath);
|
|
@@ -6986,7 +8478,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6986
8478
|
let tsxLoaderActive = false;
|
|
6987
8479
|
try {
|
|
6988
8480
|
const projectRequire = createRequire3(
|
|
6989
|
-
|
|
8481
|
+
import_node_path12.default.join(projectPath, "package.json")
|
|
6990
8482
|
);
|
|
6991
8483
|
const tsxEsmApiPath = projectRequire.resolve("tsx/esm/api");
|
|
6992
8484
|
const tsxEsmApi = await import((0, import_node_url3.pathToFileURL)(tsxEsmApiPath).href);
|
|
@@ -7017,7 +8509,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
7017
8509
|
)
|
|
7018
8510
|
);
|
|
7019
8511
|
}
|
|
7020
|
-
const serverFilePath =
|
|
8512
|
+
const serverFilePath = import_node_path12.default.join(projectPath, serverFile);
|
|
7021
8513
|
const serverFileUrl = (0, import_node_url3.pathToFileURL)(serverFilePath).href;
|
|
7022
8514
|
globalThis.__mcpUseHmrMode = true;
|
|
7023
8515
|
const importServerModule = async () => {
|
|
@@ -7114,8 +8606,8 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
7114
8606
|
}
|
|
7115
8607
|
let watcher = chokidar.watch(".", {
|
|
7116
8608
|
cwd: projectPath,
|
|
7117
|
-
ignored: (
|
|
7118
|
-
const normalizedPath =
|
|
8609
|
+
ignored: (path11, stats) => {
|
|
8610
|
+
const normalizedPath = path11.replace(/\\/g, "/");
|
|
7119
8611
|
if (/(^|\/)\.[^/]/.test(normalizedPath)) {
|
|
7120
8612
|
return true;
|
|
7121
8613
|
}
|
|
@@ -7289,10 +8781,10 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
7289
8781
|
}
|
|
7290
8782
|
tunnelUrl = void 0;
|
|
7291
8783
|
if (withTunnel) {
|
|
7292
|
-
const manifestPath =
|
|
8784
|
+
const manifestPath = import_node_path12.default.join(projectPath, "dist", "mcp-use.json");
|
|
7293
8785
|
let existingSubdomain;
|
|
7294
8786
|
try {
|
|
7295
|
-
const manifestContent = await (0,
|
|
8787
|
+
const manifestContent = await (0, import_promises8.readFile)(manifestPath, "utf-8");
|
|
7296
8788
|
const manifest = JSON.parse(manifestContent);
|
|
7297
8789
|
existingSubdomain = manifest.tunnel?.subdomain;
|
|
7298
8790
|
if (existingSubdomain) {
|
|
@@ -7326,16 +8818,16 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
7326
8818
|
tunnelSubdomain = tunnelInfo.subdomain;
|
|
7327
8819
|
process.env.MCP_URL = tunnelUrl;
|
|
7328
8820
|
try {
|
|
7329
|
-
const mPath =
|
|
8821
|
+
const mPath = import_node_path12.default.join(projectPath, "dist", "mcp-use.json");
|
|
7330
8822
|
let manifest = {};
|
|
7331
8823
|
try {
|
|
7332
|
-
manifest = JSON.parse(await (0,
|
|
8824
|
+
manifest = JSON.parse(await (0, import_promises8.readFile)(mPath, "utf-8"));
|
|
7333
8825
|
} catch {
|
|
7334
8826
|
}
|
|
7335
8827
|
if (!manifest.tunnel) manifest.tunnel = {};
|
|
7336
8828
|
manifest.tunnel.subdomain = tunnelSubdomain;
|
|
7337
|
-
await (0,
|
|
7338
|
-
await (0,
|
|
8829
|
+
await (0, import_promises8.mkdir)(import_node_path12.default.dirname(mPath), { recursive: true });
|
|
8830
|
+
await (0, import_promises8.writeFile)(mPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
7339
8831
|
} catch {
|
|
7340
8832
|
}
|
|
7341
8833
|
} else {
|
|
@@ -7438,7 +8930,7 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
7438
8930
|
"Folder holding the MCP entry + resources (e.g. 'src/mcp' for Next.js apps)"
|
|
7439
8931
|
).option("--port <port>", "Server port", "3000").option("--tunnel", "Expose server through a tunnel").action(async (options) => {
|
|
7440
8932
|
try {
|
|
7441
|
-
const projectPath =
|
|
8933
|
+
const projectPath = import_node_path12.default.resolve(options.path);
|
|
7442
8934
|
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
8935
|
let port = portFlagProvided ? parseInt(options.port, 10) : parseInt(process.env.PORT || options.port || "3000", 10);
|
|
7444
8936
|
if (!await isPortAvailable(port)) {
|
|
@@ -7456,10 +8948,10 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
7456
8948
|
let tunnelSubdomain = void 0;
|
|
7457
8949
|
if (options.tunnel) {
|
|
7458
8950
|
try {
|
|
7459
|
-
const manifestPath2 =
|
|
8951
|
+
const manifestPath2 = import_node_path12.default.join(projectPath, "dist", "mcp-use.json");
|
|
7460
8952
|
let existingSubdomain;
|
|
7461
8953
|
try {
|
|
7462
|
-
const manifestContent = await (0,
|
|
8954
|
+
const manifestContent = await (0, import_promises8.readFile)(manifestPath2, "utf-8");
|
|
7463
8955
|
const manifest = JSON.parse(manifestContent);
|
|
7464
8956
|
existingSubdomain = manifest.tunnel?.subdomain;
|
|
7465
8957
|
if (existingSubdomain) {
|
|
@@ -7503,7 +8995,7 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
7503
8995
|
try {
|
|
7504
8996
|
let manifest = {};
|
|
7505
8997
|
try {
|
|
7506
|
-
const manifestContent = await (0,
|
|
8998
|
+
const manifestContent = await (0, import_promises8.readFile)(manifestPath2, "utf-8");
|
|
7507
8999
|
manifest = JSON.parse(manifestContent);
|
|
7508
9000
|
} catch {
|
|
7509
9001
|
}
|
|
@@ -7511,8 +9003,8 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
7511
9003
|
manifest.tunnel = {};
|
|
7512
9004
|
}
|
|
7513
9005
|
manifest.tunnel.subdomain = subdomain;
|
|
7514
|
-
await (0,
|
|
7515
|
-
await (0,
|
|
9006
|
+
await (0, import_promises8.mkdir)(import_node_path12.default.dirname(manifestPath2), { recursive: true });
|
|
9007
|
+
await (0, import_promises8.writeFile)(
|
|
7516
9008
|
manifestPath2,
|
|
7517
9009
|
JSON.stringify(manifest, null, 2),
|
|
7518
9010
|
"utf-8"
|
|
@@ -7530,12 +9022,12 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
7530
9022
|
}
|
|
7531
9023
|
}
|
|
7532
9024
|
let serverFile;
|
|
7533
|
-
const manifestPath =
|
|
9025
|
+
const manifestPath = import_node_path12.default.join(projectPath, "dist", "mcp-use.json");
|
|
7534
9026
|
try {
|
|
7535
|
-
const manifestContent = await (0,
|
|
9027
|
+
const manifestContent = await (0, import_promises8.readFile)(manifestPath, "utf-8");
|
|
7536
9028
|
const manifest = JSON.parse(manifestContent);
|
|
7537
9029
|
if (manifest.entryPoint) {
|
|
7538
|
-
await (0,
|
|
9030
|
+
await (0, import_promises8.access)(import_node_path12.default.join(projectPath, manifest.entryPoint));
|
|
7539
9031
|
serverFile = manifest.entryPoint;
|
|
7540
9032
|
}
|
|
7541
9033
|
} catch {
|
|
@@ -7556,7 +9048,7 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
7556
9048
|
];
|
|
7557
9049
|
for (const candidate of serverCandidates) {
|
|
7558
9050
|
try {
|
|
7559
|
-
await (0,
|
|
9051
|
+
await (0, import_promises8.access)(import_node_path12.default.join(projectPath, candidate));
|
|
7560
9052
|
serverFile = candidate;
|
|
7561
9053
|
break;
|
|
7562
9054
|
} catch {
|
|
@@ -7607,13 +9099,13 @@ Looked for:
|
|
|
7607
9099
|
if (isTsEntry) {
|
|
7608
9100
|
try {
|
|
7609
9101
|
const projectRequire = (0, import_node_module2.createRequire)(
|
|
7610
|
-
|
|
9102
|
+
import_node_path12.default.join(projectPath, "package.json")
|
|
7611
9103
|
);
|
|
7612
9104
|
const tsxPkgPath = projectRequire.resolve("tsx/package.json");
|
|
7613
|
-
const tsxPkg = JSON.parse(await (0,
|
|
9105
|
+
const tsxPkg = JSON.parse(await (0, import_promises8.readFile)(tsxPkgPath, "utf-8"));
|
|
7614
9106
|
const binField = typeof tsxPkg.bin === "string" ? tsxPkg.bin : tsxPkg.bin?.tsx ?? Object.values(tsxPkg.bin ?? {})[0];
|
|
7615
9107
|
if (!binField) throw new Error("tsx bin entry not found");
|
|
7616
|
-
const tsxBin =
|
|
9108
|
+
const tsxBin = import_node_path12.default.resolve(import_node_path12.default.dirname(tsxPkgPath), binField);
|
|
7617
9109
|
spawnCmd = "node";
|
|
7618
9110
|
spawnArgs = [tsxBin, serverFile];
|
|
7619
9111
|
} catch (error) {
|
|
@@ -7626,7 +9118,7 @@ Looked for:
|
|
|
7626
9118
|
spawnArgs = ["tsx", serverFile];
|
|
7627
9119
|
}
|
|
7628
9120
|
}
|
|
7629
|
-
const serverProc = (0,
|
|
9121
|
+
const serverProc = (0, import_node_child_process11.spawn)(spawnCmd, spawnArgs, {
|
|
7630
9122
|
cwd: projectPath,
|
|
7631
9123
|
stdio: "inherit",
|
|
7632
9124
|
env: env2
|
|
@@ -7762,7 +9254,7 @@ program.addCommand(createSkillsCommand());
|
|
|
7762
9254
|
program.command("generate-types").description(
|
|
7763
9255
|
"Generate TypeScript type definitions for tools (writes .mcp-use/tool-registry.d.ts)"
|
|
7764
9256
|
).option("-p, --path <path>", "Path to project directory", process.cwd()).option("--server <file>", "Server entry file", "index.ts").action(async (options) => {
|
|
7765
|
-
const projectPath =
|
|
9257
|
+
const projectPath = import_node_path12.default.resolve(options.path);
|
|
7766
9258
|
try {
|
|
7767
9259
|
console.log(source_default.blue("Generating tool registry types..."));
|
|
7768
9260
|
const result = await generateToolRegistryTypesForServer(
|
|
@@ -7792,5 +9284,49 @@ program.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
|
7792
9284
|
const projectPath = actionCommand.opts().path;
|
|
7793
9285
|
await notifyIfUpdateAvailable(projectPath);
|
|
7794
9286
|
});
|
|
7795
|
-
|
|
9287
|
+
var argv = process.argv;
|
|
9288
|
+
var clientIdx = argv[2] === "client" ? 2 : -1;
|
|
9289
|
+
var perClientName = clientIdx !== -1 && argv.length > clientIdx + 1 && !argv[clientIdx + 1].startsWith("-") && !RESERVED_CLIENT_SUBCOMMANDS.has(argv[clientIdx + 1]) ? argv[clientIdx + 1] : null;
|
|
9290
|
+
if (perClientName) {
|
|
9291
|
+
if (PER_CLIENT_SCOPES.has(perClientName)) {
|
|
9292
|
+
const rest2 = argv.slice(clientIdx + 1).join(" ");
|
|
9293
|
+
console.error(formatError("Missing server name."));
|
|
9294
|
+
console.error("");
|
|
9295
|
+
console.error(
|
|
9296
|
+
`'${perClientName}' is a per-server subcommand, not a server name. Address it through a saved server:`
|
|
9297
|
+
);
|
|
9298
|
+
console.error("");
|
|
9299
|
+
console.error(` mcp-use client <name> ${rest2}`);
|
|
9300
|
+
console.error("");
|
|
9301
|
+
console.error("See your saved servers with:");
|
|
9302
|
+
console.error(" mcp-use client list");
|
|
9303
|
+
process.exit(1);
|
|
9304
|
+
}
|
|
9305
|
+
const rest = argv.slice(clientIdx + 2);
|
|
9306
|
+
const isHelpOnly = rest.length === 0 || rest.length === 1 && (rest[0] === "--help" || rest[0] === "-h");
|
|
9307
|
+
(async () => {
|
|
9308
|
+
if (isHelpOnly) {
|
|
9309
|
+
const config = await getSession(perClientName);
|
|
9310
|
+
if (!config) {
|
|
9311
|
+
console.error(formatError(`Server '${perClientName}' not found.`));
|
|
9312
|
+
console.error("");
|
|
9313
|
+
console.error("Connect to an MCP server and save it under this name:");
|
|
9314
|
+
console.error(` mcp-use client connect ${perClientName} <url>`);
|
|
9315
|
+
console.error("");
|
|
9316
|
+
console.error("See your saved servers with:");
|
|
9317
|
+
console.error(" mcp-use client list");
|
|
9318
|
+
process.exit(1);
|
|
9319
|
+
}
|
|
9320
|
+
}
|
|
9321
|
+
await createPerClientCommand(perClientName).parseAsync(rest, {
|
|
9322
|
+
from: "user"
|
|
9323
|
+
});
|
|
9324
|
+
})().catch((err) => {
|
|
9325
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
9326
|
+
console.error(formatError(message));
|
|
9327
|
+
process.exit(1);
|
|
9328
|
+
});
|
|
9329
|
+
} else {
|
|
9330
|
+
program.parse();
|
|
9331
|
+
}
|
|
7796
9332
|
//# sourceMappingURL=index.cjs.map
|