@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.js CHANGED
@@ -503,7 +503,7 @@ var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
503
503
  var source_default = chalk;
504
504
 
505
505
  // src/index.ts
506
- import { Command as Command4 } from "commander";
506
+ import { Command as Command5 } from "commander";
507
507
  import "dotenv/config";
508
508
  import { spawn } from "child_process";
509
509
  import { readFileSync as readFileSync2 } from "fs";
@@ -1147,14 +1147,21 @@ async function ensureConfigDir() {
1147
1147
  async function readConfig() {
1148
1148
  try {
1149
1149
  const content = await fs7.readFile(CONFIG_FILE, "utf-8");
1150
- return JSON.parse(content);
1150
+ const raw = JSON.parse(content);
1151
+ return {
1152
+ ...raw,
1153
+ orgId: raw.orgId ?? raw.profileId,
1154
+ orgName: raw.orgName ?? raw.profileName,
1155
+ orgSlug: raw.orgSlug ?? raw.profileSlug
1156
+ };
1151
1157
  } catch (error) {
1152
1158
  return {};
1153
1159
  }
1154
1160
  }
1155
1161
  async function writeConfig(config) {
1156
1162
  await ensureConfigDir();
1157
- await fs7.writeFile(CONFIG_FILE, JSON.stringify(config, null, 2), "utf-8");
1163
+ const { profileId: _a, profileName: _b, profileSlug: _c, ...clean } = config;
1164
+ await fs7.writeFile(CONFIG_FILE, JSON.stringify(clean, null, 2), "utf-8");
1158
1165
  }
1159
1166
  async function deleteConfig() {
1160
1167
  try {
@@ -1174,9 +1181,9 @@ async function isLoggedIn() {
1174
1181
  const apiKey = await getApiKey();
1175
1182
  return !!apiKey;
1176
1183
  }
1177
- async function getProfileId() {
1184
+ async function getOrgId() {
1178
1185
  const config = await readConfig();
1179
- return config.profileId || null;
1186
+ return config.orgId || null;
1180
1187
  }
1181
1188
  async function getWebUrl() {
1182
1189
  return DEFAULT_WEB_URL;
@@ -1190,30 +1197,21 @@ async function getAuthBaseUrl() {
1190
1197
  var McpUseAPI = class _McpUseAPI {
1191
1198
  baseUrl;
1192
1199
  apiKey;
1193
- profileId;
1194
- constructor(baseUrl, apiKey, profileId) {
1200
+ orgId;
1201
+ constructor(baseUrl, apiKey, orgId) {
1195
1202
  this.baseUrl = baseUrl || "";
1196
1203
  this.apiKey = apiKey;
1197
- this.profileId = profileId;
1204
+ this.orgId = orgId;
1198
1205
  }
1199
- /**
1200
- * Initialize API client with config
1201
- */
1202
1206
  static async create() {
1203
1207
  const baseUrl = await getApiUrl();
1204
1208
  const apiKey = await getApiKey();
1205
- const profileId = await getProfileId();
1206
- return new _McpUseAPI(baseUrl, apiKey ?? void 0, profileId ?? void 0);
1209
+ const orgId = await getOrgId();
1210
+ return new _McpUseAPI(baseUrl, apiKey ?? void 0, orgId ?? void 0);
1207
1211
  }
1208
- /**
1209
- * Override the profile ID for this API client instance (e.g. from --org flag)
1210
- */
1211
- setProfileId(profileId) {
1212
- this.profileId = profileId;
1212
+ setOrgId(orgId) {
1213
+ this.orgId = orgId;
1213
1214
  }
1214
- /**
1215
- * Make authenticated request
1216
- */
1217
1215
  async request(endpoint, options = {}) {
1218
1216
  const url = `${this.baseUrl}${endpoint}`;
1219
1217
  const headers = {
@@ -1223,8 +1221,8 @@ var McpUseAPI = class _McpUseAPI {
1223
1221
  if (this.apiKey) {
1224
1222
  headers["x-api-key"] = this.apiKey;
1225
1223
  }
1226
- if (this.profileId) {
1227
- headers["x-profile-id"] = this.profileId;
1224
+ if (this.orgId) {
1225
+ headers["x-profile-id"] = this.orgId;
1228
1226
  }
1229
1227
  const timeout = options.timeout || 3e4;
1230
1228
  const controller = new AbortController();
@@ -1251,16 +1249,13 @@ var McpUseAPI = class _McpUseAPI {
1251
1249
  } catch (error) {
1252
1250
  clearTimeout(timeoutId);
1253
1251
  if (error.name === "AbortError") {
1254
- throw new Error(
1255
- `Request timeout after ${timeout / 1e3}s. Try using --follow flag to stream logs instead.`
1256
- );
1252
+ throw new Error(`Request timeout after ${timeout / 1e3}s.`);
1257
1253
  }
1258
1254
  throw error;
1259
1255
  }
1260
1256
  }
1261
1257
  /**
1262
1258
  * Create a persistent API key using a Better Auth access token.
1263
- * Calls Better Auth's built-in POST /api/auth/api-key/create endpoint.
1264
1259
  */
1265
1260
  async createApiKeyWithAccessToken(accessToken, name = "CLI") {
1266
1261
  const authBase = await getAuthBaseUrl();
@@ -1279,255 +1274,171 @@ var McpUseAPI = class _McpUseAPI {
1279
1274
  }
1280
1275
  return response.json();
1281
1276
  }
1282
- /**
1283
- * Test authentication
1284
- */
1277
+ // ── Auth ────────────────────────────────────────────────────────
1285
1278
  async testAuth() {
1286
- return this.request("/test-auth");
1279
+ const wire = await this.request("/test-auth");
1280
+ return {
1281
+ message: wire.message,
1282
+ user_id: wire.user_id,
1283
+ email: wire.email,
1284
+ default_org_id: wire.default_profile_id,
1285
+ orgs: (wire.profiles ?? []).map((p) => ({
1286
+ id: p.id,
1287
+ name: p.profile_name,
1288
+ slug: p.slug,
1289
+ role: p.role
1290
+ }))
1291
+ };
1287
1292
  }
1288
- /**
1289
- * Set the user's default profile (organization) on the server
1290
- */
1291
- async setDefaultProfile(profileId) {
1292
- await this.request(`/profiles/${profileId}/set-default`, {
1293
+ async setDefaultOrg(orgId) {
1294
+ await this.request(`/organizations/${orgId}/set-default`, {
1293
1295
  method: "POST"
1294
1296
  });
1295
1297
  }
1296
- /**
1297
- * Create deployment
1298
- */
1299
- async createDeployment(request) {
1300
- return this.request("/deployments", {
1298
+ // ── Organization ID resolution ──────────────────────────────────
1299
+ async resolveOrganizationId() {
1300
+ if (this.orgId) return this.orgId;
1301
+ const auth = await this.testAuth();
1302
+ const id = auth.default_org_id;
1303
+ if (!id) {
1304
+ throw new Error(
1305
+ "No organization set. Run `mcp-use org switch` or use --org to specify one."
1306
+ );
1307
+ }
1308
+ return id;
1309
+ }
1310
+ // ── Servers ─────────────────────────────────────────────────────
1311
+ async createServer(body) {
1312
+ return this.request("/servers", {
1301
1313
  method: "POST",
1302
- body: JSON.stringify(request)
1314
+ body: JSON.stringify(body)
1303
1315
  });
1304
1316
  }
1305
- /**
1306
- * Get deployment by ID
1307
- */
1308
- async getDeployment(deploymentId) {
1309
- return this.request(`/deployments/${deploymentId}`);
1310
- }
1311
- /**
1312
- * Stream deployment logs
1313
- */
1314
- async *streamDeploymentLogs(deploymentId) {
1315
- const url = `${this.baseUrl}/deployments/${deploymentId}/logs/stream`;
1316
- const headers = {};
1317
- if (this.apiKey) {
1318
- headers["x-api-key"] = this.apiKey;
1319
- }
1320
- if (this.profileId) {
1321
- headers["x-profile-id"] = this.profileId;
1317
+ async listServers(params) {
1318
+ const search = new URLSearchParams();
1319
+ if (params?.organizationId) {
1320
+ search.set("organizationId", params.organizationId);
1322
1321
  }
1323
- const response = await fetch(url, { headers });
1324
- if (!response.ok) {
1325
- throw new Error(`Failed to stream logs: ${response.status}`);
1322
+ if (params?.limit != null) {
1323
+ search.set("limit", String(params.limit));
1326
1324
  }
1327
- if (!response.body) {
1328
- throw new Error("Response body is null");
1325
+ if (params?.skip != null) {
1326
+ search.set("skip", String(params.skip));
1329
1327
  }
1330
- const reader = response.body.getReader();
1331
- const decoder = new TextDecoder();
1332
- let buffer = "";
1333
- try {
1334
- while (true) {
1335
- const { done, value } = await reader.read();
1336
- if (done) break;
1337
- buffer += decoder.decode(value, { stream: true });
1338
- const lines = buffer.split("\n");
1339
- buffer = lines.pop() || "";
1340
- for (const line of lines) {
1341
- if (line.startsWith("data: ")) {
1342
- const data = line.slice(6);
1343
- try {
1344
- const parsed = JSON.parse(data);
1345
- if (parsed.log) {
1346
- yield parsed.log;
1347
- } else if (parsed.error) {
1348
- throw new Error(parsed.error);
1349
- }
1350
- } catch (e) {
1351
- }
1352
- }
1353
- }
1354
- }
1355
- } finally {
1356
- reader.releaseLock();
1328
+ if (params?.sort) {
1329
+ search.set("sort", params.sort);
1357
1330
  }
1331
+ const q = search.toString();
1332
+ return this.request(`/servers${q ? `?${q}` : ""}`);
1358
1333
  }
1359
- /**
1360
- * Create deployment with source code upload
1361
- */
1362
- async createDeploymentWithUpload(request, filePath) {
1363
- const { readFile: readFile4 } = await import("fs/promises");
1364
- const { basename } = await import("path");
1365
- const { stat } = await import("fs/promises");
1366
- const stats = await stat(filePath);
1367
- const maxSize = 2 * 1024 * 1024;
1368
- if (stats.size > maxSize) {
1369
- throw new Error(
1370
- `File size (${(stats.size / 1024 / 1024).toFixed(2)}MB) exceeds maximum of 2MB`
1371
- );
1372
- }
1373
- const fileBuffer = await readFile4(filePath);
1374
- const filename = basename(filePath);
1375
- const formData = new FormData();
1376
- const blob = new Blob([fileBuffer], { type: "application/gzip" });
1377
- formData.append("source_file", blob, filename);
1378
- formData.append("name", request.name);
1379
- formData.append("source_type", "upload");
1380
- if (request.source.type === "upload") {
1381
- formData.append("runtime", request.source.runtime || "node");
1382
- formData.append("port", String(request.source.port || 3e3));
1383
- if (request.source.startCommand) {
1384
- formData.append("startCommand", request.source.startCommand);
1385
- }
1386
- if (request.source.buildCommand) {
1387
- formData.append("buildCommand", request.source.buildCommand);
1388
- }
1389
- if (request.source.env && Object.keys(request.source.env).length > 0) {
1390
- formData.append("env", JSON.stringify(request.source.env));
1334
+ async getServer(idOrSlug) {
1335
+ const path8 = encodeURIComponent(idOrSlug);
1336
+ return this.request(`/servers/${path8}`);
1337
+ }
1338
+ async deleteServer(id) {
1339
+ await this.request(
1340
+ `/servers/${encodeURIComponent(id)}`,
1341
+ {
1342
+ method: "DELETE"
1391
1343
  }
1392
- }
1393
- if (request.customDomain) {
1394
- formData.append("customDomain", request.customDomain);
1395
- }
1396
- if (request.healthCheckPath) {
1397
- formData.append("healthCheckPath", request.healthCheckPath);
1398
- }
1399
- const url = `${this.baseUrl}/deployments`;
1400
- const headers = {};
1401
- if (this.apiKey) {
1402
- headers["x-api-key"] = this.apiKey;
1403
- }
1404
- if (this.profileId) {
1405
- headers["x-profile-id"] = this.profileId;
1406
- }
1407
- const response = await fetch(url, {
1344
+ );
1345
+ }
1346
+ // ── Deployments ─────────────────────────────────────────────────
1347
+ async createDeployment(input) {
1348
+ return this.request("/deployments", {
1408
1349
  method: "POST",
1409
- headers,
1410
- body: formData
1350
+ body: JSON.stringify(input)
1411
1351
  });
1412
- if (!response.ok) {
1413
- const error = await response.text();
1414
- throw new Error(`Deployment failed: ${error}`);
1415
- }
1416
- return response.json();
1417
1352
  }
1418
- /**
1419
- * List all deployments
1420
- */
1353
+ async getDeployment(deploymentId) {
1354
+ return this.request(`/deployments/${deploymentId}`);
1355
+ }
1421
1356
  async listDeployments() {
1422
- const response = await this.request("/deployments");
1423
- return response.deployments;
1357
+ return this.request("/deployments");
1424
1358
  }
1425
- /**
1426
- * Delete deployment
1427
- */
1428
1359
  async deleteDeployment(deploymentId) {
1429
1360
  await this.request(`/deployments/${deploymentId}`, {
1430
1361
  method: "DELETE"
1431
1362
  });
1432
1363
  }
1433
- /**
1434
- * Update deployment
1435
- */
1436
- async updateDeployment(deploymentId, updates) {
1437
- return this.request(`/deployments/${deploymentId}`, {
1438
- method: "PATCH",
1439
- body: JSON.stringify(updates)
1440
- });
1441
- }
1442
- /**
1443
- * Redeploy deployment
1444
- *
1445
- * @param deploymentId - The deployment ID to redeploy
1446
- * @param configOrFilePath - Either a RedeploymentConfig object with updated settings,
1447
- * or a file path string for source code upload
1448
- */
1449
- async redeployDeployment(deploymentId, configOrFilePath) {
1450
- if (typeof configOrFilePath === "string") {
1451
- const filePath = configOrFilePath;
1452
- const { readFile: readFile4 } = await import("fs/promises");
1453
- const { basename } = await import("path");
1454
- const { stat } = await import("fs/promises");
1455
- const stats = await stat(filePath);
1456
- const maxSize = 2 * 1024 * 1024;
1457
- if (stats.size > maxSize) {
1458
- throw new Error(
1459
- `File size (${(stats.size / 1024 / 1024).toFixed(2)}MB) exceeds maximum of 2MB`
1460
- );
1461
- }
1462
- const fileBuffer = await readFile4(filePath);
1463
- const formData = new FormData();
1464
- const blob = new Blob([fileBuffer], { type: "application/gzip" });
1465
- formData.append("source_file", blob, basename(filePath));
1466
- const headers = {};
1467
- if (this.apiKey) headers["x-api-key"] = this.apiKey;
1468
- if (this.profileId) headers["x-profile-id"] = this.profileId;
1469
- const response = await fetch(
1470
- `${this.baseUrl}/deployments/${deploymentId}/redeploy`,
1471
- {
1472
- method: "POST",
1473
- headers,
1474
- body: formData
1475
- }
1476
- );
1477
- if (!response.ok) {
1478
- const error = await response.text();
1479
- throw new Error(`Redeploy failed: ${error}`);
1480
- }
1481
- return response.json();
1482
- }
1483
- const config = configOrFilePath;
1484
- return this.request(`/deployments/${deploymentId}/redeploy`, {
1485
- method: "POST",
1486
- body: config ? JSON.stringify(config) : void 0
1364
+ async stopDeployment(deploymentId) {
1365
+ await this.request(`/deployments/${deploymentId}/stop`, {
1366
+ method: "POST"
1487
1367
  });
1488
1368
  }
1489
- /**
1490
- * Get deployment logs
1491
- */
1492
- async getDeploymentLogs(deploymentId) {
1493
- const response = await this.request(
1494
- `/deployments/${deploymentId}/logs`,
1369
+ async getDeploymentLogs(deploymentId, lines = 500) {
1370
+ const resp = await this.request(
1371
+ `/deployments/${deploymentId}/logs?lines=${lines}`,
1495
1372
  { timeout: 6e4 }
1496
- // 60 second timeout for logs
1497
1373
  );
1498
- return response.data.logs;
1374
+ return resp.logs;
1499
1375
  }
1500
- /**
1501
- * Get deployment build logs
1502
- */
1503
- async getDeploymentBuildLogs(deploymentId) {
1504
- const response = await this.request(
1505
- `/deployments/${deploymentId}/logs/build`,
1376
+ async getDeploymentBuildLogs(deploymentId, offset = 0) {
1377
+ return this.request(
1378
+ `/deployments/${deploymentId}/build-logs?offset=${offset}`,
1506
1379
  { timeout: 6e4 }
1507
- // 60 second timeout for logs
1508
1380
  );
1509
- return response.data.logs;
1510
1381
  }
1511
- /**
1512
- * Get GitHub connection status
1513
- */
1382
+ // ── GitHub ──────────────────────────────────────────────────────
1514
1383
  async getGitHubConnectionStatus() {
1515
- return this.request("/github/connection");
1384
+ const orgId = await this.resolveOrganizationId();
1385
+ const resp = await this.request(`/github/installations?organizationId=${orgId}`);
1386
+ return {
1387
+ is_connected: resp.installations.length > 0,
1388
+ installations: resp.installations.map((i) => ({
1389
+ id: i.id,
1390
+ installation_id: i.installationId,
1391
+ account_login: i.account?.login ?? "",
1392
+ account_type: i.account?.type ?? "User"
1393
+ }))
1394
+ };
1395
+ }
1396
+ async getGitHubRepos(_refresh) {
1397
+ const orgId = await this.resolveOrganizationId();
1398
+ const installResp = await this.request(`/github/installations?organizationId=${orgId}`);
1399
+ if (installResp.installations.length === 0) {
1400
+ return { user: { login: "", id: 0, avatar_url: "" }, repos: [] };
1401
+ }
1402
+ const inst = installResp.installations[0];
1403
+ const reposResp = await this.request(`/github/installations/${inst.installationId}/repos`);
1404
+ return {
1405
+ user: {
1406
+ login: inst.account?.login ?? "",
1407
+ id: 0,
1408
+ avatar_url: inst.account?.avatar_url ?? ""
1409
+ },
1410
+ repos: reposResp.repos.map((r) => ({
1411
+ id: r.id,
1412
+ name: r.name,
1413
+ full_name: r.fullName,
1414
+ private: r.private,
1415
+ owner: { login: r.fullName.split("/")[0] ?? "" }
1416
+ }))
1417
+ };
1516
1418
  }
1517
- /**
1518
- * Get GitHub app name
1519
- */
1520
1419
  async getGitHubAppName() {
1521
- const response = await this.request("/github/appname");
1522
- return response.app_name;
1420
+ if (process.env.MCP_GITHUB_APP_NAME) return process.env.MCP_GITHUB_APP_NAME;
1421
+ if (this.baseUrl.includes("localhost")) return "mcp-use-local";
1422
+ if (this.baseUrl.includes(".dev.")) return "mcp-use-dev";
1423
+ return "mcp-use";
1523
1424
  }
1524
1425
  /**
1525
- * Get accessible GitHub repositories
1426
+ * Returns the GitHub numeric installation ID (not the DB UUID) for the org.
1427
+ * Used for building direct installation settings URLs.
1526
1428
  */
1527
- async getGitHubRepos(refresh = false) {
1528
- return this.request(
1529
- `/github/repos${refresh ? "?refresh=true" : ""}`
1530
- );
1429
+ async getGitHubInstallationId() {
1430
+ const status = await this.getGitHubConnectionStatus();
1431
+ return status.installations?.[0]?.installation_id ?? null;
1432
+ }
1433
+ async createGitHubRepo(opts) {
1434
+ return this.request(`/github/installations/${opts.installationId}/repos`, {
1435
+ method: "POST",
1436
+ body: JSON.stringify({
1437
+ name: opts.name,
1438
+ private: opts.private ?? true,
1439
+ org: opts.org
1440
+ })
1441
+ });
1531
1442
  }
1532
1443
  };
1533
1444
 
@@ -1592,19 +1503,17 @@ async function pollForDeviceToken(authBaseUrl, deviceCode, intervalSeconds) {
1592
1503
  }
1593
1504
  throw new Error("Login timed out. Please try again.");
1594
1505
  }
1595
- async function promptOrgSelection(profiles, defaultProfileId) {
1596
- if (profiles.length === 0) return null;
1597
- if (profiles.length === 1) {
1598
- return profiles[0];
1506
+ async function promptOrgSelection(orgs, defaultOrgId) {
1507
+ if (orgs.length === 0) return null;
1508
+ if (orgs.length === 1) {
1509
+ return orgs[0];
1599
1510
  }
1600
1511
  console.log(source_default.cyan.bold("\n\u{1F3E2} Select an organization:\n"));
1601
- for (let i = 0; i < profiles.length; i++) {
1602
- const p = profiles[i];
1603
- const marker = p.id === defaultProfileId ? source_default.green(" (current)") : "";
1604
- const slug = p.slug ? source_default.gray(` (${p.slug})`) : "";
1605
- console.log(
1606
- ` ${source_default.white(`${i + 1}.`)} ${p.profile_name}${slug}${marker}`
1607
- );
1512
+ for (let i = 0; i < orgs.length; i++) {
1513
+ const o = orgs[i];
1514
+ const marker = o.id === defaultOrgId ? source_default.green(" (current)") : "";
1515
+ const slug = o.slug ? source_default.gray(` (${o.slug})`) : "";
1516
+ console.log(` ${source_default.white(`${i + 1}.`)} ${o.name}${slug}${marker}`);
1608
1517
  }
1609
1518
  const readline = await import("readline");
1610
1519
  const rl = readline.createInterface({
@@ -1612,7 +1521,7 @@ async function promptOrgSelection(profiles, defaultProfileId) {
1612
1521
  output: process.stdout
1613
1522
  });
1614
1523
  return new Promise((resolve2) => {
1615
- const defaultIdx = defaultProfileId ? profiles.findIndex((p) => p.id === defaultProfileId) : 0;
1524
+ const defaultIdx = defaultOrgId ? orgs.findIndex((o) => o.id === defaultOrgId) : 0;
1616
1525
  const defaultDisplay = defaultIdx >= 0 ? defaultIdx + 1 : 1;
1617
1526
  rl.question(
1618
1527
  source_default.gray(`
@@ -1621,11 +1530,11 @@ Enter number [${defaultDisplay}]: `),
1621
1530
  rl.close();
1622
1531
  const trimmed = answer.trim();
1623
1532
  const idx = trimmed === "" ? defaultIdx : parseInt(trimmed, 10) - 1;
1624
- if (idx >= 0 && idx < profiles.length) {
1625
- resolve2(profiles[idx]);
1533
+ if (idx >= 0 && idx < orgs.length) {
1534
+ resolve2(orgs[idx]);
1626
1535
  } else {
1627
1536
  console.log(source_default.yellow("Invalid selection, using default."));
1628
- resolve2(profiles[defaultIdx >= 0 ? defaultIdx : 0]);
1537
+ resolve2(orgs[defaultIdx >= 0 ? defaultIdx : 0]);
1629
1538
  }
1630
1539
  }
1631
1540
  );
@@ -1704,28 +1613,25 @@ async function loginCommand(options) {
1704
1613
  const masked = storedKey.substring(0, 8) + "...";
1705
1614
  console.log(source_default.white(" API Key: ") + source_default.gray(masked));
1706
1615
  }
1707
- const profiles = authInfo.profiles ?? [];
1708
- if (profiles.length > 0) {
1709
- let selectedProfile = null;
1710
- if (profiles.length === 1) {
1711
- selectedProfile = profiles[0];
1616
+ const orgs = authInfo.orgs ?? [];
1617
+ if (orgs.length > 0) {
1618
+ let selectedOrg = null;
1619
+ if (orgs.length === 1) {
1620
+ selectedOrg = orgs[0];
1712
1621
  } else {
1713
- selectedProfile = await promptOrgSelection(
1714
- profiles,
1715
- authInfo.default_profile_id
1716
- );
1622
+ selectedOrg = await promptOrgSelection(orgs, authInfo.default_org_id);
1717
1623
  }
1718
- if (selectedProfile) {
1624
+ if (selectedOrg) {
1719
1625
  const config = await readConfig();
1720
1626
  await writeConfig({
1721
1627
  ...config,
1722
- profileId: selectedProfile.id,
1723
- profileName: selectedProfile.profile_name,
1724
- profileSlug: selectedProfile.slug ?? void 0
1628
+ orgId: selectedOrg.id,
1629
+ orgName: selectedOrg.name,
1630
+ orgSlug: selectedOrg.slug ?? void 0
1725
1631
  });
1726
- const slug = selectedProfile.slug ? source_default.gray(` (${selectedProfile.slug})`) : "";
1632
+ const slug = selectedOrg.slug ? source_default.gray(` (${selectedOrg.slug})`) : "";
1727
1633
  console.log(
1728
- source_default.white(" Org: ") + source_default.cyan(selectedProfile.profile_name) + slug
1634
+ source_default.white(" Org: ") + source_default.cyan(selectedOrg.name) + slug
1729
1635
  );
1730
1636
  }
1731
1637
  }
@@ -1795,22 +1701,22 @@ async function whoamiCommand() {
1795
1701
  console.log(source_default.white("API Key: ") + source_default.gray(masked));
1796
1702
  }
1797
1703
  const config = await readConfig();
1798
- const profiles = authInfo.profiles ?? [];
1799
- if (profiles.length > 0) {
1800
- const activeProfile = profiles.find(
1801
- (p) => p.id === (config.profileId || authInfo.default_profile_id)
1704
+ const orgs = authInfo.orgs ?? [];
1705
+ if (orgs.length > 0) {
1706
+ const activeOrg = orgs.find(
1707
+ (o) => o.id === (config.orgId || authInfo.default_org_id)
1802
1708
  );
1803
- if (activeProfile) {
1804
- const slug = activeProfile.slug ? source_default.gray(` (${activeProfile.slug})`) : "";
1709
+ if (activeOrg) {
1710
+ const slug = activeOrg.slug ? source_default.gray(` (${activeOrg.slug})`) : "";
1805
1711
  console.log(
1806
- source_default.white("Org: ") + source_default.cyan(activeProfile.profile_name) + slug
1712
+ source_default.white("Org: ") + source_default.cyan(activeOrg.name) + slug
1807
1713
  );
1808
1714
  }
1809
- if (profiles.length > 1) {
1715
+ if (orgs.length > 1) {
1810
1716
  console.log(
1811
1717
  source_default.gray(
1812
1718
  `
1813
- ${profiles.length} organizations available. Use ` + source_default.white("npx mcp-use org list") + " to see all."
1719
+ ${orgs.length} organizations available. Use ` + source_default.white("npx mcp-use org list") + " to see all."
1814
1720
  )
1815
1721
  );
1816
1722
  }
@@ -2587,9 +2493,9 @@ async function listPromptsCommand(options) {
2587
2493
  }
2588
2494
  console.log(formatHeader(`Available Prompts (${prompts.length}):`));
2589
2495
  console.log("");
2590
- const tableData = prompts.map((prompt3) => ({
2591
- name: source_default.bold(prompt3.name),
2592
- description: prompt3.description || source_default.gray("No description")
2496
+ const tableData = prompts.map((prompt4) => ({
2497
+ name: source_default.bold(prompt4.name),
2498
+ description: prompt4.description || source_default.gray("No description")
2593
2499
  }));
2594
2500
  console.log(
2595
2501
  formatTable(tableData, [
@@ -2617,20 +2523,20 @@ async function getPromptCommand(promptName, argsJson, options) {
2617
2523
  }
2618
2524
  }
2619
2525
  console.error(formatInfo(`Getting prompt '${promptName}'...`));
2620
- const prompt3 = await session.getPrompt(promptName, args);
2526
+ const prompt4 = await session.getPrompt(promptName, args);
2621
2527
  if (options?.json) {
2622
- console.log(formatJson(prompt3));
2528
+ console.log(formatJson(prompt4));
2623
2529
  } else {
2624
2530
  console.log(formatHeader(`Prompt: ${promptName}`));
2625
2531
  console.log("");
2626
- if (prompt3.description) {
2627
- console.log(prompt3.description);
2532
+ if (prompt4.description) {
2533
+ console.log(prompt4.description);
2628
2534
  console.log("");
2629
2535
  }
2630
- if (prompt3.messages) {
2536
+ if (prompt4.messages) {
2631
2537
  console.log(formatHeader("Messages:"));
2632
2538
  console.log("");
2633
- console.log(formatPromptMessages(prompt3.messages));
2539
+ console.log(formatPromptMessages(prompt4.messages));
2634
2540
  }
2635
2541
  }
2636
2542
  } catch (error) {
@@ -2770,8 +2676,8 @@ async function interactiveCommand(options) {
2770
2676
  async (argsInput) => {
2771
2677
  try {
2772
2678
  const args = argsInput.trim() ? JSON.parse(argsInput) : {};
2773
- const prompt3 = await session.getPrompt(arg, args);
2774
- console.log(formatPromptMessages(prompt3.messages));
2679
+ const prompt4 = await session.getPrompt(arg, args);
2680
+ console.log(formatPromptMessages(prompt4.messages));
2775
2681
  } catch (error) {
2776
2682
  console.error(formatError(error.message));
2777
2683
  }
@@ -2937,6 +2843,20 @@ async function getGitInfo(cwd = process.cwd()) {
2937
2843
  hasUncommittedChanges: uncommittedChanges
2938
2844
  };
2939
2845
  }
2846
+ async function gitInit(cwd, message = "Initial commit") {
2847
+ await gitCommand("git init", cwd);
2848
+ await gitCommand("git add .", cwd);
2849
+ await gitCommand(`git commit -m "${message}"`, cwd);
2850
+ }
2851
+ async function gitAddRemoteAndPush(cwd, cloneUrl, branch = "main") {
2852
+ await gitCommand(`git remote add origin ${cloneUrl}`, cwd);
2853
+ await gitCommand(`git push -u origin ${branch}`, cwd);
2854
+ }
2855
+ async function gitCommitAndPush(cwd, message, branch = "main") {
2856
+ await gitCommand("git add .", cwd);
2857
+ await gitCommand(`git commit -m "${message}"`, cwd);
2858
+ await gitCommand(`git push origin ${branch}`, cwd);
2859
+ }
2940
2860
  function isGitHubUrl(url) {
2941
2861
  try {
2942
2862
  const parsedUrl = new URL(url);
@@ -2951,6 +2871,22 @@ function isGitHubUrl(url) {
2951
2871
  return false;
2952
2872
  }
2953
2873
 
2874
+ // src/utils/cloud-urls.ts
2875
+ var GATEWAY_DOMAIN = "run.mcp-use.com";
2876
+ function buildGatewayUrl(slugOrId) {
2877
+ return `https://${slugOrId}.${GATEWAY_DOMAIN}/mcp`;
2878
+ }
2879
+ function getMcpServerUrl(deployment) {
2880
+ if (deployment.mcpUrl) return deployment.mcpUrl;
2881
+ if (deployment.serverId) return buildGatewayUrl(deployment.serverId);
2882
+ return "";
2883
+ }
2884
+ function getMcpServerUrlForCloudServer(server) {
2885
+ if (server.mcpUrl) return server.mcpUrl;
2886
+ const hostKey = server.slug && server.slug.trim() || server.id;
2887
+ return buildGatewayUrl(hostKey);
2888
+ }
2889
+
2954
2890
  // src/utils/project-link.ts
2955
2891
  import { promises as fs8 } from "fs";
2956
2892
  import path4 from "path";
@@ -2997,10 +2933,6 @@ ${MCP_USE_DIR}
2997
2933
  }
2998
2934
 
2999
2935
  // src/commands/deploy.ts
3000
- var GATEWAY_DOMAIN = "run.mcp-use.com";
3001
- function buildGatewayUrl(slugOrId) {
3002
- return `https://${slugOrId}.${GATEWAY_DOMAIN}/mcp`;
3003
- }
3004
2936
  async function parseEnvFile(filePath) {
3005
2937
  try {
3006
2938
  const content = await fs9.readFile(filePath, "utf-8");
@@ -3010,9 +2942,7 @@ async function parseEnvFile(filePath) {
3010
2942
  let currentValue = "";
3011
2943
  for (let line of lines) {
3012
2944
  line = line.trim();
3013
- if (!line || line.startsWith("#")) {
3014
- continue;
3015
- }
2945
+ if (!line || line.startsWith("#")) continue;
3016
2946
  if (currentKey && !line.includes("=")) {
3017
2947
  currentValue += "\n" + line;
3018
2948
  continue;
@@ -3023,20 +2953,15 @@ async function parseEnvFile(filePath) {
3023
2953
  currentValue = "";
3024
2954
  }
3025
2955
  const equalIndex = line.indexOf("=");
3026
- if (equalIndex === -1) {
3027
- continue;
3028
- }
2956
+ if (equalIndex === -1) continue;
3029
2957
  const key = line.substring(0, equalIndex).trim();
3030
- let value = line.substring(equalIndex + 1).trim();
2958
+ const value = line.substring(equalIndex + 1).trim();
3031
2959
  if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
3032
- console.log(
3033
- source_default.yellow(`\u26A0\uFE0F Skipping invalid environment variable key: ${key}`)
3034
- );
2960
+ console.log(source_default.yellow(`\u26A0\uFE0F Skipping invalid env key: ${key}`));
3035
2961
  continue;
3036
2962
  }
3037
2963
  if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
3038
- value = value.slice(1, -1);
3039
- envVars[key] = value;
2964
+ envVars[key] = value.slice(1, -1);
3040
2965
  } else if (value.startsWith('"') || value.startsWith("'")) {
3041
2966
  currentKey = key;
3042
2967
  currentValue = value.slice(1);
@@ -3060,16 +2985,12 @@ async function parseEnvFile(filePath) {
3060
2985
  function parseEnvVar(envStr) {
3061
2986
  const equalIndex = envStr.indexOf("=");
3062
2987
  if (equalIndex === -1) {
3063
- throw new Error(
3064
- `Invalid environment variable format: "${envStr}". Expected KEY=VALUE`
3065
- );
2988
+ throw new Error(`Invalid env format: "${envStr}". Expected KEY=VALUE`);
3066
2989
  }
3067
2990
  const key = envStr.substring(0, equalIndex).trim();
3068
2991
  const value = envStr.substring(equalIndex + 1);
3069
2992
  if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
3070
- throw new Error(
3071
- `Invalid environment variable key: "${key}". Keys must start with a letter or underscore and contain only letters, numbers, and underscores.`
3072
- );
2993
+ throw new Error(`Invalid env key: "${key}".`);
3073
2994
  }
3074
2995
  return { key, value };
3075
2996
  }
@@ -3112,72 +3033,48 @@ async function buildEnvVars(options) {
3112
3033
  }
3113
3034
  async function isMcpProject(cwd = process.cwd()) {
3114
3035
  try {
3115
- const packageJsonPath = path5.join(cwd, "package.json");
3116
- const content = await fs9.readFile(packageJsonPath, "utf-8");
3117
- const packageJson2 = JSON.parse(content);
3118
- const hasMcpDeps = packageJson2.dependencies?.["mcp-use"] || packageJson2.dependencies?.["@modelcontextprotocol/sdk"] || packageJson2.devDependencies?.["mcp-use"] || packageJson2.devDependencies?.["@modelcontextprotocol/sdk"];
3119
- const hasMcpScripts = packageJson2.scripts?.mcp || packageJson2.scripts?.["mcp:dev"];
3120
- return !!(hasMcpDeps || hasMcpScripts);
3036
+ const content = await fs9.readFile(path5.join(cwd, "package.json"), "utf-8");
3037
+ const pkg = JSON.parse(content);
3038
+ return !!(pkg.dependencies?.["mcp-use"] || pkg.dependencies?.["@modelcontextprotocol/sdk"] || pkg.devDependencies?.["mcp-use"] || pkg.devDependencies?.["@modelcontextprotocol/sdk"]);
3121
3039
  } catch {
3122
3040
  return false;
3123
3041
  }
3124
3042
  }
3125
3043
  async function getProjectName(cwd = process.cwd()) {
3126
3044
  try {
3127
- const packageJsonPath = path5.join(cwd, "package.json");
3128
- const content = await fs9.readFile(packageJsonPath, "utf-8");
3129
- const packageJson2 = JSON.parse(content);
3130
- if (packageJson2.name) {
3131
- return packageJson2.name;
3132
- }
3045
+ const content = await fs9.readFile(path5.join(cwd, "package.json"), "utf-8");
3046
+ const pkg = JSON.parse(content);
3047
+ if (pkg.name) return pkg.name;
3133
3048
  } catch {
3134
3049
  }
3135
3050
  return path5.basename(cwd);
3136
3051
  }
3137
- async function detectBuildCommand(cwd = process.cwd()) {
3052
+ async function detectBuildCommand(cwd) {
3138
3053
  try {
3139
- const packageJsonPath = path5.join(cwd, "package.json");
3140
- const content = await fs9.readFile(packageJsonPath, "utf-8");
3141
- const packageJson2 = JSON.parse(content);
3142
- if (packageJson2.scripts?.build) {
3143
- return "npm run build";
3144
- }
3054
+ const content = await fs9.readFile(path5.join(cwd, "package.json"), "utf-8");
3055
+ if (JSON.parse(content).scripts?.build) return "npm run build";
3145
3056
  } catch {
3146
3057
  }
3147
3058
  return void 0;
3148
3059
  }
3149
- async function detectStartCommand(cwd = process.cwd()) {
3060
+ async function detectStartCommand(cwd) {
3150
3061
  try {
3151
- const packageJsonPath = path5.join(cwd, "package.json");
3152
- const content = await fs9.readFile(packageJsonPath, "utf-8");
3153
- const packageJson2 = JSON.parse(content);
3154
- if (packageJson2.scripts?.start) {
3155
- return "npm start";
3156
- }
3157
- if (packageJson2.main) {
3158
- return `node ${packageJson2.main}`;
3159
- }
3062
+ const content = await fs9.readFile(path5.join(cwd, "package.json"), "utf-8");
3063
+ const pkg = JSON.parse(content);
3064
+ if (pkg.scripts?.start) return "npm start";
3065
+ if (pkg.main) return `node ${pkg.main}`;
3160
3066
  } catch {
3161
3067
  }
3162
3068
  return void 0;
3163
3069
  }
3164
- async function detectRuntime(cwd = process.cwd()) {
3165
- try {
3166
- const pythonFiles = ["requirements.txt", "pyproject.toml", "setup.py"];
3167
- for (const file of pythonFiles) {
3168
- try {
3169
- await fs9.access(path5.join(cwd, file));
3170
- return "python";
3171
- } catch {
3172
- continue;
3173
- }
3174
- }
3070
+ async function detectRuntime(cwd) {
3071
+ for (const f of ["requirements.txt", "pyproject.toml", "setup.py"]) {
3175
3072
  try {
3176
- await fs9.access(path5.join(cwd, "package.json"));
3177
- return "node";
3073
+ await fs9.access(path5.join(cwd, f));
3074
+ return "python";
3178
3075
  } catch {
3076
+ continue;
3179
3077
  }
3180
- } catch {
3181
3078
  }
3182
3079
  return "node";
3183
3080
  }
@@ -3187,50 +3084,64 @@ async function prompt(question, defaultValue = "n") {
3187
3084
  input: process.stdin,
3188
3085
  output: process.stdout
3189
3086
  });
3190
- const defaultIndicator = defaultValue === "y" ? "Y/n" : "y/N";
3191
- const questionWithDefault = question.replace(
3192
- /(\(y\/n\):)/,
3193
- `(${defaultIndicator}):`
3194
- );
3087
+ const indicator = defaultValue === "y" ? "Y/n" : "y/N";
3088
+ const q = question.replace(/(\(y\/n\):)/, `(${indicator}):`);
3195
3089
  return new Promise((resolve2) => {
3196
- rl.question(questionWithDefault, (answer) => {
3090
+ rl.question(q, (answer) => {
3197
3091
  rl.close();
3198
- const trimmedAnswer = answer.trim().toLowerCase();
3199
- if (trimmedAnswer === "") {
3200
- resolve2(defaultValue === "y");
3201
- } else {
3202
- resolve2(trimmedAnswer === "y" || trimmedAnswer === "yes");
3203
- }
3092
+ const a = answer.trim().toLowerCase();
3093
+ if (a === "") resolve2(defaultValue === "y");
3094
+ else resolve2(a === "y" || a === "yes");
3204
3095
  });
3205
3096
  });
3206
3097
  }
3207
- function getMcpServerUrl(deployment) {
3208
- if (deployment.customDomain) {
3209
- return `https://${deployment.customDomain}/mcp`;
3210
- } else if (deployment.serverSlug) {
3211
- return buildGatewayUrl(deployment.serverSlug);
3212
- } else if (deployment.serverId) {
3213
- return buildGatewayUrl(deployment.serverId);
3214
- } else {
3215
- return `https://${deployment.domain}/mcp`;
3098
+ async function promptText(question, defaultValue) {
3099
+ const readline = await import("readline");
3100
+ const rl = readline.createInterface({
3101
+ input: process.stdin,
3102
+ output: process.stdout
3103
+ });
3104
+ const suffix = defaultValue ? source_default.gray(` [${defaultValue}]`) : "";
3105
+ return new Promise((resolve2) => {
3106
+ rl.question(question + suffix + " ", (answer) => {
3107
+ rl.close();
3108
+ resolve2(answer.trim() || defaultValue || "");
3109
+ });
3110
+ });
3111
+ }
3112
+ var REQUIRED_IGNORES = [
3113
+ "node_modules",
3114
+ "dist",
3115
+ ".env",
3116
+ ".env.local",
3117
+ ".mcp-use"
3118
+ ];
3119
+ async function ensureGitignore(cwd) {
3120
+ const gitignorePath = path5.join(cwd, ".gitignore");
3121
+ let content = "";
3122
+ try {
3123
+ content = await fs9.readFile(gitignorePath, "utf-8");
3124
+ } catch {
3125
+ }
3126
+ const missing = REQUIRED_IGNORES.filter((entry) => !content.includes(entry));
3127
+ if (missing.length > 0) {
3128
+ const additions = missing.join("\n");
3129
+ const newContent = content + (content.endsWith("\n") ? "" : "\n") + additions + "\n";
3130
+ await fs9.writeFile(gitignorePath, newContent, "utf-8");
3216
3131
  }
3217
3132
  }
3218
- async function displayDeploymentProgress(api, deployment, progressOptions) {
3133
+ async function displayDeploymentProgress(api, deploymentId, progressOptions) {
3219
3134
  const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
3220
3135
  let frameIndex = 0;
3221
3136
  let spinnerInterval = null;
3222
- let lastStep = "";
3223
3137
  const startSpinner = (message) => {
3224
- if (spinnerInterval) {
3225
- clearInterval(spinnerInterval);
3226
- }
3138
+ if (spinnerInterval) clearInterval(spinnerInterval);
3227
3139
  process.stdout.write("\r\x1B[K");
3228
3140
  spinnerInterval = setInterval(() => {
3229
- const frame = frames[frameIndex];
3230
- frameIndex = (frameIndex + 1) % frames.length;
3231
3141
  process.stdout.write(
3232
- "\r" + source_default.cyan(frame) + " " + source_default.gray(message)
3142
+ "\r" + source_default.cyan(frames[frameIndex]) + " " + source_default.gray(message)
3233
3143
  );
3144
+ frameIndex = (frameIndex + 1) % frames.length;
3234
3145
  }, 80);
3235
3146
  };
3236
3147
  const stopSpinner = () => {
@@ -3242,82 +3153,56 @@ async function displayDeploymentProgress(api, deployment, progressOptions) {
3242
3153
  };
3243
3154
  console.log();
3244
3155
  startSpinner("Deploying...");
3245
- try {
3246
- for await (const log of api.streamDeploymentLogs(deployment.id)) {
3247
- try {
3248
- const logData = JSON.parse(log);
3249
- if (logData.step && logData.step !== lastStep) {
3250
- lastStep = logData.step;
3251
- const stepMessages = {
3252
- clone: "Preparing source code...",
3253
- analyze: "Analyzing project...",
3254
- build: "Building container image...",
3255
- deploy: "Deploying to cloud..."
3256
- };
3257
- const message = stepMessages[logData.step] || "Deploying...";
3258
- startSpinner(message);
3259
- }
3260
- if (logData.line) {
3261
- stopSpinner();
3262
- const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
3263
- const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
3264
- console.log(stepPrefix + levelColor(logData.line));
3265
- }
3266
- } catch {
3267
- }
3268
- }
3269
- } catch (error) {
3270
- stopSpinner();
3271
- }
3272
3156
  let checkCount = 0;
3273
- const maxChecks = 60;
3274
- let delay = 3e3;
3157
+ const maxChecks = 120;
3158
+ let delay = 2e3;
3275
3159
  const maxDelay = 1e4;
3276
- let lastDisplayedLogLength = 0;
3160
+ let buildLogOffset = 0;
3277
3161
  while (checkCount < maxChecks) {
3278
- const currentDelay = delay;
3279
- await new Promise((resolve2) => setTimeout(resolve2, currentDelay));
3280
- const finalDeployment = await api.getDeployment(deployment.id);
3281
- if (finalDeployment.buildLogs && finalDeployment.buildLogs.length > lastDisplayedLogLength) {
3282
- const newLogs = finalDeployment.buildLogs.substring(
3283
- lastDisplayedLogLength
3162
+ const waitMs = delay;
3163
+ await new Promise((r) => setTimeout(r, waitMs));
3164
+ checkCount++;
3165
+ try {
3166
+ const resp = await api.getDeploymentBuildLogs(
3167
+ deploymentId,
3168
+ buildLogOffset
3284
3169
  );
3285
- const logLines = newLogs.split("\n").filter((l) => l.trim());
3286
- for (const line of logLines) {
3287
- try {
3288
- const logData = JSON.parse(line);
3289
- if (logData.line) {
3170
+ if (resp.logs.length > 0) {
3171
+ for (const line of resp.logs.split("\n").filter((l) => l.trim())) {
3172
+ try {
3173
+ const d = JSON.parse(line);
3174
+ if (d.line) {
3175
+ stopSpinner();
3176
+ const color = d.level === "error" ? source_default.red : d.level === "warn" ? source_default.yellow : source_default.gray;
3177
+ const prefix = d.step ? source_default.cyan(`[${d.step}]`) + " " : "";
3178
+ console.log(prefix + color(d.line));
3179
+ }
3180
+ } catch {
3290
3181
  stopSpinner();
3291
- const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
3292
- const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
3293
- console.log(stepPrefix + levelColor(logData.line));
3182
+ console.log(source_default.gray(line));
3294
3183
  }
3295
- } catch {
3296
3184
  }
3185
+ buildLogOffset = resp.offset;
3297
3186
  }
3298
- lastDisplayedLogLength = finalDeployment.buildLogs.length;
3187
+ } catch {
3299
3188
  }
3300
- if (finalDeployment.status === "running") {
3301
- const mcpServerUrl = getMcpServerUrl(finalDeployment);
3302
- let dashboardUrl = null;
3189
+ const dep = await api.getDeployment(deploymentId);
3190
+ if (dep.status === "running") {
3191
+ stopSpinner();
3192
+ const mcpUrl = getMcpServerUrl(dep);
3303
3193
  const webUrl = (await getWebUrl()).replace(/\/$/, "");
3304
3194
  const config = await readConfig();
3305
- const orgSlug = config.profileSlug;
3306
- const serverRef = finalDeployment.serverSlug || finalDeployment.serverId;
3307
- if (serverRef) {
3308
- if (orgSlug) {
3309
- dashboardUrl = `${webUrl}/cloud/${orgSlug}/servers/${serverRef}`;
3310
- } else {
3311
- dashboardUrl = `${webUrl}/cloud/servers/${serverRef}`;
3312
- }
3195
+ let dashboardUrl = null;
3196
+ if (dep.serverId) {
3197
+ dashboardUrl = config.orgSlug ? `${webUrl}/cloud/${config.orgSlug}/servers/${dep.serverId}` : `${webUrl}/cloud/servers/${dep.serverId}`;
3313
3198
  }
3314
- const inspectorUrl = `https://inspector.manufact.com/inspector?autoConnect=${encodeURIComponent(
3315
- mcpServerUrl
3316
- )}`;
3199
+ const inspectorUrl = `https://inspector.manufact.com/inspector?autoConnect=${encodeURIComponent(mcpUrl)}`;
3317
3200
  console.log(source_default.green.bold("\u2713 Deployment successful!\n"));
3318
- console.log(source_default.white("\u{1F310} MCP Server URL:"));
3319
- console.log(source_default.cyan.bold(` ${mcpServerUrl}
3201
+ if (mcpUrl) {
3202
+ console.log(source_default.white("\u{1F310} MCP Server URL:"));
3203
+ console.log(source_default.cyan.bold(` ${mcpUrl}
3320
3204
  `));
3205
+ }
3321
3206
  if (dashboardUrl) {
3322
3207
  console.log(source_default.white("\u{1F4CA} Dashboard:"));
3323
3208
  console.log(source_default.cyan.bold(` ${dashboardUrl}
@@ -3326,169 +3211,76 @@ async function displayDeploymentProgress(api, deployment, progressOptions) {
3326
3211
  console.log(source_default.white("\u{1F50D} Inspector URL:"));
3327
3212
  console.log(source_default.cyan.bold(` ${inspectorUrl}
3328
3213
  `));
3329
- console.log(
3330
- source_default.gray("Deployment ID: ") + source_default.white(finalDeployment.id)
3331
- );
3214
+ console.log(source_default.gray("Deployment ID: ") + source_default.white(dep.id));
3332
3215
  return;
3333
- } else if (finalDeployment.status === "failed") {
3216
+ } else if (dep.status === "failed") {
3334
3217
  stopSpinner();
3335
3218
  console.log(source_default.red.bold("\u2717 Deployment failed\n"));
3336
- if (finalDeployment.error) {
3337
- console.log(source_default.red("Error: ") + finalDeployment.error);
3338
- if (finalDeployment.error.includes("No GitHub installations found")) {
3339
- console.log();
3340
- const retry = await promptGitHubInstallation(
3341
- api,
3342
- "not_connected",
3343
- void 0,
3344
- { yes: progressOptions?.yes }
3345
- );
3346
- if (retry) {
3347
- console.log(source_default.cyan("\n\u{1F504} Retrying deployment...\n"));
3348
- const newDeployment = await api.redeployDeployment(deployment.id);
3349
- await displayDeploymentProgress(
3350
- api,
3351
- newDeployment,
3352
- progressOptions
3353
- );
3354
- return;
3355
- }
3356
- } else if (finalDeployment.error.includes("Authenticated git clone failed")) {
3357
- let repoName;
3358
- const repoMatch = finalDeployment.error.match(
3359
- /github\.com\/([^/]+\/[^/\s]+)/
3360
- );
3361
- if (repoMatch) {
3362
- repoName = repoMatch[1].replace(/\.git$/, "");
3363
- } else if (finalDeployment.source.type === "github") {
3364
- repoName = finalDeployment.source.repo;
3365
- }
3366
- console.log();
3367
- const retry = await promptGitHubInstallation(
3368
- api,
3369
- "no_access",
3370
- repoName,
3371
- { yes: progressOptions?.yes }
3219
+ if (dep.error) {
3220
+ const internalPatterns = [
3221
+ "GraphQL",
3222
+ "authenticated",
3223
+ "INTERNAL",
3224
+ "Fly API",
3225
+ "token validation",
3226
+ "context deadline",
3227
+ "Bad gateway",
3228
+ "502",
3229
+ "503"
3230
+ ];
3231
+ const isInternalError = internalPatterns.some(
3232
+ (p) => dep.error.includes(p)
3233
+ );
3234
+ if (isInternalError) {
3235
+ console.log(
3236
+ source_default.red("Error: ") + "An internal infrastructure error occurred. Please try again."
3372
3237
  );
3373
- if (retry) {
3374
- console.log(source_default.cyan("\n\u{1F504} Retrying deployment...\n"));
3375
- const newDeployment = await api.redeployDeployment(deployment.id);
3376
- await displayDeploymentProgress(
3377
- api,
3378
- newDeployment,
3379
- progressOptions
3380
- );
3381
- return;
3382
- }
3383
- }
3384
- }
3385
- if (finalDeployment.buildLogs) {
3386
- console.log(source_default.gray("\nBuild logs:"));
3387
- try {
3388
- const logs = finalDeployment.buildLogs.split("\n").filter((l) => l.trim());
3389
- for (const log of logs) {
3390
- try {
3391
- const logData = JSON.parse(log);
3392
- if (logData.line) {
3393
- console.log(source_default.gray(` ${logData.line}`));
3394
- }
3395
- } catch {
3396
- console.log(source_default.gray(` ${log}`));
3397
- }
3398
- }
3399
- } catch {
3400
- console.log(source_default.gray(finalDeployment.buildLogs));
3238
+ console.log(source_default.gray(" Details: " + dep.error));
3239
+ } else {
3240
+ console.log(source_default.red("Error: ") + dep.error);
3401
3241
  }
3402
3242
  }
3403
3243
  process.exit(1);
3404
- } else if (finalDeployment.status === "building") {
3244
+ } else if (dep.status === "building" || dep.status === "pending") {
3405
3245
  startSpinner("Building and deploying...");
3406
- checkCount++;
3407
3246
  delay = Math.min(delay * 1.2, maxDelay);
3408
3247
  } else {
3409
- console.log(
3410
- source_default.yellow("\u26A0\uFE0F Deployment status: ") + finalDeployment.status
3411
- );
3248
+ stopSpinner();
3249
+ console.log(source_default.yellow("\u26A0\uFE0F Deployment status: ") + dep.status);
3412
3250
  return;
3413
3251
  }
3414
3252
  }
3415
3253
  stopSpinner();
3416
3254
  console.log(source_default.yellow("\u26A0\uFE0F Deployment is taking longer than expected."));
3417
3255
  console.log(
3418
- source_default.gray("Check status with: ") + source_default.white(`mcp-use status ${deployment.id}`)
3256
+ source_default.gray("Check status with: ") + source_default.white(`mcp-use deployments get ${deploymentId}`)
3419
3257
  );
3420
3258
  }
3421
3259
  async function checkRepoAccess(api, owner, repo) {
3422
3260
  try {
3423
- const reposResponse = await api.getGitHubRepos(true);
3424
- const repoFullName = `${owner}/${repo}`;
3425
- return reposResponse.repos.some((r) => r.full_name === repoFullName);
3426
- } catch (error) {
3427
- console.log(source_default.gray("Could not verify repository access"));
3261
+ const resp = await api.getGitHubRepos(true);
3262
+ return resp.repos.some((r) => r.full_name === `${owner}/${repo}`);
3263
+ } catch {
3428
3264
  return false;
3429
3265
  }
3430
3266
  }
3431
- var GITHUB_SETUP_POLL_INTERVAL_MS = 2e3;
3432
- var GITHUB_SETUP_POLL_MAX_MS = 12e4;
3433
- async function waitForGitHubSetupAfterBrowser(api, repoName, yes) {
3434
- if (!yes) {
3435
- console.log(source_default.gray("Waiting for GitHub configuration..."));
3436
- await prompt(
3437
- source_default.white("Press Enter when you've completed the GitHub setup..."),
3438
- "y"
3439
- );
3440
- return;
3441
- }
3442
- console.log(
3443
- source_default.gray(
3444
- "Waiting for GitHub configuration (polling every 2s, up to 2 min)..."
3445
- )
3446
- );
3447
- const deadline = Date.now() + GITHUB_SETUP_POLL_MAX_MS;
3448
- while (Date.now() < deadline) {
3449
- try {
3450
- const status = await api.getGitHubConnectionStatus();
3451
- if (!status.is_connected) {
3452
- await new Promise((r) => setTimeout(r, GITHUB_SETUP_POLL_INTERVAL_MS));
3453
- continue;
3454
- }
3455
- if (repoName) {
3456
- const parts = repoName.split("/");
3457
- const owner = parts[0];
3458
- const repo = parts[1];
3459
- if (owner && repo && await checkRepoAccess(api, owner, repo)) {
3460
- return;
3461
- }
3462
- } else {
3463
- return;
3464
- }
3465
- } catch {
3466
- }
3467
- await new Promise((r) => setTimeout(r, GITHUB_SETUP_POLL_INTERVAL_MS));
3468
- }
3469
- console.log(
3470
- source_default.yellow(
3471
- "\u26A0\uFE0F Timed out waiting for GitHub setup. Continuing with verification..."
3472
- )
3473
- );
3474
- }
3475
- async function promptGitHubInstallation(api, reason, repoName, opts) {
3476
- const yes = !!opts?.yes;
3477
- console.log();
3478
- if (reason === "not_connected") {
3479
- console.log(source_default.yellow("\u26A0\uFE0F GitHub account not connected"));
3480
- console.log(
3481
- source_default.white("Deployments require a connected GitHub account.\n")
3482
- );
3483
- } else {
3484
- console.log(
3485
- source_default.yellow("\u26A0\uFE0F GitHub App doesn't have access to this repository")
3486
- );
3487
- console.log(
3488
- source_default.white(
3489
- `The GitHub App needs permission to access ${source_default.cyan(repoName || "this repository")}.
3490
- `
3491
- )
3267
+ async function promptGitHubInstallation(api, reason, repoName, opts) {
3268
+ const yes = !!opts?.yes;
3269
+ console.log();
3270
+ if (reason === "not_connected") {
3271
+ console.log(source_default.yellow("\u26A0\uFE0F GitHub account not connected"));
3272
+ console.log(
3273
+ source_default.white("Deployments require a connected GitHub account.\n")
3274
+ );
3275
+ } else {
3276
+ console.log(
3277
+ source_default.yellow("\u26A0\uFE0F GitHub App doesn't have access to this repository")
3278
+ );
3279
+ console.log(
3280
+ source_default.white(
3281
+ `The GitHub App needs permission to access ${source_default.cyan(repoName || "this repository")}.
3282
+ `
3283
+ )
3492
3284
  );
3493
3285
  }
3494
3286
  const shouldInstall = yes ? true : await prompt(
@@ -3497,96 +3289,48 @@ async function promptGitHubInstallation(api, reason, repoName, opts) {
3497
3289
  ),
3498
3290
  "y"
3499
3291
  );
3500
- if (!shouldInstall) {
3501
- return false;
3502
- }
3292
+ if (!shouldInstall) return false;
3503
3293
  try {
3504
- const appName = process.env.MCP_GITHUB_APP_NAME || "mcp-use";
3505
- const installUrl = reason === "not_connected" ? `https://github.com/apps/${appName}/installations/new` : `https://github.com/settings/installations`;
3506
- console.log(
3507
- source_default.cyan(
3508
- `
3509
- Opening browser to ${reason === "not_connected" ? "install" : "configure"} GitHub App...`
3510
- )
3511
- );
3294
+ const appName = await api.getGitHubAppName();
3295
+ const installUrl = `https://github.com/apps/${appName}/installations/new`;
3296
+ console.log(source_default.cyan(`
3297
+ Opening browser...`));
3512
3298
  console.log(source_default.gray(`URL: ${installUrl}
3513
3299
  `));
3514
3300
  if (reason === "no_access") {
3515
- console.log(source_default.white("Please:"));
3516
3301
  console.log(
3517
- source_default.cyan(" 1. Find the 'mcp-use' (or similar) GitHub App")
3302
+ source_default.white("Please add ") + source_default.cyan.bold(repoName || "your repository") + source_default.white(" to the app's repository access, then return here.\n")
3518
3303
  );
3519
- console.log(source_default.cyan(" 2. Click 'Configure'"));
3304
+ } else {
3520
3305
  console.log(
3521
- source_default.cyan(
3522
- ` 3. Grant access to ${source_default.bold(repoName || "your repository")}`
3523
- )
3306
+ source_default.white("Complete the GitHub App installation, then return here.\n")
3524
3307
  );
3525
- console.log(source_default.cyan(" 4. Save your changes"));
3526
- console.log(source_default.cyan(" 5. Return here when done\n"));
3527
- } else {
3528
- console.log(source_default.white("Please:"));
3529
- console.log(source_default.cyan(" 1. Select the repositories to grant access"));
3530
- if (repoName) {
3531
- console.log(
3532
- source_default.cyan(` 2. Make sure to include ${source_default.bold(repoName)}`)
3533
- );
3534
- console.log(source_default.cyan(" 3. Complete the installation"));
3535
- } else {
3536
- console.log(source_default.cyan(" 2. Complete the installation"));
3537
- }
3538
- console.log();
3539
3308
  }
3540
3309
  await open_default(installUrl);
3541
- await waitForGitHubSetupAfterBrowser(api, repoName, yes);
3542
- console.log(source_default.gray("Verifying GitHub connection..."));
3543
- let verified = false;
3544
- try {
3545
- const status = await api.getGitHubConnectionStatus();
3546
- if (!status.is_connected) {
3547
- console.log(source_default.yellow("\u26A0\uFE0F GitHub connection not detected."));
3548
- } else if (repoName) {
3549
- const [owner, repo] = repoName.split("/");
3550
- console.log(source_default.gray(`Checking access to ${repoName}...`));
3551
- const hasAccess = await checkRepoAccess(api, owner, repo);
3552
- if (!hasAccess) {
3553
- console.log(
3554
- source_default.yellow(
3555
- `\u26A0\uFE0F The GitHub App may not have access to ${source_default.cyan(repoName)} yet`
3556
- )
3557
- );
3558
- } else {
3559
- console.log(source_default.green(`\u2713 Repository ${repoName} is accessible!
3560
- `));
3561
- verified = true;
3310
+ if (!yes) {
3311
+ await prompt(source_default.white("Press Enter when done..."), "y");
3312
+ } else {
3313
+ console.log(source_default.gray("Waiting for GitHub configuration (polling)..."));
3314
+ const deadline = Date.now() + 12e4;
3315
+ while (Date.now() < deadline) {
3316
+ await new Promise((r) => setTimeout(r, 2e3));
3317
+ try {
3318
+ const status = await api.getGitHubConnectionStatus();
3319
+ if (status.is_connected) {
3320
+ if (!repoName) return true;
3321
+ const [o, r] = repoName.split("/");
3322
+ if (o && r && await checkRepoAccess(api, o, r)) return true;
3323
+ }
3324
+ } catch {
3562
3325
  }
3563
- } else {
3564
- console.log(source_default.green("\u2713 GitHub connected successfully!\n"));
3565
- verified = true;
3566
3326
  }
3567
- } catch (error) {
3568
- console.log(
3569
- source_default.yellow("\u26A0\uFE0F Could not verify GitHub connection (API issue)")
3570
- );
3571
- }
3572
- if (!verified) {
3573
- console.log(
3574
- source_default.gray(
3575
- "\nNote: If you completed the GitHub setup, the deployment may work now.\n"
3576
- )
3577
- );
3578
3327
  }
3579
3328
  return true;
3580
- } catch (error) {
3581
- console.log(
3582
- source_default.yellow("\n\u26A0\uFE0F Unable to open GitHub installation automatically")
3583
- );
3329
+ } catch {
3330
+ console.log(source_default.yellow("\n\u26A0\uFE0F Unable to open browser automatically"));
3584
3331
  console.log(
3585
3332
  source_default.white("Please visit: ") + source_default.cyan("https://manufact.com/cloud/settings")
3586
3333
  );
3587
- console.log(
3588
- source_default.gray("Then connect your GitHub account and try again.\n")
3589
- );
3590
3334
  return false;
3591
3335
  }
3592
3336
  }
@@ -3594,47 +3338,139 @@ async function deployCommand(options) {
3594
3338
  try {
3595
3339
  const cwd = process.cwd();
3596
3340
  if (!await isLoggedIn()) {
3597
- console.log(source_default.red("\u2717 You are not logged in."));
3341
+ console.log(source_default.cyan.bold("Welcome to Manufact Cloud!\n"));
3598
3342
  if (options.yes) {
3599
3343
  console.log(
3600
- source_default.gray(
3601
- "Run " + source_default.white("npx mcp-use login") + " first. Non-interactive deploy requires an existing session."
3344
+ source_default.red(
3345
+ "\u2717 Not logged in. Run " + source_default.white("npx mcp-use login") + " first."
3602
3346
  )
3603
3347
  );
3604
3348
  process.exit(1);
3605
3349
  }
3606
3350
  const shouldLogin = await prompt(
3607
- source_default.white("Would you like to login now? (Y/n): "),
3351
+ source_default.white("You need to log in to deploy. Log in now? (Y/n): "),
3608
3352
  "y"
3609
3353
  );
3610
- if (shouldLogin) {
3611
- try {
3612
- await loginCommand({ silent: false });
3613
- if (!await isLoggedIn()) {
3614
- console.log(
3615
- source_default.red("\u2717 Login verification failed. Please try again.")
3616
- );
3617
- process.exit(1);
3618
- }
3619
- console.log(source_default.gray("\nContinuing with deployment...\n"));
3620
- } catch (error) {
3621
- console.error(
3622
- source_default.red.bold("\u2717 Login failed:"),
3623
- source_default.red(error instanceof Error ? error.message : "Unknown error")
3624
- );
3625
- process.exit(1);
3626
- }
3627
- } else {
3354
+ if (!shouldLogin) {
3628
3355
  console.log(
3629
3356
  source_default.gray(
3630
3357
  "Run " + source_default.white("npx mcp-use login") + " to get started."
3631
3358
  )
3632
3359
  );
3360
+ process.exit(0);
3361
+ }
3362
+ try {
3363
+ await loginCommand({ silent: false });
3364
+ if (!await isLoggedIn()) {
3365
+ console.log(source_default.red("\u2717 Login failed. Please try again."));
3366
+ process.exit(1);
3367
+ }
3368
+ console.log(source_default.gray("\nContinuing with deployment...\n"));
3369
+ } catch (error) {
3370
+ console.error(
3371
+ source_default.red.bold("\u2717 Login failed:"),
3372
+ source_default.red(error instanceof Error ? error.message : "Unknown error")
3373
+ );
3374
+ process.exit(1);
3375
+ }
3376
+ }
3377
+ const api = await McpUseAPI.create();
3378
+ if (options.org) {
3379
+ const authInfo = await api.testAuth();
3380
+ const match = (authInfo.orgs ?? []).find(
3381
+ (o) => o.slug === options.org || o.id === options.org || o.name.toLowerCase() === options.org.toLowerCase()
3382
+ );
3383
+ if (match) {
3384
+ api.setOrgId(match.id);
3385
+ const slug = match.slug ? source_default.gray(` (${match.slug})`) : "";
3386
+ console.log(
3387
+ source_default.gray("Organization: ") + source_default.cyan(match.name) + slug
3388
+ );
3389
+ } else {
3390
+ console.error(
3391
+ source_default.red(
3392
+ `\u2717 Organization "${options.org}" not found. Run ${source_default.white("npx mcp-use org list")} to see available organizations.`
3393
+ )
3394
+ );
3395
+ process.exit(1);
3396
+ }
3397
+ } else {
3398
+ const config = await readConfig();
3399
+ if (!config.orgId) {
3400
+ const authInfo = await api.testAuth();
3401
+ if (authInfo.orgs.length === 0) {
3402
+ console.log(
3403
+ source_default.red(
3404
+ "\u2717 No organizations found. Please create one at manufact.com/cloud."
3405
+ )
3406
+ );
3407
+ process.exit(1);
3408
+ }
3409
+ let selectedOrg;
3410
+ if (authInfo.orgs.length === 1) {
3411
+ selectedOrg = authInfo.orgs[0];
3412
+ } else {
3413
+ selectedOrg = await promptOrgSelection(
3414
+ authInfo.orgs,
3415
+ authInfo.default_org_id
3416
+ );
3417
+ }
3418
+ if (!selectedOrg) {
3419
+ console.log(source_default.red("\u2717 No organization selected."));
3420
+ process.exit(1);
3421
+ }
3422
+ api.setOrgId(selectedOrg.id);
3423
+ await writeConfig({
3424
+ ...config,
3425
+ orgId: selectedOrg.id,
3426
+ orgName: selectedOrg.name,
3427
+ orgSlug: selectedOrg.slug ?? void 0
3428
+ });
3429
+ console.log(
3430
+ source_default.gray("Organization: ") + source_default.cyan(selectedOrg.name)
3431
+ );
3432
+ } else {
3433
+ if (config.orgName) {
3434
+ const slug = config.orgSlug ? source_default.gray(` (${config.orgSlug})`) : "";
3435
+ console.log(
3436
+ source_default.gray("Organization: ") + source_default.cyan(config.orgName) + slug
3437
+ );
3438
+ }
3439
+ }
3440
+ }
3441
+ console.log(source_default.cyan.bold("\n\u{1F680} Deploying to Manufact cloud...\n"));
3442
+ let connectionStatus = await api.getGitHubConnectionStatus().catch(() => null);
3443
+ if (!connectionStatus?.is_connected) {
3444
+ const installed = await promptGitHubInstallation(
3445
+ api,
3446
+ "not_connected",
3447
+ void 0,
3448
+ { yes: options.yes }
3449
+ );
3450
+ if (!installed) {
3633
3451
  console.log(source_default.gray("Deployment cancelled."));
3634
3452
  process.exit(0);
3635
3453
  }
3454
+ connectionStatus = await api.getGitHubConnectionStatus().catch(() => null);
3455
+ if (!connectionStatus?.is_connected) {
3456
+ console.log(source_default.red("\n\u2717 GitHub connection could not be verified."));
3457
+ console.log(
3458
+ source_default.cyan(
3459
+ " Visit https://manufact.com/cloud/settings to connect GitHub.\n"
3460
+ )
3461
+ );
3462
+ process.exit(1);
3463
+ }
3464
+ }
3465
+ const installations = connectionStatus.installations ?? [];
3466
+ if (installations.length === 0) {
3467
+ console.log(source_default.red("\u2717 No GitHub installations found."));
3468
+ process.exit(1);
3636
3469
  }
3637
- console.log(source_default.cyan.bold("\u{1F680} Deploying to Manufact cloud...\n"));
3470
+ const defaultInstallation = installations.find((i) => i.account_type === "Organization") ?? installations[0];
3471
+ const installationDbId = defaultInstallation.id;
3472
+ const githubInstallationId = defaultInstallation.installation_id;
3473
+ console.log(source_default.green("\u2713 GitHub connected\n"));
3638
3474
  const projectDir = options.rootDir ? path5.resolve(cwd, options.rootDir) : cwd;
3639
3475
  if (options.rootDir) {
3640
3476
  try {
@@ -3645,381 +3481,383 @@ async function deployCommand(options) {
3645
3481
  );
3646
3482
  process.exit(1);
3647
3483
  }
3648
- console.log(source_default.gray(` Root dir: `) + source_default.cyan(options.rootDir));
3649
3484
  }
3650
3485
  const isMcp = await isMcpProject(projectDir);
3651
- if (!isMcp) {
3486
+ if (!isMcp && !options.yes) {
3652
3487
  console.log(
3653
- source_default.yellow(
3654
- "\u26A0\uFE0F This doesn't appear to be an MCP server project (no mcp-use or @modelcontextprotocol/sdk dependency found)."
3655
- )
3488
+ source_default.yellow("\u26A0\uFE0F This doesn't look like an MCP server project.")
3489
+ );
3490
+ const shouldContinue = await prompt(
3491
+ source_default.white("Continue anyway? (y/n): ")
3656
3492
  );
3657
- if (!options.yes) {
3658
- const shouldContinue = await prompt(
3659
- source_default.white("Continue anyway? (y/n): ")
3493
+ if (!shouldContinue) {
3494
+ process.exit(0);
3495
+ }
3496
+ console.log();
3497
+ }
3498
+ let gitInfo = await getGitInfo(cwd);
3499
+ let repoFullName;
3500
+ let branch = "main";
3501
+ if (!gitInfo.isGitRepo || !gitInfo.remoteUrl) {
3502
+ const projectName2 = options.name || await getProjectName(projectDir);
3503
+ console.log(source_default.yellow("\u26A0\uFE0F No GitHub remote found.\n"));
3504
+ if (options.yes) {
3505
+ console.log(source_default.gray("Creating GitHub repository automatically..."));
3506
+ } else {
3507
+ const shouldCreate = await prompt(
3508
+ source_default.white("Create a GitHub repository and push your code? (Y/n): "),
3509
+ "y"
3660
3510
  );
3661
- if (!shouldContinue) {
3662
- console.log(source_default.gray("Deployment cancelled."));
3511
+ if (!shouldCreate) {
3512
+ console.log(
3513
+ source_default.gray(
3514
+ "Deployment cancelled. Set up a GitHub remote and try again."
3515
+ )
3516
+ );
3663
3517
  process.exit(0);
3664
3518
  }
3665
3519
  }
3666
- console.log();
3667
- }
3668
- const gitInfo = await getGitInfo(cwd);
3669
- if (!gitInfo.isGitRepo) {
3670
- console.log(source_default.red("\u2717 Not a git repository\n"));
3671
- console.log(source_default.white("To deploy, initialize git and push to GitHub:"));
3672
- console.log(source_default.gray(" 1. Initialize git:"));
3673
- console.log(source_default.cyan(" git init\n"));
3674
- console.log(source_default.gray(" 2. Create a GitHub repository at:"));
3675
- console.log(source_default.cyan(" https://github.com/new\n"));
3676
- console.log(source_default.gray(" 3. Add the remote and push:"));
3677
- console.log(source_default.cyan(" git remote add origin <your-github-url>"));
3678
- console.log(source_default.cyan(" git add ."));
3679
- console.log(source_default.cyan(" git commit -m 'Initial commit'"));
3680
- console.log(source_default.cyan(" git push -u origin main\n"));
3681
- process.exit(1);
3682
- }
3683
- if (!gitInfo.remoteUrl) {
3684
- console.log(source_default.red("\u2717 No git remote configured\n"));
3685
- console.log(source_default.white("Add a GitHub remote:"));
3686
- console.log(source_default.cyan(" git remote add origin <your-github-url>\n"));
3687
- process.exit(1);
3688
- }
3689
- if (!isGitHubUrl(gitInfo.remoteUrl)) {
3520
+ const defaultIdx = installations.findIndex(
3521
+ (i) => i.account_type === "Organization"
3522
+ );
3523
+ let selectedIdx = defaultIdx >= 0 ? defaultIdx : 0;
3524
+ if (installations.length > 1 && !options.yes) {
3525
+ console.log(
3526
+ source_default.cyan.bold("\u{1F419} Select a GitHub account for the repository:\n")
3527
+ );
3528
+ for (let i = 0; i < installations.length; i++) {
3529
+ const inst = installations[i];
3530
+ const typeLabel = inst.account_type === "Organization" ? source_default.gray(" (org)") : source_default.gray(" (personal)");
3531
+ const marker = i === selectedIdx ? source_default.green(" \u2190 default") : "";
3532
+ console.log(
3533
+ ` ${source_default.white(`${i + 1}.`)} ${inst.account_login}${typeLabel}${marker}`
3534
+ );
3535
+ }
3536
+ console.log();
3537
+ const readline = await import("readline");
3538
+ const rl = readline.createInterface({
3539
+ input: process.stdin,
3540
+ output: process.stdout
3541
+ });
3542
+ const answer = await new Promise((resolve2) => {
3543
+ rl.question(
3544
+ source_default.gray(`Enter number [${selectedIdx + 1}]: `),
3545
+ (a) => {
3546
+ rl.close();
3547
+ resolve2(a.trim());
3548
+ }
3549
+ );
3550
+ });
3551
+ const parsed = answer === "" ? selectedIdx : parseInt(answer, 10) - 1;
3552
+ if (parsed >= 0 && parsed < installations.length) {
3553
+ selectedIdx = parsed;
3554
+ }
3555
+ }
3556
+ const repoInstallation = installations[selectedIdx];
3557
+ if (repoInstallation.account_type !== "Organization") {
3558
+ console.log(
3559
+ source_default.yellow(
3560
+ "\n\u26A0\uFE0F GitHub Apps cannot create repos on personal accounts.\n"
3561
+ )
3562
+ );
3563
+ console.log(
3564
+ source_default.white("To deploy from ") + source_default.cyan(repoInstallation.account_login) + source_default.white(", create a repository manually:\n")
3565
+ );
3566
+ console.log(
3567
+ source_default.cyan(" 1. ") + source_default.white("Go to ") + source_default.cyan("https://github.com/new")
3568
+ );
3569
+ console.log(
3570
+ source_default.cyan(" 2. ") + source_default.white("Create a repository (any name, can be private)")
3571
+ );
3572
+ console.log(source_default.cyan(" 3. ") + source_default.white("Add it as a remote:"));
3573
+ console.log(source_default.gray(" git init && git remote add origin <url>"));
3574
+ console.log(source_default.cyan(" 4. ") + source_default.white("Push your code:"));
3575
+ console.log(
3576
+ source_default.gray(
3577
+ " git add . && git commit -m 'Initial commit' && git push -u origin main"
3578
+ )
3579
+ );
3580
+ console.log(
3581
+ source_default.cyan(" 5. ") + source_default.white("Grant the GitHub App access to the repo:")
3582
+ );
3583
+ const appName = await api.getGitHubAppName();
3584
+ console.log(
3585
+ source_default.gray(
3586
+ ` https://github.com/apps/${appName}/installations/new`
3587
+ )
3588
+ );
3589
+ console.log(
3590
+ source_default.cyan(" 6. ") + source_default.white("Run ") + source_default.cyan("mcp-use deploy") + source_default.white(" again\n")
3591
+ );
3592
+ process.exit(0);
3593
+ }
3594
+ const repoName = options.yes ? projectName2 : await promptText(source_default.gray("Repository name:"), projectName2);
3595
+ await ensureGitignore(cwd);
3596
+ console.log(
3597
+ source_default.gray(
3598
+ `Creating repository on ${repoInstallation.account_login}...`
3599
+ )
3600
+ );
3601
+ const repoResult = await api.createGitHubRepo({
3602
+ installationId: repoInstallation.installation_id,
3603
+ name: repoName,
3604
+ private: true,
3605
+ org: repoInstallation.account_login
3606
+ });
3607
+ console.log(source_default.green(`\u2713 Created ${source_default.cyan(repoResult.fullName)}`));
3608
+ if (!gitInfo.isGitRepo) {
3609
+ console.log(source_default.gray("Initializing git..."));
3610
+ await gitInit(cwd, "Initial commit");
3611
+ console.log(source_default.gray("Pushing to GitHub..."));
3612
+ await gitAddRemoteAndPush(cwd, repoResult.cloneUrl, "main");
3613
+ } else {
3614
+ console.log(source_default.gray("Adding remote and pushing..."));
3615
+ await gitAddRemoteAndPush(
3616
+ cwd,
3617
+ repoResult.cloneUrl,
3618
+ gitInfo.branch || "main"
3619
+ );
3620
+ }
3621
+ console.log(source_default.green("\u2713 Code pushed to GitHub\n"));
3622
+ gitInfo = await getGitInfo(cwd);
3623
+ repoFullName = repoResult.fullName;
3624
+ branch = gitInfo.branch || "main";
3625
+ } else if (!isGitHubUrl(gitInfo.remoteUrl)) {
3690
3626
  console.log(source_default.red("\u2717 Remote is not a GitHub repository"));
3691
3627
  console.log(source_default.yellow(` Current remote: ${gitInfo.remoteUrl}
3692
3628
  `));
3693
- console.log(source_default.white("Please add a GitHub remote to deploy."));
3694
3629
  process.exit(1);
3695
- }
3696
- if (!gitInfo.owner || !gitInfo.repo) {
3630
+ } else if (!gitInfo.owner || !gitInfo.repo) {
3697
3631
  console.log(source_default.red("\u2717 Could not parse GitHub repository information"));
3698
3632
  process.exit(1);
3699
- }
3700
- if (gitInfo.hasUncommittedChanges) {
3701
- console.log(source_default.yellow("\u26A0\uFE0F You have uncommitted changes\n"));
3702
- console.log(source_default.white("Deployments use the code pushed to GitHub."));
3703
- console.log(
3704
- source_default.white(
3705
- "Local changes will not be included until you commit and push.\n"
3706
- )
3633
+ } else {
3634
+ repoFullName = `${gitInfo.owner}/${gitInfo.repo}`;
3635
+ branch = gitInfo.branch || "main";
3636
+ if (gitInfo.hasUncommittedChanges) {
3637
+ console.log(source_default.yellow("\u26A0\uFE0F You have uncommitted changes.\n"));
3638
+ if (!options.yes) {
3639
+ const shouldCommit = await prompt(
3640
+ source_default.white("Commit and push changes before deploying? (Y/n): "),
3641
+ "y"
3642
+ );
3643
+ if (shouldCommit) {
3644
+ await ensureGitignore(cwd);
3645
+ console.log(source_default.gray("Committing and pushing..."));
3646
+ await gitCommitAndPush(cwd, "Deploy changes", branch);
3647
+ gitInfo = await getGitInfo(cwd);
3648
+ console.log(source_default.green("\u2713 Changes pushed\n"));
3649
+ } else {
3650
+ console.log(source_default.gray("Deploying from last pushed commit.\n"));
3651
+ }
3652
+ }
3653
+ }
3654
+ console.log(source_default.gray("Checking repository access..."));
3655
+ const hasAccess = await checkRepoAccess(
3656
+ api,
3657
+ gitInfo.owner,
3658
+ gitInfo.repo
3707
3659
  );
3708
- if (!options.yes) {
3709
- const shouldContinue = await prompt(
3710
- source_default.white("Continue with deployment from GitHub? (y/n): ")
3660
+ if (!hasAccess) {
3661
+ console.log(
3662
+ source_default.yellow(
3663
+ `\u26A0\uFE0F GitHub App doesn't have access to ${source_default.cyan(repoFullName)}`
3664
+ )
3665
+ );
3666
+ const configured = await promptGitHubInstallation(
3667
+ api,
3668
+ "no_access",
3669
+ repoFullName,
3670
+ { yes: options.yes, installationId: githubInstallationId }
3711
3671
  );
3712
- if (!shouldContinue) {
3713
- console.log(source_default.gray("Deployment cancelled."));
3672
+ if (!configured) {
3714
3673
  process.exit(0);
3715
3674
  }
3675
+ const retry = await checkRepoAccess(api, gitInfo.owner, gitInfo.repo);
3676
+ if (!retry) {
3677
+ const appName = await api.getGitHubAppName();
3678
+ console.log(
3679
+ source_default.red(
3680
+ `
3681
+ \u2717 Repository ${source_default.cyan(repoFullName)} is still not accessible.`
3682
+ )
3683
+ );
3684
+ console.log(
3685
+ source_default.cyan(
3686
+ ` https://github.com/apps/${appName}/installations/new
3687
+ `
3688
+ )
3689
+ );
3690
+ process.exit(1);
3691
+ }
3716
3692
  }
3717
- console.log();
3718
- }
3719
- console.log(source_default.white("GitHub repository detected:"));
3720
- console.log(
3721
- source_default.gray(` Repository: `) + source_default.cyan(`${gitInfo.owner}/${gitInfo.repo}`)
3722
- );
3723
- console.log(
3724
- source_default.gray(` Branch: `) + source_default.cyan(gitInfo.branch || "main")
3725
- );
3726
- if (gitInfo.commitSha) {
3727
- console.log(
3728
- source_default.gray(` Commit: `) + source_default.gray(gitInfo.commitSha.substring(0, 7))
3729
- );
3730
- }
3731
- if (gitInfo.commitMessage) {
3732
- console.log(
3733
- source_default.gray(` Message: `) + source_default.gray(gitInfo.commitMessage.split("\n")[0])
3734
- );
3735
- }
3736
- console.log();
3737
- if (!options.yes) {
3738
- const shouldDeploy = await prompt(
3739
- source_default.white(
3740
- `Deploy from GitHub repository ${gitInfo.owner}/${gitInfo.repo}? (Y/n): `
3741
- ),
3742
- "y"
3743
- );
3744
- if (!shouldDeploy) {
3745
- console.log(source_default.gray("Deployment cancelled."));
3746
- process.exit(0);
3747
- }
3693
+ console.log(source_default.green("\u2713 Repository access confirmed"));
3748
3694
  }
3749
3695
  const projectName = options.name || await getProjectName(projectDir);
3750
- const runtime = options.runtime || await detectRuntime(projectDir);
3751
3696
  const port = options.port || 3e3;
3752
3697
  const buildCommand = await detectBuildCommand(projectDir);
3753
3698
  const startCommand = await detectStartCommand(projectDir);
3699
+ const runtime = options.runtime || await detectRuntime(projectDir);
3754
3700
  const envVars = await buildEnvVars(options);
3755
3701
  console.log();
3756
3702
  console.log(source_default.white("Deployment configuration:"));
3703
+ console.log(source_default.gray(` Repository: `) + source_default.cyan(repoFullName));
3704
+ console.log(source_default.gray(` Branch: `) + source_default.cyan(branch));
3757
3705
  console.log(source_default.gray(` Name: `) + source_default.cyan(projectName));
3758
3706
  console.log(source_default.gray(` Runtime: `) + source_default.cyan(runtime));
3759
3707
  console.log(source_default.gray(` Port: `) + source_default.cyan(port));
3760
- if (options.rootDir) {
3708
+ if (options.region)
3709
+ console.log(source_default.gray(` Region: `) + source_default.cyan(options.region));
3710
+ if (options.buildCommand)
3761
3711
  console.log(
3762
- source_default.gray(` Root dir: `) + source_default.cyan(options.rootDir)
3712
+ source_default.gray(` Build command: `) + source_default.cyan(options.buildCommand)
3763
3713
  );
3764
- }
3765
- if (buildCommand) {
3766
- console.log(source_default.gray(` Build command: `) + source_default.cyan(buildCommand));
3767
- }
3768
- if (startCommand) {
3769
- console.log(source_default.gray(` Start command: `) + source_default.cyan(startCommand));
3770
- }
3771
- if (envVars && Object.keys(envVars).length > 0) {
3714
+ else if (buildCommand)
3772
3715
  console.log(
3773
- source_default.gray(` Environment: `) + source_default.cyan(`${Object.keys(envVars).length} variable(s)`)
3716
+ source_default.gray(` Build command: `) + source_default.gray(buildCommand + " (auto-detected)")
3774
3717
  );
3718
+ if (options.startCommand)
3775
3719
  console.log(
3776
- source_default.gray(` `) + source_default.gray(Object.keys(envVars).join(", "))
3720
+ source_default.gray(` Start command: `) + source_default.cyan(options.startCommand)
3777
3721
  );
3778
- }
3779
- console.log();
3780
- const api = await McpUseAPI.create();
3781
- if (options.org) {
3782
- try {
3783
- const authInfo = await api.testAuth();
3784
- const match = (authInfo.profiles ?? []).find(
3785
- (p) => p.slug === options.org || p.id === options.org || p.profile_name.toLowerCase() === options.org.toLowerCase()
3786
- );
3787
- if (match) {
3788
- api.setProfileId(match.id);
3789
- const slug = match.slug ? source_default.gray(` (${match.slug})`) : "";
3790
- console.log(
3791
- source_default.gray("Organization: ") + source_default.cyan(match.profile_name) + slug
3792
- );
3793
- } else {
3794
- console.error(
3795
- source_default.red(
3796
- `\u2717 Organization "${options.org}" not found. Run ${source_default.white("npx mcp-use org list")} to see available organizations.`
3797
- )
3798
- );
3799
- process.exit(1);
3800
- }
3801
- } catch (error) {
3802
- console.error(
3803
- source_default.red("\u2717 Failed to resolve organization:"),
3804
- source_default.red(error instanceof Error ? error.message : "Unknown error")
3805
- );
3806
- process.exit(1);
3807
- }
3808
- }
3809
- let githubVerified = false;
3810
- try {
3811
- console.log(source_default.gray(`[DEBUG] API URL: ${api.baseUrl}`));
3812
- const connectionStatus = await api.getGitHubConnectionStatus();
3813
- if (!connectionStatus.is_connected) {
3814
- const repoFullName = `${gitInfo.owner}/${gitInfo.repo}`;
3815
- const installed = await promptGitHubInstallation(
3816
- api,
3817
- "not_connected",
3818
- repoFullName,
3819
- { yes: options.yes }
3820
- );
3821
- if (!installed) {
3822
- console.log(source_default.gray("Deployment cancelled."));
3823
- process.exit(0);
3824
- }
3825
- const retryStatus = await api.getGitHubConnectionStatus();
3826
- if (!retryStatus.is_connected) {
3827
- console.log(
3828
- source_default.red("\n\u2717 GitHub connection could not be verified.")
3829
- );
3830
- console.log(
3831
- source_default.gray("Please try connecting GitHub from the web UI:")
3832
- );
3833
- console.log(source_default.cyan(" https://manufact.com/cloud/settings\n"));
3834
- process.exit(1);
3835
- }
3836
- githubVerified = true;
3837
- } else if (gitInfo.owner && gitInfo.repo) {
3838
- console.log(source_default.gray("Checking repository access..."));
3839
- const hasAccess = await checkRepoAccess(
3840
- api,
3841
- gitInfo.owner,
3842
- gitInfo.repo
3843
- );
3844
- if (!hasAccess) {
3845
- const repoFullName = `${gitInfo.owner}/${gitInfo.repo}`;
3846
- console.log(
3847
- source_default.yellow(
3848
- `\u26A0\uFE0F GitHub App doesn't have access to ${source_default.cyan(repoFullName)}`
3849
- )
3850
- );
3851
- const configured = await promptGitHubInstallation(
3852
- api,
3853
- "no_access",
3854
- repoFullName,
3855
- { yes: options.yes }
3856
- );
3857
- if (!configured) {
3858
- console.log(source_default.gray("Deployment cancelled."));
3859
- process.exit(0);
3860
- }
3861
- const hasAccessRetry = await checkRepoAccess(
3862
- api,
3863
- gitInfo.owner,
3864
- gitInfo.repo
3865
- );
3866
- if (!hasAccessRetry) {
3867
- console.log(
3868
- source_default.red(
3869
- `
3870
- \u2717 Repository ${source_default.cyan(repoFullName)} is still not accessible.`
3871
- )
3872
- );
3873
- console.log(
3874
- source_default.gray(
3875
- "Please make sure the GitHub App has access to this repository."
3876
- )
3877
- );
3878
- console.log(
3879
- source_default.cyan(" https://github.com/settings/installations\n")
3880
- );
3881
- process.exit(1);
3882
- }
3883
- githubVerified = true;
3884
- } else {
3885
- console.log(source_default.green("\u2713 Repository access confirmed"));
3886
- githubVerified = true;
3887
- }
3888
- }
3889
- } catch (error) {
3890
- console.log(source_default.red("\u2717 Could not verify GitHub connection"));
3891
- console.log(
3892
- source_default.gray(
3893
- "Error: " + (error instanceof Error ? error.message : "Unknown error")
3894
- )
3895
- );
3896
- console.log(source_default.gray("\nPlease ensure:"));
3722
+ else if (startCommand)
3897
3723
  console.log(
3898
- source_default.cyan(
3899
- " 1. You have connected GitHub at https://manufact.com/cloud/settings"
3900
- )
3724
+ source_default.gray(` Start command: `) + source_default.gray(startCommand + " (auto-detected)")
3901
3725
  );
3726
+ if (Object.keys(envVars).length > 0) {
3902
3727
  console.log(
3903
- source_default.cyan(" 2. The GitHub App has access to your repository")
3728
+ source_default.gray(` Environment: `) + source_default.cyan(`${Object.keys(envVars).length} variable(s)`)
3904
3729
  );
3905
- console.log(source_default.cyan(" 3. Your internet connection is stable\n"));
3906
- process.exit(1);
3907
3730
  }
3908
- if (!githubVerified) {
3909
- console.log(
3910
- source_default.red("\n\u2717 GitHub verification required for this deployment")
3911
- );
3912
- process.exit(1);
3731
+ console.log();
3732
+ if (!options.yes) {
3733
+ const shouldDeploy = await prompt(source_default.white(`Deploy? (Y/n): `), "y");
3734
+ if (!shouldDeploy) {
3735
+ console.log(source_default.gray("Deployment cancelled."));
3736
+ process.exit(0);
3737
+ }
3913
3738
  }
3914
3739
  const existingLink = !options.new ? await getProjectLink(cwd) : null;
3915
- const serverId = existingLink?.serverId;
3916
- if (existingLink) {
3740
+ let serverId = existingLink?.serverId;
3741
+ if (existingLink && serverId) {
3917
3742
  try {
3918
- const existingDeployment = await api.getDeployment(
3919
- existingLink.deploymentId
3920
- );
3921
- if (existingDeployment && existingDeployment.status !== "failed") {
3922
- console.log(source_default.green(`\u2713 Found linked deployment`));
3743
+ const existingDep = await api.getDeployment(existingLink.deploymentId);
3744
+ if (existingDep && existingDep.status !== "failed") {
3745
+ console.log(source_default.green(`\u2713 Found linked server`));
3923
3746
  console.log(source_default.gray(` Redeploying to maintain the same URL...`));
3924
- console.log(
3925
- source_default.cyan(` URL: ${getMcpServerUrl(existingDeployment)}
3926
- `)
3927
- );
3928
- const redeploymentConfig = {
3929
- buildCommand,
3930
- startCommand,
3931
- ...options.port !== void 0 ? { port: options.port } : {},
3932
- env: Object.keys(envVars).length > 0 ? envVars : void 0,
3933
- rootDir: options.rootDir || void 0
3934
- };
3935
- const deployment2 = await api.redeployDeployment(
3936
- existingLink.deploymentId,
3937
- redeploymentConfig
3938
- );
3747
+ console.log(source_default.cyan(` URL: ${getMcpServerUrl(existingDep)}
3748
+ `));
3749
+ const newDep = await api.createDeployment({
3750
+ serverId,
3751
+ branch,
3752
+ trigger: "redeploy"
3753
+ });
3939
3754
  await saveProjectLink(cwd, {
3940
3755
  ...existingLink,
3941
- linkedAt: (/* @__PURE__ */ new Date()).toISOString()
3942
- });
3943
- await displayDeploymentProgress(api, deployment2, {
3944
- yes: options.yes
3756
+ linkedAt: (/* @__PURE__ */ new Date()).toISOString(),
3757
+ deploymentId: newDep.id
3945
3758
  });
3946
- if (options.open && deployment2.domain) {
3947
- console.log();
3948
- console.log(source_default.gray("Opening deployment in browser..."));
3949
- await open_default(`https://${deployment2.domain}`);
3950
- }
3759
+ console.log(
3760
+ source_default.green("\u2713 Deployment created: ") + source_default.gray(newDep.id)
3761
+ );
3762
+ await displayDeploymentProgress(api, newDep.id, { yes: options.yes });
3951
3763
  return;
3952
- } else {
3764
+ }
3765
+ } catch (err) {
3766
+ const is404 = err?.status === 404 || (err?.message ?? "").includes("404");
3767
+ if (is404) {
3953
3768
  console.log(
3954
- source_default.yellow(
3955
- `\u26A0\uFE0F Linked deployment not found or failed, creating new one...`
3956
- )
3769
+ source_default.yellow("\u26A0\uFE0F Previously linked server no longer exists.\n")
3957
3770
  );
3958
- if (serverId) {
3959
- console.log(
3960
- source_default.gray(` Will reuse existing server: ${serverId}`)
3771
+ if (!options.yes) {
3772
+ const shouldRecreate = await prompt(
3773
+ source_default.white("Create a new server and deploy? (Y/n): "),
3774
+ "y"
3961
3775
  );
3776
+ if (!shouldRecreate) {
3777
+ console.log(source_default.gray("Deployment cancelled."));
3778
+ process.exit(0);
3779
+ }
3962
3780
  }
3781
+ serverId = void 0;
3963
3782
  }
3964
- } catch (error) {
3965
- console.log(
3966
- source_default.yellow(`\u26A0\uFE0F Linked deployment not found, creating new one...`)
3967
- );
3968
- if (serverId) {
3969
- console.log(source_default.gray(` Will reuse existing server: ${serverId}`));
3783
+ }
3784
+ }
3785
+ let deploymentId;
3786
+ if (serverId) {
3787
+ console.log(source_default.gray("Creating deployment..."));
3788
+ try {
3789
+ const result = await api.createDeployment({
3790
+ serverId,
3791
+ branch,
3792
+ trigger: "manual"
3793
+ });
3794
+ deploymentId = result.id;
3795
+ } catch (err) {
3796
+ const is404 = err?.status === 404 || (err?.message ?? "").includes("404");
3797
+ if (is404) {
3798
+ console.log(
3799
+ source_default.yellow(
3800
+ "\u26A0\uFE0F Linked server no longer exists. Creating a new one...\n"
3801
+ )
3802
+ );
3803
+ serverId = void 0;
3804
+ } else {
3805
+ throw err;
3970
3806
  }
3971
3807
  }
3972
3808
  }
3973
- const deploymentRequest = {
3974
- name: projectName,
3975
- source: {
3809
+ if (!serverId) {
3810
+ const orgId = await api.resolveOrganizationId();
3811
+ console.log(source_default.gray("Creating server and deployment..."));
3812
+ const serverResult = await api.createServer({
3976
3813
  type: "github",
3977
- repo: `${gitInfo.owner}/${gitInfo.repo}`,
3978
- branch: gitInfo.branch || "main",
3979
- rootDir: options.rootDir || void 0,
3980
- runtime,
3814
+ organizationId: orgId,
3815
+ installationId: installationDbId,
3816
+ name: projectName,
3817
+ repoFullName,
3818
+ branch,
3819
+ rootDir: options.rootDir,
3981
3820
  port,
3982
- buildCommand,
3983
- startCommand,
3984
- env: Object.keys(envVars).length > 0 ? envVars : void 0
3985
- },
3986
- healthCheckPath: "/healthz",
3987
- serverId
3988
- };
3989
- if (!options.org) {
3990
- try {
3991
- const config = await readConfig();
3992
- if (config.profileName) {
3993
- const slug = config.profileSlug ? source_default.gray(` (${config.profileSlug})`) : "";
3994
- console.log(
3995
- source_default.gray("Organization: ") + source_default.cyan(config.profileName) + slug
3996
- );
3997
- }
3998
- } catch {
3821
+ env: Object.keys(envVars).length > 0 ? envVars : void 0,
3822
+ region: options.region,
3823
+ buildCommand: options.buildCommand,
3824
+ startCommand: options.startCommand
3825
+ });
3826
+ deploymentId = serverResult.deploymentId ?? "";
3827
+ if (!deploymentId) {
3828
+ console.log(
3829
+ source_default.green("\u2713 Server created: ") + source_default.gray(serverResult.server.id)
3830
+ );
3831
+ console.log(source_default.yellow("\u26A0\uFE0F No deployment was triggered."));
3832
+ return;
3999
3833
  }
3834
+ await saveProjectLink(cwd, {
3835
+ deploymentId,
3836
+ deploymentName: projectName,
3837
+ linkedAt: (/* @__PURE__ */ new Date()).toISOString(),
3838
+ serverId: serverResult.server.id
3839
+ });
3840
+ console.log(
3841
+ source_default.gray(` Linked to this project (stored in .mcp-use/project.json)`)
3842
+ );
3843
+ console.log(source_default.gray(` Future deploys will reuse the same URL
3844
+ `));
3845
+ }
3846
+ if (!deploymentId) {
3847
+ console.log(source_default.red("\u2717 No deployment was created."));
3848
+ process.exit(1);
4000
3849
  }
4001
- console.log(source_default.gray("Creating deployment..."));
4002
- const deployment = await api.createDeployment(deploymentRequest);
4003
- console.log(
4004
- source_default.green("\u2713 Deployment created: ") + source_default.gray(deployment.id)
4005
- );
4006
- await saveProjectLink(cwd, {
4007
- deploymentId: deployment.id,
4008
- deploymentName: projectName,
4009
- deploymentUrl: deployment.domain,
4010
- linkedAt: (/* @__PURE__ */ new Date()).toISOString(),
4011
- serverId: deployment.serverId
4012
- });
4013
3850
  console.log(
4014
- source_default.gray(` Linked to this project (stored in .mcp-use/project.json)`)
3851
+ source_default.green("\u2713 Deployment created: ") + source_default.gray(deploymentId)
4015
3852
  );
4016
- console.log(source_default.gray(` Future deploys will reuse the same URL
4017
- `));
4018
- await displayDeploymentProgress(api, deployment, { yes: options.yes });
4019
- if (options.open && deployment.domain) {
4020
- console.log();
4021
- console.log(source_default.gray("Opening deployment in browser..."));
4022
- await open_default(`https://${deployment.domain}`);
3853
+ await displayDeploymentProgress(api, deploymentId, { yes: options.yes });
3854
+ if (options.open) {
3855
+ const dep = await api.getDeployment(deploymentId);
3856
+ const url = getMcpServerUrl(dep);
3857
+ if (url) {
3858
+ console.log(source_default.gray("\nOpening in browser..."));
3859
+ await open_default(url);
3860
+ }
4023
3861
  }
4024
3862
  } catch (error) {
4025
3863
  console.error(
@@ -4095,19 +3933,19 @@ async function listDeploymentsCommand() {
4095
3933
  );
4096
3934
  console.log(
4097
3935
  source_default.white.bold(
4098
- `${"ID".padEnd(40)} ${"NAME".padEnd(25)} ${"STATUS".padEnd(12)} ${"DOMAIN".padEnd(35)} ${"CREATED"}`
3936
+ `${"ID".padEnd(40)} ${"NAME".padEnd(25)} ${"STATUS".padEnd(12)} ${"MCP URL".padEnd(45)} ${"CREATED"}`
4099
3937
  )
4100
3938
  );
4101
- console.log(source_default.gray("\u2500".repeat(130)));
3939
+ console.log(source_default.gray("\u2500".repeat(140)));
4102
3940
  for (const deployment of sortedDeployments) {
4103
3941
  const id = formatId(deployment.id).padEnd(40);
4104
3942
  const name = deployment.name.substring(0, 24).padEnd(25);
4105
3943
  const statusColor = getStatusColor(deployment.status);
4106
3944
  const status = statusColor(deployment.status.padEnd(12));
4107
- const domain = (deployment.domain || "-").substring(0, 34).padEnd(35);
3945
+ const mcpUrl = (deployment.mcpUrl || "-").substring(0, 44).padEnd(45);
4108
3946
  const created = formatRelativeTime(deployment.createdAt);
4109
3947
  console.log(
4110
- `${source_default.gray(id)} ${name} ${status} ${source_default.cyan(domain)} ${source_default.gray(created)}`
3948
+ `${source_default.gray(id)} ${name} ${status} ${source_default.cyan(mcpUrl)} ${source_default.gray(created)}`
4111
3949
  );
4112
3950
  }
4113
3951
  console.log();
@@ -4139,31 +3977,28 @@ async function getDeploymentCommand(deploymentId) {
4139
3977
  console.log(
4140
3978
  source_default.white("Status: ") + statusColor(deployment.status)
4141
3979
  );
4142
- if (deployment.domain) {
3980
+ if (deployment.serverId) {
4143
3981
  console.log(
4144
- source_default.white("Domain: ") + source_default.cyan(`https://${deployment.domain}`)
3982
+ source_default.white("Server ID: ") + source_default.gray(deployment.serverId)
4145
3983
  );
4146
3984
  }
4147
- if (deployment.customDomain) {
4148
- console.log(
4149
- source_default.white("Custom Domain: ") + source_default.cyan(`https://${deployment.customDomain}`)
4150
- );
3985
+ const mcpUrl = getMcpServerUrl(deployment);
3986
+ if (mcpUrl) {
3987
+ console.log(source_default.white("MCP URL: ") + source_default.cyan(mcpUrl));
4151
3988
  }
4152
- console.log(
4153
- source_default.white("Source: ") + source_default.gray(deployment.source.type)
4154
- );
4155
- if (deployment.source.type === "github") {
3989
+ if (deployment.gitBranch) {
4156
3990
  console.log(
4157
- source_default.white("Repository: ") + source_default.gray(deployment.source.repo)
3991
+ source_default.white("Branch: ") + source_default.gray(deployment.gitBranch)
4158
3992
  );
3993
+ }
3994
+ if (deployment.gitCommitSha) {
4159
3995
  console.log(
4160
- source_default.white("Branch: ") + source_default.gray(deployment.source.branch || "main")
3996
+ source_default.white("Commit: ") + source_default.gray(deployment.gitCommitSha.substring(0, 7))
4161
3997
  );
4162
3998
  }
4163
- console.log(source_default.white("Port: ") + source_default.gray(deployment.port));
4164
- console.log(
4165
- source_default.white("Runtime: ") + source_default.gray(deployment.source.runtime || "node")
4166
- );
3999
+ if (deployment.port) {
4000
+ console.log(source_default.white("Port: ") + source_default.gray(deployment.port));
4001
+ }
4167
4002
  if (deployment.provider) {
4168
4003
  console.log(
4169
4004
  source_default.white("Provider: ") + source_default.gray(deployment.provider)
@@ -4175,13 +4010,6 @@ async function getDeploymentCommand(deploymentId) {
4175
4010
  console.log(
4176
4011
  source_default.white("Updated: ") + source_default.gray(formatRelativeTime(deployment.updatedAt))
4177
4012
  );
4178
- if (deployment.source.env && Object.keys(deployment.source.env).length > 0) {
4179
- console.log(source_default.white("\nEnvironment Variables:"));
4180
- for (const [key, value] of Object.entries(deployment.source.env)) {
4181
- const displayValue = key.toLowerCase().includes("key") || key.toLowerCase().includes("secret") || key.toLowerCase().includes("password") || key.toLowerCase().includes("token") ? "***" : value;
4182
- console.log(source_default.gray(` ${key}=`) + source_default.white(displayValue));
4183
- }
4184
- }
4185
4013
  if (deployment.status === "failed" && deployment.error) {
4186
4014
  console.log(source_default.red("\nError:"));
4187
4015
  console.log(source_default.red(` ${deployment.error}`));
@@ -4208,43 +4036,56 @@ async function restartDeploymentCommand(deploymentId, options) {
4208
4036
  }
4209
4037
  const api = await McpUseAPI.create();
4210
4038
  const deployment = await api.getDeployment(deploymentId);
4039
+ if (!deployment.serverId) {
4040
+ console.log(
4041
+ source_default.red("\u2717 Cannot restart: deployment has no linked server.")
4042
+ );
4043
+ process.exit(1);
4044
+ }
4211
4045
  console.log(
4212
4046
  source_default.cyan.bold(`
4213
4047
  \u{1F504} Restarting deployment: ${deployment.name}
4214
4048
  `)
4215
4049
  );
4216
- const redeployedDeployment = await api.redeployDeployment(deploymentId);
4217
- console.log(
4218
- source_default.green("\u2713 Restart initiated: ") + source_default.gray(redeployedDeployment.id)
4219
- );
4050
+ const newDep = await api.createDeployment({
4051
+ serverId: deployment.serverId,
4052
+ trigger: "redeploy"
4053
+ });
4054
+ console.log(source_default.green("\u2713 Restart initiated: ") + source_default.gray(newDep.id));
4220
4055
  if (options.follow) {
4221
- console.log(source_default.gray("\nFollowing deployment logs...\n"));
4222
- try {
4223
- for await (const log of api.streamDeploymentLogs(
4224
- redeployedDeployment.id
4225
- )) {
4226
- try {
4227
- const logData = JSON.parse(log);
4228
- if (logData.line) {
4229
- const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
4230
- const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
4231
- console.log(stepPrefix + levelColor(logData.line));
4056
+ console.log(source_default.gray("\nFollowing build logs...\n"));
4057
+ let offset = 0;
4058
+ let terminal = false;
4059
+ while (!terminal) {
4060
+ await new Promise((r) => setTimeout(r, 2e3));
4061
+ try {
4062
+ const resp = await api.getDeploymentBuildLogs(newDep.id, offset);
4063
+ if (resp.logs.length > 0) {
4064
+ const lines = resp.logs.split("\n").filter((l) => l.trim());
4065
+ for (const line of lines) {
4066
+ try {
4067
+ const logData = JSON.parse(line);
4068
+ if (logData.line) {
4069
+ const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
4070
+ const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
4071
+ console.log(stepPrefix + levelColor(logData.line));
4072
+ }
4073
+ } catch {
4074
+ console.log(source_default.gray(line));
4075
+ }
4232
4076
  }
4233
- } catch {
4234
- console.log(source_default.gray(log));
4077
+ offset = resp.offset;
4078
+ }
4079
+ if (resp.status === "running" || resp.status === "failed" || resp.status === "stopped") {
4080
+ terminal = true;
4235
4081
  }
4082
+ } catch {
4236
4083
  }
4237
- } catch (error) {
4238
- console.log(
4239
- source_default.gray(
4240
- "\nLog stream ended. Use " + source_default.white(`mcp-use deployments get ${deploymentId}`) + " to check status."
4241
- )
4242
- );
4243
4084
  }
4244
4085
  } else {
4245
4086
  console.log(
4246
4087
  source_default.gray(
4247
- "\nCheck status with: " + source_default.white(`mcp-use deployments get ${deploymentId}`)
4088
+ "\nCheck status with: " + source_default.white(`mcp-use deployments get ${newDep.id}`)
4248
4089
  )
4249
4090
  );
4250
4091
  }
@@ -4278,8 +4119,10 @@ async function deleteDeploymentCommand(deploymentId, options) {
4278
4119
  )
4279
4120
  );
4280
4121
  console.log(source_default.gray(` ID: ${deployment.id}`));
4281
- console.log(source_default.gray(` Domain: ${deployment.domain || "none"}
4122
+ if (deployment.mcpUrl) {
4123
+ console.log(source_default.gray(` URL: ${deployment.mcpUrl}
4282
4124
  `));
4125
+ }
4283
4126
  const confirmed = await prompt2(
4284
4127
  source_default.white("Are you sure you want to delete this deployment? (y/N): ")
4285
4128
  );
@@ -4315,30 +4158,41 @@ async function logsCommand(deploymentId, options) {
4315
4158
  }
4316
4159
  const api = await McpUseAPI.create();
4317
4160
  if (options.follow) {
4318
- console.log(source_default.gray("Streaming logs...\n"));
4319
- try {
4320
- for await (const log of api.streamDeploymentLogs(deploymentId)) {
4321
- try {
4322
- const logData = JSON.parse(log);
4323
- if (logData.line) {
4324
- const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
4325
- const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
4326
- console.log(stepPrefix + levelColor(logData.line));
4161
+ console.log(source_default.gray("Following build logs...\n"));
4162
+ let offset = 0;
4163
+ let terminal = false;
4164
+ while (!terminal) {
4165
+ await new Promise((r) => setTimeout(r, 2e3));
4166
+ try {
4167
+ const resp = await api.getDeploymentBuildLogs(deploymentId, offset);
4168
+ if (resp.logs.length > 0) {
4169
+ const lines = resp.logs.split("\n").filter((l) => l.trim());
4170
+ for (const line of lines) {
4171
+ try {
4172
+ const logData = JSON.parse(line);
4173
+ if (logData.line) {
4174
+ const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
4175
+ const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
4176
+ console.log(stepPrefix + levelColor(logData.line));
4177
+ }
4178
+ } catch {
4179
+ console.log(source_default.gray(line));
4180
+ }
4327
4181
  }
4328
- } catch {
4329
- console.log(source_default.gray(log));
4182
+ offset = resp.offset;
4183
+ }
4184
+ if (resp.status === "running" || resp.status === "failed" || resp.status === "stopped") {
4185
+ terminal = true;
4330
4186
  }
4187
+ } catch {
4331
4188
  }
4332
- } catch (error) {
4333
- console.log(source_default.gray("\nLog stream ended."));
4334
4189
  }
4335
- } else {
4336
- const logs = options.build ? await api.getDeploymentBuildLogs(deploymentId) : await api.getDeploymentLogs(deploymentId);
4190
+ } else if (options.build) {
4191
+ const resp = await api.getDeploymentBuildLogs(deploymentId);
4192
+ const logs = resp.logs;
4337
4193
  if (!logs || logs.trim() === "") {
4338
4194
  console.log(
4339
- source_default.yellow(
4340
- `No ${options.build ? "build " : ""}logs available for this deployment.`
4341
- )
4195
+ source_default.yellow("No build logs available for this deployment.")
4342
4196
  );
4343
4197
  return;
4344
4198
  }
@@ -4355,6 +4209,25 @@ async function logsCommand(deploymentId, options) {
4355
4209
  console.log(source_default.gray(line));
4356
4210
  }
4357
4211
  }
4212
+ } else {
4213
+ const logs = await api.getDeploymentLogs(deploymentId);
4214
+ if (!logs || logs.trim() === "") {
4215
+ console.log(source_default.yellow("No logs available for this deployment."));
4216
+ return;
4217
+ }
4218
+ const logLines = logs.split("\n").filter((l) => l.trim());
4219
+ for (const line of logLines) {
4220
+ try {
4221
+ const logData = JSON.parse(line);
4222
+ if (logData.line) {
4223
+ const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
4224
+ const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
4225
+ console.log(stepPrefix + levelColor(logData.line));
4226
+ }
4227
+ } catch {
4228
+ console.log(source_default.gray(line));
4229
+ }
4230
+ }
4358
4231
  }
4359
4232
  console.log();
4360
4233
  } catch (error) {
@@ -4365,7 +4238,7 @@ async function logsCommand(deploymentId, options) {
4365
4238
  process.exit(1);
4366
4239
  }
4367
4240
  }
4368
- async function listEnvCommand(deploymentId) {
4241
+ async function stopDeploymentCommand(deploymentId) {
4369
4242
  try {
4370
4243
  if (!await isLoggedIn()) {
4371
4244
  console.log(source_default.red("\u2717 You are not logged in."));
@@ -4377,33 +4250,19 @@ async function listEnvCommand(deploymentId) {
4377
4250
  process.exit(1);
4378
4251
  }
4379
4252
  const api = await McpUseAPI.create();
4380
- const deployment = await api.getDeployment(deploymentId);
4381
- console.log(
4382
- source_default.cyan.bold(`
4383
- \u{1F510} Environment Variables: ${deployment.name}
4384
- `)
4385
- );
4386
- if (!deployment.source.env || Object.keys(deployment.source.env).length === 0) {
4387
- console.log(source_default.yellow("No environment variables set."));
4388
- console.log();
4389
- return;
4390
- }
4391
- for (const [key, value] of Object.entries(deployment.source.env)) {
4392
- const displayValue = key.toLowerCase().includes("key") || key.toLowerCase().includes("secret") || key.toLowerCase().includes("password") || key.toLowerCase().includes("token") ? "***" : value;
4393
- console.log(
4394
- source_default.white(key) + source_default.gray("=") + source_default.cyan(displayValue)
4395
- );
4396
- }
4397
- console.log();
4253
+ await api.stopDeployment(deploymentId);
4254
+ console.log(source_default.green.bold(`
4255
+ \u2713 Deployment stopped
4256
+ `));
4398
4257
  } catch (error) {
4399
4258
  console.error(
4400
- source_default.red.bold("\n\u2717 Failed to list environment variables:"),
4259
+ source_default.red.bold("\n\u2717 Failed to stop deployment:"),
4401
4260
  source_default.red(error instanceof Error ? error.message : "Unknown error")
4402
4261
  );
4403
4262
  process.exit(1);
4404
4263
  }
4405
4264
  }
4406
- async function setEnvCommand(deploymentId, envPairs) {
4265
+ async function startDeploymentCommand(deploymentId) {
4407
4266
  try {
4408
4267
  if (!await isLoggedIn()) {
4409
4268
  console.log(source_default.red("\u2717 You are not logged in."));
@@ -4414,43 +4273,87 @@ async function setEnvCommand(deploymentId, envPairs) {
4414
4273
  );
4415
4274
  process.exit(1);
4416
4275
  }
4417
- const env2 = {};
4418
- for (const pair of envPairs) {
4419
- const [key, ...valueParts] = pair.split("=");
4420
- if (!key || valueParts.length === 0) {
4421
- console.log(source_default.red(`\u2717 Invalid format: ${pair}. Expected KEY=VALUE`));
4422
- process.exit(1);
4423
- }
4424
- env2[key.trim()] = valueParts.join("=").trim();
4425
- }
4426
- const api = await McpUseAPI.create();
4427
- const deployment = await api.getDeployment(deploymentId);
4428
- const currentEnv = deployment.source.env || {};
4429
- const mergedEnv = { ...currentEnv, ...env2 };
4430
- const updated = await api.updateDeployment(deploymentId, {
4431
- env: mergedEnv
4432
- });
4433
4276
  console.log(
4434
- source_default.green.bold(`
4435
- \u2713 Environment variables updated: ${updated.name}
4436
- `)
4277
+ source_default.yellow(
4278
+ "\u26A0\uFE0F Start is not supported in this version. Use `mcp-use deployments restart` to redeploy."
4279
+ )
4437
4280
  );
4438
- for (const key of Object.keys(env2)) {
4439
- const displayValue = key.toLowerCase().includes("key") || key.toLowerCase().includes("secret") || key.toLowerCase().includes("password") || key.toLowerCase().includes("token") ? "***" : env2[key];
4440
- console.log(
4441
- source_default.white(key) + source_default.gray("=") + source_default.cyan(displayValue)
4442
- );
4443
- }
4444
- console.log();
4445
4281
  } catch (error) {
4446
4282
  console.error(
4447
- source_default.red.bold("\n\u2717 Failed to set environment variables:"),
4283
+ source_default.red.bold("\n\u2717 Failed to start deployment:"),
4448
4284
  source_default.red(error instanceof Error ? error.message : "Unknown error")
4449
4285
  );
4450
4286
  process.exit(1);
4451
4287
  }
4452
4288
  }
4453
- async function unsetEnvCommand(deploymentId, keys) {
4289
+ function createDeploymentsCommand() {
4290
+ const deploymentsCommand = new Command2("deployments").description(
4291
+ "Manage cloud deployments"
4292
+ );
4293
+ deploymentsCommand.command("list").alias("ls").description("List all deployments").action(listDeploymentsCommand);
4294
+ deploymentsCommand.command("get").argument("<deployment-id>", "Deployment ID").description("Get deployment details").action(getDeploymentCommand);
4295
+ deploymentsCommand.command("restart").argument("<deployment-id>", "Deployment ID").option("-f, --follow", "Follow build logs").description(
4296
+ "Restart a deployment (triggers a new deployment on the same server)"
4297
+ ).action(restartDeploymentCommand);
4298
+ deploymentsCommand.command("delete").alias("rm").argument("<deployment-id>", "Deployment ID").option("-y, --yes", "Skip confirmation prompt").description("Delete a deployment").action(deleteDeploymentCommand);
4299
+ 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);
4300
+ deploymentsCommand.command("stop").argument("<deployment-id>", "Deployment ID").description("Stop a deployment").action(stopDeploymentCommand);
4301
+ deploymentsCommand.command("start").argument("<deployment-id>", "Deployment ID").description("Start a stopped deployment").action(startDeploymentCommand);
4302
+ return deploymentsCommand;
4303
+ }
4304
+
4305
+ // src/commands/servers.ts
4306
+ import { Command as Command3 } from "commander";
4307
+ async function prompt3(question) {
4308
+ const readline = await import("readline");
4309
+ const rl = readline.createInterface({
4310
+ input: process.stdin,
4311
+ output: process.stdout
4312
+ });
4313
+ return new Promise((resolve2) => {
4314
+ rl.question(question, (answer) => {
4315
+ rl.close();
4316
+ const trimmedAnswer = answer.trim().toLowerCase();
4317
+ resolve2(trimmedAnswer === "y" || trimmedAnswer === "yes");
4318
+ });
4319
+ });
4320
+ }
4321
+ function isRecord(v) {
4322
+ return typeof v === "object" && v !== null;
4323
+ }
4324
+ function pickStr(obj, key) {
4325
+ if (!isRecord(obj)) return "-";
4326
+ const v = obj[key];
4327
+ if (typeof v === "string") return v;
4328
+ if (v != null && typeof v !== "object") return String(v);
4329
+ return "-";
4330
+ }
4331
+ async function applyOrgOption(api, org) {
4332
+ if (!org) return;
4333
+ const authInfo = await api.testAuth();
4334
+ const match = (authInfo.orgs ?? []).find(
4335
+ (o) => o.slug === org || o.id === org || o.name.toLowerCase() === org.toLowerCase()
4336
+ );
4337
+ if (!match) {
4338
+ console.error(
4339
+ source_default.red(
4340
+ `\u2717 Organization "${org}" not found. Run ${source_default.white("npx mcp-use org list")} to see available organizations.`
4341
+ )
4342
+ );
4343
+ process.exit(1);
4344
+ }
4345
+ api.setOrgId(match.id);
4346
+ const slug = match.slug ? source_default.gray(` (${match.slug})`) : "";
4347
+ console.log(source_default.gray("Organization: ") + source_default.cyan(match.name) + slug);
4348
+ }
4349
+ function getStatusColor2(status) {
4350
+ const s = status.toLowerCase();
4351
+ if (s.includes("run") || s === "active") return source_default.green;
4352
+ if (s.includes("fail") || s.includes("error")) return source_default.red;
4353
+ if (s.includes("build") || s.includes("pend")) return source_default.yellow;
4354
+ return source_default.gray;
4355
+ }
4356
+ async function listServersCommand(options) {
4454
4357
  try {
4455
4358
  if (!await isLoggedIn()) {
4456
4359
  console.log(source_default.red("\u2717 You are not logged in."));
@@ -4462,32 +4365,62 @@ async function unsetEnvCommand(deploymentId, keys) {
4462
4365
  process.exit(1);
4463
4366
  }
4464
4367
  const api = await McpUseAPI.create();
4465
- const deployment = await api.getDeployment(deploymentId);
4466
- const currentEnv = { ...deployment.source.env || {} };
4467
- for (const key of keys) {
4468
- delete currentEnv[key];
4368
+ await applyOrgOption(api, options.org);
4369
+ if (options.org) console.log();
4370
+ const limit = options.limit ? parseInt(options.limit, 10) : void 0;
4371
+ const skip = options.skip ? parseInt(options.skip, 10) : void 0;
4372
+ if (limit !== void 0 && (Number.isNaN(limit) || limit < 1)) {
4373
+ console.log(source_default.red("\u2717 Invalid --limit"));
4374
+ process.exit(1);
4469
4375
  }
4470
- const updated = await api.updateDeployment(deploymentId, {
4471
- env: currentEnv
4376
+ if (skip !== void 0 && (Number.isNaN(skip) || skip < 0)) {
4377
+ console.log(source_default.red("\u2717 Invalid --skip"));
4378
+ process.exit(1);
4379
+ }
4380
+ const servers = await api.listServers({
4381
+ limit,
4382
+ skip,
4383
+ sort: options.sort
4472
4384
  });
4385
+ if (servers.length === 0) {
4386
+ console.log(source_default.yellow("No servers found."));
4387
+ console.log(
4388
+ source_default.gray(
4389
+ "\nCreate one by deploying with " + source_default.white("mcp-use deploy")
4390
+ )
4391
+ );
4392
+ return;
4393
+ }
4394
+ console.log(source_default.cyan.bold(`
4395
+ \u{1F5A5} Servers (${servers.length})
4396
+ `));
4473
4397
  console.log(
4474
- source_default.green.bold(`
4475
- \u2713 Environment variables removed: ${updated.name}
4476
- `)
4398
+ source_default.white.bold(
4399
+ `${"ID".padEnd(38)} ${"NAME".padEnd(22)} ${"STATUS".padEnd(14)} ${"REPO".padEnd(32)} ${"MCP URL".padEnd(52)}`
4400
+ )
4477
4401
  );
4478
- for (const key of keys) {
4479
- console.log(source_default.gray(` ${key}`));
4402
+ console.log(source_default.gray("\u2500".repeat(165)));
4403
+ for (const s of servers) {
4404
+ const id = s.id.substring(0, 37).padEnd(38);
4405
+ const name = (s.name || s.slug || "-").substring(0, 21).padEnd(22);
4406
+ const statusColor = getStatusColor2(s.status);
4407
+ const status = statusColor(s.status.substring(0, 13).padEnd(14));
4408
+ const repo = (s.connectedRepository?.repoFullName ?? "-").substring(0, 31).padEnd(32);
4409
+ const mcp = getMcpServerUrlForCloudServer(s).substring(0, 51).padEnd(52);
4410
+ console.log(
4411
+ `${source_default.gray(id)} ${name} ${status} ${source_default.gray(repo)} ${source_default.cyan(mcp)}`
4412
+ );
4480
4413
  }
4481
4414
  console.log();
4482
4415
  } catch (error) {
4483
4416
  console.error(
4484
- source_default.red.bold("\n\u2717 Failed to unset environment variables:"),
4417
+ source_default.red.bold("\n\u2717 Failed to list servers:"),
4485
4418
  source_default.red(error instanceof Error ? error.message : "Unknown error")
4486
4419
  );
4487
4420
  process.exit(1);
4488
4421
  }
4489
4422
  }
4490
- async function stopDeploymentCommand(deploymentId) {
4423
+ async function getServerCommand(idOrSlug, options) {
4491
4424
  try {
4492
4425
  if (!await isLoggedIn()) {
4493
4426
  console.log(source_default.red("\u2717 You are not logged in."));
@@ -4499,21 +4432,99 @@ async function stopDeploymentCommand(deploymentId) {
4499
4432
  process.exit(1);
4500
4433
  }
4501
4434
  const api = await McpUseAPI.create();
4502
- const updated = await api.updateDeployment(deploymentId, {
4503
- status: "stopped"
4504
- });
4505
- console.log(source_default.green.bold(`
4506
- \u2713 Deployment stopped: ${updated.name}
4507
- `));
4435
+ await applyOrgOption(api, options.org);
4436
+ if (options.org) console.log();
4437
+ const server = await api.getServer(idOrSlug);
4438
+ console.log(source_default.cyan.bold("\n\u{1F5A5} Server Details\n"));
4439
+ console.log(source_default.white("ID: ") + source_default.gray(server.id));
4440
+ if (server.slug) {
4441
+ console.log(source_default.white("Slug: ") + source_default.cyan(server.slug));
4442
+ }
4443
+ console.log(
4444
+ source_default.white("Name: ") + source_default.cyan(server.name ?? "-")
4445
+ );
4446
+ const statusColor = getStatusColor2(server.status);
4447
+ console.log(source_default.white("Status: ") + statusColor(server.status));
4448
+ if (server.latestDeploymentStatus) {
4449
+ console.log(
4450
+ source_default.white("Last deploy: ") + source_default.gray(server.latestDeploymentStatus)
4451
+ );
4452
+ }
4453
+ console.log(source_default.white("Region: ") + source_default.gray(server.region));
4454
+ console.log(
4455
+ source_default.white("MCP URL: ") + source_default.cyan(getMcpServerUrlForCloudServer(server))
4456
+ );
4457
+ if (server.connectedRepository) {
4458
+ const cr = server.connectedRepository;
4459
+ console.log(source_default.white("\nRepository"));
4460
+ console.log(source_default.white(" Full name: ") + source_default.gray(cr.repoFullName));
4461
+ console.log(
4462
+ source_default.white(" Prod branch: ") + source_default.gray(cr.productionBranch)
4463
+ );
4464
+ }
4465
+ if (server.activeDeploymentId) {
4466
+ console.log(
4467
+ source_default.white("\nActive deployment: ") + source_default.cyan(server.activeDeploymentId)
4468
+ );
4469
+ }
4470
+ if (server.previousDeploymentId) {
4471
+ console.log(
4472
+ source_default.white("Previous deployment: ") + source_default.gray(server.previousDeploymentId)
4473
+ );
4474
+ }
4475
+ const depCount = server._count?.deployments;
4476
+ if (depCount != null) {
4477
+ console.log(
4478
+ source_default.white("Deployment count: ") + source_default.gray(String(depCount))
4479
+ );
4480
+ }
4481
+ console.log(
4482
+ source_default.white("Created: ") + source_default.gray(formatRelativeTime(server.createdAt))
4483
+ );
4484
+ console.log(
4485
+ source_default.white("Updated: ") + source_default.gray(formatRelativeTime(server.updatedAt))
4486
+ );
4487
+ const config = await readConfig();
4488
+ const base = (await getWebUrl()).replace(/\/$/, "");
4489
+ if (config.orgSlug) {
4490
+ console.log(
4491
+ source_default.white("\nDashboard: ") + source_default.cyan(`${base}/cloud/${config.orgSlug}/servers/${server.id}`)
4492
+ );
4493
+ } else {
4494
+ console.log(
4495
+ source_default.white("\nDashboard: ") + source_default.cyan(`${base}/cloud/servers/${server.id}`)
4496
+ );
4497
+ }
4498
+ if (Array.isArray(server.deployments) && server.deployments.length > 0) {
4499
+ console.log(source_default.cyan.bold("\nRecent deployments\n"));
4500
+ console.log(
4501
+ source_default.white.bold(
4502
+ `${"ID".padEnd(40)} ${"NAME".padEnd(24)} ${"STATUS".padEnd(12)} ${"UPDATED"}`
4503
+ )
4504
+ );
4505
+ console.log(source_default.gray("\u2500".repeat(100)));
4506
+ for (const d of server.deployments) {
4507
+ const did = pickStr(d, "id").padEnd(40);
4508
+ const dname = pickStr(d, "name").substring(0, 23).padEnd(24);
4509
+ const dst = pickStr(d, "status").padEnd(12);
4510
+ const du = pickStr(d, "updatedAt");
4511
+ const updated = du !== "-" ? formatRelativeTime(du) : source_default.gray("-");
4512
+ const sc = getStatusColor2(dst.trim());
4513
+ console.log(
4514
+ `${source_default.gray(did)} ${dname} ${sc(dst)} ${source_default.gray(updated)}`
4515
+ );
4516
+ }
4517
+ }
4518
+ console.log();
4508
4519
  } catch (error) {
4509
4520
  console.error(
4510
- source_default.red.bold("\n\u2717 Failed to stop deployment:"),
4521
+ source_default.red.bold("\n\u2717 Failed to get server:"),
4511
4522
  source_default.red(error instanceof Error ? error.message : "Unknown error")
4512
4523
  );
4513
4524
  process.exit(1);
4514
4525
  }
4515
4526
  }
4516
- async function startDeploymentCommand(deploymentId) {
4527
+ async function deleteServerCommand(serverId, options) {
4517
4528
  try {
4518
4529
  if (!await isLoggedIn()) {
4519
4530
  console.log(source_default.red("\u2717 You are not logged in."));
@@ -4525,36 +4536,59 @@ async function startDeploymentCommand(deploymentId) {
4525
4536
  process.exit(1);
4526
4537
  }
4527
4538
  const api = await McpUseAPI.create();
4528
- const updated = await api.updateDeployment(deploymentId, {
4529
- status: "running"
4530
- });
4531
- console.log(source_default.green.bold(`
4532
- \u2713 Deployment started: ${updated.name}
4533
- `));
4539
+ await applyOrgOption(api, options.org);
4540
+ if (options.org) console.log();
4541
+ const server = await api.getServer(serverId);
4542
+ if (!options.yes) {
4543
+ console.log(
4544
+ source_default.yellow(
4545
+ `
4546
+ \u26A0\uFE0F You are about to delete server: ${source_default.white(server.name || server.slug || server.id)}`
4547
+ )
4548
+ );
4549
+ console.log(source_default.gray(` ID: ${server.id}`));
4550
+ if (server.connectedRepository?.repoFullName) {
4551
+ console.log(
4552
+ source_default.gray(` Repo: ${server.connectedRepository.repoFullName}
4553
+ `)
4554
+ );
4555
+ } else {
4556
+ console.log();
4557
+ }
4558
+ const confirmed = await prompt3(
4559
+ source_default.white(
4560
+ "This deletes the server and all its deployments. Continue? (y/N): "
4561
+ )
4562
+ );
4563
+ if (!confirmed) {
4564
+ console.log(source_default.gray("Deletion cancelled."));
4565
+ return;
4566
+ }
4567
+ }
4568
+ await api.deleteServer(server.id);
4569
+ console.log(
4570
+ source_default.green.bold(
4571
+ `
4572
+ \u2713 Server deleted: ${server.name || server.slug || server.id}
4573
+ `
4574
+ )
4575
+ );
4534
4576
  } catch (error) {
4535
4577
  console.error(
4536
- source_default.red.bold("\n\u2717 Failed to start deployment:"),
4578
+ source_default.red.bold("\n\u2717 Failed to delete server:"),
4537
4579
  source_default.red(error instanceof Error ? error.message : "Unknown error")
4538
4580
  );
4539
4581
  process.exit(1);
4540
4582
  }
4541
4583
  }
4542
- function createDeploymentsCommand() {
4543
- const deploymentsCommand = new Command2("deployments").description(
4544
- "Manage cloud deployments"
4584
+ function createServersCommand() {
4585
+ const serversCommand = new Command3("servers").description(
4586
+ "Manage cloud servers (Git-backed deploy targets)"
4545
4587
  );
4546
- deploymentsCommand.command("list").alias("ls").description("List all deployments").action(listDeploymentsCommand);
4547
- deploymentsCommand.command("get").argument("<deployment-id>", "Deployment ID").description("Get deployment details").action(getDeploymentCommand);
4548
- deploymentsCommand.command("restart").argument("<deployment-id>", "Deployment ID").option("-f, --follow", "Follow deployment logs").description("Restart a deployment").action(restartDeploymentCommand);
4549
- deploymentsCommand.command("delete").alias("rm").argument("<deployment-id>", "Deployment ID").option("-y, --yes", "Skip confirmation prompt").description("Delete a deployment").action(deleteDeploymentCommand);
4550
- 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);
4551
- const envCommand = deploymentsCommand.command("env").description("Manage environment variables");
4552
- envCommand.command("list").argument("<deployment-id>", "Deployment ID").description("List environment variables").action(listEnvCommand);
4553
- envCommand.command("set").argument("<deployment-id>", "Deployment ID").argument("<pairs...>", "Environment variables in KEY=VALUE format").description("Set environment variables").action(setEnvCommand);
4554
- envCommand.command("unset").argument("<deployment-id>", "Deployment ID").argument("<keys...>", "Environment variable keys to remove").description("Unset environment variables").action(unsetEnvCommand);
4555
- deploymentsCommand.command("stop").argument("<deployment-id>", "Deployment ID").description("Stop a deployment").action(stopDeploymentCommand);
4556
- deploymentsCommand.command("start").argument("<deployment-id>", "Deployment ID").description("Start a stopped deployment").action(startDeploymentCommand);
4557
- return deploymentsCommand;
4588
+ serversCommand.command("list").alias("ls").description("List servers for the current organization").option("--org <slug-or-id>", "Target organization (slug, id, or name)").option("--limit <n>", "Page size (1\u2013100, default 50)").option("--skip <n>", "Offset for pagination").option("--sort <field:asc|desc>", "Sort (e.g. updatedAt:desc)").action(listServersCommand);
4589
+ serversCommand.command("get").argument("<id-or-slug>", "Server UUID or slug").option("--org <slug-or-id>", "Resolve org context before fetch").description("Show server details and recent deployments").action(getServerCommand);
4590
+ serversCommand.command("delete").alias("rm").argument("<server-id>", "Server UUID (or slug if API accepts it)").option("-y, --yes", "Skip confirmation prompt").option("--org <slug-or-id>", "Target organization").description("Delete a server and all its deployments").action(deleteServerCommand);
4591
+ return serversCommand;
4558
4592
  }
4559
4593
 
4560
4594
  // src/commands/org.ts
@@ -4574,22 +4608,22 @@ async function orgListCommand() {
4574
4608
  const api = await McpUseAPI.create();
4575
4609
  const authInfo = await api.testAuth();
4576
4610
  const config = await readConfig();
4577
- const profiles = authInfo.profiles ?? [];
4578
- const activeId = config.profileId || authInfo.default_profile_id;
4579
- if (profiles.length === 0) {
4611
+ const orgs = authInfo.orgs ?? [];
4612
+ const activeId = config.orgId || authInfo.default_org_id;
4613
+ if (orgs.length === 0) {
4580
4614
  console.log(source_default.yellow("No organizations found."));
4581
4615
  return;
4582
4616
  }
4583
4617
  console.log(source_default.cyan.bold("\u{1F3E2} Your organizations:\n"));
4584
- for (const p of profiles) {
4585
- const isActive = p.id === activeId;
4618
+ for (const o of orgs) {
4619
+ const isActive = o.id === activeId;
4586
4620
  const marker = isActive ? source_default.green(" \u2190 active") : "";
4587
- const slug = p.slug ? source_default.gray(` (${p.slug})`) : "";
4588
- const role = source_default.gray(` [${p.role}]`);
4589
- const name = isActive ? source_default.cyan.bold(p.profile_name) : source_default.white(p.profile_name);
4621
+ const slug = o.slug ? source_default.gray(` (${o.slug})`) : "";
4622
+ const role = source_default.gray(` [${o.role}]`);
4623
+ const name = isActive ? source_default.cyan.bold(o.name) : source_default.white(o.name);
4590
4624
  console.log(` ${name}${slug}${role}${marker}`);
4591
4625
  }
4592
- if (profiles.length > 1) {
4626
+ if (orgs.length > 1) {
4593
4627
  console.log(
4594
4628
  source_default.gray("\nSwitch with " + source_default.white("npx mcp-use org switch"))
4595
4629
  );
@@ -4608,40 +4642,40 @@ async function orgSwitchCommand() {
4608
4642
  const api = await McpUseAPI.create();
4609
4643
  const authInfo = await api.testAuth();
4610
4644
  const config = await readConfig();
4611
- const profiles = authInfo.profiles ?? [];
4612
- if (profiles.length === 0) {
4645
+ const orgs = authInfo.orgs ?? [];
4646
+ if (orgs.length === 0) {
4613
4647
  console.log(source_default.yellow("No organizations found."));
4614
4648
  return;
4615
4649
  }
4616
- if (profiles.length === 1) {
4617
- const p = profiles[0];
4618
- const slug2 = p.slug ? source_default.gray(` (${p.slug})`) : "";
4650
+ if (orgs.length === 1) {
4651
+ const o = orgs[0];
4652
+ const slug2 = o.slug ? source_default.gray(` (${o.slug})`) : "";
4619
4653
  console.log(
4620
4654
  source_default.yellow(
4621
- `You only have one organization: ${source_default.cyan(p.profile_name)}${slug2}`
4655
+ `You only have one organization: ${source_default.cyan(o.name)}${slug2}`
4622
4656
  )
4623
4657
  );
4624
4658
  return;
4625
4659
  }
4626
- const activeId = config.profileId || authInfo.default_profile_id;
4627
- const selected = await promptOrgSelection(profiles, activeId);
4660
+ const activeId = config.orgId || authInfo.default_org_id;
4661
+ const selected = await promptOrgSelection(orgs, activeId);
4628
4662
  if (!selected) {
4629
4663
  console.log(source_default.yellow("No organization selected."));
4630
4664
  return;
4631
4665
  }
4632
4666
  await writeConfig({
4633
4667
  ...config,
4634
- profileId: selected.id,
4635
- profileName: selected.profile_name,
4636
- profileSlug: selected.slug ?? void 0
4668
+ orgId: selected.id,
4669
+ orgName: selected.name,
4670
+ orgSlug: selected.slug ?? void 0
4637
4671
  });
4638
4672
  try {
4639
- await api.setDefaultProfile(selected.id);
4673
+ await api.setDefaultOrg(selected.id);
4640
4674
  } catch {
4641
4675
  }
4642
4676
  const slug = selected.slug ? source_default.gray(` (${selected.slug})`) : "";
4643
4677
  console.log(
4644
- source_default.green.bold("\n\u2713 Switched to ") + source_default.cyan.bold(selected.profile_name) + slug
4678
+ source_default.green.bold("\n\u2713 Switched to ") + source_default.cyan.bold(selected.name) + slug
4645
4679
  );
4646
4680
  } catch (error) {
4647
4681
  console.error(
@@ -4655,7 +4689,7 @@ async function orgCurrentCommand() {
4655
4689
  try {
4656
4690
  if (!await ensureLoggedIn()) return;
4657
4691
  const config = await readConfig();
4658
- if (!config.profileId) {
4692
+ if (!config.orgId) {
4659
4693
  console.log(
4660
4694
  source_default.yellow(
4661
4695
  "No organization selected. Run " + source_default.white("npx mcp-use org switch") + " to pick one."
@@ -4663,9 +4697,9 @@ async function orgCurrentCommand() {
4663
4697
  );
4664
4698
  return;
4665
4699
  }
4666
- const slug = config.profileSlug ? source_default.gray(` (${config.profileSlug})`) : "";
4700
+ const slug = config.orgSlug ? source_default.gray(` (${config.orgSlug})`) : "";
4667
4701
  console.log(
4668
- source_default.cyan.bold("\u{1F3E2} Active organization: ") + source_default.white(config.profileName || config.profileId) + slug
4702
+ source_default.cyan.bold("\u{1F3E2} Active organization: ") + source_default.white(config.orgName || config.orgId) + slug
4669
4703
  );
4670
4704
  } catch (error) {
4671
4705
  console.error(
@@ -4677,7 +4711,7 @@ async function orgCurrentCommand() {
4677
4711
  }
4678
4712
 
4679
4713
  // src/commands/skills.ts
4680
- import { Command as Command3 } from "commander";
4714
+ import { Command as Command4 } from "commander";
4681
4715
  import { cpSync, existsSync as existsSync2, mkdtempSync, readdirSync, rmSync } from "fs";
4682
4716
  import { tmpdir } from "os";
4683
4717
  import { join as join2, resolve } from "path";
@@ -4747,7 +4781,7 @@ async function addSkillsToProject(projectPath) {
4747
4781
  }
4748
4782
  }
4749
4783
  function createSkillsCommand() {
4750
- const skills = new Command3("skills").description(
4784
+ const skills = new Command4("skills").description(
4751
4785
  "Manage mcp-use AI agent skills"
4752
4786
  );
4753
4787
  const installAction = async (options) => {
@@ -4923,7 +4957,7 @@ A new release of ${source_default.bold(PACKAGE_NAME)} is available: ${source_def
4923
4957
  }
4924
4958
 
4925
4959
  // src/index.ts
4926
- var program = new Command4();
4960
+ var program = new Command5();
4927
4961
  var packageContent = readFileSync2(
4928
4962
  path7.join(__dirname, "../package.json"),
4929
4963
  "utf-8"
@@ -6751,7 +6785,13 @@ program.command("deploy").description("Deploy MCP server from GitHub to Manufact
6751
6785
  ).option(
6752
6786
  "--org <slug-or-id>",
6753
6787
  "Deploy to a specific organization (by slug or ID)"
6754
- ).option("-y, --yes", "Skip confirmation prompts").action(async (options) => {
6788
+ ).option("-y, --yes", "Skip confirmation prompts").option("--region <region>", "Deploy region: US, EU, or APAC (default: US)").option(
6789
+ "--build-command <cmd>",
6790
+ "Custom build command (overrides auto-detection)"
6791
+ ).option(
6792
+ "--start-command <cmd>",
6793
+ "Custom start command (overrides auto-detection)"
6794
+ ).action(async (options) => {
6755
6795
  await deployCommand({
6756
6796
  open: options.open,
6757
6797
  name: options.name,
@@ -6762,11 +6802,15 @@ program.command("deploy").description("Deploy MCP server from GitHub to Manufact
6762
6802
  envFile: options.envFile,
6763
6803
  rootDir: options.rootDir,
6764
6804
  org: options.org,
6765
- yes: options.yes
6805
+ yes: options.yes,
6806
+ region: options.region,
6807
+ buildCommand: options.buildCommand,
6808
+ startCommand: options.startCommand
6766
6809
  });
6767
6810
  });
6768
6811
  program.addCommand(createClientCommand());
6769
6812
  program.addCommand(createDeploymentsCommand());
6813
+ program.addCommand(createServersCommand());
6770
6814
  program.addCommand(createSkillsCommand());
6771
6815
  program.command("generate-types").description(
6772
6816
  "Generate TypeScript type definitions for tools (writes .mcp-use/tool-registry.d.ts)"