@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/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.14_tsx@4.21.0_typescript@5.9.3_yaml@2.8.3/node_modules/tsup/assets/cjs_shims.js
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, argv = globalThis.Deno ? globalThis.Deno.args : import_node_process.default.argv) {
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 = argv.indexOf(prefix + flag);
223
- const terminatorPosition = argv.indexOf("--");
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 import_commander6 = require("commander");
526
+ var import_commander7 = require("commander");
527
527
  var import_config8 = require("dotenv/config");
528
- var import_node_child_process9 = require("child_process");
529
- var import_node_fs11 = require("fs");
530
- var import_promises7 = require("fs/promises");
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 import_node_path9 = __toESM(require("path"), 1);
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 (path8) => {
720
- if (/^[a-z]+:\/\//i.test(path8)) {
721
- return path8;
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", path8], { encoding: "utf8" });
724
+ const { stdout } = await execFile2("wslpath", ["-aw", path11], { encoding: "utf8" });
725
725
  return stdout.trim();
726
726
  } catch {
727
- return path8;
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 auth = await this.testAuth();
1344
- const id = auth.default_org_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 path8 = encodeURIComponent(idOrSlug);
1378
- return this.request(`/servers/${path8}`);
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 import_commander = require("commander");
1879
- var import_client = require("mcp-use/client");
1880
- var import_server = require("mcp-use/server");
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
- function formatTable(data, columns) {
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 widths = columns.map((col) => {
1889
- const maxDataWidth = Math.max(
1890
- ...data.map((row) => String(row[col.key] || "").length)
1891
- );
1892
- const headerWidth = col.header.length;
1893
- return col.width || Math.max(maxDataWidth, headerWidth, 10);
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 createRow = (values, bold = false) => {
1896
- const cells = values.map((val, i) => {
1897
- const padded = val.padEnd(widths[i]);
1898
- return bold ? source_default.bold(padded) : padded;
1899
- });
1900
- return `\u2502 ${cells.join(" \u2502 ")} \u2502`;
1901
- };
1902
- const separator = (char) => {
1903
- const parts = widths.map((w) => char.repeat(w + 2));
1904
- if (char === "\u2500") {
1905
- return `\u251C${parts.join("\u253C")}\u2524`;
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
- return `\u2514${parts.join("\u2534")}\u2518`;
1908
- };
1954
+ }
1909
1955
  const lines = [];
1910
- lines.push(`\u250C${widths.map((w) => "\u2500".repeat(w + 2)).join("\u252C")}\u2510`);
1911
- lines.push(
1912
- createRow(
1913
- columns.map((c) => c.header),
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(separator("\u2500"));
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
- if (result.isError) {
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 (result.content && result.content.length > 0) {
1940
- result.content.forEach((item, index) => {
1941
- if (result.content.length > 1) {
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 < result.content.length - 1) {
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
- const dir = (0, import_node_path3.join)((0, import_node_os4.homedir)(), ".mcp-use");
2127
- if (!(0, import_node_fs5.existsSync)(dir)) {
2128
- await (0, import_promises4.mkdir)(dir, { recursive: true });
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 { activeSession: null, sessions: {} };
2400
+ return { sessions: {} };
2136
2401
  }
2137
2402
  const content = await (0, import_promises4.readFile)(SESSION_FILE_PATH, "utf-8");
2138
- return JSON.parse(content);
2139
- } catch (error) {
2140
- return { activeSession: null, sessions: {} };
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 getActiveSession() {
2421
+ async function removeSession(name) {
2159
2422
  const storage = await loadSessions();
2160
- if (!storage.activeSession || !storage.sessions[storage.activeSession]) {
2161
- return null;
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/commands/client.ts
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
- async function getOrRestoreSession(sessionName) {
2202
- if (!sessionName) {
2203
- const active = await getActiveSession();
2204
- if (!active) {
2205
- console.error(
2206
- formatError("No active session. Connect to a server first.")
2207
- );
2208
- console.error(
2209
- formatInfo("Use: npx mcp-use client connect <url> --name <name>")
2210
- );
2211
- return null;
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
- sessionName = active.name;
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(`Session '${sessionName}' not found`));
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
- client.addServer(sessionName, {
2229
- url: config.url,
2230
- headers: config.authToken ? { Authorization: `Bearer ${config.authToken}` } : void 0,
2231
- clientInfo: cliClientInfo
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
- const session = await client.createSession(sessionName);
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 session: ${error.message}`));
2547
+ console.error(formatError(`Failed to restore server: ${error.message}`));
2250
2548
  return null;
2251
2549
  }
2252
- }
2253
- function getCliClientInfo() {
2254
- return {
2255
- name: "mcp-use CLI",
2256
- title: "mcp-use CLI",
2257
- version: (0, import_server.getPackageVersion)(),
2258
- description: "mcp-use CLI - Command-line interface for MCP servers",
2259
- icons: [
2260
- {
2261
- src: "https://manufact.com/logo.png"
2262
- }
2263
- ],
2264
- websiteUrl: "https://manufact.com"
2265
- };
2266
- }
2267
- async function connectCommand(urlOrCommand, options) {
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 sessionName = options.name || `session-${Date.now()}`;
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 = urlOrCommand.split(" ");
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 ${urlOrCommand}...`));
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: urlOrCommand,
2296
- headers: options.auth ? { Authorization: `Bearer ${options.auth}` } : void 0,
3596
+ url: target,
3597
+ ...authProvider ? { authProvider } : options.auth ? { headers: { Authorization: `Bearer ${options.auth}` } } : {},
2297
3598
  clientInfo: cliClientInfo
2298
3599
  });
2299
- session = await client.createSession(sessionName);
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: urlOrCommand,
2303
- authToken: options.auth,
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 to ${sessionName}`));
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
- process.exit(1);
3656
+ await cleanupAndExit(1);
2340
3657
  }
3658
+ await cleanupAndExit(0);
2341
3659
  }
2342
- async function disconnectCommand(sessionName, options) {
3660
+ async function disconnectCommand(name) {
2343
3661
  try {
2344
- if (options?.all) {
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(sessionName);
2364
- console.log(formatSuccess(`Disconnected from ${sessionName}`));
3665
+ activeSessions.delete(name);
3666
+ console.log(formatSuccess(`Disconnected from ${name}`));
2365
3667
  } else {
2366
- console.log(formatInfo(`Session '${sessionName}' is not connected`));
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
- process.exit(1);
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 listSessionsCommand() {
3724
+ async function listClientsCommand() {
2374
3725
  try {
2375
3726
  const sessions = await listAllSessions();
2376
3727
  if (sessions.length === 0) {
2377
- console.log(formatInfo("No saved sessions"));
2378
- console.log(
2379
- formatInfo("Connect to a server with: npx mcp-use client connect <url>")
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
- console.log(formatHeader("Saved Sessions:"));
2384
- console.log("");
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.isActive ? source_default.green.bold(`${s.name} *`) : s.name,
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", width: 40 },
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 switch session: ${error.message}`));
2414
- process.exit(1);
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(options.session || null);
2420
- if (!result) return;
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
- return;
2426
- }
2427
- if (tools.length === 0) {
2428
- console.log(formatInfo("No tools available"));
2429
- return;
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
- process.exit(1);
3813
+ await cleanupAndExit(1);
2446
3814
  }
3815
+ await cleanupAndExit(0);
2447
3816
  }
2448
- async function describeToolCommand(toolName, options) {
3817
+ async function describeToolCommand(name, toolName) {
2449
3818
  try {
2450
- const result = await getOrRestoreSession(options.session || null);
2451
- if (!result) return;
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
- return;
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
- process.exit(1);
3845
+ await cleanupAndExit(1);
2475
3846
  }
3847
+ await cleanupAndExit(0);
2476
3848
  }
2477
- async function callToolCommand(toolName, argsJson, options) {
3849
+ async function callToolCommand(name, toolName, argsList, options) {
2478
3850
  try {
2479
- const result = await getOrRestoreSession(options?.session || null);
2480
- if (!result) return;
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 (argsJson) {
3859
+ if (argsList && argsList.length > 0) {
2484
3860
  try {
2485
- args = JSON.parse(argsJson);
3861
+ args = parseToolArgs(argsList, tool?.inputSchema);
2486
3862
  } catch (error) {
2487
- console.error(formatError("Invalid JSON arguments"));
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("Example:"));
3865
+ console.log(formatInfo("Usage:"));
2501
3866
  console.log(
2502
- ` npx mcp-use client tools call ${toolName} '{"param": "value"}'`
3867
+ ` npx mcp-use client ${name} tools call ${toolName} key=value [key2=value2 ...]`
2503
3868
  );
2504
- console.log("");
2505
- console.log(formatInfo("Tool schema:"));
2506
- console.log(formatSchema(tool.inputSchema));
2507
- return;
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
- process.exit(1);
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(options.session || null);
2527
- if (!result) return;
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
- return;
2534
- }
2535
- if (resources.length === 0) {
2536
- console.log(formatInfo("No resources available"));
2537
- return;
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
- process.exit(1);
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(options.session || null);
2561
- if (!result) return;
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
- process.exit(1);
4016
+ await cleanupAndExit(1);
2573
4017
  }
4018
+ await cleanupAndExit(0);
2574
4019
  }
2575
- async function subscribeResourceCommand(uri, options) {
4020
+ async function subscribeResourceCommand(name, uri) {
2576
4021
  try {
2577
- const result = await getOrRestoreSession(options.session || null);
2578
- if (!result) return;
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
- process.exit(1);
4043
+ await cleanupAndExit(1);
2597
4044
  }
2598
4045
  }
2599
- async function unsubscribeResourceCommand(uri, options) {
4046
+ async function unsubscribeResourceCommand(name, uri) {
2600
4047
  try {
2601
- const result = await getOrRestoreSession(options.session || null);
2602
- if (!result) return;
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
- process.exit(1);
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(options.session || null);
2616
- if (!result) return;
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
- return;
2623
- }
2624
- if (prompts.length === 0) {
2625
- console.log(formatInfo("No prompts available"));
2626
- return;
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
- process.exit(1);
4103
+ await cleanupAndExit(1);
2643
4104
  }
4105
+ await cleanupAndExit(0);
2644
4106
  }
2645
- async function getPromptCommand(promptName, argsJson, options) {
4107
+ async function getPromptCommand(name, promptName, argsList, options) {
2646
4108
  try {
2647
- const result = await getOrRestoreSession(options?.session || null);
2648
- if (!result) return;
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 (argsJson) {
4115
+ if (argsList && argsList.length > 0) {
2652
4116
  try {
2653
- args = JSON.parse(argsJson);
4117
+ args = parsePromptArgs(argsList);
2654
4118
  } catch (error) {
2655
- console.error(formatError("Invalid JSON arguments"));
2656
- return;
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
- process.exit(1);
4150
+ await cleanupAndExit(1);
2679
4151
  }
4152
+ await cleanupAndExit(0);
2680
4153
  }
2681
- async function interactiveCommand(options) {
4154
+ async function interactiveCommand(name) {
2682
4155
  try {
2683
- const result = await getOrRestoreSession(options.session || null);
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, import_node_readline.createInterface)({
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
- process.exit(0);
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, sessions"
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
- process.exit(0);
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
- process.exit(1);
4319
+ await cleanupAndExit(1);
2863
4320
  }
2864
4321
  }
2865
4322
  function createClientCommand() {
2866
- const clientCommand = new import_commander.Command("client").description(
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
- clientCommand.command("connect <url>").description("Connect to an MCP server").option("--name <name>", "Session name").option("--stdio", "Use stdio connector instead of HTTP").option("--auth <token>", "Authentication token").action(connectCommand);
2870
- clientCommand.command("disconnect [session]").description("Disconnect from a session").option("--all", "Disconnect all sessions").action(disconnectCommand);
2871
- const sessionsCommand = new import_commander.Command("sessions").description(
2872
- "Manage CLI sessions"
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
- sessionsCommand.command("list").description("List all saved sessions").action(listSessionsCommand);
2875
- sessionsCommand.command("switch <name>").description("Switch to a different session").action(switchSessionCommand);
2876
- clientCommand.addCommand(sessionsCommand);
2877
- const toolsCommand = new import_commander.Command("tools").description(
2878
- "Interact with MCP tools"
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("list").description("List available tools").option("--session <name>", "Use specific session").option("--json", "Output as JSON").action(listToolsCommand);
2881
- toolsCommand.command("call <name> [args]").description("Call a tool with arguments (JSON string)").option("--session <name>", "Use specific session").option("--timeout <ms>", "Request timeout in milliseconds", parseInt).option("--json", "Output as JSON").action(callToolCommand);
2882
- toolsCommand.command("describe <name>").description("Show tool details and schema").option("--session <name>", "Use specific session").action(describeToolCommand);
2883
- clientCommand.addCommand(toolsCommand);
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("--session <name>", "Use specific session").option("--json", "Output as JSON").action(listResourcesCommand);
2888
- resourcesCommand.command("read <uri>").description("Read a resource by URI").option("--session <name>", "Use specific session").option("--json", "Output as JSON").action(readResourceCommand);
2889
- resourcesCommand.command("subscribe <uri>").description("Subscribe to resource updates").option("--session <name>", "Use specific session").action(subscribeResourceCommand);
2890
- resourcesCommand.command("unsubscribe <uri>").description("Unsubscribe from resource updates").option("--session <name>", "Use specific session").action(unsubscribeResourceCommand);
2891
- clientCommand.addCommand(resourcesCommand);
2892
- const promptsCommand = new import_commander.Command("prompts").description(
2893
- "Interact with MCP prompts"
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("--session <name>", "Use specific session").option("--json", "Output as JSON").action(listPromptsCommand);
2896
- promptsCommand.command("get <name> [args]").description("Get a prompt with arguments (JSON string)").option("--session <name>", "Use specific session").option("--json", "Output as JSON").action(getPromptCommand);
2897
- clientCommand.addCommand(promptsCommand);
2898
- clientCommand.command("interactive").description("Start interactive REPL mode").option("--session <name>", "Use specific session").action(interactiveCommand);
2899
- return clientCommand;
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 import_node_fs7 = require("fs");
2904
- var import_node_path5 = __toESM(require("path"), 1);
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 import_node_child_process8 = require("child_process");
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)(import_node_child_process8.execFile);
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 import_node_fs6 = require("fs");
3059
- var import_node_path4 = __toESM(require("path"), 1);
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 import_node_path4.default.join(cwd, MCP_USE_DIR);
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 = import_node_path4.default.join(getMcpUseDirectory(cwd), MCP_USE_DIR_PROJECT);
3068
- const content = await import_node_fs6.promises.readFile(linkPath, "utf-8");
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 import_node_fs6.promises.mkdir(mcpUseDir, { recursive: true });
3078
- const linkPath = import_node_path4.default.join(mcpUseDir, MCP_USE_DIR_PROJECT);
3079
- await import_node_fs6.promises.writeFile(linkPath, JSON.stringify(link, null, 2), "utf-8");
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 = import_node_path4.default.join(cwd, ".gitignore");
4577
+ const gitignorePath = import_node_path7.default.join(cwd, ".gitignore");
3084
4578
  try {
3085
4579
  let content = "";
3086
4580
  try {
3087
- content = await import_node_fs6.promises.readFile(gitignorePath, "utf-8");
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 import_node_fs6.promises.writeFile(gitignorePath, newContent, "utf-8");
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 import_node_fs7.promises.readFile(filePath, "utf-8");
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 import_node_fs7.promises.readFile(import_node_path5.default.join(cwd, "package.json"), "utf-8");
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 import_node_fs7.promises.readFile(import_node_path5.default.join(cwd, "package.json"), "utf-8");
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 import_node_path5.default.basename(cwd);
4732
+ return import_node_path8.default.basename(cwd);
3239
4733
  }
3240
4734
  async function detectBuildCommand(cwd) {
3241
4735
  try {
3242
- const content = await import_node_fs7.promises.readFile(import_node_path5.default.join(cwd, "package.json"), "utf-8");
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 import_node_fs7.promises.readFile(import_node_path5.default.join(cwd, "package.json"), "utf-8");
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 import_node_fs7.promises.access(import_node_path5.default.join(cwd, f));
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 = import_node_path5.default.join(cwd, ".gitignore");
4802
+ const gitignorePath = import_node_path8.default.join(cwd, ".gitignore");
3309
4803
  let content = "";
3310
4804
  try {
3311
- content = await import_node_fs7.promises.readFile(gitignorePath, "utf-8");
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 import_node_fs7.promises.writeFile(gitignorePath, newContent, "utf-8");
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 ? import_node_path5.default.resolve(cwd, options.rootDir) : cwd;
5262
+ const projectDir = options.rootDir ? import_node_path8.default.resolve(cwd, options.rootDir) : cwd;
3769
5263
  if (options.rootDir) {
3770
5264
  try {
3771
- await import_node_fs7.promises.access(projectDir);
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 import_commander2 = require("commander");
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 import_commander2.Command("deployments").description(
4693
- "Manage cloud deployments"
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 import_commander4 = require("commander");
6202
+ var import_commander5 = require("commander");
4709
6203
 
4710
6204
  // src/commands/env.ts
4711
- var import_commander3 = require("commander");
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 import_commander3.Command("env").description(
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 import_commander4.Command("servers").description(
5141
- "Manage cloud servers (Git-backed deploy targets)"
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 import_commander5 = require("commander");
5259
- var import_node_fs8 = require("fs");
5260
- var import_node_os5 = require("os");
5261
- var import_node_path6 = require("path");
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 import_promises5 = require("stream/promises");
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, import_node_fs8.mkdtempSync)((0, import_node_path6.join)((0, import_node_os5.tmpdir)(), "mcp-use-skills-"));
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, import_promises5.pipeline)(
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: (path8) => path8.includes("/skills/"),
6800
+ filter: (path11) => path11.includes("/skills/"),
5309
6801
  strip: 1
5310
6802
  })
5311
6803
  );
5312
- const skillsPath = (0, import_node_path6.join)(tempDir, "skills");
5313
- if (!(0, import_node_fs8.existsSync)(skillsPath)) {
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, import_node_path6.join)(projectPath, folderName, "skills");
5319
- (0, import_node_fs8.cpSync)(skillsPath, outputPath, { recursive: true });
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, import_node_fs8.readdirSync)(skillsPath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
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, import_node_fs8.rmSync)(tempDir, { recursive: true, force: true });
6816
+ (0, import_node_fs11.rmSync)(tempDir, { recursive: true, force: true });
5325
6817
  }
5326
6818
  }
5327
6819
  function createSkillsCommand() {
5328
- const skills = new import_commander5.Command("skills").description(
5329
- "Manage mcp-use AI agent skills"
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, import_node_path6.resolve)(options.path);
5333
- if (!(0, import_node_fs8.existsSync)(projectPath)) {
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 import_node_fs9 = require("fs");
5375
- var import_node_path7 = __toESM(require("path"), 1);
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 = import_node_path7.default.join(projectPath, "package.json");
5380
- const content = await import_node_fs9.promises.readFile(pkgPath, "utf-8");
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 = import_node_path7.default.join(projectPath, file);
6890
+ const abs = import_node_path10.default.join(projectPath, file);
5399
6891
  try {
5400
- await import_node_fs9.promises.access(abs);
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 import_node_path7.default.dirname((0, import_node_url2.fileURLToPath)(url));
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
- import_node_path7.default.join(thisDir, "shims", filename),
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
- import_node_path7.default.join(thisDir, "..", "shims", filename),
5419
- import_node_path7.default.join(thisDir, "..", "..", "src", "shims", filename),
5420
- import_node_path7.default.join(thisDir, "..", "src", "shims", filename)
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, import_node_fs9.existsSync)(candidate)) return candidate;
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() + import_node_path7.default.sep).href);
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() + import_node_path7.default.sep).href);
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 import_node_fs10 = require("fs");
5475
- var import_promises6 = require("fs/promises");
6966
+ var import_node_fs13 = require("fs");
6967
+ var import_promises7 = require("fs/promises");
5476
6968
  var import_node_module = require("module");
5477
- var import_node_os6 = __toESM(require("os"), 1);
5478
- var import_node_path8 = __toESM(require("path"), 1);
5479
- var CACHE_DIR = import_node_path8.default.join(import_node_os6.default.homedir(), ".mcp-use");
5480
- var CACHE_FILE = import_node_path8.default.join(CACHE_DIR, "update-check.json");
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, import_promises6.readFile)(CACHE_FILE, "utf-8");
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, import_promises6.mkdir)(CACHE_DIR, { recursive: true });
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, import_promises6.writeFile)(CACHE_FILE, JSON.stringify(cache, null, 2), "utf-8");
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
- import_node_path8.default.join(projectPath, "package.json")
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(() => import_node_path8.default.join(__dirname, "../../mcp-use/package.json"));
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, import_node_fs10.readFileSync)(pkgPath, "utf-8"));
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 import_commander6.Command();
5605
- var packageContent = (0, import_node_fs11.readFileSync)(
5606
- import_node_path9.default.join(__dirname, "../package.json"),
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
- import_node_path9.default.join(projectPath, "package.json")
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 = import_node_path9.default.join(__dirname, pkg.relativePath);
7133
+ pkgPath = import_node_path12.default.join(__dirname, pkg.relativePath);
5642
7134
  }
5643
7135
  } else {
5644
- pkgPath = import_node_path9.default.join(__dirname, pkg.relativePath);
7136
+ pkgPath = import_node_path12.default.join(__dirname, pkg.relativePath);
5645
7137
  }
5646
- const pkgContent = (0, import_node_fs11.readFileSync)(pkgPath, "utf-8");
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, import_node_child_process9.spawn)(command, args, {
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, import_node_child_process9.spawn)("npx", tunnelArgs, {
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, import_promises7.access)(import_node_path9.default.join(projectPath, cliEntry)).catch(() => {
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
- import_node_path9.default.join(mcpDir, "index.ts"),
5806
- import_node_path9.default.join(mcpDir, "index.tsx"),
5807
- import_node_path9.default.join(mcpDir, "server.ts"),
5808
- import_node_path9.default.join(mcpDir, "server.tsx")
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, import_promises7.access)(import_node_path9.default.join(projectPath, candidate));
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) => import_node_path9.default.relative(projectPath, import_node_path9.default.join(projectPath, c))).join(", ")}
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 ${import_node_path9.default.join(mcpDir, "index.ts")}, or
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, import_promises7.access)(import_node_path9.default.join(projectPath, candidate));
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 import_node_path9.default.join(mcpDir, "resources");
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 = import_node_path9.default.join(projectPath, serverFileRelative);
5885
- const serverFileExists = await (0, import_promises7.access)(serverFile).then(() => true).catch(() => false);
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 = import_node_path9.default.join(projectPath, "tsconfig.json");
5911
- const hasTsconfig = await (0, import_promises7.access)(projectTsconfigPath).then(() => true).catch(() => false);
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
- import_node_path9.default.join(projectPath, "package.json")
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 = import_node_path9.default.join(projectPath, "node_modules", "mcp-use");
5947
- const { generateToolRegistryTypes } = await import((0, import_node_url3.pathToFileURL)(import_node_path9.default.join(mcpUsePath, "dist", "src", "server", "index.js")).href).then((mod) => mod);
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 = import_node_path9.default.resolve(projectPath, widgetsDirRelative);
7457
+ const resourcesDir = import_node_path12.default.resolve(projectPath, widgetsDirRelative);
5966
7458
  const mcpUrl = process.env.MCP_URL;
5967
7459
  try {
5968
- await (0, import_promises7.access)(resourcesDir);
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: import_node_path9.default.join(resourcesDir, dirent.name)
7479
+ path: import_node_path12.default.join(resourcesDir, dirent.name)
5988
7480
  });
5989
7481
  } else if (dirent.isDirectory()) {
5990
- const widgetPath = import_node_path9.default.join(resourcesDir, dirent.name, "widget.tsx");
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 = import_node_path9.default.join(projectPath, "tsconfig.json");
7512
+ const projectTsconfigPath = import_node_path12.default.join(projectPath, "tsconfig.json");
6021
7513
  let hasProjectTsconfig = false;
6022
7514
  try {
6023
- await (0, import_promises7.access)(projectTsconfigPath);
7515
+ await (0, import_promises8.access)(projectTsconfigPath);
6024
7516
  hasProjectTsconfig = true;
6025
7517
  } catch {
6026
7518
  }
6027
- const packageJsonPath = import_node_path9.default.join(projectPath, "package.json");
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 = import_node_path9.default.join(projectPath, ".mcp-use", widgetName);
7531
+ const tempDir = import_node_path12.default.join(projectPath, ".mcp-use", widgetName);
6040
7532
  await fs11.mkdir(tempDir, { recursive: true });
6041
- const relativeResourcesPath = import_node_path9.default.relative(tempDir, resourcesDir).replace(/\\/g, "/");
6042
- const mcpUsePath = import_node_path9.default.join(projectPath, "node_modules", "mcp-use");
6043
- const relativeMcpUsePath = import_node_path9.default.relative(tempDir, mcpUsePath).replace(/\\/g, "/");
6044
- const projectSrcDir = import_node_path9.default.join(projectPath, "src");
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, import_promises7.access)(projectSrcDir);
6048
- const relativeProjectSrcPath = import_node_path9.default.relative(tempDir, projectSrcDir).replace(/\\/g, "/");
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(import_node_path9.default.join(tempDir, "styles.css"), cssContent, "utf8");
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(import_node_path9.default.join(tempDir, "entry.tsx"), entryContent, "utf8");
6085
- await fs11.writeFile(import_node_path9.default.join(tempDir, "index.html"), htmlContent, "utf8");
6086
- const outDir = import_node_path9.default.join(
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 = import_node_path9.default.join(
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 createServer({
7622
+ const metadataServer = await createServer2({
6131
7623
  root: metadataTempDir,
6132
- cacheDir: import_node_path9.default.join(metadataTempDir, ".vite-cache"),
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: import_node_path9.default.join(tempDir, "index.html"),
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 = import_node_path9.default.join(outDir, "assets");
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 = import_node_path9.default.join(assetsDir, jsFile);
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 = import_node_path9.default.join(outDir, "index.html");
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, import_promises7.access)(import_node_path9.default.join(projectPath, file));
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 = import_node_path9.default.join(projectPath, prefix);
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 = import_node_path9.default.join(prefix, entryStr);
6497
- if (/\.tsx?$/.test(entryStr) && !entryStr.endsWith(".d.ts") && !excludeSet.has(rel.split(import_node_path9.default.sep)[0])) {
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 = import_node_path9.default.join(projectPath, "tsconfig.json");
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 ? import_node_path9.default.resolve(projectPath, compilerOptions.rootDir) : projectPath;
8031
+ const outbase = compilerOptions.rootDir ? import_node_path12.default.resolve(projectPath, compilerOptions.rootDir) : projectPath;
6540
8032
  await esbuild.build({
6541
- entryPoints: files.map((f) => import_node_path9.default.join(projectPath, f)),
6542
- outdir: import_node_path9.default.join(projectPath, 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 = import_node_path9.default.resolve(options.path);
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 = import_node_path9.default.join(
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 = import_node_path9.default.basename(sourceServerFile, ".ts") + ".js";
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, import_promises7.access)(import_node_path9.default.join(projectPath, candidate));
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 = import_node_path9.default.join(projectPath, "public");
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, import_node_path9.default.join(projectPath, "dist", "public"), {
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 = import_node_path9.default.join(projectPath, "dist", "mcp-use.json");
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(import_node_path9.default.dirname(manifestPath), { recursive: true });
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 = import_node_path9.default.resolve(options.path);
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 = import_node_path9.default.join(projectPath, "dist", "mcp-use.json");
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, import_promises7.readFile)(manifestPath, "utf-8");
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, import_promises7.readFile)(manifestPath, "utf-8");
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, import_promises7.mkdir)(import_node_path9.default.dirname(manifestPath), { recursive: true });
6822
- await (0, import_promises7.writeFile)(
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
- import_node_path9.default.join(projectPath, "package.json")
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, import_promises7.readFile)(tsxPkgPath, "utf-8"));
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 = import_node_path9.default.resolve(import_node_path9.default.dirname(tsxPkgPath), binPath);
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 = import_node_path9.default.join(projectPath, "tsconfig.json");
8469
+ const projectTsconfigPath = import_node_path12.default.join(projectPath, "tsconfig.json");
6978
8470
  let tsconfigAvailable = false;
6979
8471
  try {
6980
- await (0, import_promises7.access)(projectTsconfigPath);
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
- import_node_path9.default.join(projectPath, "package.json")
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 = import_node_path9.default.join(projectPath, serverFile);
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: (path8, stats) => {
7118
- const normalizedPath = path8.replace(/\\/g, "/");
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 = import_node_path9.default.join(projectPath, "dist", "mcp-use.json");
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, import_promises7.readFile)(manifestPath, "utf-8");
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 = import_node_path9.default.join(projectPath, "dist", "mcp-use.json");
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, import_promises7.readFile)(mPath, "utf-8"));
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, import_promises7.mkdir)(import_node_path9.default.dirname(mPath), { recursive: true });
7338
- await (0, import_promises7.writeFile)(mPath, JSON.stringify(manifest, null, 2), "utf-8");
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 = import_node_path9.default.resolve(options.path);
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 = import_node_path9.default.join(projectPath, "dist", "mcp-use.json");
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, import_promises7.readFile)(manifestPath2, "utf-8");
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, import_promises7.readFile)(manifestPath2, "utf-8");
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, import_promises7.mkdir)(import_node_path9.default.dirname(manifestPath2), { recursive: true });
7515
- await (0, import_promises7.writeFile)(
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 = import_node_path9.default.join(projectPath, "dist", "mcp-use.json");
9025
+ const manifestPath = import_node_path12.default.join(projectPath, "dist", "mcp-use.json");
7534
9026
  try {
7535
- const manifestContent = await (0, import_promises7.readFile)(manifestPath, "utf-8");
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, import_promises7.access)(import_node_path9.default.join(projectPath, manifest.entryPoint));
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, import_promises7.access)(import_node_path9.default.join(projectPath, candidate));
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
- import_node_path9.default.join(projectPath, "package.json")
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, import_promises7.readFile)(tsxPkgPath, "utf-8"));
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 = import_node_path9.default.resolve(import_node_path9.default.dirname(tsxPkgPath), binField);
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, import_node_child_process9.spawn)(spawnCmd, spawnArgs, {
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 = import_node_path9.default.resolve(options.path);
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
- program.parse();
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