@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.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // ../../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/esm_shims.js
3
+ // ../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.9_tsx@4.21.0_typescript@5.9.3_yaml@2.8.3/node_modules/tsup/assets/esm_shims.js
4
4
  import path from "path";
5
5
  import { fileURLToPath } from "url";
6
6
  var getFilename = () => fileURLToPath(import.meta.url);
@@ -197,10 +197,10 @@ var ansi_styles_default = ansiStyles;
197
197
  import process2 from "process";
198
198
  import os from "os";
199
199
  import tty from "tty";
200
- function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process2.argv) {
200
+ function hasFlag(flag, argv2 = globalThis.Deno ? globalThis.Deno.args : process2.argv) {
201
201
  const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
202
- const position = argv.indexOf(prefix + flag);
203
- const terminatorPosition = argv.indexOf("--");
202
+ const position = argv2.indexOf(prefix + flag);
203
+ const terminatorPosition = argv2.indexOf("--");
204
204
  return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
205
205
  }
206
206
  var { env } = process2;
@@ -503,13 +503,13 @@ var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
503
503
  var source_default = chalk;
504
504
 
505
505
  // src/index.ts
506
- import { Command as Command6 } from "commander";
506
+ import { Command as Command7 } from "commander";
507
507
  import "dotenv/config";
508
- import { spawn } from "child_process";
508
+ import { spawn as spawn3 } from "child_process";
509
509
  import { readFileSync as readFileSync2 } from "fs";
510
- import { access, mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
510
+ import { access, mkdir as mkdir4, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
511
511
  import { createRequire as createRequire2 } from "module";
512
- import path8 from "path";
512
+ import path11 from "path";
513
513
  import { pathToFileURL as pathToFileURL2 } from "url";
514
514
 
515
515
  // ../../node_modules/.pnpm/open@11.0.0/node_modules/open/index.js
@@ -595,7 +595,7 @@ var is_wsl_default = process3.env.__IS_WSL_TEST__ ? isWsl : isWsl();
595
595
 
596
596
  // ../../node_modules/.pnpm/powershell-utils@0.1.0/node_modules/powershell-utils/index.js
597
597
  import process4 from "process";
598
- import { Buffer } from "buffer";
598
+ import { Buffer as Buffer2 } from "buffer";
599
599
  import { promisify } from "util";
600
600
  import childProcess from "child_process";
601
601
  import fs4, { constants as fsConstants } from "fs/promises";
@@ -626,7 +626,7 @@ executePowerShell.argumentsPrefix = [
626
626
  "Bypass",
627
627
  "-EncodedCommand"
628
628
  ];
629
- executePowerShell.encodeCommand = (command) => Buffer.from(command, "utf16le").toString("base64");
629
+ executePowerShell.encodeCommand = (command) => Buffer2.from(command, "utf16le").toString("base64");
630
630
  executePowerShell.escapeArgument = (value) => `'${String(value).replaceAll("'", "''")}'`;
631
631
 
632
632
  // ../../node_modules/.pnpm/wsl-utils@0.3.1/node_modules/wsl-utils/utilities.js
@@ -696,15 +696,15 @@ var wslDefaultBrowser = async () => {
696
696
  const { stdout } = await executePowerShell(command, { powerShellPath: psPath });
697
697
  return stdout.trim();
698
698
  };
699
- var convertWslPathToWindows = async (path9) => {
700
- if (/^[a-z]+:\/\//i.test(path9)) {
701
- return path9;
699
+ var convertWslPathToWindows = async (path12) => {
700
+ if (/^[a-z]+:\/\//i.test(path12)) {
701
+ return path12;
702
702
  }
703
703
  try {
704
- const { stdout } = await execFile2("wslpath", ["-aw", path9], { encoding: "utf8" });
704
+ const { stdout } = await execFile2("wslpath", ["-aw", path12], { encoding: "utf8" });
705
705
  return stdout.trim();
706
706
  } catch {
707
- return path9;
707
+ return path12;
708
708
  }
709
709
  };
710
710
 
@@ -1320,8 +1320,8 @@ var McpUseAPI = class _McpUseAPI {
1320
1320
  // ── Organization ID resolution ──────────────────────────────────
1321
1321
  async resolveOrganizationId() {
1322
1322
  if (this.orgId) return this.orgId;
1323
- const auth = await this.testAuth();
1324
- const id = auth.default_org_id;
1323
+ const auth2 = await this.testAuth();
1324
+ const id = auth2.default_org_id;
1325
1325
  if (!id) {
1326
1326
  throw new Error(
1327
1327
  "No organization set. Run `mcp-use org switch` or use --org to specify one."
@@ -1354,8 +1354,8 @@ var McpUseAPI = class _McpUseAPI {
1354
1354
  return this.request(`/servers${q ? `?${q}` : ""}`);
1355
1355
  }
1356
1356
  async getServer(idOrSlug) {
1357
- const path9 = encodeURIComponent(idOrSlug);
1358
- return this.request(`/servers/${path9}`);
1357
+ const path12 = encodeURIComponent(idOrSlug);
1358
+ return this.request(`/servers/${path12}`);
1359
1359
  }
1360
1360
  async deleteServer(id) {
1361
1361
  await this.request(
@@ -1855,52 +1855,110 @@ async function whoamiCommand() {
1855
1855
  }
1856
1856
 
1857
1857
  // src/commands/client.ts
1858
- import { Command } from "commander";
1859
- import { MCPClient } from "mcp-use/client";
1860
- import { getPackageVersion } from "mcp-use/server";
1861
- import { createInterface } from "readline";
1858
+ import { Command as Command2 } from "commander";
1859
+ import { MCPClient as MCPClient3 } from "mcp-use/client";
1860
+ import { createInterface as createInterface2 } from "readline";
1862
1861
 
1863
1862
  // src/utils/format.ts
1864
- function formatTable(data, columns) {
1863
+ var ANSI_RE = /\x1b\[[0-9;]*m/g;
1864
+ var GUTTER = " ";
1865
+ var MIN_TRUNCATABLE_WIDTH = 8;
1866
+ var DEFAULT_MAX_WIDTH = 100;
1867
+ function stripAnsi(s) {
1868
+ return s.replace(ANSI_RE, "");
1869
+ }
1870
+ function visibleWidth(s) {
1871
+ return stripAnsi(s).length;
1872
+ }
1873
+ function padCell(s, width) {
1874
+ const w = visibleWidth(s);
1875
+ if (w >= width) return s;
1876
+ return s + " ".repeat(width - w);
1877
+ }
1878
+ function truncateCell(s, width) {
1879
+ if (width <= 0) return "";
1880
+ const plain = stripAnsi(s);
1881
+ if (plain.length <= width) return s;
1882
+ if (width === 1) return "\u2026";
1883
+ return plain.slice(0, width - 1) + "\u2026";
1884
+ }
1885
+ function formatTable(data, columns, options = {}) {
1886
+ const tsv = options.tsv ?? !process.stdout.isTTY;
1887
+ if (tsv) {
1888
+ return data.map(
1889
+ (row) => columns.map(
1890
+ (c) => stripAnsi(String(row[c.key] ?? "")).replace(/[\t\r\n]+/g, " ")
1891
+ ).join(" ")
1892
+ ).join("\n");
1893
+ }
1865
1894
  if (data.length === 0) {
1866
1895
  return source_default.gray("No items found");
1867
1896
  }
1868
- const widths = columns.map((col) => {
1869
- const maxDataWidth = Math.max(
1870
- ...data.map((row) => String(row[col.key] || "").length)
1871
- );
1872
- const headerWidth = col.header.length;
1873
- return col.width || Math.max(maxDataWidth, headerWidth, 10);
1897
+ const maxWidth = options.maxWidth ?? process.stdout.columns ?? DEFAULT_MAX_WIDTH;
1898
+ const natural = columns.map((col) => {
1899
+ const headerW = col.header.length;
1900
+ const dataW = data.reduce((m, row) => {
1901
+ return Math.max(m, visibleWidth(String(row[col.key] ?? "")));
1902
+ }, 0);
1903
+ return Math.max(headerW, dataW);
1874
1904
  });
1875
- const createRow = (values, bold = false) => {
1876
- const cells = values.map((val, i) => {
1877
- const padded = val.padEnd(widths[i]);
1878
- return bold ? source_default.bold(padded) : padded;
1879
- });
1880
- return `\u2502 ${cells.join(" \u2502 ")} \u2502`;
1881
- };
1882
- const separator = (char) => {
1883
- const parts = widths.map((w) => char.repeat(w + 2));
1884
- if (char === "\u2500") {
1885
- return `\u251C${parts.join("\u253C")}\u2524`;
1905
+ const widths = columns.map((c, i) => c.width ?? natural[i]);
1906
+ const overhead = GUTTER.length * (columns.length - 1);
1907
+ const totalWidth = () => widths.reduce((s, w) => s + w, 0) + overhead;
1908
+ if (totalWidth() > maxWidth) {
1909
+ const truncIdxs = columns.map((c, i) => c.truncate ? i : -1).filter((i) => i >= 0);
1910
+ if (truncIdxs.length > 0) {
1911
+ const fixedSum = columns.reduce(
1912
+ (s, c, i) => s + (c.truncate ? 0 : widths[i]),
1913
+ 0
1914
+ );
1915
+ const remaining = Math.max(
1916
+ truncIdxs.length * MIN_TRUNCATABLE_WIDTH,
1917
+ maxWidth - fixedSum - overhead
1918
+ );
1919
+ const truncSum = truncIdxs.reduce((s, i) => s + widths[i], 0) || 1;
1920
+ let used = 0;
1921
+ truncIdxs.forEach((i, idx) => {
1922
+ if (idx === truncIdxs.length - 1) {
1923
+ widths[i] = Math.max(MIN_TRUNCATABLE_WIDTH, remaining - used);
1924
+ } else {
1925
+ const share = Math.max(
1926
+ MIN_TRUNCATABLE_WIDTH,
1927
+ Math.floor(widths[i] / truncSum * remaining)
1928
+ );
1929
+ widths[i] = share;
1930
+ used += share;
1931
+ }
1932
+ });
1886
1933
  }
1887
- return `\u2514${parts.join("\u2534")}\u2518`;
1888
- };
1934
+ }
1889
1935
  const lines = [];
1890
- lines.push(`\u250C${widths.map((w) => "\u2500".repeat(w + 2)).join("\u252C")}\u2510`);
1891
- lines.push(
1892
- createRow(
1893
- columns.map((c) => c.header),
1894
- true
1895
- )
1896
- );
1897
- lines.push(separator("\u2500"));
1898
- data.forEach((row) => {
1899
- lines.push(createRow(columns.map((c) => String(row[c.key] || ""))));
1936
+ const headerCells = columns.map((c, i) => {
1937
+ const text = c.header.toUpperCase();
1938
+ const cell = i === columns.length - 1 ? text : padCell(text, widths[i]);
1939
+ return source_default.bold(cell);
1900
1940
  });
1901
- lines.push(separator("\u2500"));
1941
+ lines.push(headerCells.join(GUTTER).trimEnd());
1942
+ for (const row of data) {
1943
+ const cells = columns.map((c, i) => {
1944
+ let v = String(row[c.key] ?? "");
1945
+ if (visibleWidth(v) > widths[i]) {
1946
+ v = truncateCell(v, widths[i]);
1947
+ }
1948
+ return i === columns.length - 1 ? v : padCell(v, widths[i]);
1949
+ });
1950
+ lines.push(cells.join(GUTTER).trimEnd());
1951
+ }
1902
1952
  return lines.join("\n");
1903
1953
  }
1954
+ function isStdoutTty() {
1955
+ return Boolean(process.stdout.isTTY);
1956
+ }
1957
+ function formatToolMode(annotations) {
1958
+ if (annotations?.readOnlyHint === true) return source_default.green("read-only");
1959
+ if (annotations?.destructiveHint === true) return source_default.red("destructive");
1960
+ return source_default.yellow("write");
1961
+ }
1904
1962
  function formatJson(data, pretty = true) {
1905
1963
  if (pretty) {
1906
1964
  return JSON.stringify(data, null, 2);
@@ -1909,20 +1967,29 @@ function formatJson(data, pretty = true) {
1909
1967
  }
1910
1968
  function formatToolCall(result) {
1911
1969
  const lines = [];
1912
- if (result.isError) {
1970
+ const { isError, structuredContent } = result;
1971
+ const hasStructured = structuredContent !== void 0 && structuredContent !== null;
1972
+ const visibleContent = (result.content ?? []).filter(
1973
+ (item) => !hasStructured || item.type !== "text"
1974
+ );
1975
+ const hasVisibleContent = visibleContent.length > 0;
1976
+ if (isError) {
1913
1977
  lines.push(source_default.red("\u2717 Tool execution failed"));
1914
1978
  lines.push("");
1915
1979
  } else {
1916
1980
  lines.push(source_default.green("\u2713 Tool executed successfully"));
1917
1981
  lines.push("");
1918
1982
  }
1919
- if (result.content && result.content.length > 0) {
1920
- result.content.forEach((item, index) => {
1921
- if (result.content.length > 1) {
1983
+ if (hasVisibleContent) {
1984
+ if (isError) {
1985
+ lines.push(source_default.red.bold("Error details:"));
1986
+ }
1987
+ visibleContent.forEach((item, index) => {
1988
+ if (visibleContent.length > 1) {
1922
1989
  lines.push(source_default.bold(`Content ${index + 1}:`));
1923
1990
  }
1924
1991
  if (item.type === "text") {
1925
- lines.push(item.text);
1992
+ lines.push(isError ? source_default.red(item.text) : item.text);
1926
1993
  } else if (item.type === "image") {
1927
1994
  lines.push(source_default.cyan(`[Image: ${item.mimeType || "unknown type"}]`));
1928
1995
  if (item.data) {
@@ -1939,11 +2006,20 @@ function formatToolCall(result) {
1939
2006
  } else {
1940
2007
  lines.push(source_default.gray(`[Unknown content type: ${item.type}]`));
1941
2008
  }
1942
- if (index < result.content.length - 1) {
2009
+ if (index < visibleContent.length - 1) {
1943
2010
  lines.push("");
1944
2011
  }
1945
2012
  });
1946
2013
  }
2014
+ if (hasStructured) {
2015
+ if (isError) {
2016
+ lines.push(source_default.bold("Structured error data:"));
2017
+ }
2018
+ lines.push(formatJson(structuredContent));
2019
+ }
2020
+ if (isError && !hasVisibleContent && !hasStructured) {
2021
+ lines.push(source_default.gray("(no error details provided by server)"));
2022
+ }
1947
2023
  return lines.join("\n");
1948
2024
  }
1949
2025
  function formatResourceContent(content) {
@@ -2096,28 +2172,223 @@ function formatPromptMessages(messages) {
2096
2172
  return lines.join("\n");
2097
2173
  }
2098
2174
 
2175
+ // src/utils/parse-args.ts
2176
+ function parseToolArgs(rawArgs, inputSchema) {
2177
+ if (!rawArgs || rawArgs.length === 0) return {};
2178
+ if (rawArgs.length === 1) {
2179
+ const trimmed = rawArgs[0].trim();
2180
+ if (trimmed.startsWith("{")) {
2181
+ try {
2182
+ const parsed = JSON.parse(trimmed);
2183
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
2184
+ throw new Error("expected a JSON object");
2185
+ }
2186
+ return parsed;
2187
+ } catch (err) {
2188
+ throw new Error(`Invalid JSON arguments: ${err.message}`);
2189
+ }
2190
+ }
2191
+ }
2192
+ const props = inputSchema?.properties ?? {};
2193
+ const result = {};
2194
+ for (const raw of rawArgs) {
2195
+ const token = raw.startsWith("--") ? raw.slice(2) : raw;
2196
+ const jsonIdx = token.indexOf(":=");
2197
+ const eqIdx = token.indexOf("=");
2198
+ let key;
2199
+ let rawValue;
2200
+ let forceJson = false;
2201
+ if (jsonIdx !== -1 && (eqIdx === -1 || jsonIdx < eqIdx)) {
2202
+ key = token.slice(0, jsonIdx);
2203
+ rawValue = token.slice(jsonIdx + 2);
2204
+ forceJson = true;
2205
+ } else if (eqIdx !== -1) {
2206
+ key = token.slice(0, eqIdx);
2207
+ rawValue = token.slice(eqIdx + 1);
2208
+ } else {
2209
+ throw new Error(
2210
+ `Invalid argument '${raw}'. Use key=value or key:=jsonvalue.`
2211
+ );
2212
+ }
2213
+ if (!key) {
2214
+ throw new Error(`Empty key in argument '${raw}'`);
2215
+ }
2216
+ result[key] = coerceArgValue(rawValue, props[key], forceJson, key);
2217
+ }
2218
+ return result;
2219
+ }
2220
+ function coerceArgValue(value, propSchema, forceJson, key) {
2221
+ if (forceJson) {
2222
+ try {
2223
+ return JSON.parse(value);
2224
+ } catch (err) {
2225
+ throw new Error(
2226
+ `Invalid JSON value for '${key}': ${err.message}`
2227
+ );
2228
+ }
2229
+ }
2230
+ const types = Array.isArray(propSchema?.type) ? propSchema.type : propSchema?.type ? [propSchema.type] : [];
2231
+ if (types.includes("null") && (value === "null" || value === "")) {
2232
+ return null;
2233
+ }
2234
+ if (types.includes("integer")) {
2235
+ const n = Number(value);
2236
+ if (!Number.isFinite(n) || !Number.isInteger(n)) {
2237
+ throw new Error(`Expected integer for '${key}', got '${value}'`);
2238
+ }
2239
+ return n;
2240
+ }
2241
+ if (types.includes("number")) {
2242
+ const n = Number(value);
2243
+ if (!Number.isFinite(n)) {
2244
+ throw new Error(`Expected number for '${key}', got '${value}'`);
2245
+ }
2246
+ return n;
2247
+ }
2248
+ if (types.includes("boolean")) {
2249
+ if (value === "true" || value === "1") return true;
2250
+ if (value === "false" || value === "0") return false;
2251
+ throw new Error(
2252
+ `Expected boolean (true/false) for '${key}', got '${value}'`
2253
+ );
2254
+ }
2255
+ if (types.includes("array") || types.includes("object")) {
2256
+ try {
2257
+ return JSON.parse(value);
2258
+ } catch (err) {
2259
+ const wanted = types.includes("array") ? "array" : "object";
2260
+ throw new Error(
2261
+ `Expected JSON ${wanted} for '${key}'. Tip: use ${key}:=<json>. ${err.message}`
2262
+ );
2263
+ }
2264
+ }
2265
+ return value;
2266
+ }
2267
+ function parsePromptArgs(rawArgs) {
2268
+ if (!rawArgs || rawArgs.length === 0) return {};
2269
+ if (rawArgs.length === 1) {
2270
+ const trimmed = rawArgs[0].trim();
2271
+ if (trimmed.startsWith("{")) {
2272
+ try {
2273
+ const parsed = JSON.parse(trimmed);
2274
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
2275
+ throw new Error("expected a JSON object");
2276
+ }
2277
+ const out = {};
2278
+ for (const [k, v] of Object.entries(parsed)) {
2279
+ out[k] = typeof v === "string" ? v : JSON.stringify(v);
2280
+ }
2281
+ return out;
2282
+ } catch (err) {
2283
+ throw new Error(`Invalid JSON arguments: ${err.message}`);
2284
+ }
2285
+ }
2286
+ }
2287
+ const result = {};
2288
+ for (const raw of rawArgs) {
2289
+ const token = raw.startsWith("--") ? raw.slice(2) : raw;
2290
+ const eqIdx = token.indexOf("=");
2291
+ if (eqIdx === -1) {
2292
+ throw new Error(`Invalid argument '${raw}'. Use key=value.`);
2293
+ }
2294
+ const key = token.slice(0, eqIdx);
2295
+ const value = token.slice(eqIdx + 1);
2296
+ if (!key) {
2297
+ throw new Error(`Empty key in argument '${raw}'`);
2298
+ }
2299
+ result[key] = value;
2300
+ }
2301
+ return result;
2302
+ }
2303
+
2304
+ // src/utils/oauth.ts
2305
+ import {
2306
+ auth,
2307
+ NodeOAuthClientProvider,
2308
+ OAuthFlowError,
2309
+ UnauthorizedError
2310
+ } from "mcp-use/auth/node";
2311
+ import { createInterface } from "readline";
2312
+ async function buildOAuthProvider(serverUrl, options = {}) {
2313
+ return NodeOAuthClientProvider.create(serverUrl, {
2314
+ clientName: "mcp-use CLI",
2315
+ clientUri: "https://mcp-use.com",
2316
+ storageKeyPrefix: "mcp:auth",
2317
+ ...options,
2318
+ openBrowser: async (url) => {
2319
+ console.error(`
2320
+ Open this URL in a browser to authenticate:`);
2321
+ console.error(` ${url}
2322
+ `);
2323
+ }
2324
+ });
2325
+ }
2326
+ async function runOAuthFlow(provider, serverUrl, print = console.error.bind(console)) {
2327
+ print(`\u2192 OAuth authentication required.`);
2328
+ print(
2329
+ ` Listening on http://127.0.0.1:${provider.callbackPort}/callback (waiting up to 5m)`
2330
+ );
2331
+ if (!provider.hasPendingFlow) {
2332
+ const result = await auth(provider, { serverUrl });
2333
+ if (result === "AUTHORIZED") {
2334
+ return;
2335
+ }
2336
+ if (result !== "REDIRECT") {
2337
+ throw new OAuthFlowError(
2338
+ "unexpected_auth_result",
2339
+ `auth() returned ${result}`
2340
+ );
2341
+ }
2342
+ }
2343
+ const code = await provider.getAuthorizationCode();
2344
+ await auth(provider, { serverUrl, authorizationCode: code });
2345
+ }
2346
+ function isUnauthorized(err) {
2347
+ if (err instanceof UnauthorizedError) return true;
2348
+ if (err instanceof Error && err.name === "UnauthorizedError") return true;
2349
+ if (err instanceof Error && err.code === 401) {
2350
+ return true;
2351
+ }
2352
+ return false;
2353
+ }
2354
+ async function promptYesNo(question, defaultYes = true) {
2355
+ if (!process.stdin.isTTY) return false;
2356
+ const rl = createInterface({ input: process.stdin, output: process.stderr });
2357
+ try {
2358
+ const answer = await new Promise((resolve2) => {
2359
+ rl.question(`${question} ${defaultYes ? "[Y/n] " : "[y/N] "}`, resolve2);
2360
+ });
2361
+ const trimmed = answer.trim().toLowerCase();
2362
+ if (!trimmed) return defaultYes;
2363
+ return trimmed === "y" || trimmed === "yes";
2364
+ } finally {
2365
+ rl.close();
2366
+ }
2367
+ }
2368
+
2099
2369
  // src/utils/session-storage.ts
2100
2370
  import { homedir } from "os";
2101
2371
  import { join } from "path";
2102
2372
  import { readFile, writeFile, mkdir } from "fs/promises";
2103
2373
  import { existsSync } from "fs";
2104
2374
  var SESSION_FILE_PATH = join(homedir(), ".mcp-use", "cli-sessions.json");
2375
+ var _dirEnsured = false;
2105
2376
  async function ensureSessionDir() {
2106
- const dir = join(homedir(), ".mcp-use");
2107
- if (!existsSync(dir)) {
2108
- await mkdir(dir, { recursive: true });
2109
- }
2377
+ if (_dirEnsured) return;
2378
+ await mkdir(join(homedir(), ".mcp-use"), { recursive: true });
2379
+ _dirEnsured = true;
2110
2380
  }
2111
2381
  async function loadSessions() {
2112
2382
  try {
2113
2383
  await ensureSessionDir();
2114
2384
  if (!existsSync(SESSION_FILE_PATH)) {
2115
- return { activeSession: null, sessions: {} };
2385
+ return { sessions: {} };
2116
2386
  }
2117
2387
  const content = await readFile(SESSION_FILE_PATH, "utf-8");
2118
- return JSON.parse(content);
2119
- } catch (error) {
2120
- return { activeSession: null, sessions: {} };
2388
+ const parsed = JSON.parse(content);
2389
+ return { sessions: parsed?.sessions ?? {} };
2390
+ } catch {
2391
+ return { sessions: {} };
2121
2392
  }
2122
2393
  }
2123
2394
  async function saveSessions(storage) {
@@ -2130,40 +2401,22 @@ async function saveSession(name, config) {
2130
2401
  ...config,
2131
2402
  lastUsed: (/* @__PURE__ */ new Date()).toISOString()
2132
2403
  };
2133
- if (!storage.activeSession) {
2134
- storage.activeSession = name;
2135
- }
2136
2404
  await saveSessions(storage);
2137
2405
  }
2138
- async function getActiveSession() {
2406
+ async function removeSession(name) {
2139
2407
  const storage = await loadSessions();
2140
- if (!storage.activeSession || !storage.sessions[storage.activeSession]) {
2141
- return null;
2142
- }
2143
- return {
2144
- name: storage.activeSession,
2145
- config: storage.sessions[storage.activeSession]
2146
- };
2408
+ delete storage.sessions[name];
2409
+ await saveSessions(storage);
2147
2410
  }
2148
2411
  async function getSession(name) {
2149
2412
  const storage = await loadSessions();
2150
2413
  return storage.sessions[name] || null;
2151
2414
  }
2152
- async function setActiveSession(name) {
2153
- const storage = await loadSessions();
2154
- if (!storage.sessions[name]) {
2155
- throw new Error(`Session '${name}' not found`);
2156
- }
2157
- storage.activeSession = name;
2158
- storage.sessions[name].lastUsed = (/* @__PURE__ */ new Date()).toISOString();
2159
- await saveSessions(storage);
2160
- }
2161
2415
  async function listAllSessions() {
2162
2416
  const storage = await loadSessions();
2163
2417
  return Object.entries(storage.sessions).map(([name, config]) => ({
2164
2418
  name,
2165
- config,
2166
- isActive: name === storage.activeSession
2419
+ config
2167
2420
  }));
2168
2421
  }
2169
2422
  async function updateSessionInfo(name, serverInfo, capabilities) {
@@ -2176,40 +2429,68 @@ async function updateSessionInfo(name, serverInfo, capabilities) {
2176
2429
  }
2177
2430
  }
2178
2431
 
2179
- // src/commands/client.ts
2432
+ // src/utils/session.ts
2433
+ import { MCPClient } from "mcp-use/client";
2434
+ import { getPackageVersion } from "mcp-use/server";
2180
2435
  var activeSessions = /* @__PURE__ */ new Map();
2181
- async function getOrRestoreSession(sessionName) {
2182
- if (!sessionName) {
2183
- const active = await getActiveSession();
2184
- if (!active) {
2185
- console.error(
2186
- formatError("No active session. Connect to a server first.")
2187
- );
2188
- console.error(
2189
- formatInfo("Use: npx mcp-use client connect <url> --name <name>")
2190
- );
2191
- return null;
2436
+ function getCliClientInfo() {
2437
+ return {
2438
+ name: "mcp-use CLI",
2439
+ title: "mcp-use CLI",
2440
+ version: getPackageVersion(),
2441
+ description: "mcp-use CLI - Command-line interface for MCP servers",
2442
+ icons: [
2443
+ {
2444
+ src: "https://manufact.com/logo.png"
2445
+ }
2446
+ ],
2447
+ websiteUrl: "https://manufact.com"
2448
+ };
2449
+ }
2450
+ async function cleanupAndExit(code) {
2451
+ for (const [name, { client }] of activeSessions) {
2452
+ try {
2453
+ await client.closeAllSessions();
2454
+ } catch {
2192
2455
  }
2193
- sessionName = active.name;
2456
+ activeSessions.delete(name);
2194
2457
  }
2458
+ process.exit(code);
2459
+ }
2460
+ async function getOrRestoreSession(sessionName) {
2195
2461
  if (activeSessions.has(sessionName)) {
2196
2462
  const { session } = activeSessions.get(sessionName);
2197
2463
  return { name: sessionName, session };
2198
2464
  }
2199
2465
  const config = await getSession(sessionName);
2200
2466
  if (!config) {
2201
- console.error(formatError(`Session '${sessionName}' not found`));
2467
+ console.error(formatError(`Server '${sessionName}' not found`));
2468
+ console.error(
2469
+ formatInfo(
2470
+ `Connect with: npx mcp-use client connect ${sessionName} <url>`
2471
+ )
2472
+ );
2202
2473
  return null;
2203
2474
  }
2204
2475
  try {
2205
2476
  const client = new MCPClient();
2206
2477
  const cliClientInfo = getCliClientInfo();
2478
+ let authProvider;
2207
2479
  if (config.type === "http") {
2208
- client.addServer(sessionName, {
2209
- url: config.url,
2210
- headers: config.authToken ? { Authorization: `Bearer ${config.authToken}` } : void 0,
2211
- clientInfo: cliClientInfo
2212
- });
2480
+ if (config.authMode === "oauth") {
2481
+ authProvider = await buildOAuthProvider(config.url);
2482
+ client.addServer(sessionName, {
2483
+ url: config.url,
2484
+ authProvider,
2485
+ clientInfo: cliClientInfo
2486
+ });
2487
+ } else {
2488
+ client.addServer(sessionName, {
2489
+ url: config.url,
2490
+ headers: config.authToken ? { Authorization: `Bearer ${config.authToken}` } : void 0,
2491
+ clientInfo: cliClientInfo
2492
+ });
2493
+ }
2213
2494
  } else if (config.type === "stdio") {
2214
2495
  client.addServer(sessionName, {
2215
2496
  command: config.command,
@@ -2221,37 +2502,1054 @@ async function getOrRestoreSession(sessionName) {
2221
2502
  console.error(formatError(`Unknown session type: ${config.type}`));
2222
2503
  return null;
2223
2504
  }
2224
- const session = await client.createSession(sessionName);
2225
- activeSessions.set(sessionName, { client, session });
2226
- console.error(formatInfo(`Reconnected to session '${sessionName}'`));
2227
- return { name: sessionName, session };
2228
- } catch (error) {
2229
- console.error(formatError(`Failed to restore session: ${error.message}`));
2230
- return null;
2505
+ let session;
2506
+ try {
2507
+ session = await client.createSession(sessionName);
2508
+ } catch (err) {
2509
+ if (config.type === "http" && config.authMode === "oauth" && authProvider && isUnauthorized(err)) {
2510
+ const reAuth = await promptYesNo(
2511
+ `! Tokens for server '${sessionName}' expired and could not refresh. Re-authenticate now?`,
2512
+ true
2513
+ );
2514
+ if (!reAuth) {
2515
+ console.error(formatError(`Tokens expired and could not refresh.`));
2516
+ console.error(
2517
+ formatInfo(
2518
+ `Run: mcp-use client connect ${sessionName} ${config.url}`
2519
+ )
2520
+ );
2521
+ return null;
2522
+ }
2523
+ await runOAuthFlow(authProvider, config.url);
2524
+ session = await client.createSession(sessionName);
2525
+ } else {
2526
+ throw err;
2527
+ }
2528
+ }
2529
+ activeSessions.set(sessionName, { client, session });
2530
+ return { name: sessionName, session };
2531
+ } catch (error) {
2532
+ console.error(formatError(`Failed to restore server: ${error.message}`));
2533
+ return null;
2534
+ }
2535
+ }
2536
+
2537
+ // src/commands/client-auth.ts
2538
+ async function resolveSession(name) {
2539
+ const config = await getSession(name);
2540
+ if (!config) {
2541
+ console.error(formatError(`Server '${name}' not found`));
2542
+ return null;
2543
+ }
2544
+ if (config.type !== "http") {
2545
+ console.error(formatError("Auth commands only apply to HTTP servers"));
2546
+ return null;
2547
+ }
2548
+ if (config.authMode !== "oauth") {
2549
+ console.error(
2550
+ formatError(
2551
+ `Server '${name}' was not authenticated via OAuth (authMode=${config.authMode ?? "bearer"})`
2552
+ )
2553
+ );
2554
+ return null;
2555
+ }
2556
+ return { name, url: config.url };
2557
+ }
2558
+ function formatExpiresIn(expSec) {
2559
+ const ms = expSec * 1e3 - Date.now();
2560
+ if (ms <= 0) return "expired";
2561
+ const mins = Math.round(ms / 6e4);
2562
+ if (mins < 60) return `${mins}m`;
2563
+ const hours = Math.floor(mins / 60);
2564
+ const rem = mins % 60;
2565
+ return rem ? `${hours}h${rem}m` : `${hours}h`;
2566
+ }
2567
+ function decodeJwtExp(token) {
2568
+ try {
2569
+ const parts = token.split(".");
2570
+ if (parts.length < 2) return null;
2571
+ const payload = JSON.parse(
2572
+ Buffer.from(parts[1], "base64url").toString("utf-8")
2573
+ );
2574
+ return typeof payload.exp === "number" ? payload.exp : null;
2575
+ } catch {
2576
+ return null;
2577
+ }
2578
+ }
2579
+ async function authStatusCommand(name) {
2580
+ const target = await resolveSession(name);
2581
+ if (!target) {
2582
+ process.exit(1);
2583
+ }
2584
+ const { name: serverName, url } = target;
2585
+ const provider = await buildOAuthProvider(url);
2586
+ const tokens = await provider.tokens();
2587
+ const fields = {
2588
+ server: serverName,
2589
+ url,
2590
+ tokens: tokens?.access_token ? "present" : "missing"
2591
+ };
2592
+ if (tokens?.scope) fields.scope = tokens.scope;
2593
+ if (tokens?.access_token) {
2594
+ const exp = decodeJwtExp(tokens.access_token);
2595
+ fields.expires_in = exp ? formatExpiresIn(exp) : "unknown (opaque token)";
2596
+ }
2597
+ fields.refresh = tokens?.refresh_token ? "available" : "missing";
2598
+ console.log(formatKeyValue(fields));
2599
+ if (!tokens?.access_token) process.exit(1);
2600
+ }
2601
+ async function authRefreshCommand(name) {
2602
+ const target = await resolveSession(name);
2603
+ if (!target) {
2604
+ process.exit(1);
2605
+ }
2606
+ const { name: serverName, url } = target;
2607
+ const provider = await buildOAuthProvider(url);
2608
+ const refreshed = await provider.forceRefresh();
2609
+ if (!refreshed) {
2610
+ console.error(
2611
+ formatError(
2612
+ "Refresh failed (no refresh_token, or server rejected). Re-connect to re-authenticate."
2613
+ )
2614
+ );
2615
+ console.error(
2616
+ formatInfo(`Run: mcp-use client connect ${serverName} ${url}`)
2617
+ );
2618
+ process.exit(1);
2619
+ }
2620
+ const exp = refreshed.access_token ? decodeJwtExp(refreshed.access_token) : null;
2621
+ console.log(
2622
+ formatSuccess(
2623
+ `Refreshed access token${exp ? ` (expires in ${formatExpiresIn(exp)})` : ""}`
2624
+ )
2625
+ );
2626
+ }
2627
+ async function authLogoutCommand(name) {
2628
+ const target = await resolveSession(name);
2629
+ if (!target) {
2630
+ process.exit(1);
2631
+ }
2632
+ const { name: serverName, url } = target;
2633
+ const provider = await buildOAuthProvider(url);
2634
+ await provider.invalidateCredentials("all");
2635
+ console.log(formatSuccess(`Removed tokens for ${url}`));
2636
+ console.log(
2637
+ formatInfo(
2638
+ `Server '${serverName}' kept; reconnect with \`mcp-use client connect\`.`
2639
+ )
2640
+ );
2641
+ }
2642
+
2643
+ // src/commands/screenshot.ts
2644
+ import { Command } from "commander";
2645
+ import { MCPClient as MCPClient2 } from "mcp-use/client";
2646
+ import { spawn as spawn2 } from "child_process";
2647
+ import { existsSync as existsSync2 } from "fs";
2648
+ import { mkdir as mkdir2 } from "fs/promises";
2649
+ import { createServer } from "net";
2650
+ import path6 from "path";
2651
+
2652
+ // src/utils/cdp-screenshot.ts
2653
+ import { spawn } from "child_process";
2654
+ import { mkdtempSync, rmSync, writeFileSync } from "fs";
2655
+ import os4 from "os";
2656
+ import path4 from "path";
2657
+ import WebSocket from "ws";
2658
+ var CdpClient = class {
2659
+ constructor(ws) {
2660
+ this.ws = ws;
2661
+ ws.on("message", (data) => {
2662
+ let msg;
2663
+ try {
2664
+ msg = JSON.parse(data.toString());
2665
+ } catch {
2666
+ return;
2667
+ }
2668
+ if (typeof msg.id !== "number") return;
2669
+ const cb = this.pending.get(msg.id);
2670
+ if (!cb) return;
2671
+ this.pending.delete(msg.id);
2672
+ if (msg.error) {
2673
+ cb.reject(new Error(msg.error.message ?? "CDP error"));
2674
+ } else {
2675
+ cb.resolve(msg.result ?? {});
2676
+ }
2677
+ });
2678
+ ws.on("close", () => {
2679
+ for (const cb of this.pending.values()) {
2680
+ cb.reject(new Error("CDP WebSocket closed"));
2681
+ }
2682
+ this.pending.clear();
2683
+ });
2684
+ ws.on("error", (err) => {
2685
+ for (const cb of this.pending.values()) {
2686
+ cb.reject(err);
2687
+ }
2688
+ this.pending.clear();
2689
+ });
2690
+ }
2691
+ nextId = 0;
2692
+ pending = /* @__PURE__ */ new Map();
2693
+ send(method, params = {}, sessionId) {
2694
+ const id = ++this.nextId;
2695
+ const payload = { id, method, params };
2696
+ if (sessionId) payload.sessionId = sessionId;
2697
+ return new Promise((resolve2, reject) => {
2698
+ this.pending.set(id, {
2699
+ resolve: (r) => resolve2(r),
2700
+ reject
2701
+ });
2702
+ this.ws.send(JSON.stringify(payload));
2703
+ });
2704
+ }
2705
+ close() {
2706
+ try {
2707
+ this.ws.close();
2708
+ } catch {
2709
+ }
2710
+ }
2711
+ };
2712
+ function waitForDevToolsUrl(child, timeoutMs = 5e3) {
2713
+ return new Promise((resolve2, reject) => {
2714
+ let buf = "";
2715
+ const onData = (d) => {
2716
+ buf += d.toString();
2717
+ const m = buf.match(/DevTools listening on (ws:\/\/\S+)/);
2718
+ if (m) {
2719
+ cleanup();
2720
+ resolve2(m[1]);
2721
+ }
2722
+ };
2723
+ const onExit = (code) => {
2724
+ cleanup();
2725
+ reject(
2726
+ new Error(
2727
+ `Chrome exited (code ${code}) before exposing a DevTools port. Last stderr: ${buf.slice(-500)}`
2728
+ )
2729
+ );
2730
+ };
2731
+ const cleanup = () => {
2732
+ child.stderr?.off("data", onData);
2733
+ child.off("exit", onExit);
2734
+ clearTimeout(timer);
2735
+ };
2736
+ const timer = setTimeout(() => {
2737
+ cleanup();
2738
+ reject(
2739
+ new Error(`Chrome did not expose a DevTools port within ${timeoutMs}ms`)
2740
+ );
2741
+ }, timeoutMs);
2742
+ child.stderr?.on("data", onData);
2743
+ child.on("exit", onExit);
2744
+ });
2745
+ }
2746
+ async function captureScreenshot(opts) {
2747
+ let userDataDir;
2748
+ let child;
2749
+ let cdp;
2750
+ let cleanedUp = false;
2751
+ const cleanup = () => {
2752
+ if (cleanedUp) return;
2753
+ cleanedUp = true;
2754
+ cdp?.close();
2755
+ if (child && !child.killed) {
2756
+ try {
2757
+ child.kill("SIGTERM");
2758
+ } catch {
2759
+ }
2760
+ const localChild = child;
2761
+ const killTimer = setTimeout(() => {
2762
+ if (!localChild.killed) {
2763
+ try {
2764
+ localChild.kill("SIGKILL");
2765
+ } catch {
2766
+ }
2767
+ }
2768
+ }, 2e3);
2769
+ killTimer.unref();
2770
+ }
2771
+ if (userDataDir) {
2772
+ try {
2773
+ rmSync(userDataDir, { recursive: true, force: true });
2774
+ } catch {
2775
+ }
2776
+ }
2777
+ };
2778
+ try {
2779
+ let wsUrl;
2780
+ if (opts.cdpUrl) {
2781
+ wsUrl = opts.cdpUrl;
2782
+ } else {
2783
+ if (!opts.chromePath) {
2784
+ throw new Error(
2785
+ "captureScreenshot requires either `cdpUrl` or `chromePath`"
2786
+ );
2787
+ }
2788
+ userDataDir = mkdtempSync(path4.join(os4.tmpdir(), "mcp-use-chrome-"));
2789
+ const chromeArgs = [
2790
+ "--headless=new",
2791
+ "--remote-debugging-port=0",
2792
+ `--user-data-dir=${userDataDir}`,
2793
+ "--no-first-run",
2794
+ "--no-default-browser-check",
2795
+ "--disable-extensions",
2796
+ "--disable-gpu",
2797
+ "--hide-scrollbars",
2798
+ "--mute-audio",
2799
+ `--window-size=${opts.width},${opts.height}`,
2800
+ "about:blank"
2801
+ ];
2802
+ child = spawn(opts.chromePath, chromeArgs, {
2803
+ stdio: ["ignore", "pipe", "pipe"]
2804
+ });
2805
+ child.stdout?.resume();
2806
+ wsUrl = await waitForDevToolsUrl(child);
2807
+ }
2808
+ const ws = new WebSocket(wsUrl);
2809
+ await new Promise((resolve2, reject) => {
2810
+ const onOpen = () => {
2811
+ ws.off("error", onError);
2812
+ resolve2();
2813
+ };
2814
+ const onError = (err) => {
2815
+ ws.off("open", onOpen);
2816
+ reject(err);
2817
+ };
2818
+ ws.once("open", onOpen);
2819
+ ws.once("error", onError);
2820
+ });
2821
+ cdp = new CdpClient(ws);
2822
+ let sessionId;
2823
+ if (opts.cdpUrl) {
2824
+ const attachPromise = new Promise((resolve2, reject) => {
2825
+ const timer = setTimeout(
2826
+ () => reject(
2827
+ new Error(
2828
+ "Timed out waiting for Target.attachedToTarget event from remote CDP"
2829
+ )
2830
+ ),
2831
+ 1e4
2832
+ );
2833
+ const onMessage = (data) => {
2834
+ try {
2835
+ const msg = JSON.parse(data.toString());
2836
+ if (msg.method === "Target.attachedToTarget" && msg.params?.targetInfo?.type === "page" && typeof msg.params.sessionId === "string") {
2837
+ clearTimeout(timer);
2838
+ ws.off("message", onMessage);
2839
+ resolve2(msg.params.sessionId);
2840
+ }
2841
+ } catch {
2842
+ }
2843
+ };
2844
+ ws.on("message", onMessage);
2845
+ });
2846
+ await cdp.send("Target.setAutoAttach", {
2847
+ autoAttach: true,
2848
+ waitForDebuggerOnStart: false,
2849
+ flatten: true
2850
+ });
2851
+ sessionId = await attachPromise;
2852
+ } else {
2853
+ const { targetId } = await cdp.send(
2854
+ "Target.createTarget",
2855
+ { url: "about:blank" }
2856
+ );
2857
+ const attach = await cdp.send(
2858
+ "Target.attachToTarget",
2859
+ { targetId, flatten: true }
2860
+ );
2861
+ sessionId = attach.sessionId;
2862
+ }
2863
+ await cdp.send("Page.enable", {}, sessionId);
2864
+ await cdp.send(
2865
+ "Emulation.setDeviceMetricsOverride",
2866
+ {
2867
+ width: opts.width,
2868
+ height: opts.height,
2869
+ deviceScaleFactor: 1,
2870
+ mobile: false
2871
+ },
2872
+ sessionId
2873
+ );
2874
+ await cdp.send(
2875
+ "Emulation.setEmulatedMedia",
2876
+ {
2877
+ features: [
2878
+ { name: "prefers-color-scheme", value: opts.theme },
2879
+ { name: "prefers-reduced-motion", value: "reduce" }
2880
+ ]
2881
+ },
2882
+ sessionId
2883
+ );
2884
+ if (opts.bundle !== void 0) {
2885
+ const payload = JSON.stringify(JSON.stringify(opts.bundle));
2886
+ await cdp.send(
2887
+ "Page.addScriptToEvaluateOnNewDocument",
2888
+ {
2889
+ source: `globalThis.__mcpUsePreviewBundle = JSON.parse(${payload});`,
2890
+ runImmediately: true
2891
+ },
2892
+ sessionId
2893
+ );
2894
+ }
2895
+ await cdp.send("Page.navigate", { url: opts.url }, sessionId);
2896
+ const start = Date.now();
2897
+ const exprSelector = JSON.stringify(opts.waitForSelector);
2898
+ while (true) {
2899
+ const r = await cdp.send(
2900
+ "Runtime.evaluate",
2901
+ {
2902
+ expression: `!!document.querySelector(${exprSelector})`,
2903
+ returnByValue: true
2904
+ },
2905
+ sessionId
2906
+ );
2907
+ if (r.result?.value === true) break;
2908
+ if (Date.now() - start > opts.timeoutMs) {
2909
+ throw new Error(
2910
+ `Timed out after ${opts.timeoutMs}ms waiting for selector "${opts.waitForSelector}"`
2911
+ );
2912
+ }
2913
+ await new Promise((res) => setTimeout(res, 100));
2914
+ }
2915
+ if (opts.delayMs && opts.delayMs > 0) {
2916
+ await new Promise((res) => setTimeout(res, opts.delayMs));
2917
+ }
2918
+ const shot = await cdp.send(
2919
+ "Page.captureScreenshot",
2920
+ {
2921
+ format: "png",
2922
+ clip: {
2923
+ x: 0,
2924
+ y: 0,
2925
+ width: opts.width,
2926
+ height: opts.height,
2927
+ scale: 1
2928
+ }
2929
+ },
2930
+ sessionId
2931
+ );
2932
+ writeFileSync(opts.outputPath, Buffer.from(shot.data, "base64"));
2933
+ } finally {
2934
+ cleanup();
2935
+ }
2936
+ }
2937
+
2938
+ // src/utils/chrome-path.ts
2939
+ import { accessSync, constants } from "fs";
2940
+ import path5 from "path";
2941
+ var ENV_VAR_NAMES = [
2942
+ "MCP_USE_CHROME_PATH",
2943
+ "PUPPETEER_EXECUTABLE_PATH",
2944
+ "CHROME_PATH"
2945
+ ];
2946
+ var DARWIN_PATHS = [
2947
+ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
2948
+ "/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary",
2949
+ "/Applications/Chromium.app/Contents/MacOS/Chromium",
2950
+ "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
2951
+ "/Applications/Brave Browser.app/Contents/MacOS/Brave Browser"
2952
+ ];
2953
+ var LINUX_BINARIES = [
2954
+ "google-chrome-stable",
2955
+ "google-chrome",
2956
+ "chromium",
2957
+ "chromium-browser",
2958
+ "microsoft-edge",
2959
+ "microsoft-edge-stable",
2960
+ "brave-browser"
2961
+ ];
2962
+ var WIN_SUBPATHS = [
2963
+ "Google\\Chrome\\Application\\chrome.exe",
2964
+ "Microsoft\\Edge\\Application\\msedge.exe",
2965
+ "BraveSoftware\\Brave-Browser\\Application\\brave.exe",
2966
+ "Chromium\\Application\\chrome.exe"
2967
+ ];
2968
+ function isAccessible(p) {
2969
+ try {
2970
+ accessSync(p, constants.F_OK);
2971
+ return true;
2972
+ } catch {
2973
+ return false;
2974
+ }
2975
+ }
2976
+ function findOnPath(binary) {
2977
+ const PATH = process.env.PATH ?? "";
2978
+ for (const dir of PATH.split(":")) {
2979
+ if (!dir) continue;
2980
+ const candidate = path5.posix.join(dir, binary);
2981
+ if (isAccessible(candidate)) return candidate;
2982
+ }
2983
+ return null;
2984
+ }
2985
+ function findChrome() {
2986
+ for (const name of ENV_VAR_NAMES) {
2987
+ const v = process.env[name];
2988
+ if (v && isAccessible(v)) return v;
2989
+ }
2990
+ if (process.platform === "darwin") {
2991
+ for (const p of DARWIN_PATHS) {
2992
+ if (isAccessible(p)) return p;
2993
+ }
2994
+ return null;
2995
+ }
2996
+ if (process.platform === "linux") {
2997
+ for (const bin of LINUX_BINARIES) {
2998
+ const p = findOnPath(bin);
2999
+ if (p) return p;
3000
+ }
3001
+ return null;
3002
+ }
3003
+ if (process.platform === "win32") {
3004
+ const dirs = [
3005
+ process.env["ProgramFiles"],
3006
+ process.env["ProgramFiles(x86)"],
3007
+ process.env["LocalAppData"]
3008
+ ].filter((d) => Boolean(d));
3009
+ for (const dir of dirs) {
3010
+ for (const sub of WIN_SUBPATHS) {
3011
+ const candidate = path5.join(dir, sub);
3012
+ if (isAccessible(candidate)) return candidate;
3013
+ }
3014
+ }
3015
+ return null;
3016
+ }
3017
+ return null;
3018
+ }
3019
+ function resolveChromePath() {
3020
+ const found = findChrome();
3021
+ if (found) return found;
3022
+ throw new Error(
3023
+ "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."
3024
+ );
3025
+ }
3026
+
3027
+ // src/commands/screenshot.ts
3028
+ function parseHeaderArg(raw) {
3029
+ const idx = raw.indexOf(":");
3030
+ if (idx === -1) {
3031
+ throw new Error(
3032
+ `Invalid --header value "${raw}". Expected "Key: Value" (e.g. "Authorization: Bearer xyz").`
3033
+ );
3034
+ }
3035
+ const key = raw.slice(0, idx).trim();
3036
+ const value = raw.slice(idx + 1).trim();
3037
+ if (!key) {
3038
+ throw new Error(`Invalid --header value "${raw}". Header name is empty.`);
3039
+ }
3040
+ return [key, value];
3041
+ }
3042
+ function parseHeaderArgs(args) {
3043
+ const headers = {};
3044
+ for (const raw of args) {
3045
+ const [key, value] = parseHeaderArg(raw);
3046
+ headers[key] = value;
3047
+ }
3048
+ return headers;
3049
+ }
3050
+ function collectHeader(value, previous = []) {
3051
+ return previous.concat([value]);
3052
+ }
3053
+ function detectToolResourceUri(tool) {
3054
+ if (!tool) return null;
3055
+ const meta = tool._meta;
3056
+ if (!meta) return null;
3057
+ const uiMeta = meta.ui ?? void 0;
3058
+ return uiMeta?.resourceUri ?? meta["openai/outputTemplate"] ?? null;
3059
+ }
3060
+ async function captureToolScreenshot(inputs, options = {}) {
3061
+ const width = options.width ?? 800;
3062
+ const height = options.height ?? 600;
3063
+ const theme = options.theme ?? "light";
3064
+ const timeoutMs = options.timeoutMs ?? 3e4;
3065
+ const delayMs = options.delayMs ?? 0;
3066
+ const chromePath = options.cdpUrl ? void 0 : resolveChromePath();
3067
+ const view = extractViewName(inputs.resourceUri);
3068
+ const devOptions = {
3069
+ width: String(width),
3070
+ height: String(height),
3071
+ theme,
3072
+ timeout: String(timeoutMs),
3073
+ inspector: options.inspector,
3074
+ quiet: options.quiet
3075
+ };
3076
+ let devHandle;
3077
+ try {
3078
+ devHandle = await ensureDevServer(devOptions);
3079
+ const resourceContents = await inputs.session.readResource(
3080
+ inputs.resourceUri
3081
+ );
3082
+ const bundle = {
3083
+ resourceUri: inputs.resourceUri,
3084
+ resourceContents,
3085
+ toolInput: inputs.toolArgs,
3086
+ toolOutput: inputs.toolOutput
3087
+ };
3088
+ const previewUrl = new URL(`/inspector/preview/${view}`, devHandle.url);
3089
+ previewUrl.searchParams.set("theme", theme);
3090
+ const ts = timestampSuffix();
3091
+ const outputPath = path6.resolve(options.output ?? `./${view}-${ts}.png`);
3092
+ await mkdir2(path6.dirname(outputPath), { recursive: true });
3093
+ await captureScreenshot({
3094
+ url: previewUrl.toString(),
3095
+ width,
3096
+ height,
3097
+ theme,
3098
+ waitForSelector: options.waitFor ?? 'body[data-view-ready="true"]',
3099
+ timeoutMs,
3100
+ outputPath,
3101
+ chromePath,
3102
+ cdpUrl: options.cdpUrl,
3103
+ delayMs: Number.isFinite(delayMs) && delayMs > 0 ? delayMs : 0,
3104
+ bundle
3105
+ });
3106
+ return { outputPath, width, height, view };
3107
+ } finally {
3108
+ killChild(devHandle?.child);
3109
+ }
3110
+ }
3111
+ function getFreePort() {
3112
+ return new Promise((resolve2, reject) => {
3113
+ const srv = createServer();
3114
+ srv.unref();
3115
+ srv.on("error", reject);
3116
+ srv.listen(0, () => {
3117
+ const addr = srv.address();
3118
+ if (typeof addr === "object" && addr) {
3119
+ const port = addr.port;
3120
+ srv.close(() => resolve2(port));
3121
+ } else {
3122
+ srv.close(() => reject(new Error("Failed to allocate free port")));
3123
+ }
3124
+ });
3125
+ });
3126
+ }
3127
+ async function probeServer(url, timeoutMs = 1500) {
3128
+ const controller = new AbortController();
3129
+ const t = setTimeout(() => controller.abort(), timeoutMs);
3130
+ try {
3131
+ const u = new URL("/inspector/health", url);
3132
+ const res = await fetch(u, { signal: controller.signal });
3133
+ if (!res.ok) return false;
3134
+ const ct = res.headers.get("content-type") ?? "";
3135
+ if (!ct.includes("application/json")) return false;
3136
+ const body = await res.json();
3137
+ return body?.status === "ok";
3138
+ } catch {
3139
+ return false;
3140
+ } finally {
3141
+ clearTimeout(t);
3142
+ }
3143
+ }
3144
+ async function waitForHealth(url, timeoutMs = 15e3) {
3145
+ const deadline = Date.now() + timeoutMs;
3146
+ while (Date.now() < deadline) {
3147
+ if (await probeServer(url)) return true;
3148
+ await new Promise((r) => setTimeout(r, 200));
3149
+ }
3150
+ return false;
3151
+ }
3152
+ function resolveInspectorCli() {
3153
+ const candidateRoots = /* @__PURE__ */ new Set();
3154
+ const moduleDir = typeof __dirname !== "undefined" ? __dirname : path6.dirname(new URL(import.meta.url).pathname);
3155
+ candidateRoots.add(moduleDir);
3156
+ candidateRoots.add(process.cwd());
3157
+ for (const start of candidateRoots) {
3158
+ let dir = start;
3159
+ while (true) {
3160
+ const candidate = path6.join(
3161
+ dir,
3162
+ "node_modules",
3163
+ "@mcp-use",
3164
+ "inspector",
3165
+ "dist",
3166
+ "cli.js"
3167
+ );
3168
+ if (existsSync2(candidate)) return candidate;
3169
+ const parent = path6.dirname(dir);
3170
+ if (parent === dir) break;
3171
+ dir = parent;
3172
+ }
3173
+ }
3174
+ throw new Error(
3175
+ "Could not locate `@mcp-use/inspector` in node_modules. Install the inspector package or pass --inspector <url> to use an existing instance."
3176
+ );
3177
+ }
3178
+ async function ensureDevServer(options) {
3179
+ if (options.inspector) {
3180
+ const ok = await probeServer(options.inspector);
3181
+ if (!ok) {
3182
+ throw new Error(
3183
+ `Inspector at ${options.inspector} did not respond on /inspector/health with status:"ok"`
3184
+ );
3185
+ }
3186
+ return { url: options.inspector };
3187
+ }
3188
+ const port = await getFreePort();
3189
+ const url = `http://localhost:${port}`;
3190
+ if (!options.quiet) {
3191
+ console.error(formatInfo(`Starting inspector on port ${port}\u2026`));
3192
+ }
3193
+ const inspectorCli = resolveInspectorCli();
3194
+ const child = spawn2(
3195
+ process.execPath,
3196
+ [inspectorCli, "--port", String(port), "--no-open"],
3197
+ {
3198
+ cwd: process.cwd(),
3199
+ stdio: ["ignore", "pipe", "pipe"],
3200
+ env: { ...process.env, MCP_INSPECTOR_MODE: "standalone" }
3201
+ }
3202
+ );
3203
+ const prefix = source_default.gray("[inspector]");
3204
+ if (!options.quiet) {
3205
+ child.stdout?.on("data", (d) => {
3206
+ process.stderr.write(`${prefix} ${d}`);
3207
+ });
3208
+ child.stderr?.on("data", (d) => {
3209
+ process.stderr.write(`${prefix} ${d}`);
3210
+ });
3211
+ } else {
3212
+ child.stdout?.resume();
3213
+ child.stderr?.resume();
3214
+ }
3215
+ const ready = await waitForHealth(url);
3216
+ if (!ready) {
3217
+ child.kill("SIGTERM");
3218
+ throw new Error(`Inspector failed to come up on ${url} within 15s.`);
3219
+ }
3220
+ return { url, child };
3221
+ }
3222
+ function killChild(child) {
3223
+ if (!child || child.killed) return;
3224
+ try {
3225
+ child.kill("SIGTERM");
3226
+ } catch {
3227
+ }
3228
+ }
3229
+ function timestampSuffix(date = /* @__PURE__ */ new Date()) {
3230
+ const pad = (n) => String(n).padStart(2, "0");
3231
+ const datePart = `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
3232
+ const timePart = `${pad(date.getHours())}-${pad(date.getMinutes())}-${pad(date.getSeconds())}`;
3233
+ return `${datePart}_${timePart}`;
3234
+ }
3235
+ function extractViewName(resourceUri) {
3236
+ const m = resourceUri.match(/^ui:\/\/widget\/(.+)$/);
3237
+ if (!m) return resourceUri;
3238
+ return m[1].replace(/\.html$/, "").replace(/\.[0-9a-f]+$/i, "");
3239
+ }
3240
+ function parseDimension(raw, name) {
3241
+ const n = parseInt(raw, 10);
3242
+ if (!Number.isFinite(n) || n <= 0) {
3243
+ throw new Error(`--${name} must be a positive integer (got "${raw}")`);
3244
+ }
3245
+ return n;
3246
+ }
3247
+ var AD_HOC_SESSION_NAME = "__screenshot_ad_hoc__";
3248
+ async function resolveSessionForScreenshot(options, sessionName, headers) {
3249
+ if (sessionName) {
3250
+ const result = await getOrRestoreSession(sessionName);
3251
+ return result?.session ?? null;
3252
+ }
3253
+ if (options.mcp) {
3254
+ const client = new MCPClient2();
3255
+ client.addServer(AD_HOC_SESSION_NAME, {
3256
+ url: options.mcp,
3257
+ ...headers ? { headers } : {},
3258
+ clientInfo: getCliClientInfo()
3259
+ });
3260
+ try {
3261
+ const session = await client.createSession(AD_HOC_SESSION_NAME);
3262
+ activeSessions.set(AD_HOC_SESSION_NAME, { client, session });
3263
+ return session;
3264
+ } catch (err) {
3265
+ const msg = err instanceof Error ? err.message : String(err);
3266
+ console.error(formatError(`Failed to connect to ${options.mcp}: ${msg}`));
3267
+ return null;
3268
+ }
3269
+ }
3270
+ console.error(
3271
+ formatError(
3272
+ "No MCP target. Pass --mcp <url> for an ad-hoc connection, or use `mcp-use client <name> screenshot` for a saved server."
3273
+ )
3274
+ );
3275
+ return null;
3276
+ }
3277
+ async function screenshotCommand(options, argsList, context) {
3278
+ let exitCode = 0;
3279
+ try {
3280
+ if (!options.tool) {
3281
+ console.error(
3282
+ formatError(
3283
+ "--tool <name> is required (optionally with key=value args)."
3284
+ )
3285
+ );
3286
+ exitCode = 1;
3287
+ return;
3288
+ }
3289
+ let headers;
3290
+ if (options.header && options.header.length > 0) {
3291
+ if (!options.mcp) {
3292
+ console.error(
3293
+ formatError(
3294
+ "--header is only supported with --mcp <url>. Saved servers carry their own auth from `mcp-use client connect`."
3295
+ )
3296
+ );
3297
+ exitCode = 1;
3298
+ return;
3299
+ }
3300
+ try {
3301
+ headers = parseHeaderArgs(options.header);
3302
+ } catch (err) {
3303
+ console.error(
3304
+ formatError(err instanceof Error ? err.message : String(err))
3305
+ );
3306
+ exitCode = 1;
3307
+ return;
3308
+ }
3309
+ }
3310
+ try {
3311
+ resolveChromePath();
3312
+ } catch (err) {
3313
+ console.error(
3314
+ formatError(err instanceof Error ? err.message : String(err))
3315
+ );
3316
+ exitCode = 1;
3317
+ return;
3318
+ }
3319
+ const width = parseDimension(options.width, "width");
3320
+ const height = parseDimension(options.height, "height");
3321
+ const navTimeout = parseInt(options.timeout, 10) || 3e4;
3322
+ const delayMs = options.delay ? parseInt(options.delay, 10) : 0;
3323
+ const session = await resolveSessionForScreenshot(
3324
+ options,
3325
+ context.sessionName,
3326
+ headers
3327
+ );
3328
+ if (!session) {
3329
+ exitCode = 1;
3330
+ return;
3331
+ }
3332
+ const tool = session.tools.find((t) => t.name === options.tool);
3333
+ if (!tool) {
3334
+ throw new Error(
3335
+ `Tool "${options.tool}" not found. Available: ${session.tools.map((t) => t.name).join(", ")}`
3336
+ );
3337
+ }
3338
+ const resourceUri = detectToolResourceUri(tool);
3339
+ if (!resourceUri) {
3340
+ throw new Error(
3341
+ `Tool "${options.tool}" does not declare a UI resource (expected _meta.ui.resourceUri or openai/outputTemplate).`
3342
+ );
3343
+ }
3344
+ let toolArgs = {};
3345
+ if (argsList && argsList.length > 0) {
3346
+ try {
3347
+ toolArgs = parseToolArgs(
3348
+ argsList,
3349
+ tool.inputSchema
3350
+ );
3351
+ } catch (err) {
3352
+ console.error(
3353
+ formatError(err instanceof Error ? err.message : String(err))
3354
+ );
3355
+ console.log("");
3356
+ console.log(formatInfo("Usage:"));
3357
+ console.log(
3358
+ ` npx ${context.usagePrefix} --tool ${options.tool} key=value [key2=value2 ...]`
3359
+ );
3360
+ console.log(
3361
+ ` npx ${context.usagePrefix} --tool ${options.tool} nested:='{"a":1}' # JSON value`
3362
+ );
3363
+ console.log(
3364
+ ` npx ${context.usagePrefix} --tool ${options.tool} '{"key":"value"}' # full JSON object`
3365
+ );
3366
+ if (tool.inputSchema) {
3367
+ console.log("");
3368
+ console.log(formatInfo("Tool schema:"));
3369
+ console.log(formatSchema(tool.inputSchema));
3370
+ }
3371
+ exitCode = 1;
3372
+ return;
3373
+ }
3374
+ }
3375
+ const toolOutput = await session.callTool(options.tool, toolArgs);
3376
+ const result = await captureToolScreenshot(
3377
+ {
3378
+ session,
3379
+ toolName: options.tool,
3380
+ toolArgs,
3381
+ toolOutput,
3382
+ resourceUri
3383
+ },
3384
+ {
3385
+ width,
3386
+ height,
3387
+ theme: options.theme,
3388
+ output: options.output,
3389
+ waitFor: options.waitFor,
3390
+ delayMs,
3391
+ timeoutMs: navTimeout,
3392
+ inspector: options.inspector,
3393
+ quiet: options.quiet,
3394
+ cdpUrl: options.cdpUrl
3395
+ }
3396
+ );
3397
+ console.log(
3398
+ `Saved screenshot: ${result.outputPath} (${result.width}\xD7${result.height})`
3399
+ );
3400
+ } catch (err) {
3401
+ const msg = err instanceof Error ? err.message : String(err);
3402
+ console.error(formatError(`Screenshot failed: ${msg}`));
3403
+ exitCode = 1;
3404
+ } finally {
3405
+ await cleanupAndExit(exitCode);
3406
+ }
3407
+ }
3408
+ function withCommonScreenshotOptions(cmd) {
3409
+ return cmd.argument(
3410
+ "[args...]",
3411
+ "Tool args as key=value pairs (use key:=<json> for nested values, or pass a single JSON object)."
3412
+ ).option(
3413
+ "--tool <name>",
3414
+ "Tool to call. Its UI resource is rendered with the result."
3415
+ ).option("--width <px>", "Browser viewport width in pixels.", "800").option("--height <px>", "Browser viewport height in pixels.", "600").option(
3416
+ "--inspector <url>",
3417
+ "Inspector host that serves /inspector/preview/:view. When omitted, auto-spawns `@mcp-use/inspector` on a free port."
3418
+ ).option(
3419
+ "--theme <light|dark>",
3420
+ "Color scheme to render the view in.",
3421
+ "light"
3422
+ ).option(
3423
+ "--output <path>",
3424
+ "Output PNG path. Defaults to ./<view>-<timestamp>.png in cwd."
3425
+ ).option(
3426
+ "--wait-for <selector>",
3427
+ 'Override readiness selector (default: body[data-view-ready="true"]).'
3428
+ ).option(
3429
+ "--delay <ms>",
3430
+ "Extra wait after readiness, to let chart animations / async layouts settle.",
3431
+ "0"
3432
+ ).option("--timeout <ms>", "Navigation + readiness timeout in ms.", "30000").option(
3433
+ "--cdp-url <url>",
3434
+ "Connect to an existing CDP WebSocket (ws:// or wss://) instead of spawning local Chrome. Useful for hosted browsers like Notte."
3435
+ ).option("--quiet", "Suppress dev-server output.");
3436
+ }
3437
+ function createClientScreenshotCommand() {
3438
+ const cmd = withCommonScreenshotOptions(
3439
+ new Command("screenshot").description(
3440
+ "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`."
3441
+ )
3442
+ ).option(
3443
+ "--mcp <url>",
3444
+ "Ad-hoc MCP server URL. Required for the top-level form. No authentication unless --header is supplied."
3445
+ ).option(
3446
+ "-H, --header <header>",
3447
+ '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.',
3448
+ collectHeader,
3449
+ []
3450
+ );
3451
+ cmd.action(async (args, opts) => {
3452
+ await screenshotCommand(opts, args, {
3453
+ usagePrefix: "mcp-use client screenshot"
3454
+ });
3455
+ });
3456
+ return cmd;
3457
+ }
3458
+ function createPerClientScreenshotCommand(name) {
3459
+ const cmd = withCommonScreenshotOptions(
3460
+ new Command("screenshot").description(
3461
+ `Render an MCP Apps view headlessly using the saved server '${name}'.`
3462
+ )
3463
+ );
3464
+ cmd.action(async (args, opts) => {
3465
+ await screenshotCommand(opts, args, {
3466
+ sessionName: name,
3467
+ usagePrefix: `mcp-use client ${name} screenshot`
3468
+ });
3469
+ });
3470
+ return cmd;
3471
+ }
3472
+
3473
+ // src/commands/client.ts
3474
+ var RESERVED_CLIENT_SUBCOMMANDS = /* @__PURE__ */ new Set([
3475
+ "connect",
3476
+ "list",
3477
+ "remove",
3478
+ "screenshot",
3479
+ "help"
3480
+ ]);
3481
+ var PER_CLIENT_SCOPES = /* @__PURE__ */ new Set([
3482
+ "tools",
3483
+ "resources",
3484
+ "prompts",
3485
+ "auth",
3486
+ "disconnect",
3487
+ "interactive",
3488
+ "screenshot"
3489
+ ]);
3490
+ async function connectCommand(name, urlOrCommand, options) {
3491
+ if (!name || !urlOrCommand) {
3492
+ const looksLikeUrl = !!name && /^https?:\/\//i.test(name);
3493
+ if (looksLikeUrl && !urlOrCommand && !options.stdio) {
3494
+ console.error(formatError("Missing server name."));
3495
+ console.error("");
3496
+ console.error(
3497
+ formatInfo(
3498
+ "Each saved server needs a short name you'll use to address it later."
3499
+ )
3500
+ );
3501
+ console.error("");
3502
+ console.error("Try:");
3503
+ console.error(` mcp-use client connect <name> ${name}`);
3504
+ console.error("");
3505
+ console.error("Example:");
3506
+ console.error(` mcp-use client connect my-server ${name}`);
3507
+ console.error(" mcp-use client my-server tools list");
3508
+ } else if (name && !urlOrCommand) {
3509
+ console.error(
3510
+ formatError(options.stdio ? "Missing <command>." : "Missing <url>.")
3511
+ );
3512
+ console.error("");
3513
+ console.error(formatInfo("Usage:"));
3514
+ console.error(
3515
+ options.stdio ? ` mcp-use client connect ${name} "<command>" --stdio` : ` mcp-use client connect ${name} <url>`
3516
+ );
3517
+ } else {
3518
+ console.error(formatError("Missing required arguments: <name> <url>."));
3519
+ console.error("");
3520
+ console.error(formatInfo("Usage:"));
3521
+ console.error(" mcp-use client connect <name> <url>");
3522
+ console.error("");
3523
+ console.error("Example:");
3524
+ console.error(
3525
+ " mcp-use client connect manufact https://mcp.manufact.com/mcp"
3526
+ );
3527
+ }
3528
+ await cleanupAndExit(1);
3529
+ }
3530
+ const sessionName = name;
3531
+ const target = urlOrCommand;
3532
+ if (PER_CLIENT_SCOPES.has(sessionName)) {
3533
+ console.error(
3534
+ formatError(
3535
+ `'${sessionName}' is a reserved name and can't be used for a saved server.`
3536
+ )
3537
+ );
3538
+ console.error("");
3539
+ console.error(
3540
+ `Reserved names: ${Array.from(PER_CLIENT_SCOPES).sort().join(", ")}`
3541
+ );
3542
+ console.error("");
3543
+ console.error("Pick a different name, e.g.:");
3544
+ console.error(` mcp-use client connect my-${sessionName} ${target}`);
3545
+ await cleanupAndExit(1);
2231
3546
  }
2232
- }
2233
- function getCliClientInfo() {
2234
- return {
2235
- name: "mcp-use CLI",
2236
- title: "mcp-use CLI",
2237
- version: getPackageVersion(),
2238
- description: "mcp-use CLI - Command-line interface for MCP servers",
2239
- icons: [
2240
- {
2241
- src: "https://manufact.com/logo.png"
2242
- }
2243
- ],
2244
- websiteUrl: "https://manufact.com"
2245
- };
2246
- }
2247
- async function connectCommand(urlOrCommand, options) {
2248
3547
  try {
2249
- const sessionName = options.name || `session-${Date.now()}`;
2250
- const client = new MCPClient();
3548
+ const client = new MCPClient3();
2251
3549
  let session;
2252
3550
  const cliClientInfo = getCliClientInfo();
2253
3551
  if (options.stdio) {
2254
- const parts = urlOrCommand.split(" ");
3552
+ const parts = target.split(" ");
2255
3553
  const command = parts[0];
2256
3554
  const args = parts.slice(1);
2257
3555
  console.error(
@@ -2270,17 +3568,41 @@ async function connectCommand(urlOrCommand, options) {
2270
3568
  lastUsed: (/* @__PURE__ */ new Date()).toISOString()
2271
3569
  });
2272
3570
  } else {
2273
- console.error(formatInfo(`Connecting to ${urlOrCommand}...`));
3571
+ console.error(formatInfo(`Connecting to ${target}...`));
3572
+ const wantOAuth = !options.auth && options.oauth !== false;
3573
+ let authProvider;
3574
+ if (wantOAuth) {
3575
+ const authTimeoutMs = options.authTimeout ? Number.parseInt(options.authTimeout, 10) : void 0;
3576
+ authProvider = await buildOAuthProvider(target, {
3577
+ ...authTimeoutMs ? { authTimeoutMs } : {}
3578
+ });
3579
+ }
2274
3580
  client.addServer(sessionName, {
2275
- url: urlOrCommand,
2276
- headers: options.auth ? { Authorization: `Bearer ${options.auth}` } : void 0,
3581
+ url: target,
3582
+ ...authProvider ? { authProvider } : options.auth ? { headers: { Authorization: `Bearer ${options.auth}` } } : {},
2277
3583
  clientInfo: cliClientInfo
2278
3584
  });
2279
- session = await client.createSession(sessionName);
3585
+ try {
3586
+ session = await client.createSession(sessionName);
3587
+ } catch (err) {
3588
+ if (authProvider && isUnauthorized(err)) {
3589
+ console.error(
3590
+ formatWarning(
3591
+ "Server requires authentication. Starting OAuth flow."
3592
+ )
3593
+ );
3594
+ await runOAuthFlow(authProvider, target);
3595
+ console.error(formatSuccess("Authentication successful"));
3596
+ session = await client.createSession(sessionName);
3597
+ } else {
3598
+ throw err;
3599
+ }
3600
+ }
2280
3601
  await saveSession(sessionName, {
2281
3602
  type: "http",
2282
- url: urlOrCommand,
2283
- authToken: options.auth,
3603
+ url: target,
3604
+ authMode: authProvider ? "oauth" : options.auth ? "bearer" : void 0,
3605
+ authToken: authProvider ? void 0 : options.auth,
2284
3606
  lastUsed: (/* @__PURE__ */ new Date()).toISOString()
2285
3607
  });
2286
3608
  }
@@ -2290,7 +3612,7 @@ async function connectCommand(urlOrCommand, options) {
2290
3612
  if (serverInfo) {
2291
3613
  await updateSessionInfo(sessionName, serverInfo, capabilities);
2292
3614
  }
2293
- console.log(formatSuccess(`Connected to ${sessionName}`));
3615
+ console.log(formatSuccess(`Connected as '${sessionName}'`));
2294
3616
  if (serverInfo) {
2295
3617
  console.log("");
2296
3618
  console.log(formatHeader("Server Information:"));
@@ -2316,119 +3638,173 @@ async function connectCommand(urlOrCommand, options) {
2316
3638
  );
2317
3639
  } catch (error) {
2318
3640
  console.error(formatError(`Connection failed: ${error.message}`));
2319
- process.exit(1);
3641
+ await cleanupAndExit(1);
2320
3642
  }
3643
+ await cleanupAndExit(0);
2321
3644
  }
2322
- async function disconnectCommand(sessionName, options) {
3645
+ async function disconnectCommand(name) {
2323
3646
  try {
2324
- if (options?.all) {
2325
- for (const [name, { client }] of activeSessions.entries()) {
2326
- await client.closeAllSessions();
2327
- activeSessions.delete(name);
2328
- console.log(formatSuccess(`Disconnected from ${name}`));
2329
- }
2330
- return;
2331
- }
2332
- if (!sessionName) {
2333
- const active = await getActiveSession();
2334
- if (!active) {
2335
- console.error(formatError("No active session to disconnect"));
2336
- return;
2337
- }
2338
- sessionName = active.name;
2339
- }
2340
- const sessionData = activeSessions.get(sessionName);
3647
+ const sessionData = activeSessions.get(name);
2341
3648
  if (sessionData) {
2342
3649
  await sessionData.client.closeAllSessions();
2343
- activeSessions.delete(sessionName);
2344
- console.log(formatSuccess(`Disconnected from ${sessionName}`));
3650
+ activeSessions.delete(name);
3651
+ console.log(formatSuccess(`Disconnected from ${name}`));
2345
3652
  } else {
2346
- console.log(formatInfo(`Session '${sessionName}' is not connected`));
3653
+ console.log(formatInfo(`Server '${name}' is not connected`));
2347
3654
  }
2348
3655
  } catch (error) {
2349
3656
  console.error(formatError(`Failed to disconnect: ${error.message}`));
2350
- process.exit(1);
3657
+ await cleanupAndExit(1);
3658
+ }
3659
+ await cleanupAndExit(0);
3660
+ }
3661
+ async function removeClientCommand(name) {
3662
+ try {
3663
+ const config = await getSession(name);
3664
+ if (!config) {
3665
+ console.error(formatError(`Server '${name}' not found`));
3666
+ console.error("");
3667
+ console.error("See your saved servers with:");
3668
+ console.error(" mcp-use client list");
3669
+ await cleanupAndExit(1);
3670
+ }
3671
+ const sessionData = activeSessions.get(name);
3672
+ if (sessionData) {
3673
+ await sessionData.client.closeAllSessions();
3674
+ activeSessions.delete(name);
3675
+ }
3676
+ const isOAuthHttp = config.type === "http" && config.authMode === "oauth" && typeof config.url === "string";
3677
+ const sharedUrlSibling = isOAuthHttp ? (await listAllSessions()).find(
3678
+ (s) => s.name !== name && s.config.type === "http" && s.config.url === config.url
3679
+ ) : void 0;
3680
+ await removeSession(name);
3681
+ console.log(formatSuccess(`Removed saved server '${name}'`));
3682
+ if (isOAuthHttp) {
3683
+ if (sharedUrlSibling) {
3684
+ console.log(
3685
+ formatInfo(
3686
+ `OAuth tokens for ${config.url} were kept because saved server '${sharedUrlSibling.name}' still uses that URL.`
3687
+ )
3688
+ );
3689
+ } else {
3690
+ try {
3691
+ const provider = await buildOAuthProvider(config.url);
3692
+ await provider.invalidateCredentials("all");
3693
+ console.log(formatInfo(`Removed OAuth tokens for ${config.url}`));
3694
+ } catch (error) {
3695
+ console.error(
3696
+ formatWarning(
3697
+ `Saved entry removed, but failed to clear OAuth tokens for ${config.url}: ${error.message}`
3698
+ )
3699
+ );
3700
+ }
3701
+ }
3702
+ }
3703
+ } catch (error) {
3704
+ console.error(formatError(`Failed to remove server: ${error.message}`));
3705
+ await cleanupAndExit(1);
2351
3706
  }
3707
+ await cleanupAndExit(0);
2352
3708
  }
2353
- async function listSessionsCommand() {
3709
+ async function listClientsCommand() {
2354
3710
  try {
2355
3711
  const sessions = await listAllSessions();
2356
3712
  if (sessions.length === 0) {
2357
- console.log(formatInfo("No saved sessions"));
2358
- console.log(
2359
- formatInfo("Connect to a server with: npx mcp-use client connect <url>")
2360
- );
3713
+ if (isStdoutTty()) {
3714
+ console.log(formatInfo("No saved servers"));
3715
+ console.log(
3716
+ formatInfo(
3717
+ "Connect to a server with: npx mcp-use client connect <name> <url>"
3718
+ )
3719
+ );
3720
+ }
2361
3721
  return;
2362
3722
  }
2363
- console.log(formatHeader("Saved Sessions:"));
2364
- console.log("");
3723
+ const tty2 = isStdoutTty();
3724
+ if (tty2) {
3725
+ console.log(formatHeader("Saved Servers:"));
3726
+ console.log("");
3727
+ }
2365
3728
  const tableData = sessions.map((s) => ({
2366
- name: s.isActive ? source_default.green.bold(`${s.name} *`) : s.name,
3729
+ name: s.name,
2367
3730
  type: s.config.type,
2368
3731
  target: s.config.type === "http" ? s.config.url || "" : `${s.config.command} ${(s.config.args || []).join(" ")}`,
2369
- server: s.config.serverInfo?.name || "unknown",
2370
- status: activeSessions.has(s.name) ? source_default.green("connected") : source_default.gray("disconnected")
3732
+ server: s.config.serverInfo?.name || "unknown"
2371
3733
  }));
2372
3734
  console.log(
2373
3735
  formatTable(tableData, [
2374
3736
  { key: "name", header: "Name" },
2375
3737
  { key: "type", header: "Type" },
2376
- { key: "target", header: "Target", width: 40 },
2377
- { key: "server", header: "Server" },
2378
- { key: "status", header: "Status" }
3738
+ { key: "target", header: "Target", truncate: true },
3739
+ { key: "server", header: "Server" }
2379
3740
  ])
2380
3741
  );
2381
- console.log("");
2382
- console.log(source_default.gray("* = active session"));
2383
- } catch (error) {
2384
- console.error(formatError(`Failed to list sessions: ${error.message}`));
2385
- process.exit(1);
2386
- }
2387
- }
2388
- async function switchSessionCommand(name) {
2389
- try {
2390
- await setActiveSession(name);
2391
- console.log(formatSuccess(`Switched to session '${name}'`));
2392
3742
  } catch (error) {
2393
- console.error(formatError(`Failed to switch session: ${error.message}`));
2394
- process.exit(1);
3743
+ console.error(formatError(`Failed to list servers: ${error.message}`));
3744
+ await cleanupAndExit(1);
2395
3745
  }
3746
+ await cleanupAndExit(0);
2396
3747
  }
2397
- async function listToolsCommand(options) {
3748
+ async function listToolsCommand(name, options) {
2398
3749
  try {
2399
- const result = await getOrRestoreSession(options.session || null);
2400
- if (!result) return;
3750
+ const result = await getOrRestoreSession(name);
3751
+ if (!result) {
3752
+ await cleanupAndExit(1);
3753
+ }
2401
3754
  const { session } = result;
2402
3755
  const tools = await session.listTools();
2403
3756
  if (options.json) {
2404
3757
  console.log(formatJson(tools));
2405
- return;
2406
- }
2407
- if (tools.length === 0) {
2408
- console.log(formatInfo("No tools available"));
2409
- return;
3758
+ } else if (tools.length === 0) {
3759
+ if (isStdoutTty()) console.log(formatInfo("No tools available"));
3760
+ } else {
3761
+ const tty2 = isStdoutTty();
3762
+ if (tty2) {
3763
+ console.log(formatHeader(`Available Tools (${tools.length}):`));
3764
+ console.log("");
3765
+ }
3766
+ const tableData = tools.map((tool) => {
3767
+ const props = tool.inputSchema?.properties ?? {};
3768
+ const required = tool.inputSchema?.required ?? [];
3769
+ const total = Object.keys(props).length;
3770
+ const reqCount = Array.isArray(required) ? required.length : 0;
3771
+ const argsCell = total === 0 ? source_default.gray("\u2014") : `${reqCount}/${total}`;
3772
+ return {
3773
+ name: source_default.bold(tool.name),
3774
+ mode: formatToolMode(tool.annotations),
3775
+ args: argsCell,
3776
+ description: tool.description || source_default.gray("(no description)")
3777
+ };
3778
+ });
3779
+ console.log(
3780
+ formatTable(tableData, [
3781
+ { key: "name", header: "Tool" },
3782
+ { key: "mode", header: "Mode" },
3783
+ { key: "args", header: "Args" },
3784
+ { key: "description", header: "Description", truncate: true }
3785
+ ])
3786
+ );
3787
+ if (tty2) {
3788
+ console.log("");
3789
+ console.log(
3790
+ source_default.gray(
3791
+ "ARGS shows required/total. Modes: read-only \xB7 write \xB7 destructive."
3792
+ )
3793
+ );
3794
+ }
2410
3795
  }
2411
- console.log(formatHeader(`Available Tools (${tools.length}):`));
2412
- console.log("");
2413
- const tableData = tools.map((tool) => ({
2414
- name: source_default.bold(tool.name),
2415
- description: tool.description || source_default.gray("No description")
2416
- }));
2417
- console.log(
2418
- formatTable(tableData, [
2419
- { key: "name", header: "Tool", width: 25 },
2420
- { key: "description", header: "Description", width: 50 }
2421
- ])
2422
- );
2423
3796
  } catch (error) {
2424
3797
  console.error(formatError(`Failed to list tools: ${error.message}`));
2425
- process.exit(1);
3798
+ await cleanupAndExit(1);
2426
3799
  }
3800
+ await cleanupAndExit(0);
2427
3801
  }
2428
- async function describeToolCommand(toolName, options) {
3802
+ async function describeToolCommand(name, toolName) {
2429
3803
  try {
2430
- const result = await getOrRestoreSession(options.session || null);
2431
- if (!result) return;
3804
+ const result = await getOrRestoreSession(name);
3805
+ if (!result) {
3806
+ await cleanupAndExit(1);
3807
+ }
2432
3808
  const { session } = result;
2433
3809
  const tools = session.tools;
2434
3810
  const tool = tools.find((t) => t.name === toolName);
@@ -2437,7 +3813,7 @@ async function describeToolCommand(toolName, options) {
2437
3813
  console.log("");
2438
3814
  console.log(formatInfo("Available tools:"));
2439
3815
  tools.forEach((t) => console.log(` \u2022 ${t.name}`));
2440
- return;
3816
+ await cleanupAndExit(1);
2441
3817
  }
2442
3818
  console.log(formatHeader(`Tool: ${tool.name}`));
2443
3819
  console.log("");
@@ -2451,94 +3827,167 @@ async function describeToolCommand(toolName, options) {
2451
3827
  }
2452
3828
  } catch (error) {
2453
3829
  console.error(formatError(`Failed to describe tool: ${error.message}`));
2454
- process.exit(1);
3830
+ await cleanupAndExit(1);
2455
3831
  }
3832
+ await cleanupAndExit(0);
2456
3833
  }
2457
- async function callToolCommand(toolName, argsJson, options) {
3834
+ async function callToolCommand(name, toolName, argsList, options) {
2458
3835
  try {
2459
- const result = await getOrRestoreSession(options?.session || null);
2460
- if (!result) return;
3836
+ const result = await getOrRestoreSession(name);
3837
+ if (!result) {
3838
+ await cleanupAndExit(1);
3839
+ }
2461
3840
  const { session } = result;
3841
+ const tools = session.tools;
3842
+ const tool = tools.find((t) => t.name === toolName);
2462
3843
  let args = {};
2463
- if (argsJson) {
3844
+ if (argsList && argsList.length > 0) {
2464
3845
  try {
2465
- args = JSON.parse(argsJson);
3846
+ args = parseToolArgs(argsList, tool?.inputSchema);
2466
3847
  } catch (error) {
2467
- console.error(formatError("Invalid JSON arguments"));
2468
- return;
2469
- }
2470
- } else {
2471
- const tools = session.tools;
2472
- const tool = tools.find((t) => t.name === toolName);
2473
- if (tool?.inputSchema?.required && tool.inputSchema.required.length > 0) {
2474
- console.error(
2475
- formatError(
2476
- "This tool requires arguments. Provide them as a JSON string."
2477
- )
2478
- );
3848
+ console.error(formatError(error.message));
2479
3849
  console.log("");
2480
- console.log(formatInfo("Example:"));
3850
+ console.log(formatInfo("Usage:"));
2481
3851
  console.log(
2482
- ` npx mcp-use client tools call ${toolName} '{"param": "value"}'`
3852
+ ` npx mcp-use client ${name} tools call ${toolName} key=value [key2=value2 ...]`
2483
3853
  );
2484
- console.log("");
2485
- console.log(formatInfo("Tool schema:"));
2486
- console.log(formatSchema(tool.inputSchema));
2487
- return;
3854
+ console.log(
3855
+ ` npx mcp-use client ${name} tools call ${toolName} nested:='{"a":1}' # JSON value`
3856
+ );
3857
+ console.log(
3858
+ ` npx mcp-use client ${name} tools call ${toolName} '{"key":"value"}' # full JSON object`
3859
+ );
3860
+ if (tool?.inputSchema) {
3861
+ console.log("");
3862
+ console.log(formatInfo("Tool schema:"));
3863
+ console.log(formatSchema(tool.inputSchema));
3864
+ }
3865
+ await cleanupAndExit(1);
2488
3866
  }
3867
+ } else if (tool?.inputSchema?.required && tool.inputSchema.required.length > 0) {
3868
+ console.error(formatError("This tool requires arguments."));
3869
+ console.log("");
3870
+ console.log(formatInfo("Provide arguments as key=value pairs:"));
3871
+ console.log(
3872
+ ` npx mcp-use client ${name} tools call ${toolName} key=value [key2=value2 ...]`
3873
+ );
3874
+ console.log("");
3875
+ console.log(formatInfo("Tool schema:"));
3876
+ console.log(formatSchema(tool.inputSchema));
3877
+ await cleanupAndExit(1);
2489
3878
  }
2490
3879
  console.error(formatInfo(`Calling tool '${toolName}'...`));
2491
3880
  const callResult = await session.callTool(toolName, args, {
2492
3881
  timeout: options?.timeout
2493
3882
  });
3883
+ let screenshot = null;
3884
+ let screenshotError = null;
3885
+ if (options?.screenshot !== false) {
3886
+ const tool2 = session.tools.find((t) => t.name === toolName);
3887
+ const resourceUri = detectToolResourceUri(tool2);
3888
+ if (resourceUri) {
3889
+ console.error(
3890
+ formatInfo(`Capturing widget screenshot (${resourceUri})...`)
3891
+ );
3892
+ try {
3893
+ const shot = await captureToolScreenshot(
3894
+ {
3895
+ session,
3896
+ toolName,
3897
+ toolArgs: args,
3898
+ toolOutput: callResult,
3899
+ resourceUri
3900
+ },
3901
+ options?.screenshotOutput ? { output: options.screenshotOutput } : {}
3902
+ );
3903
+ screenshot = {
3904
+ path: shot.outputPath,
3905
+ width: shot.width,
3906
+ height: shot.height,
3907
+ view: shot.view
3908
+ };
3909
+ } catch (err) {
3910
+ screenshotError = err?.message ?? String(err);
3911
+ }
3912
+ }
3913
+ }
2494
3914
  if (options?.json) {
2495
3915
  console.log(formatJson(callResult));
2496
3916
  } else {
2497
3917
  console.log(formatToolCall(callResult));
2498
3918
  }
3919
+ if (screenshot) {
3920
+ console.error(
3921
+ formatSuccess(
3922
+ `Saved widget screenshot: ${screenshot.path} (${screenshot.width}\xD7${screenshot.height})`
3923
+ )
3924
+ );
3925
+ }
3926
+ if (screenshotError) {
3927
+ console.error(
3928
+ formatWarning(`Skipped widget screenshot: ${screenshotError}`)
3929
+ );
3930
+ }
3931
+ if (callResult.isError) {
3932
+ await cleanupAndExit(1);
3933
+ }
2499
3934
  } catch (error) {
2500
3935
  console.error(formatError(`Failed to call tool: ${error.message}`));
2501
- process.exit(1);
3936
+ if (error?.data !== void 0) {
3937
+ console.error(
3938
+ source_default.gray(
3939
+ typeof error.data === "string" ? error.data : formatJson(error.data)
3940
+ )
3941
+ );
3942
+ }
3943
+ await cleanupAndExit(1);
2502
3944
  }
3945
+ await cleanupAndExit(0);
2503
3946
  }
2504
- async function listResourcesCommand(options) {
3947
+ async function listResourcesCommand(name, options) {
2505
3948
  try {
2506
- const result = await getOrRestoreSession(options.session || null);
2507
- if (!result) return;
3949
+ const result = await getOrRestoreSession(name);
3950
+ if (!result) {
3951
+ await cleanupAndExit(1);
3952
+ }
2508
3953
  const { session } = result;
2509
3954
  const resourcesResult = await session.listAllResources();
2510
3955
  const resources = resourcesResult.resources;
2511
3956
  if (options.json) {
2512
3957
  console.log(formatJson(resources));
2513
- return;
2514
- }
2515
- if (resources.length === 0) {
2516
- console.log(formatInfo("No resources available"));
2517
- return;
3958
+ } else if (resources.length === 0) {
3959
+ if (isStdoutTty()) console.log(formatInfo("No resources available"));
3960
+ } else {
3961
+ const tty2 = isStdoutTty();
3962
+ if (tty2) {
3963
+ console.log(formatHeader(`Available Resources (${resources.length}):`));
3964
+ console.log("");
3965
+ }
3966
+ const tableData = resources.map((resource) => ({
3967
+ name: source_default.bold(resource.name || "(no name)"),
3968
+ type: resource.mimeType || source_default.gray("unknown"),
3969
+ uri: resource.uri
3970
+ }));
3971
+ console.log(
3972
+ formatTable(tableData, [
3973
+ { key: "name", header: "Name" },
3974
+ { key: "type", header: "Type" },
3975
+ { key: "uri", header: "URI", truncate: true }
3976
+ ])
3977
+ );
2518
3978
  }
2519
- console.log(formatHeader(`Available Resources (${resources.length}):`));
2520
- console.log("");
2521
- const tableData = resources.map((resource) => ({
2522
- uri: resource.uri,
2523
- name: resource.name || source_default.gray("(no name)"),
2524
- type: resource.mimeType || source_default.gray("unknown")
2525
- }));
2526
- console.log(
2527
- formatTable(tableData, [
2528
- { key: "uri", header: "URI", width: 40 },
2529
- { key: "name", header: "Name", width: 20 },
2530
- { key: "type", header: "Type", width: 15 }
2531
- ])
2532
- );
2533
3979
  } catch (error) {
2534
3980
  console.error(formatError(`Failed to list resources: ${error.message}`));
2535
- process.exit(1);
3981
+ await cleanupAndExit(1);
2536
3982
  }
3983
+ await cleanupAndExit(0);
2537
3984
  }
2538
- async function readResourceCommand(uri, options) {
3985
+ async function readResourceCommand(name, uri, options) {
2539
3986
  try {
2540
- const result = await getOrRestoreSession(options.session || null);
2541
- if (!result) return;
3987
+ const result = await getOrRestoreSession(name);
3988
+ if (!result) {
3989
+ await cleanupAndExit(1);
3990
+ }
2542
3991
  const { session } = result;
2543
3992
  console.error(formatInfo(`Reading resource: ${uri}`));
2544
3993
  const resource = await session.readResource(uri);
@@ -2549,13 +3998,16 @@ async function readResourceCommand(uri, options) {
2549
3998
  }
2550
3999
  } catch (error) {
2551
4000
  console.error(formatError(`Failed to read resource: ${error.message}`));
2552
- process.exit(1);
4001
+ await cleanupAndExit(1);
2553
4002
  }
4003
+ await cleanupAndExit(0);
2554
4004
  }
2555
- async function subscribeResourceCommand(uri, options) {
4005
+ async function subscribeResourceCommand(name, uri) {
2556
4006
  try {
2557
- const result = await getOrRestoreSession(options.session || null);
2558
- if (!result) return;
4007
+ const result = await getOrRestoreSession(name);
4008
+ if (!result) {
4009
+ await cleanupAndExit(1);
4010
+ }
2559
4011
  const { session } = result;
2560
4012
  await session.subscribeToResource(uri);
2561
4013
  console.log(formatSuccess(`Subscribed to resource: ${uri}`));
@@ -2573,13 +4025,15 @@ async function subscribeResourceCommand(uri, options) {
2573
4025
  console.error(
2574
4026
  formatError(`Failed to subscribe to resource: ${error.message}`)
2575
4027
  );
2576
- process.exit(1);
4028
+ await cleanupAndExit(1);
2577
4029
  }
2578
4030
  }
2579
- async function unsubscribeResourceCommand(uri, options) {
4031
+ async function unsubscribeResourceCommand(name, uri) {
2580
4032
  try {
2581
- const result = await getOrRestoreSession(options.session || null);
2582
- if (!result) return;
4033
+ const result = await getOrRestoreSession(name);
4034
+ if (!result) {
4035
+ await cleanupAndExit(1);
4036
+ }
2583
4037
  const { session } = result;
2584
4038
  await session.unsubscribeFromResource(uri);
2585
4039
  console.log(formatSuccess(`Unsubscribed from resource: ${uri}`));
@@ -2587,53 +4041,76 @@ async function unsubscribeResourceCommand(uri, options) {
2587
4041
  console.error(
2588
4042
  formatError(`Failed to unsubscribe from resource: ${error.message}`)
2589
4043
  );
2590
- process.exit(1);
4044
+ await cleanupAndExit(1);
2591
4045
  }
4046
+ await cleanupAndExit(0);
2592
4047
  }
2593
- async function listPromptsCommand(options) {
4048
+ async function listPromptsCommand(name, options) {
2594
4049
  try {
2595
- const result = await getOrRestoreSession(options.session || null);
2596
- if (!result) return;
4050
+ const result = await getOrRestoreSession(name);
4051
+ if (!result) {
4052
+ await cleanupAndExit(1);
4053
+ }
2597
4054
  const { session } = result;
2598
4055
  const promptsResult = await session.listPrompts();
2599
4056
  const prompts = promptsResult.prompts;
2600
4057
  if (options.json) {
2601
4058
  console.log(formatJson(prompts));
2602
- return;
2603
- }
2604
- if (prompts.length === 0) {
2605
- console.log(formatInfo("No prompts available"));
2606
- return;
4059
+ } else if (prompts.length === 0) {
4060
+ if (isStdoutTty()) console.log(formatInfo("No prompts available"));
4061
+ } else {
4062
+ const tty2 = isStdoutTty();
4063
+ if (tty2) {
4064
+ console.log(formatHeader(`Available Prompts (${prompts.length}):`));
4065
+ console.log("");
4066
+ }
4067
+ const tableData = prompts.map((prompt4) => {
4068
+ const args = prompt4.arguments ?? [];
4069
+ const reqCount = Array.isArray(args) ? args.filter((a) => a?.required).length : 0;
4070
+ const total = Array.isArray(args) ? args.length : 0;
4071
+ const argsCell = total === 0 ? source_default.gray("\u2014") : `${reqCount}/${total}`;
4072
+ return {
4073
+ name: source_default.bold(prompt4.name),
4074
+ args: argsCell,
4075
+ description: prompt4.description || source_default.gray("(no description)")
4076
+ };
4077
+ });
4078
+ console.log(
4079
+ formatTable(tableData, [
4080
+ { key: "name", header: "Prompt" },
4081
+ { key: "args", header: "Args" },
4082
+ { key: "description", header: "Description", truncate: true }
4083
+ ])
4084
+ );
2607
4085
  }
2608
- console.log(formatHeader(`Available Prompts (${prompts.length}):`));
2609
- console.log("");
2610
- const tableData = prompts.map((prompt4) => ({
2611
- name: source_default.bold(prompt4.name),
2612
- description: prompt4.description || source_default.gray("No description")
2613
- }));
2614
- console.log(
2615
- formatTable(tableData, [
2616
- { key: "name", header: "Prompt", width: 25 },
2617
- { key: "description", header: "Description", width: 50 }
2618
- ])
2619
- );
2620
4086
  } catch (error) {
2621
4087
  console.error(formatError(`Failed to list prompts: ${error.message}`));
2622
- process.exit(1);
4088
+ await cleanupAndExit(1);
2623
4089
  }
4090
+ await cleanupAndExit(0);
2624
4091
  }
2625
- async function getPromptCommand(promptName, argsJson, options) {
4092
+ async function getPromptCommand(name, promptName, argsList, options) {
2626
4093
  try {
2627
- const result = await getOrRestoreSession(options?.session || null);
2628
- if (!result) return;
4094
+ const result = await getOrRestoreSession(name);
4095
+ if (!result) {
4096
+ await cleanupAndExit(1);
4097
+ }
2629
4098
  const { session } = result;
2630
4099
  let args = {};
2631
- if (argsJson) {
4100
+ if (argsList && argsList.length > 0) {
2632
4101
  try {
2633
- args = JSON.parse(argsJson);
4102
+ args = parsePromptArgs(argsList);
2634
4103
  } catch (error) {
2635
- console.error(formatError("Invalid JSON arguments"));
2636
- return;
4104
+ console.error(formatError(error.message));
4105
+ console.log("");
4106
+ console.log(formatInfo("Usage:"));
4107
+ console.log(
4108
+ ` npx mcp-use client ${name} prompts get ${promptName} key=value [key2=value2 ...]`
4109
+ );
4110
+ console.log(
4111
+ ` npx mcp-use client ${name} prompts get ${promptName} '{"key":"value"}' # full JSON object`
4112
+ );
4113
+ await cleanupAndExit(1);
2637
4114
  }
2638
4115
  }
2639
4116
  console.error(formatInfo(`Getting prompt '${promptName}'...`));
@@ -2655,12 +4132,13 @@ async function getPromptCommand(promptName, argsJson, options) {
2655
4132
  }
2656
4133
  } catch (error) {
2657
4134
  console.error(formatError(`Failed to get prompt: ${error.message}`));
2658
- process.exit(1);
4135
+ await cleanupAndExit(1);
2659
4136
  }
4137
+ await cleanupAndExit(0);
2660
4138
  }
2661
- async function interactiveCommand(options) {
4139
+ async function interactiveCommand(name) {
2662
4140
  try {
2663
- const result = await getOrRestoreSession(options.session || null);
4141
+ const result = await getOrRestoreSession(name);
2664
4142
  if (!result) return;
2665
4143
  const { name: sessionName, session } = result;
2666
4144
  console.log(formatHeader("MCP Interactive Mode"));
@@ -2683,15 +4161,11 @@ async function interactiveCommand(options) {
2683
4161
  source_default.gray(" prompts list - List available prompts")
2684
4162
  );
2685
4163
  console.log(source_default.gray(" prompts get <name> - Get a prompt"));
2686
- console.log(source_default.gray(" sessions list - List all sessions"));
2687
- console.log(
2688
- source_default.gray(" sessions switch <name> - Switch to another session")
2689
- );
2690
4164
  console.log(
2691
4165
  source_default.gray(" exit, quit - Exit interactive mode")
2692
4166
  );
2693
4167
  console.log("");
2694
- const rl = createInterface({
4168
+ const rl = createInterface2({
2695
4169
  input: process.stdin,
2696
4170
  output: process.stdout,
2697
4171
  prompt: source_default.cyan("mcp> ")
@@ -2706,7 +4180,7 @@ async function interactiveCommand(options) {
2706
4180
  if (trimmed === "exit" || trimmed === "quit") {
2707
4181
  console.log(formatInfo("Goodbye!"));
2708
4182
  rl.close();
2709
- process.exit(0);
4183
+ await cleanupAndExit(0);
2710
4184
  }
2711
4185
  const parts = trimmed.split(" ");
2712
4186
  const scope = parts[0];
@@ -2806,22 +4280,10 @@ async function interactiveCommand(options) {
2806
4280
  )
2807
4281
  );
2808
4282
  }
2809
- } else if (scope === "sessions") {
2810
- if (command === "list") {
2811
- await listSessionsCommand();
2812
- } else if (command === "switch" && arg) {
2813
- console.log(
2814
- formatWarning(
2815
- "Session switching in interactive mode will be available in a future version"
2816
- )
2817
- );
2818
- } else {
2819
- console.error(formatError("Invalid command. Try: sessions list"));
2820
- }
2821
4283
  } else {
2822
4284
  console.error(
2823
4285
  formatError(
2824
- "Unknown command. Type a valid scope: tools, resources, prompts, sessions"
4286
+ "Unknown command. Type a valid scope: tools, resources, prompts"
2825
4287
  )
2826
4288
  );
2827
4289
  }
@@ -2830,58 +4292,95 @@ async function interactiveCommand(options) {
2830
4292
  }
2831
4293
  rl.prompt();
2832
4294
  });
2833
- rl.on("close", () => {
4295
+ rl.on("close", async () => {
2834
4296
  console.log("");
2835
4297
  console.log(formatInfo("Goodbye!"));
2836
- process.exit(0);
4298
+ await cleanupAndExit(0);
2837
4299
  });
2838
4300
  } catch (error) {
2839
4301
  console.error(
2840
4302
  formatError(`Failed to start interactive mode: ${error.message}`)
2841
4303
  );
2842
- process.exit(1);
4304
+ await cleanupAndExit(1);
2843
4305
  }
2844
4306
  }
2845
4307
  function createClientCommand() {
2846
- const clientCommand = new Command("client").description(
2847
- "Interactive MCP client for terminal usage"
4308
+ const clientCommand = new Command2("client").description(
4309
+ "Interactive MCP client for terminal usage. Use `mcp-use client <name> ...` to run commands against a saved server."
4310
+ ).showHelpAfterError(
4311
+ "(Run `mcp-use client --help` to see available commands)"
4312
+ );
4313
+ clientCommand.command("connect [name] [url]").description(
4314
+ "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`)."
4315
+ ).option("--stdio", "Use stdio connector instead of HTTP").option("--auth <token>", "Static Bearer token (skips OAuth)").option(
4316
+ "--no-oauth",
4317
+ "Don't auto-trigger OAuth on 401; fail with the 401 instead"
4318
+ ).option(
4319
+ "--auth-timeout <ms>",
4320
+ "OAuth loopback wait timeout in ms (default 300000)"
4321
+ ).action(connectCommand);
4322
+ clientCommand.command("list").description("List saved servers").action(listClientsCommand);
4323
+ clientCommand.command("remove <name>").description(
4324
+ "Remove a saved server. Also clears any OAuth tokens for that URL, unless another saved server still uses it."
4325
+ ).action(removeClientCommand);
4326
+ clientCommand.addCommand(createClientScreenshotCommand());
4327
+ return clientCommand;
4328
+ }
4329
+ function createPerClientCommand(name) {
4330
+ const cmd = new Command2(`mcp-use client ${name}`).description(`Commands for server '${name}'`).showHelpAfterError(
4331
+ `(Run \`mcp-use client ${name} --help\` to see available commands)`
4332
+ );
4333
+ cmd.command("disconnect").description("Disconnect from this server").action(() => disconnectCommand(name));
4334
+ cmd.command("interactive").description("Start interactive REPL mode for this server").action(() => interactiveCommand(name));
4335
+ const toolsCommand = new Command2("tools").description("Interact with MCP tools").showHelpAfterError(
4336
+ `(Run \`mcp-use client ${name} tools --help\` to see available actions)`
2848
4337
  );
2849
- 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);
2850
- clientCommand.command("disconnect [session]").description("Disconnect from a session").option("--all", "Disconnect all sessions").action(disconnectCommand);
2851
- const sessionsCommand = new Command("sessions").description(
2852
- "Manage CLI sessions"
4338
+ toolsCommand.command("list").description("List available tools").option("--json", "Output as JSON").action((options) => listToolsCommand(name, options));
4339
+ toolsCommand.command("call <tool> [args...]").description(
4340
+ "Call a tool. Args as key=value pairs (use key:=<json> for nested values, or pass a JSON object)"
4341
+ ).option("--timeout <ms>", "Request timeout in milliseconds", parseInt).option("--json", "Output as JSON").option(
4342
+ "--no-screenshot",
4343
+ "Skip the auto-screenshot for tools that render a widget"
4344
+ ).option(
4345
+ "--screenshot-output <path>",
4346
+ "Output PNG path for the widget screenshot (defaults to ./<view>-<timestamp>.png)"
4347
+ ).action(
4348
+ (tool, args, options) => callToolCommand(name, tool, args, options)
2853
4349
  );
2854
- sessionsCommand.command("list").description("List all saved sessions").action(listSessionsCommand);
2855
- sessionsCommand.command("switch <name>").description("Switch to a different session").action(switchSessionCommand);
2856
- clientCommand.addCommand(sessionsCommand);
2857
- const toolsCommand = new Command("tools").description(
2858
- "Interact with MCP tools"
4350
+ toolsCommand.command("describe <tool>").description("Show tool details and schema").action((tool) => describeToolCommand(name, tool));
4351
+ cmd.addCommand(toolsCommand);
4352
+ const resourcesCommand = new Command2("resources").description("Interact with MCP resources").showHelpAfterError(
4353
+ `(Run \`mcp-use client ${name} resources --help\` to see available actions)`
2859
4354
  );
2860
- toolsCommand.command("list").description("List available tools").option("--session <name>", "Use specific session").option("--json", "Output as JSON").action(listToolsCommand);
2861
- 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);
2862
- toolsCommand.command("describe <name>").description("Show tool details and schema").option("--session <name>", "Use specific session").action(describeToolCommand);
2863
- clientCommand.addCommand(toolsCommand);
2864
- const resourcesCommand = new Command("resources").description(
2865
- "Interact with MCP resources"
4355
+ resourcesCommand.command("list").description("List available resources").option("--json", "Output as JSON").action((options) => listResourcesCommand(name, options));
4356
+ resourcesCommand.command("read <uri>").description("Read a resource by URI").option("--json", "Output as JSON").action((uri, options) => readResourceCommand(name, uri, options));
4357
+ resourcesCommand.command("subscribe <uri>").description("Subscribe to resource updates").action((uri) => subscribeResourceCommand(name, uri));
4358
+ resourcesCommand.command("unsubscribe <uri>").description("Unsubscribe from resource updates").action((uri) => unsubscribeResourceCommand(name, uri));
4359
+ cmd.addCommand(resourcesCommand);
4360
+ const promptsCommand = new Command2("prompts").description("Interact with MCP prompts").showHelpAfterError(
4361
+ `(Run \`mcp-use client ${name} prompts --help\` to see available actions)`
2866
4362
  );
2867
- resourcesCommand.command("list").description("List available resources").option("--session <name>", "Use specific session").option("--json", "Output as JSON").action(listResourcesCommand);
2868
- resourcesCommand.command("read <uri>").description("Read a resource by URI").option("--session <name>", "Use specific session").option("--json", "Output as JSON").action(readResourceCommand);
2869
- resourcesCommand.command("subscribe <uri>").description("Subscribe to resource updates").option("--session <name>", "Use specific session").action(subscribeResourceCommand);
2870
- resourcesCommand.command("unsubscribe <uri>").description("Unsubscribe from resource updates").option("--session <name>", "Use specific session").action(unsubscribeResourceCommand);
2871
- clientCommand.addCommand(resourcesCommand);
2872
- const promptsCommand = new Command("prompts").description(
2873
- "Interact with MCP prompts"
4363
+ promptsCommand.command("list").description("List available prompts").option("--json", "Output as JSON").action((options) => listPromptsCommand(name, options));
4364
+ promptsCommand.command("get <prompt> [args...]").description(
4365
+ "Get a prompt. Args as key=value pairs (or pass a JSON object)"
4366
+ ).option("--json", "Output as JSON").action(
4367
+ (prompt4, args, options) => getPromptCommand(name, prompt4, args, options)
2874
4368
  );
2875
- promptsCommand.command("list").description("List available prompts").option("--session <name>", "Use specific session").option("--json", "Output as JSON").action(listPromptsCommand);
2876
- 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);
2877
- clientCommand.addCommand(promptsCommand);
2878
- clientCommand.command("interactive").description("Start interactive REPL mode").option("--session <name>", "Use specific session").action(interactiveCommand);
2879
- return clientCommand;
4369
+ cmd.addCommand(promptsCommand);
4370
+ const authCommand = new Command2("auth").description("Manage OAuth tokens for HTTP servers").showHelpAfterError(
4371
+ `(Run \`mcp-use client ${name} auth --help\` to see available actions)`
4372
+ );
4373
+ authCommand.command("status").description("Show OAuth token status for this server").action(() => authStatusCommand(name));
4374
+ authCommand.command("refresh").description("Force-refresh the OAuth access token").action(() => authRefreshCommand(name));
4375
+ authCommand.command("logout").description("Remove stored OAuth tokens for this server's URL").action(() => authLogoutCommand(name));
4376
+ cmd.addCommand(authCommand);
4377
+ cmd.addCommand(createPerClientScreenshotCommand(name));
4378
+ return cmd;
2880
4379
  }
2881
4380
 
2882
4381
  // src/commands/deploy.ts
2883
4382
  import { promises as fs9 } from "fs";
2884
- import path5 from "path";
4383
+ import path8 from "path";
2885
4384
 
2886
4385
  // src/utils/git.ts
2887
4386
  import { execFile as execFile7 } from "child_process";
@@ -3036,15 +4535,15 @@ function getMcpServerUrlForCloudServer(server) {
3036
4535
 
3037
4536
  // src/utils/project-link.ts
3038
4537
  import { promises as fs8 } from "fs";
3039
- import path4 from "path";
4538
+ import path7 from "path";
3040
4539
  var MCP_USE_DIR = ".mcp-use";
3041
4540
  var MCP_USE_DIR_PROJECT = "project.json";
3042
4541
  function getMcpUseDirectory(cwd) {
3043
- return path4.join(cwd, MCP_USE_DIR);
4542
+ return path7.join(cwd, MCP_USE_DIR);
3044
4543
  }
3045
4544
  async function getProjectLink(cwd) {
3046
4545
  try {
3047
- const linkPath = path4.join(getMcpUseDirectory(cwd), MCP_USE_DIR_PROJECT);
4546
+ const linkPath = path7.join(getMcpUseDirectory(cwd), MCP_USE_DIR_PROJECT);
3048
4547
  const content = await fs8.readFile(linkPath, "utf-8");
3049
4548
  return JSON.parse(content);
3050
4549
  } catch (err) {
@@ -3055,12 +4554,12 @@ async function getProjectLink(cwd) {
3055
4554
  async function saveProjectLink(cwd, link) {
3056
4555
  const mcpUseDir = getMcpUseDirectory(cwd);
3057
4556
  await fs8.mkdir(mcpUseDir, { recursive: true });
3058
- const linkPath = path4.join(mcpUseDir, MCP_USE_DIR_PROJECT);
4557
+ const linkPath = path7.join(mcpUseDir, MCP_USE_DIR_PROJECT);
3059
4558
  await fs8.writeFile(linkPath, JSON.stringify(link, null, 2), "utf-8");
3060
4559
  await addToGitIgnore(cwd);
3061
4560
  }
3062
4561
  async function addToGitIgnore(cwd) {
3063
- const gitignorePath = path4.join(cwd, ".gitignore");
4562
+ const gitignorePath = path7.join(cwd, ".gitignore");
3064
4563
  try {
3065
4564
  let content = "";
3066
4565
  try {
@@ -3201,7 +4700,7 @@ async function buildEnvVars(options) {
3201
4700
  }
3202
4701
  async function isMcpProject(cwd = process.cwd()) {
3203
4702
  try {
3204
- const content = await fs9.readFile(path5.join(cwd, "package.json"), "utf-8");
4703
+ const content = await fs9.readFile(path8.join(cwd, "package.json"), "utf-8");
3205
4704
  const pkg = JSON.parse(content);
3206
4705
  return !!(pkg.dependencies?.["mcp-use"] || pkg.dependencies?.["@modelcontextprotocol/sdk"] || pkg.devDependencies?.["mcp-use"] || pkg.devDependencies?.["@modelcontextprotocol/sdk"]);
3207
4706
  } catch {
@@ -3210,16 +4709,16 @@ async function isMcpProject(cwd = process.cwd()) {
3210
4709
  }
3211
4710
  async function getProjectName(cwd = process.cwd()) {
3212
4711
  try {
3213
- const content = await fs9.readFile(path5.join(cwd, "package.json"), "utf-8");
4712
+ const content = await fs9.readFile(path8.join(cwd, "package.json"), "utf-8");
3214
4713
  const pkg = JSON.parse(content);
3215
4714
  if (pkg.name) return pkg.name;
3216
4715
  } catch {
3217
4716
  }
3218
- return path5.basename(cwd);
4717
+ return path8.basename(cwd);
3219
4718
  }
3220
4719
  async function detectBuildCommand(cwd) {
3221
4720
  try {
3222
- const content = await fs9.readFile(path5.join(cwd, "package.json"), "utf-8");
4721
+ const content = await fs9.readFile(path8.join(cwd, "package.json"), "utf-8");
3223
4722
  if (JSON.parse(content).scripts?.build) return "npm run build";
3224
4723
  } catch {
3225
4724
  }
@@ -3227,7 +4726,7 @@ async function detectBuildCommand(cwd) {
3227
4726
  }
3228
4727
  async function detectStartCommand(cwd) {
3229
4728
  try {
3230
- const content = await fs9.readFile(path5.join(cwd, "package.json"), "utf-8");
4729
+ const content = await fs9.readFile(path8.join(cwd, "package.json"), "utf-8");
3231
4730
  const pkg = JSON.parse(content);
3232
4731
  if (pkg.scripts?.start) return "npm start";
3233
4732
  if (pkg.main) return `node ${pkg.main}`;
@@ -3238,7 +4737,7 @@ async function detectStartCommand(cwd) {
3238
4737
  async function detectRuntime(cwd) {
3239
4738
  for (const f of ["requirements.txt", "pyproject.toml", "setup.py"]) {
3240
4739
  try {
3241
- await fs9.access(path5.join(cwd, f));
4740
+ await fs9.access(path8.join(cwd, f));
3242
4741
  return "python";
3243
4742
  } catch {
3244
4743
  continue;
@@ -3285,7 +4784,7 @@ var REQUIRED_IGNORES = [
3285
4784
  ".mcp-use"
3286
4785
  ];
3287
4786
  async function ensureGitignore(cwd) {
3288
- const gitignorePath = path5.join(cwd, ".gitignore");
4787
+ const gitignorePath = path8.join(cwd, ".gitignore");
3289
4788
  let content = "";
3290
4789
  try {
3291
4790
  content = await fs9.readFile(gitignorePath, "utf-8");
@@ -3745,7 +5244,7 @@ async function deployCommand(options) {
3745
5244
  console.log(source_default.green("\u2713 GitHub connected\n"));
3746
5245
  let installationDbId;
3747
5246
  let githubInstallationId;
3748
- const projectDir = options.rootDir ? path5.resolve(cwd, options.rootDir) : cwd;
5247
+ const projectDir = options.rootDir ? path8.resolve(cwd, options.rootDir) : cwd;
3749
5248
  if (options.rootDir) {
3750
5249
  try {
3751
5250
  await fs9.access(projectDir);
@@ -4257,7 +5756,7 @@ async function deployCommand(options) {
4257
5756
  }
4258
5757
 
4259
5758
  // src/commands/deployments.ts
4260
- import { Command as Command2 } from "commander";
5759
+ import { Command as Command3 } from "commander";
4261
5760
  async function prompt2(question) {
4262
5761
  const readline = await import("readline");
4263
5762
  const rl = readline.createInterface({
@@ -4669,8 +6168,8 @@ async function startDeploymentCommand(deploymentId) {
4669
6168
  }
4670
6169
  }
4671
6170
  function createDeploymentsCommand() {
4672
- const deploymentsCommand = new Command2("deployments").description(
4673
- "Manage cloud deployments"
6171
+ const deploymentsCommand = new Command3("deployments").description("Manage cloud deployments").showHelpAfterError(
6172
+ "(Run `mcp-use deployments --help` to see available commands)"
4674
6173
  );
4675
6174
  deploymentsCommand.command("list").alias("ls").description("List all deployments").action(listDeploymentsCommand);
4676
6175
  deploymentsCommand.command("get").argument("<deployment-id>", "Deployment ID").description("Get deployment details").action(getDeploymentCommand);
@@ -4685,10 +6184,10 @@ function createDeploymentsCommand() {
4685
6184
  }
4686
6185
 
4687
6186
  // src/commands/servers.ts
4688
- import { Command as Command4 } from "commander";
6187
+ import { Command as Command5 } from "commander";
4689
6188
 
4690
6189
  // src/commands/env.ts
4691
- import { Command as Command3 } from "commander";
6190
+ import { Command as Command4 } from "commander";
4692
6191
  var ALL_ENVS = ["production", "preview", "development"];
4693
6192
  function parseEnvironments(raw) {
4694
6193
  const parts = raw.split(",").map((s) => s.trim().toLowerCase()).filter(Boolean);
@@ -4833,9 +6332,7 @@ async function removeEnvCommand(varId, options) {
4833
6332
  }
4834
6333
  }
4835
6334
  function createEnvCommand() {
4836
- const envCommand = new Command3("env").description(
4837
- "Manage environment variables for a server"
4838
- );
6335
+ const envCommand = new Command4("env").description("Manage environment variables for a server").showHelpAfterError("(Run `mcp-use env --help` to see available commands)");
4839
6336
  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);
4840
6337
  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(
4841
6338
  "--env <environments>",
@@ -5117,8 +6614,8 @@ async function deleteServerCommand(serverId, options) {
5117
6614
  }
5118
6615
  }
5119
6616
  function createServersCommand() {
5120
- const serversCommand = new Command4("servers").description(
5121
- "Manage cloud servers (Git-backed deploy targets)"
6617
+ const serversCommand = new Command5("servers").description("Manage cloud servers (Git-backed deploy targets)").showHelpAfterError(
6618
+ "(Run `mcp-use servers --help` to see available commands)"
5122
6619
  );
5123
6620
  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);
5124
6621
  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);
@@ -5235,8 +6732,8 @@ async function orgCurrentCommand() {
5235
6732
  }
5236
6733
 
5237
6734
  // src/commands/skills.ts
5238
- import { Command as Command5 } from "commander";
5239
- import { cpSync, existsSync as existsSync2, mkdtempSync, readdirSync, rmSync } from "fs";
6735
+ import { Command as Command6 } from "commander";
6736
+ import { cpSync, existsSync as existsSync3, mkdtempSync as mkdtempSync2, readdirSync, rmSync as rmSync2 } from "fs";
5240
6737
  import { tmpdir } from "os";
5241
6738
  import { join as join2, resolve } from "path";
5242
6739
  import { Readable } from "stream";
@@ -5275,7 +6772,7 @@ function sendInstallTelemetryEvent(agents, skills) {
5275
6772
  }
5276
6773
  async function addSkillsToProject(projectPath) {
5277
6774
  const tarballUrl = `https://codeload.github.com/${REPO_OWNER}/${REPO_NAME}/tar.gz/${REPO_BRANCH}`;
5278
- const tempDir = mkdtempSync(join2(tmpdir(), "mcp-use-skills-"));
6775
+ const tempDir = mkdtempSync2(join2(tmpdir(), "mcp-use-skills-"));
5279
6776
  try {
5280
6777
  const response = await fetch(tarballUrl);
5281
6778
  if (!response.ok) {
@@ -5285,12 +6782,12 @@ async function addSkillsToProject(projectPath) {
5285
6782
  Readable.fromWeb(response.body),
5286
6783
  extract({
5287
6784
  cwd: tempDir,
5288
- filter: (path9) => path9.includes("/skills/"),
6785
+ filter: (path12) => path12.includes("/skills/"),
5289
6786
  strip: 1
5290
6787
  })
5291
6788
  );
5292
6789
  const skillsPath = join2(tempDir, "skills");
5293
- if (!existsSync2(skillsPath)) {
6790
+ if (!existsSync3(skillsPath)) {
5294
6791
  throw new Error("Skills folder not found in repository");
5295
6792
  }
5296
6793
  for (const preset of ALL_PRESETS) {
@@ -5301,16 +6798,16 @@ async function addSkillsToProject(projectPath) {
5301
6798
  const skillNames = readdirSync(skillsPath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
5302
6799
  sendInstallTelemetryEvent(ALL_PRESETS.join(","), skillNames.join(","));
5303
6800
  } finally {
5304
- rmSync(tempDir, { recursive: true, force: true });
6801
+ rmSync2(tempDir, { recursive: true, force: true });
5305
6802
  }
5306
6803
  }
5307
6804
  function createSkillsCommand() {
5308
- const skills = new Command5("skills").description(
5309
- "Manage mcp-use AI agent skills"
6805
+ const skills = new Command6("skills").description("Manage mcp-use AI agent skills").showHelpAfterError(
6806
+ "(Run `mcp-use skills --help` to see available commands)"
5310
6807
  );
5311
6808
  const installAction = async (options) => {
5312
6809
  const projectPath = resolve(options.path);
5313
- if (!existsSync2(projectPath)) {
6810
+ if (!existsSync3(projectPath)) {
5314
6811
  console.error(source_default.red(`Directory not found: ${projectPath}`));
5315
6812
  process.exit(1);
5316
6813
  }
@@ -5351,12 +6848,12 @@ function createSkillsCommand() {
5351
6848
  }
5352
6849
 
5353
6850
  // src/utils/next-shims.ts
5354
- import { existsSync as existsSync3, promises as fs10 } from "fs";
5355
- import path6 from "path";
6851
+ import { existsSync as existsSync4, promises as fs10 } from "fs";
6852
+ import path9 from "path";
5356
6853
  import { fileURLToPath as fileURLToPath3, pathToFileURL } from "url";
5357
6854
  async function detectNextJsProject(projectPath) {
5358
6855
  try {
5359
- const pkgPath = path6.join(projectPath, "package.json");
6856
+ const pkgPath = path9.join(projectPath, "package.json");
5360
6857
  const content = await fs10.readFile(pkgPath, "utf-8");
5361
6858
  const pkg = JSON.parse(content);
5362
6859
  const deps = pkg.dependencies ?? {};
@@ -5375,7 +6872,7 @@ async function loadNextJsEnvFiles(projectPath) {
5375
6872
  ];
5376
6873
  const dotenv = await import("dotenv");
5377
6874
  for (const file of files) {
5378
- const abs = path6.join(projectPath, file);
6875
+ const abs = path9.join(projectPath, file);
5379
6876
  try {
5380
6877
  await fs10.access(abs);
5381
6878
  } catch {
@@ -5387,20 +6884,20 @@ async function loadNextJsEnvFiles(projectPath) {
5387
6884
  function getThisDir() {
5388
6885
  if (typeof __dirname === "string") return __dirname;
5389
6886
  const url = import.meta.url;
5390
- return path6.dirname(fileURLToPath3(url));
6887
+ return path9.dirname(fileURLToPath3(url));
5391
6888
  }
5392
6889
  function resolveShimPath(filename) {
5393
6890
  const thisDir = getThisDir();
5394
6891
  const candidates = [
5395
6892
  // Production: `dist/` next to this module
5396
- path6.join(thisDir, "shims", filename),
6893
+ path9.join(thisDir, "shims", filename),
5397
6894
  // Test / dev: one level up (e.g., from `dist/utils/` back to `src/shims/`)
5398
- path6.join(thisDir, "..", "shims", filename),
5399
- path6.join(thisDir, "..", "..", "src", "shims", filename),
5400
- path6.join(thisDir, "..", "src", "shims", filename)
6895
+ path9.join(thisDir, "..", "shims", filename),
6896
+ path9.join(thisDir, "..", "..", "src", "shims", filename),
6897
+ path9.join(thisDir, "..", "src", "shims", filename)
5401
6898
  ];
5402
6899
  for (const candidate of candidates) {
5403
- if (existsSync3(candidate)) return candidate;
6900
+ if (existsSync4(candidate)) return candidate;
5404
6901
  }
5405
6902
  return void 0;
5406
6903
  }
@@ -5418,7 +6915,7 @@ async function registerNextShimsInProcess() {
5418
6915
  const cjsPath = getShimCjsPreloadPath();
5419
6916
  if (cjsPath) {
5420
6917
  const { createRequire: createRequire3 } = await import("module");
5421
- const req = createRequire3(pathToFileURL(getThisDir() + path6.sep).href);
6918
+ const req = createRequire3(pathToFileURL(getThisDir() + path9.sep).href);
5422
6919
  req(cjsPath);
5423
6920
  anyRegistered = true;
5424
6921
  }
@@ -5426,7 +6923,7 @@ async function registerNextShimsInProcess() {
5426
6923
  if (loaderPath) {
5427
6924
  const { register } = await import("module");
5428
6925
  const loaderUrl = pathToFileURL(loaderPath).href;
5429
- register(loaderUrl, pathToFileURL(getThisDir() + path6.sep).href);
6926
+ register(loaderUrl, pathToFileURL(getThisDir() + path9.sep).href);
5430
6927
  anyRegistered = true;
5431
6928
  }
5432
6929
  return anyRegistered;
@@ -5452,12 +6949,12 @@ function quoteNodeOption(value) {
5452
6949
 
5453
6950
  // src/utils/update-check.ts
5454
6951
  import { readFileSync } from "fs";
5455
- import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
6952
+ import { mkdir as mkdir3, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
5456
6953
  import { createRequire } from "module";
5457
- import os4 from "os";
5458
- import path7 from "path";
5459
- var CACHE_DIR = path7.join(os4.homedir(), ".mcp-use");
5460
- var CACHE_FILE = path7.join(CACHE_DIR, "update-check.json");
6954
+ import os5 from "os";
6955
+ import path10 from "path";
6956
+ var CACHE_DIR = path10.join(os5.homedir(), ".mcp-use");
6957
+ var CACHE_FILE = path10.join(CACHE_DIR, "update-check.json");
5461
6958
  var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
5462
6959
  var FETCH_TIMEOUT_MS = 3e3;
5463
6960
  var PACKAGE_NAME = "mcp-use";
@@ -5490,7 +6987,7 @@ async function readCache() {
5490
6987
  }
5491
6988
  async function writeCache(latestVersion) {
5492
6989
  try {
5493
- await mkdir2(CACHE_DIR, { recursive: true });
6990
+ await mkdir3(CACHE_DIR, { recursive: true });
5494
6991
  const cache = {
5495
6992
  lastChecked: (/* @__PURE__ */ new Date()).toISOString(),
5496
6993
  latestVersion
@@ -5540,12 +7037,12 @@ function resolveInstalledVersion(projectPath) {
5540
7037
  if (projectPath) {
5541
7038
  attempts.push(() => {
5542
7039
  const projectRequire = createRequire(
5543
- path7.join(projectPath, "package.json")
7040
+ path10.join(projectPath, "package.json")
5544
7041
  );
5545
7042
  return projectRequire.resolve(`${PACKAGE_NAME}/package.json`);
5546
7043
  });
5547
7044
  }
5548
- attempts.push(() => path7.join(__dirname, "../../mcp-use/package.json"));
7045
+ attempts.push(() => path10.join(__dirname, "../../mcp-use/package.json"));
5549
7046
  for (const attempt of attempts) {
5550
7047
  try {
5551
7048
  const pkgPath = attempt();
@@ -5581,14 +7078,14 @@ A new release of ${source_default.bold(PACKAGE_NAME)} is available: ${source_def
5581
7078
  }
5582
7079
 
5583
7080
  // src/index.ts
5584
- var program = new Command6();
7081
+ var program = new Command7();
5585
7082
  var packageContent = readFileSync2(
5586
- path8.join(__dirname, "../package.json"),
7083
+ path11.join(__dirname, "../package.json"),
5587
7084
  "utf-8"
5588
7085
  );
5589
7086
  var packageJson = JSON.parse(packageContent);
5590
7087
  var packageVersion = packageJson.version || "unknown";
5591
- program.name("mcp-use").description("Create and run MCP servers with ui resources widgets").version(packageVersion);
7088
+ 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)");
5592
7089
  function displayPackageVersions(projectPath) {
5593
7090
  const packages = [
5594
7091
  { name: "@mcp-use/cli", relativePath: "../package.json" },
@@ -5614,14 +7111,14 @@ function displayPackageVersions(projectPath) {
5614
7111
  if (projectPath) {
5615
7112
  try {
5616
7113
  const projectRequire = createRequire2(
5617
- path8.join(projectPath, "package.json")
7114
+ path11.join(projectPath, "package.json")
5618
7115
  );
5619
7116
  pkgPath = projectRequire.resolve(`${pkg.name}/package.json`);
5620
7117
  } catch (resolveError) {
5621
- pkgPath = path8.join(__dirname, pkg.relativePath);
7118
+ pkgPath = path11.join(__dirname, pkg.relativePath);
5622
7119
  }
5623
7120
  } else {
5624
- pkgPath = path8.join(__dirname, pkg.relativePath);
7121
+ pkgPath = path11.join(__dirname, pkg.relativePath);
5625
7122
  }
5626
7123
  const pkgContent = readFileSync2(pkgPath, "utf-8");
5627
7124
  const pkgJson = JSON.parse(pkgContent);
@@ -5678,7 +7175,7 @@ function normalizeBrowserHost(host) {
5678
7175
  return host === "0.0.0.0" ? "localhost" : host;
5679
7176
  }
5680
7177
  function runCommand(command, args, cwd, env2, filterStderr = false) {
5681
- const proc = spawn(command, args, {
7178
+ const proc = spawn3(command, args, {
5682
7179
  cwd,
5683
7180
  stdio: filterStderr ? ["inherit", "inherit", "pipe"] : "inherit",
5684
7181
  shell: process.platform === "win32",
@@ -5711,7 +7208,7 @@ async function startTunnel(port, subdomain) {
5711
7208
  if (subdomain) {
5712
7209
  tunnelArgs.push("--subdomain", subdomain);
5713
7210
  }
5714
- const proc = spawn("npx", tunnelArgs, {
7211
+ const proc = spawn3("npx", tunnelArgs, {
5715
7212
  stdio: ["ignore", "pipe", "pipe"],
5716
7213
  shell: process.platform === "win32"
5717
7214
  });
@@ -5775,21 +7272,21 @@ async function startTunnel(port, subdomain) {
5775
7272
  }
5776
7273
  async function resolveEntryFile(projectPath, cliEntry, mcpDir) {
5777
7274
  if (cliEntry) {
5778
- await access(path8.join(projectPath, cliEntry)).catch(() => {
7275
+ await access(path11.join(projectPath, cliEntry)).catch(() => {
5779
7276
  throw new Error(`File not found: ${cliEntry}`);
5780
7277
  });
5781
7278
  return cliEntry;
5782
7279
  }
5783
7280
  if (mcpDir) {
5784
7281
  const mcpCandidates = [
5785
- path8.join(mcpDir, "index.ts"),
5786
- path8.join(mcpDir, "index.tsx"),
5787
- path8.join(mcpDir, "server.ts"),
5788
- path8.join(mcpDir, "server.tsx")
7282
+ path11.join(mcpDir, "index.ts"),
7283
+ path11.join(mcpDir, "index.tsx"),
7284
+ path11.join(mcpDir, "server.ts"),
7285
+ path11.join(mcpDir, "server.tsx")
5789
7286
  ];
5790
7287
  for (const candidate of mcpCandidates) {
5791
7288
  try {
5792
- await access(path8.join(projectPath, candidate));
7289
+ await access(path11.join(projectPath, candidate));
5793
7290
  return candidate;
5794
7291
  } catch {
5795
7292
  continue;
@@ -5798,17 +7295,17 @@ async function resolveEntryFile(projectPath, cliEntry, mcpDir) {
5798
7295
  throw new Error(
5799
7296
  `No entry file found inside ${mcpDir}.
5800
7297
 
5801
- Expected one of: ${mcpCandidates.map((c) => path8.relative(projectPath, path8.join(projectPath, c))).join(", ")}
7298
+ Expected one of: ${mcpCandidates.map((c) => path11.relative(projectPath, path11.join(projectPath, c))).join(", ")}
5802
7299
 
5803
7300
  Fix this by either:
5804
- 1. Creating ${path8.join(mcpDir, "index.ts")}, or
7301
+ 1. Creating ${path11.join(mcpDir, "index.ts")}, or
5805
7302
  2. Passing --entry <file> on the command line`
5806
7303
  );
5807
7304
  }
5808
7305
  const candidates = ["index.ts", "src/index.ts", "server.ts", "src/server.ts"];
5809
7306
  for (const candidate of candidates) {
5810
7307
  try {
5811
- await access(path8.join(projectPath, candidate));
7308
+ await access(path11.join(projectPath, candidate));
5812
7309
  return candidate;
5813
7310
  } catch {
5814
7311
  continue;
@@ -5826,7 +7323,7 @@ Fix this by either:
5826
7323
  }
5827
7324
  function resolveWidgetsDir(cliWidgetsDir, mcpDir) {
5828
7325
  if (cliWidgetsDir) return cliWidgetsDir;
5829
- if (mcpDir) return path8.join(mcpDir, "resources");
7326
+ if (mcpDir) return path11.join(mcpDir, "resources");
5830
7327
  return "resources";
5831
7328
  }
5832
7329
  function makeWidgetServerOnlyGuard(widgetName) {
@@ -5861,7 +7358,7 @@ function isBunRuntime() {
5861
7358
  return typeof globalThis.Bun !== "undefined" || typeof process.versions.bun === "string";
5862
7359
  }
5863
7360
  async function generateToolRegistryTypesForServer(projectPath, serverFileRelative) {
5864
- const serverFile = path8.join(projectPath, serverFileRelative);
7361
+ const serverFile = path11.join(projectPath, serverFileRelative);
5865
7362
  const serverFileExists = await access(serverFile).then(() => true).catch(() => false);
5866
7363
  if (!serverFileExists) {
5867
7364
  throw new Error(`Server file not found: ${serverFile}`);
@@ -5887,7 +7384,7 @@ async function generateToolRegistryTypesForServer(projectPath, serverFileRelativ
5887
7384
  await loadNextJsEnvFiles(projectPath);
5888
7385
  await registerNextShimsInProcess();
5889
7386
  }
5890
- const projectTsconfigPath = path8.join(projectPath, "tsconfig.json");
7387
+ const projectTsconfigPath = path11.join(projectPath, "tsconfig.json");
5891
7388
  const hasTsconfig = await access(projectTsconfigPath).then(() => true).catch(() => false);
5892
7389
  if (hasTsconfig) {
5893
7390
  process.env.TSX_TSCONFIG_PATH = projectTsconfigPath;
@@ -5896,7 +7393,7 @@ async function generateToolRegistryTypesForServer(projectPath, serverFileRelativ
5896
7393
  if (previousCwd !== projectPath) process.chdir(projectPath);
5897
7394
  try {
5898
7395
  const projectRequire = createRequire2(
5899
- path8.join(projectPath, "package.json")
7396
+ path11.join(projectPath, "package.json")
5900
7397
  );
5901
7398
  const tsxEsmApiPath = projectRequire.resolve("tsx/esm/api");
5902
7399
  const tsxEsmApi = await import(pathToFileURL2(tsxEsmApiPath).href);
@@ -5923,8 +7420,8 @@ async function generateToolRegistryTypesForServer(projectPath, serverFileRelativ
5923
7420
  "No MCPServer instance found. Make sure your server file creates an MCPServer instance."
5924
7421
  );
5925
7422
  }
5926
- const mcpUsePath = path8.join(projectPath, "node_modules", "mcp-use");
5927
- const { generateToolRegistryTypes } = await import(pathToFileURL2(path8.join(mcpUsePath, "dist", "src", "server", "index.js")).href).then((mod) => mod);
7423
+ const mcpUsePath = path11.join(projectPath, "node_modules", "mcp-use");
7424
+ const { generateToolRegistryTypes } = await import(pathToFileURL2(path11.join(mcpUsePath, "dist", "src", "server", "index.js")).href).then((mod) => mod);
5928
7425
  if (!generateToolRegistryTypes) {
5929
7426
  throw new Error("generateToolRegistryTypes not found in mcp-use package");
5930
7427
  }
@@ -5942,7 +7439,7 @@ async function buildWidgets(projectPath, options = {}) {
5942
7439
  const { promises: fs11 } = await import("fs");
5943
7440
  const { build } = await import("vite");
5944
7441
  const widgetsDirRelative = options.widgetsDir ?? "resources";
5945
- const resourcesDir = path8.resolve(projectPath, widgetsDirRelative);
7442
+ const resourcesDir = path11.resolve(projectPath, widgetsDirRelative);
5946
7443
  const mcpUrl = process.env.MCP_URL;
5947
7444
  try {
5948
7445
  await access(resourcesDir);
@@ -5964,10 +7461,10 @@ async function buildWidgets(projectPath, options = {}) {
5964
7461
  if (dirent.isFile() && (dirent.name.endsWith(".tsx") || dirent.name.endsWith(".ts"))) {
5965
7462
  entries.push({
5966
7463
  name: dirent.name.replace(/\.tsx?$/, ""),
5967
- path: path8.join(resourcesDir, dirent.name)
7464
+ path: path11.join(resourcesDir, dirent.name)
5968
7465
  });
5969
7466
  } else if (dirent.isDirectory()) {
5970
- const widgetPath = path8.join(resourcesDir, dirent.name, "widget.tsx");
7467
+ const widgetPath = path11.join(resourcesDir, dirent.name, "widget.tsx");
5971
7468
  try {
5972
7469
  await fs11.access(widgetPath);
5973
7470
  entries.push({
@@ -5997,14 +7494,14 @@ async function buildWidgets(projectPath, options = {}) {
5997
7494
  );
5998
7495
  const react = (await import("@vitejs/plugin-react")).default;
5999
7496
  const tailwindcss = (await import("@tailwindcss/vite")).default;
6000
- const projectTsconfigPath = path8.join(projectPath, "tsconfig.json");
7497
+ const projectTsconfigPath = path11.join(projectPath, "tsconfig.json");
6001
7498
  let hasProjectTsconfig = false;
6002
7499
  try {
6003
7500
  await access(projectTsconfigPath);
6004
7501
  hasProjectTsconfig = true;
6005
7502
  } catch {
6006
7503
  }
6007
- const packageJsonPath = path8.join(projectPath, "package.json");
7504
+ const packageJsonPath = path11.join(projectPath, "package.json");
6008
7505
  let favicon = "";
6009
7506
  try {
6010
7507
  const pkgContent = await fs11.readFile(packageJsonPath, "utf-8");
@@ -6016,16 +7513,16 @@ async function buildWidgets(projectPath, options = {}) {
6016
7513
  const widgetName = entry.name;
6017
7514
  const entryPath = entry.path.replace(/\\/g, "/");
6018
7515
  console.log(source_default.gray(` - Building ${widgetName}...`));
6019
- const tempDir = path8.join(projectPath, ".mcp-use", widgetName);
7516
+ const tempDir = path11.join(projectPath, ".mcp-use", widgetName);
6020
7517
  await fs11.mkdir(tempDir, { recursive: true });
6021
- const relativeResourcesPath = path8.relative(tempDir, resourcesDir).replace(/\\/g, "/");
6022
- const mcpUsePath = path8.join(projectPath, "node_modules", "mcp-use");
6023
- const relativeMcpUsePath = path8.relative(tempDir, mcpUsePath).replace(/\\/g, "/");
6024
- const projectSrcDir = path8.join(projectPath, "src");
7518
+ const relativeResourcesPath = path11.relative(tempDir, resourcesDir).replace(/\\/g, "/");
7519
+ const mcpUsePath = path11.join(projectPath, "node_modules", "mcp-use");
7520
+ const relativeMcpUsePath = path11.relative(tempDir, mcpUsePath).replace(/\\/g, "/");
7521
+ const projectSrcDir = path11.join(projectPath, "src");
6025
7522
  let projectSrcSourceLine = "";
6026
7523
  try {
6027
7524
  await access(projectSrcDir);
6028
- const relativeProjectSrcPath = path8.relative(tempDir, projectSrcDir).replace(/\\/g, "/");
7525
+ const relativeProjectSrcPath = path11.relative(tempDir, projectSrcDir).replace(/\\/g, "/");
6029
7526
  projectSrcSourceLine = `@source "${relativeProjectSrcPath}";
6030
7527
  `;
6031
7528
  } catch {
@@ -6036,7 +7533,7 @@ async function buildWidgets(projectPath, options = {}) {
6036
7533
  @source "${relativeResourcesPath}";
6037
7534
  @source "${relativeMcpUsePath}/**/*.{ts,tsx,js,jsx}";
6038
7535
  ${projectSrcSourceLine}`;
6039
- await fs11.writeFile(path8.join(tempDir, "styles.css"), cssContent, "utf8");
7536
+ await fs11.writeFile(path11.join(tempDir, "styles.css"), cssContent, "utf8");
6040
7537
  const entryContent = `import React from 'react'
6041
7538
  import { createRoot } from 'react-dom/client'
6042
7539
  import './styles.css'
@@ -6061,9 +7558,9 @@ if (container && Component) {
6061
7558
  <script type="module" src="/entry.tsx"></script>
6062
7559
  </body>
6063
7560
  </html>`;
6064
- await fs11.writeFile(path8.join(tempDir, "entry.tsx"), entryContent, "utf8");
6065
- await fs11.writeFile(path8.join(tempDir, "index.html"), htmlContent, "utf8");
6066
- const outDir = path8.join(
7561
+ await fs11.writeFile(path11.join(tempDir, "entry.tsx"), entryContent, "utf8");
7562
+ await fs11.writeFile(path11.join(tempDir, "index.html"), htmlContent, "utf8");
7563
+ const outDir = path11.join(
6067
7564
  projectPath,
6068
7565
  "dist",
6069
7566
  "resources",
@@ -6073,13 +7570,13 @@ if (container && Component) {
6073
7570
  const baseUrl = mcpUrl ? `${mcpUrl}/${widgetName}/` : `/mcp-use/widgets/${widgetName}/`;
6074
7571
  let widgetMetadata = {};
6075
7572
  try {
6076
- const metadataTempDir = path8.join(
7573
+ const metadataTempDir = path11.join(
6077
7574
  projectPath,
6078
7575
  ".mcp-use",
6079
7576
  `${widgetName}-metadata`
6080
7577
  );
6081
7578
  await fs11.mkdir(metadataTempDir, { recursive: true });
6082
- const { createServer } = await import("vite");
7579
+ const { createServer: createServer2 } = await import("vite");
6083
7580
  const nodeStubsPlugin = {
6084
7581
  name: "node-stubs",
6085
7582
  enforce: "pre",
@@ -6107,9 +7604,9 @@ export default PostHog;
6107
7604
  }
6108
7605
  };
6109
7606
  const serverOnlyGuard = makeWidgetServerOnlyGuard(widgetName);
6110
- const metadataServer = await createServer({
7607
+ const metadataServer = await createServer2({
6111
7608
  root: metadataTempDir,
6112
- cacheDir: path8.join(metadataTempDir, ".vite-cache"),
7609
+ cacheDir: path11.join(metadataTempDir, ".vite-cache"),
6113
7610
  plugins: [serverOnlyGuard, nodeStubsPlugin, tailwindcss(), react()],
6114
7611
  // When the project has a tsconfig, enable Vite's native tsconfig-paths
6115
7612
  // resolver so `@/*` (or any custom alias) resolves through the
@@ -6340,7 +7837,7 @@ export default {
6340
7837
  // Inline all assets under 100MB (effectively all)
6341
7838
  } : {},
6342
7839
  rolldownOptions: {
6343
- input: path8.join(tempDir, "index.html"),
7840
+ input: path11.join(tempDir, "index.html"),
6344
7841
  external: (id) => {
6345
7842
  return false;
6346
7843
  }
@@ -6348,11 +7845,11 @@ export default {
6348
7845
  }
6349
7846
  });
6350
7847
  try {
6351
- const assetsDir = path8.join(outDir, "assets");
7848
+ const assetsDir = path11.join(outDir, "assets");
6352
7849
  const assetFiles = await fs11.readdir(assetsDir);
6353
7850
  const jsFiles = assetFiles.filter((f) => f.endsWith(".js"));
6354
7851
  for (const jsFile of jsFiles) {
6355
- const jsPath = path8.join(assetsDir, jsFile);
7852
+ const jsPath = path11.join(assetsDir, jsFile);
6356
7853
  let content = await fs11.readFile(jsPath, "utf8");
6357
7854
  const zodConfigPatterns = [
6358
7855
  // Non-minified: export const globalConfig = {}
@@ -6384,7 +7881,7 @@ export default {
6384
7881
  const mcpServerUrl = process.env.MCP_SERVER_URL;
6385
7882
  if (mcpServerUrl) {
6386
7883
  try {
6387
- const htmlPath = path8.join(outDir, "index.html");
7884
+ const htmlPath = path11.join(outDir, "index.html");
6388
7885
  let html = await fs11.readFile(htmlPath, "utf8");
6389
7886
  const injectionScript = `<script>window.__getFile = (filename) => { return "${mcpUrl}/${widgetName}/"+filename }; window.__mcpPublicUrl = "${mcpServerUrl}/mcp-use/public"; window.__mcpPublicAssetsUrl = "${mcpUrl}/public";</script>`;
6390
7887
  if (!html.includes("window.__mcpPublicUrl")) {
@@ -6460,7 +7957,7 @@ async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
6460
7957
  for (const file of literalFiles) {
6461
7958
  if (/\.tsx?$/.test(file) && !file.endsWith(".d.ts")) {
6462
7959
  try {
6463
- await access(path8.join(projectPath, file));
7960
+ await access(path11.join(projectPath, file));
6464
7961
  files.push(file);
6465
7962
  } catch {
6466
7963
  }
@@ -6468,13 +7965,13 @@ async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
6468
7965
  }
6469
7966
  const excludeSet = new Set(excludePatterns.map((e) => e.replace(/\*+/g, "")));
6470
7967
  for (const prefix of dirPrefixes) {
6471
- const dirPath = path8.join(projectPath, prefix);
7968
+ const dirPath = path11.join(projectPath, prefix);
6472
7969
  try {
6473
7970
  const entries = await fs11.readdir(dirPath, { recursive: true });
6474
7971
  for (const entry of entries) {
6475
7972
  const entryStr = String(entry);
6476
- const rel = path8.join(prefix, entryStr);
6477
- if (/\.tsx?$/.test(entryStr) && !entryStr.endsWith(".d.ts") && !excludeSet.has(rel.split(path8.sep)[0])) {
7973
+ const rel = path11.join(prefix, entryStr);
7974
+ if (/\.tsx?$/.test(entryStr) && !entryStr.endsWith(".d.ts") && !excludeSet.has(rel.split(path11.sep)[0])) {
6478
7975
  files.push(rel);
6479
7976
  }
6480
7977
  }
@@ -6486,7 +7983,7 @@ async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
6486
7983
  async function transpileWithEsbuild(projectPath) {
6487
7984
  const esbuild = await import("esbuild");
6488
7985
  const { promises: fs11 } = await import("fs");
6489
- const tsconfigPath = path8.join(projectPath, "tsconfig.json");
7986
+ const tsconfigPath = path11.join(projectPath, "tsconfig.json");
6490
7987
  let tsconfig = {};
6491
7988
  try {
6492
7989
  const raw = await fs11.readFile(tsconfigPath, "utf-8");
@@ -6516,10 +8013,10 @@ async function transpileWithEsbuild(projectPath) {
6516
8013
  const target = (compilerOptions.target || "ES2022").toLowerCase();
6517
8014
  const moduleStr = (compilerOptions.module || "ESNext").toLowerCase();
6518
8015
  const format = moduleStr.includes("commonjs") ? "cjs" : "esm";
6519
- const outbase = compilerOptions.rootDir ? path8.resolve(projectPath, compilerOptions.rootDir) : projectPath;
8016
+ const outbase = compilerOptions.rootDir ? path11.resolve(projectPath, compilerOptions.rootDir) : projectPath;
6520
8017
  await esbuild.build({
6521
- entryPoints: files.map((f) => path8.join(projectPath, f)),
6522
- outdir: path8.join(projectPath, outDir),
8018
+ entryPoints: files.map((f) => path11.join(projectPath, f)),
8019
+ outdir: path11.join(projectPath, outDir),
6523
8020
  outbase,
6524
8021
  bundle: true,
6525
8022
  packages: "external",
@@ -6546,7 +8043,7 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
6546
8043
  "Inline all JS/CSS into HTML (required for VS Code MCP Apps)"
6547
8044
  ).option("--no-inline", "Keep JS/CSS as separate files (default)").option("--no-typecheck", "Skip TypeScript type checking (faster builds)").action(async (options) => {
6548
8045
  try {
6549
- const projectPath = path8.resolve(options.path);
8046
+ const projectPath = path11.resolve(options.path);
6550
8047
  const { promises: fs11 } = await import("fs");
6551
8048
  displayPackageVersions(projectPath);
6552
8049
  const mcpDir = options.mcpDir;
@@ -6606,7 +8103,7 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
6606
8103
  }
6607
8104
  if (options.typecheck !== false && !mcpDir) {
6608
8105
  console.log(source_default.gray("Type checking..."));
6609
- const tscBin = path8.join(
8106
+ const tscBin = path11.join(
6610
8107
  projectPath,
6611
8108
  "node_modules",
6612
8109
  "typescript",
@@ -6629,7 +8126,7 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
6629
8126
  if (mcpDir) {
6630
8127
  entryPoint = sourceServerFile;
6631
8128
  } else {
6632
- const baseName = path8.basename(sourceServerFile, ".ts") + ".js";
8129
+ const baseName = path11.basename(sourceServerFile, ".ts") + ".js";
6633
8130
  const possibleOutputs = [
6634
8131
  `dist/${baseName}`,
6635
8132
  // rootDir set to project root or src
@@ -6640,7 +8137,7 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
6640
8137
  ];
6641
8138
  for (const candidate of possibleOutputs) {
6642
8139
  try {
6643
- await access(path8.join(projectPath, candidate));
8140
+ await access(path11.join(projectPath, candidate));
6644
8141
  entryPoint = candidate;
6645
8142
  break;
6646
8143
  } catch {
@@ -6649,17 +8146,17 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
6649
8146
  }
6650
8147
  }
6651
8148
  }
6652
- const publicDir = path8.join(projectPath, "public");
8149
+ const publicDir = path11.join(projectPath, "public");
6653
8150
  try {
6654
8151
  await fs11.access(publicDir);
6655
8152
  console.log(source_default.gray("Copying public assets..."));
6656
- await fs11.cp(publicDir, path8.join(projectPath, "dist", "public"), {
8153
+ await fs11.cp(publicDir, path11.join(projectPath, "dist", "public"), {
6657
8154
  recursive: true
6658
8155
  });
6659
8156
  console.log(source_default.green("\u2713 Public assets copied"));
6660
8157
  } catch {
6661
8158
  }
6662
- const manifestPath = path8.join(projectPath, "dist", "mcp-use.json");
8159
+ const manifestPath = path11.join(projectPath, "dist", "mcp-use.json");
6663
8160
  let existingManifest = {};
6664
8161
  try {
6665
8162
  const existingContent = await fs11.readFile(manifestPath, "utf-8");
@@ -6684,7 +8181,7 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
6684
8181
  // Server entry point for `mcp-use start`
6685
8182
  widgets: widgetsData
6686
8183
  };
6687
- await fs11.mkdir(path8.dirname(manifestPath), { recursive: true });
8184
+ await fs11.mkdir(path11.dirname(manifestPath), { recursive: true });
6688
8185
  await fs11.writeFile(
6689
8186
  manifestPath,
6690
8187
  JSON.stringify(manifest, null, 2),
@@ -6721,7 +8218,7 @@ program.command("dev").description("Run development server with auto-reload and
6721
8218
  ).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) => {
6722
8219
  try {
6723
8220
  process.env.MCP_USE_CLI_DEV = "1";
6724
- const projectPath = path8.resolve(options.path);
8221
+ const projectPath = path11.resolve(options.path);
6725
8222
  let port = parseInt(options.port, 10);
6726
8223
  const host = options.host;
6727
8224
  const useHmr = options.hmr !== false;
@@ -6749,7 +8246,7 @@ program.command("dev").description("Run development server with auto-reload and
6749
8246
  let tunnelUrl = void 0;
6750
8247
  if (options.tunnel) {
6751
8248
  try {
6752
- const manifestPath = path8.join(projectPath, "dist", "mcp-use.json");
8249
+ const manifestPath = path11.join(projectPath, "dist", "mcp-use.json");
6753
8250
  let existingSubdomain;
6754
8251
  try {
6755
8252
  const manifestContent = await readFile3(manifestPath, "utf-8");
@@ -6798,7 +8295,7 @@ program.command("dev").description("Run development server with auto-reload and
6798
8295
  manifest.tunnel = {};
6799
8296
  }
6800
8297
  manifest.tunnel.subdomain = tunnelSubdomain;
6801
- await mkdir3(path8.dirname(manifestPath), { recursive: true });
8298
+ await mkdir4(path11.dirname(manifestPath), { recursive: true });
6802
8299
  await writeFile3(
6803
8300
  manifestPath,
6804
8301
  JSON.stringify(manifest, null, 2),
@@ -6853,7 +8350,7 @@ program.command("dev").description("Run development server with auto-reload and
6853
8350
  let args;
6854
8351
  try {
6855
8352
  const projectRequire = createRequire4(
6856
- path8.join(projectPath, "package.json")
8353
+ path11.join(projectPath, "package.json")
6857
8354
  );
6858
8355
  const tsxPkgPath = projectRequire.resolve("tsx/package.json");
6859
8356
  const tsxPkg = JSON.parse(await readFile3(tsxPkgPath, "utf-8"));
@@ -6865,7 +8362,7 @@ program.command("dev").description("Run development server with auto-reload and
6865
8362
  } else {
6866
8363
  throw new Error("No bin field found in tsx package.json");
6867
8364
  }
6868
- const tsxBin = path8.resolve(path8.dirname(tsxPkgPath), binPath);
8365
+ const tsxBin = path11.resolve(path11.dirname(tsxPkgPath), binPath);
6869
8366
  cmd = "node";
6870
8367
  args = [tsxBin, "watch", serverFile];
6871
8368
  } catch (error) {
@@ -6954,7 +8451,7 @@ program.command("dev").description("Run development server with auto-reload and
6954
8451
  const chokidar = chokidarModule.default || chokidarModule;
6955
8452
  const { fileURLToPath: fileURLToPath4 } = await import("url");
6956
8453
  const { createRequire: createRequire3 } = await import("module");
6957
- const projectTsconfigPath = path8.join(projectPath, "tsconfig.json");
8454
+ const projectTsconfigPath = path11.join(projectPath, "tsconfig.json");
6958
8455
  let tsconfigAvailable = false;
6959
8456
  try {
6960
8457
  await access(projectTsconfigPath);
@@ -6966,7 +8463,7 @@ program.command("dev").description("Run development server with auto-reload and
6966
8463
  let tsxLoaderActive = false;
6967
8464
  try {
6968
8465
  const projectRequire = createRequire3(
6969
- path8.join(projectPath, "package.json")
8466
+ path11.join(projectPath, "package.json")
6970
8467
  );
6971
8468
  const tsxEsmApiPath = projectRequire.resolve("tsx/esm/api");
6972
8469
  const tsxEsmApi = await import(pathToFileURL2(tsxEsmApiPath).href);
@@ -6997,7 +8494,7 @@ program.command("dev").description("Run development server with auto-reload and
6997
8494
  )
6998
8495
  );
6999
8496
  }
7000
- const serverFilePath = path8.join(projectPath, serverFile);
8497
+ const serverFilePath = path11.join(projectPath, serverFile);
7001
8498
  const serverFileUrl = pathToFileURL2(serverFilePath).href;
7002
8499
  globalThis.__mcpUseHmrMode = true;
7003
8500
  const importServerModule = async () => {
@@ -7094,8 +8591,8 @@ program.command("dev").description("Run development server with auto-reload and
7094
8591
  }
7095
8592
  let watcher = chokidar.watch(".", {
7096
8593
  cwd: projectPath,
7097
- ignored: (path9, stats) => {
7098
- const normalizedPath = path9.replace(/\\/g, "/");
8594
+ ignored: (path12, stats) => {
8595
+ const normalizedPath = path12.replace(/\\/g, "/");
7099
8596
  if (/(^|\/)\.[^/]/.test(normalizedPath)) {
7100
8597
  return true;
7101
8598
  }
@@ -7269,7 +8766,7 @@ program.command("dev").description("Run development server with auto-reload and
7269
8766
  }
7270
8767
  tunnelUrl = void 0;
7271
8768
  if (withTunnel) {
7272
- const manifestPath = path8.join(projectPath, "dist", "mcp-use.json");
8769
+ const manifestPath = path11.join(projectPath, "dist", "mcp-use.json");
7273
8770
  let existingSubdomain;
7274
8771
  try {
7275
8772
  const manifestContent = await readFile3(manifestPath, "utf-8");
@@ -7306,7 +8803,7 @@ program.command("dev").description("Run development server with auto-reload and
7306
8803
  tunnelSubdomain = tunnelInfo.subdomain;
7307
8804
  process.env.MCP_URL = tunnelUrl;
7308
8805
  try {
7309
- const mPath = path8.join(projectPath, "dist", "mcp-use.json");
8806
+ const mPath = path11.join(projectPath, "dist", "mcp-use.json");
7310
8807
  let manifest = {};
7311
8808
  try {
7312
8809
  manifest = JSON.parse(await readFile3(mPath, "utf-8"));
@@ -7314,7 +8811,7 @@ program.command("dev").description("Run development server with auto-reload and
7314
8811
  }
7315
8812
  if (!manifest.tunnel) manifest.tunnel = {};
7316
8813
  manifest.tunnel.subdomain = tunnelSubdomain;
7317
- await mkdir3(path8.dirname(mPath), { recursive: true });
8814
+ await mkdir4(path11.dirname(mPath), { recursive: true });
7318
8815
  await writeFile3(mPath, JSON.stringify(manifest, null, 2), "utf-8");
7319
8816
  } catch {
7320
8817
  }
@@ -7418,7 +8915,7 @@ program.command("start").description("Start production server").option("-p, --pa
7418
8915
  "Folder holding the MCP entry + resources (e.g. 'src/mcp' for Next.js apps)"
7419
8916
  ).option("--port <port>", "Server port", "3000").option("--tunnel", "Expose server through a tunnel").action(async (options) => {
7420
8917
  try {
7421
- const projectPath = path8.resolve(options.path);
8918
+ const projectPath = path11.resolve(options.path);
7422
8919
  const portFlagProvided = process.argv.includes("--port") || process.argv.includes("-p") || process.argv.some((arg) => arg.startsWith("--port=")) || process.argv.some((arg) => arg.startsWith("-p="));
7423
8920
  let port = portFlagProvided ? parseInt(options.port, 10) : parseInt(process.env.PORT || options.port || "3000", 10);
7424
8921
  if (!await isPortAvailable(port)) {
@@ -7436,7 +8933,7 @@ program.command("start").description("Start production server").option("-p, --pa
7436
8933
  let tunnelSubdomain = void 0;
7437
8934
  if (options.tunnel) {
7438
8935
  try {
7439
- const manifestPath2 = path8.join(projectPath, "dist", "mcp-use.json");
8936
+ const manifestPath2 = path11.join(projectPath, "dist", "mcp-use.json");
7440
8937
  let existingSubdomain;
7441
8938
  try {
7442
8939
  const manifestContent = await readFile3(manifestPath2, "utf-8");
@@ -7491,7 +8988,7 @@ program.command("start").description("Start production server").option("-p, --pa
7491
8988
  manifest.tunnel = {};
7492
8989
  }
7493
8990
  manifest.tunnel.subdomain = subdomain;
7494
- await mkdir3(path8.dirname(manifestPath2), { recursive: true });
8991
+ await mkdir4(path11.dirname(manifestPath2), { recursive: true });
7495
8992
  await writeFile3(
7496
8993
  manifestPath2,
7497
8994
  JSON.stringify(manifest, null, 2),
@@ -7510,12 +9007,12 @@ program.command("start").description("Start production server").option("-p, --pa
7510
9007
  }
7511
9008
  }
7512
9009
  let serverFile;
7513
- const manifestPath = path8.join(projectPath, "dist", "mcp-use.json");
9010
+ const manifestPath = path11.join(projectPath, "dist", "mcp-use.json");
7514
9011
  try {
7515
9012
  const manifestContent = await readFile3(manifestPath, "utf-8");
7516
9013
  const manifest = JSON.parse(manifestContent);
7517
9014
  if (manifest.entryPoint) {
7518
- await access(path8.join(projectPath, manifest.entryPoint));
9015
+ await access(path11.join(projectPath, manifest.entryPoint));
7519
9016
  serverFile = manifest.entryPoint;
7520
9017
  }
7521
9018
  } catch {
@@ -7536,7 +9033,7 @@ program.command("start").description("Start production server").option("-p, --pa
7536
9033
  ];
7537
9034
  for (const candidate of serverCandidates) {
7538
9035
  try {
7539
- await access(path8.join(projectPath, candidate));
9036
+ await access(path11.join(projectPath, candidate));
7540
9037
  serverFile = candidate;
7541
9038
  break;
7542
9039
  } catch {
@@ -7587,13 +9084,13 @@ Looked for:
7587
9084
  if (isTsEntry) {
7588
9085
  try {
7589
9086
  const projectRequire = createRequire2(
7590
- path8.join(projectPath, "package.json")
9087
+ path11.join(projectPath, "package.json")
7591
9088
  );
7592
9089
  const tsxPkgPath = projectRequire.resolve("tsx/package.json");
7593
9090
  const tsxPkg = JSON.parse(await readFile3(tsxPkgPath, "utf-8"));
7594
9091
  const binField = typeof tsxPkg.bin === "string" ? tsxPkg.bin : tsxPkg.bin?.tsx ?? Object.values(tsxPkg.bin ?? {})[0];
7595
9092
  if (!binField) throw new Error("tsx bin entry not found");
7596
- const tsxBin = path8.resolve(path8.dirname(tsxPkgPath), binField);
9093
+ const tsxBin = path11.resolve(path11.dirname(tsxPkgPath), binField);
7597
9094
  spawnCmd = "node";
7598
9095
  spawnArgs = [tsxBin, serverFile];
7599
9096
  } catch (error) {
@@ -7606,7 +9103,7 @@ Looked for:
7606
9103
  spawnArgs = ["tsx", serverFile];
7607
9104
  }
7608
9105
  }
7609
- const serverProc = spawn(spawnCmd, spawnArgs, {
9106
+ const serverProc = spawn3(spawnCmd, spawnArgs, {
7610
9107
  cwd: projectPath,
7611
9108
  stdio: "inherit",
7612
9109
  env: env2
@@ -7742,7 +9239,7 @@ program.addCommand(createSkillsCommand());
7742
9239
  program.command("generate-types").description(
7743
9240
  "Generate TypeScript type definitions for tools (writes .mcp-use/tool-registry.d.ts)"
7744
9241
  ).option("-p, --path <path>", "Path to project directory", process.cwd()).option("--server <file>", "Server entry file", "index.ts").action(async (options) => {
7745
- const projectPath = path8.resolve(options.path);
9242
+ const projectPath = path11.resolve(options.path);
7746
9243
  try {
7747
9244
  console.log(source_default.blue("Generating tool registry types..."));
7748
9245
  const result = await generateToolRegistryTypesForServer(
@@ -7772,5 +9269,49 @@ program.hook("preAction", async (_thisCommand, actionCommand) => {
7772
9269
  const projectPath = actionCommand.opts().path;
7773
9270
  await notifyIfUpdateAvailable(projectPath);
7774
9271
  });
7775
- program.parse();
9272
+ var argv = process.argv;
9273
+ var clientIdx = argv[2] === "client" ? 2 : -1;
9274
+ var perClientName = clientIdx !== -1 && argv.length > clientIdx + 1 && !argv[clientIdx + 1].startsWith("-") && !RESERVED_CLIENT_SUBCOMMANDS.has(argv[clientIdx + 1]) ? argv[clientIdx + 1] : null;
9275
+ if (perClientName) {
9276
+ if (PER_CLIENT_SCOPES.has(perClientName)) {
9277
+ const rest2 = argv.slice(clientIdx + 1).join(" ");
9278
+ console.error(formatError("Missing server name."));
9279
+ console.error("");
9280
+ console.error(
9281
+ `'${perClientName}' is a per-server subcommand, not a server name. Address it through a saved server:`
9282
+ );
9283
+ console.error("");
9284
+ console.error(` mcp-use client <name> ${rest2}`);
9285
+ console.error("");
9286
+ console.error("See your saved servers with:");
9287
+ console.error(" mcp-use client list");
9288
+ process.exit(1);
9289
+ }
9290
+ const rest = argv.slice(clientIdx + 2);
9291
+ const isHelpOnly = rest.length === 0 || rest.length === 1 && (rest[0] === "--help" || rest[0] === "-h");
9292
+ (async () => {
9293
+ if (isHelpOnly) {
9294
+ const config = await getSession(perClientName);
9295
+ if (!config) {
9296
+ console.error(formatError(`Server '${perClientName}' not found.`));
9297
+ console.error("");
9298
+ console.error("Connect to an MCP server and save it under this name:");
9299
+ console.error(` mcp-use client connect ${perClientName} <url>`);
9300
+ console.error("");
9301
+ console.error("See your saved servers with:");
9302
+ console.error(" mcp-use client list");
9303
+ process.exit(1);
9304
+ }
9305
+ }
9306
+ await createPerClientCommand(perClientName).parseAsync(rest, {
9307
+ from: "user"
9308
+ });
9309
+ })().catch((err) => {
9310
+ const message = err instanceof Error ? err.message : String(err);
9311
+ console.error(formatError(message));
9312
+ process.exit(1);
9313
+ });
9314
+ } else {
9315
+ program.parse();
9316
+ }
7776
9317
  //# sourceMappingURL=index.js.map