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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -523,8 +523,8 @@ var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
523
523
  var source_default = chalk;
524
524
 
525
525
  // src/index.ts
526
- var import_commander4 = require("commander");
527
- var import_config6 = require("dotenv/config");
526
+ var import_commander5 = require("commander");
527
+ var import_config7 = require("dotenv/config");
528
528
  var import_node_child_process9 = require("child_process");
529
529
  var import_node_fs10 = require("fs");
530
530
  var import_promises7 = require("fs/promises");
@@ -1334,6 +1334,35 @@ var McpUseAPI = class _McpUseAPI {
1334
1334
  body: JSON.stringify(body)
1335
1335
  });
1336
1336
  }
1337
+ async listServers(params) {
1338
+ const search = new URLSearchParams();
1339
+ if (params?.organizationId) {
1340
+ search.set("organizationId", params.organizationId);
1341
+ }
1342
+ if (params?.limit != null) {
1343
+ search.set("limit", String(params.limit));
1344
+ }
1345
+ if (params?.skip != null) {
1346
+ search.set("skip", String(params.skip));
1347
+ }
1348
+ if (params?.sort) {
1349
+ search.set("sort", params.sort);
1350
+ }
1351
+ const q = search.toString();
1352
+ return this.request(`/servers${q ? `?${q}` : ""}`);
1353
+ }
1354
+ async getServer(idOrSlug) {
1355
+ const path7 = encodeURIComponent(idOrSlug);
1356
+ return this.request(`/servers/${path7}`);
1357
+ }
1358
+ async deleteServer(id) {
1359
+ await this.request(
1360
+ `/servers/${encodeURIComponent(id)}`,
1361
+ {
1362
+ method: "DELETE"
1363
+ }
1364
+ );
1365
+ }
1337
1366
  // ── Deployments ─────────────────────────────────────────────────
1338
1367
  async createDeployment(input) {
1339
1368
  return this.request("/deployments", {
@@ -1378,7 +1407,9 @@ var McpUseAPI = class _McpUseAPI {
1378
1407
  is_connected: resp.installations.length > 0,
1379
1408
  installations: resp.installations.map((i) => ({
1380
1409
  id: i.id,
1381
- installation_id: i.installationId
1410
+ installation_id: i.installationId,
1411
+ account_login: i.account?.login ?? "",
1412
+ account_type: i.account?.type ?? "User"
1382
1413
  }))
1383
1414
  };
1384
1415
  }
@@ -1407,7 +1438,27 @@ var McpUseAPI = class _McpUseAPI {
1407
1438
  }
1408
1439
  async getGitHubAppName() {
1409
1440
  if (process.env.MCP_GITHUB_APP_NAME) return process.env.MCP_GITHUB_APP_NAME;
1410
- return this.baseUrl.includes(".dev.") ? "mcp-use-dev" : "mcp-use";
1441
+ if (this.baseUrl.includes("localhost")) return "mcp-use-local";
1442
+ if (this.baseUrl.includes(".dev.")) return "mcp-use-dev";
1443
+ return "mcp-use";
1444
+ }
1445
+ /**
1446
+ * Returns the GitHub numeric installation ID (not the DB UUID) for the org.
1447
+ * Used for building direct installation settings URLs.
1448
+ */
1449
+ async getGitHubInstallationId() {
1450
+ const status = await this.getGitHubConnectionStatus();
1451
+ return status.installations?.[0]?.installation_id ?? null;
1452
+ }
1453
+ async createGitHubRepo(opts) {
1454
+ return this.request(`/github/installations/${opts.installationId}/repos`, {
1455
+ method: "POST",
1456
+ body: JSON.stringify({
1457
+ name: opts.name,
1458
+ private: opts.private ?? true,
1459
+ org: opts.org
1460
+ })
1461
+ });
1411
1462
  }
1412
1463
  };
1413
1464
 
@@ -2462,9 +2513,9 @@ async function listPromptsCommand(options) {
2462
2513
  }
2463
2514
  console.log(formatHeader(`Available Prompts (${prompts.length}):`));
2464
2515
  console.log("");
2465
- const tableData = prompts.map((prompt3) => ({
2466
- name: source_default.bold(prompt3.name),
2467
- description: prompt3.description || source_default.gray("No description")
2516
+ const tableData = prompts.map((prompt4) => ({
2517
+ name: source_default.bold(prompt4.name),
2518
+ description: prompt4.description || source_default.gray("No description")
2468
2519
  }));
2469
2520
  console.log(
2470
2521
  formatTable(tableData, [
@@ -2492,20 +2543,20 @@ async function getPromptCommand(promptName, argsJson, options) {
2492
2543
  }
2493
2544
  }
2494
2545
  console.error(formatInfo(`Getting prompt '${promptName}'...`));
2495
- const prompt3 = await session.getPrompt(promptName, args);
2546
+ const prompt4 = await session.getPrompt(promptName, args);
2496
2547
  if (options?.json) {
2497
- console.log(formatJson(prompt3));
2548
+ console.log(formatJson(prompt4));
2498
2549
  } else {
2499
2550
  console.log(formatHeader(`Prompt: ${promptName}`));
2500
2551
  console.log("");
2501
- if (prompt3.description) {
2502
- console.log(prompt3.description);
2552
+ if (prompt4.description) {
2553
+ console.log(prompt4.description);
2503
2554
  console.log("");
2504
2555
  }
2505
- if (prompt3.messages) {
2556
+ if (prompt4.messages) {
2506
2557
  console.log(formatHeader("Messages:"));
2507
2558
  console.log("");
2508
- console.log(formatPromptMessages(prompt3.messages));
2559
+ console.log(formatPromptMessages(prompt4.messages));
2509
2560
  }
2510
2561
  }
2511
2562
  } catch (error) {
@@ -2645,8 +2696,8 @@ async function interactiveCommand(options) {
2645
2696
  async (argsInput) => {
2646
2697
  try {
2647
2698
  const args = argsInput.trim() ? JSON.parse(argsInput) : {};
2648
- const prompt3 = await session.getPrompt(arg, args);
2649
- console.log(formatPromptMessages(prompt3.messages));
2699
+ const prompt4 = await session.getPrompt(arg, args);
2700
+ console.log(formatPromptMessages(prompt4.messages));
2650
2701
  } catch (error) {
2651
2702
  console.error(formatError(error.message));
2652
2703
  }
@@ -2812,6 +2863,20 @@ async function getGitInfo(cwd = process.cwd()) {
2812
2863
  hasUncommittedChanges: uncommittedChanges
2813
2864
  };
2814
2865
  }
2866
+ async function gitInit(cwd, message = "Initial commit") {
2867
+ await gitCommand("git init", cwd);
2868
+ await gitCommand("git add .", cwd);
2869
+ await gitCommand(`git commit -m "${message}"`, cwd);
2870
+ }
2871
+ async function gitAddRemoteAndPush(cwd, cloneUrl, branch = "main") {
2872
+ await gitCommand(`git remote add origin ${cloneUrl}`, cwd);
2873
+ await gitCommand(`git push -u origin ${branch}`, cwd);
2874
+ }
2875
+ async function gitCommitAndPush(cwd, message, branch = "main") {
2876
+ await gitCommand("git add .", cwd);
2877
+ await gitCommand(`git commit -m "${message}"`, cwd);
2878
+ await gitCommand(`git push origin ${branch}`, cwd);
2879
+ }
2815
2880
  function isGitHubUrl(url) {
2816
2881
  try {
2817
2882
  const parsedUrl = new URL(url);
@@ -2826,6 +2891,22 @@ function isGitHubUrl(url) {
2826
2891
  return false;
2827
2892
  }
2828
2893
 
2894
+ // src/utils/cloud-urls.ts
2895
+ var GATEWAY_DOMAIN = "run.mcp-use.com";
2896
+ function buildGatewayUrl(slugOrId) {
2897
+ return `https://${slugOrId}.${GATEWAY_DOMAIN}/mcp`;
2898
+ }
2899
+ function getMcpServerUrl(deployment) {
2900
+ if (deployment.mcpUrl) return deployment.mcpUrl;
2901
+ if (deployment.serverId) return buildGatewayUrl(deployment.serverId);
2902
+ return "";
2903
+ }
2904
+ function getMcpServerUrlForCloudServer(server) {
2905
+ if (server.mcpUrl) return server.mcpUrl;
2906
+ const hostKey = server.slug && server.slug.trim() || server.id;
2907
+ return buildGatewayUrl(hostKey);
2908
+ }
2909
+
2829
2910
  // src/utils/project-link.ts
2830
2911
  var import_node_fs6 = require("fs");
2831
2912
  var import_node_path4 = __toESM(require("path"), 1);
@@ -2872,10 +2953,6 @@ ${MCP_USE_DIR}
2872
2953
  }
2873
2954
 
2874
2955
  // src/commands/deploy.ts
2875
- var GATEWAY_DOMAIN = "run.mcp-use.com";
2876
- function buildGatewayUrl(slugOrId) {
2877
- return `https://${slugOrId}.${GATEWAY_DOMAIN}/mcp`;
2878
- }
2879
2956
  async function parseEnvFile(filePath) {
2880
2957
  try {
2881
2958
  const content = await import_node_fs7.promises.readFile(filePath, "utf-8");
@@ -2885,9 +2962,7 @@ async function parseEnvFile(filePath) {
2885
2962
  let currentValue = "";
2886
2963
  for (let line of lines) {
2887
2964
  line = line.trim();
2888
- if (!line || line.startsWith("#")) {
2889
- continue;
2890
- }
2965
+ if (!line || line.startsWith("#")) continue;
2891
2966
  if (currentKey && !line.includes("=")) {
2892
2967
  currentValue += "\n" + line;
2893
2968
  continue;
@@ -2898,20 +2973,15 @@ async function parseEnvFile(filePath) {
2898
2973
  currentValue = "";
2899
2974
  }
2900
2975
  const equalIndex = line.indexOf("=");
2901
- if (equalIndex === -1) {
2902
- continue;
2903
- }
2976
+ if (equalIndex === -1) continue;
2904
2977
  const key = line.substring(0, equalIndex).trim();
2905
- let value = line.substring(equalIndex + 1).trim();
2978
+ const value = line.substring(equalIndex + 1).trim();
2906
2979
  if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
2907
- console.log(
2908
- source_default.yellow(`\u26A0\uFE0F Skipping invalid environment variable key: ${key}`)
2909
- );
2980
+ console.log(source_default.yellow(`\u26A0\uFE0F Skipping invalid env key: ${key}`));
2910
2981
  continue;
2911
2982
  }
2912
2983
  if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
2913
- value = value.slice(1, -1);
2914
- envVars[key] = value;
2984
+ envVars[key] = value.slice(1, -1);
2915
2985
  } else if (value.startsWith('"') || value.startsWith("'")) {
2916
2986
  currentKey = key;
2917
2987
  currentValue = value.slice(1);
@@ -2935,16 +3005,12 @@ async function parseEnvFile(filePath) {
2935
3005
  function parseEnvVar(envStr) {
2936
3006
  const equalIndex = envStr.indexOf("=");
2937
3007
  if (equalIndex === -1) {
2938
- throw new Error(
2939
- `Invalid environment variable format: "${envStr}". Expected KEY=VALUE`
2940
- );
3008
+ throw new Error(`Invalid env format: "${envStr}". Expected KEY=VALUE`);
2941
3009
  }
2942
3010
  const key = envStr.substring(0, equalIndex).trim();
2943
3011
  const value = envStr.substring(equalIndex + 1);
2944
3012
  if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
2945
- throw new Error(
2946
- `Invalid environment variable key: "${key}". Keys must start with a letter or underscore and contain only letters, numbers, and underscores.`
2947
- );
3013
+ throw new Error(`Invalid env key: "${key}".`);
2948
3014
  }
2949
3015
  return { key, value };
2950
3016
  }
@@ -2987,72 +3053,48 @@ async function buildEnvVars(options) {
2987
3053
  }
2988
3054
  async function isMcpProject(cwd = process.cwd()) {
2989
3055
  try {
2990
- const packageJsonPath = import_node_path5.default.join(cwd, "package.json");
2991
- const content = await import_node_fs7.promises.readFile(packageJsonPath, "utf-8");
2992
- const packageJson2 = JSON.parse(content);
2993
- const hasMcpDeps = packageJson2.dependencies?.["mcp-use"] || packageJson2.dependencies?.["@modelcontextprotocol/sdk"] || packageJson2.devDependencies?.["mcp-use"] || packageJson2.devDependencies?.["@modelcontextprotocol/sdk"];
2994
- const hasMcpScripts = packageJson2.scripts?.mcp || packageJson2.scripts?.["mcp:dev"];
2995
- return !!(hasMcpDeps || hasMcpScripts);
3056
+ const content = await import_node_fs7.promises.readFile(import_node_path5.default.join(cwd, "package.json"), "utf-8");
3057
+ const pkg = JSON.parse(content);
3058
+ return !!(pkg.dependencies?.["mcp-use"] || pkg.dependencies?.["@modelcontextprotocol/sdk"] || pkg.devDependencies?.["mcp-use"] || pkg.devDependencies?.["@modelcontextprotocol/sdk"]);
2996
3059
  } catch {
2997
3060
  return false;
2998
3061
  }
2999
3062
  }
3000
3063
  async function getProjectName(cwd = process.cwd()) {
3001
3064
  try {
3002
- const packageJsonPath = import_node_path5.default.join(cwd, "package.json");
3003
- const content = await import_node_fs7.promises.readFile(packageJsonPath, "utf-8");
3004
- const packageJson2 = JSON.parse(content);
3005
- if (packageJson2.name) {
3006
- return packageJson2.name;
3007
- }
3065
+ const content = await import_node_fs7.promises.readFile(import_node_path5.default.join(cwd, "package.json"), "utf-8");
3066
+ const pkg = JSON.parse(content);
3067
+ if (pkg.name) return pkg.name;
3008
3068
  } catch {
3009
3069
  }
3010
3070
  return import_node_path5.default.basename(cwd);
3011
3071
  }
3012
- async function detectBuildCommand(cwd = process.cwd()) {
3072
+ async function detectBuildCommand(cwd) {
3013
3073
  try {
3014
- const packageJsonPath = import_node_path5.default.join(cwd, "package.json");
3015
- const content = await import_node_fs7.promises.readFile(packageJsonPath, "utf-8");
3016
- const packageJson2 = JSON.parse(content);
3017
- if (packageJson2.scripts?.build) {
3018
- return "npm run build";
3019
- }
3074
+ const content = await import_node_fs7.promises.readFile(import_node_path5.default.join(cwd, "package.json"), "utf-8");
3075
+ if (JSON.parse(content).scripts?.build) return "npm run build";
3020
3076
  } catch {
3021
3077
  }
3022
3078
  return void 0;
3023
3079
  }
3024
- async function detectStartCommand(cwd = process.cwd()) {
3080
+ async function detectStartCommand(cwd) {
3025
3081
  try {
3026
- const packageJsonPath = import_node_path5.default.join(cwd, "package.json");
3027
- const content = await import_node_fs7.promises.readFile(packageJsonPath, "utf-8");
3028
- const packageJson2 = JSON.parse(content);
3029
- if (packageJson2.scripts?.start) {
3030
- return "npm start";
3031
- }
3032
- if (packageJson2.main) {
3033
- return `node ${packageJson2.main}`;
3034
- }
3082
+ const content = await import_node_fs7.promises.readFile(import_node_path5.default.join(cwd, "package.json"), "utf-8");
3083
+ const pkg = JSON.parse(content);
3084
+ if (pkg.scripts?.start) return "npm start";
3085
+ if (pkg.main) return `node ${pkg.main}`;
3035
3086
  } catch {
3036
3087
  }
3037
3088
  return void 0;
3038
3089
  }
3039
- async function detectRuntime(cwd = process.cwd()) {
3040
- try {
3041
- const pythonFiles = ["requirements.txt", "pyproject.toml", "setup.py"];
3042
- for (const file of pythonFiles) {
3043
- try {
3044
- await import_node_fs7.promises.access(import_node_path5.default.join(cwd, file));
3045
- return "python";
3046
- } catch {
3047
- continue;
3048
- }
3049
- }
3090
+ async function detectRuntime(cwd) {
3091
+ for (const f of ["requirements.txt", "pyproject.toml", "setup.py"]) {
3050
3092
  try {
3051
- await import_node_fs7.promises.access(import_node_path5.default.join(cwd, "package.json"));
3052
- return "node";
3093
+ await import_node_fs7.promises.access(import_node_path5.default.join(cwd, f));
3094
+ return "python";
3053
3095
  } catch {
3096
+ continue;
3054
3097
  }
3055
- } catch {
3056
3098
  }
3057
3099
  return "node";
3058
3100
  }
@@ -3062,31 +3104,51 @@ async function prompt(question, defaultValue = "n") {
3062
3104
  input: process.stdin,
3063
3105
  output: process.stdout
3064
3106
  });
3065
- const defaultIndicator = defaultValue === "y" ? "Y/n" : "y/N";
3066
- const questionWithDefault = question.replace(
3067
- /(\(y\/n\):)/,
3068
- `(${defaultIndicator}):`
3069
- );
3107
+ const indicator = defaultValue === "y" ? "Y/n" : "y/N";
3108
+ const q = question.replace(/(\(y\/n\):)/, `(${indicator}):`);
3070
3109
  return new Promise((resolve2) => {
3071
- rl.question(questionWithDefault, (answer) => {
3110
+ rl.question(q, (answer) => {
3072
3111
  rl.close();
3073
- const trimmedAnswer = answer.trim().toLowerCase();
3074
- if (trimmedAnswer === "") {
3075
- resolve2(defaultValue === "y");
3076
- } else {
3077
- resolve2(trimmedAnswer === "y" || trimmedAnswer === "yes");
3078
- }
3112
+ const a = answer.trim().toLowerCase();
3113
+ if (a === "") resolve2(defaultValue === "y");
3114
+ else resolve2(a === "y" || a === "yes");
3079
3115
  });
3080
3116
  });
3081
3117
  }
3082
- function getMcpServerUrl(deployment) {
3083
- if (deployment.mcpUrl) {
3084
- return deployment.mcpUrl;
3118
+ async function promptText(question, defaultValue) {
3119
+ const readline = await import("readline");
3120
+ const rl = readline.createInterface({
3121
+ input: process.stdin,
3122
+ output: process.stdout
3123
+ });
3124
+ const suffix = defaultValue ? source_default.gray(` [${defaultValue}]`) : "";
3125
+ return new Promise((resolve2) => {
3126
+ rl.question(question + suffix + " ", (answer) => {
3127
+ rl.close();
3128
+ resolve2(answer.trim() || defaultValue || "");
3129
+ });
3130
+ });
3131
+ }
3132
+ var REQUIRED_IGNORES = [
3133
+ "node_modules",
3134
+ "dist",
3135
+ ".env",
3136
+ ".env.local",
3137
+ ".mcp-use"
3138
+ ];
3139
+ async function ensureGitignore(cwd) {
3140
+ const gitignorePath = import_node_path5.default.join(cwd, ".gitignore");
3141
+ let content = "";
3142
+ try {
3143
+ content = await import_node_fs7.promises.readFile(gitignorePath, "utf-8");
3144
+ } catch {
3085
3145
  }
3086
- if (deployment.serverId) {
3087
- return buildGatewayUrl(deployment.serverId);
3146
+ const missing = REQUIRED_IGNORES.filter((entry) => !content.includes(entry));
3147
+ if (missing.length > 0) {
3148
+ const additions = missing.join("\n");
3149
+ const newContent = content + (content.endsWith("\n") ? "" : "\n") + additions + "\n";
3150
+ await import_node_fs7.promises.writeFile(gitignorePath, newContent, "utf-8");
3088
3151
  }
3089
- return "";
3090
3152
  }
3091
3153
  async function displayDeploymentProgress(api, deploymentId, progressOptions) {
3092
3154
  const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
@@ -3096,11 +3158,10 @@ async function displayDeploymentProgress(api, deploymentId, progressOptions) {
3096
3158
  if (spinnerInterval) clearInterval(spinnerInterval);
3097
3159
  process.stdout.write("\r\x1B[K");
3098
3160
  spinnerInterval = setInterval(() => {
3099
- const frame = frames[frameIndex];
3100
- frameIndex = (frameIndex + 1) % frames.length;
3101
3161
  process.stdout.write(
3102
- "\r" + source_default.cyan(frame) + " " + source_default.gray(message)
3162
+ "\r" + source_default.cyan(frames[frameIndex]) + " " + source_default.gray(message)
3103
3163
  );
3164
+ frameIndex = (frameIndex + 1) % frames.length;
3104
3165
  }, 80);
3105
3166
  };
3106
3167
  const stopSpinner = () => {
@@ -3117,57 +3178,49 @@ async function displayDeploymentProgress(api, deploymentId, progressOptions) {
3117
3178
  let delay = 2e3;
3118
3179
  const maxDelay = 1e4;
3119
3180
  let buildLogOffset = 0;
3120
- const sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
3121
3181
  while (checkCount < maxChecks) {
3122
- await sleep(delay);
3182
+ const waitMs = delay;
3183
+ await new Promise((r) => setTimeout(r, waitMs));
3123
3184
  checkCount++;
3124
3185
  try {
3125
- const buildLogsResp = await api.getDeploymentBuildLogs(
3186
+ const resp = await api.getDeploymentBuildLogs(
3126
3187
  deploymentId,
3127
3188
  buildLogOffset
3128
3189
  );
3129
- if (buildLogsResp.logs.length > 0) {
3130
- const logLines = buildLogsResp.logs.split("\n").filter((l) => l.trim());
3131
- for (const line of logLines) {
3190
+ if (resp.logs.length > 0) {
3191
+ for (const line of resp.logs.split("\n").filter((l) => l.trim())) {
3132
3192
  try {
3133
- const logData = JSON.parse(line);
3134
- if (logData.line) {
3193
+ const d = JSON.parse(line);
3194
+ if (d.line) {
3135
3195
  stopSpinner();
3136
- const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
3137
- const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
3138
- console.log(stepPrefix + levelColor(logData.line));
3196
+ const color = d.level === "error" ? source_default.red : d.level === "warn" ? source_default.yellow : source_default.gray;
3197
+ const prefix = d.step ? source_default.cyan(`[${d.step}]`) + " " : "";
3198
+ console.log(prefix + color(d.line));
3139
3199
  }
3140
3200
  } catch {
3141
3201
  stopSpinner();
3142
3202
  console.log(source_default.gray(line));
3143
3203
  }
3144
3204
  }
3145
- buildLogOffset = buildLogsResp.offset;
3205
+ buildLogOffset = resp.offset;
3146
3206
  }
3147
3207
  } catch {
3148
3208
  }
3149
- const deployment = await api.getDeployment(deploymentId);
3150
- if (deployment.status === "running") {
3209
+ const dep = await api.getDeployment(deploymentId);
3210
+ if (dep.status === "running") {
3151
3211
  stopSpinner();
3152
- const mcpServerUrl = getMcpServerUrl(deployment);
3153
- let dashboardUrl = null;
3212
+ const mcpUrl = getMcpServerUrl(dep);
3154
3213
  const webUrl = (await getWebUrl()).replace(/\/$/, "");
3155
3214
  const config = await readConfig();
3156
- const orgSlug = config.orgSlug;
3157
- if (deployment.serverId) {
3158
- if (orgSlug) {
3159
- dashboardUrl = `${webUrl}/cloud/${orgSlug}/servers/${deployment.serverId}`;
3160
- } else {
3161
- dashboardUrl = `${webUrl}/cloud/servers/${deployment.serverId}`;
3162
- }
3215
+ let dashboardUrl = null;
3216
+ if (dep.serverId) {
3217
+ dashboardUrl = config.orgSlug ? `${webUrl}/cloud/${config.orgSlug}/servers/${dep.serverId}` : `${webUrl}/cloud/servers/${dep.serverId}`;
3163
3218
  }
3164
- const inspectorUrl = `https://inspector.manufact.com/inspector?autoConnect=${encodeURIComponent(
3165
- mcpServerUrl
3166
- )}`;
3219
+ const inspectorUrl = `https://inspector.manufact.com/inspector?autoConnect=${encodeURIComponent(mcpUrl)}`;
3167
3220
  console.log(source_default.green.bold("\u2713 Deployment successful!\n"));
3168
- if (mcpServerUrl) {
3221
+ if (mcpUrl) {
3169
3222
  console.log(source_default.white("\u{1F310} MCP Server URL:"));
3170
- console.log(source_default.cyan.bold(` ${mcpServerUrl}
3223
+ console.log(source_default.cyan.bold(` ${mcpUrl}
3171
3224
  `));
3172
3225
  }
3173
3226
  if (dashboardUrl) {
@@ -3178,39 +3231,42 @@ async function displayDeploymentProgress(api, deploymentId, progressOptions) {
3178
3231
  console.log(source_default.white("\u{1F50D} Inspector URL:"));
3179
3232
  console.log(source_default.cyan.bold(` ${inspectorUrl}
3180
3233
  `));
3181
- console.log(source_default.gray("Deployment ID: ") + source_default.white(deployment.id));
3234
+ console.log(source_default.gray("Deployment ID: ") + source_default.white(dep.id));
3182
3235
  return;
3183
- } else if (deployment.status === "failed") {
3236
+ } else if (dep.status === "failed") {
3184
3237
  stopSpinner();
3185
3238
  console.log(source_default.red.bold("\u2717 Deployment failed\n"));
3186
- if (deployment.error) {
3187
- console.log(source_default.red("Error: ") + deployment.error);
3188
- if (deployment.error.includes("No GitHub installations found")) {
3189
- console.log();
3190
- const retry = await promptGitHubInstallation(
3191
- api,
3192
- "not_connected",
3193
- void 0,
3194
- { yes: progressOptions?.yes }
3239
+ if (dep.error) {
3240
+ const internalPatterns = [
3241
+ "GraphQL",
3242
+ "authenticated",
3243
+ "INTERNAL",
3244
+ "Fly API",
3245
+ "token validation",
3246
+ "context deadline",
3247
+ "Bad gateway",
3248
+ "502",
3249
+ "503"
3250
+ ];
3251
+ const isInternalError = internalPatterns.some(
3252
+ (p) => dep.error.includes(p)
3253
+ );
3254
+ if (isInternalError) {
3255
+ console.log(
3256
+ source_default.red("Error: ") + "An internal infrastructure error occurred. Please try again."
3195
3257
  );
3196
- if (retry && deployment.serverId) {
3197
- console.log(source_default.cyan("\n\u{1F504} Retrying deployment...\n"));
3198
- const newDep = await api.createDeployment({
3199
- serverId: deployment.serverId,
3200
- trigger: "redeploy"
3201
- });
3202
- await displayDeploymentProgress(api, newDep.id, progressOptions);
3203
- return;
3204
- }
3258
+ console.log(source_default.gray(" Details: " + dep.error));
3259
+ } else {
3260
+ console.log(source_default.red("Error: ") + dep.error);
3205
3261
  }
3206
3262
  }
3207
3263
  process.exit(1);
3208
- } else if (deployment.status === "building" || deployment.status === "pending") {
3264
+ } else if (dep.status === "building" || dep.status === "pending") {
3209
3265
  startSpinner("Building and deploying...");
3210
3266
  delay = Math.min(delay * 1.2, maxDelay);
3211
3267
  } else {
3212
3268
  stopSpinner();
3213
- console.log(source_default.yellow("\u26A0\uFE0F Deployment status: ") + deployment.status);
3269
+ console.log(source_default.yellow("\u26A0\uFE0F Deployment status: ") + dep.status);
3214
3270
  return;
3215
3271
  }
3216
3272
  }
@@ -3222,58 +3278,12 @@ async function displayDeploymentProgress(api, deploymentId, progressOptions) {
3222
3278
  }
3223
3279
  async function checkRepoAccess(api, owner, repo) {
3224
3280
  try {
3225
- const reposResponse = await api.getGitHubRepos(true);
3226
- const repoFullName = `${owner}/${repo}`;
3227
- return reposResponse.repos.some((r) => r.full_name === repoFullName);
3228
- } catch (error) {
3229
- console.log(source_default.gray("Could not verify repository access"));
3281
+ const resp = await api.getGitHubRepos(true);
3282
+ return resp.repos.some((r) => r.full_name === `${owner}/${repo}`);
3283
+ } catch {
3230
3284
  return false;
3231
3285
  }
3232
3286
  }
3233
- var GITHUB_SETUP_POLL_INTERVAL_MS = 2e3;
3234
- var GITHUB_SETUP_POLL_MAX_MS = 12e4;
3235
- async function waitForGitHubSetupAfterBrowser(api, repoName, yes) {
3236
- if (!yes) {
3237
- console.log(source_default.gray("Waiting for GitHub configuration..."));
3238
- await prompt(
3239
- source_default.white("Press Enter when you've completed the GitHub setup..."),
3240
- "y"
3241
- );
3242
- return;
3243
- }
3244
- console.log(
3245
- source_default.gray(
3246
- "Waiting for GitHub configuration (polling every 2s, up to 2 min)..."
3247
- )
3248
- );
3249
- const deadline = Date.now() + GITHUB_SETUP_POLL_MAX_MS;
3250
- while (Date.now() < deadline) {
3251
- try {
3252
- const status = await api.getGitHubConnectionStatus();
3253
- if (!status.is_connected) {
3254
- await new Promise((r) => setTimeout(r, GITHUB_SETUP_POLL_INTERVAL_MS));
3255
- continue;
3256
- }
3257
- if (repoName) {
3258
- const parts = repoName.split("/");
3259
- const owner = parts[0];
3260
- const repo = parts[1];
3261
- if (owner && repo && await checkRepoAccess(api, owner, repo)) {
3262
- return;
3263
- }
3264
- } else {
3265
- return;
3266
- }
3267
- } catch {
3268
- }
3269
- await new Promise((r) => setTimeout(r, GITHUB_SETUP_POLL_INTERVAL_MS));
3270
- }
3271
- console.log(
3272
- source_default.yellow(
3273
- "\u26A0\uFE0F Timed out waiting for GitHub setup. Continuing with verification..."
3274
- )
3275
- );
3276
- }
3277
3287
  async function promptGitHubInstallation(api, reason, repoName, opts) {
3278
3288
  const yes = !!opts?.yes;
3279
3289
  console.log();
@@ -3299,96 +3309,48 @@ async function promptGitHubInstallation(api, reason, repoName, opts) {
3299
3309
  ),
3300
3310
  "y"
3301
3311
  );
3302
- if (!shouldInstall) {
3303
- return false;
3304
- }
3312
+ if (!shouldInstall) return false;
3305
3313
  try {
3306
3314
  const appName = await api.getGitHubAppName();
3307
- const installUrl = reason === "not_connected" ? `https://github.com/apps/${appName}/installations/new` : `https://github.com/settings/installations`;
3308
- console.log(
3309
- source_default.cyan(
3310
- `
3311
- Opening browser to ${reason === "not_connected" ? "install" : "configure"} GitHub App...`
3312
- )
3313
- );
3315
+ const installUrl = `https://github.com/apps/${appName}/installations/new`;
3316
+ console.log(source_default.cyan(`
3317
+ Opening browser...`));
3314
3318
  console.log(source_default.gray(`URL: ${installUrl}
3315
3319
  `));
3316
3320
  if (reason === "no_access") {
3317
- console.log(source_default.white("Please:"));
3318
3321
  console.log(
3319
- source_default.cyan(" 1. Find the 'mcp-use' (or similar) GitHub App")
3322
+ 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")
3320
3323
  );
3321
- console.log(source_default.cyan(" 2. Click 'Configure'"));
3324
+ } else {
3322
3325
  console.log(
3323
- source_default.cyan(
3324
- ` 3. Grant access to ${source_default.bold(repoName || "your repository")}`
3325
- )
3326
+ source_default.white("Complete the GitHub App installation, then return here.\n")
3326
3327
  );
3327
- console.log(source_default.cyan(" 4. Save your changes"));
3328
- console.log(source_default.cyan(" 5. Return here when done\n"));
3329
- } else {
3330
- console.log(source_default.white("Please:"));
3331
- console.log(source_default.cyan(" 1. Select the repositories to grant access"));
3332
- if (repoName) {
3333
- console.log(
3334
- source_default.cyan(` 2. Make sure to include ${source_default.bold(repoName)}`)
3335
- );
3336
- console.log(source_default.cyan(" 3. Complete the installation"));
3337
- } else {
3338
- console.log(source_default.cyan(" 2. Complete the installation"));
3339
- }
3340
- console.log();
3341
3328
  }
3342
3329
  await open_default(installUrl);
3343
- await waitForGitHubSetupAfterBrowser(api, repoName, yes);
3344
- console.log(source_default.gray("Verifying GitHub connection..."));
3345
- let verified = false;
3346
- try {
3347
- const status = await api.getGitHubConnectionStatus();
3348
- if (!status.is_connected) {
3349
- console.log(source_default.yellow("\u26A0\uFE0F GitHub connection not detected."));
3350
- } else if (repoName) {
3351
- const [owner, repo] = repoName.split("/");
3352
- console.log(source_default.gray(`Checking access to ${repoName}...`));
3353
- const hasAccess = await checkRepoAccess(api, owner, repo);
3354
- if (!hasAccess) {
3355
- console.log(
3356
- source_default.yellow(
3357
- `\u26A0\uFE0F The GitHub App may not have access to ${source_default.cyan(repoName)} yet`
3358
- )
3359
- );
3360
- } else {
3361
- console.log(source_default.green(`\u2713 Repository ${repoName} is accessible!
3362
- `));
3363
- verified = true;
3330
+ if (!yes) {
3331
+ await prompt(source_default.white("Press Enter when done..."), "y");
3332
+ } else {
3333
+ console.log(source_default.gray("Waiting for GitHub configuration (polling)..."));
3334
+ const deadline = Date.now() + 12e4;
3335
+ while (Date.now() < deadline) {
3336
+ await new Promise((r) => setTimeout(r, 2e3));
3337
+ try {
3338
+ const status = await api.getGitHubConnectionStatus();
3339
+ if (status.is_connected) {
3340
+ if (!repoName) return true;
3341
+ const [o, r] = repoName.split("/");
3342
+ if (o && r && await checkRepoAccess(api, o, r)) return true;
3343
+ }
3344
+ } catch {
3364
3345
  }
3365
- } else {
3366
- console.log(source_default.green("\u2713 GitHub connected successfully!\n"));
3367
- verified = true;
3368
3346
  }
3369
- } catch (error) {
3370
- console.log(
3371
- source_default.yellow("\u26A0\uFE0F Could not verify GitHub connection (API issue)")
3372
- );
3373
- }
3374
- if (!verified) {
3375
- console.log(
3376
- source_default.gray(
3377
- "\nNote: If you completed the GitHub setup, the deployment may work now.\n"
3378
- )
3379
- );
3380
3347
  }
3381
3348
  return true;
3382
- } catch (error) {
3383
- console.log(
3384
- source_default.yellow("\n\u26A0\uFE0F Unable to open GitHub installation automatically")
3385
- );
3349
+ } catch {
3350
+ console.log(source_default.yellow("\n\u26A0\uFE0F Unable to open browser automatically"));
3386
3351
  console.log(
3387
3352
  source_default.white("Please visit: ") + source_default.cyan("https://manufact.com/cloud/settings")
3388
3353
  );
3389
- console.log(
3390
- source_default.gray("Then connect your GitHub account and try again.\n")
3391
- );
3392
3354
  return false;
3393
3355
  }
3394
3356
  }
@@ -3396,47 +3358,139 @@ async function deployCommand(options) {
3396
3358
  try {
3397
3359
  const cwd = process.cwd();
3398
3360
  if (!await isLoggedIn()) {
3399
- console.log(source_default.red("\u2717 You are not logged in."));
3361
+ console.log(source_default.cyan.bold("Welcome to Manufact Cloud!\n"));
3400
3362
  if (options.yes) {
3401
3363
  console.log(
3402
- source_default.gray(
3403
- "Run " + source_default.white("npx mcp-use login") + " first. Non-interactive deploy requires an existing session."
3364
+ source_default.red(
3365
+ "\u2717 Not logged in. Run " + source_default.white("npx mcp-use login") + " first."
3404
3366
  )
3405
3367
  );
3406
3368
  process.exit(1);
3407
3369
  }
3408
3370
  const shouldLogin = await prompt(
3409
- source_default.white("Would you like to login now? (Y/n): "),
3371
+ source_default.white("You need to log in to deploy. Log in now? (Y/n): "),
3410
3372
  "y"
3411
3373
  );
3412
- if (shouldLogin) {
3413
- try {
3414
- await loginCommand({ silent: false });
3415
- if (!await isLoggedIn()) {
3416
- console.log(
3417
- source_default.red("\u2717 Login verification failed. Please try again.")
3418
- );
3419
- process.exit(1);
3420
- }
3421
- console.log(source_default.gray("\nContinuing with deployment...\n"));
3422
- } catch (error) {
3423
- console.error(
3424
- source_default.red.bold("\u2717 Login failed:"),
3425
- source_default.red(error instanceof Error ? error.message : "Unknown error")
3426
- );
3427
- process.exit(1);
3428
- }
3429
- } else {
3374
+ if (!shouldLogin) {
3430
3375
  console.log(
3431
3376
  source_default.gray(
3432
3377
  "Run " + source_default.white("npx mcp-use login") + " to get started."
3433
3378
  )
3434
3379
  );
3380
+ process.exit(0);
3381
+ }
3382
+ try {
3383
+ await loginCommand({ silent: false });
3384
+ if (!await isLoggedIn()) {
3385
+ console.log(source_default.red("\u2717 Login failed. Please try again."));
3386
+ process.exit(1);
3387
+ }
3388
+ console.log(source_default.gray("\nContinuing with deployment...\n"));
3389
+ } catch (error) {
3390
+ console.error(
3391
+ source_default.red.bold("\u2717 Login failed:"),
3392
+ source_default.red(error instanceof Error ? error.message : "Unknown error")
3393
+ );
3394
+ process.exit(1);
3395
+ }
3396
+ }
3397
+ const api = await McpUseAPI.create();
3398
+ if (options.org) {
3399
+ const authInfo = await api.testAuth();
3400
+ const match = (authInfo.orgs ?? []).find(
3401
+ (o) => o.slug === options.org || o.id === options.org || o.name.toLowerCase() === options.org.toLowerCase()
3402
+ );
3403
+ if (match) {
3404
+ api.setOrgId(match.id);
3405
+ const slug = match.slug ? source_default.gray(` (${match.slug})`) : "";
3406
+ console.log(
3407
+ source_default.gray("Organization: ") + source_default.cyan(match.name) + slug
3408
+ );
3409
+ } else {
3410
+ console.error(
3411
+ source_default.red(
3412
+ `\u2717 Organization "${options.org}" not found. Run ${source_default.white("npx mcp-use org list")} to see available organizations.`
3413
+ )
3414
+ );
3415
+ process.exit(1);
3416
+ }
3417
+ } else {
3418
+ const config = await readConfig();
3419
+ if (!config.orgId) {
3420
+ const authInfo = await api.testAuth();
3421
+ if (authInfo.orgs.length === 0) {
3422
+ console.log(
3423
+ source_default.red(
3424
+ "\u2717 No organizations found. Please create one at manufact.com/cloud."
3425
+ )
3426
+ );
3427
+ process.exit(1);
3428
+ }
3429
+ let selectedOrg;
3430
+ if (authInfo.orgs.length === 1) {
3431
+ selectedOrg = authInfo.orgs[0];
3432
+ } else {
3433
+ selectedOrg = await promptOrgSelection(
3434
+ authInfo.orgs,
3435
+ authInfo.default_org_id
3436
+ );
3437
+ }
3438
+ if (!selectedOrg) {
3439
+ console.log(source_default.red("\u2717 No organization selected."));
3440
+ process.exit(1);
3441
+ }
3442
+ api.setOrgId(selectedOrg.id);
3443
+ await writeConfig({
3444
+ ...config,
3445
+ orgId: selectedOrg.id,
3446
+ orgName: selectedOrg.name,
3447
+ orgSlug: selectedOrg.slug ?? void 0
3448
+ });
3449
+ console.log(
3450
+ source_default.gray("Organization: ") + source_default.cyan(selectedOrg.name)
3451
+ );
3452
+ } else {
3453
+ if (config.orgName) {
3454
+ const slug = config.orgSlug ? source_default.gray(` (${config.orgSlug})`) : "";
3455
+ console.log(
3456
+ source_default.gray("Organization: ") + source_default.cyan(config.orgName) + slug
3457
+ );
3458
+ }
3459
+ }
3460
+ }
3461
+ console.log(source_default.cyan.bold("\n\u{1F680} Deploying to Manufact cloud...\n"));
3462
+ let connectionStatus = await api.getGitHubConnectionStatus().catch(() => null);
3463
+ if (!connectionStatus?.is_connected) {
3464
+ const installed = await promptGitHubInstallation(
3465
+ api,
3466
+ "not_connected",
3467
+ void 0,
3468
+ { yes: options.yes }
3469
+ );
3470
+ if (!installed) {
3435
3471
  console.log(source_default.gray("Deployment cancelled."));
3436
3472
  process.exit(0);
3437
3473
  }
3474
+ connectionStatus = await api.getGitHubConnectionStatus().catch(() => null);
3475
+ if (!connectionStatus?.is_connected) {
3476
+ console.log(source_default.red("\n\u2717 GitHub connection could not be verified."));
3477
+ console.log(
3478
+ source_default.cyan(
3479
+ " Visit https://manufact.com/cloud/settings to connect GitHub.\n"
3480
+ )
3481
+ );
3482
+ process.exit(1);
3483
+ }
3484
+ }
3485
+ const installations = connectionStatus.installations ?? [];
3486
+ if (installations.length === 0) {
3487
+ console.log(source_default.red("\u2717 No GitHub installations found."));
3488
+ process.exit(1);
3438
3489
  }
3439
- console.log(source_default.cyan.bold("\u{1F680} Deploying to Manufact cloud...\n"));
3490
+ const defaultInstallation = installations.find((i) => i.account_type === "Organization") ?? installations[0];
3491
+ const installationDbId = defaultInstallation.id;
3492
+ const githubInstallationId = defaultInstallation.installation_id;
3493
+ console.log(source_default.green("\u2713 GitHub connected\n"));
3440
3494
  const projectDir = options.rootDir ? import_node_path5.default.resolve(cwd, options.rootDir) : cwd;
3441
3495
  if (options.rootDir) {
3442
3496
  try {
@@ -3447,292 +3501,274 @@ async function deployCommand(options) {
3447
3501
  );
3448
3502
  process.exit(1);
3449
3503
  }
3450
- console.log(source_default.gray(` Root dir: `) + source_default.cyan(options.rootDir));
3451
3504
  }
3452
3505
  const isMcp = await isMcpProject(projectDir);
3453
- if (!isMcp) {
3506
+ if (!isMcp && !options.yes) {
3454
3507
  console.log(
3455
- source_default.yellow(
3456
- "\u26A0\uFE0F This doesn't appear to be an MCP server project (no mcp-use or @modelcontextprotocol/sdk dependency found)."
3457
- )
3508
+ source_default.yellow("\u26A0\uFE0F This doesn't look like an MCP server project.")
3458
3509
  );
3459
- if (!options.yes) {
3460
- const shouldContinue = await prompt(
3461
- source_default.white("Continue anyway? (y/n): ")
3462
- );
3463
- if (!shouldContinue) {
3464
- console.log(source_default.gray("Deployment cancelled."));
3465
- process.exit(0);
3466
- }
3510
+ const shouldContinue = await prompt(
3511
+ source_default.white("Continue anyway? (y/n): ")
3512
+ );
3513
+ if (!shouldContinue) {
3514
+ process.exit(0);
3467
3515
  }
3468
3516
  console.log();
3469
3517
  }
3470
- const gitInfo = await getGitInfo(cwd);
3471
- if (!gitInfo.isGitRepo) {
3472
- console.log(source_default.red("\u2717 Not a git repository\n"));
3473
- console.log(source_default.white("To deploy, initialize git and push to GitHub:"));
3474
- console.log(source_default.gray(" 1. Initialize git:"));
3475
- console.log(source_default.cyan(" git init\n"));
3476
- console.log(source_default.gray(" 2. Create a GitHub repository at:"));
3477
- console.log(source_default.cyan(" https://github.com/new\n"));
3478
- console.log(source_default.gray(" 3. Add the remote and push:"));
3479
- console.log(source_default.cyan(" git remote add origin <your-github-url>"));
3480
- console.log(source_default.cyan(" git add ."));
3481
- console.log(source_default.cyan(" git commit -m 'Initial commit'"));
3482
- console.log(source_default.cyan(" git push -u origin main\n"));
3483
- process.exit(1);
3484
- }
3485
- if (!gitInfo.remoteUrl) {
3486
- console.log(source_default.red("\u2717 No git remote configured\n"));
3487
- console.log(source_default.white("Add a GitHub remote:"));
3488
- console.log(source_default.cyan(" git remote add origin <your-github-url>\n"));
3489
- process.exit(1);
3490
- }
3491
- if (!isGitHubUrl(gitInfo.remoteUrl)) {
3492
- console.log(source_default.red("\u2717 Remote is not a GitHub repository"));
3493
- console.log(source_default.yellow(` Current remote: ${gitInfo.remoteUrl}
3494
- `));
3495
- console.log(source_default.white("Please add a GitHub remote to deploy."));
3496
- process.exit(1);
3497
- }
3498
- if (!gitInfo.owner || !gitInfo.repo) {
3499
- console.log(source_default.red("\u2717 Could not parse GitHub repository information"));
3500
- process.exit(1);
3501
- }
3502
- if (gitInfo.hasUncommittedChanges) {
3503
- console.log(source_default.yellow("\u26A0\uFE0F You have uncommitted changes\n"));
3504
- console.log(source_default.white("Deployments use the code pushed to GitHub."));
3505
- console.log(
3506
- source_default.white(
3507
- "Local changes will not be included until you commit and push.\n"
3508
- )
3509
- );
3510
- if (!options.yes) {
3511
- const shouldContinue = await prompt(
3512
- source_default.white("Continue with deployment from GitHub? (y/n): ")
3518
+ let gitInfo = await getGitInfo(cwd);
3519
+ let repoFullName;
3520
+ let branch = "main";
3521
+ if (!gitInfo.isGitRepo || !gitInfo.remoteUrl) {
3522
+ const projectName2 = options.name || await getProjectName(projectDir);
3523
+ console.log(source_default.yellow("\u26A0\uFE0F No GitHub remote found.\n"));
3524
+ if (options.yes) {
3525
+ console.log(source_default.gray("Creating GitHub repository automatically..."));
3526
+ } else {
3527
+ const shouldCreate = await prompt(
3528
+ source_default.white("Create a GitHub repository and push your code? (Y/n): "),
3529
+ "y"
3513
3530
  );
3514
- if (!shouldContinue) {
3515
- console.log(source_default.gray("Deployment cancelled."));
3531
+ if (!shouldCreate) {
3532
+ console.log(
3533
+ source_default.gray(
3534
+ "Deployment cancelled. Set up a GitHub remote and try again."
3535
+ )
3536
+ );
3516
3537
  process.exit(0);
3517
3538
  }
3518
3539
  }
3519
- console.log();
3520
- }
3521
- console.log(source_default.white("GitHub repository detected:"));
3522
- console.log(
3523
- source_default.gray(` Repository: `) + source_default.cyan(`${gitInfo.owner}/${gitInfo.repo}`)
3524
- );
3525
- console.log(
3526
- source_default.gray(` Branch: `) + source_default.cyan(gitInfo.branch || "main")
3527
- );
3528
- if (gitInfo.commitSha) {
3529
- console.log(
3530
- source_default.gray(` Commit: `) + source_default.gray(gitInfo.commitSha.substring(0, 7))
3531
- );
3532
- }
3533
- if (gitInfo.commitMessage) {
3534
- console.log(
3535
- source_default.gray(` Message: `) + source_default.gray(gitInfo.commitMessage.split("\n")[0])
3540
+ const defaultIdx = installations.findIndex(
3541
+ (i) => i.account_type === "Organization"
3536
3542
  );
3537
- }
3538
- console.log();
3539
- if (!options.yes) {
3540
- const shouldDeploy = await prompt(
3541
- source_default.white(
3542
- `Deploy from GitHub repository ${gitInfo.owner}/${gitInfo.repo}? (Y/n): `
3543
- ),
3544
- "y"
3545
- );
3546
- if (!shouldDeploy) {
3547
- console.log(source_default.gray("Deployment cancelled."));
3543
+ let selectedIdx = defaultIdx >= 0 ? defaultIdx : 0;
3544
+ if (installations.length > 1 && !options.yes) {
3545
+ console.log(
3546
+ source_default.cyan.bold("\u{1F419} Select a GitHub account for the repository:\n")
3547
+ );
3548
+ for (let i = 0; i < installations.length; i++) {
3549
+ const inst = installations[i];
3550
+ const typeLabel = inst.account_type === "Organization" ? source_default.gray(" (org)") : source_default.gray(" (personal)");
3551
+ const marker = i === selectedIdx ? source_default.green(" \u2190 default") : "";
3552
+ console.log(
3553
+ ` ${source_default.white(`${i + 1}.`)} ${inst.account_login}${typeLabel}${marker}`
3554
+ );
3555
+ }
3556
+ console.log();
3557
+ const readline = await import("readline");
3558
+ const rl = readline.createInterface({
3559
+ input: process.stdin,
3560
+ output: process.stdout
3561
+ });
3562
+ const answer = await new Promise((resolve2) => {
3563
+ rl.question(
3564
+ source_default.gray(`Enter number [${selectedIdx + 1}]: `),
3565
+ (a) => {
3566
+ rl.close();
3567
+ resolve2(a.trim());
3568
+ }
3569
+ );
3570
+ });
3571
+ const parsed = answer === "" ? selectedIdx : parseInt(answer, 10) - 1;
3572
+ if (parsed >= 0 && parsed < installations.length) {
3573
+ selectedIdx = parsed;
3574
+ }
3575
+ }
3576
+ const repoInstallation = installations[selectedIdx];
3577
+ if (repoInstallation.account_type !== "Organization") {
3578
+ console.log(
3579
+ source_default.yellow(
3580
+ "\n\u26A0\uFE0F GitHub Apps cannot create repos on personal accounts.\n"
3581
+ )
3582
+ );
3583
+ console.log(
3584
+ source_default.white("To deploy from ") + source_default.cyan(repoInstallation.account_login) + source_default.white(", create a repository manually:\n")
3585
+ );
3586
+ console.log(
3587
+ source_default.cyan(" 1. ") + source_default.white("Go to ") + source_default.cyan("https://github.com/new")
3588
+ );
3589
+ console.log(
3590
+ source_default.cyan(" 2. ") + source_default.white("Create a repository (any name, can be private)")
3591
+ );
3592
+ console.log(source_default.cyan(" 3. ") + source_default.white("Add it as a remote:"));
3593
+ console.log(source_default.gray(" git init && git remote add origin <url>"));
3594
+ console.log(source_default.cyan(" 4. ") + source_default.white("Push your code:"));
3595
+ console.log(
3596
+ source_default.gray(
3597
+ " git add . && git commit -m 'Initial commit' && git push -u origin main"
3598
+ )
3599
+ );
3600
+ console.log(
3601
+ source_default.cyan(" 5. ") + source_default.white("Grant the GitHub App access to the repo:")
3602
+ );
3603
+ const appName = await api.getGitHubAppName();
3604
+ console.log(
3605
+ source_default.gray(
3606
+ ` https://github.com/apps/${appName}/installations/new`
3607
+ )
3608
+ );
3609
+ console.log(
3610
+ source_default.cyan(" 6. ") + source_default.white("Run ") + source_default.cyan("mcp-use deploy") + source_default.white(" again\n")
3611
+ );
3548
3612
  process.exit(0);
3549
3613
  }
3550
- }
3551
- const projectName = options.name || await getProjectName(projectDir);
3552
- const runtime = options.runtime || await detectRuntime(projectDir);
3553
- const port = options.port || 3e3;
3554
- const buildCommand = await detectBuildCommand(projectDir);
3555
- const startCommand = await detectStartCommand(projectDir);
3556
- const envVars = await buildEnvVars(options);
3557
- console.log();
3558
- console.log(source_default.white("Deployment configuration:"));
3559
- console.log(source_default.gray(` Name: `) + source_default.cyan(projectName));
3560
- console.log(source_default.gray(` Runtime: `) + source_default.cyan(runtime));
3561
- console.log(source_default.gray(` Port: `) + source_default.cyan(port));
3562
- if (options.rootDir) {
3614
+ const repoName = options.yes ? projectName2 : await promptText(source_default.gray("Repository name:"), projectName2);
3615
+ await ensureGitignore(cwd);
3563
3616
  console.log(
3564
- source_default.gray(` Root dir: `) + source_default.cyan(options.rootDir)
3565
- );
3566
- }
3567
- if (buildCommand) {
3568
- console.log(source_default.gray(` Build command: `) + source_default.cyan(buildCommand));
3569
- }
3570
- if (startCommand) {
3571
- console.log(source_default.gray(` Start command: `) + source_default.cyan(startCommand));
3572
- }
3573
- if (envVars && Object.keys(envVars).length > 0) {
3574
- console.log(
3575
- source_default.gray(` Environment: `) + source_default.cyan(`${Object.keys(envVars).length} variable(s)`)
3576
- );
3577
- console.log(
3578
- source_default.gray(` `) + source_default.gray(Object.keys(envVars).join(", "))
3617
+ source_default.gray(
3618
+ `Creating repository on ${repoInstallation.account_login}...`
3619
+ )
3579
3620
  );
3580
- }
3581
- console.log();
3582
- const api = await McpUseAPI.create();
3583
- if (options.org) {
3584
- try {
3585
- const authInfo = await api.testAuth();
3586
- const match = (authInfo.orgs ?? []).find(
3587
- (o) => o.slug === options.org || o.id === options.org || o.name.toLowerCase() === options.org.toLowerCase()
3621
+ const repoResult = await api.createGitHubRepo({
3622
+ installationId: repoInstallation.installation_id,
3623
+ name: repoName,
3624
+ private: true,
3625
+ org: repoInstallation.account_login
3626
+ });
3627
+ console.log(source_default.green(`\u2713 Created ${source_default.cyan(repoResult.fullName)}`));
3628
+ if (!gitInfo.isGitRepo) {
3629
+ console.log(source_default.gray("Initializing git..."));
3630
+ await gitInit(cwd, "Initial commit");
3631
+ console.log(source_default.gray("Pushing to GitHub..."));
3632
+ await gitAddRemoteAndPush(cwd, repoResult.cloneUrl, "main");
3633
+ } else {
3634
+ console.log(source_default.gray("Adding remote and pushing..."));
3635
+ await gitAddRemoteAndPush(
3636
+ cwd,
3637
+ repoResult.cloneUrl,
3638
+ gitInfo.branch || "main"
3588
3639
  );
3589
- if (match) {
3590
- api.setOrgId(match.id);
3591
- const slug = match.slug ? source_default.gray(` (${match.slug})`) : "";
3592
- console.log(
3593
- source_default.gray("Organization: ") + source_default.cyan(match.name) + slug
3594
- );
3595
- } else {
3596
- console.error(
3597
- source_default.red(
3598
- `\u2717 Organization "${options.org}" not found. Run ${source_default.white("npx mcp-use org list")} to see available organizations.`
3599
- )
3640
+ }
3641
+ console.log(source_default.green("\u2713 Code pushed to GitHub\n"));
3642
+ gitInfo = await getGitInfo(cwd);
3643
+ repoFullName = repoResult.fullName;
3644
+ branch = gitInfo.branch || "main";
3645
+ } else if (!isGitHubUrl(gitInfo.remoteUrl)) {
3646
+ console.log(source_default.red("\u2717 Remote is not a GitHub repository"));
3647
+ console.log(source_default.yellow(` Current remote: ${gitInfo.remoteUrl}
3648
+ `));
3649
+ process.exit(1);
3650
+ } else if (!gitInfo.owner || !gitInfo.repo) {
3651
+ console.log(source_default.red("\u2717 Could not parse GitHub repository information"));
3652
+ process.exit(1);
3653
+ } else {
3654
+ repoFullName = `${gitInfo.owner}/${gitInfo.repo}`;
3655
+ branch = gitInfo.branch || "main";
3656
+ if (gitInfo.hasUncommittedChanges) {
3657
+ console.log(source_default.yellow("\u26A0\uFE0F You have uncommitted changes.\n"));
3658
+ if (!options.yes) {
3659
+ const shouldCommit = await prompt(
3660
+ source_default.white("Commit and push changes before deploying? (Y/n): "),
3661
+ "y"
3600
3662
  );
3601
- process.exit(1);
3663
+ if (shouldCommit) {
3664
+ await ensureGitignore(cwd);
3665
+ console.log(source_default.gray("Committing and pushing..."));
3666
+ await gitCommitAndPush(cwd, "Deploy changes", branch);
3667
+ gitInfo = await getGitInfo(cwd);
3668
+ console.log(source_default.green("\u2713 Changes pushed\n"));
3669
+ } else {
3670
+ console.log(source_default.gray("Deploying from last pushed commit.\n"));
3671
+ }
3602
3672
  }
3603
- } catch (error) {
3604
- console.error(
3605
- source_default.red("\u2717 Failed to resolve organization:"),
3606
- source_default.red(error instanceof Error ? error.message : "Unknown error")
3607
- );
3608
- process.exit(1);
3609
3673
  }
3610
- }
3611
- let githubVerified = false;
3612
- let installationDbId;
3613
- try {
3614
- console.log(source_default.gray(`[DEBUG] API URL: ${api.baseUrl}`));
3615
- const connectionStatus = await api.getGitHubConnectionStatus();
3616
- if (!connectionStatus.is_connected) {
3617
- const repoFullName = `${gitInfo.owner}/${gitInfo.repo}`;
3618
- const installed = await promptGitHubInstallation(
3674
+ console.log(source_default.gray("Checking repository access..."));
3675
+ const hasAccess = await checkRepoAccess(
3676
+ api,
3677
+ gitInfo.owner,
3678
+ gitInfo.repo
3679
+ );
3680
+ if (!hasAccess) {
3681
+ console.log(
3682
+ source_default.yellow(
3683
+ `\u26A0\uFE0F GitHub App doesn't have access to ${source_default.cyan(repoFullName)}`
3684
+ )
3685
+ );
3686
+ const configured = await promptGitHubInstallation(
3619
3687
  api,
3620
- "not_connected",
3688
+ "no_access",
3621
3689
  repoFullName,
3622
- { yes: options.yes }
3690
+ { yes: options.yes, installationId: githubInstallationId }
3623
3691
  );
3624
- if (!installed) {
3625
- console.log(source_default.gray("Deployment cancelled."));
3692
+ if (!configured) {
3626
3693
  process.exit(0);
3627
3694
  }
3628
- const retryStatus = await api.getGitHubConnectionStatus();
3629
- if (!retryStatus.is_connected) {
3630
- console.log(
3631
- source_default.red("\n\u2717 GitHub connection could not be verified.")
3632
- );
3695
+ const retry = await checkRepoAccess(api, gitInfo.owner, gitInfo.repo);
3696
+ if (!retry) {
3697
+ const appName = await api.getGitHubAppName();
3633
3698
  console.log(
3634
- source_default.gray("Please try connecting GitHub from the web UI:")
3635
- );
3636
- console.log(source_default.cyan(" https://manufact.com/cloud/settings\n"));
3637
- process.exit(1);
3638
- }
3639
- installationDbId = retryStatus.installations?.[0]?.id;
3640
- githubVerified = true;
3641
- } else if (gitInfo.owner && gitInfo.repo) {
3642
- installationDbId = connectionStatus.installations?.[0]?.id;
3643
- console.log(source_default.gray("Checking repository access..."));
3644
- const hasAccess = await checkRepoAccess(
3645
- api,
3646
- gitInfo.owner,
3647
- gitInfo.repo
3648
- );
3649
- if (!hasAccess) {
3650
- const repoFullName = `${gitInfo.owner}/${gitInfo.repo}`;
3651
- console.log(
3652
- source_default.yellow(
3653
- `\u26A0\uFE0F GitHub App doesn't have access to ${source_default.cyan(repoFullName)}`
3699
+ source_default.red(
3700
+ `
3701
+ \u2717 Repository ${source_default.cyan(repoFullName)} is still not accessible.`
3654
3702
  )
3655
3703
  );
3656
- const configured = await promptGitHubInstallation(
3657
- api,
3658
- "no_access",
3659
- repoFullName,
3660
- { yes: options.yes }
3661
- );
3662
- if (!configured) {
3663
- console.log(source_default.gray("Deployment cancelled."));
3664
- process.exit(0);
3665
- }
3666
- const hasAccessRetry = await checkRepoAccess(
3667
- api,
3668
- gitInfo.owner,
3669
- gitInfo.repo
3670
- );
3671
- if (!hasAccessRetry) {
3672
- console.log(
3673
- source_default.red(
3674
- `
3675
- \u2717 Repository ${source_default.cyan(repoFullName)} is still not accessible.`
3676
- )
3677
- );
3678
- console.log(
3679
- source_default.gray(
3680
- "Please make sure the GitHub App has access to this repository."
3681
- )
3682
- );
3683
- console.log(
3684
- source_default.cyan(" https://github.com/settings/installations\n")
3685
- );
3686
- process.exit(1);
3687
- }
3688
- githubVerified = true;
3689
- } else {
3690
- console.log(source_default.green("\u2713 Repository access confirmed"));
3691
- githubVerified = true;
3704
+ console.log(
3705
+ source_default.cyan(
3706
+ ` https://github.com/apps/${appName}/installations/new
3707
+ `
3708
+ )
3709
+ );
3710
+ process.exit(1);
3692
3711
  }
3693
3712
  }
3694
- } catch (error) {
3695
- console.log(source_default.red("\u2717 Could not verify GitHub connection"));
3713
+ console.log(source_default.green("\u2713 Repository access confirmed"));
3714
+ }
3715
+ const projectName = options.name || await getProjectName(projectDir);
3716
+ const port = options.port || 3e3;
3717
+ const buildCommand = await detectBuildCommand(projectDir);
3718
+ const startCommand = await detectStartCommand(projectDir);
3719
+ const runtime = options.runtime || await detectRuntime(projectDir);
3720
+ const envVars = await buildEnvVars(options);
3721
+ console.log();
3722
+ console.log(source_default.white("Deployment configuration:"));
3723
+ console.log(source_default.gray(` Repository: `) + source_default.cyan(repoFullName));
3724
+ console.log(source_default.gray(` Branch: `) + source_default.cyan(branch));
3725
+ console.log(source_default.gray(` Name: `) + source_default.cyan(projectName));
3726
+ console.log(source_default.gray(` Runtime: `) + source_default.cyan(runtime));
3727
+ console.log(source_default.gray(` Port: `) + source_default.cyan(port));
3728
+ if (options.region)
3729
+ console.log(source_default.gray(` Region: `) + source_default.cyan(options.region));
3730
+ if (options.buildCommand)
3696
3731
  console.log(
3697
- source_default.gray(
3698
- "Error: " + (error instanceof Error ? error.message : "Unknown error")
3699
- )
3732
+ source_default.gray(` Build command: `) + source_default.cyan(options.buildCommand)
3700
3733
  );
3701
- console.log(source_default.gray("\nPlease ensure:"));
3734
+ else if (buildCommand)
3702
3735
  console.log(
3703
- source_default.cyan(
3704
- " 1. You have connected GitHub at https://manufact.com/cloud/settings"
3705
- )
3736
+ source_default.gray(` Build command: `) + source_default.gray(buildCommand + " (auto-detected)")
3706
3737
  );
3738
+ if (options.startCommand)
3707
3739
  console.log(
3708
- source_default.cyan(" 2. The GitHub App has access to your repository")
3740
+ source_default.gray(` Start command: `) + source_default.cyan(options.startCommand)
3709
3741
  );
3710
- console.log(source_default.cyan(" 3. Your internet connection is stable\n"));
3711
- process.exit(1);
3712
- }
3713
- if (!githubVerified) {
3742
+ else if (startCommand)
3714
3743
  console.log(
3715
- source_default.red("\n\u2717 GitHub verification required for this deployment")
3744
+ source_default.gray(` Start command: `) + source_default.gray(startCommand + " (auto-detected)")
3716
3745
  );
3717
- process.exit(1);
3746
+ if (Object.keys(envVars).length > 0) {
3747
+ console.log(
3748
+ source_default.gray(` Environment: `) + source_default.cyan(`${Object.keys(envVars).length} variable(s)`)
3749
+ );
3750
+ }
3751
+ console.log();
3752
+ if (!options.yes) {
3753
+ const shouldDeploy = await prompt(source_default.white(`Deploy? (Y/n): `), "y");
3754
+ if (!shouldDeploy) {
3755
+ console.log(source_default.gray("Deployment cancelled."));
3756
+ process.exit(0);
3757
+ }
3718
3758
  }
3719
3759
  const existingLink = !options.new ? await getProjectLink(cwd) : null;
3720
- const serverId = existingLink?.serverId;
3760
+ let serverId = existingLink?.serverId;
3721
3761
  if (existingLink && serverId) {
3722
3762
  try {
3723
- const existingDeployment = await api.getDeployment(
3724
- existingLink.deploymentId
3725
- );
3726
- if (existingDeployment && existingDeployment.status !== "failed") {
3727
- console.log(source_default.green(`\u2713 Found linked deployment`));
3763
+ const existingDep = await api.getDeployment(existingLink.deploymentId);
3764
+ if (existingDep && existingDep.status !== "failed") {
3765
+ console.log(source_default.green(`\u2713 Found linked server`));
3728
3766
  console.log(source_default.gray(` Redeploying to maintain the same URL...`));
3729
- console.log(
3730
- source_default.cyan(` URL: ${getMcpServerUrl(existingDeployment)}
3731
- `)
3732
- );
3767
+ console.log(source_default.cyan(` URL: ${getMcpServerUrl(existingDep)}
3768
+ `));
3733
3769
  const newDep = await api.createDeployment({
3734
3770
  serverId,
3735
- branch: gitInfo.branch || "main",
3771
+ branch,
3736
3772
  trigger: "redeploy"
3737
3773
  });
3738
3774
  await saveProjectLink(cwd, {
@@ -3740,89 +3776,79 @@ async function deployCommand(options) {
3740
3776
  linkedAt: (/* @__PURE__ */ new Date()).toISOString(),
3741
3777
  deploymentId: newDep.id
3742
3778
  });
3743
- await displayDeploymentProgress(api, newDep.id, {
3744
- yes: options.yes
3745
- });
3746
- return;
3747
- } else {
3748
3779
  console.log(
3749
- source_default.yellow(
3750
- `\u26A0\uFE0F Linked deployment not found or failed, creating new one...`
3751
- )
3780
+ source_default.green("\u2713 Deployment created: ") + source_default.gray(newDep.id)
3752
3781
  );
3753
- console.log(source_default.gray(` Will reuse existing server: ${serverId}`));
3782
+ await displayDeploymentProgress(api, newDep.id, { yes: options.yes });
3783
+ return;
3754
3784
  }
3755
- } catch (error) {
3756
- console.log(
3757
- source_default.yellow(`\u26A0\uFE0F Linked deployment not found, creating new one...`)
3758
- );
3759
- console.log(source_default.gray(` Will reuse existing server: ${serverId}`));
3760
- }
3761
- }
3762
- if (!options.org) {
3763
- try {
3764
- const config = await readConfig();
3765
- if (config.orgName) {
3766
- const slug = config.orgSlug ? source_default.gray(` (${config.orgSlug})`) : "";
3785
+ } catch (err) {
3786
+ const is404 = err?.status === 404 || (err?.message ?? "").includes("404");
3787
+ if (is404) {
3767
3788
  console.log(
3768
- source_default.gray("Organization: ") + source_default.cyan(config.orgName) + slug
3789
+ source_default.yellow("\u26A0\uFE0F Previously linked server no longer exists.\n")
3769
3790
  );
3791
+ if (!options.yes) {
3792
+ const shouldRecreate = await prompt(
3793
+ source_default.white("Create a new server and deploy? (Y/n): "),
3794
+ "y"
3795
+ );
3796
+ if (!shouldRecreate) {
3797
+ console.log(source_default.gray("Deployment cancelled."));
3798
+ process.exit(0);
3799
+ }
3800
+ }
3801
+ serverId = void 0;
3770
3802
  }
3771
- } catch {
3772
3803
  }
3773
3804
  }
3774
3805
  let deploymentId;
3775
3806
  if (serverId) {
3776
3807
  console.log(source_default.gray("Creating deployment..."));
3777
- const result = await api.createDeployment({
3778
- serverId,
3779
- branch: gitInfo.branch || "main",
3780
- trigger: "manual"
3781
- });
3782
- deploymentId = result.id;
3783
- } else {
3784
- if (!installationDbId) {
3785
- console.log(source_default.red("\u2717 Could not determine GitHub installation ID."));
3786
- console.log(
3787
- source_default.gray(
3788
- "Please ensure your GitHub App is installed and try again."
3789
- )
3790
- );
3791
- process.exit(1);
3792
- }
3793
- const config = await readConfig();
3794
- const authInfo = await api.testAuth();
3795
- const orgId = config.orgId || authInfo.default_org_id;
3796
- if (!orgId) {
3797
- console.log(
3798
- source_default.red("\u2717 No organization set. Run `mcp-use org switch` first.")
3799
- );
3800
- process.exit(1);
3808
+ try {
3809
+ const result = await api.createDeployment({
3810
+ serverId,
3811
+ branch,
3812
+ trigger: "manual"
3813
+ });
3814
+ deploymentId = result.id;
3815
+ } catch (err) {
3816
+ const is404 = err?.status === 404 || (err?.message ?? "").includes("404");
3817
+ if (is404) {
3818
+ console.log(
3819
+ source_default.yellow(
3820
+ "\u26A0\uFE0F Linked server no longer exists. Creating a new one...\n"
3821
+ )
3822
+ );
3823
+ serverId = void 0;
3824
+ } else {
3825
+ throw err;
3826
+ }
3801
3827
  }
3828
+ }
3829
+ if (!serverId) {
3830
+ const orgId = await api.resolveOrganizationId();
3802
3831
  console.log(source_default.gray("Creating server and deployment..."));
3803
3832
  const serverResult = await api.createServer({
3804
3833
  type: "github",
3805
3834
  organizationId: orgId,
3806
3835
  installationId: installationDbId,
3807
3836
  name: projectName,
3808
- repoFullName: `${gitInfo.owner}/${gitInfo.repo}`,
3809
- branch: gitInfo.branch || "main",
3837
+ repoFullName,
3838
+ branch,
3810
3839
  rootDir: options.rootDir,
3811
3840
  port,
3812
- buildCommand,
3813
- startCommand,
3814
- env: Object.keys(envVars).length > 0 ? envVars : void 0
3841
+ env: Object.keys(envVars).length > 0 ? envVars : void 0,
3842
+ region: options.region,
3843
+ buildCommand: options.buildCommand,
3844
+ startCommand: options.startCommand
3815
3845
  });
3816
3846
  deploymentId = serverResult.deploymentId ?? "";
3817
3847
  if (!deploymentId) {
3818
3848
  console.log(
3819
3849
  source_default.green("\u2713 Server created: ") + source_default.gray(serverResult.server.id)
3820
3850
  );
3821
- console.log(
3822
- source_default.yellow(
3823
- "\u26A0\uFE0F No deployment was triggered. You may need to trigger one manually."
3824
- )
3825
- );
3851
+ console.log(source_default.yellow("\u26A0\uFE0F No deployment was triggered."));
3826
3852
  return;
3827
3853
  }
3828
3854
  await saveProjectLink(cwd, {
@@ -3837,10 +3863,22 @@ async function deployCommand(options) {
3837
3863
  console.log(source_default.gray(` Future deploys will reuse the same URL
3838
3864
  `));
3839
3865
  }
3866
+ if (!deploymentId) {
3867
+ console.log(source_default.red("\u2717 No deployment was created."));
3868
+ process.exit(1);
3869
+ }
3840
3870
  console.log(
3841
3871
  source_default.green("\u2713 Deployment created: ") + source_default.gray(deploymentId)
3842
3872
  );
3843
3873
  await displayDeploymentProgress(api, deploymentId, { yes: options.yes });
3874
+ if (options.open) {
3875
+ const dep = await api.getDeployment(deploymentId);
3876
+ const url = getMcpServerUrl(dep);
3877
+ if (url) {
3878
+ console.log(source_default.gray("\nOpening in browser..."));
3879
+ await open_default(url);
3880
+ }
3881
+ }
3844
3882
  } catch (error) {
3845
3883
  console.error(
3846
3884
  source_default.red.bold("\n\u2717 Deployment failed:"),
@@ -3959,11 +3997,15 @@ async function getDeploymentCommand(deploymentId) {
3959
3997
  console.log(
3960
3998
  source_default.white("Status: ") + statusColor(deployment.status)
3961
3999
  );
3962
- if (deployment.mcpUrl) {
4000
+ if (deployment.serverId) {
3963
4001
  console.log(
3964
- source_default.white("MCP URL: ") + source_default.cyan(deployment.mcpUrl)
4002
+ source_default.white("Server ID: ") + source_default.gray(deployment.serverId)
3965
4003
  );
3966
4004
  }
4005
+ const mcpUrl = getMcpServerUrl(deployment);
4006
+ if (mcpUrl) {
4007
+ console.log(source_default.white("MCP URL: ") + source_default.cyan(mcpUrl));
4008
+ }
3967
4009
  if (deployment.gitBranch) {
3968
4010
  console.log(
3969
4011
  source_default.white("Branch: ") + source_default.gray(deployment.gitBranch)
@@ -4280,6 +4322,295 @@ function createDeploymentsCommand() {
4280
4322
  return deploymentsCommand;
4281
4323
  }
4282
4324
 
4325
+ // src/commands/servers.ts
4326
+ var import_commander3 = require("commander");
4327
+ async function prompt3(question) {
4328
+ const readline = await import("readline");
4329
+ const rl = readline.createInterface({
4330
+ input: process.stdin,
4331
+ output: process.stdout
4332
+ });
4333
+ return new Promise((resolve2) => {
4334
+ rl.question(question, (answer) => {
4335
+ rl.close();
4336
+ const trimmedAnswer = answer.trim().toLowerCase();
4337
+ resolve2(trimmedAnswer === "y" || trimmedAnswer === "yes");
4338
+ });
4339
+ });
4340
+ }
4341
+ function isRecord(v) {
4342
+ return typeof v === "object" && v !== null;
4343
+ }
4344
+ function pickStr(obj, key) {
4345
+ if (!isRecord(obj)) return "-";
4346
+ const v = obj[key];
4347
+ if (typeof v === "string") return v;
4348
+ if (v != null && typeof v !== "object") return String(v);
4349
+ return "-";
4350
+ }
4351
+ async function applyOrgOption(api, org) {
4352
+ if (!org) return;
4353
+ const authInfo = await api.testAuth();
4354
+ const match = (authInfo.orgs ?? []).find(
4355
+ (o) => o.slug === org || o.id === org || o.name.toLowerCase() === org.toLowerCase()
4356
+ );
4357
+ if (!match) {
4358
+ console.error(
4359
+ source_default.red(
4360
+ `\u2717 Organization "${org}" not found. Run ${source_default.white("npx mcp-use org list")} to see available organizations.`
4361
+ )
4362
+ );
4363
+ process.exit(1);
4364
+ }
4365
+ api.setOrgId(match.id);
4366
+ const slug = match.slug ? source_default.gray(` (${match.slug})`) : "";
4367
+ console.log(source_default.gray("Organization: ") + source_default.cyan(match.name) + slug);
4368
+ }
4369
+ function getStatusColor2(status) {
4370
+ const s = status.toLowerCase();
4371
+ if (s.includes("run") || s === "active") return source_default.green;
4372
+ if (s.includes("fail") || s.includes("error")) return source_default.red;
4373
+ if (s.includes("build") || s.includes("pend")) return source_default.yellow;
4374
+ return source_default.gray;
4375
+ }
4376
+ async function listServersCommand(options) {
4377
+ try {
4378
+ if (!await isLoggedIn()) {
4379
+ console.log(source_default.red("\u2717 You are not logged in."));
4380
+ console.log(
4381
+ source_default.gray(
4382
+ "Run " + source_default.white("npx mcp-use login") + " to get started."
4383
+ )
4384
+ );
4385
+ process.exit(1);
4386
+ }
4387
+ const api = await McpUseAPI.create();
4388
+ await applyOrgOption(api, options.org);
4389
+ if (options.org) console.log();
4390
+ const limit = options.limit ? parseInt(options.limit, 10) : void 0;
4391
+ const skip = options.skip ? parseInt(options.skip, 10) : void 0;
4392
+ if (limit !== void 0 && (Number.isNaN(limit) || limit < 1)) {
4393
+ console.log(source_default.red("\u2717 Invalid --limit"));
4394
+ process.exit(1);
4395
+ }
4396
+ if (skip !== void 0 && (Number.isNaN(skip) || skip < 0)) {
4397
+ console.log(source_default.red("\u2717 Invalid --skip"));
4398
+ process.exit(1);
4399
+ }
4400
+ const servers = await api.listServers({
4401
+ limit,
4402
+ skip,
4403
+ sort: options.sort
4404
+ });
4405
+ if (servers.length === 0) {
4406
+ console.log(source_default.yellow("No servers found."));
4407
+ console.log(
4408
+ source_default.gray(
4409
+ "\nCreate one by deploying with " + source_default.white("mcp-use deploy")
4410
+ )
4411
+ );
4412
+ return;
4413
+ }
4414
+ console.log(source_default.cyan.bold(`
4415
+ \u{1F5A5} Servers (${servers.length})
4416
+ `));
4417
+ console.log(
4418
+ source_default.white.bold(
4419
+ `${"ID".padEnd(38)} ${"NAME".padEnd(22)} ${"STATUS".padEnd(14)} ${"REPO".padEnd(32)} ${"MCP URL".padEnd(52)}`
4420
+ )
4421
+ );
4422
+ console.log(source_default.gray("\u2500".repeat(165)));
4423
+ for (const s of servers) {
4424
+ const id = s.id.substring(0, 37).padEnd(38);
4425
+ const name = (s.name || s.slug || "-").substring(0, 21).padEnd(22);
4426
+ const statusColor = getStatusColor2(s.status);
4427
+ const status = statusColor(s.status.substring(0, 13).padEnd(14));
4428
+ const repo = (s.connectedRepository?.repoFullName ?? "-").substring(0, 31).padEnd(32);
4429
+ const mcp = getMcpServerUrlForCloudServer(s).substring(0, 51).padEnd(52);
4430
+ console.log(
4431
+ `${source_default.gray(id)} ${name} ${status} ${source_default.gray(repo)} ${source_default.cyan(mcp)}`
4432
+ );
4433
+ }
4434
+ console.log();
4435
+ } catch (error) {
4436
+ console.error(
4437
+ source_default.red.bold("\n\u2717 Failed to list servers:"),
4438
+ source_default.red(error instanceof Error ? error.message : "Unknown error")
4439
+ );
4440
+ process.exit(1);
4441
+ }
4442
+ }
4443
+ async function getServerCommand(idOrSlug, options) {
4444
+ try {
4445
+ if (!await isLoggedIn()) {
4446
+ console.log(source_default.red("\u2717 You are not logged in."));
4447
+ console.log(
4448
+ source_default.gray(
4449
+ "Run " + source_default.white("npx mcp-use login") + " to get started."
4450
+ )
4451
+ );
4452
+ process.exit(1);
4453
+ }
4454
+ const api = await McpUseAPI.create();
4455
+ await applyOrgOption(api, options.org);
4456
+ if (options.org) console.log();
4457
+ const server = await api.getServer(idOrSlug);
4458
+ console.log(source_default.cyan.bold("\n\u{1F5A5} Server Details\n"));
4459
+ console.log(source_default.white("ID: ") + source_default.gray(server.id));
4460
+ if (server.slug) {
4461
+ console.log(source_default.white("Slug: ") + source_default.cyan(server.slug));
4462
+ }
4463
+ console.log(
4464
+ source_default.white("Name: ") + source_default.cyan(server.name ?? "-")
4465
+ );
4466
+ const statusColor = getStatusColor2(server.status);
4467
+ console.log(source_default.white("Status: ") + statusColor(server.status));
4468
+ if (server.latestDeploymentStatus) {
4469
+ console.log(
4470
+ source_default.white("Last deploy: ") + source_default.gray(server.latestDeploymentStatus)
4471
+ );
4472
+ }
4473
+ console.log(source_default.white("Region: ") + source_default.gray(server.region));
4474
+ console.log(
4475
+ source_default.white("MCP URL: ") + source_default.cyan(getMcpServerUrlForCloudServer(server))
4476
+ );
4477
+ if (server.connectedRepository) {
4478
+ const cr = server.connectedRepository;
4479
+ console.log(source_default.white("\nRepository"));
4480
+ console.log(source_default.white(" Full name: ") + source_default.gray(cr.repoFullName));
4481
+ console.log(
4482
+ source_default.white(" Prod branch: ") + source_default.gray(cr.productionBranch)
4483
+ );
4484
+ }
4485
+ if (server.activeDeploymentId) {
4486
+ console.log(
4487
+ source_default.white("\nActive deployment: ") + source_default.cyan(server.activeDeploymentId)
4488
+ );
4489
+ }
4490
+ if (server.previousDeploymentId) {
4491
+ console.log(
4492
+ source_default.white("Previous deployment: ") + source_default.gray(server.previousDeploymentId)
4493
+ );
4494
+ }
4495
+ const depCount = server._count?.deployments;
4496
+ if (depCount != null) {
4497
+ console.log(
4498
+ source_default.white("Deployment count: ") + source_default.gray(String(depCount))
4499
+ );
4500
+ }
4501
+ console.log(
4502
+ source_default.white("Created: ") + source_default.gray(formatRelativeTime(server.createdAt))
4503
+ );
4504
+ console.log(
4505
+ source_default.white("Updated: ") + source_default.gray(formatRelativeTime(server.updatedAt))
4506
+ );
4507
+ const config = await readConfig();
4508
+ const base = (await getWebUrl()).replace(/\/$/, "");
4509
+ if (config.orgSlug) {
4510
+ console.log(
4511
+ source_default.white("\nDashboard: ") + source_default.cyan(`${base}/cloud/${config.orgSlug}/servers/${server.id}`)
4512
+ );
4513
+ } else {
4514
+ console.log(
4515
+ source_default.white("\nDashboard: ") + source_default.cyan(`${base}/cloud/servers/${server.id}`)
4516
+ );
4517
+ }
4518
+ if (Array.isArray(server.deployments) && server.deployments.length > 0) {
4519
+ console.log(source_default.cyan.bold("\nRecent deployments\n"));
4520
+ console.log(
4521
+ source_default.white.bold(
4522
+ `${"ID".padEnd(40)} ${"NAME".padEnd(24)} ${"STATUS".padEnd(12)} ${"UPDATED"}`
4523
+ )
4524
+ );
4525
+ console.log(source_default.gray("\u2500".repeat(100)));
4526
+ for (const d of server.deployments) {
4527
+ const did = pickStr(d, "id").padEnd(40);
4528
+ const dname = pickStr(d, "name").substring(0, 23).padEnd(24);
4529
+ const dst = pickStr(d, "status").padEnd(12);
4530
+ const du = pickStr(d, "updatedAt");
4531
+ const updated = du !== "-" ? formatRelativeTime(du) : source_default.gray("-");
4532
+ const sc = getStatusColor2(dst.trim());
4533
+ console.log(
4534
+ `${source_default.gray(did)} ${dname} ${sc(dst)} ${source_default.gray(updated)}`
4535
+ );
4536
+ }
4537
+ }
4538
+ console.log();
4539
+ } catch (error) {
4540
+ console.error(
4541
+ source_default.red.bold("\n\u2717 Failed to get server:"),
4542
+ source_default.red(error instanceof Error ? error.message : "Unknown error")
4543
+ );
4544
+ process.exit(1);
4545
+ }
4546
+ }
4547
+ async function deleteServerCommand(serverId, options) {
4548
+ try {
4549
+ if (!await isLoggedIn()) {
4550
+ console.log(source_default.red("\u2717 You are not logged in."));
4551
+ console.log(
4552
+ source_default.gray(
4553
+ "Run " + source_default.white("npx mcp-use login") + " to get started."
4554
+ )
4555
+ );
4556
+ process.exit(1);
4557
+ }
4558
+ const api = await McpUseAPI.create();
4559
+ await applyOrgOption(api, options.org);
4560
+ if (options.org) console.log();
4561
+ const server = await api.getServer(serverId);
4562
+ if (!options.yes) {
4563
+ console.log(
4564
+ source_default.yellow(
4565
+ `
4566
+ \u26A0\uFE0F You are about to delete server: ${source_default.white(server.name || server.slug || server.id)}`
4567
+ )
4568
+ );
4569
+ console.log(source_default.gray(` ID: ${server.id}`));
4570
+ if (server.connectedRepository?.repoFullName) {
4571
+ console.log(
4572
+ source_default.gray(` Repo: ${server.connectedRepository.repoFullName}
4573
+ `)
4574
+ );
4575
+ } else {
4576
+ console.log();
4577
+ }
4578
+ const confirmed = await prompt3(
4579
+ source_default.white(
4580
+ "This deletes the server and all its deployments. Continue? (y/N): "
4581
+ )
4582
+ );
4583
+ if (!confirmed) {
4584
+ console.log(source_default.gray("Deletion cancelled."));
4585
+ return;
4586
+ }
4587
+ }
4588
+ await api.deleteServer(server.id);
4589
+ console.log(
4590
+ source_default.green.bold(
4591
+ `
4592
+ \u2713 Server deleted: ${server.name || server.slug || server.id}
4593
+ `
4594
+ )
4595
+ );
4596
+ } catch (error) {
4597
+ console.error(
4598
+ source_default.red.bold("\n\u2717 Failed to delete server:"),
4599
+ source_default.red(error instanceof Error ? error.message : "Unknown error")
4600
+ );
4601
+ process.exit(1);
4602
+ }
4603
+ }
4604
+ function createServersCommand() {
4605
+ const serversCommand = new import_commander3.Command("servers").description(
4606
+ "Manage cloud servers (Git-backed deploy targets)"
4607
+ );
4608
+ 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);
4609
+ 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);
4610
+ 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);
4611
+ return serversCommand;
4612
+ }
4613
+
4283
4614
  // src/commands/org.ts
4284
4615
  async function ensureLoggedIn() {
4285
4616
  if (!await isLoggedIn()) {
@@ -4400,7 +4731,7 @@ async function orgCurrentCommand() {
4400
4731
  }
4401
4732
 
4402
4733
  // src/commands/skills.ts
4403
- var import_commander3 = require("commander");
4734
+ var import_commander4 = require("commander");
4404
4735
  var import_node_fs8 = require("fs");
4405
4736
  var import_node_os5 = require("os");
4406
4737
  var import_node_path6 = require("path");
@@ -4470,7 +4801,7 @@ async function addSkillsToProject(projectPath) {
4470
4801
  }
4471
4802
  }
4472
4803
  function createSkillsCommand() {
4473
- const skills = new import_commander3.Command("skills").description(
4804
+ const skills = new import_commander4.Command("skills").description(
4474
4805
  "Manage mcp-use AI agent skills"
4475
4806
  );
4476
4807
  const installAction = async (options) => {
@@ -4646,7 +4977,7 @@ A new release of ${source_default.bold(PACKAGE_NAME)} is available: ${source_def
4646
4977
  }
4647
4978
 
4648
4979
  // src/index.ts
4649
- var program = new import_commander4.Command();
4980
+ var program = new import_commander5.Command();
4650
4981
  var packageContent = (0, import_node_fs10.readFileSync)(
4651
4982
  import_node_path8.default.join(__dirname, "../package.json"),
4652
4983
  "utf-8"
@@ -6474,7 +6805,13 @@ program.command("deploy").description("Deploy MCP server from GitHub to Manufact
6474
6805
  ).option(
6475
6806
  "--org <slug-or-id>",
6476
6807
  "Deploy to a specific organization (by slug or ID)"
6477
- ).option("-y, --yes", "Skip confirmation prompts").action(async (options) => {
6808
+ ).option("-y, --yes", "Skip confirmation prompts").option("--region <region>", "Deploy region: US, EU, or APAC (default: US)").option(
6809
+ "--build-command <cmd>",
6810
+ "Custom build command (overrides auto-detection)"
6811
+ ).option(
6812
+ "--start-command <cmd>",
6813
+ "Custom start command (overrides auto-detection)"
6814
+ ).action(async (options) => {
6478
6815
  await deployCommand({
6479
6816
  open: options.open,
6480
6817
  name: options.name,
@@ -6485,11 +6822,15 @@ program.command("deploy").description("Deploy MCP server from GitHub to Manufact
6485
6822
  envFile: options.envFile,
6486
6823
  rootDir: options.rootDir,
6487
6824
  org: options.org,
6488
- yes: options.yes
6825
+ yes: options.yes,
6826
+ region: options.region,
6827
+ buildCommand: options.buildCommand,
6828
+ startCommand: options.startCommand
6489
6829
  });
6490
6830
  });
6491
6831
  program.addCommand(createClientCommand());
6492
6832
  program.addCommand(createDeploymentsCommand());
6833
+ program.addCommand(createServersCommand());
6493
6834
  program.addCommand(createSkillsCommand());
6494
6835
  program.command("generate-types").description(
6495
6836
  "Generate TypeScript type definitions for tools (writes .mcp-use/tool-registry.d.ts)"