@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.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
|
-
|
|
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
|
-
|
|
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
|
|
1184
|
+
async function getOrgId() {
|
|
1184
1185
|
const config = await readConfig();
|
|
1185
|
-
return config.
|
|
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
|
-
|
|
1196
|
-
constructor(baseUrl, apiKey,
|
|
1200
|
+
orgId;
|
|
1201
|
+
constructor(baseUrl, apiKey, orgId) {
|
|
1197
1202
|
this.baseUrl = baseUrl || "";
|
|
1198
1203
|
this.apiKey = apiKey;
|
|
1199
|
-
this.
|
|
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
|
|
1208
|
-
return new _McpUseAPI(baseUrl, apiKey ?? void 0,
|
|
1209
|
+
const orgId = await getOrgId();
|
|
1210
|
+
return new _McpUseAPI(baseUrl, apiKey ?? void 0, orgId ?? void 0);
|
|
1209
1211
|
}
|
|
1210
|
-
|
|
1211
|
-
|
|
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.
|
|
1229
|
-
headers["x-profile-id"] = this.
|
|
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
|
|
1258
|
+
* Create a persistent API key using a Better Auth access token.
|
|
1258
1259
|
*/
|
|
1259
|
-
async
|
|
1260
|
-
const
|
|
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 ${
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
1345
|
+
return resp.logs;
|
|
1492
1346
|
}
|
|
1493
|
-
|
|
1494
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
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
|
-
|
|
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
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
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
|
-
|
|
1413
|
+
return response.json();
|
|
1547
1414
|
}
|
|
1548
|
-
async function
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
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
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
(
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
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
|
-
|
|
1791
|
-
|
|
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(
|
|
1797
|
-
if (
|
|
1798
|
-
if (
|
|
1799
|
-
return
|
|
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 <
|
|
1803
|
-
const
|
|
1804
|
-
const marker =
|
|
1805
|
-
const 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 =
|
|
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 <
|
|
1826
|
-
resolve2(
|
|
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(
|
|
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
|
-
"
|
|
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("
|
|
1848
|
-
const
|
|
1849
|
-
const
|
|
1850
|
-
const
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
source_default.gray("
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
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
|
|
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
|
|
1887
|
-
const authInfo = await
|
|
1888
|
-
console.log(source_default.cyan.bold("\
|
|
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
|
|
1892
|
-
if (
|
|
1893
|
-
const masked =
|
|
1894
|
-
console.log(source_default.white("API Key: ") + source_default.gray(masked));
|
|
1895
|
-
}
|
|
1896
|
-
const
|
|
1897
|
-
if (
|
|
1898
|
-
let
|
|
1899
|
-
if (
|
|
1900
|
-
|
|
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
|
-
|
|
1903
|
-
profiles,
|
|
1904
|
-
authInfo.default_profile_id
|
|
1905
|
-
);
|
|
1571
|
+
selectedOrg = await promptOrgSelection(orgs, authInfo.default_org_id);
|
|
1906
1572
|
}
|
|
1907
|
-
if (
|
|
1573
|
+
if (selectedOrg) {
|
|
1908
1574
|
const config = await readConfig();
|
|
1909
1575
|
await writeConfig({
|
|
1910
1576
|
...config,
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1577
|
+
orgId: selectedOrg.id,
|
|
1578
|
+
orgName: selectedOrg.name,
|
|
1579
|
+
orgSlug: selectedOrg.slug ?? void 0
|
|
1914
1580
|
});
|
|
1915
|
-
const slug =
|
|
1581
|
+
const slug = selectedOrg.slug ? source_default.gray(` (${selectedOrg.slug})`) : "";
|
|
1916
1582
|
console.log(
|
|
1917
|
-
source_default.white("Org: ") + source_default.cyan(
|
|
1583
|
+
source_default.white(" Org: ") + source_default.cyan(selectedOrg.name) + slug
|
|
1918
1584
|
);
|
|
1919
1585
|
}
|
|
1920
1586
|
}
|
|
1921
|
-
} catch
|
|
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
|
-
"\
|
|
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
|
|
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
|
|
1988
|
-
if (
|
|
1989
|
-
const
|
|
1990
|
-
(
|
|
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 (
|
|
1993
|
-
const 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(
|
|
1661
|
+
source_default.white("Org: ") + source_default.cyan(activeOrg.name) + slug
|
|
1996
1662
|
);
|
|
1997
1663
|
}
|
|
1998
|
-
if (
|
|
1664
|
+
if (orgs.length > 1) {
|
|
1999
1665
|
console.log(
|
|
2000
1666
|
source_default.gray(
|
|
2001
1667
|
`
|
|
2002
|
-
${
|
|
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
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
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.
|
|
3388
|
-
return
|
|
3389
|
-
}
|
|
3390
|
-
|
|
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,
|
|
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 =
|
|
3453
|
-
let delay =
|
|
3096
|
+
const maxChecks = 120;
|
|
3097
|
+
let delay = 2e3;
|
|
3454
3098
|
const maxDelay = 1e4;
|
|
3455
|
-
let
|
|
3099
|
+
let buildLogOffset = 0;
|
|
3100
|
+
const sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
3456
3101
|
while (checkCount < maxChecks) {
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3102
|
+
await sleep(delay);
|
|
3103
|
+
checkCount++;
|
|
3104
|
+
try {
|
|
3105
|
+
const buildLogsResp = await api.getDeploymentBuildLogs(
|
|
3106
|
+
deploymentId,
|
|
3107
|
+
buildLogOffset
|
|
3463
3108
|
);
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3127
|
+
} catch {
|
|
3478
3128
|
}
|
|
3479
|
-
|
|
3480
|
-
|
|
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.
|
|
3485
|
-
|
|
3486
|
-
if (serverRef) {
|
|
3136
|
+
const orgSlug = config.orgSlug;
|
|
3137
|
+
if (deployment.serverId) {
|
|
3487
3138
|
if (orgSlug) {
|
|
3488
|
-
dashboardUrl = `${webUrl}/cloud/${orgSlug}/servers/${
|
|
3139
|
+
dashboardUrl = `${webUrl}/cloud/${orgSlug}/servers/${deployment.serverId}`;
|
|
3489
3140
|
} else {
|
|
3490
|
-
dashboardUrl = `${webUrl}/cloud/servers/${
|
|
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
|
-
|
|
3498
|
-
|
|
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 (
|
|
3163
|
+
} else if (deployment.status === "failed") {
|
|
3513
3164
|
stopSpinner();
|
|
3514
3165
|
console.log(source_default.red.bold("\u2717 Deployment failed\n"));
|
|
3515
|
-
if (
|
|
3516
|
-
console.log(source_default.red("Error: ") +
|
|
3517
|
-
if (
|
|
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
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
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 (
|
|
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
|
-
|
|
3589
|
-
|
|
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
|
|
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 =
|
|
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.
|
|
3964
|
-
(
|
|
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.
|
|
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.
|
|
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
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
4172
|
-
const slug = config.
|
|
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.
|
|
3748
|
+
source_default.gray("Organization: ") + source_default.cyan(config.orgName) + slug
|
|
4175
3749
|
);
|
|
4176
3750
|
}
|
|
4177
3751
|
} catch {
|
|
4178
3752
|
}
|
|
4179
3753
|
}
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
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)} ${"
|
|
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(
|
|
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
|
|
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(
|
|
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.
|
|
3942
|
+
if (deployment.mcpUrl) {
|
|
4322
3943
|
console.log(
|
|
4323
|
-
source_default.white("
|
|
3944
|
+
source_default.white("MCP URL: ") + source_default.cyan(deployment.mcpUrl)
|
|
4324
3945
|
);
|
|
4325
3946
|
}
|
|
4326
|
-
if (deployment.
|
|
3947
|
+
if (deployment.gitBranch) {
|
|
4327
3948
|
console.log(
|
|
4328
|
-
source_default.white("
|
|
3949
|
+
source_default.white("Branch: ") + source_default.gray(deployment.gitBranch)
|
|
4329
3950
|
);
|
|
4330
3951
|
}
|
|
4331
|
-
|
|
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("
|
|
3954
|
+
source_default.white("Commit: ") + source_default.gray(deployment.gitCommitSha.substring(0, 7))
|
|
4340
3955
|
);
|
|
4341
3956
|
}
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
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
|
|
4396
|
-
|
|
4397
|
-
|
|
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
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
))
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
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
|
-
|
|
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 ${
|
|
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
|
-
|
|
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("
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
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
|
-
|
|
4508
|
-
|
|
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
|
|
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
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
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
|
|
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
|
-
|
|
4682
|
-
status: "stopped"
|
|
4683
|
-
});
|
|
4211
|
+
await api.stopDeployment(deploymentId);
|
|
4684
4212
|
console.log(source_default.green.bold(`
|
|
4685
|
-
\u2713 Deployment stopped
|
|
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
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
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
|
|
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", "
|
|
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
|
|
4757
|
-
const activeId = config.
|
|
4758
|
-
if (
|
|
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
|
|
4764
|
-
const isActive =
|
|
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 =
|
|
4767
|
-
const role = source_default.gray(` [${
|
|
4768
|
-
const name = isActive ? source_default.cyan.bold(
|
|
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 (
|
|
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
|
|
4791
|
-
if (
|
|
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 (
|
|
4796
|
-
const
|
|
4797
|
-
const slug2 =
|
|
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(
|
|
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.
|
|
4806
|
-
const selected = await promptOrgSelection(
|
|
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
|
-
|
|
4814
|
-
|
|
4815
|
-
|
|
4337
|
+
orgId: selected.id,
|
|
4338
|
+
orgName: selected.name,
|
|
4339
|
+
orgSlug: selected.slug ?? void 0
|
|
4816
4340
|
});
|
|
4817
4341
|
try {
|
|
4818
|
-
await api.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(
|