@mcp-use/cli 2.21.5-canary.2 → 3.0.0-canary.4

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
@@ -1130,12 +1130,6 @@ var open_default = open;
1130
1130
  import { viteSingleFile } from "vite-plugin-singlefile";
1131
1131
  import { toJSONSchema } from "zod";
1132
1132
 
1133
- // src/commands/auth.ts
1134
- import crypto from "crypto";
1135
- import {
1136
- createServer
1137
- } from "http";
1138
-
1139
1133
  // src/utils/config.ts
1140
1134
  import { promises as fs7 } from "fs";
1141
1135
  import os3 from "os";
@@ -1153,14 +1147,21 @@ async function ensureConfigDir() {
1153
1147
  async function readConfig() {
1154
1148
  try {
1155
1149
  const content = await fs7.readFile(CONFIG_FILE, "utf-8");
1156
- 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
+ };
1157
1157
  } catch (error) {
1158
1158
  return {};
1159
1159
  }
1160
1160
  }
1161
1161
  async function writeConfig(config) {
1162
1162
  await ensureConfigDir();
1163
- 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");
1164
1165
  }
1165
1166
  async function deleteConfig() {
1166
1167
  try {
@@ -1180,42 +1181,37 @@ async function isLoggedIn() {
1180
1181
  const apiKey = await getApiKey();
1181
1182
  return !!apiKey;
1182
1183
  }
1183
- async function getProfileId() {
1184
+ async function getOrgId() {
1184
1185
  const config = await readConfig();
1185
- return config.profileId || null;
1186
+ return config.orgId || null;
1186
1187
  }
1187
1188
  async function getWebUrl() {
1188
1189
  return DEFAULT_WEB_URL;
1189
1190
  }
1191
+ async function getAuthBaseUrl() {
1192
+ const apiUrl = await getApiUrl();
1193
+ return apiUrl.replace(/\/api\/v1$/, "");
1194
+ }
1190
1195
 
1191
1196
  // src/utils/api.ts
1192
1197
  var McpUseAPI = class _McpUseAPI {
1193
1198
  baseUrl;
1194
1199
  apiKey;
1195
- profileId;
1196
- constructor(baseUrl, apiKey, profileId) {
1200
+ orgId;
1201
+ constructor(baseUrl, apiKey, orgId) {
1197
1202
  this.baseUrl = baseUrl || "";
1198
1203
  this.apiKey = apiKey;
1199
- this.profileId = profileId;
1204
+ this.orgId = orgId;
1200
1205
  }
1201
- /**
1202
- * Initialize API client with config
1203
- */
1204
1206
  static async create() {
1205
1207
  const baseUrl = await getApiUrl();
1206
1208
  const apiKey = await getApiKey();
1207
- const profileId = await getProfileId();
1208
- 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);
1209
1211
  }
1210
- /**
1211
- * Override the profile ID for this API client instance (e.g. from --org flag)
1212
- */
1213
- setProfileId(profileId) {
1214
- this.profileId = profileId;
1212
+ setOrgId(orgId) {
1213
+ this.orgId = orgId;
1215
1214
  }
1216
- /**
1217
- * Make authenticated request
1218
- */
1219
1215
  async request(endpoint, options = {}) {
1220
1216
  const url = `${this.baseUrl}${endpoint}`;
1221
1217
  const headers = {
@@ -1225,8 +1221,8 @@ var McpUseAPI = class _McpUseAPI {
1225
1221
  if (this.apiKey) {
1226
1222
  headers["x-api-key"] = this.apiKey;
1227
1223
  }
1228
- if (this.profileId) {
1229
- headers["x-profile-id"] = this.profileId;
1224
+ if (this.orgId) {
1225
+ headers["x-profile-id"] = this.orgId;
1230
1226
  }
1231
1227
  const timeout = options.timeout || 3e4;
1232
1228
  const controller = new AbortController();
@@ -1238,6 +1234,13 @@ var McpUseAPI = class _McpUseAPI {
1238
1234
  signal: controller.signal
1239
1235
  });
1240
1236
  clearTimeout(timeoutId);
1237
+ if (response.status === 401) {
1238
+ const err = new Error(
1239
+ "Your session has expired or your API key is invalid."
1240
+ );
1241
+ err.status = 401;
1242
+ throw err;
1243
+ }
1241
1244
  if (!response.ok) {
1242
1245
  const error = await response.text();
1243
1246
  throw new Error(`API request failed: ${response.status} ${error}`);
@@ -1246,25 +1249,24 @@ var McpUseAPI = class _McpUseAPI {
1246
1249
  } catch (error) {
1247
1250
  clearTimeout(timeoutId);
1248
1251
  if (error.name === "AbortError") {
1249
- throw new Error(
1250
- `Request timeout after ${timeout / 1e3}s. Try using --follow flag to stream logs instead.`
1251
- );
1252
+ throw new Error(`Request timeout after ${timeout / 1e3}s.`);
1252
1253
  }
1253
1254
  throw error;
1254
1255
  }
1255
1256
  }
1256
1257
  /**
1257
- * Create API key using JWT token
1258
+ * Create a persistent API key using a Better Auth access token.
1258
1259
  */
1259
- async createApiKey(jwtToken, name = "CLI") {
1260
- const url = `${this.baseUrl}/api-key`;
1260
+ async createApiKeyWithAccessToken(accessToken, name = "CLI") {
1261
+ const authBase = await getAuthBaseUrl();
1262
+ const url = `${authBase}/api/auth/api-key/create`;
1261
1263
  const response = await fetch(url, {
1262
1264
  method: "POST",
1263
1265
  headers: {
1264
1266
  "Content-Type": "application/json",
1265
- Authorization: `Bearer ${jwtToken}`
1267
+ Authorization: `Bearer ${accessToken}`
1266
1268
  },
1267
- body: JSON.stringify({ name })
1269
+ body: JSON.stringify({ name, prefix: "mcp_" })
1268
1270
  });
1269
1271
  if (!response.ok) {
1270
1272
  const error = await response.text();
@@ -1272,540 +1274,195 @@ var McpUseAPI = class _McpUseAPI {
1272
1274
  }
1273
1275
  return response.json();
1274
1276
  }
1275
- /**
1276
- * Test authentication
1277
- */
1277
+ // ── Auth ────────────────────────────────────────────────────────
1278
1278
  async testAuth() {
1279
- 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
+ };
1280
1292
  }
1281
- /**
1282
- * Set the user's default profile (organization) on the server
1283
- */
1284
- async setDefaultProfile(profileId) {
1285
- await this.request(`/profiles/${profileId}/set-default`, {
1293
+ async setDefaultOrg(orgId) {
1294
+ await this.request(`/organizations/${orgId}/set-default`, {
1286
1295
  method: "POST"
1287
1296
  });
1288
1297
  }
1289
- /**
1290
- * Create deployment
1291
- */
1292
- async createDeployment(request) {
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", {
1313
+ method: "POST",
1314
+ body: JSON.stringify(body)
1315
+ });
1316
+ }
1317
+ // ── Deployments ─────────────────────────────────────────────────
1318
+ async createDeployment(input) {
1293
1319
  return this.request("/deployments", {
1294
1320
  method: "POST",
1295
- body: JSON.stringify(request)
1321
+ body: JSON.stringify(input)
1296
1322
  });
1297
1323
  }
1298
- /**
1299
- * Get deployment by ID
1300
- */
1301
1324
  async getDeployment(deploymentId) {
1302
1325
  return this.request(`/deployments/${deploymentId}`);
1303
1326
  }
1304
- /**
1305
- * Stream deployment logs
1306
- */
1307
- async *streamDeploymentLogs(deploymentId) {
1308
- const url = `${this.baseUrl}/deployments/${deploymentId}/logs/stream`;
1309
- const headers = {};
1310
- if (this.apiKey) {
1311
- headers["x-api-key"] = this.apiKey;
1312
- }
1313
- if (this.profileId) {
1314
- headers["x-profile-id"] = this.profileId;
1315
- }
1316
- const response = await fetch(url, { headers });
1317
- if (!response.ok) {
1318
- throw new Error(`Failed to stream logs: ${response.status}`);
1319
- }
1320
- if (!response.body) {
1321
- throw new Error("Response body is null");
1322
- }
1323
- const reader = response.body.getReader();
1324
- const decoder = new TextDecoder();
1325
- let buffer = "";
1326
- try {
1327
- while (true) {
1328
- const { done, value } = await reader.read();
1329
- if (done) break;
1330
- buffer += decoder.decode(value, { stream: true });
1331
- const lines = buffer.split("\n");
1332
- buffer = lines.pop() || "";
1333
- for (const line of lines) {
1334
- if (line.startsWith("data: ")) {
1335
- const data = line.slice(6);
1336
- try {
1337
- const parsed = JSON.parse(data);
1338
- if (parsed.log) {
1339
- yield parsed.log;
1340
- } else if (parsed.error) {
1341
- throw new Error(parsed.error);
1342
- }
1343
- } catch (e) {
1344
- }
1345
- }
1346
- }
1347
- }
1348
- } finally {
1349
- reader.releaseLock();
1350
- }
1351
- }
1352
- /**
1353
- * Create deployment with source code upload
1354
- */
1355
- async createDeploymentWithUpload(request, filePath) {
1356
- const { readFile: readFile4 } = await import("fs/promises");
1357
- const { basename } = await import("path");
1358
- const { stat } = await import("fs/promises");
1359
- const stats = await stat(filePath);
1360
- const maxSize = 2 * 1024 * 1024;
1361
- if (stats.size > maxSize) {
1362
- throw new Error(
1363
- `File size (${(stats.size / 1024 / 1024).toFixed(2)}MB) exceeds maximum of 2MB`
1364
- );
1365
- }
1366
- const fileBuffer = await readFile4(filePath);
1367
- const filename = basename(filePath);
1368
- const formData = new FormData();
1369
- const blob = new Blob([fileBuffer], { type: "application/gzip" });
1370
- formData.append("source_file", blob, filename);
1371
- formData.append("name", request.name);
1372
- formData.append("source_type", "upload");
1373
- if (request.source.type === "upload") {
1374
- formData.append("runtime", request.source.runtime || "node");
1375
- formData.append("port", String(request.source.port || 3e3));
1376
- if (request.source.startCommand) {
1377
- formData.append("startCommand", request.source.startCommand);
1378
- }
1379
- if (request.source.buildCommand) {
1380
- formData.append("buildCommand", request.source.buildCommand);
1381
- }
1382
- if (request.source.env && Object.keys(request.source.env).length > 0) {
1383
- formData.append("env", JSON.stringify(request.source.env));
1384
- }
1385
- }
1386
- if (request.customDomain) {
1387
- formData.append("customDomain", request.customDomain);
1388
- }
1389
- if (request.healthCheckPath) {
1390
- formData.append("healthCheckPath", request.healthCheckPath);
1391
- }
1392
- const url = `${this.baseUrl}/deployments`;
1393
- const headers = {};
1394
- if (this.apiKey) {
1395
- headers["x-api-key"] = this.apiKey;
1396
- }
1397
- if (this.profileId) {
1398
- headers["x-profile-id"] = this.profileId;
1399
- }
1400
- const response = await fetch(url, {
1401
- method: "POST",
1402
- headers,
1403
- body: formData
1404
- });
1405
- if (!response.ok) {
1406
- const error = await response.text();
1407
- throw new Error(`Deployment failed: ${error}`);
1408
- }
1409
- return response.json();
1410
- }
1411
- /**
1412
- * List all deployments
1413
- */
1414
1327
  async listDeployments() {
1415
- const response = await this.request("/deployments");
1416
- return response.deployments;
1328
+ return this.request("/deployments");
1417
1329
  }
1418
- /**
1419
- * Delete deployment
1420
- */
1421
1330
  async deleteDeployment(deploymentId) {
1422
1331
  await this.request(`/deployments/${deploymentId}`, {
1423
1332
  method: "DELETE"
1424
1333
  });
1425
1334
  }
1426
- /**
1427
- * Update deployment
1428
- */
1429
- async updateDeployment(deploymentId, updates) {
1430
- return this.request(`/deployments/${deploymentId}`, {
1431
- method: "PATCH",
1432
- body: JSON.stringify(updates)
1433
- });
1434
- }
1435
- /**
1436
- * Redeploy deployment
1437
- *
1438
- * @param deploymentId - The deployment ID to redeploy
1439
- * @param configOrFilePath - Either a RedeploymentConfig object with updated settings,
1440
- * or a file path string for source code upload
1441
- */
1442
- async redeployDeployment(deploymentId, configOrFilePath) {
1443
- if (typeof configOrFilePath === "string") {
1444
- const filePath = configOrFilePath;
1445
- const { readFile: readFile4 } = await import("fs/promises");
1446
- const { basename } = await import("path");
1447
- const { stat } = await import("fs/promises");
1448
- const stats = await stat(filePath);
1449
- const maxSize = 2 * 1024 * 1024;
1450
- if (stats.size > maxSize) {
1451
- throw new Error(
1452
- `File size (${(stats.size / 1024 / 1024).toFixed(2)}MB) exceeds maximum of 2MB`
1453
- );
1454
- }
1455
- const fileBuffer = await readFile4(filePath);
1456
- const formData = new FormData();
1457
- const blob = new Blob([fileBuffer], { type: "application/gzip" });
1458
- formData.append("source_file", blob, basename(filePath));
1459
- const headers = {};
1460
- if (this.apiKey) headers["x-api-key"] = this.apiKey;
1461
- if (this.profileId) headers["x-profile-id"] = this.profileId;
1462
- const response = await fetch(
1463
- `${this.baseUrl}/deployments/${deploymentId}/redeploy`,
1464
- {
1465
- method: "POST",
1466
- headers,
1467
- body: formData
1468
- }
1469
- );
1470
- if (!response.ok) {
1471
- const error = await response.text();
1472
- throw new Error(`Redeploy failed: ${error}`);
1473
- }
1474
- return response.json();
1475
- }
1476
- const config = configOrFilePath;
1477
- return this.request(`/deployments/${deploymentId}/redeploy`, {
1478
- method: "POST",
1479
- body: config ? JSON.stringify(config) : void 0
1335
+ async stopDeployment(deploymentId) {
1336
+ await this.request(`/deployments/${deploymentId}/stop`, {
1337
+ method: "POST"
1480
1338
  });
1481
1339
  }
1482
- /**
1483
- * Get deployment logs
1484
- */
1485
- async getDeploymentLogs(deploymentId) {
1486
- const response = await this.request(
1487
- `/deployments/${deploymentId}/logs`,
1340
+ async getDeploymentLogs(deploymentId, lines = 500) {
1341
+ const resp = await this.request(
1342
+ `/deployments/${deploymentId}/logs?lines=${lines}`,
1488
1343
  { timeout: 6e4 }
1489
- // 60 second timeout for logs
1490
1344
  );
1491
- return response.data.logs;
1345
+ return resp.logs;
1492
1346
  }
1493
- /**
1494
- * Get deployment build logs
1495
- */
1496
- async getDeploymentBuildLogs(deploymentId) {
1497
- const response = await this.request(
1498
- `/deployments/${deploymentId}/logs/build`,
1347
+ async getDeploymentBuildLogs(deploymentId, offset = 0) {
1348
+ return this.request(
1349
+ `/deployments/${deploymentId}/build-logs?offset=${offset}`,
1499
1350
  { timeout: 6e4 }
1500
- // 60 second timeout for logs
1501
1351
  );
1502
- return response.data.logs;
1503
1352
  }
1504
- /**
1505
- * Get GitHub connection status
1506
- */
1353
+ // ── GitHub ──────────────────────────────────────────────────────
1507
1354
  async getGitHubConnectionStatus() {
1508
- return this.request("/github/connection");
1355
+ const orgId = await this.resolveOrganizationId();
1356
+ const resp = await this.request(`/github/installations?organizationId=${orgId}`);
1357
+ return {
1358
+ is_connected: resp.installations.length > 0,
1359
+ installations: resp.installations.map((i) => ({
1360
+ id: i.id,
1361
+ installation_id: i.installationId
1362
+ }))
1363
+ };
1509
1364
  }
1510
- /**
1511
- * Get GitHub app name
1512
- */
1513
- async getGitHubAppName() {
1514
- const response = await this.request("/github/appname");
1515
- return response.app_name;
1365
+ async getGitHubRepos(_refresh) {
1366
+ const orgId = await this.resolveOrganizationId();
1367
+ const installResp = await this.request(`/github/installations?organizationId=${orgId}`);
1368
+ if (installResp.installations.length === 0) {
1369
+ return { user: { login: "", id: 0, avatar_url: "" }, repos: [] };
1370
+ }
1371
+ const inst = installResp.installations[0];
1372
+ const reposResp = await this.request(`/github/installations/${inst.installationId}/repos`);
1373
+ return {
1374
+ user: {
1375
+ login: inst.account?.login ?? "",
1376
+ id: 0,
1377
+ avatar_url: inst.account?.avatar_url ?? ""
1378
+ },
1379
+ repos: reposResp.repos.map((r) => ({
1380
+ id: r.id,
1381
+ name: r.name,
1382
+ full_name: r.fullName,
1383
+ private: r.private,
1384
+ owner: { login: r.fullName.split("/")[0] ?? "" }
1385
+ }))
1386
+ };
1516
1387
  }
1517
- /**
1518
- * Get accessible GitHub repositories
1519
- */
1520
- async getGitHubRepos(refresh = false) {
1521
- return this.request(
1522
- `/github/repos${refresh ? "?refresh=true" : ""}`
1523
- );
1388
+ async getGitHubAppName() {
1389
+ if (process.env.MCP_GITHUB_APP_NAME) return process.env.MCP_GITHUB_APP_NAME;
1390
+ return this.baseUrl.includes(".dev.") ? "mcp-use-dev" : "mcp-use";
1524
1391
  }
1525
1392
  };
1526
1393
 
1527
1394
  // src/commands/auth.ts
1528
- var LOGIN_TIMEOUT = 3e5;
1529
- async function findAvailablePort(startPort = 8765) {
1530
- for (let port = startPort; port < startPort + 100; port++) {
1531
- try {
1532
- await new Promise((resolve2, reject) => {
1533
- const server = createServer();
1534
- server.once("error", reject);
1535
- server.once("listening", () => {
1536
- server.close();
1537
- resolve2();
1538
- });
1539
- server.listen(port);
1540
- });
1541
- return port;
1542
- } catch {
1543
- continue;
1544
- }
1395
+ var DEVICE_CLIENT_ID = "mcp-use-cli";
1396
+ var DEVICE_POLL_TIMEOUT = 18e5;
1397
+ async function requestDeviceCode(authBaseUrl) {
1398
+ const url = `${authBaseUrl}/api/auth/device/code`;
1399
+ const response = await fetch(url, {
1400
+ method: "POST",
1401
+ headers: { "Content-Type": "application/json" },
1402
+ body: JSON.stringify({
1403
+ client_id: DEVICE_CLIENT_ID,
1404
+ scope: "openid profile email"
1405
+ })
1406
+ });
1407
+ if (!response.ok) {
1408
+ const error = await response.text();
1409
+ throw new Error(
1410
+ `Failed to request device code: ${response.status} ${error}`
1411
+ );
1545
1412
  }
1546
- throw new Error("No available ports found");
1413
+ return response.json();
1547
1414
  }
1548
- async function startCallbackServer(port, expectedState) {
1549
- return new Promise((resolve2, reject) => {
1550
- let tokenResolver = null;
1551
- const tokenPromise = new Promise((res) => {
1552
- tokenResolver = res;
1415
+ async function pollForDeviceToken(authBaseUrl, deviceCode, intervalSeconds) {
1416
+ let pollingInterval = intervalSeconds;
1417
+ const deadline = Date.now() + DEVICE_POLL_TIMEOUT;
1418
+ while (Date.now() < deadline) {
1419
+ const delayMs = pollingInterval * 1e3;
1420
+ await new Promise((r) => setTimeout(r, delayMs));
1421
+ const url = `${authBaseUrl}/api/auth/device/token`;
1422
+ const response = await fetch(url, {
1423
+ method: "POST",
1424
+ headers: { "Content-Type": "application/json" },
1425
+ body: JSON.stringify({
1426
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
1427
+ device_code: deviceCode,
1428
+ client_id: DEVICE_CLIENT_ID
1429
+ })
1553
1430
  });
1554
- const server = createServer(
1555
- {
1556
- maxHeaderSize: 65536
1557
- // 64KB - handle very long JWT tokens in URL (increased from default 8192)
1558
- },
1559
- (req, res) => {
1560
- if (req.url?.startsWith("/callback")) {
1561
- const url = new URL(req.url, `http://localhost:${port}`);
1562
- const token = url.searchParams.get("token");
1563
- const state = url.searchParams.get("state");
1564
- if (state !== expectedState) {
1565
- res.writeHead(400, { "Content-Type": "text/html" });
1566
- res.end(`
1567
- <!DOCTYPE html>
1568
- <html>
1569
- <head>
1570
- <title>Security Error</title>
1571
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
1572
- <style>
1573
- body {
1574
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
1575
- display: flex;
1576
- justify-content: center;
1577
- align-items: center;
1578
- min-height: 100vh;
1579
- background: #000;
1580
- padding: 1rem;
1581
- margin: 0;
1582
- }
1583
- .container {
1584
- max-width: 28rem;
1585
- padding: 3rem;
1586
- text-align: center;
1587
- background: rgba(255, 255, 255, 0.1);
1588
- backdrop-filter: blur(40px);
1589
- border: 1px solid rgba(255, 255, 255, 0.2);
1590
- border-radius: 1.5rem;
1591
- }
1592
- h1 { color: #fff; font-size: 2rem; margin-bottom: 1rem; }
1593
- p { color: rgba(255, 255, 255, 0.8); font-size: 1rem; }
1594
- </style>
1595
- </head>
1596
- <body>
1597
- <div class="container">
1598
- <h1>Security Error</h1>
1599
- <p>Invalid state parameter. Please try logging in again.</p>
1600
- </div>
1601
- </body>
1602
- </html>
1603
- `);
1604
- return;
1605
- }
1606
- if (token && tokenResolver) {
1607
- res.writeHead(200, { "Content-Type": "text/html" });
1608
- res.end(`
1609
- <!DOCTYPE html>
1610
- <html>
1611
- <head>
1612
- <title>Login Successful</title>
1613
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
1614
- <style>
1615
- * {
1616
- margin: 0;
1617
- padding: 0;
1618
- box-sizing: border-box;
1619
- }
1620
- body {
1621
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
1622
- display: flex;
1623
- justify-content: center;
1624
- align-items: center;
1625
- min-height: 100vh;
1626
- background: #000;
1627
- padding: 1rem;
1628
- }
1629
- .container {
1630
- width: 100%;
1631
- max-width: 28rem;
1632
- padding: 3rem;
1633
- text-align: center;
1634
- -webkit-backdrop-filter: blur(40px);
1635
- border: 1px solid rgba(255, 255, 255, 0.2);
1636
- border-radius: 1.5rem;
1637
- box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
1638
- }
1639
- .icon-container {
1640
- display: inline-flex;
1641
- align-items: center;
1642
- justify-content: center;
1643
- width: 6rem;
1644
- height: 6rem;
1645
- margin-bottom: 2rem;
1646
- background: rgba(255, 255, 255, 0.1);
1647
- backdrop-filter: blur(10px);
1648
- -webkit-backdrop-filter: blur(10px);
1649
- border-radius: 50%;
1650
- }
1651
- .checkmark {
1652
- font-size: 4rem;
1653
- color: #fff;
1654
- line-height: 1;
1655
- animation: scaleIn 0.5s ease-out;
1656
- }
1657
- @keyframes scaleIn {
1658
- from {
1659
- transform: scale(0);
1660
- opacity: 0;
1661
- }
1662
- to {
1663
- transform: scale(1);
1664
- opacity: 1;
1665
- }
1666
- }
1667
- h1 {
1668
- color: #fff;
1669
- margin: 0 0 1rem 0;
1670
- font-size: 2.5rem;
1671
- font-weight: 700;
1672
- letter-spacing: -0.025em;
1673
- }
1674
- p {
1675
- color: rgba(255, 255, 255, 0.8);
1676
- margin: 0 0 2rem 0;
1677
- font-size: 1.125rem;
1678
- line-height: 1.5;
1679
- }
1680
- .spinner {
1681
- display: inline-block;
1682
- width: 2rem;
1683
- height: 2rem;
1684
- border: 3px solid rgba(255, 255, 255, 0.3);
1685
- border-top-color: #fff;
1686
- border-radius: 50%;
1687
- animation: spin 0.8s linear infinite;
1688
- }
1689
- @keyframes spin {
1690
- to { transform: rotate(360deg); }
1691
- }
1692
- .footer {
1693
- margin-top: 2rem;
1694
- color: rgba(255, 255, 255, 0.6);
1695
- font-size: 0.875rem;
1696
- }
1697
- </style>
1698
- </head>
1699
- <body>
1700
- <div class="container">
1701
- <h1>Authentication Successful!</h1>
1702
- <p>You can now close this window and return to the CLI.</p>
1703
- </div>
1704
- </body>
1705
- </html>
1706
- `);
1707
- tokenResolver(token);
1708
- } else {
1709
- res.writeHead(400, { "Content-Type": "text/html" });
1710
- res.end(`
1711
- <!DOCTYPE html>
1712
- <html>
1713
- <head>
1714
- <title>Login Failed</title>
1715
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
1716
- <style>
1717
- * {
1718
- margin: 0;
1719
- padding: 0;
1720
- box-sizing: border-box;
1721
- }
1722
- body {
1723
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
1724
- display: flex;
1725
- justify-content: center;
1726
- align-items: center;
1727
- min-height: 100vh;
1728
- background: #000;
1729
- padding: 1rem;
1730
- }
1731
- .container {
1732
- width: 100%;
1733
- max-width: 28rem;
1734
- padding: 3rem;
1735
- text-align: center;
1736
- background: rgba(255, 255, 255, 0.1);
1737
- backdrop-filter: blur(40px);
1738
- -webkit-backdrop-filter: blur(40px);
1739
- border: 1px solid rgba(255, 255, 255, 0.2);
1740
- border-radius: 1.5rem;
1741
- box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
1742
- }
1743
- .icon-container {
1744
- display: inline-flex;
1745
- align-items: center;
1746
- justify-content: center;
1747
- width: 6rem;
1748
- height: 6rem;
1749
- margin-bottom: 2rem;
1750
- background: rgba(255, 255, 255, 0.1);
1751
- backdrop-filter: blur(10px);
1752
- -webkit-backdrop-filter: blur(10px);
1753
- border-radius: 50%;
1754
- }
1755
- .cross {
1756
- font-size: 4rem;
1757
- color: #fff;
1758
- line-height: 1;
1759
- }
1760
- h1 {
1761
- color: #fff;
1762
- margin: 0 0 1rem 0;
1763
- font-size: 2.5rem;
1764
- font-weight: 700;
1765
- letter-spacing: -0.025em;
1766
- }
1767
- p {
1768
- color: rgba(255, 255, 255, 0.8);
1769
- margin: 0;
1770
- font-size: 1.125rem;
1771
- line-height: 1.5;
1772
- }
1773
- </style>
1774
- </head>
1775
- <body>
1776
- <div class="container">
1777
- <div class="icon-container">
1778
- <div class="cross">\u2717</div>
1779
- </div>
1780
- <h1>Login Failed</h1>
1781
- <p>No token received. Please try again.</p>
1782
- </div>
1783
- </body>
1784
- </html>
1785
- `);
1786
- }
1787
- }
1431
+ const data = await response.json();
1432
+ if (data.access_token) {
1433
+ return data.access_token;
1434
+ }
1435
+ if (data.error) {
1436
+ switch (data.error) {
1437
+ case "authorization_pending":
1438
+ break;
1439
+ case "slow_down":
1440
+ pollingInterval += 5;
1441
+ break;
1442
+ case "access_denied":
1443
+ throw new Error("Authorization was denied by the user.");
1444
+ case "expired_token":
1445
+ throw new Error("The device code has expired. Please try again.");
1446
+ default:
1447
+ throw new Error(
1448
+ data.error_description || `Device auth error: ${data.error}`
1449
+ );
1788
1450
  }
1789
- );
1790
- server.listen(port, () => {
1791
- resolve2({ server, token: tokenPromise });
1792
- });
1793
- server.on("error", reject);
1794
- });
1451
+ }
1452
+ }
1453
+ throw new Error("Login timed out. Please try again.");
1795
1454
  }
1796
- async function promptOrgSelection(profiles, defaultProfileId) {
1797
- if (profiles.length === 0) return null;
1798
- if (profiles.length === 1) {
1799
- return profiles[0];
1455
+ async function promptOrgSelection(orgs, defaultOrgId) {
1456
+ if (orgs.length === 0) return null;
1457
+ if (orgs.length === 1) {
1458
+ return orgs[0];
1800
1459
  }
1801
1460
  console.log(source_default.cyan.bold("\n\u{1F3E2} Select an organization:\n"));
1802
- for (let i = 0; i < profiles.length; i++) {
1803
- const p = profiles[i];
1804
- const marker = p.id === defaultProfileId ? source_default.green(" (current)") : "";
1805
- const slug = p.slug ? source_default.gray(` (${p.slug})`) : "";
1806
- console.log(
1807
- ` ${source_default.white(`${i + 1}.`)} ${p.profile_name}${slug}${marker}`
1808
- );
1461
+ for (let i = 0; i < orgs.length; i++) {
1462
+ const o = orgs[i];
1463
+ const marker = o.id === defaultOrgId ? source_default.green(" (current)") : "";
1464
+ const slug = o.slug ? source_default.gray(` (${o.slug})`) : "";
1465
+ console.log(` ${source_default.white(`${i + 1}.`)} ${o.name}${slug}${marker}`);
1809
1466
  }
1810
1467
  const readline = await import("readline");
1811
1468
  const rl = readline.createInterface({
@@ -1813,7 +1470,7 @@ async function promptOrgSelection(profiles, defaultProfileId) {
1813
1470
  output: process.stdout
1814
1471
  });
1815
1472
  return new Promise((resolve2) => {
1816
- const defaultIdx = defaultProfileId ? profiles.findIndex((p) => p.id === defaultProfileId) : 0;
1473
+ const defaultIdx = defaultOrgId ? orgs.findIndex((o) => o.id === defaultOrgId) : 0;
1817
1474
  const defaultDisplay = defaultIdx >= 0 ? defaultIdx + 1 : 1;
1818
1475
  rl.question(
1819
1476
  source_default.gray(`
@@ -1822,11 +1479,11 @@ Enter number [${defaultDisplay}]: `),
1822
1479
  rl.close();
1823
1480
  const trimmed = answer.trim();
1824
1481
  const idx = trimmed === "" ? defaultIdx : parseInt(trimmed, 10) - 1;
1825
- if (idx >= 0 && idx < profiles.length) {
1826
- resolve2(profiles[idx]);
1482
+ if (idx >= 0 && idx < orgs.length) {
1483
+ resolve2(orgs[idx]);
1827
1484
  } else {
1828
1485
  console.log(source_default.yellow("Invalid selection, using default."));
1829
- resolve2(profiles[defaultIdx >= 0 ? defaultIdx : 0]);
1486
+ resolve2(orgs[defaultIdx >= 0 ? defaultIdx : 0]);
1830
1487
  }
1831
1488
  }
1832
1489
  );
@@ -1834,105 +1491,114 @@ Enter number [${defaultDisplay}]: `),
1834
1491
  }
1835
1492
  async function loginCommand(options) {
1836
1493
  try {
1494
+ const directKey = options?.apiKey || process.env.MCP_USE_API_KEY;
1495
+ if (directKey) {
1496
+ await writeConfig({ apiKey: directKey });
1497
+ if (!options?.silent) {
1498
+ console.log(source_default.green.bold("\u2713 API key saved."));
1499
+ try {
1500
+ const api2 = await McpUseAPI.create();
1501
+ const authInfo = await api2.testAuth();
1502
+ console.log(source_default.gray(` Authenticated as ${authInfo.email}`));
1503
+ } catch {
1504
+ console.log(
1505
+ source_default.gray(
1506
+ " (could not verify key \u2014 will be checked on next command)"
1507
+ )
1508
+ );
1509
+ }
1510
+ }
1511
+ return;
1512
+ }
1837
1513
  if (await isLoggedIn()) {
1838
1514
  if (!options?.silent) {
1839
1515
  console.log(
1840
1516
  source_default.yellow(
1841
- "\u26A0\uFE0F You are already logged in. Run 'npx mcp-use logout' first if you want to login with a different account."
1517
+ "You are already logged in. Run 'npx mcp-use logout' first if you want to login with a different account."
1842
1518
  )
1843
1519
  );
1844
1520
  }
1845
1521
  return;
1846
1522
  }
1847
- console.log(source_default.cyan.bold("\u{1F510} Logging in to Manufact cloud...\n"));
1848
- const state = crypto.randomBytes(32).toString("hex");
1849
- const port = await findAvailablePort();
1850
- const redirectUri = `http://localhost:${port}/callback`;
1851
- console.log(source_default.gray(`Starting local server on port ${port}...`));
1852
- const { server, token } = await startCallbackServer(port, state);
1853
- const webUrl = await getWebUrl();
1854
- const loginUrl = `${webUrl}/auth/cli?redirect_uri=${encodeURIComponent(redirectUri)}&state=${state}`;
1855
- console.log(source_default.gray(`Opening browser to ${webUrl}/auth/cli...
1856
- `));
1857
- console.log(
1858
- source_default.white(
1859
- "If the browser doesn't open automatically, please visit:\n" + source_default.cyan(loginUrl)
1860
- )
1861
- );
1862
- await open_default(loginUrl);
1863
- console.log(
1864
- source_default.gray("\nWaiting for authentication... (this may take a moment)")
1865
- );
1866
- const jwtToken = await Promise.race([
1867
- token,
1868
- new Promise(
1869
- (_, reject) => setTimeout(
1870
- () => reject(new Error("Login timeout - please try again")),
1871
- LOGIN_TIMEOUT
1872
- )
1873
- )
1874
- ]);
1875
- server.close();
1876
- console.log(
1877
- source_default.gray("Received authentication token, creating API key...")
1523
+ console.log(source_default.cyan.bold("Logging in to mcp-use cloud...\n"));
1524
+ const authBaseUrl = await getAuthBaseUrl();
1525
+ const deviceResp = await requestDeviceCode(authBaseUrl);
1526
+ const {
1527
+ device_code,
1528
+ user_code,
1529
+ verification_uri,
1530
+ verification_uri_complete,
1531
+ interval
1532
+ } = deviceResp;
1533
+ const displayCode = user_code.length === 8 ? `${user_code.slice(0, 4)}-${user_code.slice(4)}` : user_code;
1534
+ console.log(source_default.white(" Visit: ") + source_default.cyan(verification_uri));
1535
+ console.log(source_default.white(" Code: ") + source_default.bold.white(displayCode));
1536
+ console.log();
1537
+ const urlToOpen = verification_uri_complete || verification_uri;
1538
+ try {
1539
+ await open_default(urlToOpen);
1540
+ console.log(source_default.gray(" Browser opened. Waiting for approval..."));
1541
+ } catch {
1542
+ console.log(source_default.gray(" Open the URL above in your browser."));
1543
+ }
1544
+ const accessToken = await pollForDeviceToken(
1545
+ authBaseUrl,
1546
+ device_code,
1547
+ interval || 5
1878
1548
  );
1549
+ console.log(source_default.gray("\n Creating persistent API key..."));
1879
1550
  const api = await McpUseAPI.create();
1880
- const apiKeyResponse = await api.createApiKey(jwtToken, "CLI");
1881
- await writeConfig({
1882
- apiKey: apiKeyResponse.api_key
1883
- });
1551
+ const keyResp = await api.createApiKeyWithAccessToken(accessToken, "CLI");
1552
+ await writeConfig({ apiKey: keyResp.key });
1884
1553
  console.log(source_default.green.bold("\n\u2713 Successfully logged in!"));
1885
1554
  try {
1886
- const api2 = await McpUseAPI.create();
1887
- const authInfo = await api2.testAuth();
1888
- console.log(source_default.cyan.bold("\n\u{1F464} Current user:\n"));
1889
- console.log(source_default.white("Email: ") + source_default.cyan(authInfo.email));
1890
- console.log(source_default.white("User ID: ") + source_default.gray(authInfo.user_id));
1891
- const apiKey = await getApiKey();
1892
- if (apiKey) {
1893
- const masked = apiKey.substring(0, 6) + "...";
1894
- console.log(source_default.white("API Key: ") + source_default.gray(masked));
1895
- }
1896
- const profiles = authInfo.profiles ?? [];
1897
- if (profiles.length > 0) {
1898
- let selectedProfile = null;
1899
- if (profiles.length === 1) {
1900
- selectedProfile = profiles[0];
1555
+ const freshApi = await McpUseAPI.create();
1556
+ const authInfo = await freshApi.testAuth();
1557
+ console.log(source_default.cyan.bold("\nCurrent user:\n"));
1558
+ console.log(source_default.white(" Email: ") + source_default.cyan(authInfo.email));
1559
+ console.log(source_default.white(" User ID: ") + source_default.gray(authInfo.user_id));
1560
+ const storedKey = await getApiKey();
1561
+ if (storedKey) {
1562
+ const masked = storedKey.substring(0, 8) + "...";
1563
+ console.log(source_default.white(" API Key: ") + source_default.gray(masked));
1564
+ }
1565
+ const orgs = authInfo.orgs ?? [];
1566
+ if (orgs.length > 0) {
1567
+ let selectedOrg = null;
1568
+ if (orgs.length === 1) {
1569
+ selectedOrg = orgs[0];
1901
1570
  } else {
1902
- selectedProfile = await promptOrgSelection(
1903
- profiles,
1904
- authInfo.default_profile_id
1905
- );
1571
+ selectedOrg = await promptOrgSelection(orgs, authInfo.default_org_id);
1906
1572
  }
1907
- if (selectedProfile) {
1573
+ if (selectedOrg) {
1908
1574
  const config = await readConfig();
1909
1575
  await writeConfig({
1910
1576
  ...config,
1911
- profileId: selectedProfile.id,
1912
- profileName: selectedProfile.profile_name,
1913
- profileSlug: selectedProfile.slug ?? void 0
1577
+ orgId: selectedOrg.id,
1578
+ orgName: selectedOrg.name,
1579
+ orgSlug: selectedOrg.slug ?? void 0
1914
1580
  });
1915
- const slug = selectedProfile.slug ? source_default.gray(` (${selectedProfile.slug})`) : "";
1581
+ const slug = selectedOrg.slug ? source_default.gray(` (${selectedOrg.slug})`) : "";
1916
1582
  console.log(
1917
- source_default.white("Org: ") + source_default.cyan(selectedProfile.profile_name) + slug
1583
+ source_default.white(" Org: ") + source_default.cyan(selectedOrg.name) + slug
1918
1584
  );
1919
1585
  }
1920
1586
  }
1921
- } catch (error) {
1587
+ } catch {
1922
1588
  console.log(
1923
1589
  source_default.gray(
1924
1590
  `
1925
- Your API key has been saved to ${source_default.white("~/.mcp-use/config.json")}`
1591
+ Your API key has been saved to ${source_default.white("~/.mcp-use/config.json")}`
1926
1592
  )
1927
1593
  );
1928
1594
  }
1929
1595
  console.log(
1930
1596
  source_default.gray(
1931
- "\nYou can now deploy your MCP servers with " + source_default.white("npx mcp-use deploy")
1597
+ "\n Deploy your MCP servers with " + source_default.white("npx mcp-use deploy")
1932
1598
  )
1933
1599
  );
1934
1600
  console.log(
1935
- source_default.gray("To logout later, run " + source_default.white("npx mcp-use logout"))
1601
+ source_default.gray(" To logout, run " + source_default.white("npx mcp-use logout"))
1936
1602
  );
1937
1603
  } catch (error) {
1938
1604
  throw new Error(
@@ -1984,31 +1650,41 @@ async function whoamiCommand() {
1984
1650
  console.log(source_default.white("API Key: ") + source_default.gray(masked));
1985
1651
  }
1986
1652
  const config = await readConfig();
1987
- const profiles = authInfo.profiles ?? [];
1988
- if (profiles.length > 0) {
1989
- const activeProfile = profiles.find(
1990
- (p) => p.id === (config.profileId || authInfo.default_profile_id)
1653
+ const orgs = authInfo.orgs ?? [];
1654
+ if (orgs.length > 0) {
1655
+ const activeOrg = orgs.find(
1656
+ (o) => o.id === (config.orgId || authInfo.default_org_id)
1991
1657
  );
1992
- if (activeProfile) {
1993
- const slug = activeProfile.slug ? source_default.gray(` (${activeProfile.slug})`) : "";
1658
+ if (activeOrg) {
1659
+ const slug = activeOrg.slug ? source_default.gray(` (${activeOrg.slug})`) : "";
1994
1660
  console.log(
1995
- source_default.white("Org: ") + source_default.cyan(activeProfile.profile_name) + slug
1661
+ source_default.white("Org: ") + source_default.cyan(activeOrg.name) + slug
1996
1662
  );
1997
1663
  }
1998
- if (profiles.length > 1) {
1664
+ if (orgs.length > 1) {
1999
1665
  console.log(
2000
1666
  source_default.gray(
2001
1667
  `
2002
- ${profiles.length} organizations available. Use ` + source_default.white("npx mcp-use org list") + " to see all."
1668
+ ${orgs.length} organizations available. Use ` + source_default.white("npx mcp-use org list") + " to see all."
2003
1669
  )
2004
1670
  );
2005
1671
  }
2006
1672
  }
2007
1673
  } catch (error) {
2008
- console.error(
2009
- source_default.red.bold("\n\u2717 Failed to get user info:"),
2010
- source_default.red(error instanceof Error ? error.message : "Unknown error")
2011
- );
1674
+ if (error?.status === 401) {
1675
+ console.error(
1676
+ source_default.red("\nYour session has expired or your API key is invalid.")
1677
+ );
1678
+ console.log(
1679
+ source_default.gray(`Run ${source_default.white("mcp-use login")} to re-authenticate.
1680
+ `)
1681
+ );
1682
+ } else {
1683
+ console.error(
1684
+ source_default.red.bold("\n\u2717 Failed to get user info:"),
1685
+ source_default.red(error instanceof Error ? error.message : "Unknown error")
1686
+ );
1687
+ }
2012
1688
  process.exit(1);
2013
1689
  }
2014
1690
  }
@@ -3384,25 +3060,20 @@ async function prompt(question, defaultValue = "n") {
3384
3060
  });
3385
3061
  }
3386
3062
  function getMcpServerUrl(deployment) {
3387
- if (deployment.customDomain) {
3388
- return `https://${deployment.customDomain}/mcp`;
3389
- } else if (deployment.serverSlug) {
3390
- return buildGatewayUrl(deployment.serverSlug);
3391
- } else if (deployment.serverId) {
3063
+ if (deployment.mcpUrl) {
3064
+ return deployment.mcpUrl;
3065
+ }
3066
+ if (deployment.serverId) {
3392
3067
  return buildGatewayUrl(deployment.serverId);
3393
- } else {
3394
- return `https://${deployment.domain}/mcp`;
3395
3068
  }
3069
+ return "";
3396
3070
  }
3397
- async function displayDeploymentProgress(api, deployment, progressOptions) {
3071
+ async function displayDeploymentProgress(api, deploymentId, progressOptions) {
3398
3072
  const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
3399
3073
  let frameIndex = 0;
3400
3074
  let spinnerInterval = null;
3401
- let lastStep = "";
3402
3075
  const startSpinner = (message) => {
3403
- if (spinnerInterval) {
3404
- clearInterval(spinnerInterval);
3405
- }
3076
+ if (spinnerInterval) clearInterval(spinnerInterval);
3406
3077
  process.stdout.write("\r\x1B[K");
3407
3078
  spinnerInterval = setInterval(() => {
3408
3079
  const frame = frames[frameIndex];
@@ -3421,82 +3092,64 @@ async function displayDeploymentProgress(api, deployment, progressOptions) {
3421
3092
  };
3422
3093
  console.log();
3423
3094
  startSpinner("Deploying...");
3424
- try {
3425
- for await (const log of api.streamDeploymentLogs(deployment.id)) {
3426
- try {
3427
- const logData = JSON.parse(log);
3428
- if (logData.step && logData.step !== lastStep) {
3429
- lastStep = logData.step;
3430
- const stepMessages = {
3431
- clone: "Preparing source code...",
3432
- analyze: "Analyzing project...",
3433
- build: "Building container image...",
3434
- deploy: "Deploying to cloud..."
3435
- };
3436
- const message = stepMessages[logData.step] || "Deploying...";
3437
- startSpinner(message);
3438
- }
3439
- if (logData.line) {
3440
- stopSpinner();
3441
- const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
3442
- const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
3443
- console.log(stepPrefix + levelColor(logData.line));
3444
- }
3445
- } catch {
3446
- }
3447
- }
3448
- } catch (error) {
3449
- stopSpinner();
3450
- }
3451
3095
  let checkCount = 0;
3452
- const maxChecks = 60;
3453
- let delay = 3e3;
3096
+ const maxChecks = 120;
3097
+ let delay = 2e3;
3454
3098
  const maxDelay = 1e4;
3455
- let lastDisplayedLogLength = 0;
3099
+ let buildLogOffset = 0;
3100
+ const sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
3456
3101
  while (checkCount < maxChecks) {
3457
- const currentDelay = delay;
3458
- await new Promise((resolve2) => setTimeout(resolve2, currentDelay));
3459
- const finalDeployment = await api.getDeployment(deployment.id);
3460
- if (finalDeployment.buildLogs && finalDeployment.buildLogs.length > lastDisplayedLogLength) {
3461
- const newLogs = finalDeployment.buildLogs.substring(
3462
- lastDisplayedLogLength
3102
+ await sleep(delay);
3103
+ checkCount++;
3104
+ try {
3105
+ const buildLogsResp = await api.getDeploymentBuildLogs(
3106
+ deploymentId,
3107
+ buildLogOffset
3463
3108
  );
3464
- const logLines = newLogs.split("\n").filter((l) => l.trim());
3465
- for (const line of logLines) {
3466
- try {
3467
- const logData = JSON.parse(line);
3468
- if (logData.line) {
3109
+ if (buildLogsResp.logs.length > 0) {
3110
+ const logLines = buildLogsResp.logs.split("\n").filter((l) => l.trim());
3111
+ for (const line of logLines) {
3112
+ try {
3113
+ const logData = JSON.parse(line);
3114
+ if (logData.line) {
3115
+ stopSpinner();
3116
+ const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
3117
+ const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
3118
+ console.log(stepPrefix + levelColor(logData.line));
3119
+ }
3120
+ } catch {
3469
3121
  stopSpinner();
3470
- const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
3471
- const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
3472
- console.log(stepPrefix + levelColor(logData.line));
3122
+ console.log(source_default.gray(line));
3473
3123
  }
3474
- } catch {
3475
3124
  }
3125
+ buildLogOffset = buildLogsResp.offset;
3476
3126
  }
3477
- lastDisplayedLogLength = finalDeployment.buildLogs.length;
3127
+ } catch {
3478
3128
  }
3479
- if (finalDeployment.status === "running") {
3480
- const mcpServerUrl = getMcpServerUrl(finalDeployment);
3129
+ const deployment = await api.getDeployment(deploymentId);
3130
+ if (deployment.status === "running") {
3131
+ stopSpinner();
3132
+ const mcpServerUrl = getMcpServerUrl(deployment);
3481
3133
  let dashboardUrl = null;
3482
3134
  const webUrl = (await getWebUrl()).replace(/\/$/, "");
3483
3135
  const config = await readConfig();
3484
- const orgSlug = config.profileSlug;
3485
- const serverRef = finalDeployment.serverSlug || finalDeployment.serverId;
3486
- if (serverRef) {
3136
+ const orgSlug = config.orgSlug;
3137
+ if (deployment.serverId) {
3487
3138
  if (orgSlug) {
3488
- dashboardUrl = `${webUrl}/cloud/${orgSlug}/servers/${serverRef}`;
3139
+ dashboardUrl = `${webUrl}/cloud/${orgSlug}/servers/${deployment.serverId}`;
3489
3140
  } else {
3490
- dashboardUrl = `${webUrl}/cloud/servers/${serverRef}`;
3141
+ dashboardUrl = `${webUrl}/cloud/servers/${deployment.serverId}`;
3491
3142
  }
3492
3143
  }
3493
3144
  const inspectorUrl = `https://inspector.manufact.com/inspector?autoConnect=${encodeURIComponent(
3494
3145
  mcpServerUrl
3495
3146
  )}`;
3496
3147
  console.log(source_default.green.bold("\u2713 Deployment successful!\n"));
3497
- console.log(source_default.white("\u{1F310} MCP Server URL:"));
3498
- console.log(source_default.cyan.bold(` ${mcpServerUrl}
3148
+ if (mcpServerUrl) {
3149
+ console.log(source_default.white("\u{1F310} MCP Server URL:"));
3150
+ console.log(source_default.cyan.bold(` ${mcpServerUrl}
3499
3151
  `));
3152
+ }
3500
3153
  if (dashboardUrl) {
3501
3154
  console.log(source_default.white("\u{1F4CA} Dashboard:"));
3502
3155
  console.log(source_default.cyan.bold(` ${dashboardUrl}
@@ -3505,16 +3158,14 @@ async function displayDeploymentProgress(api, deployment, progressOptions) {
3505
3158
  console.log(source_default.white("\u{1F50D} Inspector URL:"));
3506
3159
  console.log(source_default.cyan.bold(` ${inspectorUrl}
3507
3160
  `));
3508
- console.log(
3509
- source_default.gray("Deployment ID: ") + source_default.white(finalDeployment.id)
3510
- );
3161
+ console.log(source_default.gray("Deployment ID: ") + source_default.white(deployment.id));
3511
3162
  return;
3512
- } else if (finalDeployment.status === "failed") {
3163
+ } else if (deployment.status === "failed") {
3513
3164
  stopSpinner();
3514
3165
  console.log(source_default.red.bold("\u2717 Deployment failed\n"));
3515
- if (finalDeployment.error) {
3516
- console.log(source_default.red("Error: ") + finalDeployment.error);
3517
- if (finalDeployment.error.includes("No GitHub installations found")) {
3166
+ if (deployment.error) {
3167
+ console.log(source_default.red("Error: ") + deployment.error);
3168
+ if (deployment.error.includes("No GitHub installations found")) {
3518
3169
  console.log();
3519
3170
  const retry = await promptGitHubInstallation(
3520
3171
  api,
@@ -3522,79 +3173,31 @@ async function displayDeploymentProgress(api, deployment, progressOptions) {
3522
3173
  void 0,
3523
3174
  { yes: progressOptions?.yes }
3524
3175
  );
3525
- if (retry) {
3176
+ if (retry && deployment.serverId) {
3526
3177
  console.log(source_default.cyan("\n\u{1F504} Retrying deployment...\n"));
3527
- const newDeployment = await api.redeployDeployment(deployment.id);
3528
- await displayDeploymentProgress(
3529
- api,
3530
- newDeployment,
3531
- progressOptions
3532
- );
3533
- return;
3534
- }
3535
- } else if (finalDeployment.error.includes("Authenticated git clone failed")) {
3536
- let repoName;
3537
- const repoMatch = finalDeployment.error.match(
3538
- /github\.com\/([^/]+\/[^/\s]+)/
3539
- );
3540
- if (repoMatch) {
3541
- repoName = repoMatch[1].replace(/\.git$/, "");
3542
- } else if (finalDeployment.source.type === "github") {
3543
- repoName = finalDeployment.source.repo;
3544
- }
3545
- console.log();
3546
- const retry = await promptGitHubInstallation(
3547
- api,
3548
- "no_access",
3549
- repoName,
3550
- { yes: progressOptions?.yes }
3551
- );
3552
- if (retry) {
3553
- console.log(source_default.cyan("\n\u{1F504} Retrying deployment...\n"));
3554
- const newDeployment = await api.redeployDeployment(deployment.id);
3555
- await displayDeploymentProgress(
3556
- api,
3557
- newDeployment,
3558
- progressOptions
3559
- );
3178
+ const newDep = await api.createDeployment({
3179
+ serverId: deployment.serverId,
3180
+ trigger: "redeploy"
3181
+ });
3182
+ await displayDeploymentProgress(api, newDep.id, progressOptions);
3560
3183
  return;
3561
3184
  }
3562
3185
  }
3563
3186
  }
3564
- if (finalDeployment.buildLogs) {
3565
- console.log(source_default.gray("\nBuild logs:"));
3566
- try {
3567
- const logs = finalDeployment.buildLogs.split("\n").filter((l) => l.trim());
3568
- for (const log of logs) {
3569
- try {
3570
- const logData = JSON.parse(log);
3571
- if (logData.line) {
3572
- console.log(source_default.gray(` ${logData.line}`));
3573
- }
3574
- } catch {
3575
- console.log(source_default.gray(` ${log}`));
3576
- }
3577
- }
3578
- } catch {
3579
- console.log(source_default.gray(finalDeployment.buildLogs));
3580
- }
3581
- }
3582
3187
  process.exit(1);
3583
- } else if (finalDeployment.status === "building") {
3188
+ } else if (deployment.status === "building" || deployment.status === "pending") {
3584
3189
  startSpinner("Building and deploying...");
3585
- checkCount++;
3586
3190
  delay = Math.min(delay * 1.2, maxDelay);
3587
3191
  } else {
3588
- console.log(
3589
- source_default.yellow("\u26A0\uFE0F Deployment status: ") + finalDeployment.status
3590
- );
3192
+ stopSpinner();
3193
+ console.log(source_default.yellow("\u26A0\uFE0F Deployment status: ") + deployment.status);
3591
3194
  return;
3592
3195
  }
3593
3196
  }
3594
3197
  stopSpinner();
3595
3198
  console.log(source_default.yellow("\u26A0\uFE0F Deployment is taking longer than expected."));
3596
3199
  console.log(
3597
- source_default.gray("Check status with: ") + source_default.white(`mcp-use status ${deployment.id}`)
3200
+ source_default.gray("Check status with: ") + source_default.white(`mcp-use deployments get ${deploymentId}`)
3598
3201
  );
3599
3202
  }
3600
3203
  async function checkRepoAccess(api, owner, repo) {
@@ -3680,7 +3283,7 @@ async function promptGitHubInstallation(api, reason, repoName, opts) {
3680
3283
  return false;
3681
3284
  }
3682
3285
  try {
3683
- const appName = process.env.MCP_GITHUB_APP_NAME || "mcp-use";
3286
+ const appName = await api.getGitHubAppName();
3684
3287
  const installUrl = reason === "not_connected" ? `https://github.com/apps/${appName}/installations/new` : `https://github.com/settings/installations`;
3685
3288
  console.log(
3686
3289
  source_default.cyan(
@@ -3960,14 +3563,14 @@ async function deployCommand(options) {
3960
3563
  if (options.org) {
3961
3564
  try {
3962
3565
  const authInfo = await api.testAuth();
3963
- const match = (authInfo.profiles ?? []).find(
3964
- (p) => p.slug === options.org || p.id === options.org || p.profile_name.toLowerCase() === options.org.toLowerCase()
3566
+ const match = (authInfo.orgs ?? []).find(
3567
+ (o) => o.slug === options.org || o.id === options.org || o.name.toLowerCase() === options.org.toLowerCase()
3965
3568
  );
3966
3569
  if (match) {
3967
- api.setProfileId(match.id);
3570
+ api.setOrgId(match.id);
3968
3571
  const slug = match.slug ? source_default.gray(` (${match.slug})`) : "";
3969
3572
  console.log(
3970
- source_default.gray("Organization: ") + source_default.cyan(match.profile_name) + slug
3573
+ source_default.gray("Organization: ") + source_default.cyan(match.name) + slug
3971
3574
  );
3972
3575
  } else {
3973
3576
  console.error(
@@ -3986,6 +3589,7 @@ async function deployCommand(options) {
3986
3589
  }
3987
3590
  }
3988
3591
  let githubVerified = false;
3592
+ let installationDbId;
3989
3593
  try {
3990
3594
  console.log(source_default.gray(`[DEBUG] API URL: ${api.baseUrl}`));
3991
3595
  const connectionStatus = await api.getGitHubConnectionStatus();
@@ -4012,8 +3616,10 @@ async function deployCommand(options) {
4012
3616
  console.log(source_default.cyan(" https://manufact.com/cloud/settings\n"));
4013
3617
  process.exit(1);
4014
3618
  }
3619
+ installationDbId = retryStatus.installations?.[0]?.id;
4015
3620
  githubVerified = true;
4016
3621
  } else if (gitInfo.owner && gitInfo.repo) {
3622
+ installationDbId = connectionStatus.installations?.[0]?.id;
4017
3623
  console.log(source_default.gray("Checking repository access..."));
4018
3624
  const hasAccess = await checkRepoAccess(
4019
3625
  api,
@@ -4092,7 +3698,7 @@ async function deployCommand(options) {
4092
3698
  }
4093
3699
  const existingLink = !options.new ? await getProjectLink(cwd) : null;
4094
3700
  const serverId = existingLink?.serverId;
4095
- if (existingLink) {
3701
+ if (existingLink && serverId) {
4096
3702
  try {
4097
3703
  const existingDeployment = await api.getDeployment(
4098
3704
  existingLink.deploymentId
@@ -4104,29 +3710,19 @@ async function deployCommand(options) {
4104
3710
  source_default.cyan(` URL: ${getMcpServerUrl(existingDeployment)}
4105
3711
  `)
4106
3712
  );
4107
- const redeploymentConfig = {
4108
- buildCommand,
4109
- startCommand,
4110
- ...options.port !== void 0 ? { port: options.port } : {},
4111
- env: Object.keys(envVars).length > 0 ? envVars : void 0,
4112
- rootDir: options.rootDir || void 0
4113
- };
4114
- const deployment2 = await api.redeployDeployment(
4115
- existingLink.deploymentId,
4116
- redeploymentConfig
4117
- );
3713
+ const newDep = await api.createDeployment({
3714
+ serverId,
3715
+ branch: gitInfo.branch || "main",
3716
+ trigger: "redeploy"
3717
+ });
4118
3718
  await saveProjectLink(cwd, {
4119
3719
  ...existingLink,
4120
- linkedAt: (/* @__PURE__ */ new Date()).toISOString()
3720
+ linkedAt: (/* @__PURE__ */ new Date()).toISOString(),
3721
+ deploymentId: newDep.id
4121
3722
  });
4122
- await displayDeploymentProgress(api, deployment2, {
3723
+ await displayDeploymentProgress(api, newDep.id, {
4123
3724
  yes: options.yes
4124
3725
  });
4125
- if (options.open && deployment2.domain) {
4126
- console.log();
4127
- console.log(source_default.gray("Opening deployment in browser..."));
4128
- await open_default(`https://${deployment2.domain}`);
4129
- }
4130
3726
  return;
4131
3727
  } else {
4132
3728
  console.log(
@@ -4134,72 +3730,97 @@ async function deployCommand(options) {
4134
3730
  `\u26A0\uFE0F Linked deployment not found or failed, creating new one...`
4135
3731
  )
4136
3732
  );
4137
- if (serverId) {
4138
- console.log(
4139
- source_default.gray(` Will reuse existing server: ${serverId}`)
4140
- );
4141
- }
3733
+ console.log(source_default.gray(` Will reuse existing server: ${serverId}`));
4142
3734
  }
4143
3735
  } catch (error) {
4144
3736
  console.log(
4145
3737
  source_default.yellow(`\u26A0\uFE0F Linked deployment not found, creating new one...`)
4146
3738
  );
4147
- if (serverId) {
4148
- console.log(source_default.gray(` Will reuse existing server: ${serverId}`));
4149
- }
3739
+ console.log(source_default.gray(` Will reuse existing server: ${serverId}`));
4150
3740
  }
4151
3741
  }
4152
- const deploymentRequest = {
4153
- name: projectName,
4154
- source: {
4155
- type: "github",
4156
- repo: `${gitInfo.owner}/${gitInfo.repo}`,
4157
- branch: gitInfo.branch || "main",
4158
- rootDir: options.rootDir || void 0,
4159
- runtime,
4160
- port,
4161
- buildCommand,
4162
- startCommand,
4163
- env: Object.keys(envVars).length > 0 ? envVars : void 0
4164
- },
4165
- healthCheckPath: "/healthz",
4166
- serverId
4167
- };
4168
3742
  if (!options.org) {
4169
3743
  try {
4170
3744
  const config = await readConfig();
4171
- if (config.profileName) {
4172
- const slug = config.profileSlug ? source_default.gray(` (${config.profileSlug})`) : "";
3745
+ if (config.orgName) {
3746
+ const slug = config.orgSlug ? source_default.gray(` (${config.orgSlug})`) : "";
4173
3747
  console.log(
4174
- source_default.gray("Organization: ") + source_default.cyan(config.profileName) + slug
3748
+ source_default.gray("Organization: ") + source_default.cyan(config.orgName) + slug
4175
3749
  );
4176
3750
  }
4177
3751
  } catch {
4178
3752
  }
4179
3753
  }
4180
- console.log(source_default.gray("Creating deployment..."));
4181
- const deployment = await api.createDeployment(deploymentRequest);
4182
- console.log(
4183
- source_default.green("\u2713 Deployment created: ") + source_default.gray(deployment.id)
4184
- );
4185
- await saveProjectLink(cwd, {
4186
- deploymentId: deployment.id,
4187
- deploymentName: projectName,
4188
- deploymentUrl: deployment.domain,
4189
- linkedAt: (/* @__PURE__ */ new Date()).toISOString(),
4190
- serverId: deployment.serverId
4191
- });
4192
- console.log(
4193
- source_default.gray(` Linked to this project (stored in .mcp-use/project.json)`)
4194
- );
4195
- console.log(source_default.gray(` Future deploys will reuse the same URL
3754
+ let deploymentId;
3755
+ if (serverId) {
3756
+ console.log(source_default.gray("Creating deployment..."));
3757
+ const result = await api.createDeployment({
3758
+ serverId,
3759
+ branch: gitInfo.branch || "main",
3760
+ trigger: "manual"
3761
+ });
3762
+ deploymentId = result.id;
3763
+ } else {
3764
+ if (!installationDbId) {
3765
+ console.log(source_default.red("\u2717 Could not determine GitHub installation ID."));
3766
+ console.log(
3767
+ source_default.gray(
3768
+ "Please ensure your GitHub App is installed and try again."
3769
+ )
3770
+ );
3771
+ process.exit(1);
3772
+ }
3773
+ const config = await readConfig();
3774
+ const authInfo = await api.testAuth();
3775
+ const orgId = config.orgId || authInfo.default_org_id;
3776
+ if (!orgId) {
3777
+ console.log(
3778
+ source_default.red("\u2717 No organization set. Run `mcp-use org switch` first.")
3779
+ );
3780
+ process.exit(1);
3781
+ }
3782
+ console.log(source_default.gray("Creating server and deployment..."));
3783
+ const serverResult = await api.createServer({
3784
+ type: "github",
3785
+ organizationId: orgId,
3786
+ installationId: installationDbId,
3787
+ name: projectName,
3788
+ repoFullName: `${gitInfo.owner}/${gitInfo.repo}`,
3789
+ branch: gitInfo.branch || "main",
3790
+ rootDir: options.rootDir,
3791
+ port,
3792
+ buildCommand,
3793
+ startCommand,
3794
+ env: Object.keys(envVars).length > 0 ? envVars : void 0
3795
+ });
3796
+ deploymentId = serverResult.deploymentId ?? "";
3797
+ if (!deploymentId) {
3798
+ console.log(
3799
+ source_default.green("\u2713 Server created: ") + source_default.gray(serverResult.server.id)
3800
+ );
3801
+ console.log(
3802
+ source_default.yellow(
3803
+ "\u26A0\uFE0F No deployment was triggered. You may need to trigger one manually."
3804
+ )
3805
+ );
3806
+ return;
3807
+ }
3808
+ await saveProjectLink(cwd, {
3809
+ deploymentId,
3810
+ deploymentName: projectName,
3811
+ linkedAt: (/* @__PURE__ */ new Date()).toISOString(),
3812
+ serverId: serverResult.server.id
3813
+ });
3814
+ console.log(
3815
+ source_default.gray(` Linked to this project (stored in .mcp-use/project.json)`)
3816
+ );
3817
+ console.log(source_default.gray(` Future deploys will reuse the same URL
4196
3818
  `));
4197
- await displayDeploymentProgress(api, deployment, { yes: options.yes });
4198
- if (options.open && deployment.domain) {
4199
- console.log();
4200
- console.log(source_default.gray("Opening deployment in browser..."));
4201
- await open_default(`https://${deployment.domain}`);
4202
3819
  }
3820
+ console.log(
3821
+ source_default.green("\u2713 Deployment created: ") + source_default.gray(deploymentId)
3822
+ );
3823
+ await displayDeploymentProgress(api, deploymentId, { yes: options.yes });
4203
3824
  } catch (error) {
4204
3825
  console.error(
4205
3826
  source_default.red.bold("\n\u2717 Deployment failed:"),
@@ -4274,19 +3895,19 @@ async function listDeploymentsCommand() {
4274
3895
  );
4275
3896
  console.log(
4276
3897
  source_default.white.bold(
4277
- `${"ID".padEnd(40)} ${"NAME".padEnd(25)} ${"STATUS".padEnd(12)} ${"DOMAIN".padEnd(35)} ${"CREATED"}`
3898
+ `${"ID".padEnd(40)} ${"NAME".padEnd(25)} ${"STATUS".padEnd(12)} ${"MCP URL".padEnd(45)} ${"CREATED"}`
4278
3899
  )
4279
3900
  );
4280
- console.log(source_default.gray("\u2500".repeat(130)));
3901
+ console.log(source_default.gray("\u2500".repeat(140)));
4281
3902
  for (const deployment of sortedDeployments) {
4282
3903
  const id = formatId(deployment.id).padEnd(40);
4283
3904
  const name = deployment.name.substring(0, 24).padEnd(25);
4284
3905
  const statusColor = getStatusColor(deployment.status);
4285
3906
  const status = statusColor(deployment.status.padEnd(12));
4286
- const domain = (deployment.domain || "-").substring(0, 34).padEnd(35);
3907
+ const mcpUrl = (deployment.mcpUrl || "-").substring(0, 44).padEnd(45);
4287
3908
  const created = formatRelativeTime(deployment.createdAt);
4288
3909
  console.log(
4289
- `${source_default.gray(id)} ${name} ${status} ${source_default.cyan(domain)} ${source_default.gray(created)}`
3910
+ `${source_default.gray(id)} ${name} ${status} ${source_default.cyan(mcpUrl)} ${source_default.gray(created)}`
4290
3911
  );
4291
3912
  }
4292
3913
  console.log();
@@ -4318,31 +3939,24 @@ async function getDeploymentCommand(deploymentId) {
4318
3939
  console.log(
4319
3940
  source_default.white("Status: ") + statusColor(deployment.status)
4320
3941
  );
4321
- if (deployment.domain) {
3942
+ if (deployment.mcpUrl) {
4322
3943
  console.log(
4323
- source_default.white("Domain: ") + source_default.cyan(`https://${deployment.domain}`)
3944
+ source_default.white("MCP URL: ") + source_default.cyan(deployment.mcpUrl)
4324
3945
  );
4325
3946
  }
4326
- if (deployment.customDomain) {
3947
+ if (deployment.gitBranch) {
4327
3948
  console.log(
4328
- source_default.white("Custom Domain: ") + source_default.cyan(`https://${deployment.customDomain}`)
3949
+ source_default.white("Branch: ") + source_default.gray(deployment.gitBranch)
4329
3950
  );
4330
3951
  }
4331
- console.log(
4332
- source_default.white("Source: ") + source_default.gray(deployment.source.type)
4333
- );
4334
- if (deployment.source.type === "github") {
4335
- console.log(
4336
- source_default.white("Repository: ") + source_default.gray(deployment.source.repo)
4337
- );
3952
+ if (deployment.gitCommitSha) {
4338
3953
  console.log(
4339
- source_default.white("Branch: ") + source_default.gray(deployment.source.branch || "main")
3954
+ source_default.white("Commit: ") + source_default.gray(deployment.gitCommitSha.substring(0, 7))
4340
3955
  );
4341
3956
  }
4342
- console.log(source_default.white("Port: ") + source_default.gray(deployment.port));
4343
- console.log(
4344
- source_default.white("Runtime: ") + source_default.gray(deployment.source.runtime || "node")
4345
- );
3957
+ if (deployment.port) {
3958
+ console.log(source_default.white("Port: ") + source_default.gray(deployment.port));
3959
+ }
4346
3960
  if (deployment.provider) {
4347
3961
  console.log(
4348
3962
  source_default.white("Provider: ") + source_default.gray(deployment.provider)
@@ -4354,13 +3968,6 @@ async function getDeploymentCommand(deploymentId) {
4354
3968
  console.log(
4355
3969
  source_default.white("Updated: ") + source_default.gray(formatRelativeTime(deployment.updatedAt))
4356
3970
  );
4357
- if (deployment.source.env && Object.keys(deployment.source.env).length > 0) {
4358
- console.log(source_default.white("\nEnvironment Variables:"));
4359
- for (const [key, value] of Object.entries(deployment.source.env)) {
4360
- const displayValue = key.toLowerCase().includes("key") || key.toLowerCase().includes("secret") || key.toLowerCase().includes("password") || key.toLowerCase().includes("token") ? "***" : value;
4361
- console.log(source_default.gray(` ${key}=`) + source_default.white(displayValue));
4362
- }
4363
- }
4364
3971
  if (deployment.status === "failed" && deployment.error) {
4365
3972
  console.log(source_default.red("\nError:"));
4366
3973
  console.log(source_default.red(` ${deployment.error}`));
@@ -4387,43 +3994,56 @@ async function restartDeploymentCommand(deploymentId, options) {
4387
3994
  }
4388
3995
  const api = await McpUseAPI.create();
4389
3996
  const deployment = await api.getDeployment(deploymentId);
3997
+ if (!deployment.serverId) {
3998
+ console.log(
3999
+ source_default.red("\u2717 Cannot restart: deployment has no linked server.")
4000
+ );
4001
+ process.exit(1);
4002
+ }
4390
4003
  console.log(
4391
4004
  source_default.cyan.bold(`
4392
4005
  \u{1F504} Restarting deployment: ${deployment.name}
4393
4006
  `)
4394
4007
  );
4395
- const redeployedDeployment = await api.redeployDeployment(deploymentId);
4396
- console.log(
4397
- source_default.green("\u2713 Restart initiated: ") + source_default.gray(redeployedDeployment.id)
4398
- );
4008
+ const newDep = await api.createDeployment({
4009
+ serverId: deployment.serverId,
4010
+ trigger: "redeploy"
4011
+ });
4012
+ console.log(source_default.green("\u2713 Restart initiated: ") + source_default.gray(newDep.id));
4399
4013
  if (options.follow) {
4400
- console.log(source_default.gray("\nFollowing deployment logs...\n"));
4401
- try {
4402
- for await (const log of api.streamDeploymentLogs(
4403
- redeployedDeployment.id
4404
- )) {
4405
- try {
4406
- const logData = JSON.parse(log);
4407
- if (logData.line) {
4408
- const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
4409
- const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
4410
- console.log(stepPrefix + levelColor(logData.line));
4014
+ console.log(source_default.gray("\nFollowing build logs...\n"));
4015
+ let offset = 0;
4016
+ let terminal = false;
4017
+ while (!terminal) {
4018
+ await new Promise((r) => setTimeout(r, 2e3));
4019
+ try {
4020
+ const resp = await api.getDeploymentBuildLogs(newDep.id, offset);
4021
+ if (resp.logs.length > 0) {
4022
+ const lines = resp.logs.split("\n").filter((l) => l.trim());
4023
+ for (const line of lines) {
4024
+ try {
4025
+ const logData = JSON.parse(line);
4026
+ if (logData.line) {
4027
+ const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
4028
+ const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
4029
+ console.log(stepPrefix + levelColor(logData.line));
4030
+ }
4031
+ } catch {
4032
+ console.log(source_default.gray(line));
4033
+ }
4411
4034
  }
4412
- } catch {
4413
- console.log(source_default.gray(log));
4035
+ offset = resp.offset;
4414
4036
  }
4037
+ if (resp.status === "running" || resp.status === "failed" || resp.status === "stopped") {
4038
+ terminal = true;
4039
+ }
4040
+ } catch {
4415
4041
  }
4416
- } catch (error) {
4417
- console.log(
4418
- source_default.gray(
4419
- "\nLog stream ended. Use " + source_default.white(`mcp-use deployments get ${deploymentId}`) + " to check status."
4420
- )
4421
- );
4422
4042
  }
4423
4043
  } else {
4424
4044
  console.log(
4425
4045
  source_default.gray(
4426
- "\nCheck status with: " + source_default.white(`mcp-use deployments get ${deploymentId}`)
4046
+ "\nCheck status with: " + source_default.white(`mcp-use deployments get ${newDep.id}`)
4427
4047
  )
4428
4048
  );
4429
4049
  }
@@ -4457,8 +4077,10 @@ async function deleteDeploymentCommand(deploymentId, options) {
4457
4077
  )
4458
4078
  );
4459
4079
  console.log(source_default.gray(` ID: ${deployment.id}`));
4460
- console.log(source_default.gray(` Domain: ${deployment.domain || "none"}
4080
+ if (deployment.mcpUrl) {
4081
+ console.log(source_default.gray(` URL: ${deployment.mcpUrl}
4461
4082
  `));
4083
+ }
4462
4084
  const confirmed = await prompt2(
4463
4085
  source_default.white("Are you sure you want to delete this deployment? (y/N): ")
4464
4086
  );
@@ -4494,30 +4116,41 @@ async function logsCommand(deploymentId, options) {
4494
4116
  }
4495
4117
  const api = await McpUseAPI.create();
4496
4118
  if (options.follow) {
4497
- console.log(source_default.gray("Streaming logs...\n"));
4498
- try {
4499
- for await (const log of api.streamDeploymentLogs(deploymentId)) {
4500
- try {
4501
- const logData = JSON.parse(log);
4502
- if (logData.line) {
4503
- const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
4504
- const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
4505
- console.log(stepPrefix + levelColor(logData.line));
4119
+ console.log(source_default.gray("Following build logs...\n"));
4120
+ let offset = 0;
4121
+ let terminal = false;
4122
+ while (!terminal) {
4123
+ await new Promise((r) => setTimeout(r, 2e3));
4124
+ try {
4125
+ const resp = await api.getDeploymentBuildLogs(deploymentId, offset);
4126
+ if (resp.logs.length > 0) {
4127
+ const lines = resp.logs.split("\n").filter((l) => l.trim());
4128
+ for (const line of lines) {
4129
+ try {
4130
+ const logData = JSON.parse(line);
4131
+ if (logData.line) {
4132
+ const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
4133
+ const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
4134
+ console.log(stepPrefix + levelColor(logData.line));
4135
+ }
4136
+ } catch {
4137
+ console.log(source_default.gray(line));
4138
+ }
4506
4139
  }
4507
- } catch {
4508
- console.log(source_default.gray(log));
4140
+ offset = resp.offset;
4141
+ }
4142
+ if (resp.status === "running" || resp.status === "failed" || resp.status === "stopped") {
4143
+ terminal = true;
4509
4144
  }
4145
+ } catch {
4510
4146
  }
4511
- } catch (error) {
4512
- console.log(source_default.gray("\nLog stream ended."));
4513
4147
  }
4514
- } else {
4515
- const logs = options.build ? await api.getDeploymentBuildLogs(deploymentId) : await api.getDeploymentLogs(deploymentId);
4148
+ } else if (options.build) {
4149
+ const resp = await api.getDeploymentBuildLogs(deploymentId);
4150
+ const logs = resp.logs;
4516
4151
  if (!logs || logs.trim() === "") {
4517
4152
  console.log(
4518
- source_default.yellow(
4519
- `No ${options.build ? "build " : ""}logs available for this deployment.`
4520
- )
4153
+ source_default.yellow("No build logs available for this deployment.")
4521
4154
  );
4522
4155
  return;
4523
4156
  }
@@ -4534,133 +4167,30 @@ async function logsCommand(deploymentId, options) {
4534
4167
  console.log(source_default.gray(line));
4535
4168
  }
4536
4169
  }
4537
- }
4538
- console.log();
4539
- } catch (error) {
4540
- console.error(
4541
- source_default.red.bold("\n\u2717 Failed to get logs:"),
4542
- source_default.red(error instanceof Error ? error.message : "Unknown error")
4543
- );
4544
- process.exit(1);
4545
- }
4546
- }
4547
- async function listEnvCommand(deploymentId) {
4548
- try {
4549
- if (!await isLoggedIn()) {
4550
- console.log(source_default.red("\u2717 You are not logged in."));
4551
- console.log(
4552
- source_default.gray(
4553
- "Run " + source_default.white("npx mcp-use login") + " to get started."
4554
- )
4555
- );
4556
- process.exit(1);
4557
- }
4558
- const api = await McpUseAPI.create();
4559
- const deployment = await api.getDeployment(deploymentId);
4560
- console.log(
4561
- source_default.cyan.bold(`
4562
- \u{1F510} Environment Variables: ${deployment.name}
4563
- `)
4564
- );
4565
- if (!deployment.source.env || Object.keys(deployment.source.env).length === 0) {
4566
- console.log(source_default.yellow("No environment variables set."));
4567
- console.log();
4568
- return;
4569
- }
4570
- for (const [key, value] of Object.entries(deployment.source.env)) {
4571
- const displayValue = key.toLowerCase().includes("key") || key.toLowerCase().includes("secret") || key.toLowerCase().includes("password") || key.toLowerCase().includes("token") ? "***" : value;
4572
- console.log(
4573
- source_default.white(key) + source_default.gray("=") + source_default.cyan(displayValue)
4574
- );
4575
- }
4576
- console.log();
4577
- } catch (error) {
4578
- console.error(
4579
- source_default.red.bold("\n\u2717 Failed to list environment variables:"),
4580
- source_default.red(error instanceof Error ? error.message : "Unknown error")
4581
- );
4582
- process.exit(1);
4583
- }
4584
- }
4585
- async function setEnvCommand(deploymentId, envPairs) {
4586
- try {
4587
- if (!await isLoggedIn()) {
4588
- console.log(source_default.red("\u2717 You are not logged in."));
4589
- console.log(
4590
- source_default.gray(
4591
- "Run " + source_default.white("npx mcp-use login") + " to get started."
4592
- )
4593
- );
4594
- process.exit(1);
4595
- }
4596
- const env2 = {};
4597
- for (const pair of envPairs) {
4598
- const [key, ...valueParts] = pair.split("=");
4599
- if (!key || valueParts.length === 0) {
4600
- console.log(source_default.red(`\u2717 Invalid format: ${pair}. Expected KEY=VALUE`));
4601
- process.exit(1);
4170
+ } else {
4171
+ const logs = await api.getDeploymentLogs(deploymentId);
4172
+ if (!logs || logs.trim() === "") {
4173
+ console.log(source_default.yellow("No logs available for this deployment."));
4174
+ return;
4175
+ }
4176
+ const logLines = logs.split("\n").filter((l) => l.trim());
4177
+ for (const line of logLines) {
4178
+ try {
4179
+ const logData = JSON.parse(line);
4180
+ if (logData.line) {
4181
+ const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
4182
+ const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
4183
+ console.log(stepPrefix + levelColor(logData.line));
4184
+ }
4185
+ } catch {
4186
+ console.log(source_default.gray(line));
4187
+ }
4602
4188
  }
4603
- env2[key.trim()] = valueParts.join("=").trim();
4604
- }
4605
- const api = await McpUseAPI.create();
4606
- const deployment = await api.getDeployment(deploymentId);
4607
- const currentEnv = deployment.source.env || {};
4608
- const mergedEnv = { ...currentEnv, ...env2 };
4609
- const updated = await api.updateDeployment(deploymentId, {
4610
- env: mergedEnv
4611
- });
4612
- console.log(
4613
- source_default.green.bold(`
4614
- \u2713 Environment variables updated: ${updated.name}
4615
- `)
4616
- );
4617
- for (const key of Object.keys(env2)) {
4618
- const displayValue = key.toLowerCase().includes("key") || key.toLowerCase().includes("secret") || key.toLowerCase().includes("password") || key.toLowerCase().includes("token") ? "***" : env2[key];
4619
- console.log(
4620
- source_default.white(key) + source_default.gray("=") + source_default.cyan(displayValue)
4621
- );
4622
- }
4623
- console.log();
4624
- } catch (error) {
4625
- console.error(
4626
- source_default.red.bold("\n\u2717 Failed to set environment variables:"),
4627
- source_default.red(error instanceof Error ? error.message : "Unknown error")
4628
- );
4629
- process.exit(1);
4630
- }
4631
- }
4632
- async function unsetEnvCommand(deploymentId, keys) {
4633
- try {
4634
- if (!await isLoggedIn()) {
4635
- console.log(source_default.red("\u2717 You are not logged in."));
4636
- console.log(
4637
- source_default.gray(
4638
- "Run " + source_default.white("npx mcp-use login") + " to get started."
4639
- )
4640
- );
4641
- process.exit(1);
4642
- }
4643
- const api = await McpUseAPI.create();
4644
- const deployment = await api.getDeployment(deploymentId);
4645
- const currentEnv = { ...deployment.source.env || {} };
4646
- for (const key of keys) {
4647
- delete currentEnv[key];
4648
- }
4649
- const updated = await api.updateDeployment(deploymentId, {
4650
- env: currentEnv
4651
- });
4652
- console.log(
4653
- source_default.green.bold(`
4654
- \u2713 Environment variables removed: ${updated.name}
4655
- `)
4656
- );
4657
- for (const key of keys) {
4658
- console.log(source_default.gray(` ${key}`));
4659
4189
  }
4660
4190
  console.log();
4661
4191
  } catch (error) {
4662
4192
  console.error(
4663
- source_default.red.bold("\n\u2717 Failed to unset environment variables:"),
4193
+ source_default.red.bold("\n\u2717 Failed to get logs:"),
4664
4194
  source_default.red(error instanceof Error ? error.message : "Unknown error")
4665
4195
  );
4666
4196
  process.exit(1);
@@ -4678,11 +4208,9 @@ async function stopDeploymentCommand(deploymentId) {
4678
4208
  process.exit(1);
4679
4209
  }
4680
4210
  const api = await McpUseAPI.create();
4681
- const updated = await api.updateDeployment(deploymentId, {
4682
- status: "stopped"
4683
- });
4211
+ await api.stopDeployment(deploymentId);
4684
4212
  console.log(source_default.green.bold(`
4685
- \u2713 Deployment stopped: ${updated.name}
4213
+ \u2713 Deployment stopped
4686
4214
  `));
4687
4215
  } catch (error) {
4688
4216
  console.error(
@@ -4703,13 +4231,11 @@ async function startDeploymentCommand(deploymentId) {
4703
4231
  );
4704
4232
  process.exit(1);
4705
4233
  }
4706
- const api = await McpUseAPI.create();
4707
- const updated = await api.updateDeployment(deploymentId, {
4708
- status: "running"
4709
- });
4710
- console.log(source_default.green.bold(`
4711
- \u2713 Deployment started: ${updated.name}
4712
- `));
4234
+ console.log(
4235
+ source_default.yellow(
4236
+ "\u26A0\uFE0F Start is not supported in this version. Use `mcp-use deployments restart` to redeploy."
4237
+ )
4238
+ );
4713
4239
  } catch (error) {
4714
4240
  console.error(
4715
4241
  source_default.red.bold("\n\u2717 Failed to start deployment:"),
@@ -4724,13 +4250,11 @@ function createDeploymentsCommand() {
4724
4250
  );
4725
4251
  deploymentsCommand.command("list").alias("ls").description("List all deployments").action(listDeploymentsCommand);
4726
4252
  deploymentsCommand.command("get").argument("<deployment-id>", "Deployment ID").description("Get deployment details").action(getDeploymentCommand);
4727
- deploymentsCommand.command("restart").argument("<deployment-id>", "Deployment ID").option("-f, --follow", "Follow deployment logs").description("Restart a deployment").action(restartDeploymentCommand);
4253
+ deploymentsCommand.command("restart").argument("<deployment-id>", "Deployment ID").option("-f, --follow", "Follow build logs").description(
4254
+ "Restart a deployment (triggers a new deployment on the same server)"
4255
+ ).action(restartDeploymentCommand);
4728
4256
  deploymentsCommand.command("delete").alias("rm").argument("<deployment-id>", "Deployment ID").option("-y, --yes", "Skip confirmation prompt").description("Delete a deployment").action(deleteDeploymentCommand);
4729
- 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);
4730
- const envCommand = deploymentsCommand.command("env").description("Manage environment variables");
4731
- envCommand.command("list").argument("<deployment-id>", "Deployment ID").description("List environment variables").action(listEnvCommand);
4732
- envCommand.command("set").argument("<deployment-id>", "Deployment ID").argument("<pairs...>", "Environment variables in KEY=VALUE format").description("Set environment variables").action(setEnvCommand);
4733
- envCommand.command("unset").argument("<deployment-id>", "Deployment ID").argument("<keys...>", "Environment variable keys to remove").description("Unset environment variables").action(unsetEnvCommand);
4257
+ 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);
4734
4258
  deploymentsCommand.command("stop").argument("<deployment-id>", "Deployment ID").description("Stop a deployment").action(stopDeploymentCommand);
4735
4259
  deploymentsCommand.command("start").argument("<deployment-id>", "Deployment ID").description("Start a stopped deployment").action(startDeploymentCommand);
4736
4260
  return deploymentsCommand;
@@ -4753,22 +4277,22 @@ async function orgListCommand() {
4753
4277
  const api = await McpUseAPI.create();
4754
4278
  const authInfo = await api.testAuth();
4755
4279
  const config = await readConfig();
4756
- const profiles = authInfo.profiles ?? [];
4757
- const activeId = config.profileId || authInfo.default_profile_id;
4758
- if (profiles.length === 0) {
4280
+ const orgs = authInfo.orgs ?? [];
4281
+ const activeId = config.orgId || authInfo.default_org_id;
4282
+ if (orgs.length === 0) {
4759
4283
  console.log(source_default.yellow("No organizations found."));
4760
4284
  return;
4761
4285
  }
4762
4286
  console.log(source_default.cyan.bold("\u{1F3E2} Your organizations:\n"));
4763
- for (const p of profiles) {
4764
- const isActive = p.id === activeId;
4287
+ for (const o of orgs) {
4288
+ const isActive = o.id === activeId;
4765
4289
  const marker = isActive ? source_default.green(" \u2190 active") : "";
4766
- const slug = p.slug ? source_default.gray(` (${p.slug})`) : "";
4767
- const role = source_default.gray(` [${p.role}]`);
4768
- const name = isActive ? source_default.cyan.bold(p.profile_name) : source_default.white(p.profile_name);
4290
+ const slug = o.slug ? source_default.gray(` (${o.slug})`) : "";
4291
+ const role = source_default.gray(` [${o.role}]`);
4292
+ const name = isActive ? source_default.cyan.bold(o.name) : source_default.white(o.name);
4769
4293
  console.log(` ${name}${slug}${role}${marker}`);
4770
4294
  }
4771
- if (profiles.length > 1) {
4295
+ if (orgs.length > 1) {
4772
4296
  console.log(
4773
4297
  source_default.gray("\nSwitch with " + source_default.white("npx mcp-use org switch"))
4774
4298
  );
@@ -4787,40 +4311,40 @@ async function orgSwitchCommand() {
4787
4311
  const api = await McpUseAPI.create();
4788
4312
  const authInfo = await api.testAuth();
4789
4313
  const config = await readConfig();
4790
- const profiles = authInfo.profiles ?? [];
4791
- if (profiles.length === 0) {
4314
+ const orgs = authInfo.orgs ?? [];
4315
+ if (orgs.length === 0) {
4792
4316
  console.log(source_default.yellow("No organizations found."));
4793
4317
  return;
4794
4318
  }
4795
- if (profiles.length === 1) {
4796
- const p = profiles[0];
4797
- const slug2 = p.slug ? source_default.gray(` (${p.slug})`) : "";
4319
+ if (orgs.length === 1) {
4320
+ const o = orgs[0];
4321
+ const slug2 = o.slug ? source_default.gray(` (${o.slug})`) : "";
4798
4322
  console.log(
4799
4323
  source_default.yellow(
4800
- `You only have one organization: ${source_default.cyan(p.profile_name)}${slug2}`
4324
+ `You only have one organization: ${source_default.cyan(o.name)}${slug2}`
4801
4325
  )
4802
4326
  );
4803
4327
  return;
4804
4328
  }
4805
- const activeId = config.profileId || authInfo.default_profile_id;
4806
- const selected = await promptOrgSelection(profiles, activeId);
4329
+ const activeId = config.orgId || authInfo.default_org_id;
4330
+ const selected = await promptOrgSelection(orgs, activeId);
4807
4331
  if (!selected) {
4808
4332
  console.log(source_default.yellow("No organization selected."));
4809
4333
  return;
4810
4334
  }
4811
4335
  await writeConfig({
4812
4336
  ...config,
4813
- profileId: selected.id,
4814
- profileName: selected.profile_name,
4815
- profileSlug: selected.slug ?? void 0
4337
+ orgId: selected.id,
4338
+ orgName: selected.name,
4339
+ orgSlug: selected.slug ?? void 0
4816
4340
  });
4817
4341
  try {
4818
- await api.setDefaultProfile(selected.id);
4342
+ await api.setDefaultOrg(selected.id);
4819
4343
  } catch {
4820
4344
  }
4821
4345
  const slug = selected.slug ? source_default.gray(` (${selected.slug})`) : "";
4822
4346
  console.log(
4823
- source_default.green.bold("\n\u2713 Switched to ") + source_default.cyan.bold(selected.profile_name) + slug
4347
+ source_default.green.bold("\n\u2713 Switched to ") + source_default.cyan.bold(selected.name) + slug
4824
4348
  );
4825
4349
  } catch (error) {
4826
4350
  console.error(
@@ -4834,7 +4358,7 @@ async function orgCurrentCommand() {
4834
4358
  try {
4835
4359
  if (!await ensureLoggedIn()) return;
4836
4360
  const config = await readConfig();
4837
- if (!config.profileId) {
4361
+ if (!config.orgId) {
4838
4362
  console.log(
4839
4363
  source_default.yellow(
4840
4364
  "No organization selected. Run " + source_default.white("npx mcp-use org switch") + " to pick one."
@@ -4842,9 +4366,9 @@ async function orgCurrentCommand() {
4842
4366
  );
4843
4367
  return;
4844
4368
  }
4845
- const slug = config.profileSlug ? source_default.gray(` (${config.profileSlug})`) : "";
4369
+ const slug = config.orgSlug ? source_default.gray(` (${config.orgSlug})`) : "";
4846
4370
  console.log(
4847
- source_default.cyan.bold("\u{1F3E2} Active organization: ") + source_default.white(config.profileName || config.profileId) + slug
4371
+ source_default.cyan.bold("\u{1F3E2} Active organization: ") + source_default.white(config.orgName || config.orgId) + slug
4848
4372
  );
4849
4373
  } catch (error) {
4850
4374
  console.error(
@@ -5169,7 +4693,7 @@ async function isPortAvailable(port, host = "localhost") {
5169
4693
  return true;
5170
4694
  }
5171
4695
  }
5172
- async function findAvailablePort2(startPort, host = "localhost") {
4696
+ async function findAvailablePort(startPort, host = "localhost") {
5173
4697
  for (let port = startPort; port < startPort + 100; port++) {
5174
4698
  if (await isPortAvailable(port, host)) {
5175
4699
  return port;
@@ -5460,7 +4984,7 @@ if (container && Component) {
5460
4984
  `${widgetName}-metadata`
5461
4985
  );
5462
4986
  await fs10.mkdir(metadataTempDir, { recursive: true });
5463
- const { createServer: createServer2 } = await import("vite");
4987
+ const { createServer } = await import("vite");
5464
4988
  const nodeStubsPlugin = {
5465
4989
  name: "node-stubs",
5466
4990
  enforce: "pre",
@@ -5487,7 +5011,7 @@ export default PostHog;
5487
5011
  return null;
5488
5012
  }
5489
5013
  };
5490
- const metadataServer = await createServer2({
5014
+ const metadataServer = await createServer({
5491
5015
  root: metadataTempDir,
5492
5016
  cacheDir: path7.join(metadataTempDir, ".vite-cache"),
5493
5017
  plugins: [nodeStubsPlugin, tailwindcss(), react()],
@@ -6052,7 +5576,7 @@ program.command("dev").description("Run development server with auto-reload and
6052
5576
  displayPackageVersions(projectPath);
6053
5577
  if (!await isPortAvailable(port, host)) {
6054
5578
  console.log(source_default.yellow.bold(`\u26A0\uFE0F Port ${port} is already in use`));
6055
- const availablePort = await findAvailablePort2(port, host);
5579
+ const availablePort = await findAvailablePort(port, host);
6056
5580
  console.log(source_default.green.bold(`\u2713 Using port ${availablePort} instead`));
6057
5581
  port = availablePort;
6058
5582
  }
@@ -6887,9 +6411,12 @@ Looked for:
6887
6411
  process.exit(1);
6888
6412
  }
6889
6413
  });
6890
- program.command("login").description("Login to Manufact cloud").action(async () => {
6414
+ program.command("login").description("Login to mcp-use cloud").option(
6415
+ "--api-key <key>",
6416
+ "Login with an API key directly (non-interactive, for CI/CD)"
6417
+ ).action(async (opts) => {
6891
6418
  try {
6892
- await loginCommand();
6419
+ await loginCommand({ apiKey: opts.apiKey });
6893
6420
  process.exit(0);
6894
6421
  } catch (error) {
6895
6422
  console.error(