@mcp-use/cli 3.0.0-canary.4 → 3.0.0-canary.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -503,7 +503,7 @@ 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 Command4 } from "commander";
506
+ import { Command as Command5 } from "commander";
507
507
  import "dotenv/config";
508
508
  import { spawn } from "child_process";
509
509
  import { readFileSync as readFileSync2 } from "fs";
@@ -1314,6 +1314,35 @@ var McpUseAPI = class _McpUseAPI {
1314
1314
  body: JSON.stringify(body)
1315
1315
  });
1316
1316
  }
1317
+ async listServers(params) {
1318
+ const search = new URLSearchParams();
1319
+ if (params?.organizationId) {
1320
+ search.set("organizationId", params.organizationId);
1321
+ }
1322
+ if (params?.limit != null) {
1323
+ search.set("limit", String(params.limit));
1324
+ }
1325
+ if (params?.skip != null) {
1326
+ search.set("skip", String(params.skip));
1327
+ }
1328
+ if (params?.sort) {
1329
+ search.set("sort", params.sort);
1330
+ }
1331
+ const q = search.toString();
1332
+ return this.request(`/servers${q ? `?${q}` : ""}`);
1333
+ }
1334
+ async getServer(idOrSlug) {
1335
+ const path8 = encodeURIComponent(idOrSlug);
1336
+ return this.request(`/servers/${path8}`);
1337
+ }
1338
+ async deleteServer(id) {
1339
+ await this.request(
1340
+ `/servers/${encodeURIComponent(id)}`,
1341
+ {
1342
+ method: "DELETE"
1343
+ }
1344
+ );
1345
+ }
1317
1346
  // ── Deployments ─────────────────────────────────────────────────
1318
1347
  async createDeployment(input) {
1319
1348
  return this.request("/deployments", {
@@ -1358,7 +1387,9 @@ var McpUseAPI = class _McpUseAPI {
1358
1387
  is_connected: resp.installations.length > 0,
1359
1388
  installations: resp.installations.map((i) => ({
1360
1389
  id: i.id,
1361
- installation_id: i.installationId
1390
+ installation_id: i.installationId,
1391
+ account_login: i.account?.login ?? "",
1392
+ account_type: i.account?.type ?? "User"
1362
1393
  }))
1363
1394
  };
1364
1395
  }
@@ -1387,7 +1418,27 @@ var McpUseAPI = class _McpUseAPI {
1387
1418
  }
1388
1419
  async getGitHubAppName() {
1389
1420
  if (process.env.MCP_GITHUB_APP_NAME) return process.env.MCP_GITHUB_APP_NAME;
1390
- return this.baseUrl.includes(".dev.") ? "mcp-use-dev" : "mcp-use";
1421
+ if (this.baseUrl.includes("localhost")) return "mcp-use-local";
1422
+ if (this.baseUrl.includes(".dev.")) return "mcp-use-dev";
1423
+ return "mcp-use";
1424
+ }
1425
+ /**
1426
+ * Returns the GitHub numeric installation ID (not the DB UUID) for the org.
1427
+ * Used for building direct installation settings URLs.
1428
+ */
1429
+ async getGitHubInstallationId() {
1430
+ const status = await this.getGitHubConnectionStatus();
1431
+ return status.installations?.[0]?.installation_id ?? null;
1432
+ }
1433
+ async createGitHubRepo(opts) {
1434
+ return this.request(`/github/installations/${opts.installationId}/repos`, {
1435
+ method: "POST",
1436
+ body: JSON.stringify({
1437
+ name: opts.name,
1438
+ private: opts.private ?? true,
1439
+ org: opts.org
1440
+ })
1441
+ });
1391
1442
  }
1392
1443
  };
1393
1444
 
@@ -2442,9 +2493,9 @@ async function listPromptsCommand(options) {
2442
2493
  }
2443
2494
  console.log(formatHeader(`Available Prompts (${prompts.length}):`));
2444
2495
  console.log("");
2445
- const tableData = prompts.map((prompt3) => ({
2446
- name: source_default.bold(prompt3.name),
2447
- description: prompt3.description || source_default.gray("No description")
2496
+ const tableData = prompts.map((prompt4) => ({
2497
+ name: source_default.bold(prompt4.name),
2498
+ description: prompt4.description || source_default.gray("No description")
2448
2499
  }));
2449
2500
  console.log(
2450
2501
  formatTable(tableData, [
@@ -2472,20 +2523,20 @@ async function getPromptCommand(promptName, argsJson, options) {
2472
2523
  }
2473
2524
  }
2474
2525
  console.error(formatInfo(`Getting prompt '${promptName}'...`));
2475
- const prompt3 = await session.getPrompt(promptName, args);
2526
+ const prompt4 = await session.getPrompt(promptName, args);
2476
2527
  if (options?.json) {
2477
- console.log(formatJson(prompt3));
2528
+ console.log(formatJson(prompt4));
2478
2529
  } else {
2479
2530
  console.log(formatHeader(`Prompt: ${promptName}`));
2480
2531
  console.log("");
2481
- if (prompt3.description) {
2482
- console.log(prompt3.description);
2532
+ if (prompt4.description) {
2533
+ console.log(prompt4.description);
2483
2534
  console.log("");
2484
2535
  }
2485
- if (prompt3.messages) {
2536
+ if (prompt4.messages) {
2486
2537
  console.log(formatHeader("Messages:"));
2487
2538
  console.log("");
2488
- console.log(formatPromptMessages(prompt3.messages));
2539
+ console.log(formatPromptMessages(prompt4.messages));
2489
2540
  }
2490
2541
  }
2491
2542
  } catch (error) {
@@ -2625,8 +2676,8 @@ async function interactiveCommand(options) {
2625
2676
  async (argsInput) => {
2626
2677
  try {
2627
2678
  const args = argsInput.trim() ? JSON.parse(argsInput) : {};
2628
- const prompt3 = await session.getPrompt(arg, args);
2629
- console.log(formatPromptMessages(prompt3.messages));
2679
+ const prompt4 = await session.getPrompt(arg, args);
2680
+ console.log(formatPromptMessages(prompt4.messages));
2630
2681
  } catch (error) {
2631
2682
  console.error(formatError(error.message));
2632
2683
  }
@@ -2792,6 +2843,20 @@ async function getGitInfo(cwd = process.cwd()) {
2792
2843
  hasUncommittedChanges: uncommittedChanges
2793
2844
  };
2794
2845
  }
2846
+ async function gitInit(cwd, message = "Initial commit") {
2847
+ await gitCommand("git init", cwd);
2848
+ await gitCommand("git add .", cwd);
2849
+ await gitCommand(`git commit -m "${message}"`, cwd);
2850
+ }
2851
+ async function gitAddRemoteAndPush(cwd, cloneUrl, branch = "main") {
2852
+ await gitCommand(`git remote add origin ${cloneUrl}`, cwd);
2853
+ await gitCommand(`git push -u origin ${branch}`, cwd);
2854
+ }
2855
+ async function gitCommitAndPush(cwd, message, branch = "main") {
2856
+ await gitCommand("git add .", cwd);
2857
+ await gitCommand(`git commit -m "${message}"`, cwd);
2858
+ await gitCommand(`git push origin ${branch}`, cwd);
2859
+ }
2795
2860
  function isGitHubUrl(url) {
2796
2861
  try {
2797
2862
  const parsedUrl = new URL(url);
@@ -2806,6 +2871,22 @@ function isGitHubUrl(url) {
2806
2871
  return false;
2807
2872
  }
2808
2873
 
2874
+ // src/utils/cloud-urls.ts
2875
+ var GATEWAY_DOMAIN = "run.mcp-use.com";
2876
+ function buildGatewayUrl(slugOrId) {
2877
+ return `https://${slugOrId}.${GATEWAY_DOMAIN}/mcp`;
2878
+ }
2879
+ function getMcpServerUrl(deployment) {
2880
+ if (deployment.mcpUrl) return deployment.mcpUrl;
2881
+ if (deployment.serverId) return buildGatewayUrl(deployment.serverId);
2882
+ return "";
2883
+ }
2884
+ function getMcpServerUrlForCloudServer(server) {
2885
+ if (server.mcpUrl) return server.mcpUrl;
2886
+ const hostKey = server.slug && server.slug.trim() || server.id;
2887
+ return buildGatewayUrl(hostKey);
2888
+ }
2889
+
2809
2890
  // src/utils/project-link.ts
2810
2891
  import { promises as fs8 } from "fs";
2811
2892
  import path4 from "path";
@@ -2852,10 +2933,6 @@ ${MCP_USE_DIR}
2852
2933
  }
2853
2934
 
2854
2935
  // src/commands/deploy.ts
2855
- var GATEWAY_DOMAIN = "run.mcp-use.com";
2856
- function buildGatewayUrl(slugOrId) {
2857
- return `https://${slugOrId}.${GATEWAY_DOMAIN}/mcp`;
2858
- }
2859
2936
  async function parseEnvFile(filePath) {
2860
2937
  try {
2861
2938
  const content = await fs9.readFile(filePath, "utf-8");
@@ -2865,9 +2942,7 @@ async function parseEnvFile(filePath) {
2865
2942
  let currentValue = "";
2866
2943
  for (let line of lines) {
2867
2944
  line = line.trim();
2868
- if (!line || line.startsWith("#")) {
2869
- continue;
2870
- }
2945
+ if (!line || line.startsWith("#")) continue;
2871
2946
  if (currentKey && !line.includes("=")) {
2872
2947
  currentValue += "\n" + line;
2873
2948
  continue;
@@ -2878,20 +2953,15 @@ async function parseEnvFile(filePath) {
2878
2953
  currentValue = "";
2879
2954
  }
2880
2955
  const equalIndex = line.indexOf("=");
2881
- if (equalIndex === -1) {
2882
- continue;
2883
- }
2956
+ if (equalIndex === -1) continue;
2884
2957
  const key = line.substring(0, equalIndex).trim();
2885
- let value = line.substring(equalIndex + 1).trim();
2958
+ const value = line.substring(equalIndex + 1).trim();
2886
2959
  if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
2887
- console.log(
2888
- source_default.yellow(`\u26A0\uFE0F Skipping invalid environment variable key: ${key}`)
2889
- );
2960
+ console.log(source_default.yellow(`\u26A0\uFE0F Skipping invalid env key: ${key}`));
2890
2961
  continue;
2891
2962
  }
2892
2963
  if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
2893
- value = value.slice(1, -1);
2894
- envVars[key] = value;
2964
+ envVars[key] = value.slice(1, -1);
2895
2965
  } else if (value.startsWith('"') || value.startsWith("'")) {
2896
2966
  currentKey = key;
2897
2967
  currentValue = value.slice(1);
@@ -2915,16 +2985,12 @@ async function parseEnvFile(filePath) {
2915
2985
  function parseEnvVar(envStr) {
2916
2986
  const equalIndex = envStr.indexOf("=");
2917
2987
  if (equalIndex === -1) {
2918
- throw new Error(
2919
- `Invalid environment variable format: "${envStr}". Expected KEY=VALUE`
2920
- );
2988
+ throw new Error(`Invalid env format: "${envStr}". Expected KEY=VALUE`);
2921
2989
  }
2922
2990
  const key = envStr.substring(0, equalIndex).trim();
2923
2991
  const value = envStr.substring(equalIndex + 1);
2924
2992
  if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
2925
- throw new Error(
2926
- `Invalid environment variable key: "${key}". Keys must start with a letter or underscore and contain only letters, numbers, and underscores.`
2927
- );
2993
+ throw new Error(`Invalid env key: "${key}".`);
2928
2994
  }
2929
2995
  return { key, value };
2930
2996
  }
@@ -2967,72 +3033,48 @@ async function buildEnvVars(options) {
2967
3033
  }
2968
3034
  async function isMcpProject(cwd = process.cwd()) {
2969
3035
  try {
2970
- const packageJsonPath = path5.join(cwd, "package.json");
2971
- const content = await fs9.readFile(packageJsonPath, "utf-8");
2972
- const packageJson2 = JSON.parse(content);
2973
- const hasMcpDeps = packageJson2.dependencies?.["mcp-use"] || packageJson2.dependencies?.["@modelcontextprotocol/sdk"] || packageJson2.devDependencies?.["mcp-use"] || packageJson2.devDependencies?.["@modelcontextprotocol/sdk"];
2974
- const hasMcpScripts = packageJson2.scripts?.mcp || packageJson2.scripts?.["mcp:dev"];
2975
- return !!(hasMcpDeps || hasMcpScripts);
3036
+ const content = await fs9.readFile(path5.join(cwd, "package.json"), "utf-8");
3037
+ const pkg = JSON.parse(content);
3038
+ return !!(pkg.dependencies?.["mcp-use"] || pkg.dependencies?.["@modelcontextprotocol/sdk"] || pkg.devDependencies?.["mcp-use"] || pkg.devDependencies?.["@modelcontextprotocol/sdk"]);
2976
3039
  } catch {
2977
3040
  return false;
2978
3041
  }
2979
3042
  }
2980
3043
  async function getProjectName(cwd = process.cwd()) {
2981
3044
  try {
2982
- const packageJsonPath = path5.join(cwd, "package.json");
2983
- const content = await fs9.readFile(packageJsonPath, "utf-8");
2984
- const packageJson2 = JSON.parse(content);
2985
- if (packageJson2.name) {
2986
- return packageJson2.name;
2987
- }
3045
+ const content = await fs9.readFile(path5.join(cwd, "package.json"), "utf-8");
3046
+ const pkg = JSON.parse(content);
3047
+ if (pkg.name) return pkg.name;
2988
3048
  } catch {
2989
3049
  }
2990
3050
  return path5.basename(cwd);
2991
3051
  }
2992
- async function detectBuildCommand(cwd = process.cwd()) {
3052
+ async function detectBuildCommand(cwd) {
2993
3053
  try {
2994
- const packageJsonPath = path5.join(cwd, "package.json");
2995
- const content = await fs9.readFile(packageJsonPath, "utf-8");
2996
- const packageJson2 = JSON.parse(content);
2997
- if (packageJson2.scripts?.build) {
2998
- return "npm run build";
2999
- }
3054
+ const content = await fs9.readFile(path5.join(cwd, "package.json"), "utf-8");
3055
+ if (JSON.parse(content).scripts?.build) return "npm run build";
3000
3056
  } catch {
3001
3057
  }
3002
3058
  return void 0;
3003
3059
  }
3004
- async function detectStartCommand(cwd = process.cwd()) {
3060
+ async function detectStartCommand(cwd) {
3005
3061
  try {
3006
- const packageJsonPath = path5.join(cwd, "package.json");
3007
- const content = await fs9.readFile(packageJsonPath, "utf-8");
3008
- const packageJson2 = JSON.parse(content);
3009
- if (packageJson2.scripts?.start) {
3010
- return "npm start";
3011
- }
3012
- if (packageJson2.main) {
3013
- return `node ${packageJson2.main}`;
3014
- }
3062
+ const content = await fs9.readFile(path5.join(cwd, "package.json"), "utf-8");
3063
+ const pkg = JSON.parse(content);
3064
+ if (pkg.scripts?.start) return "npm start";
3065
+ if (pkg.main) return `node ${pkg.main}`;
3015
3066
  } catch {
3016
3067
  }
3017
3068
  return void 0;
3018
3069
  }
3019
- async function detectRuntime(cwd = process.cwd()) {
3020
- try {
3021
- const pythonFiles = ["requirements.txt", "pyproject.toml", "setup.py"];
3022
- for (const file of pythonFiles) {
3023
- try {
3024
- await fs9.access(path5.join(cwd, file));
3025
- return "python";
3026
- } catch {
3027
- continue;
3028
- }
3029
- }
3070
+ async function detectRuntime(cwd) {
3071
+ for (const f of ["requirements.txt", "pyproject.toml", "setup.py"]) {
3030
3072
  try {
3031
- await fs9.access(path5.join(cwd, "package.json"));
3032
- return "node";
3073
+ await fs9.access(path5.join(cwd, f));
3074
+ return "python";
3033
3075
  } catch {
3076
+ continue;
3034
3077
  }
3035
- } catch {
3036
3078
  }
3037
3079
  return "node";
3038
3080
  }
@@ -3042,31 +3084,51 @@ async function prompt(question, defaultValue = "n") {
3042
3084
  input: process.stdin,
3043
3085
  output: process.stdout
3044
3086
  });
3045
- const defaultIndicator = defaultValue === "y" ? "Y/n" : "y/N";
3046
- const questionWithDefault = question.replace(
3047
- /(\(y\/n\):)/,
3048
- `(${defaultIndicator}):`
3049
- );
3087
+ const indicator = defaultValue === "y" ? "Y/n" : "y/N";
3088
+ const q = question.replace(/(\(y\/n\):)/, `(${indicator}):`);
3050
3089
  return new Promise((resolve2) => {
3051
- rl.question(questionWithDefault, (answer) => {
3090
+ rl.question(q, (answer) => {
3052
3091
  rl.close();
3053
- const trimmedAnswer = answer.trim().toLowerCase();
3054
- if (trimmedAnswer === "") {
3055
- resolve2(defaultValue === "y");
3056
- } else {
3057
- resolve2(trimmedAnswer === "y" || trimmedAnswer === "yes");
3058
- }
3092
+ const a = answer.trim().toLowerCase();
3093
+ if (a === "") resolve2(defaultValue === "y");
3094
+ else resolve2(a === "y" || a === "yes");
3059
3095
  });
3060
3096
  });
3061
3097
  }
3062
- function getMcpServerUrl(deployment) {
3063
- if (deployment.mcpUrl) {
3064
- return deployment.mcpUrl;
3098
+ async function promptText(question, defaultValue) {
3099
+ const readline = await import("readline");
3100
+ const rl = readline.createInterface({
3101
+ input: process.stdin,
3102
+ output: process.stdout
3103
+ });
3104
+ const suffix = defaultValue ? source_default.gray(` [${defaultValue}]`) : "";
3105
+ return new Promise((resolve2) => {
3106
+ rl.question(question + suffix + " ", (answer) => {
3107
+ rl.close();
3108
+ resolve2(answer.trim() || defaultValue || "");
3109
+ });
3110
+ });
3111
+ }
3112
+ var REQUIRED_IGNORES = [
3113
+ "node_modules",
3114
+ "dist",
3115
+ ".env",
3116
+ ".env.local",
3117
+ ".mcp-use"
3118
+ ];
3119
+ async function ensureGitignore(cwd) {
3120
+ const gitignorePath = path5.join(cwd, ".gitignore");
3121
+ let content = "";
3122
+ try {
3123
+ content = await fs9.readFile(gitignorePath, "utf-8");
3124
+ } catch {
3065
3125
  }
3066
- if (deployment.serverId) {
3067
- return buildGatewayUrl(deployment.serverId);
3126
+ const missing = REQUIRED_IGNORES.filter((entry) => !content.includes(entry));
3127
+ if (missing.length > 0) {
3128
+ const additions = missing.join("\n");
3129
+ const newContent = content + (content.endsWith("\n") ? "" : "\n") + additions + "\n";
3130
+ await fs9.writeFile(gitignorePath, newContent, "utf-8");
3068
3131
  }
3069
- return "";
3070
3132
  }
3071
3133
  async function displayDeploymentProgress(api, deploymentId, progressOptions) {
3072
3134
  const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
@@ -3076,11 +3138,10 @@ async function displayDeploymentProgress(api, deploymentId, progressOptions) {
3076
3138
  if (spinnerInterval) clearInterval(spinnerInterval);
3077
3139
  process.stdout.write("\r\x1B[K");
3078
3140
  spinnerInterval = setInterval(() => {
3079
- const frame = frames[frameIndex];
3080
- frameIndex = (frameIndex + 1) % frames.length;
3081
3141
  process.stdout.write(
3082
- "\r" + source_default.cyan(frame) + " " + source_default.gray(message)
3142
+ "\r" + source_default.cyan(frames[frameIndex]) + " " + source_default.gray(message)
3083
3143
  );
3144
+ frameIndex = (frameIndex + 1) % frames.length;
3084
3145
  }, 80);
3085
3146
  };
3086
3147
  const stopSpinner = () => {
@@ -3097,57 +3158,49 @@ async function displayDeploymentProgress(api, deploymentId, progressOptions) {
3097
3158
  let delay = 2e3;
3098
3159
  const maxDelay = 1e4;
3099
3160
  let buildLogOffset = 0;
3100
- const sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
3101
3161
  while (checkCount < maxChecks) {
3102
- await sleep(delay);
3162
+ const waitMs = delay;
3163
+ await new Promise((r) => setTimeout(r, waitMs));
3103
3164
  checkCount++;
3104
3165
  try {
3105
- const buildLogsResp = await api.getDeploymentBuildLogs(
3166
+ const resp = await api.getDeploymentBuildLogs(
3106
3167
  deploymentId,
3107
3168
  buildLogOffset
3108
3169
  );
3109
- if (buildLogsResp.logs.length > 0) {
3110
- const logLines = buildLogsResp.logs.split("\n").filter((l) => l.trim());
3111
- for (const line of logLines) {
3170
+ if (resp.logs.length > 0) {
3171
+ for (const line of resp.logs.split("\n").filter((l) => l.trim())) {
3112
3172
  try {
3113
- const logData = JSON.parse(line);
3114
- if (logData.line) {
3173
+ const d = JSON.parse(line);
3174
+ if (d.line) {
3115
3175
  stopSpinner();
3116
- const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
3117
- const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
3118
- console.log(stepPrefix + levelColor(logData.line));
3176
+ const color = d.level === "error" ? source_default.red : d.level === "warn" ? source_default.yellow : source_default.gray;
3177
+ const prefix = d.step ? source_default.cyan(`[${d.step}]`) + " " : "";
3178
+ console.log(prefix + color(d.line));
3119
3179
  }
3120
3180
  } catch {
3121
3181
  stopSpinner();
3122
3182
  console.log(source_default.gray(line));
3123
3183
  }
3124
3184
  }
3125
- buildLogOffset = buildLogsResp.offset;
3185
+ buildLogOffset = resp.offset;
3126
3186
  }
3127
3187
  } catch {
3128
3188
  }
3129
- const deployment = await api.getDeployment(deploymentId);
3130
- if (deployment.status === "running") {
3189
+ const dep = await api.getDeployment(deploymentId);
3190
+ if (dep.status === "running") {
3131
3191
  stopSpinner();
3132
- const mcpServerUrl = getMcpServerUrl(deployment);
3133
- let dashboardUrl = null;
3192
+ const mcpUrl = getMcpServerUrl(dep);
3134
3193
  const webUrl = (await getWebUrl()).replace(/\/$/, "");
3135
3194
  const config = await readConfig();
3136
- const orgSlug = config.orgSlug;
3137
- if (deployment.serverId) {
3138
- if (orgSlug) {
3139
- dashboardUrl = `${webUrl}/cloud/${orgSlug}/servers/${deployment.serverId}`;
3140
- } else {
3141
- dashboardUrl = `${webUrl}/cloud/servers/${deployment.serverId}`;
3142
- }
3195
+ let dashboardUrl = null;
3196
+ if (dep.serverId) {
3197
+ dashboardUrl = config.orgSlug ? `${webUrl}/cloud/${config.orgSlug}/servers/${dep.serverId}` : `${webUrl}/cloud/servers/${dep.serverId}`;
3143
3198
  }
3144
- const inspectorUrl = `https://inspector.manufact.com/inspector?autoConnect=${encodeURIComponent(
3145
- mcpServerUrl
3146
- )}`;
3199
+ const inspectorUrl = `https://inspector.manufact.com/inspector?autoConnect=${encodeURIComponent(mcpUrl)}`;
3147
3200
  console.log(source_default.green.bold("\u2713 Deployment successful!\n"));
3148
- if (mcpServerUrl) {
3201
+ if (mcpUrl) {
3149
3202
  console.log(source_default.white("\u{1F310} MCP Server URL:"));
3150
- console.log(source_default.cyan.bold(` ${mcpServerUrl}
3203
+ console.log(source_default.cyan.bold(` ${mcpUrl}
3151
3204
  `));
3152
3205
  }
3153
3206
  if (dashboardUrl) {
@@ -3158,39 +3211,42 @@ async function displayDeploymentProgress(api, deploymentId, progressOptions) {
3158
3211
  console.log(source_default.white("\u{1F50D} Inspector URL:"));
3159
3212
  console.log(source_default.cyan.bold(` ${inspectorUrl}
3160
3213
  `));
3161
- console.log(source_default.gray("Deployment ID: ") + source_default.white(deployment.id));
3214
+ console.log(source_default.gray("Deployment ID: ") + source_default.white(dep.id));
3162
3215
  return;
3163
- } else if (deployment.status === "failed") {
3216
+ } else if (dep.status === "failed") {
3164
3217
  stopSpinner();
3165
3218
  console.log(source_default.red.bold("\u2717 Deployment failed\n"));
3166
- if (deployment.error) {
3167
- console.log(source_default.red("Error: ") + deployment.error);
3168
- if (deployment.error.includes("No GitHub installations found")) {
3169
- console.log();
3170
- const retry = await promptGitHubInstallation(
3171
- api,
3172
- "not_connected",
3173
- void 0,
3174
- { yes: progressOptions?.yes }
3219
+ if (dep.error) {
3220
+ const internalPatterns = [
3221
+ "GraphQL",
3222
+ "authenticated",
3223
+ "INTERNAL",
3224
+ "Fly API",
3225
+ "token validation",
3226
+ "context deadline",
3227
+ "Bad gateway",
3228
+ "502",
3229
+ "503"
3230
+ ];
3231
+ const isInternalError = internalPatterns.some(
3232
+ (p) => dep.error.includes(p)
3233
+ );
3234
+ if (isInternalError) {
3235
+ console.log(
3236
+ source_default.red("Error: ") + "An internal infrastructure error occurred. Please try again."
3175
3237
  );
3176
- if (retry && deployment.serverId) {
3177
- console.log(source_default.cyan("\n\u{1F504} Retrying deployment...\n"));
3178
- const newDep = await api.createDeployment({
3179
- serverId: deployment.serverId,
3180
- trigger: "redeploy"
3181
- });
3182
- await displayDeploymentProgress(api, newDep.id, progressOptions);
3183
- return;
3184
- }
3238
+ console.log(source_default.gray(" Details: " + dep.error));
3239
+ } else {
3240
+ console.log(source_default.red("Error: ") + dep.error);
3185
3241
  }
3186
3242
  }
3187
3243
  process.exit(1);
3188
- } else if (deployment.status === "building" || deployment.status === "pending") {
3244
+ } else if (dep.status === "building" || dep.status === "pending") {
3189
3245
  startSpinner("Building and deploying...");
3190
3246
  delay = Math.min(delay * 1.2, maxDelay);
3191
3247
  } else {
3192
3248
  stopSpinner();
3193
- console.log(source_default.yellow("\u26A0\uFE0F Deployment status: ") + deployment.status);
3249
+ console.log(source_default.yellow("\u26A0\uFE0F Deployment status: ") + dep.status);
3194
3250
  return;
3195
3251
  }
3196
3252
  }
@@ -3202,58 +3258,12 @@ async function displayDeploymentProgress(api, deploymentId, progressOptions) {
3202
3258
  }
3203
3259
  async function checkRepoAccess(api, owner, repo) {
3204
3260
  try {
3205
- const reposResponse = await api.getGitHubRepos(true);
3206
- const repoFullName = `${owner}/${repo}`;
3207
- return reposResponse.repos.some((r) => r.full_name === repoFullName);
3208
- } catch (error) {
3209
- console.log(source_default.gray("Could not verify repository access"));
3261
+ const resp = await api.getGitHubRepos(true);
3262
+ return resp.repos.some((r) => r.full_name === `${owner}/${repo}`);
3263
+ } catch {
3210
3264
  return false;
3211
3265
  }
3212
3266
  }
3213
- var GITHUB_SETUP_POLL_INTERVAL_MS = 2e3;
3214
- var GITHUB_SETUP_POLL_MAX_MS = 12e4;
3215
- async function waitForGitHubSetupAfterBrowser(api, repoName, yes) {
3216
- if (!yes) {
3217
- console.log(source_default.gray("Waiting for GitHub configuration..."));
3218
- await prompt(
3219
- source_default.white("Press Enter when you've completed the GitHub setup..."),
3220
- "y"
3221
- );
3222
- return;
3223
- }
3224
- console.log(
3225
- source_default.gray(
3226
- "Waiting for GitHub configuration (polling every 2s, up to 2 min)..."
3227
- )
3228
- );
3229
- const deadline = Date.now() + GITHUB_SETUP_POLL_MAX_MS;
3230
- while (Date.now() < deadline) {
3231
- try {
3232
- const status = await api.getGitHubConnectionStatus();
3233
- if (!status.is_connected) {
3234
- await new Promise((r) => setTimeout(r, GITHUB_SETUP_POLL_INTERVAL_MS));
3235
- continue;
3236
- }
3237
- if (repoName) {
3238
- const parts = repoName.split("/");
3239
- const owner = parts[0];
3240
- const repo = parts[1];
3241
- if (owner && repo && await checkRepoAccess(api, owner, repo)) {
3242
- return;
3243
- }
3244
- } else {
3245
- return;
3246
- }
3247
- } catch {
3248
- }
3249
- await new Promise((r) => setTimeout(r, GITHUB_SETUP_POLL_INTERVAL_MS));
3250
- }
3251
- console.log(
3252
- source_default.yellow(
3253
- "\u26A0\uFE0F Timed out waiting for GitHub setup. Continuing with verification..."
3254
- )
3255
- );
3256
- }
3257
3267
  async function promptGitHubInstallation(api, reason, repoName, opts) {
3258
3268
  const yes = !!opts?.yes;
3259
3269
  console.log();
@@ -3279,96 +3289,48 @@ async function promptGitHubInstallation(api, reason, repoName, opts) {
3279
3289
  ),
3280
3290
  "y"
3281
3291
  );
3282
- if (!shouldInstall) {
3283
- return false;
3284
- }
3292
+ if (!shouldInstall) return false;
3285
3293
  try {
3286
3294
  const appName = await api.getGitHubAppName();
3287
- const installUrl = reason === "not_connected" ? `https://github.com/apps/${appName}/installations/new` : `https://github.com/settings/installations`;
3288
- console.log(
3289
- source_default.cyan(
3290
- `
3291
- Opening browser to ${reason === "not_connected" ? "install" : "configure"} GitHub App...`
3292
- )
3293
- );
3295
+ const installUrl = `https://github.com/apps/${appName}/installations/new`;
3296
+ console.log(source_default.cyan(`
3297
+ Opening browser...`));
3294
3298
  console.log(source_default.gray(`URL: ${installUrl}
3295
3299
  `));
3296
3300
  if (reason === "no_access") {
3297
- console.log(source_default.white("Please:"));
3298
3301
  console.log(
3299
- source_default.cyan(" 1. Find the 'mcp-use' (or similar) GitHub App")
3302
+ source_default.white("Please add ") + source_default.cyan.bold(repoName || "your repository") + source_default.white(" to the app's repository access, then return here.\n")
3300
3303
  );
3301
- console.log(source_default.cyan(" 2. Click 'Configure'"));
3304
+ } else {
3302
3305
  console.log(
3303
- source_default.cyan(
3304
- ` 3. Grant access to ${source_default.bold(repoName || "your repository")}`
3305
- )
3306
+ source_default.white("Complete the GitHub App installation, then return here.\n")
3306
3307
  );
3307
- console.log(source_default.cyan(" 4. Save your changes"));
3308
- console.log(source_default.cyan(" 5. Return here when done\n"));
3309
- } else {
3310
- console.log(source_default.white("Please:"));
3311
- console.log(source_default.cyan(" 1. Select the repositories to grant access"));
3312
- if (repoName) {
3313
- console.log(
3314
- source_default.cyan(` 2. Make sure to include ${source_default.bold(repoName)}`)
3315
- );
3316
- console.log(source_default.cyan(" 3. Complete the installation"));
3317
- } else {
3318
- console.log(source_default.cyan(" 2. Complete the installation"));
3319
- }
3320
- console.log();
3321
3308
  }
3322
3309
  await open_default(installUrl);
3323
- await waitForGitHubSetupAfterBrowser(api, repoName, yes);
3324
- console.log(source_default.gray("Verifying GitHub connection..."));
3325
- let verified = false;
3326
- try {
3327
- const status = await api.getGitHubConnectionStatus();
3328
- if (!status.is_connected) {
3329
- console.log(source_default.yellow("\u26A0\uFE0F GitHub connection not detected."));
3330
- } else if (repoName) {
3331
- const [owner, repo] = repoName.split("/");
3332
- console.log(source_default.gray(`Checking access to ${repoName}...`));
3333
- const hasAccess = await checkRepoAccess(api, owner, repo);
3334
- if (!hasAccess) {
3335
- console.log(
3336
- source_default.yellow(
3337
- `\u26A0\uFE0F The GitHub App may not have access to ${source_default.cyan(repoName)} yet`
3338
- )
3339
- );
3340
- } else {
3341
- console.log(source_default.green(`\u2713 Repository ${repoName} is accessible!
3342
- `));
3343
- verified = true;
3310
+ if (!yes) {
3311
+ await prompt(source_default.white("Press Enter when done..."), "y");
3312
+ } else {
3313
+ console.log(source_default.gray("Waiting for GitHub configuration (polling)..."));
3314
+ const deadline = Date.now() + 12e4;
3315
+ while (Date.now() < deadline) {
3316
+ await new Promise((r) => setTimeout(r, 2e3));
3317
+ try {
3318
+ const status = await api.getGitHubConnectionStatus();
3319
+ if (status.is_connected) {
3320
+ if (!repoName) return true;
3321
+ const [o, r] = repoName.split("/");
3322
+ if (o && r && await checkRepoAccess(api, o, r)) return true;
3323
+ }
3324
+ } catch {
3344
3325
  }
3345
- } else {
3346
- console.log(source_default.green("\u2713 GitHub connected successfully!\n"));
3347
- verified = true;
3348
3326
  }
3349
- } catch (error) {
3350
- console.log(
3351
- source_default.yellow("\u26A0\uFE0F Could not verify GitHub connection (API issue)")
3352
- );
3353
- }
3354
- if (!verified) {
3355
- console.log(
3356
- source_default.gray(
3357
- "\nNote: If you completed the GitHub setup, the deployment may work now.\n"
3358
- )
3359
- );
3360
3327
  }
3361
3328
  return true;
3362
- } catch (error) {
3363
- console.log(
3364
- source_default.yellow("\n\u26A0\uFE0F Unable to open GitHub installation automatically")
3365
- );
3329
+ } catch {
3330
+ console.log(source_default.yellow("\n\u26A0\uFE0F Unable to open browser automatically"));
3366
3331
  console.log(
3367
3332
  source_default.white("Please visit: ") + source_default.cyan("https://manufact.com/cloud/settings")
3368
3333
  );
3369
- console.log(
3370
- source_default.gray("Then connect your GitHub account and try again.\n")
3371
- );
3372
3334
  return false;
3373
3335
  }
3374
3336
  }
@@ -3376,47 +3338,139 @@ async function deployCommand(options) {
3376
3338
  try {
3377
3339
  const cwd = process.cwd();
3378
3340
  if (!await isLoggedIn()) {
3379
- console.log(source_default.red("\u2717 You are not logged in."));
3341
+ console.log(source_default.cyan.bold("Welcome to Manufact Cloud!\n"));
3380
3342
  if (options.yes) {
3381
3343
  console.log(
3382
- source_default.gray(
3383
- "Run " + source_default.white("npx mcp-use login") + " first. Non-interactive deploy requires an existing session."
3344
+ source_default.red(
3345
+ "\u2717 Not logged in. Run " + source_default.white("npx mcp-use login") + " first."
3384
3346
  )
3385
3347
  );
3386
3348
  process.exit(1);
3387
3349
  }
3388
3350
  const shouldLogin = await prompt(
3389
- source_default.white("Would you like to login now? (Y/n): "),
3351
+ source_default.white("You need to log in to deploy. Log in now? (Y/n): "),
3390
3352
  "y"
3391
3353
  );
3392
- if (shouldLogin) {
3393
- try {
3394
- await loginCommand({ silent: false });
3395
- if (!await isLoggedIn()) {
3396
- console.log(
3397
- source_default.red("\u2717 Login verification failed. Please try again.")
3398
- );
3399
- process.exit(1);
3400
- }
3401
- console.log(source_default.gray("\nContinuing with deployment...\n"));
3402
- } catch (error) {
3403
- console.error(
3404
- source_default.red.bold("\u2717 Login failed:"),
3405
- source_default.red(error instanceof Error ? error.message : "Unknown error")
3406
- );
3407
- process.exit(1);
3408
- }
3409
- } else {
3354
+ if (!shouldLogin) {
3410
3355
  console.log(
3411
3356
  source_default.gray(
3412
3357
  "Run " + source_default.white("npx mcp-use login") + " to get started."
3413
3358
  )
3414
3359
  );
3360
+ process.exit(0);
3361
+ }
3362
+ try {
3363
+ await loginCommand({ silent: false });
3364
+ if (!await isLoggedIn()) {
3365
+ console.log(source_default.red("\u2717 Login failed. Please try again."));
3366
+ process.exit(1);
3367
+ }
3368
+ console.log(source_default.gray("\nContinuing with deployment...\n"));
3369
+ } catch (error) {
3370
+ console.error(
3371
+ source_default.red.bold("\u2717 Login failed:"),
3372
+ source_default.red(error instanceof Error ? error.message : "Unknown error")
3373
+ );
3374
+ process.exit(1);
3375
+ }
3376
+ }
3377
+ const api = await McpUseAPI.create();
3378
+ if (options.org) {
3379
+ const authInfo = await api.testAuth();
3380
+ const match = (authInfo.orgs ?? []).find(
3381
+ (o) => o.slug === options.org || o.id === options.org || o.name.toLowerCase() === options.org.toLowerCase()
3382
+ );
3383
+ if (match) {
3384
+ api.setOrgId(match.id);
3385
+ const slug = match.slug ? source_default.gray(` (${match.slug})`) : "";
3386
+ console.log(
3387
+ source_default.gray("Organization: ") + source_default.cyan(match.name) + slug
3388
+ );
3389
+ } else {
3390
+ console.error(
3391
+ source_default.red(
3392
+ `\u2717 Organization "${options.org}" not found. Run ${source_default.white("npx mcp-use org list")} to see available organizations.`
3393
+ )
3394
+ );
3395
+ process.exit(1);
3396
+ }
3397
+ } else {
3398
+ const config = await readConfig();
3399
+ if (!config.orgId) {
3400
+ const authInfo = await api.testAuth();
3401
+ if (authInfo.orgs.length === 0) {
3402
+ console.log(
3403
+ source_default.red(
3404
+ "\u2717 No organizations found. Please create one at manufact.com/cloud."
3405
+ )
3406
+ );
3407
+ process.exit(1);
3408
+ }
3409
+ let selectedOrg;
3410
+ if (authInfo.orgs.length === 1) {
3411
+ selectedOrg = authInfo.orgs[0];
3412
+ } else {
3413
+ selectedOrg = await promptOrgSelection(
3414
+ authInfo.orgs,
3415
+ authInfo.default_org_id
3416
+ );
3417
+ }
3418
+ if (!selectedOrg) {
3419
+ console.log(source_default.red("\u2717 No organization selected."));
3420
+ process.exit(1);
3421
+ }
3422
+ api.setOrgId(selectedOrg.id);
3423
+ await writeConfig({
3424
+ ...config,
3425
+ orgId: selectedOrg.id,
3426
+ orgName: selectedOrg.name,
3427
+ orgSlug: selectedOrg.slug ?? void 0
3428
+ });
3429
+ console.log(
3430
+ source_default.gray("Organization: ") + source_default.cyan(selectedOrg.name)
3431
+ );
3432
+ } else {
3433
+ if (config.orgName) {
3434
+ const slug = config.orgSlug ? source_default.gray(` (${config.orgSlug})`) : "";
3435
+ console.log(
3436
+ source_default.gray("Organization: ") + source_default.cyan(config.orgName) + slug
3437
+ );
3438
+ }
3439
+ }
3440
+ }
3441
+ console.log(source_default.cyan.bold("\n\u{1F680} Deploying to Manufact cloud...\n"));
3442
+ let connectionStatus = await api.getGitHubConnectionStatus().catch(() => null);
3443
+ if (!connectionStatus?.is_connected) {
3444
+ const installed = await promptGitHubInstallation(
3445
+ api,
3446
+ "not_connected",
3447
+ void 0,
3448
+ { yes: options.yes }
3449
+ );
3450
+ if (!installed) {
3415
3451
  console.log(source_default.gray("Deployment cancelled."));
3416
3452
  process.exit(0);
3417
3453
  }
3454
+ connectionStatus = await api.getGitHubConnectionStatus().catch(() => null);
3455
+ if (!connectionStatus?.is_connected) {
3456
+ console.log(source_default.red("\n\u2717 GitHub connection could not be verified."));
3457
+ console.log(
3458
+ source_default.cyan(
3459
+ " Visit https://manufact.com/cloud/settings to connect GitHub.\n"
3460
+ )
3461
+ );
3462
+ process.exit(1);
3463
+ }
3464
+ }
3465
+ const installations = connectionStatus.installations ?? [];
3466
+ if (installations.length === 0) {
3467
+ console.log(source_default.red("\u2717 No GitHub installations found."));
3468
+ process.exit(1);
3418
3469
  }
3419
- console.log(source_default.cyan.bold("\u{1F680} Deploying to Manufact cloud...\n"));
3470
+ const defaultInstallation = installations.find((i) => i.account_type === "Organization") ?? installations[0];
3471
+ const installationDbId = defaultInstallation.id;
3472
+ const githubInstallationId = defaultInstallation.installation_id;
3473
+ console.log(source_default.green("\u2713 GitHub connected\n"));
3420
3474
  const projectDir = options.rootDir ? path5.resolve(cwd, options.rootDir) : cwd;
3421
3475
  if (options.rootDir) {
3422
3476
  try {
@@ -3427,292 +3481,274 @@ async function deployCommand(options) {
3427
3481
  );
3428
3482
  process.exit(1);
3429
3483
  }
3430
- console.log(source_default.gray(` Root dir: `) + source_default.cyan(options.rootDir));
3431
3484
  }
3432
3485
  const isMcp = await isMcpProject(projectDir);
3433
- if (!isMcp) {
3486
+ if (!isMcp && !options.yes) {
3434
3487
  console.log(
3435
- source_default.yellow(
3436
- "\u26A0\uFE0F This doesn't appear to be an MCP server project (no mcp-use or @modelcontextprotocol/sdk dependency found)."
3437
- )
3488
+ source_default.yellow("\u26A0\uFE0F This doesn't look like an MCP server project.")
3438
3489
  );
3439
- if (!options.yes) {
3440
- const shouldContinue = await prompt(
3441
- source_default.white("Continue anyway? (y/n): ")
3442
- );
3443
- if (!shouldContinue) {
3444
- console.log(source_default.gray("Deployment cancelled."));
3445
- process.exit(0);
3446
- }
3490
+ const shouldContinue = await prompt(
3491
+ source_default.white("Continue anyway? (y/n): ")
3492
+ );
3493
+ if (!shouldContinue) {
3494
+ process.exit(0);
3447
3495
  }
3448
3496
  console.log();
3449
3497
  }
3450
- const gitInfo = await getGitInfo(cwd);
3451
- if (!gitInfo.isGitRepo) {
3452
- console.log(source_default.red("\u2717 Not a git repository\n"));
3453
- console.log(source_default.white("To deploy, initialize git and push to GitHub:"));
3454
- console.log(source_default.gray(" 1. Initialize git:"));
3455
- console.log(source_default.cyan(" git init\n"));
3456
- console.log(source_default.gray(" 2. Create a GitHub repository at:"));
3457
- console.log(source_default.cyan(" https://github.com/new\n"));
3458
- console.log(source_default.gray(" 3. Add the remote and push:"));
3459
- console.log(source_default.cyan(" git remote add origin <your-github-url>"));
3460
- console.log(source_default.cyan(" git add ."));
3461
- console.log(source_default.cyan(" git commit -m 'Initial commit'"));
3462
- console.log(source_default.cyan(" git push -u origin main\n"));
3463
- process.exit(1);
3464
- }
3465
- if (!gitInfo.remoteUrl) {
3466
- console.log(source_default.red("\u2717 No git remote configured\n"));
3467
- console.log(source_default.white("Add a GitHub remote:"));
3468
- console.log(source_default.cyan(" git remote add origin <your-github-url>\n"));
3469
- process.exit(1);
3470
- }
3471
- if (!isGitHubUrl(gitInfo.remoteUrl)) {
3472
- console.log(source_default.red("\u2717 Remote is not a GitHub repository"));
3473
- console.log(source_default.yellow(` Current remote: ${gitInfo.remoteUrl}
3474
- `));
3475
- console.log(source_default.white("Please add a GitHub remote to deploy."));
3476
- process.exit(1);
3477
- }
3478
- if (!gitInfo.owner || !gitInfo.repo) {
3479
- console.log(source_default.red("\u2717 Could not parse GitHub repository information"));
3480
- process.exit(1);
3481
- }
3482
- if (gitInfo.hasUncommittedChanges) {
3483
- console.log(source_default.yellow("\u26A0\uFE0F You have uncommitted changes\n"));
3484
- console.log(source_default.white("Deployments use the code pushed to GitHub."));
3485
- console.log(
3486
- source_default.white(
3487
- "Local changes will not be included until you commit and push.\n"
3488
- )
3489
- );
3490
- if (!options.yes) {
3491
- const shouldContinue = await prompt(
3492
- source_default.white("Continue with deployment from GitHub? (y/n): ")
3498
+ let gitInfo = await getGitInfo(cwd);
3499
+ let repoFullName;
3500
+ let branch = "main";
3501
+ if (!gitInfo.isGitRepo || !gitInfo.remoteUrl) {
3502
+ const projectName2 = options.name || await getProjectName(projectDir);
3503
+ console.log(source_default.yellow("\u26A0\uFE0F No GitHub remote found.\n"));
3504
+ if (options.yes) {
3505
+ console.log(source_default.gray("Creating GitHub repository automatically..."));
3506
+ } else {
3507
+ const shouldCreate = await prompt(
3508
+ source_default.white("Create a GitHub repository and push your code? (Y/n): "),
3509
+ "y"
3493
3510
  );
3494
- if (!shouldContinue) {
3495
- console.log(source_default.gray("Deployment cancelled."));
3511
+ if (!shouldCreate) {
3512
+ console.log(
3513
+ source_default.gray(
3514
+ "Deployment cancelled. Set up a GitHub remote and try again."
3515
+ )
3516
+ );
3496
3517
  process.exit(0);
3497
3518
  }
3498
3519
  }
3499
- console.log();
3500
- }
3501
- console.log(source_default.white("GitHub repository detected:"));
3502
- console.log(
3503
- source_default.gray(` Repository: `) + source_default.cyan(`${gitInfo.owner}/${gitInfo.repo}`)
3504
- );
3505
- console.log(
3506
- source_default.gray(` Branch: `) + source_default.cyan(gitInfo.branch || "main")
3507
- );
3508
- if (gitInfo.commitSha) {
3509
- console.log(
3510
- source_default.gray(` Commit: `) + source_default.gray(gitInfo.commitSha.substring(0, 7))
3511
- );
3512
- }
3513
- if (gitInfo.commitMessage) {
3514
- console.log(
3515
- source_default.gray(` Message: `) + source_default.gray(gitInfo.commitMessage.split("\n")[0])
3520
+ const defaultIdx = installations.findIndex(
3521
+ (i) => i.account_type === "Organization"
3516
3522
  );
3517
- }
3518
- console.log();
3519
- if (!options.yes) {
3520
- const shouldDeploy = await prompt(
3521
- source_default.white(
3522
- `Deploy from GitHub repository ${gitInfo.owner}/${gitInfo.repo}? (Y/n): `
3523
- ),
3524
- "y"
3525
- );
3526
- if (!shouldDeploy) {
3527
- console.log(source_default.gray("Deployment cancelled."));
3523
+ let selectedIdx = defaultIdx >= 0 ? defaultIdx : 0;
3524
+ if (installations.length > 1 && !options.yes) {
3525
+ console.log(
3526
+ source_default.cyan.bold("\u{1F419} Select a GitHub account for the repository:\n")
3527
+ );
3528
+ for (let i = 0; i < installations.length; i++) {
3529
+ const inst = installations[i];
3530
+ const typeLabel = inst.account_type === "Organization" ? source_default.gray(" (org)") : source_default.gray(" (personal)");
3531
+ const marker = i === selectedIdx ? source_default.green(" \u2190 default") : "";
3532
+ console.log(
3533
+ ` ${source_default.white(`${i + 1}.`)} ${inst.account_login}${typeLabel}${marker}`
3534
+ );
3535
+ }
3536
+ console.log();
3537
+ const readline = await import("readline");
3538
+ const rl = readline.createInterface({
3539
+ input: process.stdin,
3540
+ output: process.stdout
3541
+ });
3542
+ const answer = await new Promise((resolve2) => {
3543
+ rl.question(
3544
+ source_default.gray(`Enter number [${selectedIdx + 1}]: `),
3545
+ (a) => {
3546
+ rl.close();
3547
+ resolve2(a.trim());
3548
+ }
3549
+ );
3550
+ });
3551
+ const parsed = answer === "" ? selectedIdx : parseInt(answer, 10) - 1;
3552
+ if (parsed >= 0 && parsed < installations.length) {
3553
+ selectedIdx = parsed;
3554
+ }
3555
+ }
3556
+ const repoInstallation = installations[selectedIdx];
3557
+ if (repoInstallation.account_type !== "Organization") {
3558
+ console.log(
3559
+ source_default.yellow(
3560
+ "\n\u26A0\uFE0F GitHub Apps cannot create repos on personal accounts.\n"
3561
+ )
3562
+ );
3563
+ console.log(
3564
+ source_default.white("To deploy from ") + source_default.cyan(repoInstallation.account_login) + source_default.white(", create a repository manually:\n")
3565
+ );
3566
+ console.log(
3567
+ source_default.cyan(" 1. ") + source_default.white("Go to ") + source_default.cyan("https://github.com/new")
3568
+ );
3569
+ console.log(
3570
+ source_default.cyan(" 2. ") + source_default.white("Create a repository (any name, can be private)")
3571
+ );
3572
+ console.log(source_default.cyan(" 3. ") + source_default.white("Add it as a remote:"));
3573
+ console.log(source_default.gray(" git init && git remote add origin <url>"));
3574
+ console.log(source_default.cyan(" 4. ") + source_default.white("Push your code:"));
3575
+ console.log(
3576
+ source_default.gray(
3577
+ " git add . && git commit -m 'Initial commit' && git push -u origin main"
3578
+ )
3579
+ );
3580
+ console.log(
3581
+ source_default.cyan(" 5. ") + source_default.white("Grant the GitHub App access to the repo:")
3582
+ );
3583
+ const appName = await api.getGitHubAppName();
3584
+ console.log(
3585
+ source_default.gray(
3586
+ ` https://github.com/apps/${appName}/installations/new`
3587
+ )
3588
+ );
3589
+ console.log(
3590
+ source_default.cyan(" 6. ") + source_default.white("Run ") + source_default.cyan("mcp-use deploy") + source_default.white(" again\n")
3591
+ );
3528
3592
  process.exit(0);
3529
3593
  }
3530
- }
3531
- const projectName = options.name || await getProjectName(projectDir);
3532
- const runtime = options.runtime || await detectRuntime(projectDir);
3533
- const port = options.port || 3e3;
3534
- const buildCommand = await detectBuildCommand(projectDir);
3535
- const startCommand = await detectStartCommand(projectDir);
3536
- const envVars = await buildEnvVars(options);
3537
- console.log();
3538
- console.log(source_default.white("Deployment configuration:"));
3539
- console.log(source_default.gray(` Name: `) + source_default.cyan(projectName));
3540
- console.log(source_default.gray(` Runtime: `) + source_default.cyan(runtime));
3541
- console.log(source_default.gray(` Port: `) + source_default.cyan(port));
3542
- if (options.rootDir) {
3594
+ const repoName = options.yes ? projectName2 : await promptText(source_default.gray("Repository name:"), projectName2);
3595
+ await ensureGitignore(cwd);
3543
3596
  console.log(
3544
- source_default.gray(` Root dir: `) + source_default.cyan(options.rootDir)
3545
- );
3546
- }
3547
- if (buildCommand) {
3548
- console.log(source_default.gray(` Build command: `) + source_default.cyan(buildCommand));
3549
- }
3550
- if (startCommand) {
3551
- console.log(source_default.gray(` Start command: `) + source_default.cyan(startCommand));
3552
- }
3553
- if (envVars && Object.keys(envVars).length > 0) {
3554
- console.log(
3555
- source_default.gray(` Environment: `) + source_default.cyan(`${Object.keys(envVars).length} variable(s)`)
3556
- );
3557
- console.log(
3558
- source_default.gray(` `) + source_default.gray(Object.keys(envVars).join(", "))
3597
+ source_default.gray(
3598
+ `Creating repository on ${repoInstallation.account_login}...`
3599
+ )
3559
3600
  );
3560
- }
3561
- console.log();
3562
- const api = await McpUseAPI.create();
3563
- if (options.org) {
3564
- try {
3565
- const authInfo = await api.testAuth();
3566
- const match = (authInfo.orgs ?? []).find(
3567
- (o) => o.slug === options.org || o.id === options.org || o.name.toLowerCase() === options.org.toLowerCase()
3601
+ const repoResult = await api.createGitHubRepo({
3602
+ installationId: repoInstallation.installation_id,
3603
+ name: repoName,
3604
+ private: true,
3605
+ org: repoInstallation.account_login
3606
+ });
3607
+ console.log(source_default.green(`\u2713 Created ${source_default.cyan(repoResult.fullName)}`));
3608
+ if (!gitInfo.isGitRepo) {
3609
+ console.log(source_default.gray("Initializing git..."));
3610
+ await gitInit(cwd, "Initial commit");
3611
+ console.log(source_default.gray("Pushing to GitHub..."));
3612
+ await gitAddRemoteAndPush(cwd, repoResult.cloneUrl, "main");
3613
+ } else {
3614
+ console.log(source_default.gray("Adding remote and pushing..."));
3615
+ await gitAddRemoteAndPush(
3616
+ cwd,
3617
+ repoResult.cloneUrl,
3618
+ gitInfo.branch || "main"
3568
3619
  );
3569
- if (match) {
3570
- api.setOrgId(match.id);
3571
- const slug = match.slug ? source_default.gray(` (${match.slug})`) : "";
3572
- console.log(
3573
- source_default.gray("Organization: ") + source_default.cyan(match.name) + slug
3574
- );
3575
- } else {
3576
- console.error(
3577
- source_default.red(
3578
- `\u2717 Organization "${options.org}" not found. Run ${source_default.white("npx mcp-use org list")} to see available organizations.`
3579
- )
3620
+ }
3621
+ console.log(source_default.green("\u2713 Code pushed to GitHub\n"));
3622
+ gitInfo = await getGitInfo(cwd);
3623
+ repoFullName = repoResult.fullName;
3624
+ branch = gitInfo.branch || "main";
3625
+ } else if (!isGitHubUrl(gitInfo.remoteUrl)) {
3626
+ console.log(source_default.red("\u2717 Remote is not a GitHub repository"));
3627
+ console.log(source_default.yellow(` Current remote: ${gitInfo.remoteUrl}
3628
+ `));
3629
+ process.exit(1);
3630
+ } else if (!gitInfo.owner || !gitInfo.repo) {
3631
+ console.log(source_default.red("\u2717 Could not parse GitHub repository information"));
3632
+ process.exit(1);
3633
+ } else {
3634
+ repoFullName = `${gitInfo.owner}/${gitInfo.repo}`;
3635
+ branch = gitInfo.branch || "main";
3636
+ if (gitInfo.hasUncommittedChanges) {
3637
+ console.log(source_default.yellow("\u26A0\uFE0F You have uncommitted changes.\n"));
3638
+ if (!options.yes) {
3639
+ const shouldCommit = await prompt(
3640
+ source_default.white("Commit and push changes before deploying? (Y/n): "),
3641
+ "y"
3580
3642
  );
3581
- process.exit(1);
3643
+ if (shouldCommit) {
3644
+ await ensureGitignore(cwd);
3645
+ console.log(source_default.gray("Committing and pushing..."));
3646
+ await gitCommitAndPush(cwd, "Deploy changes", branch);
3647
+ gitInfo = await getGitInfo(cwd);
3648
+ console.log(source_default.green("\u2713 Changes pushed\n"));
3649
+ } else {
3650
+ console.log(source_default.gray("Deploying from last pushed commit.\n"));
3651
+ }
3582
3652
  }
3583
- } catch (error) {
3584
- console.error(
3585
- source_default.red("\u2717 Failed to resolve organization:"),
3586
- source_default.red(error instanceof Error ? error.message : "Unknown error")
3587
- );
3588
- process.exit(1);
3589
3653
  }
3590
- }
3591
- let githubVerified = false;
3592
- let installationDbId;
3593
- try {
3594
- console.log(source_default.gray(`[DEBUG] API URL: ${api.baseUrl}`));
3595
- const connectionStatus = await api.getGitHubConnectionStatus();
3596
- if (!connectionStatus.is_connected) {
3597
- const repoFullName = `${gitInfo.owner}/${gitInfo.repo}`;
3598
- const installed = await promptGitHubInstallation(
3654
+ console.log(source_default.gray("Checking repository access..."));
3655
+ const hasAccess = await checkRepoAccess(
3656
+ api,
3657
+ gitInfo.owner,
3658
+ gitInfo.repo
3659
+ );
3660
+ if (!hasAccess) {
3661
+ console.log(
3662
+ source_default.yellow(
3663
+ `\u26A0\uFE0F GitHub App doesn't have access to ${source_default.cyan(repoFullName)}`
3664
+ )
3665
+ );
3666
+ const configured = await promptGitHubInstallation(
3599
3667
  api,
3600
- "not_connected",
3668
+ "no_access",
3601
3669
  repoFullName,
3602
- { yes: options.yes }
3670
+ { yes: options.yes, installationId: githubInstallationId }
3603
3671
  );
3604
- if (!installed) {
3605
- console.log(source_default.gray("Deployment cancelled."));
3672
+ if (!configured) {
3606
3673
  process.exit(0);
3607
3674
  }
3608
- const retryStatus = await api.getGitHubConnectionStatus();
3609
- if (!retryStatus.is_connected) {
3610
- console.log(
3611
- source_default.red("\n\u2717 GitHub connection could not be verified.")
3612
- );
3675
+ const retry = await checkRepoAccess(api, gitInfo.owner, gitInfo.repo);
3676
+ if (!retry) {
3677
+ const appName = await api.getGitHubAppName();
3613
3678
  console.log(
3614
- source_default.gray("Please try connecting GitHub from the web UI:")
3615
- );
3616
- console.log(source_default.cyan(" https://manufact.com/cloud/settings\n"));
3617
- process.exit(1);
3618
- }
3619
- installationDbId = retryStatus.installations?.[0]?.id;
3620
- githubVerified = true;
3621
- } else if (gitInfo.owner && gitInfo.repo) {
3622
- installationDbId = connectionStatus.installations?.[0]?.id;
3623
- console.log(source_default.gray("Checking repository access..."));
3624
- const hasAccess = await checkRepoAccess(
3625
- api,
3626
- gitInfo.owner,
3627
- gitInfo.repo
3628
- );
3629
- if (!hasAccess) {
3630
- const repoFullName = `${gitInfo.owner}/${gitInfo.repo}`;
3631
- console.log(
3632
- source_default.yellow(
3633
- `\u26A0\uFE0F GitHub App doesn't have access to ${source_default.cyan(repoFullName)}`
3679
+ source_default.red(
3680
+ `
3681
+ \u2717 Repository ${source_default.cyan(repoFullName)} is still not accessible.`
3634
3682
  )
3635
3683
  );
3636
- const configured = await promptGitHubInstallation(
3637
- api,
3638
- "no_access",
3639
- repoFullName,
3640
- { yes: options.yes }
3641
- );
3642
- if (!configured) {
3643
- console.log(source_default.gray("Deployment cancelled."));
3644
- process.exit(0);
3645
- }
3646
- const hasAccessRetry = await checkRepoAccess(
3647
- api,
3648
- gitInfo.owner,
3649
- gitInfo.repo
3650
- );
3651
- if (!hasAccessRetry) {
3652
- console.log(
3653
- source_default.red(
3654
- `
3655
- \u2717 Repository ${source_default.cyan(repoFullName)} is still not accessible.`
3656
- )
3657
- );
3658
- console.log(
3659
- source_default.gray(
3660
- "Please make sure the GitHub App has access to this repository."
3661
- )
3662
- );
3663
- console.log(
3664
- source_default.cyan(" https://github.com/settings/installations\n")
3665
- );
3666
- process.exit(1);
3667
- }
3668
- githubVerified = true;
3669
- } else {
3670
- console.log(source_default.green("\u2713 Repository access confirmed"));
3671
- githubVerified = true;
3684
+ console.log(
3685
+ source_default.cyan(
3686
+ ` https://github.com/apps/${appName}/installations/new
3687
+ `
3688
+ )
3689
+ );
3690
+ process.exit(1);
3672
3691
  }
3673
3692
  }
3674
- } catch (error) {
3675
- console.log(source_default.red("\u2717 Could not verify GitHub connection"));
3693
+ console.log(source_default.green("\u2713 Repository access confirmed"));
3694
+ }
3695
+ const projectName = options.name || await getProjectName(projectDir);
3696
+ const port = options.port || 3e3;
3697
+ const buildCommand = await detectBuildCommand(projectDir);
3698
+ const startCommand = await detectStartCommand(projectDir);
3699
+ const runtime = options.runtime || await detectRuntime(projectDir);
3700
+ const envVars = await buildEnvVars(options);
3701
+ console.log();
3702
+ console.log(source_default.white("Deployment configuration:"));
3703
+ console.log(source_default.gray(` Repository: `) + source_default.cyan(repoFullName));
3704
+ console.log(source_default.gray(` Branch: `) + source_default.cyan(branch));
3705
+ console.log(source_default.gray(` Name: `) + source_default.cyan(projectName));
3706
+ console.log(source_default.gray(` Runtime: `) + source_default.cyan(runtime));
3707
+ console.log(source_default.gray(` Port: `) + source_default.cyan(port));
3708
+ if (options.region)
3709
+ console.log(source_default.gray(` Region: `) + source_default.cyan(options.region));
3710
+ if (options.buildCommand)
3676
3711
  console.log(
3677
- source_default.gray(
3678
- "Error: " + (error instanceof Error ? error.message : "Unknown error")
3679
- )
3712
+ source_default.gray(` Build command: `) + source_default.cyan(options.buildCommand)
3680
3713
  );
3681
- console.log(source_default.gray("\nPlease ensure:"));
3714
+ else if (buildCommand)
3682
3715
  console.log(
3683
- source_default.cyan(
3684
- " 1. You have connected GitHub at https://manufact.com/cloud/settings"
3685
- )
3716
+ source_default.gray(` Build command: `) + source_default.gray(buildCommand + " (auto-detected)")
3686
3717
  );
3718
+ if (options.startCommand)
3687
3719
  console.log(
3688
- source_default.cyan(" 2. The GitHub App has access to your repository")
3720
+ source_default.gray(` Start command: `) + source_default.cyan(options.startCommand)
3689
3721
  );
3690
- console.log(source_default.cyan(" 3. Your internet connection is stable\n"));
3691
- process.exit(1);
3692
- }
3693
- if (!githubVerified) {
3722
+ else if (startCommand)
3694
3723
  console.log(
3695
- source_default.red("\n\u2717 GitHub verification required for this deployment")
3724
+ source_default.gray(` Start command: `) + source_default.gray(startCommand + " (auto-detected)")
3696
3725
  );
3697
- process.exit(1);
3726
+ if (Object.keys(envVars).length > 0) {
3727
+ console.log(
3728
+ source_default.gray(` Environment: `) + source_default.cyan(`${Object.keys(envVars).length} variable(s)`)
3729
+ );
3730
+ }
3731
+ console.log();
3732
+ if (!options.yes) {
3733
+ const shouldDeploy = await prompt(source_default.white(`Deploy? (Y/n): `), "y");
3734
+ if (!shouldDeploy) {
3735
+ console.log(source_default.gray("Deployment cancelled."));
3736
+ process.exit(0);
3737
+ }
3698
3738
  }
3699
3739
  const existingLink = !options.new ? await getProjectLink(cwd) : null;
3700
- const serverId = existingLink?.serverId;
3740
+ let serverId = existingLink?.serverId;
3701
3741
  if (existingLink && serverId) {
3702
3742
  try {
3703
- const existingDeployment = await api.getDeployment(
3704
- existingLink.deploymentId
3705
- );
3706
- if (existingDeployment && existingDeployment.status !== "failed") {
3707
- console.log(source_default.green(`\u2713 Found linked deployment`));
3743
+ const existingDep = await api.getDeployment(existingLink.deploymentId);
3744
+ if (existingDep && existingDep.status !== "failed") {
3745
+ console.log(source_default.green(`\u2713 Found linked server`));
3708
3746
  console.log(source_default.gray(` Redeploying to maintain the same URL...`));
3709
- console.log(
3710
- source_default.cyan(` URL: ${getMcpServerUrl(existingDeployment)}
3711
- `)
3712
- );
3747
+ console.log(source_default.cyan(` URL: ${getMcpServerUrl(existingDep)}
3748
+ `));
3713
3749
  const newDep = await api.createDeployment({
3714
3750
  serverId,
3715
- branch: gitInfo.branch || "main",
3751
+ branch,
3716
3752
  trigger: "redeploy"
3717
3753
  });
3718
3754
  await saveProjectLink(cwd, {
@@ -3720,89 +3756,79 @@ async function deployCommand(options) {
3720
3756
  linkedAt: (/* @__PURE__ */ new Date()).toISOString(),
3721
3757
  deploymentId: newDep.id
3722
3758
  });
3723
- await displayDeploymentProgress(api, newDep.id, {
3724
- yes: options.yes
3725
- });
3726
- return;
3727
- } else {
3728
3759
  console.log(
3729
- source_default.yellow(
3730
- `\u26A0\uFE0F Linked deployment not found or failed, creating new one...`
3731
- )
3760
+ source_default.green("\u2713 Deployment created: ") + source_default.gray(newDep.id)
3732
3761
  );
3733
- console.log(source_default.gray(` Will reuse existing server: ${serverId}`));
3762
+ await displayDeploymentProgress(api, newDep.id, { yes: options.yes });
3763
+ return;
3734
3764
  }
3735
- } catch (error) {
3736
- console.log(
3737
- source_default.yellow(`\u26A0\uFE0F Linked deployment not found, creating new one...`)
3738
- );
3739
- console.log(source_default.gray(` Will reuse existing server: ${serverId}`));
3740
- }
3741
- }
3742
- if (!options.org) {
3743
- try {
3744
- const config = await readConfig();
3745
- if (config.orgName) {
3746
- const slug = config.orgSlug ? source_default.gray(` (${config.orgSlug})`) : "";
3765
+ } catch (err) {
3766
+ const is404 = err?.status === 404 || (err?.message ?? "").includes("404");
3767
+ if (is404) {
3747
3768
  console.log(
3748
- source_default.gray("Organization: ") + source_default.cyan(config.orgName) + slug
3769
+ source_default.yellow("\u26A0\uFE0F Previously linked server no longer exists.\n")
3749
3770
  );
3771
+ if (!options.yes) {
3772
+ const shouldRecreate = await prompt(
3773
+ source_default.white("Create a new server and deploy? (Y/n): "),
3774
+ "y"
3775
+ );
3776
+ if (!shouldRecreate) {
3777
+ console.log(source_default.gray("Deployment cancelled."));
3778
+ process.exit(0);
3779
+ }
3780
+ }
3781
+ serverId = void 0;
3750
3782
  }
3751
- } catch {
3752
3783
  }
3753
3784
  }
3754
3785
  let deploymentId;
3755
3786
  if (serverId) {
3756
3787
  console.log(source_default.gray("Creating deployment..."));
3757
- const result = await api.createDeployment({
3758
- serverId,
3759
- branch: gitInfo.branch || "main",
3760
- trigger: "manual"
3761
- });
3762
- deploymentId = result.id;
3763
- } else {
3764
- if (!installationDbId) {
3765
- console.log(source_default.red("\u2717 Could not determine GitHub installation ID."));
3766
- console.log(
3767
- source_default.gray(
3768
- "Please ensure your GitHub App is installed and try again."
3769
- )
3770
- );
3771
- process.exit(1);
3772
- }
3773
- const config = await readConfig();
3774
- const authInfo = await api.testAuth();
3775
- const orgId = config.orgId || authInfo.default_org_id;
3776
- if (!orgId) {
3777
- console.log(
3778
- source_default.red("\u2717 No organization set. Run `mcp-use org switch` first.")
3779
- );
3780
- process.exit(1);
3788
+ try {
3789
+ const result = await api.createDeployment({
3790
+ serverId,
3791
+ branch,
3792
+ trigger: "manual"
3793
+ });
3794
+ deploymentId = result.id;
3795
+ } catch (err) {
3796
+ const is404 = err?.status === 404 || (err?.message ?? "").includes("404");
3797
+ if (is404) {
3798
+ console.log(
3799
+ source_default.yellow(
3800
+ "\u26A0\uFE0F Linked server no longer exists. Creating a new one...\n"
3801
+ )
3802
+ );
3803
+ serverId = void 0;
3804
+ } else {
3805
+ throw err;
3806
+ }
3781
3807
  }
3808
+ }
3809
+ if (!serverId) {
3810
+ const orgId = await api.resolveOrganizationId();
3782
3811
  console.log(source_default.gray("Creating server and deployment..."));
3783
3812
  const serverResult = await api.createServer({
3784
3813
  type: "github",
3785
3814
  organizationId: orgId,
3786
3815
  installationId: installationDbId,
3787
3816
  name: projectName,
3788
- repoFullName: `${gitInfo.owner}/${gitInfo.repo}`,
3789
- branch: gitInfo.branch || "main",
3817
+ repoFullName,
3818
+ branch,
3790
3819
  rootDir: options.rootDir,
3791
3820
  port,
3792
- buildCommand,
3793
- startCommand,
3794
- env: Object.keys(envVars).length > 0 ? envVars : void 0
3821
+ env: Object.keys(envVars).length > 0 ? envVars : void 0,
3822
+ region: options.region,
3823
+ buildCommand: options.buildCommand,
3824
+ startCommand: options.startCommand
3795
3825
  });
3796
3826
  deploymentId = serverResult.deploymentId ?? "";
3797
3827
  if (!deploymentId) {
3798
3828
  console.log(
3799
3829
  source_default.green("\u2713 Server created: ") + source_default.gray(serverResult.server.id)
3800
3830
  );
3801
- console.log(
3802
- source_default.yellow(
3803
- "\u26A0\uFE0F No deployment was triggered. You may need to trigger one manually."
3804
- )
3805
- );
3831
+ console.log(source_default.yellow("\u26A0\uFE0F No deployment was triggered."));
3806
3832
  return;
3807
3833
  }
3808
3834
  await saveProjectLink(cwd, {
@@ -3817,10 +3843,22 @@ async function deployCommand(options) {
3817
3843
  console.log(source_default.gray(` Future deploys will reuse the same URL
3818
3844
  `));
3819
3845
  }
3846
+ if (!deploymentId) {
3847
+ console.log(source_default.red("\u2717 No deployment was created."));
3848
+ process.exit(1);
3849
+ }
3820
3850
  console.log(
3821
3851
  source_default.green("\u2713 Deployment created: ") + source_default.gray(deploymentId)
3822
3852
  );
3823
3853
  await displayDeploymentProgress(api, deploymentId, { yes: options.yes });
3854
+ if (options.open) {
3855
+ const dep = await api.getDeployment(deploymentId);
3856
+ const url = getMcpServerUrl(dep);
3857
+ if (url) {
3858
+ console.log(source_default.gray("\nOpening in browser..."));
3859
+ await open_default(url);
3860
+ }
3861
+ }
3824
3862
  } catch (error) {
3825
3863
  console.error(
3826
3864
  source_default.red.bold("\n\u2717 Deployment failed:"),
@@ -3939,11 +3977,15 @@ async function getDeploymentCommand(deploymentId) {
3939
3977
  console.log(
3940
3978
  source_default.white("Status: ") + statusColor(deployment.status)
3941
3979
  );
3942
- if (deployment.mcpUrl) {
3980
+ if (deployment.serverId) {
3943
3981
  console.log(
3944
- source_default.white("MCP URL: ") + source_default.cyan(deployment.mcpUrl)
3982
+ source_default.white("Server ID: ") + source_default.gray(deployment.serverId)
3945
3983
  );
3946
3984
  }
3985
+ const mcpUrl = getMcpServerUrl(deployment);
3986
+ if (mcpUrl) {
3987
+ console.log(source_default.white("MCP URL: ") + source_default.cyan(mcpUrl));
3988
+ }
3947
3989
  if (deployment.gitBranch) {
3948
3990
  console.log(
3949
3991
  source_default.white("Branch: ") + source_default.gray(deployment.gitBranch)
@@ -4260,6 +4302,295 @@ function createDeploymentsCommand() {
4260
4302
  return deploymentsCommand;
4261
4303
  }
4262
4304
 
4305
+ // src/commands/servers.ts
4306
+ import { Command as Command3 } from "commander";
4307
+ async function prompt3(question) {
4308
+ const readline = await import("readline");
4309
+ const rl = readline.createInterface({
4310
+ input: process.stdin,
4311
+ output: process.stdout
4312
+ });
4313
+ return new Promise((resolve2) => {
4314
+ rl.question(question, (answer) => {
4315
+ rl.close();
4316
+ const trimmedAnswer = answer.trim().toLowerCase();
4317
+ resolve2(trimmedAnswer === "y" || trimmedAnswer === "yes");
4318
+ });
4319
+ });
4320
+ }
4321
+ function isRecord(v) {
4322
+ return typeof v === "object" && v !== null;
4323
+ }
4324
+ function pickStr(obj, key) {
4325
+ if (!isRecord(obj)) return "-";
4326
+ const v = obj[key];
4327
+ if (typeof v === "string") return v;
4328
+ if (v != null && typeof v !== "object") return String(v);
4329
+ return "-";
4330
+ }
4331
+ async function applyOrgOption(api, org) {
4332
+ if (!org) return;
4333
+ const authInfo = await api.testAuth();
4334
+ const match = (authInfo.orgs ?? []).find(
4335
+ (o) => o.slug === org || o.id === org || o.name.toLowerCase() === org.toLowerCase()
4336
+ );
4337
+ if (!match) {
4338
+ console.error(
4339
+ source_default.red(
4340
+ `\u2717 Organization "${org}" not found. Run ${source_default.white("npx mcp-use org list")} to see available organizations.`
4341
+ )
4342
+ );
4343
+ process.exit(1);
4344
+ }
4345
+ api.setOrgId(match.id);
4346
+ const slug = match.slug ? source_default.gray(` (${match.slug})`) : "";
4347
+ console.log(source_default.gray("Organization: ") + source_default.cyan(match.name) + slug);
4348
+ }
4349
+ function getStatusColor2(status) {
4350
+ const s = status.toLowerCase();
4351
+ if (s.includes("run") || s === "active") return source_default.green;
4352
+ if (s.includes("fail") || s.includes("error")) return source_default.red;
4353
+ if (s.includes("build") || s.includes("pend")) return source_default.yellow;
4354
+ return source_default.gray;
4355
+ }
4356
+ async function listServersCommand(options) {
4357
+ try {
4358
+ if (!await isLoggedIn()) {
4359
+ console.log(source_default.red("\u2717 You are not logged in."));
4360
+ console.log(
4361
+ source_default.gray(
4362
+ "Run " + source_default.white("npx mcp-use login") + " to get started."
4363
+ )
4364
+ );
4365
+ process.exit(1);
4366
+ }
4367
+ const api = await McpUseAPI.create();
4368
+ await applyOrgOption(api, options.org);
4369
+ if (options.org) console.log();
4370
+ const limit = options.limit ? parseInt(options.limit, 10) : void 0;
4371
+ const skip = options.skip ? parseInt(options.skip, 10) : void 0;
4372
+ if (limit !== void 0 && (Number.isNaN(limit) || limit < 1)) {
4373
+ console.log(source_default.red("\u2717 Invalid --limit"));
4374
+ process.exit(1);
4375
+ }
4376
+ if (skip !== void 0 && (Number.isNaN(skip) || skip < 0)) {
4377
+ console.log(source_default.red("\u2717 Invalid --skip"));
4378
+ process.exit(1);
4379
+ }
4380
+ const servers = await api.listServers({
4381
+ limit,
4382
+ skip,
4383
+ sort: options.sort
4384
+ });
4385
+ if (servers.length === 0) {
4386
+ console.log(source_default.yellow("No servers found."));
4387
+ console.log(
4388
+ source_default.gray(
4389
+ "\nCreate one by deploying with " + source_default.white("mcp-use deploy")
4390
+ )
4391
+ );
4392
+ return;
4393
+ }
4394
+ console.log(source_default.cyan.bold(`
4395
+ \u{1F5A5} Servers (${servers.length})
4396
+ `));
4397
+ console.log(
4398
+ source_default.white.bold(
4399
+ `${"ID".padEnd(38)} ${"NAME".padEnd(22)} ${"STATUS".padEnd(14)} ${"REPO".padEnd(32)} ${"MCP URL".padEnd(52)}`
4400
+ )
4401
+ );
4402
+ console.log(source_default.gray("\u2500".repeat(165)));
4403
+ for (const s of servers) {
4404
+ const id = s.id.substring(0, 37).padEnd(38);
4405
+ const name = (s.name || s.slug || "-").substring(0, 21).padEnd(22);
4406
+ const statusColor = getStatusColor2(s.status);
4407
+ const status = statusColor(s.status.substring(0, 13).padEnd(14));
4408
+ const repo = (s.connectedRepository?.repoFullName ?? "-").substring(0, 31).padEnd(32);
4409
+ const mcp = getMcpServerUrlForCloudServer(s).substring(0, 51).padEnd(52);
4410
+ console.log(
4411
+ `${source_default.gray(id)} ${name} ${status} ${source_default.gray(repo)} ${source_default.cyan(mcp)}`
4412
+ );
4413
+ }
4414
+ console.log();
4415
+ } catch (error) {
4416
+ console.error(
4417
+ source_default.red.bold("\n\u2717 Failed to list servers:"),
4418
+ source_default.red(error instanceof Error ? error.message : "Unknown error")
4419
+ );
4420
+ process.exit(1);
4421
+ }
4422
+ }
4423
+ async function getServerCommand(idOrSlug, options) {
4424
+ try {
4425
+ if (!await isLoggedIn()) {
4426
+ console.log(source_default.red("\u2717 You are not logged in."));
4427
+ console.log(
4428
+ source_default.gray(
4429
+ "Run " + source_default.white("npx mcp-use login") + " to get started."
4430
+ )
4431
+ );
4432
+ process.exit(1);
4433
+ }
4434
+ const api = await McpUseAPI.create();
4435
+ await applyOrgOption(api, options.org);
4436
+ if (options.org) console.log();
4437
+ const server = await api.getServer(idOrSlug);
4438
+ console.log(source_default.cyan.bold("\n\u{1F5A5} Server Details\n"));
4439
+ console.log(source_default.white("ID: ") + source_default.gray(server.id));
4440
+ if (server.slug) {
4441
+ console.log(source_default.white("Slug: ") + source_default.cyan(server.slug));
4442
+ }
4443
+ console.log(
4444
+ source_default.white("Name: ") + source_default.cyan(server.name ?? "-")
4445
+ );
4446
+ const statusColor = getStatusColor2(server.status);
4447
+ console.log(source_default.white("Status: ") + statusColor(server.status));
4448
+ if (server.latestDeploymentStatus) {
4449
+ console.log(
4450
+ source_default.white("Last deploy: ") + source_default.gray(server.latestDeploymentStatus)
4451
+ );
4452
+ }
4453
+ console.log(source_default.white("Region: ") + source_default.gray(server.region));
4454
+ console.log(
4455
+ source_default.white("MCP URL: ") + source_default.cyan(getMcpServerUrlForCloudServer(server))
4456
+ );
4457
+ if (server.connectedRepository) {
4458
+ const cr = server.connectedRepository;
4459
+ console.log(source_default.white("\nRepository"));
4460
+ console.log(source_default.white(" Full name: ") + source_default.gray(cr.repoFullName));
4461
+ console.log(
4462
+ source_default.white(" Prod branch: ") + source_default.gray(cr.productionBranch)
4463
+ );
4464
+ }
4465
+ if (server.activeDeploymentId) {
4466
+ console.log(
4467
+ source_default.white("\nActive deployment: ") + source_default.cyan(server.activeDeploymentId)
4468
+ );
4469
+ }
4470
+ if (server.previousDeploymentId) {
4471
+ console.log(
4472
+ source_default.white("Previous deployment: ") + source_default.gray(server.previousDeploymentId)
4473
+ );
4474
+ }
4475
+ const depCount = server._count?.deployments;
4476
+ if (depCount != null) {
4477
+ console.log(
4478
+ source_default.white("Deployment count: ") + source_default.gray(String(depCount))
4479
+ );
4480
+ }
4481
+ console.log(
4482
+ source_default.white("Created: ") + source_default.gray(formatRelativeTime(server.createdAt))
4483
+ );
4484
+ console.log(
4485
+ source_default.white("Updated: ") + source_default.gray(formatRelativeTime(server.updatedAt))
4486
+ );
4487
+ const config = await readConfig();
4488
+ const base = (await getWebUrl()).replace(/\/$/, "");
4489
+ if (config.orgSlug) {
4490
+ console.log(
4491
+ source_default.white("\nDashboard: ") + source_default.cyan(`${base}/cloud/${config.orgSlug}/servers/${server.id}`)
4492
+ );
4493
+ } else {
4494
+ console.log(
4495
+ source_default.white("\nDashboard: ") + source_default.cyan(`${base}/cloud/servers/${server.id}`)
4496
+ );
4497
+ }
4498
+ if (Array.isArray(server.deployments) && server.deployments.length > 0) {
4499
+ console.log(source_default.cyan.bold("\nRecent deployments\n"));
4500
+ console.log(
4501
+ source_default.white.bold(
4502
+ `${"ID".padEnd(40)} ${"NAME".padEnd(24)} ${"STATUS".padEnd(12)} ${"UPDATED"}`
4503
+ )
4504
+ );
4505
+ console.log(source_default.gray("\u2500".repeat(100)));
4506
+ for (const d of server.deployments) {
4507
+ const did = pickStr(d, "id").padEnd(40);
4508
+ const dname = pickStr(d, "name").substring(0, 23).padEnd(24);
4509
+ const dst = pickStr(d, "status").padEnd(12);
4510
+ const du = pickStr(d, "updatedAt");
4511
+ const updated = du !== "-" ? formatRelativeTime(du) : source_default.gray("-");
4512
+ const sc = getStatusColor2(dst.trim());
4513
+ console.log(
4514
+ `${source_default.gray(did)} ${dname} ${sc(dst)} ${source_default.gray(updated)}`
4515
+ );
4516
+ }
4517
+ }
4518
+ console.log();
4519
+ } catch (error) {
4520
+ console.error(
4521
+ source_default.red.bold("\n\u2717 Failed to get server:"),
4522
+ source_default.red(error instanceof Error ? error.message : "Unknown error")
4523
+ );
4524
+ process.exit(1);
4525
+ }
4526
+ }
4527
+ async function deleteServerCommand(serverId, options) {
4528
+ try {
4529
+ if (!await isLoggedIn()) {
4530
+ console.log(source_default.red("\u2717 You are not logged in."));
4531
+ console.log(
4532
+ source_default.gray(
4533
+ "Run " + source_default.white("npx mcp-use login") + " to get started."
4534
+ )
4535
+ );
4536
+ process.exit(1);
4537
+ }
4538
+ const api = await McpUseAPI.create();
4539
+ await applyOrgOption(api, options.org);
4540
+ if (options.org) console.log();
4541
+ const server = await api.getServer(serverId);
4542
+ if (!options.yes) {
4543
+ console.log(
4544
+ source_default.yellow(
4545
+ `
4546
+ \u26A0\uFE0F You are about to delete server: ${source_default.white(server.name || server.slug || server.id)}`
4547
+ )
4548
+ );
4549
+ console.log(source_default.gray(` ID: ${server.id}`));
4550
+ if (server.connectedRepository?.repoFullName) {
4551
+ console.log(
4552
+ source_default.gray(` Repo: ${server.connectedRepository.repoFullName}
4553
+ `)
4554
+ );
4555
+ } else {
4556
+ console.log();
4557
+ }
4558
+ const confirmed = await prompt3(
4559
+ source_default.white(
4560
+ "This deletes the server and all its deployments. Continue? (y/N): "
4561
+ )
4562
+ );
4563
+ if (!confirmed) {
4564
+ console.log(source_default.gray("Deletion cancelled."));
4565
+ return;
4566
+ }
4567
+ }
4568
+ await api.deleteServer(server.id);
4569
+ console.log(
4570
+ source_default.green.bold(
4571
+ `
4572
+ \u2713 Server deleted: ${server.name || server.slug || server.id}
4573
+ `
4574
+ )
4575
+ );
4576
+ } catch (error) {
4577
+ console.error(
4578
+ source_default.red.bold("\n\u2717 Failed to delete server:"),
4579
+ source_default.red(error instanceof Error ? error.message : "Unknown error")
4580
+ );
4581
+ process.exit(1);
4582
+ }
4583
+ }
4584
+ function createServersCommand() {
4585
+ const serversCommand = new Command3("servers").description(
4586
+ "Manage cloud servers (Git-backed deploy targets)"
4587
+ );
4588
+ 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);
4589
+ 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);
4590
+ serversCommand.command("delete").alias("rm").argument("<server-id>", "Server UUID (or slug if API accepts it)").option("-y, --yes", "Skip confirmation prompt").option("--org <slug-or-id>", "Target organization").description("Delete a server and all its deployments").action(deleteServerCommand);
4591
+ return serversCommand;
4592
+ }
4593
+
4263
4594
  // src/commands/org.ts
4264
4595
  async function ensureLoggedIn() {
4265
4596
  if (!await isLoggedIn()) {
@@ -4380,7 +4711,7 @@ async function orgCurrentCommand() {
4380
4711
  }
4381
4712
 
4382
4713
  // src/commands/skills.ts
4383
- import { Command as Command3 } from "commander";
4714
+ import { Command as Command4 } from "commander";
4384
4715
  import { cpSync, existsSync as existsSync2, mkdtempSync, readdirSync, rmSync } from "fs";
4385
4716
  import { tmpdir } from "os";
4386
4717
  import { join as join2, resolve } from "path";
@@ -4450,7 +4781,7 @@ async function addSkillsToProject(projectPath) {
4450
4781
  }
4451
4782
  }
4452
4783
  function createSkillsCommand() {
4453
- const skills = new Command3("skills").description(
4784
+ const skills = new Command4("skills").description(
4454
4785
  "Manage mcp-use AI agent skills"
4455
4786
  );
4456
4787
  const installAction = async (options) => {
@@ -4626,7 +4957,7 @@ A new release of ${source_default.bold(PACKAGE_NAME)} is available: ${source_def
4626
4957
  }
4627
4958
 
4628
4959
  // src/index.ts
4629
- var program = new Command4();
4960
+ var program = new Command5();
4630
4961
  var packageContent = readFileSync2(
4631
4962
  path7.join(__dirname, "../package.json"),
4632
4963
  "utf-8"
@@ -6454,7 +6785,13 @@ program.command("deploy").description("Deploy MCP server from GitHub to Manufact
6454
6785
  ).option(
6455
6786
  "--org <slug-or-id>",
6456
6787
  "Deploy to a specific organization (by slug or ID)"
6457
- ).option("-y, --yes", "Skip confirmation prompts").action(async (options) => {
6788
+ ).option("-y, --yes", "Skip confirmation prompts").option("--region <region>", "Deploy region: US, EU, or APAC (default: US)").option(
6789
+ "--build-command <cmd>",
6790
+ "Custom build command (overrides auto-detection)"
6791
+ ).option(
6792
+ "--start-command <cmd>",
6793
+ "Custom start command (overrides auto-detection)"
6794
+ ).action(async (options) => {
6458
6795
  await deployCommand({
6459
6796
  open: options.open,
6460
6797
  name: options.name,
@@ -6465,11 +6802,15 @@ program.command("deploy").description("Deploy MCP server from GitHub to Manufact
6465
6802
  envFile: options.envFile,
6466
6803
  rootDir: options.rootDir,
6467
6804
  org: options.org,
6468
- yes: options.yes
6805
+ yes: options.yes,
6806
+ region: options.region,
6807
+ buildCommand: options.buildCommand,
6808
+ startCommand: options.startCommand
6469
6809
  });
6470
6810
  });
6471
6811
  program.addCommand(createClientCommand());
6472
6812
  program.addCommand(createDeploymentsCommand());
6813
+ program.addCommand(createServersCommand());
6473
6814
  program.addCommand(createSkillsCommand());
6474
6815
  program.command("generate-types").description(
6475
6816
  "Generate TypeScript type definitions for tools (writes .mcp-use/tool-registry.d.ts)"