@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/commands/auth.d.ts +4 -4
- package/dist/commands/auth.d.ts.map +1 -1
- package/dist/commands/deploy.d.ts +0 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deployments.d.ts +0 -3
- package/dist/commands/deployments.d.ts.map +1 -1
- package/dist/commands/org.d.ts.map +1 -1
- package/dist/index.cjs +582 -1053
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +582 -1055
- package/dist/index.js.map +1 -1
- package/dist/utils/api.d.ts +67 -155
- package/dist/utils/api.d.ts.map +1 -1
- package/dist/utils/config.d.ts +17 -5
- package/dist/utils/config.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -1150,10 +1150,6 @@ var open_default = open;
|
|
|
1150
1150
|
var import_vite_plugin_singlefile = require("vite-plugin-singlefile");
|
|
1151
1151
|
var import_zod = require("zod");
|
|
1152
1152
|
|
|
1153
|
-
// src/commands/auth.ts
|
|
1154
|
-
var import_node_crypto = __toESM(require("crypto"), 1);
|
|
1155
|
-
var import_node_http = require("http");
|
|
1156
|
-
|
|
1157
1153
|
// src/utils/config.ts
|
|
1158
1154
|
var import_node_fs4 = require("fs");
|
|
1159
1155
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
@@ -1171,14 +1167,21 @@ async function ensureConfigDir() {
|
|
|
1171
1167
|
async function readConfig() {
|
|
1172
1168
|
try {
|
|
1173
1169
|
const content = await import_node_fs4.promises.readFile(CONFIG_FILE, "utf-8");
|
|
1174
|
-
|
|
1170
|
+
const raw = JSON.parse(content);
|
|
1171
|
+
return {
|
|
1172
|
+
...raw,
|
|
1173
|
+
orgId: raw.orgId ?? raw.profileId,
|
|
1174
|
+
orgName: raw.orgName ?? raw.profileName,
|
|
1175
|
+
orgSlug: raw.orgSlug ?? raw.profileSlug
|
|
1176
|
+
};
|
|
1175
1177
|
} catch (error) {
|
|
1176
1178
|
return {};
|
|
1177
1179
|
}
|
|
1178
1180
|
}
|
|
1179
1181
|
async function writeConfig(config) {
|
|
1180
1182
|
await ensureConfigDir();
|
|
1181
|
-
|
|
1183
|
+
const { profileId: _a, profileName: _b, profileSlug: _c, ...clean } = config;
|
|
1184
|
+
await import_node_fs4.promises.writeFile(CONFIG_FILE, JSON.stringify(clean, null, 2), "utf-8");
|
|
1182
1185
|
}
|
|
1183
1186
|
async function deleteConfig() {
|
|
1184
1187
|
try {
|
|
@@ -1198,42 +1201,37 @@ async function isLoggedIn() {
|
|
|
1198
1201
|
const apiKey = await getApiKey();
|
|
1199
1202
|
return !!apiKey;
|
|
1200
1203
|
}
|
|
1201
|
-
async function
|
|
1204
|
+
async function getOrgId() {
|
|
1202
1205
|
const config = await readConfig();
|
|
1203
|
-
return config.
|
|
1206
|
+
return config.orgId || null;
|
|
1204
1207
|
}
|
|
1205
1208
|
async function getWebUrl() {
|
|
1206
1209
|
return DEFAULT_WEB_URL;
|
|
1207
1210
|
}
|
|
1211
|
+
async function getAuthBaseUrl() {
|
|
1212
|
+
const apiUrl = await getApiUrl();
|
|
1213
|
+
return apiUrl.replace(/\/api\/v1$/, "");
|
|
1214
|
+
}
|
|
1208
1215
|
|
|
1209
1216
|
// src/utils/api.ts
|
|
1210
1217
|
var McpUseAPI = class _McpUseAPI {
|
|
1211
1218
|
baseUrl;
|
|
1212
1219
|
apiKey;
|
|
1213
|
-
|
|
1214
|
-
constructor(baseUrl, apiKey,
|
|
1220
|
+
orgId;
|
|
1221
|
+
constructor(baseUrl, apiKey, orgId) {
|
|
1215
1222
|
this.baseUrl = baseUrl || "";
|
|
1216
1223
|
this.apiKey = apiKey;
|
|
1217
|
-
this.
|
|
1224
|
+
this.orgId = orgId;
|
|
1218
1225
|
}
|
|
1219
|
-
/**
|
|
1220
|
-
* Initialize API client with config
|
|
1221
|
-
*/
|
|
1222
1226
|
static async create() {
|
|
1223
1227
|
const baseUrl = await getApiUrl();
|
|
1224
1228
|
const apiKey = await getApiKey();
|
|
1225
|
-
const
|
|
1226
|
-
return new _McpUseAPI(baseUrl, apiKey ?? void 0,
|
|
1229
|
+
const orgId = await getOrgId();
|
|
1230
|
+
return new _McpUseAPI(baseUrl, apiKey ?? void 0, orgId ?? void 0);
|
|
1227
1231
|
}
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
*/
|
|
1231
|
-
setProfileId(profileId) {
|
|
1232
|
-
this.profileId = profileId;
|
|
1232
|
+
setOrgId(orgId) {
|
|
1233
|
+
this.orgId = orgId;
|
|
1233
1234
|
}
|
|
1234
|
-
/**
|
|
1235
|
-
* Make authenticated request
|
|
1236
|
-
*/
|
|
1237
1235
|
async request(endpoint, options = {}) {
|
|
1238
1236
|
const url = `${this.baseUrl}${endpoint}`;
|
|
1239
1237
|
const headers = {
|
|
@@ -1243,8 +1241,8 @@ var McpUseAPI = class _McpUseAPI {
|
|
|
1243
1241
|
if (this.apiKey) {
|
|
1244
1242
|
headers["x-api-key"] = this.apiKey;
|
|
1245
1243
|
}
|
|
1246
|
-
if (this.
|
|
1247
|
-
headers["x-profile-id"] = this.
|
|
1244
|
+
if (this.orgId) {
|
|
1245
|
+
headers["x-profile-id"] = this.orgId;
|
|
1248
1246
|
}
|
|
1249
1247
|
const timeout = options.timeout || 3e4;
|
|
1250
1248
|
const controller = new AbortController();
|
|
@@ -1256,6 +1254,13 @@ var McpUseAPI = class _McpUseAPI {
|
|
|
1256
1254
|
signal: controller.signal
|
|
1257
1255
|
});
|
|
1258
1256
|
clearTimeout(timeoutId);
|
|
1257
|
+
if (response.status === 401) {
|
|
1258
|
+
const err = new Error(
|
|
1259
|
+
"Your session has expired or your API key is invalid."
|
|
1260
|
+
);
|
|
1261
|
+
err.status = 401;
|
|
1262
|
+
throw err;
|
|
1263
|
+
}
|
|
1259
1264
|
if (!response.ok) {
|
|
1260
1265
|
const error = await response.text();
|
|
1261
1266
|
throw new Error(`API request failed: ${response.status} ${error}`);
|
|
@@ -1264,25 +1269,24 @@ var McpUseAPI = class _McpUseAPI {
|
|
|
1264
1269
|
} catch (error) {
|
|
1265
1270
|
clearTimeout(timeoutId);
|
|
1266
1271
|
if (error.name === "AbortError") {
|
|
1267
|
-
throw new Error(
|
|
1268
|
-
`Request timeout after ${timeout / 1e3}s. Try using --follow flag to stream logs instead.`
|
|
1269
|
-
);
|
|
1272
|
+
throw new Error(`Request timeout after ${timeout / 1e3}s.`);
|
|
1270
1273
|
}
|
|
1271
1274
|
throw error;
|
|
1272
1275
|
}
|
|
1273
1276
|
}
|
|
1274
1277
|
/**
|
|
1275
|
-
* Create API key using
|
|
1278
|
+
* Create a persistent API key using a Better Auth access token.
|
|
1276
1279
|
*/
|
|
1277
|
-
async
|
|
1278
|
-
const
|
|
1280
|
+
async createApiKeyWithAccessToken(accessToken, name = "CLI") {
|
|
1281
|
+
const authBase = await getAuthBaseUrl();
|
|
1282
|
+
const url = `${authBase}/api/auth/api-key/create`;
|
|
1279
1283
|
const response = await fetch(url, {
|
|
1280
1284
|
method: "POST",
|
|
1281
1285
|
headers: {
|
|
1282
1286
|
"Content-Type": "application/json",
|
|
1283
|
-
Authorization: `Bearer ${
|
|
1287
|
+
Authorization: `Bearer ${accessToken}`
|
|
1284
1288
|
},
|
|
1285
|
-
body: JSON.stringify({ name })
|
|
1289
|
+
body: JSON.stringify({ name, prefix: "mcp_" })
|
|
1286
1290
|
});
|
|
1287
1291
|
if (!response.ok) {
|
|
1288
1292
|
const error = await response.text();
|
|
@@ -1290,540 +1294,195 @@ var McpUseAPI = class _McpUseAPI {
|
|
|
1290
1294
|
}
|
|
1291
1295
|
return response.json();
|
|
1292
1296
|
}
|
|
1293
|
-
|
|
1294
|
-
* Test authentication
|
|
1295
|
-
*/
|
|
1297
|
+
// ── Auth ────────────────────────────────────────────────────────
|
|
1296
1298
|
async testAuth() {
|
|
1297
|
-
|
|
1299
|
+
const wire = await this.request("/test-auth");
|
|
1300
|
+
return {
|
|
1301
|
+
message: wire.message,
|
|
1302
|
+
user_id: wire.user_id,
|
|
1303
|
+
email: wire.email,
|
|
1304
|
+
default_org_id: wire.default_profile_id,
|
|
1305
|
+
orgs: (wire.profiles ?? []).map((p) => ({
|
|
1306
|
+
id: p.id,
|
|
1307
|
+
name: p.profile_name,
|
|
1308
|
+
slug: p.slug,
|
|
1309
|
+
role: p.role
|
|
1310
|
+
}))
|
|
1311
|
+
};
|
|
1298
1312
|
}
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
*/
|
|
1302
|
-
async setDefaultProfile(profileId) {
|
|
1303
|
-
await this.request(`/profiles/${profileId}/set-default`, {
|
|
1313
|
+
async setDefaultOrg(orgId) {
|
|
1314
|
+
await this.request(`/organizations/${orgId}/set-default`, {
|
|
1304
1315
|
method: "POST"
|
|
1305
1316
|
});
|
|
1306
1317
|
}
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1318
|
+
// ── Organization ID resolution ──────────────────────────────────
|
|
1319
|
+
async resolveOrganizationId() {
|
|
1320
|
+
if (this.orgId) return this.orgId;
|
|
1321
|
+
const auth = await this.testAuth();
|
|
1322
|
+
const id = auth.default_org_id;
|
|
1323
|
+
if (!id) {
|
|
1324
|
+
throw new Error(
|
|
1325
|
+
"No organization set. Run `mcp-use org switch` or use --org to specify one."
|
|
1326
|
+
);
|
|
1327
|
+
}
|
|
1328
|
+
return id;
|
|
1329
|
+
}
|
|
1330
|
+
// ── Servers ─────────────────────────────────────────────────────
|
|
1331
|
+
async createServer(body) {
|
|
1332
|
+
return this.request("/servers", {
|
|
1333
|
+
method: "POST",
|
|
1334
|
+
body: JSON.stringify(body)
|
|
1335
|
+
});
|
|
1336
|
+
}
|
|
1337
|
+
// ── Deployments ─────────────────────────────────────────────────
|
|
1338
|
+
async createDeployment(input) {
|
|
1311
1339
|
return this.request("/deployments", {
|
|
1312
1340
|
method: "POST",
|
|
1313
|
-
body: JSON.stringify(
|
|
1341
|
+
body: JSON.stringify(input)
|
|
1314
1342
|
});
|
|
1315
1343
|
}
|
|
1316
|
-
/**
|
|
1317
|
-
* Get deployment by ID
|
|
1318
|
-
*/
|
|
1319
1344
|
async getDeployment(deploymentId) {
|
|
1320
1345
|
return this.request(`/deployments/${deploymentId}`);
|
|
1321
1346
|
}
|
|
1322
|
-
/**
|
|
1323
|
-
* Stream deployment logs
|
|
1324
|
-
*/
|
|
1325
|
-
async *streamDeploymentLogs(deploymentId) {
|
|
1326
|
-
const url = `${this.baseUrl}/deployments/${deploymentId}/logs/stream`;
|
|
1327
|
-
const headers = {};
|
|
1328
|
-
if (this.apiKey) {
|
|
1329
|
-
headers["x-api-key"] = this.apiKey;
|
|
1330
|
-
}
|
|
1331
|
-
if (this.profileId) {
|
|
1332
|
-
headers["x-profile-id"] = this.profileId;
|
|
1333
|
-
}
|
|
1334
|
-
const response = await fetch(url, { headers });
|
|
1335
|
-
if (!response.ok) {
|
|
1336
|
-
throw new Error(`Failed to stream logs: ${response.status}`);
|
|
1337
|
-
}
|
|
1338
|
-
if (!response.body) {
|
|
1339
|
-
throw new Error("Response body is null");
|
|
1340
|
-
}
|
|
1341
|
-
const reader = response.body.getReader();
|
|
1342
|
-
const decoder = new TextDecoder();
|
|
1343
|
-
let buffer = "";
|
|
1344
|
-
try {
|
|
1345
|
-
while (true) {
|
|
1346
|
-
const { done, value } = await reader.read();
|
|
1347
|
-
if (done) break;
|
|
1348
|
-
buffer += decoder.decode(value, { stream: true });
|
|
1349
|
-
const lines = buffer.split("\n");
|
|
1350
|
-
buffer = lines.pop() || "";
|
|
1351
|
-
for (const line of lines) {
|
|
1352
|
-
if (line.startsWith("data: ")) {
|
|
1353
|
-
const data = line.slice(6);
|
|
1354
|
-
try {
|
|
1355
|
-
const parsed = JSON.parse(data);
|
|
1356
|
-
if (parsed.log) {
|
|
1357
|
-
yield parsed.log;
|
|
1358
|
-
} else if (parsed.error) {
|
|
1359
|
-
throw new Error(parsed.error);
|
|
1360
|
-
}
|
|
1361
|
-
} catch (e) {
|
|
1362
|
-
}
|
|
1363
|
-
}
|
|
1364
|
-
}
|
|
1365
|
-
}
|
|
1366
|
-
} finally {
|
|
1367
|
-
reader.releaseLock();
|
|
1368
|
-
}
|
|
1369
|
-
}
|
|
1370
|
-
/**
|
|
1371
|
-
* Create deployment with source code upload
|
|
1372
|
-
*/
|
|
1373
|
-
async createDeploymentWithUpload(request, filePath) {
|
|
1374
|
-
const { readFile: readFile4 } = await import("fs/promises");
|
|
1375
|
-
const { basename } = await import("path");
|
|
1376
|
-
const { stat } = await import("fs/promises");
|
|
1377
|
-
const stats = await stat(filePath);
|
|
1378
|
-
const maxSize = 2 * 1024 * 1024;
|
|
1379
|
-
if (stats.size > maxSize) {
|
|
1380
|
-
throw new Error(
|
|
1381
|
-
`File size (${(stats.size / 1024 / 1024).toFixed(2)}MB) exceeds maximum of 2MB`
|
|
1382
|
-
);
|
|
1383
|
-
}
|
|
1384
|
-
const fileBuffer = await readFile4(filePath);
|
|
1385
|
-
const filename = basename(filePath);
|
|
1386
|
-
const formData = new FormData();
|
|
1387
|
-
const blob = new Blob([fileBuffer], { type: "application/gzip" });
|
|
1388
|
-
formData.append("source_file", blob, filename);
|
|
1389
|
-
formData.append("name", request.name);
|
|
1390
|
-
formData.append("source_type", "upload");
|
|
1391
|
-
if (request.source.type === "upload") {
|
|
1392
|
-
formData.append("runtime", request.source.runtime || "node");
|
|
1393
|
-
formData.append("port", String(request.source.port || 3e3));
|
|
1394
|
-
if (request.source.startCommand) {
|
|
1395
|
-
formData.append("startCommand", request.source.startCommand);
|
|
1396
|
-
}
|
|
1397
|
-
if (request.source.buildCommand) {
|
|
1398
|
-
formData.append("buildCommand", request.source.buildCommand);
|
|
1399
|
-
}
|
|
1400
|
-
if (request.source.env && Object.keys(request.source.env).length > 0) {
|
|
1401
|
-
formData.append("env", JSON.stringify(request.source.env));
|
|
1402
|
-
}
|
|
1403
|
-
}
|
|
1404
|
-
if (request.customDomain) {
|
|
1405
|
-
formData.append("customDomain", request.customDomain);
|
|
1406
|
-
}
|
|
1407
|
-
if (request.healthCheckPath) {
|
|
1408
|
-
formData.append("healthCheckPath", request.healthCheckPath);
|
|
1409
|
-
}
|
|
1410
|
-
const url = `${this.baseUrl}/deployments`;
|
|
1411
|
-
const headers = {};
|
|
1412
|
-
if (this.apiKey) {
|
|
1413
|
-
headers["x-api-key"] = this.apiKey;
|
|
1414
|
-
}
|
|
1415
|
-
if (this.profileId) {
|
|
1416
|
-
headers["x-profile-id"] = this.profileId;
|
|
1417
|
-
}
|
|
1418
|
-
const response = await fetch(url, {
|
|
1419
|
-
method: "POST",
|
|
1420
|
-
headers,
|
|
1421
|
-
body: formData
|
|
1422
|
-
});
|
|
1423
|
-
if (!response.ok) {
|
|
1424
|
-
const error = await response.text();
|
|
1425
|
-
throw new Error(`Deployment failed: ${error}`);
|
|
1426
|
-
}
|
|
1427
|
-
return response.json();
|
|
1428
|
-
}
|
|
1429
|
-
/**
|
|
1430
|
-
* List all deployments
|
|
1431
|
-
*/
|
|
1432
1347
|
async listDeployments() {
|
|
1433
|
-
|
|
1434
|
-
return response.deployments;
|
|
1348
|
+
return this.request("/deployments");
|
|
1435
1349
|
}
|
|
1436
|
-
/**
|
|
1437
|
-
* Delete deployment
|
|
1438
|
-
*/
|
|
1439
1350
|
async deleteDeployment(deploymentId) {
|
|
1440
1351
|
await this.request(`/deployments/${deploymentId}`, {
|
|
1441
1352
|
method: "DELETE"
|
|
1442
1353
|
});
|
|
1443
1354
|
}
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
async updateDeployment(deploymentId, updates) {
|
|
1448
|
-
return this.request(`/deployments/${deploymentId}`, {
|
|
1449
|
-
method: "PATCH",
|
|
1450
|
-
body: JSON.stringify(updates)
|
|
1451
|
-
});
|
|
1452
|
-
}
|
|
1453
|
-
/**
|
|
1454
|
-
* Redeploy deployment
|
|
1455
|
-
*
|
|
1456
|
-
* @param deploymentId - The deployment ID to redeploy
|
|
1457
|
-
* @param configOrFilePath - Either a RedeploymentConfig object with updated settings,
|
|
1458
|
-
* or a file path string for source code upload
|
|
1459
|
-
*/
|
|
1460
|
-
async redeployDeployment(deploymentId, configOrFilePath) {
|
|
1461
|
-
if (typeof configOrFilePath === "string") {
|
|
1462
|
-
const filePath = configOrFilePath;
|
|
1463
|
-
const { readFile: readFile4 } = await import("fs/promises");
|
|
1464
|
-
const { basename } = await import("path");
|
|
1465
|
-
const { stat } = await import("fs/promises");
|
|
1466
|
-
const stats = await stat(filePath);
|
|
1467
|
-
const maxSize = 2 * 1024 * 1024;
|
|
1468
|
-
if (stats.size > maxSize) {
|
|
1469
|
-
throw new Error(
|
|
1470
|
-
`File size (${(stats.size / 1024 / 1024).toFixed(2)}MB) exceeds maximum of 2MB`
|
|
1471
|
-
);
|
|
1472
|
-
}
|
|
1473
|
-
const fileBuffer = await readFile4(filePath);
|
|
1474
|
-
const formData = new FormData();
|
|
1475
|
-
const blob = new Blob([fileBuffer], { type: "application/gzip" });
|
|
1476
|
-
formData.append("source_file", blob, basename(filePath));
|
|
1477
|
-
const headers = {};
|
|
1478
|
-
if (this.apiKey) headers["x-api-key"] = this.apiKey;
|
|
1479
|
-
if (this.profileId) headers["x-profile-id"] = this.profileId;
|
|
1480
|
-
const response = await fetch(
|
|
1481
|
-
`${this.baseUrl}/deployments/${deploymentId}/redeploy`,
|
|
1482
|
-
{
|
|
1483
|
-
method: "POST",
|
|
1484
|
-
headers,
|
|
1485
|
-
body: formData
|
|
1486
|
-
}
|
|
1487
|
-
);
|
|
1488
|
-
if (!response.ok) {
|
|
1489
|
-
const error = await response.text();
|
|
1490
|
-
throw new Error(`Redeploy failed: ${error}`);
|
|
1491
|
-
}
|
|
1492
|
-
return response.json();
|
|
1493
|
-
}
|
|
1494
|
-
const config = configOrFilePath;
|
|
1495
|
-
return this.request(`/deployments/${deploymentId}/redeploy`, {
|
|
1496
|
-
method: "POST",
|
|
1497
|
-
body: config ? JSON.stringify(config) : void 0
|
|
1355
|
+
async stopDeployment(deploymentId) {
|
|
1356
|
+
await this.request(`/deployments/${deploymentId}/stop`, {
|
|
1357
|
+
method: "POST"
|
|
1498
1358
|
});
|
|
1499
1359
|
}
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
async getDeploymentLogs(deploymentId) {
|
|
1504
|
-
const response = await this.request(
|
|
1505
|
-
`/deployments/${deploymentId}/logs`,
|
|
1360
|
+
async getDeploymentLogs(deploymentId, lines = 500) {
|
|
1361
|
+
const resp = await this.request(
|
|
1362
|
+
`/deployments/${deploymentId}/logs?lines=${lines}`,
|
|
1506
1363
|
{ timeout: 6e4 }
|
|
1507
|
-
// 60 second timeout for logs
|
|
1508
1364
|
);
|
|
1509
|
-
return
|
|
1365
|
+
return resp.logs;
|
|
1510
1366
|
}
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
async getDeploymentBuildLogs(deploymentId) {
|
|
1515
|
-
const response = await this.request(
|
|
1516
|
-
`/deployments/${deploymentId}/logs/build`,
|
|
1367
|
+
async getDeploymentBuildLogs(deploymentId, offset = 0) {
|
|
1368
|
+
return this.request(
|
|
1369
|
+
`/deployments/${deploymentId}/build-logs?offset=${offset}`,
|
|
1517
1370
|
{ timeout: 6e4 }
|
|
1518
|
-
// 60 second timeout for logs
|
|
1519
1371
|
);
|
|
1520
|
-
return response.data.logs;
|
|
1521
1372
|
}
|
|
1522
|
-
|
|
1523
|
-
* Get GitHub connection status
|
|
1524
|
-
*/
|
|
1373
|
+
// ── GitHub ──────────────────────────────────────────────────────
|
|
1525
1374
|
async getGitHubConnectionStatus() {
|
|
1526
|
-
|
|
1375
|
+
const orgId = await this.resolveOrganizationId();
|
|
1376
|
+
const resp = await this.request(`/github/installations?organizationId=${orgId}`);
|
|
1377
|
+
return {
|
|
1378
|
+
is_connected: resp.installations.length > 0,
|
|
1379
|
+
installations: resp.installations.map((i) => ({
|
|
1380
|
+
id: i.id,
|
|
1381
|
+
installation_id: i.installationId
|
|
1382
|
+
}))
|
|
1383
|
+
};
|
|
1527
1384
|
}
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1385
|
+
async getGitHubRepos(_refresh) {
|
|
1386
|
+
const orgId = await this.resolveOrganizationId();
|
|
1387
|
+
const installResp = await this.request(`/github/installations?organizationId=${orgId}`);
|
|
1388
|
+
if (installResp.installations.length === 0) {
|
|
1389
|
+
return { user: { login: "", id: 0, avatar_url: "" }, repos: [] };
|
|
1390
|
+
}
|
|
1391
|
+
const inst = installResp.installations[0];
|
|
1392
|
+
const reposResp = await this.request(`/github/installations/${inst.installationId}/repos`);
|
|
1393
|
+
return {
|
|
1394
|
+
user: {
|
|
1395
|
+
login: inst.account?.login ?? "",
|
|
1396
|
+
id: 0,
|
|
1397
|
+
avatar_url: inst.account?.avatar_url ?? ""
|
|
1398
|
+
},
|
|
1399
|
+
repos: reposResp.repos.map((r) => ({
|
|
1400
|
+
id: r.id,
|
|
1401
|
+
name: r.name,
|
|
1402
|
+
full_name: r.fullName,
|
|
1403
|
+
private: r.private,
|
|
1404
|
+
owner: { login: r.fullName.split("/")[0] ?? "" }
|
|
1405
|
+
}))
|
|
1406
|
+
};
|
|
1534
1407
|
}
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
async getGitHubRepos(refresh = false) {
|
|
1539
|
-
return this.request(
|
|
1540
|
-
`/github/repos${refresh ? "?refresh=true" : ""}`
|
|
1541
|
-
);
|
|
1408
|
+
async getGitHubAppName() {
|
|
1409
|
+
if (process.env.MCP_GITHUB_APP_NAME) return process.env.MCP_GITHUB_APP_NAME;
|
|
1410
|
+
return this.baseUrl.includes(".dev.") ? "mcp-use-dev" : "mcp-use";
|
|
1542
1411
|
}
|
|
1543
1412
|
};
|
|
1544
1413
|
|
|
1545
1414
|
// src/commands/auth.ts
|
|
1546
|
-
var
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1415
|
+
var DEVICE_CLIENT_ID = "mcp-use-cli";
|
|
1416
|
+
var DEVICE_POLL_TIMEOUT = 18e5;
|
|
1417
|
+
async function requestDeviceCode(authBaseUrl) {
|
|
1418
|
+
const url = `${authBaseUrl}/api/auth/device/code`;
|
|
1419
|
+
const response = await fetch(url, {
|
|
1420
|
+
method: "POST",
|
|
1421
|
+
headers: { "Content-Type": "application/json" },
|
|
1422
|
+
body: JSON.stringify({
|
|
1423
|
+
client_id: DEVICE_CLIENT_ID,
|
|
1424
|
+
scope: "openid profile email"
|
|
1425
|
+
})
|
|
1426
|
+
});
|
|
1427
|
+
if (!response.ok) {
|
|
1428
|
+
const error = await response.text();
|
|
1429
|
+
throw new Error(
|
|
1430
|
+
`Failed to request device code: ${response.status} ${error}`
|
|
1431
|
+
);
|
|
1563
1432
|
}
|
|
1564
|
-
|
|
1433
|
+
return response.json();
|
|
1565
1434
|
}
|
|
1566
|
-
async function
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1435
|
+
async function pollForDeviceToken(authBaseUrl, deviceCode, intervalSeconds) {
|
|
1436
|
+
let pollingInterval = intervalSeconds;
|
|
1437
|
+
const deadline = Date.now() + DEVICE_POLL_TIMEOUT;
|
|
1438
|
+
while (Date.now() < deadline) {
|
|
1439
|
+
const delayMs = pollingInterval * 1e3;
|
|
1440
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
1441
|
+
const url = `${authBaseUrl}/api/auth/device/token`;
|
|
1442
|
+
const response = await fetch(url, {
|
|
1443
|
+
method: "POST",
|
|
1444
|
+
headers: { "Content-Type": "application/json" },
|
|
1445
|
+
body: JSON.stringify({
|
|
1446
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
1447
|
+
device_code: deviceCode,
|
|
1448
|
+
client_id: DEVICE_CLIENT_ID
|
|
1449
|
+
})
|
|
1571
1450
|
});
|
|
1572
|
-
const
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
(
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
body {
|
|
1592
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
1593
|
-
display: flex;
|
|
1594
|
-
justify-content: center;
|
|
1595
|
-
align-items: center;
|
|
1596
|
-
min-height: 100vh;
|
|
1597
|
-
background: #000;
|
|
1598
|
-
padding: 1rem;
|
|
1599
|
-
margin: 0;
|
|
1600
|
-
}
|
|
1601
|
-
.container {
|
|
1602
|
-
max-width: 28rem;
|
|
1603
|
-
padding: 3rem;
|
|
1604
|
-
text-align: center;
|
|
1605
|
-
background: rgba(255, 255, 255, 0.1);
|
|
1606
|
-
backdrop-filter: blur(40px);
|
|
1607
|
-
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
1608
|
-
border-radius: 1.5rem;
|
|
1609
|
-
}
|
|
1610
|
-
h1 { color: #fff; font-size: 2rem; margin-bottom: 1rem; }
|
|
1611
|
-
p { color: rgba(255, 255, 255, 0.8); font-size: 1rem; }
|
|
1612
|
-
</style>
|
|
1613
|
-
</head>
|
|
1614
|
-
<body>
|
|
1615
|
-
<div class="container">
|
|
1616
|
-
<h1>Security Error</h1>
|
|
1617
|
-
<p>Invalid state parameter. Please try logging in again.</p>
|
|
1618
|
-
</div>
|
|
1619
|
-
</body>
|
|
1620
|
-
</html>
|
|
1621
|
-
`);
|
|
1622
|
-
return;
|
|
1623
|
-
}
|
|
1624
|
-
if (token && tokenResolver) {
|
|
1625
|
-
res.writeHead(200, { "Content-Type": "text/html" });
|
|
1626
|
-
res.end(`
|
|
1627
|
-
<!DOCTYPE html>
|
|
1628
|
-
<html>
|
|
1629
|
-
<head>
|
|
1630
|
-
<title>Login Successful</title>
|
|
1631
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1632
|
-
<style>
|
|
1633
|
-
* {
|
|
1634
|
-
margin: 0;
|
|
1635
|
-
padding: 0;
|
|
1636
|
-
box-sizing: border-box;
|
|
1637
|
-
}
|
|
1638
|
-
body {
|
|
1639
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
1640
|
-
display: flex;
|
|
1641
|
-
justify-content: center;
|
|
1642
|
-
align-items: center;
|
|
1643
|
-
min-height: 100vh;
|
|
1644
|
-
background: #000;
|
|
1645
|
-
padding: 1rem;
|
|
1646
|
-
}
|
|
1647
|
-
.container {
|
|
1648
|
-
width: 100%;
|
|
1649
|
-
max-width: 28rem;
|
|
1650
|
-
padding: 3rem;
|
|
1651
|
-
text-align: center;
|
|
1652
|
-
-webkit-backdrop-filter: blur(40px);
|
|
1653
|
-
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
1654
|
-
border-radius: 1.5rem;
|
|
1655
|
-
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
|
|
1656
|
-
}
|
|
1657
|
-
.icon-container {
|
|
1658
|
-
display: inline-flex;
|
|
1659
|
-
align-items: center;
|
|
1660
|
-
justify-content: center;
|
|
1661
|
-
width: 6rem;
|
|
1662
|
-
height: 6rem;
|
|
1663
|
-
margin-bottom: 2rem;
|
|
1664
|
-
background: rgba(255, 255, 255, 0.1);
|
|
1665
|
-
backdrop-filter: blur(10px);
|
|
1666
|
-
-webkit-backdrop-filter: blur(10px);
|
|
1667
|
-
border-radius: 50%;
|
|
1668
|
-
}
|
|
1669
|
-
.checkmark {
|
|
1670
|
-
font-size: 4rem;
|
|
1671
|
-
color: #fff;
|
|
1672
|
-
line-height: 1;
|
|
1673
|
-
animation: scaleIn 0.5s ease-out;
|
|
1674
|
-
}
|
|
1675
|
-
@keyframes scaleIn {
|
|
1676
|
-
from {
|
|
1677
|
-
transform: scale(0);
|
|
1678
|
-
opacity: 0;
|
|
1679
|
-
}
|
|
1680
|
-
to {
|
|
1681
|
-
transform: scale(1);
|
|
1682
|
-
opacity: 1;
|
|
1683
|
-
}
|
|
1684
|
-
}
|
|
1685
|
-
h1 {
|
|
1686
|
-
color: #fff;
|
|
1687
|
-
margin: 0 0 1rem 0;
|
|
1688
|
-
font-size: 2.5rem;
|
|
1689
|
-
font-weight: 700;
|
|
1690
|
-
letter-spacing: -0.025em;
|
|
1691
|
-
}
|
|
1692
|
-
p {
|
|
1693
|
-
color: rgba(255, 255, 255, 0.8);
|
|
1694
|
-
margin: 0 0 2rem 0;
|
|
1695
|
-
font-size: 1.125rem;
|
|
1696
|
-
line-height: 1.5;
|
|
1697
|
-
}
|
|
1698
|
-
.spinner {
|
|
1699
|
-
display: inline-block;
|
|
1700
|
-
width: 2rem;
|
|
1701
|
-
height: 2rem;
|
|
1702
|
-
border: 3px solid rgba(255, 255, 255, 0.3);
|
|
1703
|
-
border-top-color: #fff;
|
|
1704
|
-
border-radius: 50%;
|
|
1705
|
-
animation: spin 0.8s linear infinite;
|
|
1706
|
-
}
|
|
1707
|
-
@keyframes spin {
|
|
1708
|
-
to { transform: rotate(360deg); }
|
|
1709
|
-
}
|
|
1710
|
-
.footer {
|
|
1711
|
-
margin-top: 2rem;
|
|
1712
|
-
color: rgba(255, 255, 255, 0.6);
|
|
1713
|
-
font-size: 0.875rem;
|
|
1714
|
-
}
|
|
1715
|
-
</style>
|
|
1716
|
-
</head>
|
|
1717
|
-
<body>
|
|
1718
|
-
<div class="container">
|
|
1719
|
-
<h1>Authentication Successful!</h1>
|
|
1720
|
-
<p>You can now close this window and return to the CLI.</p>
|
|
1721
|
-
</div>
|
|
1722
|
-
</body>
|
|
1723
|
-
</html>
|
|
1724
|
-
`);
|
|
1725
|
-
tokenResolver(token);
|
|
1726
|
-
} else {
|
|
1727
|
-
res.writeHead(400, { "Content-Type": "text/html" });
|
|
1728
|
-
res.end(`
|
|
1729
|
-
<!DOCTYPE html>
|
|
1730
|
-
<html>
|
|
1731
|
-
<head>
|
|
1732
|
-
<title>Login Failed</title>
|
|
1733
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1734
|
-
<style>
|
|
1735
|
-
* {
|
|
1736
|
-
margin: 0;
|
|
1737
|
-
padding: 0;
|
|
1738
|
-
box-sizing: border-box;
|
|
1739
|
-
}
|
|
1740
|
-
body {
|
|
1741
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
1742
|
-
display: flex;
|
|
1743
|
-
justify-content: center;
|
|
1744
|
-
align-items: center;
|
|
1745
|
-
min-height: 100vh;
|
|
1746
|
-
background: #000;
|
|
1747
|
-
padding: 1rem;
|
|
1748
|
-
}
|
|
1749
|
-
.container {
|
|
1750
|
-
width: 100%;
|
|
1751
|
-
max-width: 28rem;
|
|
1752
|
-
padding: 3rem;
|
|
1753
|
-
text-align: center;
|
|
1754
|
-
background: rgba(255, 255, 255, 0.1);
|
|
1755
|
-
backdrop-filter: blur(40px);
|
|
1756
|
-
-webkit-backdrop-filter: blur(40px);
|
|
1757
|
-
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
1758
|
-
border-radius: 1.5rem;
|
|
1759
|
-
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
|
|
1760
|
-
}
|
|
1761
|
-
.icon-container {
|
|
1762
|
-
display: inline-flex;
|
|
1763
|
-
align-items: center;
|
|
1764
|
-
justify-content: center;
|
|
1765
|
-
width: 6rem;
|
|
1766
|
-
height: 6rem;
|
|
1767
|
-
margin-bottom: 2rem;
|
|
1768
|
-
background: rgba(255, 255, 255, 0.1);
|
|
1769
|
-
backdrop-filter: blur(10px);
|
|
1770
|
-
-webkit-backdrop-filter: blur(10px);
|
|
1771
|
-
border-radius: 50%;
|
|
1772
|
-
}
|
|
1773
|
-
.cross {
|
|
1774
|
-
font-size: 4rem;
|
|
1775
|
-
color: #fff;
|
|
1776
|
-
line-height: 1;
|
|
1777
|
-
}
|
|
1778
|
-
h1 {
|
|
1779
|
-
color: #fff;
|
|
1780
|
-
margin: 0 0 1rem 0;
|
|
1781
|
-
font-size: 2.5rem;
|
|
1782
|
-
font-weight: 700;
|
|
1783
|
-
letter-spacing: -0.025em;
|
|
1784
|
-
}
|
|
1785
|
-
p {
|
|
1786
|
-
color: rgba(255, 255, 255, 0.8);
|
|
1787
|
-
margin: 0;
|
|
1788
|
-
font-size: 1.125rem;
|
|
1789
|
-
line-height: 1.5;
|
|
1790
|
-
}
|
|
1791
|
-
</style>
|
|
1792
|
-
</head>
|
|
1793
|
-
<body>
|
|
1794
|
-
<div class="container">
|
|
1795
|
-
<div class="icon-container">
|
|
1796
|
-
<div class="cross">\u2717</div>
|
|
1797
|
-
</div>
|
|
1798
|
-
<h1>Login Failed</h1>
|
|
1799
|
-
<p>No token received. Please try again.</p>
|
|
1800
|
-
</div>
|
|
1801
|
-
</body>
|
|
1802
|
-
</html>
|
|
1803
|
-
`);
|
|
1804
|
-
}
|
|
1805
|
-
}
|
|
1451
|
+
const data = await response.json();
|
|
1452
|
+
if (data.access_token) {
|
|
1453
|
+
return data.access_token;
|
|
1454
|
+
}
|
|
1455
|
+
if (data.error) {
|
|
1456
|
+
switch (data.error) {
|
|
1457
|
+
case "authorization_pending":
|
|
1458
|
+
break;
|
|
1459
|
+
case "slow_down":
|
|
1460
|
+
pollingInterval += 5;
|
|
1461
|
+
break;
|
|
1462
|
+
case "access_denied":
|
|
1463
|
+
throw new Error("Authorization was denied by the user.");
|
|
1464
|
+
case "expired_token":
|
|
1465
|
+
throw new Error("The device code has expired. Please try again.");
|
|
1466
|
+
default:
|
|
1467
|
+
throw new Error(
|
|
1468
|
+
data.error_description || `Device auth error: ${data.error}`
|
|
1469
|
+
);
|
|
1806
1470
|
}
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
});
|
|
1811
|
-
server.on("error", reject);
|
|
1812
|
-
});
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
throw new Error("Login timed out. Please try again.");
|
|
1813
1474
|
}
|
|
1814
|
-
async function promptOrgSelection(
|
|
1815
|
-
if (
|
|
1816
|
-
if (
|
|
1817
|
-
return
|
|
1475
|
+
async function promptOrgSelection(orgs, defaultOrgId) {
|
|
1476
|
+
if (orgs.length === 0) return null;
|
|
1477
|
+
if (orgs.length === 1) {
|
|
1478
|
+
return orgs[0];
|
|
1818
1479
|
}
|
|
1819
1480
|
console.log(source_default.cyan.bold("\n\u{1F3E2} Select an organization:\n"));
|
|
1820
|
-
for (let i = 0; i <
|
|
1821
|
-
const
|
|
1822
|
-
const marker =
|
|
1823
|
-
const slug =
|
|
1824
|
-
console.log(
|
|
1825
|
-
` ${source_default.white(`${i + 1}.`)} ${p.profile_name}${slug}${marker}`
|
|
1826
|
-
);
|
|
1481
|
+
for (let i = 0; i < orgs.length; i++) {
|
|
1482
|
+
const o = orgs[i];
|
|
1483
|
+
const marker = o.id === defaultOrgId ? source_default.green(" (current)") : "";
|
|
1484
|
+
const slug = o.slug ? source_default.gray(` (${o.slug})`) : "";
|
|
1485
|
+
console.log(` ${source_default.white(`${i + 1}.`)} ${o.name}${slug}${marker}`);
|
|
1827
1486
|
}
|
|
1828
1487
|
const readline = await import("readline");
|
|
1829
1488
|
const rl = readline.createInterface({
|
|
@@ -1831,7 +1490,7 @@ async function promptOrgSelection(profiles, defaultProfileId) {
|
|
|
1831
1490
|
output: process.stdout
|
|
1832
1491
|
});
|
|
1833
1492
|
return new Promise((resolve2) => {
|
|
1834
|
-
const defaultIdx =
|
|
1493
|
+
const defaultIdx = defaultOrgId ? orgs.findIndex((o) => o.id === defaultOrgId) : 0;
|
|
1835
1494
|
const defaultDisplay = defaultIdx >= 0 ? defaultIdx + 1 : 1;
|
|
1836
1495
|
rl.question(
|
|
1837
1496
|
source_default.gray(`
|
|
@@ -1840,11 +1499,11 @@ Enter number [${defaultDisplay}]: `),
|
|
|
1840
1499
|
rl.close();
|
|
1841
1500
|
const trimmed = answer.trim();
|
|
1842
1501
|
const idx = trimmed === "" ? defaultIdx : parseInt(trimmed, 10) - 1;
|
|
1843
|
-
if (idx >= 0 && idx <
|
|
1844
|
-
resolve2(
|
|
1502
|
+
if (idx >= 0 && idx < orgs.length) {
|
|
1503
|
+
resolve2(orgs[idx]);
|
|
1845
1504
|
} else {
|
|
1846
1505
|
console.log(source_default.yellow("Invalid selection, using default."));
|
|
1847
|
-
resolve2(
|
|
1506
|
+
resolve2(orgs[defaultIdx >= 0 ? defaultIdx : 0]);
|
|
1848
1507
|
}
|
|
1849
1508
|
}
|
|
1850
1509
|
);
|
|
@@ -1852,105 +1511,114 @@ Enter number [${defaultDisplay}]: `),
|
|
|
1852
1511
|
}
|
|
1853
1512
|
async function loginCommand(options) {
|
|
1854
1513
|
try {
|
|
1514
|
+
const directKey = options?.apiKey || process.env.MCP_USE_API_KEY;
|
|
1515
|
+
if (directKey) {
|
|
1516
|
+
await writeConfig({ apiKey: directKey });
|
|
1517
|
+
if (!options?.silent) {
|
|
1518
|
+
console.log(source_default.green.bold("\u2713 API key saved."));
|
|
1519
|
+
try {
|
|
1520
|
+
const api2 = await McpUseAPI.create();
|
|
1521
|
+
const authInfo = await api2.testAuth();
|
|
1522
|
+
console.log(source_default.gray(` Authenticated as ${authInfo.email}`));
|
|
1523
|
+
} catch {
|
|
1524
|
+
console.log(
|
|
1525
|
+
source_default.gray(
|
|
1526
|
+
" (could not verify key \u2014 will be checked on next command)"
|
|
1527
|
+
)
|
|
1528
|
+
);
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
return;
|
|
1532
|
+
}
|
|
1855
1533
|
if (await isLoggedIn()) {
|
|
1856
1534
|
if (!options?.silent) {
|
|
1857
1535
|
console.log(
|
|
1858
1536
|
source_default.yellow(
|
|
1859
|
-
"
|
|
1537
|
+
"You are already logged in. Run 'npx mcp-use logout' first if you want to login with a different account."
|
|
1860
1538
|
)
|
|
1861
1539
|
);
|
|
1862
1540
|
}
|
|
1863
1541
|
return;
|
|
1864
1542
|
}
|
|
1865
|
-
console.log(source_default.cyan.bold("
|
|
1866
|
-
const
|
|
1867
|
-
const
|
|
1868
|
-
const
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
source_default.gray("
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
)
|
|
1891
|
-
)
|
|
1892
|
-
]);
|
|
1893
|
-
server.close();
|
|
1894
|
-
console.log(
|
|
1895
|
-
source_default.gray("Received authentication token, creating API key...")
|
|
1543
|
+
console.log(source_default.cyan.bold("Logging in to mcp-use cloud...\n"));
|
|
1544
|
+
const authBaseUrl = await getAuthBaseUrl();
|
|
1545
|
+
const deviceResp = await requestDeviceCode(authBaseUrl);
|
|
1546
|
+
const {
|
|
1547
|
+
device_code,
|
|
1548
|
+
user_code,
|
|
1549
|
+
verification_uri,
|
|
1550
|
+
verification_uri_complete,
|
|
1551
|
+
interval
|
|
1552
|
+
} = deviceResp;
|
|
1553
|
+
const displayCode = user_code.length === 8 ? `${user_code.slice(0, 4)}-${user_code.slice(4)}` : user_code;
|
|
1554
|
+
console.log(source_default.white(" Visit: ") + source_default.cyan(verification_uri));
|
|
1555
|
+
console.log(source_default.white(" Code: ") + source_default.bold.white(displayCode));
|
|
1556
|
+
console.log();
|
|
1557
|
+
const urlToOpen = verification_uri_complete || verification_uri;
|
|
1558
|
+
try {
|
|
1559
|
+
await open_default(urlToOpen);
|
|
1560
|
+
console.log(source_default.gray(" Browser opened. Waiting for approval..."));
|
|
1561
|
+
} catch {
|
|
1562
|
+
console.log(source_default.gray(" Open the URL above in your browser."));
|
|
1563
|
+
}
|
|
1564
|
+
const accessToken = await pollForDeviceToken(
|
|
1565
|
+
authBaseUrl,
|
|
1566
|
+
device_code,
|
|
1567
|
+
interval || 5
|
|
1896
1568
|
);
|
|
1569
|
+
console.log(source_default.gray("\n Creating persistent API key..."));
|
|
1897
1570
|
const api = await McpUseAPI.create();
|
|
1898
|
-
const
|
|
1899
|
-
await writeConfig({
|
|
1900
|
-
apiKey: apiKeyResponse.api_key
|
|
1901
|
-
});
|
|
1571
|
+
const keyResp = await api.createApiKeyWithAccessToken(accessToken, "CLI");
|
|
1572
|
+
await writeConfig({ apiKey: keyResp.key });
|
|
1902
1573
|
console.log(source_default.green.bold("\n\u2713 Successfully logged in!"));
|
|
1903
1574
|
try {
|
|
1904
|
-
const
|
|
1905
|
-
const authInfo = await
|
|
1906
|
-
console.log(source_default.cyan.bold("\
|
|
1907
|
-
console.log(source_default.white("Email: ") + source_default.cyan(authInfo.email));
|
|
1908
|
-
console.log(source_default.white("User ID: ") + source_default.gray(authInfo.user_id));
|
|
1909
|
-
const
|
|
1910
|
-
if (
|
|
1911
|
-
const masked =
|
|
1912
|
-
console.log(source_default.white("API Key: ") + source_default.gray(masked));
|
|
1913
|
-
}
|
|
1914
|
-
const
|
|
1915
|
-
if (
|
|
1916
|
-
let
|
|
1917
|
-
if (
|
|
1918
|
-
|
|
1575
|
+
const freshApi = await McpUseAPI.create();
|
|
1576
|
+
const authInfo = await freshApi.testAuth();
|
|
1577
|
+
console.log(source_default.cyan.bold("\nCurrent user:\n"));
|
|
1578
|
+
console.log(source_default.white(" Email: ") + source_default.cyan(authInfo.email));
|
|
1579
|
+
console.log(source_default.white(" User ID: ") + source_default.gray(authInfo.user_id));
|
|
1580
|
+
const storedKey = await getApiKey();
|
|
1581
|
+
if (storedKey) {
|
|
1582
|
+
const masked = storedKey.substring(0, 8) + "...";
|
|
1583
|
+
console.log(source_default.white(" API Key: ") + source_default.gray(masked));
|
|
1584
|
+
}
|
|
1585
|
+
const orgs = authInfo.orgs ?? [];
|
|
1586
|
+
if (orgs.length > 0) {
|
|
1587
|
+
let selectedOrg = null;
|
|
1588
|
+
if (orgs.length === 1) {
|
|
1589
|
+
selectedOrg = orgs[0];
|
|
1919
1590
|
} else {
|
|
1920
|
-
|
|
1921
|
-
profiles,
|
|
1922
|
-
authInfo.default_profile_id
|
|
1923
|
-
);
|
|
1591
|
+
selectedOrg = await promptOrgSelection(orgs, authInfo.default_org_id);
|
|
1924
1592
|
}
|
|
1925
|
-
if (
|
|
1593
|
+
if (selectedOrg) {
|
|
1926
1594
|
const config = await readConfig();
|
|
1927
1595
|
await writeConfig({
|
|
1928
1596
|
...config,
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1597
|
+
orgId: selectedOrg.id,
|
|
1598
|
+
orgName: selectedOrg.name,
|
|
1599
|
+
orgSlug: selectedOrg.slug ?? void 0
|
|
1932
1600
|
});
|
|
1933
|
-
const slug =
|
|
1601
|
+
const slug = selectedOrg.slug ? source_default.gray(` (${selectedOrg.slug})`) : "";
|
|
1934
1602
|
console.log(
|
|
1935
|
-
source_default.white("Org: ") + source_default.cyan(
|
|
1603
|
+
source_default.white(" Org: ") + source_default.cyan(selectedOrg.name) + slug
|
|
1936
1604
|
);
|
|
1937
1605
|
}
|
|
1938
1606
|
}
|
|
1939
|
-
} catch
|
|
1607
|
+
} catch {
|
|
1940
1608
|
console.log(
|
|
1941
1609
|
source_default.gray(
|
|
1942
1610
|
`
|
|
1943
|
-
Your API key has been saved to ${source_default.white("~/.mcp-use/config.json")}`
|
|
1611
|
+
Your API key has been saved to ${source_default.white("~/.mcp-use/config.json")}`
|
|
1944
1612
|
)
|
|
1945
1613
|
);
|
|
1946
1614
|
}
|
|
1947
1615
|
console.log(
|
|
1948
1616
|
source_default.gray(
|
|
1949
|
-
"\
|
|
1617
|
+
"\n Deploy your MCP servers with " + source_default.white("npx mcp-use deploy")
|
|
1950
1618
|
)
|
|
1951
1619
|
);
|
|
1952
1620
|
console.log(
|
|
1953
|
-
source_default.gray("To logout
|
|
1621
|
+
source_default.gray(" To logout, run " + source_default.white("npx mcp-use logout"))
|
|
1954
1622
|
);
|
|
1955
1623
|
} catch (error) {
|
|
1956
1624
|
throw new Error(
|
|
@@ -2002,31 +1670,41 @@ async function whoamiCommand() {
|
|
|
2002
1670
|
console.log(source_default.white("API Key: ") + source_default.gray(masked));
|
|
2003
1671
|
}
|
|
2004
1672
|
const config = await readConfig();
|
|
2005
|
-
const
|
|
2006
|
-
if (
|
|
2007
|
-
const
|
|
2008
|
-
(
|
|
1673
|
+
const orgs = authInfo.orgs ?? [];
|
|
1674
|
+
if (orgs.length > 0) {
|
|
1675
|
+
const activeOrg = orgs.find(
|
|
1676
|
+
(o) => o.id === (config.orgId || authInfo.default_org_id)
|
|
2009
1677
|
);
|
|
2010
|
-
if (
|
|
2011
|
-
const slug =
|
|
1678
|
+
if (activeOrg) {
|
|
1679
|
+
const slug = activeOrg.slug ? source_default.gray(` (${activeOrg.slug})`) : "";
|
|
2012
1680
|
console.log(
|
|
2013
|
-
source_default.white("Org: ") + source_default.cyan(
|
|
1681
|
+
source_default.white("Org: ") + source_default.cyan(activeOrg.name) + slug
|
|
2014
1682
|
);
|
|
2015
1683
|
}
|
|
2016
|
-
if (
|
|
1684
|
+
if (orgs.length > 1) {
|
|
2017
1685
|
console.log(
|
|
2018
1686
|
source_default.gray(
|
|
2019
1687
|
`
|
|
2020
|
-
${
|
|
1688
|
+
${orgs.length} organizations available. Use ` + source_default.white("npx mcp-use org list") + " to see all."
|
|
2021
1689
|
)
|
|
2022
1690
|
);
|
|
2023
1691
|
}
|
|
2024
1692
|
}
|
|
2025
1693
|
} catch (error) {
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
1694
|
+
if (error?.status === 401) {
|
|
1695
|
+
console.error(
|
|
1696
|
+
source_default.red("\nYour session has expired or your API key is invalid.")
|
|
1697
|
+
);
|
|
1698
|
+
console.log(
|
|
1699
|
+
source_default.gray(`Run ${source_default.white("mcp-use login")} to re-authenticate.
|
|
1700
|
+
`)
|
|
1701
|
+
);
|
|
1702
|
+
} else {
|
|
1703
|
+
console.error(
|
|
1704
|
+
source_default.red.bold("\n\u2717 Failed to get user info:"),
|
|
1705
|
+
source_default.red(error instanceof Error ? error.message : "Unknown error")
|
|
1706
|
+
);
|
|
1707
|
+
}
|
|
2030
1708
|
process.exit(1);
|
|
2031
1709
|
}
|
|
2032
1710
|
}
|
|
@@ -3402,25 +3080,20 @@ async function prompt(question, defaultValue = "n") {
|
|
|
3402
3080
|
});
|
|
3403
3081
|
}
|
|
3404
3082
|
function getMcpServerUrl(deployment) {
|
|
3405
|
-
if (deployment.
|
|
3406
|
-
return
|
|
3407
|
-
}
|
|
3408
|
-
|
|
3409
|
-
} else if (deployment.serverId) {
|
|
3083
|
+
if (deployment.mcpUrl) {
|
|
3084
|
+
return deployment.mcpUrl;
|
|
3085
|
+
}
|
|
3086
|
+
if (deployment.serverId) {
|
|
3410
3087
|
return buildGatewayUrl(deployment.serverId);
|
|
3411
|
-
} else {
|
|
3412
|
-
return `https://${deployment.domain}/mcp`;
|
|
3413
3088
|
}
|
|
3089
|
+
return "";
|
|
3414
3090
|
}
|
|
3415
|
-
async function displayDeploymentProgress(api,
|
|
3091
|
+
async function displayDeploymentProgress(api, deploymentId, progressOptions) {
|
|
3416
3092
|
const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
3417
3093
|
let frameIndex = 0;
|
|
3418
3094
|
let spinnerInterval = null;
|
|
3419
|
-
let lastStep = "";
|
|
3420
3095
|
const startSpinner = (message) => {
|
|
3421
|
-
if (spinnerInterval)
|
|
3422
|
-
clearInterval(spinnerInterval);
|
|
3423
|
-
}
|
|
3096
|
+
if (spinnerInterval) clearInterval(spinnerInterval);
|
|
3424
3097
|
process.stdout.write("\r\x1B[K");
|
|
3425
3098
|
spinnerInterval = setInterval(() => {
|
|
3426
3099
|
const frame = frames[frameIndex];
|
|
@@ -3439,82 +3112,64 @@ async function displayDeploymentProgress(api, deployment, progressOptions) {
|
|
|
3439
3112
|
};
|
|
3440
3113
|
console.log();
|
|
3441
3114
|
startSpinner("Deploying...");
|
|
3442
|
-
try {
|
|
3443
|
-
for await (const log of api.streamDeploymentLogs(deployment.id)) {
|
|
3444
|
-
try {
|
|
3445
|
-
const logData = JSON.parse(log);
|
|
3446
|
-
if (logData.step && logData.step !== lastStep) {
|
|
3447
|
-
lastStep = logData.step;
|
|
3448
|
-
const stepMessages = {
|
|
3449
|
-
clone: "Preparing source code...",
|
|
3450
|
-
analyze: "Analyzing project...",
|
|
3451
|
-
build: "Building container image...",
|
|
3452
|
-
deploy: "Deploying to cloud..."
|
|
3453
|
-
};
|
|
3454
|
-
const message = stepMessages[logData.step] || "Deploying...";
|
|
3455
|
-
startSpinner(message);
|
|
3456
|
-
}
|
|
3457
|
-
if (logData.line) {
|
|
3458
|
-
stopSpinner();
|
|
3459
|
-
const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
|
|
3460
|
-
const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
|
|
3461
|
-
console.log(stepPrefix + levelColor(logData.line));
|
|
3462
|
-
}
|
|
3463
|
-
} catch {
|
|
3464
|
-
}
|
|
3465
|
-
}
|
|
3466
|
-
} catch (error) {
|
|
3467
|
-
stopSpinner();
|
|
3468
|
-
}
|
|
3469
3115
|
let checkCount = 0;
|
|
3470
|
-
const maxChecks =
|
|
3471
|
-
let delay =
|
|
3116
|
+
const maxChecks = 120;
|
|
3117
|
+
let delay = 2e3;
|
|
3472
3118
|
const maxDelay = 1e4;
|
|
3473
|
-
let
|
|
3119
|
+
let buildLogOffset = 0;
|
|
3120
|
+
const sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
3474
3121
|
while (checkCount < maxChecks) {
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3122
|
+
await sleep(delay);
|
|
3123
|
+
checkCount++;
|
|
3124
|
+
try {
|
|
3125
|
+
const buildLogsResp = await api.getDeploymentBuildLogs(
|
|
3126
|
+
deploymentId,
|
|
3127
|
+
buildLogOffset
|
|
3481
3128
|
);
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3129
|
+
if (buildLogsResp.logs.length > 0) {
|
|
3130
|
+
const logLines = buildLogsResp.logs.split("\n").filter((l) => l.trim());
|
|
3131
|
+
for (const line of logLines) {
|
|
3132
|
+
try {
|
|
3133
|
+
const logData = JSON.parse(line);
|
|
3134
|
+
if (logData.line) {
|
|
3135
|
+
stopSpinner();
|
|
3136
|
+
const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
|
|
3137
|
+
const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
|
|
3138
|
+
console.log(stepPrefix + levelColor(logData.line));
|
|
3139
|
+
}
|
|
3140
|
+
} catch {
|
|
3487
3141
|
stopSpinner();
|
|
3488
|
-
|
|
3489
|
-
const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
|
|
3490
|
-
console.log(stepPrefix + levelColor(logData.line));
|
|
3142
|
+
console.log(source_default.gray(line));
|
|
3491
3143
|
}
|
|
3492
|
-
} catch {
|
|
3493
3144
|
}
|
|
3145
|
+
buildLogOffset = buildLogsResp.offset;
|
|
3494
3146
|
}
|
|
3495
|
-
|
|
3147
|
+
} catch {
|
|
3496
3148
|
}
|
|
3497
|
-
|
|
3498
|
-
|
|
3149
|
+
const deployment = await api.getDeployment(deploymentId);
|
|
3150
|
+
if (deployment.status === "running") {
|
|
3151
|
+
stopSpinner();
|
|
3152
|
+
const mcpServerUrl = getMcpServerUrl(deployment);
|
|
3499
3153
|
let dashboardUrl = null;
|
|
3500
3154
|
const webUrl = (await getWebUrl()).replace(/\/$/, "");
|
|
3501
3155
|
const config = await readConfig();
|
|
3502
|
-
const orgSlug = config.
|
|
3503
|
-
|
|
3504
|
-
if (serverRef) {
|
|
3156
|
+
const orgSlug = config.orgSlug;
|
|
3157
|
+
if (deployment.serverId) {
|
|
3505
3158
|
if (orgSlug) {
|
|
3506
|
-
dashboardUrl = `${webUrl}/cloud/${orgSlug}/servers/${
|
|
3159
|
+
dashboardUrl = `${webUrl}/cloud/${orgSlug}/servers/${deployment.serverId}`;
|
|
3507
3160
|
} else {
|
|
3508
|
-
dashboardUrl = `${webUrl}/cloud/servers/${
|
|
3161
|
+
dashboardUrl = `${webUrl}/cloud/servers/${deployment.serverId}`;
|
|
3509
3162
|
}
|
|
3510
3163
|
}
|
|
3511
3164
|
const inspectorUrl = `https://inspector.manufact.com/inspector?autoConnect=${encodeURIComponent(
|
|
3512
3165
|
mcpServerUrl
|
|
3513
3166
|
)}`;
|
|
3514
3167
|
console.log(source_default.green.bold("\u2713 Deployment successful!\n"));
|
|
3515
|
-
|
|
3516
|
-
|
|
3168
|
+
if (mcpServerUrl) {
|
|
3169
|
+
console.log(source_default.white("\u{1F310} MCP Server URL:"));
|
|
3170
|
+
console.log(source_default.cyan.bold(` ${mcpServerUrl}
|
|
3517
3171
|
`));
|
|
3172
|
+
}
|
|
3518
3173
|
if (dashboardUrl) {
|
|
3519
3174
|
console.log(source_default.white("\u{1F4CA} Dashboard:"));
|
|
3520
3175
|
console.log(source_default.cyan.bold(` ${dashboardUrl}
|
|
@@ -3523,16 +3178,14 @@ async function displayDeploymentProgress(api, deployment, progressOptions) {
|
|
|
3523
3178
|
console.log(source_default.white("\u{1F50D} Inspector URL:"));
|
|
3524
3179
|
console.log(source_default.cyan.bold(` ${inspectorUrl}
|
|
3525
3180
|
`));
|
|
3526
|
-
console.log(
|
|
3527
|
-
source_default.gray("Deployment ID: ") + source_default.white(finalDeployment.id)
|
|
3528
|
-
);
|
|
3181
|
+
console.log(source_default.gray("Deployment ID: ") + source_default.white(deployment.id));
|
|
3529
3182
|
return;
|
|
3530
|
-
} else if (
|
|
3183
|
+
} else if (deployment.status === "failed") {
|
|
3531
3184
|
stopSpinner();
|
|
3532
3185
|
console.log(source_default.red.bold("\u2717 Deployment failed\n"));
|
|
3533
|
-
if (
|
|
3534
|
-
console.log(source_default.red("Error: ") +
|
|
3535
|
-
if (
|
|
3186
|
+
if (deployment.error) {
|
|
3187
|
+
console.log(source_default.red("Error: ") + deployment.error);
|
|
3188
|
+
if (deployment.error.includes("No GitHub installations found")) {
|
|
3536
3189
|
console.log();
|
|
3537
3190
|
const retry = await promptGitHubInstallation(
|
|
3538
3191
|
api,
|
|
@@ -3540,79 +3193,31 @@ async function displayDeploymentProgress(api, deployment, progressOptions) {
|
|
|
3540
3193
|
void 0,
|
|
3541
3194
|
{ yes: progressOptions?.yes }
|
|
3542
3195
|
);
|
|
3543
|
-
if (retry) {
|
|
3196
|
+
if (retry && deployment.serverId) {
|
|
3544
3197
|
console.log(source_default.cyan("\n\u{1F504} Retrying deployment...\n"));
|
|
3545
|
-
const
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
);
|
|
3551
|
-
return;
|
|
3552
|
-
}
|
|
3553
|
-
} else if (finalDeployment.error.includes("Authenticated git clone failed")) {
|
|
3554
|
-
let repoName;
|
|
3555
|
-
const repoMatch = finalDeployment.error.match(
|
|
3556
|
-
/github\.com\/([^/]+\/[^/\s]+)/
|
|
3557
|
-
);
|
|
3558
|
-
if (repoMatch) {
|
|
3559
|
-
repoName = repoMatch[1].replace(/\.git$/, "");
|
|
3560
|
-
} else if (finalDeployment.source.type === "github") {
|
|
3561
|
-
repoName = finalDeployment.source.repo;
|
|
3562
|
-
}
|
|
3563
|
-
console.log();
|
|
3564
|
-
const retry = await promptGitHubInstallation(
|
|
3565
|
-
api,
|
|
3566
|
-
"no_access",
|
|
3567
|
-
repoName,
|
|
3568
|
-
{ yes: progressOptions?.yes }
|
|
3569
|
-
);
|
|
3570
|
-
if (retry) {
|
|
3571
|
-
console.log(source_default.cyan("\n\u{1F504} Retrying deployment...\n"));
|
|
3572
|
-
const newDeployment = await api.redeployDeployment(deployment.id);
|
|
3573
|
-
await displayDeploymentProgress(
|
|
3574
|
-
api,
|
|
3575
|
-
newDeployment,
|
|
3576
|
-
progressOptions
|
|
3577
|
-
);
|
|
3198
|
+
const newDep = await api.createDeployment({
|
|
3199
|
+
serverId: deployment.serverId,
|
|
3200
|
+
trigger: "redeploy"
|
|
3201
|
+
});
|
|
3202
|
+
await displayDeploymentProgress(api, newDep.id, progressOptions);
|
|
3578
3203
|
return;
|
|
3579
3204
|
}
|
|
3580
3205
|
}
|
|
3581
3206
|
}
|
|
3582
|
-
if (finalDeployment.buildLogs) {
|
|
3583
|
-
console.log(source_default.gray("\nBuild logs:"));
|
|
3584
|
-
try {
|
|
3585
|
-
const logs = finalDeployment.buildLogs.split("\n").filter((l) => l.trim());
|
|
3586
|
-
for (const log of logs) {
|
|
3587
|
-
try {
|
|
3588
|
-
const logData = JSON.parse(log);
|
|
3589
|
-
if (logData.line) {
|
|
3590
|
-
console.log(source_default.gray(` ${logData.line}`));
|
|
3591
|
-
}
|
|
3592
|
-
} catch {
|
|
3593
|
-
console.log(source_default.gray(` ${log}`));
|
|
3594
|
-
}
|
|
3595
|
-
}
|
|
3596
|
-
} catch {
|
|
3597
|
-
console.log(source_default.gray(finalDeployment.buildLogs));
|
|
3598
|
-
}
|
|
3599
|
-
}
|
|
3600
3207
|
process.exit(1);
|
|
3601
|
-
} else if (
|
|
3208
|
+
} else if (deployment.status === "building" || deployment.status === "pending") {
|
|
3602
3209
|
startSpinner("Building and deploying...");
|
|
3603
|
-
checkCount++;
|
|
3604
3210
|
delay = Math.min(delay * 1.2, maxDelay);
|
|
3605
3211
|
} else {
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
);
|
|
3212
|
+
stopSpinner();
|
|
3213
|
+
console.log(source_default.yellow("\u26A0\uFE0F Deployment status: ") + deployment.status);
|
|
3609
3214
|
return;
|
|
3610
3215
|
}
|
|
3611
3216
|
}
|
|
3612
3217
|
stopSpinner();
|
|
3613
3218
|
console.log(source_default.yellow("\u26A0\uFE0F Deployment is taking longer than expected."));
|
|
3614
3219
|
console.log(
|
|
3615
|
-
source_default.gray("Check status with: ") + source_default.white(`mcp-use
|
|
3220
|
+
source_default.gray("Check status with: ") + source_default.white(`mcp-use deployments get ${deploymentId}`)
|
|
3616
3221
|
);
|
|
3617
3222
|
}
|
|
3618
3223
|
async function checkRepoAccess(api, owner, repo) {
|
|
@@ -3698,7 +3303,7 @@ async function promptGitHubInstallation(api, reason, repoName, opts) {
|
|
|
3698
3303
|
return false;
|
|
3699
3304
|
}
|
|
3700
3305
|
try {
|
|
3701
|
-
const appName =
|
|
3306
|
+
const appName = await api.getGitHubAppName();
|
|
3702
3307
|
const installUrl = reason === "not_connected" ? `https://github.com/apps/${appName}/installations/new` : `https://github.com/settings/installations`;
|
|
3703
3308
|
console.log(
|
|
3704
3309
|
source_default.cyan(
|
|
@@ -3978,14 +3583,14 @@ async function deployCommand(options) {
|
|
|
3978
3583
|
if (options.org) {
|
|
3979
3584
|
try {
|
|
3980
3585
|
const authInfo = await api.testAuth();
|
|
3981
|
-
const match = (authInfo.
|
|
3982
|
-
(
|
|
3586
|
+
const match = (authInfo.orgs ?? []).find(
|
|
3587
|
+
(o) => o.slug === options.org || o.id === options.org || o.name.toLowerCase() === options.org.toLowerCase()
|
|
3983
3588
|
);
|
|
3984
3589
|
if (match) {
|
|
3985
|
-
api.
|
|
3590
|
+
api.setOrgId(match.id);
|
|
3986
3591
|
const slug = match.slug ? source_default.gray(` (${match.slug})`) : "";
|
|
3987
3592
|
console.log(
|
|
3988
|
-
source_default.gray("Organization: ") + source_default.cyan(match.
|
|
3593
|
+
source_default.gray("Organization: ") + source_default.cyan(match.name) + slug
|
|
3989
3594
|
);
|
|
3990
3595
|
} else {
|
|
3991
3596
|
console.error(
|
|
@@ -4004,6 +3609,7 @@ async function deployCommand(options) {
|
|
|
4004
3609
|
}
|
|
4005
3610
|
}
|
|
4006
3611
|
let githubVerified = false;
|
|
3612
|
+
let installationDbId;
|
|
4007
3613
|
try {
|
|
4008
3614
|
console.log(source_default.gray(`[DEBUG] API URL: ${api.baseUrl}`));
|
|
4009
3615
|
const connectionStatus = await api.getGitHubConnectionStatus();
|
|
@@ -4030,8 +3636,10 @@ async function deployCommand(options) {
|
|
|
4030
3636
|
console.log(source_default.cyan(" https://manufact.com/cloud/settings\n"));
|
|
4031
3637
|
process.exit(1);
|
|
4032
3638
|
}
|
|
3639
|
+
installationDbId = retryStatus.installations?.[0]?.id;
|
|
4033
3640
|
githubVerified = true;
|
|
4034
3641
|
} else if (gitInfo.owner && gitInfo.repo) {
|
|
3642
|
+
installationDbId = connectionStatus.installations?.[0]?.id;
|
|
4035
3643
|
console.log(source_default.gray("Checking repository access..."));
|
|
4036
3644
|
const hasAccess = await checkRepoAccess(
|
|
4037
3645
|
api,
|
|
@@ -4110,7 +3718,7 @@ async function deployCommand(options) {
|
|
|
4110
3718
|
}
|
|
4111
3719
|
const existingLink = !options.new ? await getProjectLink(cwd) : null;
|
|
4112
3720
|
const serverId = existingLink?.serverId;
|
|
4113
|
-
if (existingLink) {
|
|
3721
|
+
if (existingLink && serverId) {
|
|
4114
3722
|
try {
|
|
4115
3723
|
const existingDeployment = await api.getDeployment(
|
|
4116
3724
|
existingLink.deploymentId
|
|
@@ -4122,29 +3730,19 @@ async function deployCommand(options) {
|
|
|
4122
3730
|
source_default.cyan(` URL: ${getMcpServerUrl(existingDeployment)}
|
|
4123
3731
|
`)
|
|
4124
3732
|
);
|
|
4125
|
-
const
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
rootDir: options.rootDir || void 0
|
|
4131
|
-
};
|
|
4132
|
-
const deployment2 = await api.redeployDeployment(
|
|
4133
|
-
existingLink.deploymentId,
|
|
4134
|
-
redeploymentConfig
|
|
4135
|
-
);
|
|
3733
|
+
const newDep = await api.createDeployment({
|
|
3734
|
+
serverId,
|
|
3735
|
+
branch: gitInfo.branch || "main",
|
|
3736
|
+
trigger: "redeploy"
|
|
3737
|
+
});
|
|
4136
3738
|
await saveProjectLink(cwd, {
|
|
4137
3739
|
...existingLink,
|
|
4138
|
-
linkedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3740
|
+
linkedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3741
|
+
deploymentId: newDep.id
|
|
4139
3742
|
});
|
|
4140
|
-
await displayDeploymentProgress(api,
|
|
3743
|
+
await displayDeploymentProgress(api, newDep.id, {
|
|
4141
3744
|
yes: options.yes
|
|
4142
3745
|
});
|
|
4143
|
-
if (options.open && deployment2.domain) {
|
|
4144
|
-
console.log();
|
|
4145
|
-
console.log(source_default.gray("Opening deployment in browser..."));
|
|
4146
|
-
await open_default(`https://${deployment2.domain}`);
|
|
4147
|
-
}
|
|
4148
3746
|
return;
|
|
4149
3747
|
} else {
|
|
4150
3748
|
console.log(
|
|
@@ -4152,72 +3750,97 @@ async function deployCommand(options) {
|
|
|
4152
3750
|
`\u26A0\uFE0F Linked deployment not found or failed, creating new one...`
|
|
4153
3751
|
)
|
|
4154
3752
|
);
|
|
4155
|
-
|
|
4156
|
-
console.log(
|
|
4157
|
-
source_default.gray(` Will reuse existing server: ${serverId}`)
|
|
4158
|
-
);
|
|
4159
|
-
}
|
|
3753
|
+
console.log(source_default.gray(` Will reuse existing server: ${serverId}`));
|
|
4160
3754
|
}
|
|
4161
3755
|
} catch (error) {
|
|
4162
3756
|
console.log(
|
|
4163
3757
|
source_default.yellow(`\u26A0\uFE0F Linked deployment not found, creating new one...`)
|
|
4164
3758
|
);
|
|
4165
|
-
|
|
4166
|
-
console.log(source_default.gray(` Will reuse existing server: ${serverId}`));
|
|
4167
|
-
}
|
|
3759
|
+
console.log(source_default.gray(` Will reuse existing server: ${serverId}`));
|
|
4168
3760
|
}
|
|
4169
3761
|
}
|
|
4170
|
-
const deploymentRequest = {
|
|
4171
|
-
name: projectName,
|
|
4172
|
-
source: {
|
|
4173
|
-
type: "github",
|
|
4174
|
-
repo: `${gitInfo.owner}/${gitInfo.repo}`,
|
|
4175
|
-
branch: gitInfo.branch || "main",
|
|
4176
|
-
rootDir: options.rootDir || void 0,
|
|
4177
|
-
runtime,
|
|
4178
|
-
port,
|
|
4179
|
-
buildCommand,
|
|
4180
|
-
startCommand,
|
|
4181
|
-
env: Object.keys(envVars).length > 0 ? envVars : void 0
|
|
4182
|
-
},
|
|
4183
|
-
healthCheckPath: "/healthz",
|
|
4184
|
-
serverId
|
|
4185
|
-
};
|
|
4186
3762
|
if (!options.org) {
|
|
4187
3763
|
try {
|
|
4188
3764
|
const config = await readConfig();
|
|
4189
|
-
if (config.
|
|
4190
|
-
const slug = config.
|
|
3765
|
+
if (config.orgName) {
|
|
3766
|
+
const slug = config.orgSlug ? source_default.gray(` (${config.orgSlug})`) : "";
|
|
4191
3767
|
console.log(
|
|
4192
|
-
source_default.gray("Organization: ") + source_default.cyan(config.
|
|
3768
|
+
source_default.gray("Organization: ") + source_default.cyan(config.orgName) + slug
|
|
4193
3769
|
);
|
|
4194
3770
|
}
|
|
4195
3771
|
} catch {
|
|
4196
3772
|
}
|
|
4197
3773
|
}
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
3774
|
+
let deploymentId;
|
|
3775
|
+
if (serverId) {
|
|
3776
|
+
console.log(source_default.gray("Creating deployment..."));
|
|
3777
|
+
const result = await api.createDeployment({
|
|
3778
|
+
serverId,
|
|
3779
|
+
branch: gitInfo.branch || "main",
|
|
3780
|
+
trigger: "manual"
|
|
3781
|
+
});
|
|
3782
|
+
deploymentId = result.id;
|
|
3783
|
+
} else {
|
|
3784
|
+
if (!installationDbId) {
|
|
3785
|
+
console.log(source_default.red("\u2717 Could not determine GitHub installation ID."));
|
|
3786
|
+
console.log(
|
|
3787
|
+
source_default.gray(
|
|
3788
|
+
"Please ensure your GitHub App is installed and try again."
|
|
3789
|
+
)
|
|
3790
|
+
);
|
|
3791
|
+
process.exit(1);
|
|
3792
|
+
}
|
|
3793
|
+
const config = await readConfig();
|
|
3794
|
+
const authInfo = await api.testAuth();
|
|
3795
|
+
const orgId = config.orgId || authInfo.default_org_id;
|
|
3796
|
+
if (!orgId) {
|
|
3797
|
+
console.log(
|
|
3798
|
+
source_default.red("\u2717 No organization set. Run `mcp-use org switch` first.")
|
|
3799
|
+
);
|
|
3800
|
+
process.exit(1);
|
|
3801
|
+
}
|
|
3802
|
+
console.log(source_default.gray("Creating server and deployment..."));
|
|
3803
|
+
const serverResult = await api.createServer({
|
|
3804
|
+
type: "github",
|
|
3805
|
+
organizationId: orgId,
|
|
3806
|
+
installationId: installationDbId,
|
|
3807
|
+
name: projectName,
|
|
3808
|
+
repoFullName: `${gitInfo.owner}/${gitInfo.repo}`,
|
|
3809
|
+
branch: gitInfo.branch || "main",
|
|
3810
|
+
rootDir: options.rootDir,
|
|
3811
|
+
port,
|
|
3812
|
+
buildCommand,
|
|
3813
|
+
startCommand,
|
|
3814
|
+
env: Object.keys(envVars).length > 0 ? envVars : void 0
|
|
3815
|
+
});
|
|
3816
|
+
deploymentId = serverResult.deploymentId ?? "";
|
|
3817
|
+
if (!deploymentId) {
|
|
3818
|
+
console.log(
|
|
3819
|
+
source_default.green("\u2713 Server created: ") + source_default.gray(serverResult.server.id)
|
|
3820
|
+
);
|
|
3821
|
+
console.log(
|
|
3822
|
+
source_default.yellow(
|
|
3823
|
+
"\u26A0\uFE0F No deployment was triggered. You may need to trigger one manually."
|
|
3824
|
+
)
|
|
3825
|
+
);
|
|
3826
|
+
return;
|
|
3827
|
+
}
|
|
3828
|
+
await saveProjectLink(cwd, {
|
|
3829
|
+
deploymentId,
|
|
3830
|
+
deploymentName: projectName,
|
|
3831
|
+
linkedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3832
|
+
serverId: serverResult.server.id
|
|
3833
|
+
});
|
|
3834
|
+
console.log(
|
|
3835
|
+
source_default.gray(` Linked to this project (stored in .mcp-use/project.json)`)
|
|
3836
|
+
);
|
|
3837
|
+
console.log(source_default.gray(` Future deploys will reuse the same URL
|
|
4214
3838
|
`));
|
|
4215
|
-
await displayDeploymentProgress(api, deployment, { yes: options.yes });
|
|
4216
|
-
if (options.open && deployment.domain) {
|
|
4217
|
-
console.log();
|
|
4218
|
-
console.log(source_default.gray("Opening deployment in browser..."));
|
|
4219
|
-
await open_default(`https://${deployment.domain}`);
|
|
4220
3839
|
}
|
|
3840
|
+
console.log(
|
|
3841
|
+
source_default.green("\u2713 Deployment created: ") + source_default.gray(deploymentId)
|
|
3842
|
+
);
|
|
3843
|
+
await displayDeploymentProgress(api, deploymentId, { yes: options.yes });
|
|
4221
3844
|
} catch (error) {
|
|
4222
3845
|
console.error(
|
|
4223
3846
|
source_default.red.bold("\n\u2717 Deployment failed:"),
|
|
@@ -4292,19 +3915,19 @@ async function listDeploymentsCommand() {
|
|
|
4292
3915
|
);
|
|
4293
3916
|
console.log(
|
|
4294
3917
|
source_default.white.bold(
|
|
4295
|
-
`${"ID".padEnd(40)} ${"NAME".padEnd(25)} ${"STATUS".padEnd(12)} ${"
|
|
3918
|
+
`${"ID".padEnd(40)} ${"NAME".padEnd(25)} ${"STATUS".padEnd(12)} ${"MCP URL".padEnd(45)} ${"CREATED"}`
|
|
4296
3919
|
)
|
|
4297
3920
|
);
|
|
4298
|
-
console.log(source_default.gray("\u2500".repeat(
|
|
3921
|
+
console.log(source_default.gray("\u2500".repeat(140)));
|
|
4299
3922
|
for (const deployment of sortedDeployments) {
|
|
4300
3923
|
const id = formatId(deployment.id).padEnd(40);
|
|
4301
3924
|
const name = deployment.name.substring(0, 24).padEnd(25);
|
|
4302
3925
|
const statusColor = getStatusColor(deployment.status);
|
|
4303
3926
|
const status = statusColor(deployment.status.padEnd(12));
|
|
4304
|
-
const
|
|
3927
|
+
const mcpUrl = (deployment.mcpUrl || "-").substring(0, 44).padEnd(45);
|
|
4305
3928
|
const created = formatRelativeTime(deployment.createdAt);
|
|
4306
3929
|
console.log(
|
|
4307
|
-
`${source_default.gray(id)} ${name} ${status} ${source_default.cyan(
|
|
3930
|
+
`${source_default.gray(id)} ${name} ${status} ${source_default.cyan(mcpUrl)} ${source_default.gray(created)}`
|
|
4308
3931
|
);
|
|
4309
3932
|
}
|
|
4310
3933
|
console.log();
|
|
@@ -4336,31 +3959,24 @@ async function getDeploymentCommand(deploymentId) {
|
|
|
4336
3959
|
console.log(
|
|
4337
3960
|
source_default.white("Status: ") + statusColor(deployment.status)
|
|
4338
3961
|
);
|
|
4339
|
-
if (deployment.
|
|
3962
|
+
if (deployment.mcpUrl) {
|
|
4340
3963
|
console.log(
|
|
4341
|
-
source_default.white("
|
|
3964
|
+
source_default.white("MCP URL: ") + source_default.cyan(deployment.mcpUrl)
|
|
4342
3965
|
);
|
|
4343
3966
|
}
|
|
4344
|
-
if (deployment.
|
|
3967
|
+
if (deployment.gitBranch) {
|
|
4345
3968
|
console.log(
|
|
4346
|
-
source_default.white("
|
|
3969
|
+
source_default.white("Branch: ") + source_default.gray(deployment.gitBranch)
|
|
4347
3970
|
);
|
|
4348
3971
|
}
|
|
4349
|
-
|
|
4350
|
-
source_default.white("Source: ") + source_default.gray(deployment.source.type)
|
|
4351
|
-
);
|
|
4352
|
-
if (deployment.source.type === "github") {
|
|
4353
|
-
console.log(
|
|
4354
|
-
source_default.white("Repository: ") + source_default.gray(deployment.source.repo)
|
|
4355
|
-
);
|
|
3972
|
+
if (deployment.gitCommitSha) {
|
|
4356
3973
|
console.log(
|
|
4357
|
-
source_default.white("
|
|
3974
|
+
source_default.white("Commit: ") + source_default.gray(deployment.gitCommitSha.substring(0, 7))
|
|
4358
3975
|
);
|
|
4359
3976
|
}
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
);
|
|
3977
|
+
if (deployment.port) {
|
|
3978
|
+
console.log(source_default.white("Port: ") + source_default.gray(deployment.port));
|
|
3979
|
+
}
|
|
4364
3980
|
if (deployment.provider) {
|
|
4365
3981
|
console.log(
|
|
4366
3982
|
source_default.white("Provider: ") + source_default.gray(deployment.provider)
|
|
@@ -4372,13 +3988,6 @@ async function getDeploymentCommand(deploymentId) {
|
|
|
4372
3988
|
console.log(
|
|
4373
3989
|
source_default.white("Updated: ") + source_default.gray(formatRelativeTime(deployment.updatedAt))
|
|
4374
3990
|
);
|
|
4375
|
-
if (deployment.source.env && Object.keys(deployment.source.env).length > 0) {
|
|
4376
|
-
console.log(source_default.white("\nEnvironment Variables:"));
|
|
4377
|
-
for (const [key, value] of Object.entries(deployment.source.env)) {
|
|
4378
|
-
const displayValue = key.toLowerCase().includes("key") || key.toLowerCase().includes("secret") || key.toLowerCase().includes("password") || key.toLowerCase().includes("token") ? "***" : value;
|
|
4379
|
-
console.log(source_default.gray(` ${key}=`) + source_default.white(displayValue));
|
|
4380
|
-
}
|
|
4381
|
-
}
|
|
4382
3991
|
if (deployment.status === "failed" && deployment.error) {
|
|
4383
3992
|
console.log(source_default.red("\nError:"));
|
|
4384
3993
|
console.log(source_default.red(` ${deployment.error}`));
|
|
@@ -4405,43 +4014,56 @@ async function restartDeploymentCommand(deploymentId, options) {
|
|
|
4405
4014
|
}
|
|
4406
4015
|
const api = await McpUseAPI.create();
|
|
4407
4016
|
const deployment = await api.getDeployment(deploymentId);
|
|
4017
|
+
if (!deployment.serverId) {
|
|
4018
|
+
console.log(
|
|
4019
|
+
source_default.red("\u2717 Cannot restart: deployment has no linked server.")
|
|
4020
|
+
);
|
|
4021
|
+
process.exit(1);
|
|
4022
|
+
}
|
|
4408
4023
|
console.log(
|
|
4409
4024
|
source_default.cyan.bold(`
|
|
4410
4025
|
\u{1F504} Restarting deployment: ${deployment.name}
|
|
4411
4026
|
`)
|
|
4412
4027
|
);
|
|
4413
|
-
const
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
);
|
|
4028
|
+
const newDep = await api.createDeployment({
|
|
4029
|
+
serverId: deployment.serverId,
|
|
4030
|
+
trigger: "redeploy"
|
|
4031
|
+
});
|
|
4032
|
+
console.log(source_default.green("\u2713 Restart initiated: ") + source_default.gray(newDep.id));
|
|
4417
4033
|
if (options.follow) {
|
|
4418
|
-
console.log(source_default.gray("\nFollowing
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
))
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4034
|
+
console.log(source_default.gray("\nFollowing build logs...\n"));
|
|
4035
|
+
let offset = 0;
|
|
4036
|
+
let terminal = false;
|
|
4037
|
+
while (!terminal) {
|
|
4038
|
+
await new Promise((r) => setTimeout(r, 2e3));
|
|
4039
|
+
try {
|
|
4040
|
+
const resp = await api.getDeploymentBuildLogs(newDep.id, offset);
|
|
4041
|
+
if (resp.logs.length > 0) {
|
|
4042
|
+
const lines = resp.logs.split("\n").filter((l) => l.trim());
|
|
4043
|
+
for (const line of lines) {
|
|
4044
|
+
try {
|
|
4045
|
+
const logData = JSON.parse(line);
|
|
4046
|
+
if (logData.line) {
|
|
4047
|
+
const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
|
|
4048
|
+
const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
|
|
4049
|
+
console.log(stepPrefix + levelColor(logData.line));
|
|
4050
|
+
}
|
|
4051
|
+
} catch {
|
|
4052
|
+
console.log(source_default.gray(line));
|
|
4053
|
+
}
|
|
4429
4054
|
}
|
|
4430
|
-
|
|
4431
|
-
console.log(source_default.gray(log));
|
|
4055
|
+
offset = resp.offset;
|
|
4432
4056
|
}
|
|
4057
|
+
if (resp.status === "running" || resp.status === "failed" || resp.status === "stopped") {
|
|
4058
|
+
terminal = true;
|
|
4059
|
+
}
|
|
4060
|
+
} catch {
|
|
4433
4061
|
}
|
|
4434
|
-
} catch (error) {
|
|
4435
|
-
console.log(
|
|
4436
|
-
source_default.gray(
|
|
4437
|
-
"\nLog stream ended. Use " + source_default.white(`mcp-use deployments get ${deploymentId}`) + " to check status."
|
|
4438
|
-
)
|
|
4439
|
-
);
|
|
4440
4062
|
}
|
|
4441
4063
|
} else {
|
|
4442
4064
|
console.log(
|
|
4443
4065
|
source_default.gray(
|
|
4444
|
-
"\nCheck status with: " + source_default.white(`mcp-use deployments get ${
|
|
4066
|
+
"\nCheck status with: " + source_default.white(`mcp-use deployments get ${newDep.id}`)
|
|
4445
4067
|
)
|
|
4446
4068
|
);
|
|
4447
4069
|
}
|
|
@@ -4475,8 +4097,10 @@ async function deleteDeploymentCommand(deploymentId, options) {
|
|
|
4475
4097
|
)
|
|
4476
4098
|
);
|
|
4477
4099
|
console.log(source_default.gray(` ID: ${deployment.id}`));
|
|
4478
|
-
|
|
4100
|
+
if (deployment.mcpUrl) {
|
|
4101
|
+
console.log(source_default.gray(` URL: ${deployment.mcpUrl}
|
|
4479
4102
|
`));
|
|
4103
|
+
}
|
|
4480
4104
|
const confirmed = await prompt2(
|
|
4481
4105
|
source_default.white("Are you sure you want to delete this deployment? (y/N): ")
|
|
4482
4106
|
);
|
|
@@ -4512,30 +4136,41 @@ async function logsCommand(deploymentId, options) {
|
|
|
4512
4136
|
}
|
|
4513
4137
|
const api = await McpUseAPI.create();
|
|
4514
4138
|
if (options.follow) {
|
|
4515
|
-
console.log(source_default.gray("
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4139
|
+
console.log(source_default.gray("Following build logs...\n"));
|
|
4140
|
+
let offset = 0;
|
|
4141
|
+
let terminal = false;
|
|
4142
|
+
while (!terminal) {
|
|
4143
|
+
await new Promise((r) => setTimeout(r, 2e3));
|
|
4144
|
+
try {
|
|
4145
|
+
const resp = await api.getDeploymentBuildLogs(deploymentId, offset);
|
|
4146
|
+
if (resp.logs.length > 0) {
|
|
4147
|
+
const lines = resp.logs.split("\n").filter((l) => l.trim());
|
|
4148
|
+
for (const line of lines) {
|
|
4149
|
+
try {
|
|
4150
|
+
const logData = JSON.parse(line);
|
|
4151
|
+
if (logData.line) {
|
|
4152
|
+
const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
|
|
4153
|
+
const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
|
|
4154
|
+
console.log(stepPrefix + levelColor(logData.line));
|
|
4155
|
+
}
|
|
4156
|
+
} catch {
|
|
4157
|
+
console.log(source_default.gray(line));
|
|
4158
|
+
}
|
|
4524
4159
|
}
|
|
4525
|
-
|
|
4526
|
-
|
|
4160
|
+
offset = resp.offset;
|
|
4161
|
+
}
|
|
4162
|
+
if (resp.status === "running" || resp.status === "failed" || resp.status === "stopped") {
|
|
4163
|
+
terminal = true;
|
|
4527
4164
|
}
|
|
4165
|
+
} catch {
|
|
4528
4166
|
}
|
|
4529
|
-
} catch (error) {
|
|
4530
|
-
console.log(source_default.gray("\nLog stream ended."));
|
|
4531
4167
|
}
|
|
4532
|
-
} else {
|
|
4533
|
-
const
|
|
4168
|
+
} else if (options.build) {
|
|
4169
|
+
const resp = await api.getDeploymentBuildLogs(deploymentId);
|
|
4170
|
+
const logs = resp.logs;
|
|
4534
4171
|
if (!logs || logs.trim() === "") {
|
|
4535
4172
|
console.log(
|
|
4536
|
-
source_default.yellow(
|
|
4537
|
-
`No ${options.build ? "build " : ""}logs available for this deployment.`
|
|
4538
|
-
)
|
|
4173
|
+
source_default.yellow("No build logs available for this deployment.")
|
|
4539
4174
|
);
|
|
4540
4175
|
return;
|
|
4541
4176
|
}
|
|
@@ -4552,133 +4187,30 @@ async function logsCommand(deploymentId, options) {
|
|
|
4552
4187
|
console.log(source_default.gray(line));
|
|
4553
4188
|
}
|
|
4554
4189
|
}
|
|
4555
|
-
}
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
);
|
|
4574
|
-
process.exit(1);
|
|
4575
|
-
}
|
|
4576
|
-
const api = await McpUseAPI.create();
|
|
4577
|
-
const deployment = await api.getDeployment(deploymentId);
|
|
4578
|
-
console.log(
|
|
4579
|
-
source_default.cyan.bold(`
|
|
4580
|
-
\u{1F510} Environment Variables: ${deployment.name}
|
|
4581
|
-
`)
|
|
4582
|
-
);
|
|
4583
|
-
if (!deployment.source.env || Object.keys(deployment.source.env).length === 0) {
|
|
4584
|
-
console.log(source_default.yellow("No environment variables set."));
|
|
4585
|
-
console.log();
|
|
4586
|
-
return;
|
|
4587
|
-
}
|
|
4588
|
-
for (const [key, value] of Object.entries(deployment.source.env)) {
|
|
4589
|
-
const displayValue = key.toLowerCase().includes("key") || key.toLowerCase().includes("secret") || key.toLowerCase().includes("password") || key.toLowerCase().includes("token") ? "***" : value;
|
|
4590
|
-
console.log(
|
|
4591
|
-
source_default.white(key) + source_default.gray("=") + source_default.cyan(displayValue)
|
|
4592
|
-
);
|
|
4593
|
-
}
|
|
4594
|
-
console.log();
|
|
4595
|
-
} catch (error) {
|
|
4596
|
-
console.error(
|
|
4597
|
-
source_default.red.bold("\n\u2717 Failed to list environment variables:"),
|
|
4598
|
-
source_default.red(error instanceof Error ? error.message : "Unknown error")
|
|
4599
|
-
);
|
|
4600
|
-
process.exit(1);
|
|
4601
|
-
}
|
|
4602
|
-
}
|
|
4603
|
-
async function setEnvCommand(deploymentId, envPairs) {
|
|
4604
|
-
try {
|
|
4605
|
-
if (!await isLoggedIn()) {
|
|
4606
|
-
console.log(source_default.red("\u2717 You are not logged in."));
|
|
4607
|
-
console.log(
|
|
4608
|
-
source_default.gray(
|
|
4609
|
-
"Run " + source_default.white("npx mcp-use login") + " to get started."
|
|
4610
|
-
)
|
|
4611
|
-
);
|
|
4612
|
-
process.exit(1);
|
|
4613
|
-
}
|
|
4614
|
-
const env2 = {};
|
|
4615
|
-
for (const pair of envPairs) {
|
|
4616
|
-
const [key, ...valueParts] = pair.split("=");
|
|
4617
|
-
if (!key || valueParts.length === 0) {
|
|
4618
|
-
console.log(source_default.red(`\u2717 Invalid format: ${pair}. Expected KEY=VALUE`));
|
|
4619
|
-
process.exit(1);
|
|
4190
|
+
} else {
|
|
4191
|
+
const logs = await api.getDeploymentLogs(deploymentId);
|
|
4192
|
+
if (!logs || logs.trim() === "") {
|
|
4193
|
+
console.log(source_default.yellow("No logs available for this deployment."));
|
|
4194
|
+
return;
|
|
4195
|
+
}
|
|
4196
|
+
const logLines = logs.split("\n").filter((l) => l.trim());
|
|
4197
|
+
for (const line of logLines) {
|
|
4198
|
+
try {
|
|
4199
|
+
const logData = JSON.parse(line);
|
|
4200
|
+
if (logData.line) {
|
|
4201
|
+
const levelColor = logData.level === "error" ? source_default.red : logData.level === "warn" ? source_default.yellow : source_default.gray;
|
|
4202
|
+
const stepPrefix = logData.step ? source_default.cyan(`[${logData.step}]`) + " " : "";
|
|
4203
|
+
console.log(stepPrefix + levelColor(logData.line));
|
|
4204
|
+
}
|
|
4205
|
+
} catch {
|
|
4206
|
+
console.log(source_default.gray(line));
|
|
4207
|
+
}
|
|
4620
4208
|
}
|
|
4621
|
-
env2[key.trim()] = valueParts.join("=").trim();
|
|
4622
|
-
}
|
|
4623
|
-
const api = await McpUseAPI.create();
|
|
4624
|
-
const deployment = await api.getDeployment(deploymentId);
|
|
4625
|
-
const currentEnv = deployment.source.env || {};
|
|
4626
|
-
const mergedEnv = { ...currentEnv, ...env2 };
|
|
4627
|
-
const updated = await api.updateDeployment(deploymentId, {
|
|
4628
|
-
env: mergedEnv
|
|
4629
|
-
});
|
|
4630
|
-
console.log(
|
|
4631
|
-
source_default.green.bold(`
|
|
4632
|
-
\u2713 Environment variables updated: ${updated.name}
|
|
4633
|
-
`)
|
|
4634
|
-
);
|
|
4635
|
-
for (const key of Object.keys(env2)) {
|
|
4636
|
-
const displayValue = key.toLowerCase().includes("key") || key.toLowerCase().includes("secret") || key.toLowerCase().includes("password") || key.toLowerCase().includes("token") ? "***" : env2[key];
|
|
4637
|
-
console.log(
|
|
4638
|
-
source_default.white(key) + source_default.gray("=") + source_default.cyan(displayValue)
|
|
4639
|
-
);
|
|
4640
|
-
}
|
|
4641
|
-
console.log();
|
|
4642
|
-
} catch (error) {
|
|
4643
|
-
console.error(
|
|
4644
|
-
source_default.red.bold("\n\u2717 Failed to set environment variables:"),
|
|
4645
|
-
source_default.red(error instanceof Error ? error.message : "Unknown error")
|
|
4646
|
-
);
|
|
4647
|
-
process.exit(1);
|
|
4648
|
-
}
|
|
4649
|
-
}
|
|
4650
|
-
async function unsetEnvCommand(deploymentId, keys) {
|
|
4651
|
-
try {
|
|
4652
|
-
if (!await isLoggedIn()) {
|
|
4653
|
-
console.log(source_default.red("\u2717 You are not logged in."));
|
|
4654
|
-
console.log(
|
|
4655
|
-
source_default.gray(
|
|
4656
|
-
"Run " + source_default.white("npx mcp-use login") + " to get started."
|
|
4657
|
-
)
|
|
4658
|
-
);
|
|
4659
|
-
process.exit(1);
|
|
4660
|
-
}
|
|
4661
|
-
const api = await McpUseAPI.create();
|
|
4662
|
-
const deployment = await api.getDeployment(deploymentId);
|
|
4663
|
-
const currentEnv = { ...deployment.source.env || {} };
|
|
4664
|
-
for (const key of keys) {
|
|
4665
|
-
delete currentEnv[key];
|
|
4666
|
-
}
|
|
4667
|
-
const updated = await api.updateDeployment(deploymentId, {
|
|
4668
|
-
env: currentEnv
|
|
4669
|
-
});
|
|
4670
|
-
console.log(
|
|
4671
|
-
source_default.green.bold(`
|
|
4672
|
-
\u2713 Environment variables removed: ${updated.name}
|
|
4673
|
-
`)
|
|
4674
|
-
);
|
|
4675
|
-
for (const key of keys) {
|
|
4676
|
-
console.log(source_default.gray(` ${key}`));
|
|
4677
4209
|
}
|
|
4678
4210
|
console.log();
|
|
4679
4211
|
} catch (error) {
|
|
4680
4212
|
console.error(
|
|
4681
|
-
source_default.red.bold("\n\u2717 Failed to
|
|
4213
|
+
source_default.red.bold("\n\u2717 Failed to get logs:"),
|
|
4682
4214
|
source_default.red(error instanceof Error ? error.message : "Unknown error")
|
|
4683
4215
|
);
|
|
4684
4216
|
process.exit(1);
|
|
@@ -4696,11 +4228,9 @@ async function stopDeploymentCommand(deploymentId) {
|
|
|
4696
4228
|
process.exit(1);
|
|
4697
4229
|
}
|
|
4698
4230
|
const api = await McpUseAPI.create();
|
|
4699
|
-
|
|
4700
|
-
status: "stopped"
|
|
4701
|
-
});
|
|
4231
|
+
await api.stopDeployment(deploymentId);
|
|
4702
4232
|
console.log(source_default.green.bold(`
|
|
4703
|
-
\u2713 Deployment stopped
|
|
4233
|
+
\u2713 Deployment stopped
|
|
4704
4234
|
`));
|
|
4705
4235
|
} catch (error) {
|
|
4706
4236
|
console.error(
|
|
@@ -4721,13 +4251,11 @@ async function startDeploymentCommand(deploymentId) {
|
|
|
4721
4251
|
);
|
|
4722
4252
|
process.exit(1);
|
|
4723
4253
|
}
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
\u2713 Deployment started: ${updated.name}
|
|
4730
|
-
`));
|
|
4254
|
+
console.log(
|
|
4255
|
+
source_default.yellow(
|
|
4256
|
+
"\u26A0\uFE0F Start is not supported in this version. Use `mcp-use deployments restart` to redeploy."
|
|
4257
|
+
)
|
|
4258
|
+
);
|
|
4731
4259
|
} catch (error) {
|
|
4732
4260
|
console.error(
|
|
4733
4261
|
source_default.red.bold("\n\u2717 Failed to start deployment:"),
|
|
@@ -4742,13 +4270,11 @@ function createDeploymentsCommand() {
|
|
|
4742
4270
|
);
|
|
4743
4271
|
deploymentsCommand.command("list").alias("ls").description("List all deployments").action(listDeploymentsCommand);
|
|
4744
4272
|
deploymentsCommand.command("get").argument("<deployment-id>", "Deployment ID").description("Get deployment details").action(getDeploymentCommand);
|
|
4745
|
-
deploymentsCommand.command("restart").argument("<deployment-id>", "Deployment ID").option("-f, --follow", "Follow
|
|
4273
|
+
deploymentsCommand.command("restart").argument("<deployment-id>", "Deployment ID").option("-f, --follow", "Follow build logs").description(
|
|
4274
|
+
"Restart a deployment (triggers a new deployment on the same server)"
|
|
4275
|
+
).action(restartDeploymentCommand);
|
|
4746
4276
|
deploymentsCommand.command("delete").alias("rm").argument("<deployment-id>", "Deployment ID").option("-y, --yes", "Skip confirmation prompt").description("Delete a deployment").action(deleteDeploymentCommand);
|
|
4747
|
-
deploymentsCommand.command("logs").argument("<deployment-id>", "Deployment ID").option("-b, --build", "Show build logs instead of runtime logs").option("-f, --follow", "
|
|
4748
|
-
const envCommand = deploymentsCommand.command("env").description("Manage environment variables");
|
|
4749
|
-
envCommand.command("list").argument("<deployment-id>", "Deployment ID").description("List environment variables").action(listEnvCommand);
|
|
4750
|
-
envCommand.command("set").argument("<deployment-id>", "Deployment ID").argument("<pairs...>", "Environment variables in KEY=VALUE format").description("Set environment variables").action(setEnvCommand);
|
|
4751
|
-
envCommand.command("unset").argument("<deployment-id>", "Deployment ID").argument("<keys...>", "Environment variable keys to remove").description("Unset environment variables").action(unsetEnvCommand);
|
|
4277
|
+
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);
|
|
4752
4278
|
deploymentsCommand.command("stop").argument("<deployment-id>", "Deployment ID").description("Stop a deployment").action(stopDeploymentCommand);
|
|
4753
4279
|
deploymentsCommand.command("start").argument("<deployment-id>", "Deployment ID").description("Start a stopped deployment").action(startDeploymentCommand);
|
|
4754
4280
|
return deploymentsCommand;
|
|
@@ -4771,22 +4297,22 @@ async function orgListCommand() {
|
|
|
4771
4297
|
const api = await McpUseAPI.create();
|
|
4772
4298
|
const authInfo = await api.testAuth();
|
|
4773
4299
|
const config = await readConfig();
|
|
4774
|
-
const
|
|
4775
|
-
const activeId = config.
|
|
4776
|
-
if (
|
|
4300
|
+
const orgs = authInfo.orgs ?? [];
|
|
4301
|
+
const activeId = config.orgId || authInfo.default_org_id;
|
|
4302
|
+
if (orgs.length === 0) {
|
|
4777
4303
|
console.log(source_default.yellow("No organizations found."));
|
|
4778
4304
|
return;
|
|
4779
4305
|
}
|
|
4780
4306
|
console.log(source_default.cyan.bold("\u{1F3E2} Your organizations:\n"));
|
|
4781
|
-
for (const
|
|
4782
|
-
const isActive =
|
|
4307
|
+
for (const o of orgs) {
|
|
4308
|
+
const isActive = o.id === activeId;
|
|
4783
4309
|
const marker = isActive ? source_default.green(" \u2190 active") : "";
|
|
4784
|
-
const slug =
|
|
4785
|
-
const role = source_default.gray(` [${
|
|
4786
|
-
const name = isActive ? source_default.cyan.bold(
|
|
4310
|
+
const slug = o.slug ? source_default.gray(` (${o.slug})`) : "";
|
|
4311
|
+
const role = source_default.gray(` [${o.role}]`);
|
|
4312
|
+
const name = isActive ? source_default.cyan.bold(o.name) : source_default.white(o.name);
|
|
4787
4313
|
console.log(` ${name}${slug}${role}${marker}`);
|
|
4788
4314
|
}
|
|
4789
|
-
if (
|
|
4315
|
+
if (orgs.length > 1) {
|
|
4790
4316
|
console.log(
|
|
4791
4317
|
source_default.gray("\nSwitch with " + source_default.white("npx mcp-use org switch"))
|
|
4792
4318
|
);
|
|
@@ -4805,40 +4331,40 @@ async function orgSwitchCommand() {
|
|
|
4805
4331
|
const api = await McpUseAPI.create();
|
|
4806
4332
|
const authInfo = await api.testAuth();
|
|
4807
4333
|
const config = await readConfig();
|
|
4808
|
-
const
|
|
4809
|
-
if (
|
|
4334
|
+
const orgs = authInfo.orgs ?? [];
|
|
4335
|
+
if (orgs.length === 0) {
|
|
4810
4336
|
console.log(source_default.yellow("No organizations found."));
|
|
4811
4337
|
return;
|
|
4812
4338
|
}
|
|
4813
|
-
if (
|
|
4814
|
-
const
|
|
4815
|
-
const slug2 =
|
|
4339
|
+
if (orgs.length === 1) {
|
|
4340
|
+
const o = orgs[0];
|
|
4341
|
+
const slug2 = o.slug ? source_default.gray(` (${o.slug})`) : "";
|
|
4816
4342
|
console.log(
|
|
4817
4343
|
source_default.yellow(
|
|
4818
|
-
`You only have one organization: ${source_default.cyan(
|
|
4344
|
+
`You only have one organization: ${source_default.cyan(o.name)}${slug2}`
|
|
4819
4345
|
)
|
|
4820
4346
|
);
|
|
4821
4347
|
return;
|
|
4822
4348
|
}
|
|
4823
|
-
const activeId = config.
|
|
4824
|
-
const selected = await promptOrgSelection(
|
|
4349
|
+
const activeId = config.orgId || authInfo.default_org_id;
|
|
4350
|
+
const selected = await promptOrgSelection(orgs, activeId);
|
|
4825
4351
|
if (!selected) {
|
|
4826
4352
|
console.log(source_default.yellow("No organization selected."));
|
|
4827
4353
|
return;
|
|
4828
4354
|
}
|
|
4829
4355
|
await writeConfig({
|
|
4830
4356
|
...config,
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4357
|
+
orgId: selected.id,
|
|
4358
|
+
orgName: selected.name,
|
|
4359
|
+
orgSlug: selected.slug ?? void 0
|
|
4834
4360
|
});
|
|
4835
4361
|
try {
|
|
4836
|
-
await api.
|
|
4362
|
+
await api.setDefaultOrg(selected.id);
|
|
4837
4363
|
} catch {
|
|
4838
4364
|
}
|
|
4839
4365
|
const slug = selected.slug ? source_default.gray(` (${selected.slug})`) : "";
|
|
4840
4366
|
console.log(
|
|
4841
|
-
source_default.green.bold("\n\u2713 Switched to ") + source_default.cyan.bold(selected.
|
|
4367
|
+
source_default.green.bold("\n\u2713 Switched to ") + source_default.cyan.bold(selected.name) + slug
|
|
4842
4368
|
);
|
|
4843
4369
|
} catch (error) {
|
|
4844
4370
|
console.error(
|
|
@@ -4852,7 +4378,7 @@ async function orgCurrentCommand() {
|
|
|
4852
4378
|
try {
|
|
4853
4379
|
if (!await ensureLoggedIn()) return;
|
|
4854
4380
|
const config = await readConfig();
|
|
4855
|
-
if (!config.
|
|
4381
|
+
if (!config.orgId) {
|
|
4856
4382
|
console.log(
|
|
4857
4383
|
source_default.yellow(
|
|
4858
4384
|
"No organization selected. Run " + source_default.white("npx mcp-use org switch") + " to pick one."
|
|
@@ -4860,9 +4386,9 @@ async function orgCurrentCommand() {
|
|
|
4860
4386
|
);
|
|
4861
4387
|
return;
|
|
4862
4388
|
}
|
|
4863
|
-
const slug = config.
|
|
4389
|
+
const slug = config.orgSlug ? source_default.gray(` (${config.orgSlug})`) : "";
|
|
4864
4390
|
console.log(
|
|
4865
|
-
source_default.cyan.bold("\u{1F3E2} Active organization: ") + source_default.white(config.
|
|
4391
|
+
source_default.cyan.bold("\u{1F3E2} Active organization: ") + source_default.white(config.orgName || config.orgId) + slug
|
|
4866
4392
|
);
|
|
4867
4393
|
} catch (error) {
|
|
4868
4394
|
console.error(
|
|
@@ -5187,7 +4713,7 @@ async function isPortAvailable(port, host = "localhost") {
|
|
|
5187
4713
|
return true;
|
|
5188
4714
|
}
|
|
5189
4715
|
}
|
|
5190
|
-
async function
|
|
4716
|
+
async function findAvailablePort(startPort, host = "localhost") {
|
|
5191
4717
|
for (let port = startPort; port < startPort + 100; port++) {
|
|
5192
4718
|
if (await isPortAvailable(port, host)) {
|
|
5193
4719
|
return port;
|
|
@@ -5478,7 +5004,7 @@ if (container && Component) {
|
|
|
5478
5004
|
`${widgetName}-metadata`
|
|
5479
5005
|
);
|
|
5480
5006
|
await fs10.mkdir(metadataTempDir, { recursive: true });
|
|
5481
|
-
const { createServer
|
|
5007
|
+
const { createServer } = await import("vite");
|
|
5482
5008
|
const nodeStubsPlugin = {
|
|
5483
5009
|
name: "node-stubs",
|
|
5484
5010
|
enforce: "pre",
|
|
@@ -5505,7 +5031,7 @@ export default PostHog;
|
|
|
5505
5031
|
return null;
|
|
5506
5032
|
}
|
|
5507
5033
|
};
|
|
5508
|
-
const metadataServer = await
|
|
5034
|
+
const metadataServer = await createServer({
|
|
5509
5035
|
root: metadataTempDir,
|
|
5510
5036
|
cacheDir: import_node_path8.default.join(metadataTempDir, ".vite-cache"),
|
|
5511
5037
|
plugins: [nodeStubsPlugin, tailwindcss(), react()],
|
|
@@ -6070,7 +5596,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6070
5596
|
displayPackageVersions(projectPath);
|
|
6071
5597
|
if (!await isPortAvailable(port, host)) {
|
|
6072
5598
|
console.log(source_default.yellow.bold(`\u26A0\uFE0F Port ${port} is already in use`));
|
|
6073
|
-
const availablePort = await
|
|
5599
|
+
const availablePort = await findAvailablePort(port, host);
|
|
6074
5600
|
console.log(source_default.green.bold(`\u2713 Using port ${availablePort} instead`));
|
|
6075
5601
|
port = availablePort;
|
|
6076
5602
|
}
|
|
@@ -6905,9 +6431,12 @@ Looked for:
|
|
|
6905
6431
|
process.exit(1);
|
|
6906
6432
|
}
|
|
6907
6433
|
});
|
|
6908
|
-
program.command("login").description("Login to
|
|
6434
|
+
program.command("login").description("Login to mcp-use cloud").option(
|
|
6435
|
+
"--api-key <key>",
|
|
6436
|
+
"Login with an API key directly (non-interactive, for CI/CD)"
|
|
6437
|
+
).action(async (opts) => {
|
|
6909
6438
|
try {
|
|
6910
|
-
await loginCommand();
|
|
6439
|
+
await loginCommand({ apiKey: opts.apiKey });
|
|
6911
6440
|
process.exit(0);
|
|
6912
6441
|
} catch (error) {
|
|
6913
6442
|
console.error(
|