@mcp-use/cli 3.0.0-canary.3 → 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");
@@ -1167,14 +1167,21 @@ async function ensureConfigDir() {
1167
1167
  async function readConfig() {
1168
1168
  try {
1169
1169
  const content = await import_node_fs4.promises.readFile(CONFIG_FILE, "utf-8");
1170
- return JSON.parse(content);
1170
+ const raw = JSON.parse(content);
1171
+ return {
1172
+ ...raw,
1173
+ orgId: raw.orgId ?? raw.profileId,
1174
+ orgName: raw.orgName ?? raw.profileName,
1175
+ orgSlug: raw.orgSlug ?? raw.profileSlug
1176
+ };
1171
1177
  } catch (error) {
1172
1178
  return {};
1173
1179
  }
1174
1180
  }
1175
1181
  async function writeConfig(config) {
1176
1182
  await ensureConfigDir();
1177
- await import_node_fs4.promises.writeFile(CONFIG_FILE, JSON.stringify(config, null, 2), "utf-8");
1183
+ const { profileId: _a, profileName: _b, profileSlug: _c, ...clean } = config;
1184
+ await import_node_fs4.promises.writeFile(CONFIG_FILE, JSON.stringify(clean, null, 2), "utf-8");
1178
1185
  }
1179
1186
  async function deleteConfig() {
1180
1187
  try {
@@ -1194,9 +1201,9 @@ async function isLoggedIn() {
1194
1201
  const apiKey = await getApiKey();
1195
1202
  return !!apiKey;
1196
1203
  }
1197
- async function getProfileId() {
1204
+ async function getOrgId() {
1198
1205
  const config = await readConfig();
1199
- return config.profileId || null;
1206
+ return config.orgId || null;
1200
1207
  }
1201
1208
  async function getWebUrl() {
1202
1209
  return DEFAULT_WEB_URL;
@@ -1210,30 +1217,21 @@ async function getAuthBaseUrl() {
1210
1217
  var McpUseAPI = class _McpUseAPI {
1211
1218
  baseUrl;
1212
1219
  apiKey;
1213
- profileId;
1214
- constructor(baseUrl, apiKey, profileId) {
1220
+ orgId;
1221
+ constructor(baseUrl, apiKey, orgId) {
1215
1222
  this.baseUrl = baseUrl || "";
1216
1223
  this.apiKey = apiKey;
1217
- this.profileId = profileId;
1224
+ this.orgId = orgId;
1218
1225
  }
1219
- /**
1220
- * Initialize API client with config
1221
- */
1222
1226
  static async create() {
1223
1227
  const baseUrl = await getApiUrl();
1224
1228
  const apiKey = await getApiKey();
1225
- const profileId = await getProfileId();
1226
- return new _McpUseAPI(baseUrl, apiKey ?? void 0, profileId ?? void 0);
1229
+ const orgId = await getOrgId();
1230
+ return new _McpUseAPI(baseUrl, apiKey ?? void 0, orgId ?? void 0);
1227
1231
  }
1228
- /**
1229
- * Override the profile ID for this API client instance (e.g. from --org flag)
1230
- */
1231
- setProfileId(profileId) {
1232
- this.profileId = profileId;
1232
+ setOrgId(orgId) {
1233
+ this.orgId = orgId;
1233
1234
  }
1234
- /**
1235
- * Make authenticated request
1236
- */
1237
1235
  async request(endpoint, options = {}) {
1238
1236
  const url = `${this.baseUrl}${endpoint}`;
1239
1237
  const headers = {
@@ -1243,8 +1241,8 @@ var McpUseAPI = class _McpUseAPI {
1243
1241
  if (this.apiKey) {
1244
1242
  headers["x-api-key"] = this.apiKey;
1245
1243
  }
1246
- if (this.profileId) {
1247
- headers["x-profile-id"] = this.profileId;
1244
+ if (this.orgId) {
1245
+ headers["x-profile-id"] = this.orgId;
1248
1246
  }
1249
1247
  const timeout = options.timeout || 3e4;
1250
1248
  const controller = new AbortController();
@@ -1271,16 +1269,13 @@ var McpUseAPI = class _McpUseAPI {
1271
1269
  } catch (error) {
1272
1270
  clearTimeout(timeoutId);
1273
1271
  if (error.name === "AbortError") {
1274
- throw new Error(
1275
- `Request timeout after ${timeout / 1e3}s. Try using --follow flag to stream logs instead.`
1276
- );
1272
+ throw new Error(`Request timeout after ${timeout / 1e3}s.`);
1277
1273
  }
1278
1274
  throw error;
1279
1275
  }
1280
1276
  }
1281
1277
  /**
1282
1278
  * Create a persistent API key using a Better Auth access token.
1283
- * Calls Better Auth's built-in POST /api/auth/api-key/create endpoint.
1284
1279
  */
1285
1280
  async createApiKeyWithAccessToken(accessToken, name = "CLI") {
1286
1281
  const authBase = await getAuthBaseUrl();
@@ -1299,255 +1294,171 @@ var McpUseAPI = class _McpUseAPI {
1299
1294
  }
1300
1295
  return response.json();
1301
1296
  }
1302
- /**
1303
- * Test authentication
1304
- */
1297
+ // ── Auth ────────────────────────────────────────────────────────
1305
1298
  async testAuth() {
1306
- return this.request("/test-auth");
1299
+ const wire = await this.request("/test-auth");
1300
+ return {
1301
+ message: wire.message,
1302
+ user_id: wire.user_id,
1303
+ email: wire.email,
1304
+ default_org_id: wire.default_profile_id,
1305
+ orgs: (wire.profiles ?? []).map((p) => ({
1306
+ id: p.id,
1307
+ name: p.profile_name,
1308
+ slug: p.slug,
1309
+ role: p.role
1310
+ }))
1311
+ };
1307
1312
  }
1308
- /**
1309
- * Set the user's default profile (organization) on the server
1310
- */
1311
- async setDefaultProfile(profileId) {
1312
- await this.request(`/profiles/${profileId}/set-default`, {
1313
+ async setDefaultOrg(orgId) {
1314
+ await this.request(`/organizations/${orgId}/set-default`, {
1313
1315
  method: "POST"
1314
1316
  });
1315
1317
  }
1316
- /**
1317
- * Create deployment
1318
- */
1319
- async createDeployment(request) {
1320
- return this.request("/deployments", {
1318
+ // ── Organization ID resolution ──────────────────────────────────
1319
+ async resolveOrganizationId() {
1320
+ if (this.orgId) return this.orgId;
1321
+ const auth = await this.testAuth();
1322
+ const id = auth.default_org_id;
1323
+ if (!id) {
1324
+ throw new Error(
1325
+ "No organization set. Run `mcp-use org switch` or use --org to specify one."
1326
+ );
1327
+ }
1328
+ return id;
1329
+ }
1330
+ // ── Servers ─────────────────────────────────────────────────────
1331
+ async createServer(body) {
1332
+ return this.request("/servers", {
1321
1333
  method: "POST",
1322
- body: JSON.stringify(request)
1334
+ body: JSON.stringify(body)
1323
1335
  });
1324
1336
  }
1325
- /**
1326
- * Get deployment by ID
1327
- */
1328
- async getDeployment(deploymentId) {
1329
- return this.request(`/deployments/${deploymentId}`);
1330
- }
1331
- /**
1332
- * Stream deployment logs
1333
- */
1334
- async *streamDeploymentLogs(deploymentId) {
1335
- const url = `${this.baseUrl}/deployments/${deploymentId}/logs/stream`;
1336
- const headers = {};
1337
- if (this.apiKey) {
1338
- headers["x-api-key"] = this.apiKey;
1339
- }
1340
- if (this.profileId) {
1341
- headers["x-profile-id"] = this.profileId;
1337
+ async listServers(params) {
1338
+ const search = new URLSearchParams();
1339
+ if (params?.organizationId) {
1340
+ search.set("organizationId", params.organizationId);
1342
1341
  }
1343
- const response = await fetch(url, { headers });
1344
- if (!response.ok) {
1345
- throw new Error(`Failed to stream logs: ${response.status}`);
1342
+ if (params?.limit != null) {
1343
+ search.set("limit", String(params.limit));
1346
1344
  }
1347
- if (!response.body) {
1348
- throw new Error("Response body is null");
1345
+ if (params?.skip != null) {
1346
+ search.set("skip", String(params.skip));
1349
1347
  }
1350
- const reader = response.body.getReader();
1351
- const decoder = new TextDecoder();
1352
- let buffer = "";
1353
- try {
1354
- while (true) {
1355
- const { done, value } = await reader.read();
1356
- if (done) break;
1357
- buffer += decoder.decode(value, { stream: true });
1358
- const lines = buffer.split("\n");
1359
- buffer = lines.pop() || "";
1360
- for (const line of lines) {
1361
- if (line.startsWith("data: ")) {
1362
- const data = line.slice(6);
1363
- try {
1364
- const parsed = JSON.parse(data);
1365
- if (parsed.log) {
1366
- yield parsed.log;
1367
- } else if (parsed.error) {
1368
- throw new Error(parsed.error);
1369
- }
1370
- } catch (e) {
1371
- }
1372
- }
1373
- }
1374
- }
1375
- } finally {
1376
- reader.releaseLock();
1348
+ if (params?.sort) {
1349
+ search.set("sort", params.sort);
1377
1350
  }
1351
+ const q = search.toString();
1352
+ return this.request(`/servers${q ? `?${q}` : ""}`);
1378
1353
  }
1379
- /**
1380
- * Create deployment with source code upload
1381
- */
1382
- async createDeploymentWithUpload(request, filePath) {
1383
- const { readFile: readFile4 } = await import("fs/promises");
1384
- const { basename } = await import("path");
1385
- const { stat } = await import("fs/promises");
1386
- const stats = await stat(filePath);
1387
- const maxSize = 2 * 1024 * 1024;
1388
- if (stats.size > maxSize) {
1389
- throw new Error(
1390
- `File size (${(stats.size / 1024 / 1024).toFixed(2)}MB) exceeds maximum of 2MB`
1391
- );
1392
- }
1393
- const fileBuffer = await readFile4(filePath);
1394
- const filename = basename(filePath);
1395
- const formData = new FormData();
1396
- const blob = new Blob([fileBuffer], { type: "application/gzip" });
1397
- formData.append("source_file", blob, filename);
1398
- formData.append("name", request.name);
1399
- formData.append("source_type", "upload");
1400
- if (request.source.type === "upload") {
1401
- formData.append("runtime", request.source.runtime || "node");
1402
- formData.append("port", String(request.source.port || 3e3));
1403
- if (request.source.startCommand) {
1404
- formData.append("startCommand", request.source.startCommand);
1405
- }
1406
- if (request.source.buildCommand) {
1407
- formData.append("buildCommand", request.source.buildCommand);
1408
- }
1409
- if (request.source.env && Object.keys(request.source.env).length > 0) {
1410
- formData.append("env", JSON.stringify(request.source.env));
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"
1411
1363
  }
1412
- }
1413
- if (request.customDomain) {
1414
- formData.append("customDomain", request.customDomain);
1415
- }
1416
- if (request.healthCheckPath) {
1417
- formData.append("healthCheckPath", request.healthCheckPath);
1418
- }
1419
- const url = `${this.baseUrl}/deployments`;
1420
- const headers = {};
1421
- if (this.apiKey) {
1422
- headers["x-api-key"] = this.apiKey;
1423
- }
1424
- if (this.profileId) {
1425
- headers["x-profile-id"] = this.profileId;
1426
- }
1427
- const response = await fetch(url, {
1364
+ );
1365
+ }
1366
+ // ── Deployments ─────────────────────────────────────────────────
1367
+ async createDeployment(input) {
1368
+ return this.request("/deployments", {
1428
1369
  method: "POST",
1429
- headers,
1430
- body: formData
1370
+ body: JSON.stringify(input)
1431
1371
  });
1432
- if (!response.ok) {
1433
- const error = await response.text();
1434
- throw new Error(`Deployment failed: ${error}`);
1435
- }
1436
- return response.json();
1437
1372
  }
1438
- /**
1439
- * List all deployments
1440
- */
1373
+ async getDeployment(deploymentId) {
1374
+ return this.request(`/deployments/${deploymentId}`);
1375
+ }
1441
1376
  async listDeployments() {
1442
- const response = await this.request("/deployments");
1443
- return response.deployments;
1377
+ return this.request("/deployments");
1444
1378
  }
1445
- /**
1446
- * Delete deployment
1447
- */
1448
1379
  async deleteDeployment(deploymentId) {
1449
1380
  await this.request(`/deployments/${deploymentId}`, {
1450
1381
  method: "DELETE"
1451
1382
  });
1452
1383
  }
1453
- /**
1454
- * Update deployment
1455
- */
1456
- async updateDeployment(deploymentId, updates) {
1457
- return this.request(`/deployments/${deploymentId}`, {
1458
- method: "PATCH",
1459
- body: JSON.stringify(updates)
1460
- });
1461
- }
1462
- /**
1463
- * Redeploy deployment
1464
- *
1465
- * @param deploymentId - The deployment ID to redeploy
1466
- * @param configOrFilePath - Either a RedeploymentConfig object with updated settings,
1467
- * or a file path string for source code upload
1468
- */
1469
- async redeployDeployment(deploymentId, configOrFilePath) {
1470
- if (typeof configOrFilePath === "string") {
1471
- const filePath = configOrFilePath;
1472
- const { readFile: readFile4 } = await import("fs/promises");
1473
- const { basename } = await import("path");
1474
- const { stat } = await import("fs/promises");
1475
- const stats = await stat(filePath);
1476
- const maxSize = 2 * 1024 * 1024;
1477
- if (stats.size > maxSize) {
1478
- throw new Error(
1479
- `File size (${(stats.size / 1024 / 1024).toFixed(2)}MB) exceeds maximum of 2MB`
1480
- );
1481
- }
1482
- const fileBuffer = await readFile4(filePath);
1483
- const formData = new FormData();
1484
- const blob = new Blob([fileBuffer], { type: "application/gzip" });
1485
- formData.append("source_file", blob, basename(filePath));
1486
- const headers = {};
1487
- if (this.apiKey) headers["x-api-key"] = this.apiKey;
1488
- if (this.profileId) headers["x-profile-id"] = this.profileId;
1489
- const response = await fetch(
1490
- `${this.baseUrl}/deployments/${deploymentId}/redeploy`,
1491
- {
1492
- method: "POST",
1493
- headers,
1494
- body: formData
1495
- }
1496
- );
1497
- if (!response.ok) {
1498
- const error = await response.text();
1499
- throw new Error(`Redeploy failed: ${error}`);
1500
- }
1501
- return response.json();
1502
- }
1503
- const config = configOrFilePath;
1504
- return this.request(`/deployments/${deploymentId}/redeploy`, {
1505
- method: "POST",
1506
- body: config ? JSON.stringify(config) : void 0
1384
+ async stopDeployment(deploymentId) {
1385
+ await this.request(`/deployments/${deploymentId}/stop`, {
1386
+ method: "POST"
1507
1387
  });
1508
1388
  }
1509
- /**
1510
- * Get deployment logs
1511
- */
1512
- async getDeploymentLogs(deploymentId) {
1513
- const response = await this.request(
1514
- `/deployments/${deploymentId}/logs`,
1389
+ async getDeploymentLogs(deploymentId, lines = 500) {
1390
+ const resp = await this.request(
1391
+ `/deployments/${deploymentId}/logs?lines=${lines}`,
1515
1392
  { timeout: 6e4 }
1516
- // 60 second timeout for logs
1517
1393
  );
1518
- return response.data.logs;
1394
+ return resp.logs;
1519
1395
  }
1520
- /**
1521
- * Get deployment build logs
1522
- */
1523
- async getDeploymentBuildLogs(deploymentId) {
1524
- const response = await this.request(
1525
- `/deployments/${deploymentId}/logs/build`,
1396
+ async getDeploymentBuildLogs(deploymentId, offset = 0) {
1397
+ return this.request(
1398
+ `/deployments/${deploymentId}/build-logs?offset=${offset}`,
1526
1399
  { timeout: 6e4 }
1527
- // 60 second timeout for logs
1528
1400
  );
1529
- return response.data.logs;
1530
1401
  }
1531
- /**
1532
- * Get GitHub connection status
1533
- */
1402
+ // ── GitHub ──────────────────────────────────────────────────────
1534
1403
  async getGitHubConnectionStatus() {
1535
- return this.request("/github/connection");
1404
+ const orgId = await this.resolveOrganizationId();
1405
+ const resp = await this.request(`/github/installations?organizationId=${orgId}`);
1406
+ return {
1407
+ is_connected: resp.installations.length > 0,
1408
+ installations: resp.installations.map((i) => ({
1409
+ id: i.id,
1410
+ installation_id: i.installationId,
1411
+ account_login: i.account?.login ?? "",
1412
+ account_type: i.account?.type ?? "User"
1413
+ }))
1414
+ };
1415
+ }
1416
+ async getGitHubRepos(_refresh) {
1417
+ const orgId = await this.resolveOrganizationId();
1418
+ const installResp = await this.request(`/github/installations?organizationId=${orgId}`);
1419
+ if (installResp.installations.length === 0) {
1420
+ return { user: { login: "", id: 0, avatar_url: "" }, repos: [] };
1421
+ }
1422
+ const inst = installResp.installations[0];
1423
+ const reposResp = await this.request(`/github/installations/${inst.installationId}/repos`);
1424
+ return {
1425
+ user: {
1426
+ login: inst.account?.login ?? "",
1427
+ id: 0,
1428
+ avatar_url: inst.account?.avatar_url ?? ""
1429
+ },
1430
+ repos: reposResp.repos.map((r) => ({
1431
+ id: r.id,
1432
+ name: r.name,
1433
+ full_name: r.fullName,
1434
+ private: r.private,
1435
+ owner: { login: r.fullName.split("/")[0] ?? "" }
1436
+ }))
1437
+ };
1536
1438
  }
1537
- /**
1538
- * Get GitHub app name
1539
- */
1540
1439
  async getGitHubAppName() {
1541
- const response = await this.request("/github/appname");
1542
- return response.app_name;
1440
+ if (process.env.MCP_GITHUB_APP_NAME) return process.env.MCP_GITHUB_APP_NAME;
1441
+ if (this.baseUrl.includes("localhost")) return "mcp-use-local";
1442
+ if (this.baseUrl.includes(".dev.")) return "mcp-use-dev";
1443
+ return "mcp-use";
1543
1444
  }
1544
1445
  /**
1545
- * Get accessible GitHub repositories
1446
+ * Returns the GitHub numeric installation ID (not the DB UUID) for the org.
1447
+ * Used for building direct installation settings URLs.
1546
1448
  */
1547
- async getGitHubRepos(refresh = false) {
1548
- return this.request(
1549
- `/github/repos${refresh ? "?refresh=true" : ""}`
1550
- );
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
+ });
1551
1462
  }
1552
1463
  };
1553
1464
 
@@ -1612,19 +1523,17 @@ async function pollForDeviceToken(authBaseUrl, deviceCode, intervalSeconds) {
1612
1523
  }
1613
1524
  throw new Error("Login timed out. Please try again.");
1614
1525
  }
1615
- async function promptOrgSelection(profiles, defaultProfileId) {
1616
- if (profiles.length === 0) return null;
1617
- if (profiles.length === 1) {
1618
- return profiles[0];
1526
+ async function promptOrgSelection(orgs, defaultOrgId) {
1527
+ if (orgs.length === 0) return null;
1528
+ if (orgs.length === 1) {
1529
+ return orgs[0];
1619
1530
  }
1620
1531
  console.log(source_default.cyan.bold("\n\u{1F3E2} Select an organization:\n"));
1621
- for (let i = 0; i < profiles.length; i++) {
1622
- const p = profiles[i];
1623
- const marker = p.id === defaultProfileId ? source_default.green(" (current)") : "";
1624
- const slug = p.slug ? source_default.gray(` (${p.slug})`) : "";
1625
- console.log(
1626
- ` ${source_default.white(`${i + 1}.`)} ${p.profile_name}${slug}${marker}`
1627
- );
1532
+ for (let i = 0; i < orgs.length; i++) {
1533
+ const o = orgs[i];
1534
+ const marker = o.id === defaultOrgId ? source_default.green(" (current)") : "";
1535
+ const slug = o.slug ? source_default.gray(` (${o.slug})`) : "";
1536
+ console.log(` ${source_default.white(`${i + 1}.`)} ${o.name}${slug}${marker}`);
1628
1537
  }
1629
1538
  const readline = await import("readline");
1630
1539
  const rl = readline.createInterface({
@@ -1632,7 +1541,7 @@ async function promptOrgSelection(profiles, defaultProfileId) {
1632
1541
  output: process.stdout
1633
1542
  });
1634
1543
  return new Promise((resolve2) => {
1635
- const defaultIdx = defaultProfileId ? profiles.findIndex((p) => p.id === defaultProfileId) : 0;
1544
+ const defaultIdx = defaultOrgId ? orgs.findIndex((o) => o.id === defaultOrgId) : 0;
1636
1545
  const defaultDisplay = defaultIdx >= 0 ? defaultIdx + 1 : 1;
1637
1546
  rl.question(
1638
1547
  source_default.gray(`
@@ -1641,11 +1550,11 @@ Enter number [${defaultDisplay}]: `),
1641
1550
  rl.close();
1642
1551
  const trimmed = answer.trim();
1643
1552
  const idx = trimmed === "" ? defaultIdx : parseInt(trimmed, 10) - 1;
1644
- if (idx >= 0 && idx < profiles.length) {
1645
- resolve2(profiles[idx]);
1553
+ if (idx >= 0 && idx < orgs.length) {
1554
+ resolve2(orgs[idx]);
1646
1555
  } else {
1647
1556
  console.log(source_default.yellow("Invalid selection, using default."));
1648
- resolve2(profiles[defaultIdx >= 0 ? defaultIdx : 0]);
1557
+ resolve2(orgs[defaultIdx >= 0 ? defaultIdx : 0]);
1649
1558
  }
1650
1559
  }
1651
1560
  );
@@ -1724,28 +1633,25 @@ async function loginCommand(options) {
1724
1633
  const masked = storedKey.substring(0, 8) + "...";
1725
1634
  console.log(source_default.white(" API Key: ") + source_default.gray(masked));
1726
1635
  }
1727
- const profiles = authInfo.profiles ?? [];
1728
- if (profiles.length > 0) {
1729
- let selectedProfile = null;
1730
- if (profiles.length === 1) {
1731
- selectedProfile = profiles[0];
1636
+ const orgs = authInfo.orgs ?? [];
1637
+ if (orgs.length > 0) {
1638
+ let selectedOrg = null;
1639
+ if (orgs.length === 1) {
1640
+ selectedOrg = orgs[0];
1732
1641
  } else {
1733
- selectedProfile = await promptOrgSelection(
1734
- profiles,
1735
- authInfo.default_profile_id
1736
- );
1642
+ selectedOrg = await promptOrgSelection(orgs, authInfo.default_org_id);
1737
1643
  }
1738
- if (selectedProfile) {
1644
+ if (selectedOrg) {
1739
1645
  const config = await readConfig();
1740
1646
  await writeConfig({
1741
1647
  ...config,
1742
- profileId: selectedProfile.id,
1743
- profileName: selectedProfile.profile_name,
1744
- profileSlug: selectedProfile.slug ?? void 0
1648
+ orgId: selectedOrg.id,
1649
+ orgName: selectedOrg.name,
1650
+ orgSlug: selectedOrg.slug ?? void 0
1745
1651
  });
1746
- const slug = selectedProfile.slug ? source_default.gray(` (${selectedProfile.slug})`) : "";
1652
+ const slug = selectedOrg.slug ? source_default.gray(` (${selectedOrg.slug})`) : "";
1747
1653
  console.log(
1748
- source_default.white(" Org: ") + source_default.cyan(selectedProfile.profile_name) + slug
1654
+ source_default.white(" Org: ") + source_default.cyan(selectedOrg.name) + slug
1749
1655
  );
1750
1656
  }
1751
1657
  }
@@ -1815,22 +1721,22 @@ async function whoamiCommand() {
1815
1721
  console.log(source_default.white("API Key: ") + source_default.gray(masked));
1816
1722
  }
1817
1723
  const config = await readConfig();
1818
- const profiles = authInfo.profiles ?? [];
1819
- if (profiles.length > 0) {
1820
- const activeProfile = profiles.find(
1821
- (p) => p.id === (config.profileId || authInfo.default_profile_id)
1724
+ const orgs = authInfo.orgs ?? [];
1725
+ if (orgs.length > 0) {
1726
+ const activeOrg = orgs.find(
1727
+ (o) => o.id === (config.orgId || authInfo.default_org_id)
1822
1728
  );
1823
- if (activeProfile) {
1824
- const slug = activeProfile.slug ? source_default.gray(` (${activeProfile.slug})`) : "";
1729
+ if (activeOrg) {
1730
+ const slug = activeOrg.slug ? source_default.gray(` (${activeOrg.slug})`) : "";
1825
1731
  console.log(
1826
- source_default.white("Org: ") + source_default.cyan(activeProfile.profile_name) + slug
1732
+ source_default.white("Org: ") + source_default.cyan(activeOrg.name) + slug
1827
1733
  );
1828
1734
  }
1829
- if (profiles.length > 1) {
1735
+ if (orgs.length > 1) {
1830
1736
  console.log(
1831
1737
  source_default.gray(
1832
1738
  `
1833
- ${profiles.length} organizations available. Use ` + source_default.white("npx mcp-use org list") + " to see all."
1739
+ ${orgs.length} organizations available. Use ` + source_default.white("npx mcp-use org list") + " to see all."
1834
1740
  )
1835
1741
  );
1836
1742
  }
@@ -2607,9 +2513,9 @@ async function listPromptsCommand(options) {
2607
2513
  }
2608
2514
  console.log(formatHeader(`Available Prompts (${prompts.length}):`));
2609
2515
  console.log("");
2610
- const tableData = prompts.map((prompt3) => ({
2611
- name: source_default.bold(prompt3.name),
2612
- 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")
2613
2519
  }));
2614
2520
  console.log(
2615
2521
  formatTable(tableData, [
@@ -2637,20 +2543,20 @@ async function getPromptCommand(promptName, argsJson, options) {
2637
2543
  }
2638
2544
  }
2639
2545
  console.error(formatInfo(`Getting prompt '${promptName}'...`));
2640
- const prompt3 = await session.getPrompt(promptName, args);
2546
+ const prompt4 = await session.getPrompt(promptName, args);
2641
2547
  if (options?.json) {
2642
- console.log(formatJson(prompt3));
2548
+ console.log(formatJson(prompt4));
2643
2549
  } else {
2644
2550
  console.log(formatHeader(`Prompt: ${promptName}`));
2645
2551
  console.log("");
2646
- if (prompt3.description) {
2647
- console.log(prompt3.description);
2552
+ if (prompt4.description) {
2553
+ console.log(prompt4.description);
2648
2554
  console.log("");
2649
2555
  }
2650
- if (prompt3.messages) {
2556
+ if (prompt4.messages) {
2651
2557
  console.log(formatHeader("Messages:"));
2652
2558
  console.log("");
2653
- console.log(formatPromptMessages(prompt3.messages));
2559
+ console.log(formatPromptMessages(prompt4.messages));
2654
2560
  }
2655
2561
  }
2656
2562
  } catch (error) {
@@ -2790,8 +2696,8 @@ async function interactiveCommand(options) {
2790
2696
  async (argsInput) => {
2791
2697
  try {
2792
2698
  const args = argsInput.trim() ? JSON.parse(argsInput) : {};
2793
- const prompt3 = await session.getPrompt(arg, args);
2794
- console.log(formatPromptMessages(prompt3.messages));
2699
+ const prompt4 = await session.getPrompt(arg, args);
2700
+ console.log(formatPromptMessages(prompt4.messages));
2795
2701
  } catch (error) {
2796
2702
  console.error(formatError(error.message));
2797
2703
  }
@@ -2957,6 +2863,20 @@ async function getGitInfo(cwd = process.cwd()) {
2957
2863
  hasUncommittedChanges: uncommittedChanges
2958
2864
  };
2959
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
+ }
2960
2880
  function isGitHubUrl(url) {
2961
2881
  try {
2962
2882
  const parsedUrl = new URL(url);
@@ -2971,6 +2891,22 @@ function isGitHubUrl(url) {
2971
2891
  return false;
2972
2892
  }
2973
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
+
2974
2910
  // src/utils/project-link.ts
2975
2911
  var import_node_fs6 = require("fs");
2976
2912
  var import_node_path4 = __toESM(require("path"), 1);
@@ -3017,10 +2953,6 @@ ${MCP_USE_DIR}
3017
2953
  }
3018
2954
 
3019
2955
  // src/commands/deploy.ts
3020
- var GATEWAY_DOMAIN = "run.mcp-use.com";
3021
- function buildGatewayUrl(slugOrId) {
3022
- return `https://${slugOrId}.${GATEWAY_DOMAIN}/mcp`;
3023
- }
3024
2956
  async function parseEnvFile(filePath) {
3025
2957
  try {
3026
2958
  const content = await import_node_fs7.promises.readFile(filePath, "utf-8");
@@ -3030,9 +2962,7 @@ async function parseEnvFile(filePath) {
3030
2962
  let currentValue = "";
3031
2963
  for (let line of lines) {
3032
2964
  line = line.trim();
3033
- if (!line || line.startsWith("#")) {
3034
- continue;
3035
- }
2965
+ if (!line || line.startsWith("#")) continue;
3036
2966
  if (currentKey && !line.includes("=")) {
3037
2967
  currentValue += "\n" + line;
3038
2968
  continue;
@@ -3043,20 +2973,15 @@ async function parseEnvFile(filePath) {
3043
2973
  currentValue = "";
3044
2974
  }
3045
2975
  const equalIndex = line.indexOf("=");
3046
- if (equalIndex === -1) {
3047
- continue;
3048
- }
2976
+ if (equalIndex === -1) continue;
3049
2977
  const key = line.substring(0, equalIndex).trim();
3050
- let value = line.substring(equalIndex + 1).trim();
2978
+ const value = line.substring(equalIndex + 1).trim();
3051
2979
  if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
3052
- console.log(
3053
- source_default.yellow(`\u26A0\uFE0F Skipping invalid environment variable key: ${key}`)
3054
- );
2980
+ console.log(source_default.yellow(`\u26A0\uFE0F Skipping invalid env key: ${key}`));
3055
2981
  continue;
3056
2982
  }
3057
2983
  if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
3058
- value = value.slice(1, -1);
3059
- envVars[key] = value;
2984
+ envVars[key] = value.slice(1, -1);
3060
2985
  } else if (value.startsWith('"') || value.startsWith("'")) {
3061
2986
  currentKey = key;
3062
2987
  currentValue = value.slice(1);
@@ -3080,16 +3005,12 @@ async function parseEnvFile(filePath) {
3080
3005
  function parseEnvVar(envStr) {
3081
3006
  const equalIndex = envStr.indexOf("=");
3082
3007
  if (equalIndex === -1) {
3083
- throw new Error(
3084
- `Invalid environment variable format: "${envStr}". Expected KEY=VALUE`
3085
- );
3008
+ throw new Error(`Invalid env format: "${envStr}". Expected KEY=VALUE`);
3086
3009
  }
3087
3010
  const key = envStr.substring(0, equalIndex).trim();
3088
3011
  const value = envStr.substring(equalIndex + 1);
3089
3012
  if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
3090
- throw new Error(
3091
- `Invalid environment variable key: "${key}". Keys must start with a letter or underscore and contain only letters, numbers, and underscores.`
3092
- );
3013
+ throw new Error(`Invalid env key: "${key}".`);
3093
3014
  }
3094
3015
  return { key, value };
3095
3016
  }
@@ -3132,72 +3053,48 @@ async function buildEnvVars(options) {
3132
3053
  }
3133
3054
  async function isMcpProject(cwd = process.cwd()) {
3134
3055
  try {
3135
- const packageJsonPath = import_node_path5.default.join(cwd, "package.json");
3136
- const content = await import_node_fs7.promises.readFile(packageJsonPath, "utf-8");
3137
- const packageJson2 = JSON.parse(content);
3138
- const hasMcpDeps = packageJson2.dependencies?.["mcp-use"] || packageJson2.dependencies?.["@modelcontextprotocol/sdk"] || packageJson2.devDependencies?.["mcp-use"] || packageJson2.devDependencies?.["@modelcontextprotocol/sdk"];
3139
- const hasMcpScripts = packageJson2.scripts?.mcp || packageJson2.scripts?.["mcp:dev"];
3140
- 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"]);
3141
3059
  } catch {
3142
3060
  return false;
3143
3061
  }
3144
3062
  }
3145
3063
  async function getProjectName(cwd = process.cwd()) {
3146
3064
  try {
3147
- const packageJsonPath = import_node_path5.default.join(cwd, "package.json");
3148
- const content = await import_node_fs7.promises.readFile(packageJsonPath, "utf-8");
3149
- const packageJson2 = JSON.parse(content);
3150
- if (packageJson2.name) {
3151
- return packageJson2.name;
3152
- }
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;
3153
3068
  } catch {
3154
3069
  }
3155
3070
  return import_node_path5.default.basename(cwd);
3156
3071
  }
3157
- async function detectBuildCommand(cwd = process.cwd()) {
3072
+ async function detectBuildCommand(cwd) {
3158
3073
  try {
3159
- const packageJsonPath = import_node_path5.default.join(cwd, "package.json");
3160
- const content = await import_node_fs7.promises.readFile(packageJsonPath, "utf-8");
3161
- const packageJson2 = JSON.parse(content);
3162
- if (packageJson2.scripts?.build) {
3163
- return "npm run build";
3164
- }
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";
3165
3076
  } catch {
3166
3077
  }
3167
3078
  return void 0;
3168
3079
  }
3169
- async function detectStartCommand(cwd = process.cwd()) {
3080
+ async function detectStartCommand(cwd) {
3170
3081
  try {
3171
- const packageJsonPath = import_node_path5.default.join(cwd, "package.json");
3172
- const content = await import_node_fs7.promises.readFile(packageJsonPath, "utf-8");
3173
- const packageJson2 = JSON.parse(content);
3174
- if (packageJson2.scripts?.start) {
3175
- return "npm start";
3176
- }
3177
- if (packageJson2.main) {
3178
- return `node ${packageJson2.main}`;
3179
- }
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}`;
3180
3086
  } catch {
3181
3087
  }
3182
3088
  return void 0;
3183
3089
  }
3184
- async function detectRuntime(cwd = process.cwd()) {
3185
- try {
3186
- const pythonFiles = ["requirements.txt", "pyproject.toml", "setup.py"];
3187
- for (const file of pythonFiles) {
3188
- try {
3189
- await import_node_fs7.promises.access(import_node_path5.default.join(cwd, file));
3190
- return "python";
3191
- } catch {
3192
- continue;
3193
- }
3194
- }
3090
+ async function detectRuntime(cwd) {
3091
+ for (const f of ["requirements.txt", "pyproject.toml", "setup.py"]) {
3195
3092
  try {
3196
- await import_node_fs7.promises.access(import_node_path5.default.join(cwd, "package.json"));
3197
- return "node";
3093
+ await import_node_fs7.promises.access(import_node_path5.default.join(cwd, f));
3094
+ return "python";
3198
3095
  } catch {
3096
+ continue;
3199
3097
  }
3200
- } catch {
3201
3098
  }
3202
3099
  return "node";
3203
3100
  }
@@ -3207,50 +3104,64 @@ async function prompt(question, defaultValue = "n") {
3207
3104
  input: process.stdin,
3208
3105
  output: process.stdout
3209
3106
  });
3210
- const defaultIndicator = defaultValue === "y" ? "Y/n" : "y/N";
3211
- const questionWithDefault = question.replace(
3212
- /(\(y\/n\):)/,
3213
- `(${defaultIndicator}):`
3214
- );
3107
+ const indicator = defaultValue === "y" ? "Y/n" : "y/N";
3108
+ const q = question.replace(/(\(y\/n\):)/, `(${indicator}):`);
3215
3109
  return new Promise((resolve2) => {
3216
- rl.question(questionWithDefault, (answer) => {
3110
+ rl.question(q, (answer) => {
3217
3111
  rl.close();
3218
- const trimmedAnswer = answer.trim().toLowerCase();
3219
- if (trimmedAnswer === "") {
3220
- resolve2(defaultValue === "y");
3221
- } else {
3222
- resolve2(trimmedAnswer === "y" || trimmedAnswer === "yes");
3223
- }
3112
+ const a = answer.trim().toLowerCase();
3113
+ if (a === "") resolve2(defaultValue === "y");
3114
+ else resolve2(a === "y" || a === "yes");
3224
3115
  });
3225
3116
  });
3226
3117
  }
3227
- function getMcpServerUrl(deployment) {
3228
- if (deployment.customDomain) {
3229
- return `https://${deployment.customDomain}/mcp`;
3230
- } else if (deployment.serverSlug) {
3231
- return buildGatewayUrl(deployment.serverSlug);
3232
- } else if (deployment.serverId) {
3233
- return buildGatewayUrl(deployment.serverId);
3234
- } else {
3235
- return `https://${deployment.domain}/mcp`;
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 {
3145
+ }
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");
3236
3151
  }
3237
3152
  }
3238
- async function displayDeploymentProgress(api, deployment, progressOptions) {
3153
+ async function displayDeploymentProgress(api, deploymentId, progressOptions) {
3239
3154
  const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
3240
3155
  let frameIndex = 0;
3241
3156
  let spinnerInterval = null;
3242
- let lastStep = "";
3243
3157
  const startSpinner = (message) => {
3244
- if (spinnerInterval) {
3245
- clearInterval(spinnerInterval);
3246
- }
3158
+ if (spinnerInterval) clearInterval(spinnerInterval);
3247
3159
  process.stdout.write("\r\x1B[K");
3248
3160
  spinnerInterval = setInterval(() => {
3249
- const frame = frames[frameIndex];
3250
- frameIndex = (frameIndex + 1) % frames.length;
3251
3161
  process.stdout.write(
3252
- "\r" + source_default.cyan(frame) + " " + source_default.gray(message)
3162
+ "\r" + source_default.cyan(frames[frameIndex]) + " " + source_default.gray(message)
3253
3163
  );
3164
+ frameIndex = (frameIndex + 1) % frames.length;
3254
3165
  }, 80);
3255
3166
  };
3256
3167
  const stopSpinner = () => {
@@ -3262,82 +3173,56 @@ async function displayDeploymentProgress(api, deployment, progressOptions) {
3262
3173
  };
3263
3174
  console.log();
3264
3175
  startSpinner("Deploying...");
3265
- try {
3266
- for await (const log of api.streamDeploymentLogs(deployment.id)) {
3267
- try {
3268
- const logData = JSON.parse(log);
3269
- if (logData.step && logData.step !== lastStep) {
3270
- lastStep = logData.step;
3271
- const stepMessages = {
3272
- clone: "Preparing source code...",
3273
- analyze: "Analyzing project...",
3274
- build: "Building container image...",
3275
- deploy: "Deploying to cloud..."
3276
- };
3277
- const message = stepMessages[logData.step] || "Deploying...";
3278
- startSpinner(message);
3279
- }
3280
- if (logData.line) {
3281
- stopSpinner();
3282
- const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
3283
- const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
3284
- console.log(stepPrefix + levelColor(logData.line));
3285
- }
3286
- } catch {
3287
- }
3288
- }
3289
- } catch (error) {
3290
- stopSpinner();
3291
- }
3292
3176
  let checkCount = 0;
3293
- const maxChecks = 60;
3294
- let delay = 3e3;
3177
+ const maxChecks = 120;
3178
+ let delay = 2e3;
3295
3179
  const maxDelay = 1e4;
3296
- let lastDisplayedLogLength = 0;
3180
+ let buildLogOffset = 0;
3297
3181
  while (checkCount < maxChecks) {
3298
- const currentDelay = delay;
3299
- await new Promise((resolve2) => setTimeout(resolve2, currentDelay));
3300
- const finalDeployment = await api.getDeployment(deployment.id);
3301
- if (finalDeployment.buildLogs && finalDeployment.buildLogs.length > lastDisplayedLogLength) {
3302
- const newLogs = finalDeployment.buildLogs.substring(
3303
- lastDisplayedLogLength
3182
+ const waitMs = delay;
3183
+ await new Promise((r) => setTimeout(r, waitMs));
3184
+ checkCount++;
3185
+ try {
3186
+ const resp = await api.getDeploymentBuildLogs(
3187
+ deploymentId,
3188
+ buildLogOffset
3304
3189
  );
3305
- const logLines = newLogs.split("\n").filter((l) => l.trim());
3306
- for (const line of logLines) {
3307
- try {
3308
- const logData = JSON.parse(line);
3309
- if (logData.line) {
3190
+ if (resp.logs.length > 0) {
3191
+ for (const line of resp.logs.split("\n").filter((l) => l.trim())) {
3192
+ try {
3193
+ const d = JSON.parse(line);
3194
+ if (d.line) {
3195
+ stopSpinner();
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));
3199
+ }
3200
+ } catch {
3310
3201
  stopSpinner();
3311
- const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
3312
- const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
3313
- console.log(stepPrefix + levelColor(logData.line));
3202
+ console.log(source_default.gray(line));
3314
3203
  }
3315
- } catch {
3316
3204
  }
3205
+ buildLogOffset = resp.offset;
3317
3206
  }
3318
- lastDisplayedLogLength = finalDeployment.buildLogs.length;
3207
+ } catch {
3319
3208
  }
3320
- if (finalDeployment.status === "running") {
3321
- const mcpServerUrl = getMcpServerUrl(finalDeployment);
3322
- let dashboardUrl = null;
3209
+ const dep = await api.getDeployment(deploymentId);
3210
+ if (dep.status === "running") {
3211
+ stopSpinner();
3212
+ const mcpUrl = getMcpServerUrl(dep);
3323
3213
  const webUrl = (await getWebUrl()).replace(/\/$/, "");
3324
3214
  const config = await readConfig();
3325
- const orgSlug = config.profileSlug;
3326
- const serverRef = finalDeployment.serverSlug || finalDeployment.serverId;
3327
- if (serverRef) {
3328
- if (orgSlug) {
3329
- dashboardUrl = `${webUrl}/cloud/${orgSlug}/servers/${serverRef}`;
3330
- } else {
3331
- dashboardUrl = `${webUrl}/cloud/servers/${serverRef}`;
3332
- }
3215
+ let dashboardUrl = null;
3216
+ if (dep.serverId) {
3217
+ dashboardUrl = config.orgSlug ? `${webUrl}/cloud/${config.orgSlug}/servers/${dep.serverId}` : `${webUrl}/cloud/servers/${dep.serverId}`;
3333
3218
  }
3334
- const inspectorUrl = `https://inspector.manufact.com/inspector?autoConnect=${encodeURIComponent(
3335
- mcpServerUrl
3336
- )}`;
3219
+ const inspectorUrl = `https://inspector.manufact.com/inspector?autoConnect=${encodeURIComponent(mcpUrl)}`;
3337
3220
  console.log(source_default.green.bold("\u2713 Deployment successful!\n"));
3338
- console.log(source_default.white("\u{1F310} MCP Server URL:"));
3339
- console.log(source_default.cyan.bold(` ${mcpServerUrl}
3221
+ if (mcpUrl) {
3222
+ console.log(source_default.white("\u{1F310} MCP Server URL:"));
3223
+ console.log(source_default.cyan.bold(` ${mcpUrl}
3340
3224
  `));
3225
+ }
3341
3226
  if (dashboardUrl) {
3342
3227
  console.log(source_default.white("\u{1F4CA} Dashboard:"));
3343
3228
  console.log(source_default.cyan.bold(` ${dashboardUrl}
@@ -3346,169 +3231,76 @@ async function displayDeploymentProgress(api, deployment, progressOptions) {
3346
3231
  console.log(source_default.white("\u{1F50D} Inspector URL:"));
3347
3232
  console.log(source_default.cyan.bold(` ${inspectorUrl}
3348
3233
  `));
3349
- console.log(
3350
- source_default.gray("Deployment ID: ") + source_default.white(finalDeployment.id)
3351
- );
3234
+ console.log(source_default.gray("Deployment ID: ") + source_default.white(dep.id));
3352
3235
  return;
3353
- } else if (finalDeployment.status === "failed") {
3236
+ } else if (dep.status === "failed") {
3354
3237
  stopSpinner();
3355
3238
  console.log(source_default.red.bold("\u2717 Deployment failed\n"));
3356
- if (finalDeployment.error) {
3357
- console.log(source_default.red("Error: ") + finalDeployment.error);
3358
- if (finalDeployment.error.includes("No GitHub installations found")) {
3359
- console.log();
3360
- const retry = await promptGitHubInstallation(
3361
- api,
3362
- "not_connected",
3363
- void 0,
3364
- { yes: progressOptions?.yes }
3365
- );
3366
- if (retry) {
3367
- console.log(source_default.cyan("\n\u{1F504} Retrying deployment...\n"));
3368
- const newDeployment = await api.redeployDeployment(deployment.id);
3369
- await displayDeploymentProgress(
3370
- api,
3371
- newDeployment,
3372
- progressOptions
3373
- );
3374
- return;
3375
- }
3376
- } else if (finalDeployment.error.includes("Authenticated git clone failed")) {
3377
- let repoName;
3378
- const repoMatch = finalDeployment.error.match(
3379
- /github\.com\/([^/]+\/[^/\s]+)/
3380
- );
3381
- if (repoMatch) {
3382
- repoName = repoMatch[1].replace(/\.git$/, "");
3383
- } else if (finalDeployment.source.type === "github") {
3384
- repoName = finalDeployment.source.repo;
3385
- }
3386
- console.log();
3387
- const retry = await promptGitHubInstallation(
3388
- api,
3389
- "no_access",
3390
- repoName,
3391
- { 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."
3392
3257
  );
3393
- if (retry) {
3394
- console.log(source_default.cyan("\n\u{1F504} Retrying deployment...\n"));
3395
- const newDeployment = await api.redeployDeployment(deployment.id);
3396
- await displayDeploymentProgress(
3397
- api,
3398
- newDeployment,
3399
- progressOptions
3400
- );
3401
- return;
3402
- }
3403
- }
3404
- }
3405
- if (finalDeployment.buildLogs) {
3406
- console.log(source_default.gray("\nBuild logs:"));
3407
- try {
3408
- const logs = finalDeployment.buildLogs.split("\n").filter((l) => l.trim());
3409
- for (const log of logs) {
3410
- try {
3411
- const logData = JSON.parse(log);
3412
- if (logData.line) {
3413
- console.log(source_default.gray(` ${logData.line}`));
3414
- }
3415
- } catch {
3416
- console.log(source_default.gray(` ${log}`));
3417
- }
3418
- }
3419
- } catch {
3420
- console.log(source_default.gray(finalDeployment.buildLogs));
3258
+ console.log(source_default.gray(" Details: " + dep.error));
3259
+ } else {
3260
+ console.log(source_default.red("Error: ") + dep.error);
3421
3261
  }
3422
3262
  }
3423
3263
  process.exit(1);
3424
- } else if (finalDeployment.status === "building") {
3264
+ } else if (dep.status === "building" || dep.status === "pending") {
3425
3265
  startSpinner("Building and deploying...");
3426
- checkCount++;
3427
3266
  delay = Math.min(delay * 1.2, maxDelay);
3428
3267
  } else {
3429
- console.log(
3430
- source_default.yellow("\u26A0\uFE0F Deployment status: ") + finalDeployment.status
3431
- );
3268
+ stopSpinner();
3269
+ console.log(source_default.yellow("\u26A0\uFE0F Deployment status: ") + dep.status);
3432
3270
  return;
3433
3271
  }
3434
3272
  }
3435
3273
  stopSpinner();
3436
3274
  console.log(source_default.yellow("\u26A0\uFE0F Deployment is taking longer than expected."));
3437
3275
  console.log(
3438
- source_default.gray("Check status with: ") + source_default.white(`mcp-use status ${deployment.id}`)
3276
+ source_default.gray("Check status with: ") + source_default.white(`mcp-use deployments get ${deploymentId}`)
3439
3277
  );
3440
3278
  }
3441
3279
  async function checkRepoAccess(api, owner, repo) {
3442
3280
  try {
3443
- const reposResponse = await api.getGitHubRepos(true);
3444
- const repoFullName = `${owner}/${repo}`;
3445
- return reposResponse.repos.some((r) => r.full_name === repoFullName);
3446
- } catch (error) {
3447
- 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 {
3448
3284
  return false;
3449
3285
  }
3450
3286
  }
3451
- var GITHUB_SETUP_POLL_INTERVAL_MS = 2e3;
3452
- var GITHUB_SETUP_POLL_MAX_MS = 12e4;
3453
- async function waitForGitHubSetupAfterBrowser(api, repoName, yes) {
3454
- if (!yes) {
3455
- console.log(source_default.gray("Waiting for GitHub configuration..."));
3456
- await prompt(
3457
- source_default.white("Press Enter when you've completed the GitHub setup..."),
3458
- "y"
3459
- );
3460
- return;
3461
- }
3462
- console.log(
3463
- source_default.gray(
3464
- "Waiting for GitHub configuration (polling every 2s, up to 2 min)..."
3465
- )
3466
- );
3467
- const deadline = Date.now() + GITHUB_SETUP_POLL_MAX_MS;
3468
- while (Date.now() < deadline) {
3469
- try {
3470
- const status = await api.getGitHubConnectionStatus();
3471
- if (!status.is_connected) {
3472
- await new Promise((r) => setTimeout(r, GITHUB_SETUP_POLL_INTERVAL_MS));
3473
- continue;
3474
- }
3475
- if (repoName) {
3476
- const parts = repoName.split("/");
3477
- const owner = parts[0];
3478
- const repo = parts[1];
3479
- if (owner && repo && await checkRepoAccess(api, owner, repo)) {
3480
- return;
3481
- }
3482
- } else {
3483
- return;
3484
- }
3485
- } catch {
3486
- }
3487
- await new Promise((r) => setTimeout(r, GITHUB_SETUP_POLL_INTERVAL_MS));
3488
- }
3489
- console.log(
3490
- source_default.yellow(
3491
- "\u26A0\uFE0F Timed out waiting for GitHub setup. Continuing with verification..."
3492
- )
3493
- );
3494
- }
3495
- async function promptGitHubInstallation(api, reason, repoName, opts) {
3496
- const yes = !!opts?.yes;
3497
- console.log();
3498
- if (reason === "not_connected") {
3499
- console.log(source_default.yellow("\u26A0\uFE0F GitHub account not connected"));
3500
- console.log(
3501
- source_default.white("Deployments require a connected GitHub account.\n")
3502
- );
3503
- } else {
3504
- console.log(
3505
- source_default.yellow("\u26A0\uFE0F GitHub App doesn't have access to this repository")
3506
- );
3507
- console.log(
3508
- source_default.white(
3509
- `The GitHub App needs permission to access ${source_default.cyan(repoName || "this repository")}.
3510
- `
3511
- )
3287
+ async function promptGitHubInstallation(api, reason, repoName, opts) {
3288
+ const yes = !!opts?.yes;
3289
+ console.log();
3290
+ if (reason === "not_connected") {
3291
+ console.log(source_default.yellow("\u26A0\uFE0F GitHub account not connected"));
3292
+ console.log(
3293
+ source_default.white("Deployments require a connected GitHub account.\n")
3294
+ );
3295
+ } else {
3296
+ console.log(
3297
+ source_default.yellow("\u26A0\uFE0F GitHub App doesn't have access to this repository")
3298
+ );
3299
+ console.log(
3300
+ source_default.white(
3301
+ `The GitHub App needs permission to access ${source_default.cyan(repoName || "this repository")}.
3302
+ `
3303
+ )
3512
3304
  );
3513
3305
  }
3514
3306
  const shouldInstall = yes ? true : await prompt(
@@ -3517,96 +3309,48 @@ async function promptGitHubInstallation(api, reason, repoName, opts) {
3517
3309
  ),
3518
3310
  "y"
3519
3311
  );
3520
- if (!shouldInstall) {
3521
- return false;
3522
- }
3312
+ if (!shouldInstall) return false;
3523
3313
  try {
3524
- const appName = process.env.MCP_GITHUB_APP_NAME || "mcp-use";
3525
- const installUrl = reason === "not_connected" ? `https://github.com/apps/${appName}/installations/new` : `https://github.com/settings/installations`;
3526
- console.log(
3527
- source_default.cyan(
3528
- `
3529
- Opening browser to ${reason === "not_connected" ? "install" : "configure"} GitHub App...`
3530
- )
3531
- );
3314
+ const appName = await api.getGitHubAppName();
3315
+ const installUrl = `https://github.com/apps/${appName}/installations/new`;
3316
+ console.log(source_default.cyan(`
3317
+ Opening browser...`));
3532
3318
  console.log(source_default.gray(`URL: ${installUrl}
3533
3319
  `));
3534
3320
  if (reason === "no_access") {
3535
- console.log(source_default.white("Please:"));
3536
3321
  console.log(
3537
- 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")
3538
3323
  );
3539
- console.log(source_default.cyan(" 2. Click 'Configure'"));
3324
+ } else {
3540
3325
  console.log(
3541
- source_default.cyan(
3542
- ` 3. Grant access to ${source_default.bold(repoName || "your repository")}`
3543
- )
3326
+ source_default.white("Complete the GitHub App installation, then return here.\n")
3544
3327
  );
3545
- console.log(source_default.cyan(" 4. Save your changes"));
3546
- console.log(source_default.cyan(" 5. Return here when done\n"));
3547
- } else {
3548
- console.log(source_default.white("Please:"));
3549
- console.log(source_default.cyan(" 1. Select the repositories to grant access"));
3550
- if (repoName) {
3551
- console.log(
3552
- source_default.cyan(` 2. Make sure to include ${source_default.bold(repoName)}`)
3553
- );
3554
- console.log(source_default.cyan(" 3. Complete the installation"));
3555
- } else {
3556
- console.log(source_default.cyan(" 2. Complete the installation"));
3557
- }
3558
- console.log();
3559
3328
  }
3560
3329
  await open_default(installUrl);
3561
- await waitForGitHubSetupAfterBrowser(api, repoName, yes);
3562
- console.log(source_default.gray("Verifying GitHub connection..."));
3563
- let verified = false;
3564
- try {
3565
- const status = await api.getGitHubConnectionStatus();
3566
- if (!status.is_connected) {
3567
- console.log(source_default.yellow("\u26A0\uFE0F GitHub connection not detected."));
3568
- } else if (repoName) {
3569
- const [owner, repo] = repoName.split("/");
3570
- console.log(source_default.gray(`Checking access to ${repoName}...`));
3571
- const hasAccess = await checkRepoAccess(api, owner, repo);
3572
- if (!hasAccess) {
3573
- console.log(
3574
- source_default.yellow(
3575
- `\u26A0\uFE0F The GitHub App may not have access to ${source_default.cyan(repoName)} yet`
3576
- )
3577
- );
3578
- } else {
3579
- console.log(source_default.green(`\u2713 Repository ${repoName} is accessible!
3580
- `));
3581
- 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 {
3582
3345
  }
3583
- } else {
3584
- console.log(source_default.green("\u2713 GitHub connected successfully!\n"));
3585
- verified = true;
3586
3346
  }
3587
- } catch (error) {
3588
- console.log(
3589
- source_default.yellow("\u26A0\uFE0F Could not verify GitHub connection (API issue)")
3590
- );
3591
- }
3592
- if (!verified) {
3593
- console.log(
3594
- source_default.gray(
3595
- "\nNote: If you completed the GitHub setup, the deployment may work now.\n"
3596
- )
3597
- );
3598
3347
  }
3599
3348
  return true;
3600
- } catch (error) {
3601
- console.log(
3602
- source_default.yellow("\n\u26A0\uFE0F Unable to open GitHub installation automatically")
3603
- );
3349
+ } catch {
3350
+ console.log(source_default.yellow("\n\u26A0\uFE0F Unable to open browser automatically"));
3604
3351
  console.log(
3605
3352
  source_default.white("Please visit: ") + source_default.cyan("https://manufact.com/cloud/settings")
3606
3353
  );
3607
- console.log(
3608
- source_default.gray("Then connect your GitHub account and try again.\n")
3609
- );
3610
3354
  return false;
3611
3355
  }
3612
3356
  }
@@ -3614,47 +3358,139 @@ async function deployCommand(options) {
3614
3358
  try {
3615
3359
  const cwd = process.cwd();
3616
3360
  if (!await isLoggedIn()) {
3617
- console.log(source_default.red("\u2717 You are not logged in."));
3361
+ console.log(source_default.cyan.bold("Welcome to Manufact Cloud!\n"));
3618
3362
  if (options.yes) {
3619
3363
  console.log(
3620
- source_default.gray(
3621
- "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."
3622
3366
  )
3623
3367
  );
3624
3368
  process.exit(1);
3625
3369
  }
3626
3370
  const shouldLogin = await prompt(
3627
- 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): "),
3628
3372
  "y"
3629
3373
  );
3630
- if (shouldLogin) {
3631
- try {
3632
- await loginCommand({ silent: false });
3633
- if (!await isLoggedIn()) {
3634
- console.log(
3635
- source_default.red("\u2717 Login verification failed. Please try again.")
3636
- );
3637
- process.exit(1);
3638
- }
3639
- console.log(source_default.gray("\nContinuing with deployment...\n"));
3640
- } catch (error) {
3641
- console.error(
3642
- source_default.red.bold("\u2717 Login failed:"),
3643
- source_default.red(error instanceof Error ? error.message : "Unknown error")
3644
- );
3645
- process.exit(1);
3646
- }
3647
- } else {
3374
+ if (!shouldLogin) {
3648
3375
  console.log(
3649
3376
  source_default.gray(
3650
3377
  "Run " + source_default.white("npx mcp-use login") + " to get started."
3651
3378
  )
3652
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) {
3653
3471
  console.log(source_default.gray("Deployment cancelled."));
3654
3472
  process.exit(0);
3655
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);
3656
3489
  }
3657
- 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"));
3658
3494
  const projectDir = options.rootDir ? import_node_path5.default.resolve(cwd, options.rootDir) : cwd;
3659
3495
  if (options.rootDir) {
3660
3496
  try {
@@ -3665,381 +3501,383 @@ async function deployCommand(options) {
3665
3501
  );
3666
3502
  process.exit(1);
3667
3503
  }
3668
- console.log(source_default.gray(` Root dir: `) + source_default.cyan(options.rootDir));
3669
3504
  }
3670
3505
  const isMcp = await isMcpProject(projectDir);
3671
- if (!isMcp) {
3506
+ if (!isMcp && !options.yes) {
3672
3507
  console.log(
3673
- source_default.yellow(
3674
- "\u26A0\uFE0F This doesn't appear to be an MCP server project (no mcp-use or @modelcontextprotocol/sdk dependency found)."
3675
- )
3508
+ source_default.yellow("\u26A0\uFE0F This doesn't look like an MCP server project.")
3509
+ );
3510
+ const shouldContinue = await prompt(
3511
+ source_default.white("Continue anyway? (y/n): ")
3676
3512
  );
3677
- if (!options.yes) {
3678
- const shouldContinue = await prompt(
3679
- source_default.white("Continue anyway? (y/n): ")
3513
+ if (!shouldContinue) {
3514
+ process.exit(0);
3515
+ }
3516
+ console.log();
3517
+ }
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"
3680
3530
  );
3681
- if (!shouldContinue) {
3682
- 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
+ );
3683
3537
  process.exit(0);
3684
3538
  }
3685
3539
  }
3686
- console.log();
3687
- }
3688
- const gitInfo = await getGitInfo(cwd);
3689
- if (!gitInfo.isGitRepo) {
3690
- console.log(source_default.red("\u2717 Not a git repository\n"));
3691
- console.log(source_default.white("To deploy, initialize git and push to GitHub:"));
3692
- console.log(source_default.gray(" 1. Initialize git:"));
3693
- console.log(source_default.cyan(" git init\n"));
3694
- console.log(source_default.gray(" 2. Create a GitHub repository at:"));
3695
- console.log(source_default.cyan(" https://github.com/new\n"));
3696
- console.log(source_default.gray(" 3. Add the remote and push:"));
3697
- console.log(source_default.cyan(" git remote add origin <your-github-url>"));
3698
- console.log(source_default.cyan(" git add ."));
3699
- console.log(source_default.cyan(" git commit -m 'Initial commit'"));
3700
- console.log(source_default.cyan(" git push -u origin main\n"));
3701
- process.exit(1);
3702
- }
3703
- if (!gitInfo.remoteUrl) {
3704
- console.log(source_default.red("\u2717 No git remote configured\n"));
3705
- console.log(source_default.white("Add a GitHub remote:"));
3706
- console.log(source_default.cyan(" git remote add origin <your-github-url>\n"));
3707
- process.exit(1);
3708
- }
3709
- if (!isGitHubUrl(gitInfo.remoteUrl)) {
3540
+ const defaultIdx = installations.findIndex(
3541
+ (i) => i.account_type === "Organization"
3542
+ );
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
+ );
3612
+ process.exit(0);
3613
+ }
3614
+ const repoName = options.yes ? projectName2 : await promptText(source_default.gray("Repository name:"), projectName2);
3615
+ await ensureGitignore(cwd);
3616
+ console.log(
3617
+ source_default.gray(
3618
+ `Creating repository on ${repoInstallation.account_login}...`
3619
+ )
3620
+ );
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"
3639
+ );
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)) {
3710
3646
  console.log(source_default.red("\u2717 Remote is not a GitHub repository"));
3711
3647
  console.log(source_default.yellow(` Current remote: ${gitInfo.remoteUrl}
3712
3648
  `));
3713
- console.log(source_default.white("Please add a GitHub remote to deploy."));
3714
3649
  process.exit(1);
3715
- }
3716
- if (!gitInfo.owner || !gitInfo.repo) {
3650
+ } else if (!gitInfo.owner || !gitInfo.repo) {
3717
3651
  console.log(source_default.red("\u2717 Could not parse GitHub repository information"));
3718
3652
  process.exit(1);
3719
- }
3720
- if (gitInfo.hasUncommittedChanges) {
3721
- console.log(source_default.yellow("\u26A0\uFE0F You have uncommitted changes\n"));
3722
- console.log(source_default.white("Deployments use the code pushed to GitHub."));
3723
- console.log(
3724
- source_default.white(
3725
- "Local changes will not be included until you commit and push.\n"
3726
- )
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"
3662
+ );
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
+ }
3672
+ }
3673
+ }
3674
+ console.log(source_default.gray("Checking repository access..."));
3675
+ const hasAccess = await checkRepoAccess(
3676
+ api,
3677
+ gitInfo.owner,
3678
+ gitInfo.repo
3727
3679
  );
3728
- if (!options.yes) {
3729
- const shouldContinue = await prompt(
3730
- source_default.white("Continue with deployment from GitHub? (y/n): ")
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(
3687
+ api,
3688
+ "no_access",
3689
+ repoFullName,
3690
+ { yes: options.yes, installationId: githubInstallationId }
3731
3691
  );
3732
- if (!shouldContinue) {
3733
- console.log(source_default.gray("Deployment cancelled."));
3692
+ if (!configured) {
3734
3693
  process.exit(0);
3735
3694
  }
3695
+ const retry = await checkRepoAccess(api, gitInfo.owner, gitInfo.repo);
3696
+ if (!retry) {
3697
+ const appName = await api.getGitHubAppName();
3698
+ console.log(
3699
+ source_default.red(
3700
+ `
3701
+ \u2717 Repository ${source_default.cyan(repoFullName)} is still not accessible.`
3702
+ )
3703
+ );
3704
+ console.log(
3705
+ source_default.cyan(
3706
+ ` https://github.com/apps/${appName}/installations/new
3707
+ `
3708
+ )
3709
+ );
3710
+ process.exit(1);
3711
+ }
3736
3712
  }
3737
- console.log();
3738
- }
3739
- console.log(source_default.white("GitHub repository detected:"));
3740
- console.log(
3741
- source_default.gray(` Repository: `) + source_default.cyan(`${gitInfo.owner}/${gitInfo.repo}`)
3742
- );
3743
- console.log(
3744
- source_default.gray(` Branch: `) + source_default.cyan(gitInfo.branch || "main")
3745
- );
3746
- if (gitInfo.commitSha) {
3747
- console.log(
3748
- source_default.gray(` Commit: `) + source_default.gray(gitInfo.commitSha.substring(0, 7))
3749
- );
3750
- }
3751
- if (gitInfo.commitMessage) {
3752
- console.log(
3753
- source_default.gray(` Message: `) + source_default.gray(gitInfo.commitMessage.split("\n")[0])
3754
- );
3755
- }
3756
- console.log();
3757
- if (!options.yes) {
3758
- const shouldDeploy = await prompt(
3759
- source_default.white(
3760
- `Deploy from GitHub repository ${gitInfo.owner}/${gitInfo.repo}? (Y/n): `
3761
- ),
3762
- "y"
3763
- );
3764
- if (!shouldDeploy) {
3765
- console.log(source_default.gray("Deployment cancelled."));
3766
- process.exit(0);
3767
- }
3713
+ console.log(source_default.green("\u2713 Repository access confirmed"));
3768
3714
  }
3769
3715
  const projectName = options.name || await getProjectName(projectDir);
3770
- const runtime = options.runtime || await detectRuntime(projectDir);
3771
3716
  const port = options.port || 3e3;
3772
3717
  const buildCommand = await detectBuildCommand(projectDir);
3773
3718
  const startCommand = await detectStartCommand(projectDir);
3719
+ const runtime = options.runtime || await detectRuntime(projectDir);
3774
3720
  const envVars = await buildEnvVars(options);
3775
3721
  console.log();
3776
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));
3777
3725
  console.log(source_default.gray(` Name: `) + source_default.cyan(projectName));
3778
3726
  console.log(source_default.gray(` Runtime: `) + source_default.cyan(runtime));
3779
3727
  console.log(source_default.gray(` Port: `) + source_default.cyan(port));
3780
- if (options.rootDir) {
3728
+ if (options.region)
3729
+ console.log(source_default.gray(` Region: `) + source_default.cyan(options.region));
3730
+ if (options.buildCommand)
3781
3731
  console.log(
3782
- source_default.gray(` Root dir: `) + source_default.cyan(options.rootDir)
3732
+ source_default.gray(` Build command: `) + source_default.cyan(options.buildCommand)
3783
3733
  );
3784
- }
3785
- if (buildCommand) {
3786
- console.log(source_default.gray(` Build command: `) + source_default.cyan(buildCommand));
3787
- }
3788
- if (startCommand) {
3789
- console.log(source_default.gray(` Start command: `) + source_default.cyan(startCommand));
3790
- }
3791
- if (envVars && Object.keys(envVars).length > 0) {
3734
+ else if (buildCommand)
3792
3735
  console.log(
3793
- source_default.gray(` Environment: `) + source_default.cyan(`${Object.keys(envVars).length} variable(s)`)
3736
+ source_default.gray(` Build command: `) + source_default.gray(buildCommand + " (auto-detected)")
3794
3737
  );
3738
+ if (options.startCommand)
3795
3739
  console.log(
3796
- source_default.gray(` `) + source_default.gray(Object.keys(envVars).join(", "))
3740
+ source_default.gray(` Start command: `) + source_default.cyan(options.startCommand)
3797
3741
  );
3798
- }
3799
- console.log();
3800
- const api = await McpUseAPI.create();
3801
- if (options.org) {
3802
- try {
3803
- const authInfo = await api.testAuth();
3804
- const match = (authInfo.profiles ?? []).find(
3805
- (p) => p.slug === options.org || p.id === options.org || p.profile_name.toLowerCase() === options.org.toLowerCase()
3806
- );
3807
- if (match) {
3808
- api.setProfileId(match.id);
3809
- const slug = match.slug ? source_default.gray(` (${match.slug})`) : "";
3810
- console.log(
3811
- source_default.gray("Organization: ") + source_default.cyan(match.profile_name) + slug
3812
- );
3813
- } else {
3814
- console.error(
3815
- source_default.red(
3816
- `\u2717 Organization "${options.org}" not found. Run ${source_default.white("npx mcp-use org list")} to see available organizations.`
3817
- )
3818
- );
3819
- process.exit(1);
3820
- }
3821
- } catch (error) {
3822
- console.error(
3823
- source_default.red("\u2717 Failed to resolve organization:"),
3824
- source_default.red(error instanceof Error ? error.message : "Unknown error")
3825
- );
3826
- process.exit(1);
3827
- }
3828
- }
3829
- let githubVerified = false;
3830
- try {
3831
- console.log(source_default.gray(`[DEBUG] API URL: ${api.baseUrl}`));
3832
- const connectionStatus = await api.getGitHubConnectionStatus();
3833
- if (!connectionStatus.is_connected) {
3834
- const repoFullName = `${gitInfo.owner}/${gitInfo.repo}`;
3835
- const installed = await promptGitHubInstallation(
3836
- api,
3837
- "not_connected",
3838
- repoFullName,
3839
- { yes: options.yes }
3840
- );
3841
- if (!installed) {
3842
- console.log(source_default.gray("Deployment cancelled."));
3843
- process.exit(0);
3844
- }
3845
- const retryStatus = await api.getGitHubConnectionStatus();
3846
- if (!retryStatus.is_connected) {
3847
- console.log(
3848
- source_default.red("\n\u2717 GitHub connection could not be verified.")
3849
- );
3850
- console.log(
3851
- source_default.gray("Please try connecting GitHub from the web UI:")
3852
- );
3853
- console.log(source_default.cyan(" https://manufact.com/cloud/settings\n"));
3854
- process.exit(1);
3855
- }
3856
- githubVerified = true;
3857
- } else if (gitInfo.owner && gitInfo.repo) {
3858
- console.log(source_default.gray("Checking repository access..."));
3859
- const hasAccess = await checkRepoAccess(
3860
- api,
3861
- gitInfo.owner,
3862
- gitInfo.repo
3863
- );
3864
- if (!hasAccess) {
3865
- const repoFullName = `${gitInfo.owner}/${gitInfo.repo}`;
3866
- console.log(
3867
- source_default.yellow(
3868
- `\u26A0\uFE0F GitHub App doesn't have access to ${source_default.cyan(repoFullName)}`
3869
- )
3870
- );
3871
- const configured = await promptGitHubInstallation(
3872
- api,
3873
- "no_access",
3874
- repoFullName,
3875
- { yes: options.yes }
3876
- );
3877
- if (!configured) {
3878
- console.log(source_default.gray("Deployment cancelled."));
3879
- process.exit(0);
3880
- }
3881
- const hasAccessRetry = await checkRepoAccess(
3882
- api,
3883
- gitInfo.owner,
3884
- gitInfo.repo
3885
- );
3886
- if (!hasAccessRetry) {
3887
- console.log(
3888
- source_default.red(
3889
- `
3890
- \u2717 Repository ${source_default.cyan(repoFullName)} is still not accessible.`
3891
- )
3892
- );
3893
- console.log(
3894
- source_default.gray(
3895
- "Please make sure the GitHub App has access to this repository."
3896
- )
3897
- );
3898
- console.log(
3899
- source_default.cyan(" https://github.com/settings/installations\n")
3900
- );
3901
- process.exit(1);
3902
- }
3903
- githubVerified = true;
3904
- } else {
3905
- console.log(source_default.green("\u2713 Repository access confirmed"));
3906
- githubVerified = true;
3907
- }
3908
- }
3909
- } catch (error) {
3910
- console.log(source_default.red("\u2717 Could not verify GitHub connection"));
3911
- console.log(
3912
- source_default.gray(
3913
- "Error: " + (error instanceof Error ? error.message : "Unknown error")
3914
- )
3915
- );
3916
- console.log(source_default.gray("\nPlease ensure:"));
3742
+ else if (startCommand)
3917
3743
  console.log(
3918
- source_default.cyan(
3919
- " 1. You have connected GitHub at https://manufact.com/cloud/settings"
3920
- )
3744
+ source_default.gray(` Start command: `) + source_default.gray(startCommand + " (auto-detected)")
3921
3745
  );
3746
+ if (Object.keys(envVars).length > 0) {
3922
3747
  console.log(
3923
- source_default.cyan(" 2. The GitHub App has access to your repository")
3748
+ source_default.gray(` Environment: `) + source_default.cyan(`${Object.keys(envVars).length} variable(s)`)
3924
3749
  );
3925
- console.log(source_default.cyan(" 3. Your internet connection is stable\n"));
3926
- process.exit(1);
3927
3750
  }
3928
- if (!githubVerified) {
3929
- console.log(
3930
- source_default.red("\n\u2717 GitHub verification required for this deployment")
3931
- );
3932
- process.exit(1);
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
+ }
3933
3758
  }
3934
3759
  const existingLink = !options.new ? await getProjectLink(cwd) : null;
3935
- const serverId = existingLink?.serverId;
3936
- if (existingLink) {
3760
+ let serverId = existingLink?.serverId;
3761
+ if (existingLink && serverId) {
3937
3762
  try {
3938
- const existingDeployment = await api.getDeployment(
3939
- existingLink.deploymentId
3940
- );
3941
- if (existingDeployment && existingDeployment.status !== "failed") {
3942
- 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`));
3943
3766
  console.log(source_default.gray(` Redeploying to maintain the same URL...`));
3944
- console.log(
3945
- source_default.cyan(` URL: ${getMcpServerUrl(existingDeployment)}
3946
- `)
3947
- );
3948
- const redeploymentConfig = {
3949
- buildCommand,
3950
- startCommand,
3951
- ...options.port !== void 0 ? { port: options.port } : {},
3952
- env: Object.keys(envVars).length > 0 ? envVars : void 0,
3953
- rootDir: options.rootDir || void 0
3954
- };
3955
- const deployment2 = await api.redeployDeployment(
3956
- existingLink.deploymentId,
3957
- redeploymentConfig
3958
- );
3767
+ console.log(source_default.cyan(` URL: ${getMcpServerUrl(existingDep)}
3768
+ `));
3769
+ const newDep = await api.createDeployment({
3770
+ serverId,
3771
+ branch,
3772
+ trigger: "redeploy"
3773
+ });
3959
3774
  await saveProjectLink(cwd, {
3960
3775
  ...existingLink,
3961
- linkedAt: (/* @__PURE__ */ new Date()).toISOString()
3962
- });
3963
- await displayDeploymentProgress(api, deployment2, {
3964
- yes: options.yes
3776
+ linkedAt: (/* @__PURE__ */ new Date()).toISOString(),
3777
+ deploymentId: newDep.id
3965
3778
  });
3966
- if (options.open && deployment2.domain) {
3967
- console.log();
3968
- console.log(source_default.gray("Opening deployment in browser..."));
3969
- await open_default(`https://${deployment2.domain}`);
3970
- }
3779
+ console.log(
3780
+ source_default.green("\u2713 Deployment created: ") + source_default.gray(newDep.id)
3781
+ );
3782
+ await displayDeploymentProgress(api, newDep.id, { yes: options.yes });
3971
3783
  return;
3972
- } else {
3784
+ }
3785
+ } catch (err) {
3786
+ const is404 = err?.status === 404 || (err?.message ?? "").includes("404");
3787
+ if (is404) {
3973
3788
  console.log(
3974
- source_default.yellow(
3975
- `\u26A0\uFE0F Linked deployment not found or failed, creating new one...`
3976
- )
3789
+ source_default.yellow("\u26A0\uFE0F Previously linked server no longer exists.\n")
3977
3790
  );
3978
- if (serverId) {
3979
- console.log(
3980
- source_default.gray(` Will reuse existing server: ${serverId}`)
3791
+ if (!options.yes) {
3792
+ const shouldRecreate = await prompt(
3793
+ source_default.white("Create a new server and deploy? (Y/n): "),
3794
+ "y"
3981
3795
  );
3796
+ if (!shouldRecreate) {
3797
+ console.log(source_default.gray("Deployment cancelled."));
3798
+ process.exit(0);
3799
+ }
3982
3800
  }
3801
+ serverId = void 0;
3983
3802
  }
3984
- } catch (error) {
3985
- console.log(
3986
- source_default.yellow(`\u26A0\uFE0F Linked deployment not found, creating new one...`)
3987
- );
3988
- if (serverId) {
3989
- console.log(source_default.gray(` Will reuse existing server: ${serverId}`));
3803
+ }
3804
+ }
3805
+ let deploymentId;
3806
+ if (serverId) {
3807
+ console.log(source_default.gray("Creating deployment..."));
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;
3990
3826
  }
3991
3827
  }
3992
3828
  }
3993
- const deploymentRequest = {
3994
- name: projectName,
3995
- source: {
3829
+ if (!serverId) {
3830
+ const orgId = await api.resolveOrganizationId();
3831
+ console.log(source_default.gray("Creating server and deployment..."));
3832
+ const serverResult = await api.createServer({
3996
3833
  type: "github",
3997
- repo: `${gitInfo.owner}/${gitInfo.repo}`,
3998
- branch: gitInfo.branch || "main",
3999
- rootDir: options.rootDir || void 0,
4000
- runtime,
3834
+ organizationId: orgId,
3835
+ installationId: installationDbId,
3836
+ name: projectName,
3837
+ repoFullName,
3838
+ branch,
3839
+ rootDir: options.rootDir,
4001
3840
  port,
4002
- buildCommand,
4003
- startCommand,
4004
- env: Object.keys(envVars).length > 0 ? envVars : void 0
4005
- },
4006
- healthCheckPath: "/healthz",
4007
- serverId
4008
- };
4009
- if (!options.org) {
4010
- try {
4011
- const config = await readConfig();
4012
- if (config.profileName) {
4013
- const slug = config.profileSlug ? source_default.gray(` (${config.profileSlug})`) : "";
4014
- console.log(
4015
- source_default.gray("Organization: ") + source_default.cyan(config.profileName) + slug
4016
- );
4017
- }
4018
- } catch {
3841
+ env: Object.keys(envVars).length > 0 ? envVars : void 0,
3842
+ region: options.region,
3843
+ buildCommand: options.buildCommand,
3844
+ startCommand: options.startCommand
3845
+ });
3846
+ deploymentId = serverResult.deploymentId ?? "";
3847
+ if (!deploymentId) {
3848
+ console.log(
3849
+ source_default.green("\u2713 Server created: ") + source_default.gray(serverResult.server.id)
3850
+ );
3851
+ console.log(source_default.yellow("\u26A0\uFE0F No deployment was triggered."));
3852
+ return;
4019
3853
  }
3854
+ await saveProjectLink(cwd, {
3855
+ deploymentId,
3856
+ deploymentName: projectName,
3857
+ linkedAt: (/* @__PURE__ */ new Date()).toISOString(),
3858
+ serverId: serverResult.server.id
3859
+ });
3860
+ console.log(
3861
+ source_default.gray(` Linked to this project (stored in .mcp-use/project.json)`)
3862
+ );
3863
+ console.log(source_default.gray(` Future deploys will reuse the same URL
3864
+ `));
3865
+ }
3866
+ if (!deploymentId) {
3867
+ console.log(source_default.red("\u2717 No deployment was created."));
3868
+ process.exit(1);
4020
3869
  }
4021
- console.log(source_default.gray("Creating deployment..."));
4022
- const deployment = await api.createDeployment(deploymentRequest);
4023
- console.log(
4024
- source_default.green("\u2713 Deployment created: ") + source_default.gray(deployment.id)
4025
- );
4026
- await saveProjectLink(cwd, {
4027
- deploymentId: deployment.id,
4028
- deploymentName: projectName,
4029
- deploymentUrl: deployment.domain,
4030
- linkedAt: (/* @__PURE__ */ new Date()).toISOString(),
4031
- serverId: deployment.serverId
4032
- });
4033
3870
  console.log(
4034
- source_default.gray(` Linked to this project (stored in .mcp-use/project.json)`)
3871
+ source_default.green("\u2713 Deployment created: ") + source_default.gray(deploymentId)
4035
3872
  );
4036
- console.log(source_default.gray(` Future deploys will reuse the same URL
4037
- `));
4038
- await displayDeploymentProgress(api, deployment, { yes: options.yes });
4039
- if (options.open && deployment.domain) {
4040
- console.log();
4041
- console.log(source_default.gray("Opening deployment in browser..."));
4042
- await open_default(`https://${deployment.domain}`);
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
+ }
4043
3881
  }
4044
3882
  } catch (error) {
4045
3883
  console.error(
@@ -4115,19 +3953,19 @@ async function listDeploymentsCommand() {
4115
3953
  );
4116
3954
  console.log(
4117
3955
  source_default.white.bold(
4118
- `${"ID".padEnd(40)} ${"NAME".padEnd(25)} ${"STATUS".padEnd(12)} ${"DOMAIN".padEnd(35)} ${"CREATED"}`
3956
+ `${"ID".padEnd(40)} ${"NAME".padEnd(25)} ${"STATUS".padEnd(12)} ${"MCP URL".padEnd(45)} ${"CREATED"}`
4119
3957
  )
4120
3958
  );
4121
- console.log(source_default.gray("\u2500".repeat(130)));
3959
+ console.log(source_default.gray("\u2500".repeat(140)));
4122
3960
  for (const deployment of sortedDeployments) {
4123
3961
  const id = formatId(deployment.id).padEnd(40);
4124
3962
  const name = deployment.name.substring(0, 24).padEnd(25);
4125
3963
  const statusColor = getStatusColor(deployment.status);
4126
3964
  const status = statusColor(deployment.status.padEnd(12));
4127
- const domain = (deployment.domain || "-").substring(0, 34).padEnd(35);
3965
+ const mcpUrl = (deployment.mcpUrl || "-").substring(0, 44).padEnd(45);
4128
3966
  const created = formatRelativeTime(deployment.createdAt);
4129
3967
  console.log(
4130
- `${source_default.gray(id)} ${name} ${status} ${source_default.cyan(domain)} ${source_default.gray(created)}`
3968
+ `${source_default.gray(id)} ${name} ${status} ${source_default.cyan(mcpUrl)} ${source_default.gray(created)}`
4131
3969
  );
4132
3970
  }
4133
3971
  console.log();
@@ -4159,31 +3997,28 @@ async function getDeploymentCommand(deploymentId) {
4159
3997
  console.log(
4160
3998
  source_default.white("Status: ") + statusColor(deployment.status)
4161
3999
  );
4162
- if (deployment.domain) {
4000
+ if (deployment.serverId) {
4163
4001
  console.log(
4164
- source_default.white("Domain: ") + source_default.cyan(`https://${deployment.domain}`)
4002
+ source_default.white("Server ID: ") + source_default.gray(deployment.serverId)
4165
4003
  );
4166
4004
  }
4167
- if (deployment.customDomain) {
4168
- console.log(
4169
- source_default.white("Custom Domain: ") + source_default.cyan(`https://${deployment.customDomain}`)
4170
- );
4005
+ const mcpUrl = getMcpServerUrl(deployment);
4006
+ if (mcpUrl) {
4007
+ console.log(source_default.white("MCP URL: ") + source_default.cyan(mcpUrl));
4171
4008
  }
4172
- console.log(
4173
- source_default.white("Source: ") + source_default.gray(deployment.source.type)
4174
- );
4175
- if (deployment.source.type === "github") {
4009
+ if (deployment.gitBranch) {
4176
4010
  console.log(
4177
- source_default.white("Repository: ") + source_default.gray(deployment.source.repo)
4011
+ source_default.white("Branch: ") + source_default.gray(deployment.gitBranch)
4178
4012
  );
4013
+ }
4014
+ if (deployment.gitCommitSha) {
4179
4015
  console.log(
4180
- source_default.white("Branch: ") + source_default.gray(deployment.source.branch || "main")
4016
+ source_default.white("Commit: ") + source_default.gray(deployment.gitCommitSha.substring(0, 7))
4181
4017
  );
4182
4018
  }
4183
- console.log(source_default.white("Port: ") + source_default.gray(deployment.port));
4184
- console.log(
4185
- source_default.white("Runtime: ") + source_default.gray(deployment.source.runtime || "node")
4186
- );
4019
+ if (deployment.port) {
4020
+ console.log(source_default.white("Port: ") + source_default.gray(deployment.port));
4021
+ }
4187
4022
  if (deployment.provider) {
4188
4023
  console.log(
4189
4024
  source_default.white("Provider: ") + source_default.gray(deployment.provider)
@@ -4195,13 +4030,6 @@ async function getDeploymentCommand(deploymentId) {
4195
4030
  console.log(
4196
4031
  source_default.white("Updated: ") + source_default.gray(formatRelativeTime(deployment.updatedAt))
4197
4032
  );
4198
- if (deployment.source.env && Object.keys(deployment.source.env).length > 0) {
4199
- console.log(source_default.white("\nEnvironment Variables:"));
4200
- for (const [key, value] of Object.entries(deployment.source.env)) {
4201
- const displayValue = key.toLowerCase().includes("key") || key.toLowerCase().includes("secret") || key.toLowerCase().includes("password") || key.toLowerCase().includes("token") ? "***" : value;
4202
- console.log(source_default.gray(` ${key}=`) + source_default.white(displayValue));
4203
- }
4204
- }
4205
4033
  if (deployment.status === "failed" && deployment.error) {
4206
4034
  console.log(source_default.red("\nError:"));
4207
4035
  console.log(source_default.red(` ${deployment.error}`));
@@ -4228,43 +4056,56 @@ async function restartDeploymentCommand(deploymentId, options) {
4228
4056
  }
4229
4057
  const api = await McpUseAPI.create();
4230
4058
  const deployment = await api.getDeployment(deploymentId);
4059
+ if (!deployment.serverId) {
4060
+ console.log(
4061
+ source_default.red("\u2717 Cannot restart: deployment has no linked server.")
4062
+ );
4063
+ process.exit(1);
4064
+ }
4231
4065
  console.log(
4232
4066
  source_default.cyan.bold(`
4233
4067
  \u{1F504} Restarting deployment: ${deployment.name}
4234
4068
  `)
4235
4069
  );
4236
- const redeployedDeployment = await api.redeployDeployment(deploymentId);
4237
- console.log(
4238
- source_default.green("\u2713 Restart initiated: ") + source_default.gray(redeployedDeployment.id)
4239
- );
4070
+ const newDep = await api.createDeployment({
4071
+ serverId: deployment.serverId,
4072
+ trigger: "redeploy"
4073
+ });
4074
+ console.log(source_default.green("\u2713 Restart initiated: ") + source_default.gray(newDep.id));
4240
4075
  if (options.follow) {
4241
- console.log(source_default.gray("\nFollowing deployment logs...\n"));
4242
- try {
4243
- for await (const log of api.streamDeploymentLogs(
4244
- redeployedDeployment.id
4245
- )) {
4246
- try {
4247
- const logData = JSON.parse(log);
4248
- if (logData.line) {
4249
- const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
4250
- const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
4251
- console.log(stepPrefix + levelColor(logData.line));
4076
+ console.log(source_default.gray("\nFollowing build logs...\n"));
4077
+ let offset = 0;
4078
+ let terminal = false;
4079
+ while (!terminal) {
4080
+ await new Promise((r) => setTimeout(r, 2e3));
4081
+ try {
4082
+ const resp = await api.getDeploymentBuildLogs(newDep.id, offset);
4083
+ if (resp.logs.length > 0) {
4084
+ const lines = resp.logs.split("\n").filter((l) => l.trim());
4085
+ for (const line of lines) {
4086
+ try {
4087
+ const logData = JSON.parse(line);
4088
+ if (logData.line) {
4089
+ const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
4090
+ const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
4091
+ console.log(stepPrefix + levelColor(logData.line));
4092
+ }
4093
+ } catch {
4094
+ console.log(source_default.gray(line));
4095
+ }
4252
4096
  }
4253
- } catch {
4254
- console.log(source_default.gray(log));
4097
+ offset = resp.offset;
4098
+ }
4099
+ if (resp.status === "running" || resp.status === "failed" || resp.status === "stopped") {
4100
+ terminal = true;
4255
4101
  }
4102
+ } catch {
4256
4103
  }
4257
- } catch (error) {
4258
- console.log(
4259
- source_default.gray(
4260
- "\nLog stream ended. Use " + source_default.white(`mcp-use deployments get ${deploymentId}`) + " to check status."
4261
- )
4262
- );
4263
4104
  }
4264
4105
  } else {
4265
4106
  console.log(
4266
4107
  source_default.gray(
4267
- "\nCheck status with: " + source_default.white(`mcp-use deployments get ${deploymentId}`)
4108
+ "\nCheck status with: " + source_default.white(`mcp-use deployments get ${newDep.id}`)
4268
4109
  )
4269
4110
  );
4270
4111
  }
@@ -4298,8 +4139,10 @@ async function deleteDeploymentCommand(deploymentId, options) {
4298
4139
  )
4299
4140
  );
4300
4141
  console.log(source_default.gray(` ID: ${deployment.id}`));
4301
- console.log(source_default.gray(` Domain: ${deployment.domain || "none"}
4142
+ if (deployment.mcpUrl) {
4143
+ console.log(source_default.gray(` URL: ${deployment.mcpUrl}
4302
4144
  `));
4145
+ }
4303
4146
  const confirmed = await prompt2(
4304
4147
  source_default.white("Are you sure you want to delete this deployment? (y/N): ")
4305
4148
  );
@@ -4335,30 +4178,41 @@ async function logsCommand(deploymentId, options) {
4335
4178
  }
4336
4179
  const api = await McpUseAPI.create();
4337
4180
  if (options.follow) {
4338
- console.log(source_default.gray("Streaming logs...\n"));
4339
- try {
4340
- for await (const log of api.streamDeploymentLogs(deploymentId)) {
4341
- try {
4342
- const logData = JSON.parse(log);
4343
- if (logData.line) {
4344
- const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
4345
- const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
4346
- console.log(stepPrefix + levelColor(logData.line));
4181
+ console.log(source_default.gray("Following build logs...\n"));
4182
+ let offset = 0;
4183
+ let terminal = false;
4184
+ while (!terminal) {
4185
+ await new Promise((r) => setTimeout(r, 2e3));
4186
+ try {
4187
+ const resp = await api.getDeploymentBuildLogs(deploymentId, offset);
4188
+ if (resp.logs.length > 0) {
4189
+ const lines = resp.logs.split("\n").filter((l) => l.trim());
4190
+ for (const line of lines) {
4191
+ try {
4192
+ const logData = JSON.parse(line);
4193
+ if (logData.line) {
4194
+ const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
4195
+ const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
4196
+ console.log(stepPrefix + levelColor(logData.line));
4197
+ }
4198
+ } catch {
4199
+ console.log(source_default.gray(line));
4200
+ }
4347
4201
  }
4348
- } catch {
4349
- console.log(source_default.gray(log));
4202
+ offset = resp.offset;
4203
+ }
4204
+ if (resp.status === "running" || resp.status === "failed" || resp.status === "stopped") {
4205
+ terminal = true;
4350
4206
  }
4207
+ } catch {
4351
4208
  }
4352
- } catch (error) {
4353
- console.log(source_default.gray("\nLog stream ended."));
4354
4209
  }
4355
- } else {
4356
- const logs = options.build ? await api.getDeploymentBuildLogs(deploymentId) : await api.getDeploymentLogs(deploymentId);
4210
+ } else if (options.build) {
4211
+ const resp = await api.getDeploymentBuildLogs(deploymentId);
4212
+ const logs = resp.logs;
4357
4213
  if (!logs || logs.trim() === "") {
4358
4214
  console.log(
4359
- source_default.yellow(
4360
- `No ${options.build ? "build " : ""}logs available for this deployment.`
4361
- )
4215
+ source_default.yellow("No build logs available for this deployment.")
4362
4216
  );
4363
4217
  return;
4364
4218
  }
@@ -4375,6 +4229,25 @@ async function logsCommand(deploymentId, options) {
4375
4229
  console.log(source_default.gray(line));
4376
4230
  }
4377
4231
  }
4232
+ } else {
4233
+ const logs = await api.getDeploymentLogs(deploymentId);
4234
+ if (!logs || logs.trim() === "") {
4235
+ console.log(source_default.yellow("No logs available for this deployment."));
4236
+ return;
4237
+ }
4238
+ const logLines = logs.split("\n").filter((l) => l.trim());
4239
+ for (const line of logLines) {
4240
+ try {
4241
+ const logData = JSON.parse(line);
4242
+ if (logData.line) {
4243
+ const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
4244
+ const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
4245
+ console.log(stepPrefix + levelColor(logData.line));
4246
+ }
4247
+ } catch {
4248
+ console.log(source_default.gray(line));
4249
+ }
4250
+ }
4378
4251
  }
4379
4252
  console.log();
4380
4253
  } catch (error) {
@@ -4385,7 +4258,7 @@ async function logsCommand(deploymentId, options) {
4385
4258
  process.exit(1);
4386
4259
  }
4387
4260
  }
4388
- async function listEnvCommand(deploymentId) {
4261
+ async function stopDeploymentCommand(deploymentId) {
4389
4262
  try {
4390
4263
  if (!await isLoggedIn()) {
4391
4264
  console.log(source_default.red("\u2717 You are not logged in."));
@@ -4397,33 +4270,19 @@ async function listEnvCommand(deploymentId) {
4397
4270
  process.exit(1);
4398
4271
  }
4399
4272
  const api = await McpUseAPI.create();
4400
- const deployment = await api.getDeployment(deploymentId);
4401
- console.log(
4402
- source_default.cyan.bold(`
4403
- \u{1F510} Environment Variables: ${deployment.name}
4404
- `)
4405
- );
4406
- if (!deployment.source.env || Object.keys(deployment.source.env).length === 0) {
4407
- console.log(source_default.yellow("No environment variables set."));
4408
- console.log();
4409
- return;
4410
- }
4411
- for (const [key, value] of Object.entries(deployment.source.env)) {
4412
- const displayValue = key.toLowerCase().includes("key") || key.toLowerCase().includes("secret") || key.toLowerCase().includes("password") || key.toLowerCase().includes("token") ? "***" : value;
4413
- console.log(
4414
- source_default.white(key) + source_default.gray("=") + source_default.cyan(displayValue)
4415
- );
4416
- }
4417
- console.log();
4273
+ await api.stopDeployment(deploymentId);
4274
+ console.log(source_default.green.bold(`
4275
+ \u2713 Deployment stopped
4276
+ `));
4418
4277
  } catch (error) {
4419
4278
  console.error(
4420
- source_default.red.bold("\n\u2717 Failed to list environment variables:"),
4279
+ source_default.red.bold("\n\u2717 Failed to stop deployment:"),
4421
4280
  source_default.red(error instanceof Error ? error.message : "Unknown error")
4422
4281
  );
4423
4282
  process.exit(1);
4424
4283
  }
4425
4284
  }
4426
- async function setEnvCommand(deploymentId, envPairs) {
4285
+ async function startDeploymentCommand(deploymentId) {
4427
4286
  try {
4428
4287
  if (!await isLoggedIn()) {
4429
4288
  console.log(source_default.red("\u2717 You are not logged in."));
@@ -4434,43 +4293,87 @@ async function setEnvCommand(deploymentId, envPairs) {
4434
4293
  );
4435
4294
  process.exit(1);
4436
4295
  }
4437
- const env2 = {};
4438
- for (const pair of envPairs) {
4439
- const [key, ...valueParts] = pair.split("=");
4440
- if (!key || valueParts.length === 0) {
4441
- console.log(source_default.red(`\u2717 Invalid format: ${pair}. Expected KEY=VALUE`));
4442
- process.exit(1);
4443
- }
4444
- env2[key.trim()] = valueParts.join("=").trim();
4445
- }
4446
- const api = await McpUseAPI.create();
4447
- const deployment = await api.getDeployment(deploymentId);
4448
- const currentEnv = deployment.source.env || {};
4449
- const mergedEnv = { ...currentEnv, ...env2 };
4450
- const updated = await api.updateDeployment(deploymentId, {
4451
- env: mergedEnv
4452
- });
4453
4296
  console.log(
4454
- source_default.green.bold(`
4455
- \u2713 Environment variables updated: ${updated.name}
4456
- `)
4297
+ source_default.yellow(
4298
+ "\u26A0\uFE0F Start is not supported in this version. Use `mcp-use deployments restart` to redeploy."
4299
+ )
4457
4300
  );
4458
- for (const key of Object.keys(env2)) {
4459
- const displayValue = key.toLowerCase().includes("key") || key.toLowerCase().includes("secret") || key.toLowerCase().includes("password") || key.toLowerCase().includes("token") ? "***" : env2[key];
4460
- console.log(
4461
- source_default.white(key) + source_default.gray("=") + source_default.cyan(displayValue)
4462
- );
4463
- }
4464
- console.log();
4465
4301
  } catch (error) {
4466
4302
  console.error(
4467
- source_default.red.bold("\n\u2717 Failed to set environment variables:"),
4303
+ source_default.red.bold("\n\u2717 Failed to start deployment:"),
4468
4304
  source_default.red(error instanceof Error ? error.message : "Unknown error")
4469
4305
  );
4470
4306
  process.exit(1);
4471
4307
  }
4472
4308
  }
4473
- async function unsetEnvCommand(deploymentId, keys) {
4309
+ function createDeploymentsCommand() {
4310
+ const deploymentsCommand = new import_commander2.Command("deployments").description(
4311
+ "Manage cloud deployments"
4312
+ );
4313
+ deploymentsCommand.command("list").alias("ls").description("List all deployments").action(listDeploymentsCommand);
4314
+ deploymentsCommand.command("get").argument("<deployment-id>", "Deployment ID").description("Get deployment details").action(getDeploymentCommand);
4315
+ deploymentsCommand.command("restart").argument("<deployment-id>", "Deployment ID").option("-f, --follow", "Follow build logs").description(
4316
+ "Restart a deployment (triggers a new deployment on the same server)"
4317
+ ).action(restartDeploymentCommand);
4318
+ deploymentsCommand.command("delete").alias("rm").argument("<deployment-id>", "Deployment ID").option("-y, --yes", "Skip confirmation prompt").description("Delete a deployment").action(deleteDeploymentCommand);
4319
+ deploymentsCommand.command("logs").argument("<deployment-id>", "Deployment ID").option("-b, --build", "Show build logs instead of runtime logs").option("-f, --follow", "Follow build logs in real-time").description("View deployment logs").action(logsCommand);
4320
+ deploymentsCommand.command("stop").argument("<deployment-id>", "Deployment ID").description("Stop a deployment").action(stopDeploymentCommand);
4321
+ deploymentsCommand.command("start").argument("<deployment-id>", "Deployment ID").description("Start a stopped deployment").action(startDeploymentCommand);
4322
+ return deploymentsCommand;
4323
+ }
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) {
4474
4377
  try {
4475
4378
  if (!await isLoggedIn()) {
4476
4379
  console.log(source_default.red("\u2717 You are not logged in."));
@@ -4482,32 +4385,62 @@ async function unsetEnvCommand(deploymentId, keys) {
4482
4385
  process.exit(1);
4483
4386
  }
4484
4387
  const api = await McpUseAPI.create();
4485
- const deployment = await api.getDeployment(deploymentId);
4486
- const currentEnv = { ...deployment.source.env || {} };
4487
- for (const key of keys) {
4488
- delete currentEnv[key];
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);
4489
4395
  }
4490
- const updated = await api.updateDeployment(deploymentId, {
4491
- env: currentEnv
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
4492
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
+ `));
4493
4417
  console.log(
4494
- source_default.green.bold(`
4495
- \u2713 Environment variables removed: ${updated.name}
4496
- `)
4418
+ source_default.white.bold(
4419
+ `${"ID".padEnd(38)} ${"NAME".padEnd(22)} ${"STATUS".padEnd(14)} ${"REPO".padEnd(32)} ${"MCP URL".padEnd(52)}`
4420
+ )
4497
4421
  );
4498
- for (const key of keys) {
4499
- console.log(source_default.gray(` ${key}`));
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
+ );
4500
4433
  }
4501
4434
  console.log();
4502
4435
  } catch (error) {
4503
4436
  console.error(
4504
- source_default.red.bold("\n\u2717 Failed to unset environment variables:"),
4437
+ source_default.red.bold("\n\u2717 Failed to list servers:"),
4505
4438
  source_default.red(error instanceof Error ? error.message : "Unknown error")
4506
4439
  );
4507
4440
  process.exit(1);
4508
4441
  }
4509
4442
  }
4510
- async function stopDeploymentCommand(deploymentId) {
4443
+ async function getServerCommand(idOrSlug, options) {
4511
4444
  try {
4512
4445
  if (!await isLoggedIn()) {
4513
4446
  console.log(source_default.red("\u2717 You are not logged in."));
@@ -4519,21 +4452,99 @@ async function stopDeploymentCommand(deploymentId) {
4519
4452
  process.exit(1);
4520
4453
  }
4521
4454
  const api = await McpUseAPI.create();
4522
- const updated = await api.updateDeployment(deploymentId, {
4523
- status: "stopped"
4524
- });
4525
- console.log(source_default.green.bold(`
4526
- \u2713 Deployment stopped: ${updated.name}
4527
- `));
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();
4528
4539
  } catch (error) {
4529
4540
  console.error(
4530
- source_default.red.bold("\n\u2717 Failed to stop deployment:"),
4541
+ source_default.red.bold("\n\u2717 Failed to get server:"),
4531
4542
  source_default.red(error instanceof Error ? error.message : "Unknown error")
4532
4543
  );
4533
4544
  process.exit(1);
4534
4545
  }
4535
4546
  }
4536
- async function startDeploymentCommand(deploymentId) {
4547
+ async function deleteServerCommand(serverId, options) {
4537
4548
  try {
4538
4549
  if (!await isLoggedIn()) {
4539
4550
  console.log(source_default.red("\u2717 You are not logged in."));
@@ -4545,36 +4556,59 @@ async function startDeploymentCommand(deploymentId) {
4545
4556
  process.exit(1);
4546
4557
  }
4547
4558
  const api = await McpUseAPI.create();
4548
- const updated = await api.updateDeployment(deploymentId, {
4549
- status: "running"
4550
- });
4551
- console.log(source_default.green.bold(`
4552
- \u2713 Deployment started: ${updated.name}
4553
- `));
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
+ );
4554
4596
  } catch (error) {
4555
4597
  console.error(
4556
- source_default.red.bold("\n\u2717 Failed to start deployment:"),
4598
+ source_default.red.bold("\n\u2717 Failed to delete server:"),
4557
4599
  source_default.red(error instanceof Error ? error.message : "Unknown error")
4558
4600
  );
4559
4601
  process.exit(1);
4560
4602
  }
4561
4603
  }
4562
- function createDeploymentsCommand() {
4563
- const deploymentsCommand = new import_commander2.Command("deployments").description(
4564
- "Manage cloud deployments"
4604
+ function createServersCommand() {
4605
+ const serversCommand = new import_commander3.Command("servers").description(
4606
+ "Manage cloud servers (Git-backed deploy targets)"
4565
4607
  );
4566
- deploymentsCommand.command("list").alias("ls").description("List all deployments").action(listDeploymentsCommand);
4567
- deploymentsCommand.command("get").argument("<deployment-id>", "Deployment ID").description("Get deployment details").action(getDeploymentCommand);
4568
- deploymentsCommand.command("restart").argument("<deployment-id>", "Deployment ID").option("-f, --follow", "Follow deployment logs").description("Restart a deployment").action(restartDeploymentCommand);
4569
- deploymentsCommand.command("delete").alias("rm").argument("<deployment-id>", "Deployment ID").option("-y, --yes", "Skip confirmation prompt").description("Delete a deployment").action(deleteDeploymentCommand);
4570
- deploymentsCommand.command("logs").argument("<deployment-id>", "Deployment ID").option("-b, --build", "Show build logs instead of runtime logs").option("-f, --follow", "Stream logs in real-time").description("View deployment logs").action(logsCommand);
4571
- const envCommand = deploymentsCommand.command("env").description("Manage environment variables");
4572
- envCommand.command("list").argument("<deployment-id>", "Deployment ID").description("List environment variables").action(listEnvCommand);
4573
- envCommand.command("set").argument("<deployment-id>", "Deployment ID").argument("<pairs...>", "Environment variables in KEY=VALUE format").description("Set environment variables").action(setEnvCommand);
4574
- envCommand.command("unset").argument("<deployment-id>", "Deployment ID").argument("<keys...>", "Environment variable keys to remove").description("Unset environment variables").action(unsetEnvCommand);
4575
- deploymentsCommand.command("stop").argument("<deployment-id>", "Deployment ID").description("Stop a deployment").action(stopDeploymentCommand);
4576
- deploymentsCommand.command("start").argument("<deployment-id>", "Deployment ID").description("Start a stopped deployment").action(startDeploymentCommand);
4577
- return deploymentsCommand;
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;
4578
4612
  }
4579
4613
 
4580
4614
  // src/commands/org.ts
@@ -4594,22 +4628,22 @@ async function orgListCommand() {
4594
4628
  const api = await McpUseAPI.create();
4595
4629
  const authInfo = await api.testAuth();
4596
4630
  const config = await readConfig();
4597
- const profiles = authInfo.profiles ?? [];
4598
- const activeId = config.profileId || authInfo.default_profile_id;
4599
- if (profiles.length === 0) {
4631
+ const orgs = authInfo.orgs ?? [];
4632
+ const activeId = config.orgId || authInfo.default_org_id;
4633
+ if (orgs.length === 0) {
4600
4634
  console.log(source_default.yellow("No organizations found."));
4601
4635
  return;
4602
4636
  }
4603
4637
  console.log(source_default.cyan.bold("\u{1F3E2} Your organizations:\n"));
4604
- for (const p of profiles) {
4605
- const isActive = p.id === activeId;
4638
+ for (const o of orgs) {
4639
+ const isActive = o.id === activeId;
4606
4640
  const marker = isActive ? source_default.green(" \u2190 active") : "";
4607
- const slug = p.slug ? source_default.gray(` (${p.slug})`) : "";
4608
- const role = source_default.gray(` [${p.role}]`);
4609
- const name = isActive ? source_default.cyan.bold(p.profile_name) : source_default.white(p.profile_name);
4641
+ const slug = o.slug ? source_default.gray(` (${o.slug})`) : "";
4642
+ const role = source_default.gray(` [${o.role}]`);
4643
+ const name = isActive ? source_default.cyan.bold(o.name) : source_default.white(o.name);
4610
4644
  console.log(` ${name}${slug}${role}${marker}`);
4611
4645
  }
4612
- if (profiles.length > 1) {
4646
+ if (orgs.length > 1) {
4613
4647
  console.log(
4614
4648
  source_default.gray("\nSwitch with " + source_default.white("npx mcp-use org switch"))
4615
4649
  );
@@ -4628,40 +4662,40 @@ async function orgSwitchCommand() {
4628
4662
  const api = await McpUseAPI.create();
4629
4663
  const authInfo = await api.testAuth();
4630
4664
  const config = await readConfig();
4631
- const profiles = authInfo.profiles ?? [];
4632
- if (profiles.length === 0) {
4665
+ const orgs = authInfo.orgs ?? [];
4666
+ if (orgs.length === 0) {
4633
4667
  console.log(source_default.yellow("No organizations found."));
4634
4668
  return;
4635
4669
  }
4636
- if (profiles.length === 1) {
4637
- const p = profiles[0];
4638
- const slug2 = p.slug ? source_default.gray(` (${p.slug})`) : "";
4670
+ if (orgs.length === 1) {
4671
+ const o = orgs[0];
4672
+ const slug2 = o.slug ? source_default.gray(` (${o.slug})`) : "";
4639
4673
  console.log(
4640
4674
  source_default.yellow(
4641
- `You only have one organization: ${source_default.cyan(p.profile_name)}${slug2}`
4675
+ `You only have one organization: ${source_default.cyan(o.name)}${slug2}`
4642
4676
  )
4643
4677
  );
4644
4678
  return;
4645
4679
  }
4646
- const activeId = config.profileId || authInfo.default_profile_id;
4647
- const selected = await promptOrgSelection(profiles, activeId);
4680
+ const activeId = config.orgId || authInfo.default_org_id;
4681
+ const selected = await promptOrgSelection(orgs, activeId);
4648
4682
  if (!selected) {
4649
4683
  console.log(source_default.yellow("No organization selected."));
4650
4684
  return;
4651
4685
  }
4652
4686
  await writeConfig({
4653
4687
  ...config,
4654
- profileId: selected.id,
4655
- profileName: selected.profile_name,
4656
- profileSlug: selected.slug ?? void 0
4688
+ orgId: selected.id,
4689
+ orgName: selected.name,
4690
+ orgSlug: selected.slug ?? void 0
4657
4691
  });
4658
4692
  try {
4659
- await api.setDefaultProfile(selected.id);
4693
+ await api.setDefaultOrg(selected.id);
4660
4694
  } catch {
4661
4695
  }
4662
4696
  const slug = selected.slug ? source_default.gray(` (${selected.slug})`) : "";
4663
4697
  console.log(
4664
- source_default.green.bold("\n\u2713 Switched to ") + source_default.cyan.bold(selected.profile_name) + slug
4698
+ source_default.green.bold("\n\u2713 Switched to ") + source_default.cyan.bold(selected.name) + slug
4665
4699
  );
4666
4700
  } catch (error) {
4667
4701
  console.error(
@@ -4675,7 +4709,7 @@ async function orgCurrentCommand() {
4675
4709
  try {
4676
4710
  if (!await ensureLoggedIn()) return;
4677
4711
  const config = await readConfig();
4678
- if (!config.profileId) {
4712
+ if (!config.orgId) {
4679
4713
  console.log(
4680
4714
  source_default.yellow(
4681
4715
  "No organization selected. Run " + source_default.white("npx mcp-use org switch") + " to pick one."
@@ -4683,9 +4717,9 @@ async function orgCurrentCommand() {
4683
4717
  );
4684
4718
  return;
4685
4719
  }
4686
- const slug = config.profileSlug ? source_default.gray(` (${config.profileSlug})`) : "";
4720
+ const slug = config.orgSlug ? source_default.gray(` (${config.orgSlug})`) : "";
4687
4721
  console.log(
4688
- source_default.cyan.bold("\u{1F3E2} Active organization: ") + source_default.white(config.profileName || config.profileId) + slug
4722
+ source_default.cyan.bold("\u{1F3E2} Active organization: ") + source_default.white(config.orgName || config.orgId) + slug
4689
4723
  );
4690
4724
  } catch (error) {
4691
4725
  console.error(
@@ -4697,7 +4731,7 @@ async function orgCurrentCommand() {
4697
4731
  }
4698
4732
 
4699
4733
  // src/commands/skills.ts
4700
- var import_commander3 = require("commander");
4734
+ var import_commander4 = require("commander");
4701
4735
  var import_node_fs8 = require("fs");
4702
4736
  var import_node_os5 = require("os");
4703
4737
  var import_node_path6 = require("path");
@@ -4767,7 +4801,7 @@ async function addSkillsToProject(projectPath) {
4767
4801
  }
4768
4802
  }
4769
4803
  function createSkillsCommand() {
4770
- const skills = new import_commander3.Command("skills").description(
4804
+ const skills = new import_commander4.Command("skills").description(
4771
4805
  "Manage mcp-use AI agent skills"
4772
4806
  );
4773
4807
  const installAction = async (options) => {
@@ -4943,7 +4977,7 @@ A new release of ${source_default.bold(PACKAGE_NAME)} is available: ${source_def
4943
4977
  }
4944
4978
 
4945
4979
  // src/index.ts
4946
- var program = new import_commander4.Command();
4980
+ var program = new import_commander5.Command();
4947
4981
  var packageContent = (0, import_node_fs10.readFileSync)(
4948
4982
  import_node_path8.default.join(__dirname, "../package.json"),
4949
4983
  "utf-8"
@@ -6771,7 +6805,13 @@ program.command("deploy").description("Deploy MCP server from GitHub to Manufact
6771
6805
  ).option(
6772
6806
  "--org <slug-or-id>",
6773
6807
  "Deploy to a specific organization (by slug or ID)"
6774
- ).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) => {
6775
6815
  await deployCommand({
6776
6816
  open: options.open,
6777
6817
  name: options.name,
@@ -6782,11 +6822,15 @@ program.command("deploy").description("Deploy MCP server from GitHub to Manufact
6782
6822
  envFile: options.envFile,
6783
6823
  rootDir: options.rootDir,
6784
6824
  org: options.org,
6785
- yes: options.yes
6825
+ yes: options.yes,
6826
+ region: options.region,
6827
+ buildCommand: options.buildCommand,
6828
+ startCommand: options.startCommand
6786
6829
  });
6787
6830
  });
6788
6831
  program.addCommand(createClientCommand());
6789
6832
  program.addCommand(createDeploymentsCommand());
6833
+ program.addCommand(createServersCommand());
6790
6834
  program.addCommand(createSkillsCommand());
6791
6835
  program.command("generate-types").description(
6792
6836
  "Generate TypeScript type definitions for tools (writes .mcp-use/tool-registry.d.ts)"