@mcp-use/cli 2.2.1 → 2.2.2-canary.1
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/README.md +62 -0
- package/dist/commands/auth.d.ts +13 -0
- package/dist/commands/auth.d.ts.map +1 -0
- package/dist/commands/deploy.d.ts +13 -0
- package/dist/commands/deploy.d.ts.map +1 -0
- package/dist/index.js +1214 -74
- package/dist/index.mjs +1209 -67
- package/dist/utils/api.d.ts +103 -0
- package/dist/utils/api.d.ts.map +1 -0
- package/dist/utils/config.d.ts +34 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/git.d.ts +45 -0
- package/dist/utils/git.d.ts.map +1 -0
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -24,17 +24,1136 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
));
|
|
25
25
|
|
|
26
26
|
// src/index.ts
|
|
27
|
-
var
|
|
27
|
+
var import_config4 = require("dotenv/config");
|
|
28
28
|
var import_commander = require("commander");
|
|
29
|
-
var
|
|
30
|
-
var
|
|
29
|
+
var import_node_child_process3 = require("child_process");
|
|
30
|
+
var import_node_fs3 = require("fs");
|
|
31
31
|
var import_promises = require("fs/promises");
|
|
32
|
-
var
|
|
33
|
-
var
|
|
32
|
+
var import_node_path3 = __toESM(require("path"));
|
|
33
|
+
var import_open3 = __toESM(require("open"));
|
|
34
|
+
var import_chalk3 = __toESM(require("chalk"));
|
|
35
|
+
|
|
36
|
+
// src/commands/auth.ts
|
|
34
37
|
var import_chalk = __toESM(require("chalk"));
|
|
38
|
+
var import_node_http = require("http");
|
|
39
|
+
var import_open = __toESM(require("open"));
|
|
40
|
+
|
|
41
|
+
// src/utils/config.ts
|
|
42
|
+
var import_node_fs = require("fs");
|
|
43
|
+
var import_node_path = __toESM(require("path"));
|
|
44
|
+
var import_node_os = __toESM(require("os"));
|
|
45
|
+
var CONFIG_DIR = import_node_path.default.join(import_node_os.default.homedir(), ".mcp-use");
|
|
46
|
+
var CONFIG_FILE = import_node_path.default.join(CONFIG_DIR, "config.json");
|
|
47
|
+
var DEFAULT_API_URL = process.env.MCP_API_URL ? process.env.MCP_API_URL.replace(/\/api\/v1$/, "") + "/api/v1" : "https://cloud.mcp-use.com/api/v1";
|
|
48
|
+
var DEFAULT_WEB_URL = process.env.MCP_WEB_URL ? process.env.MCP_WEB_URL : "https://mcp-use.com";
|
|
49
|
+
async function ensureConfigDir() {
|
|
50
|
+
try {
|
|
51
|
+
await import_node_fs.promises.mkdir(CONFIG_DIR, { recursive: true });
|
|
52
|
+
} catch (error) {
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async function readConfig() {
|
|
56
|
+
try {
|
|
57
|
+
const content = await import_node_fs.promises.readFile(CONFIG_FILE, "utf-8");
|
|
58
|
+
return JSON.parse(content);
|
|
59
|
+
} catch (error) {
|
|
60
|
+
return {};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async function writeConfig(config) {
|
|
64
|
+
await ensureConfigDir();
|
|
65
|
+
await import_node_fs.promises.writeFile(CONFIG_FILE, JSON.stringify(config, null, 2), "utf-8");
|
|
66
|
+
}
|
|
67
|
+
async function deleteConfig() {
|
|
68
|
+
try {
|
|
69
|
+
await import_node_fs.promises.unlink(CONFIG_FILE);
|
|
70
|
+
} catch (error) {
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
async function getApiUrl() {
|
|
74
|
+
const config = await readConfig();
|
|
75
|
+
return config.apiUrl || DEFAULT_API_URL;
|
|
76
|
+
}
|
|
77
|
+
async function getApiKey() {
|
|
78
|
+
const config = await readConfig();
|
|
79
|
+
return config.apiKey || null;
|
|
80
|
+
}
|
|
81
|
+
async function isLoggedIn() {
|
|
82
|
+
const apiKey = await getApiKey();
|
|
83
|
+
return !!apiKey;
|
|
84
|
+
}
|
|
85
|
+
async function getWebUrl() {
|
|
86
|
+
return DEFAULT_WEB_URL;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// src/utils/api.ts
|
|
90
|
+
var McpUseAPI = class _McpUseAPI {
|
|
91
|
+
baseUrl;
|
|
92
|
+
apiKey;
|
|
93
|
+
constructor(baseUrl, apiKey) {
|
|
94
|
+
this.baseUrl = baseUrl || "";
|
|
95
|
+
this.apiKey = apiKey;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Initialize API client with config
|
|
99
|
+
*/
|
|
100
|
+
static async create() {
|
|
101
|
+
const baseUrl = await getApiUrl();
|
|
102
|
+
const apiKey = await getApiKey();
|
|
103
|
+
return new _McpUseAPI(baseUrl, apiKey ?? void 0);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Make authenticated request
|
|
107
|
+
*/
|
|
108
|
+
async request(endpoint, options = {}) {
|
|
109
|
+
const url = `${this.baseUrl}${endpoint}`;
|
|
110
|
+
const headers = {
|
|
111
|
+
"Content-Type": "application/json",
|
|
112
|
+
...options.headers || {}
|
|
113
|
+
};
|
|
114
|
+
if (this.apiKey) {
|
|
115
|
+
headers["x-api-key"] = this.apiKey;
|
|
116
|
+
}
|
|
117
|
+
const response = await fetch(url, {
|
|
118
|
+
...options,
|
|
119
|
+
headers
|
|
120
|
+
});
|
|
121
|
+
if (!response.ok) {
|
|
122
|
+
const error = await response.text();
|
|
123
|
+
throw new Error(`API request failed: ${response.status} ${error}`);
|
|
124
|
+
}
|
|
125
|
+
return response.json();
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Create API key using JWT token
|
|
129
|
+
*/
|
|
130
|
+
async createApiKey(jwtToken, name = "CLI") {
|
|
131
|
+
const url = `${this.baseUrl}/api-key`;
|
|
132
|
+
const response = await fetch(url, {
|
|
133
|
+
method: "POST",
|
|
134
|
+
headers: {
|
|
135
|
+
"Content-Type": "application/json",
|
|
136
|
+
Authorization: `Bearer ${jwtToken}`
|
|
137
|
+
},
|
|
138
|
+
body: JSON.stringify({ name })
|
|
139
|
+
});
|
|
140
|
+
if (!response.ok) {
|
|
141
|
+
const error = await response.text();
|
|
142
|
+
throw new Error(`Failed to create API key: ${response.status} ${error}`);
|
|
143
|
+
}
|
|
144
|
+
return response.json();
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Test authentication
|
|
148
|
+
*/
|
|
149
|
+
async testAuth() {
|
|
150
|
+
return this.request("/test-auth");
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Create deployment
|
|
154
|
+
*/
|
|
155
|
+
async createDeployment(request) {
|
|
156
|
+
return this.request("/deployments", {
|
|
157
|
+
method: "POST",
|
|
158
|
+
body: JSON.stringify(request)
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Get deployment by ID
|
|
163
|
+
*/
|
|
164
|
+
async getDeployment(deploymentId) {
|
|
165
|
+
return this.request(`/deployments/${deploymentId}`);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Stream deployment logs
|
|
169
|
+
*/
|
|
170
|
+
async *streamDeploymentLogs(deploymentId) {
|
|
171
|
+
const url = `${this.baseUrl}/deployments/${deploymentId}/logs/stream`;
|
|
172
|
+
const headers = {};
|
|
173
|
+
if (this.apiKey) {
|
|
174
|
+
headers["x-api-key"] = this.apiKey;
|
|
175
|
+
}
|
|
176
|
+
const response = await fetch(url, { headers });
|
|
177
|
+
if (!response.ok) {
|
|
178
|
+
throw new Error(`Failed to stream logs: ${response.status}`);
|
|
179
|
+
}
|
|
180
|
+
if (!response.body) {
|
|
181
|
+
throw new Error("Response body is null");
|
|
182
|
+
}
|
|
183
|
+
const reader = response.body.getReader();
|
|
184
|
+
const decoder = new TextDecoder();
|
|
185
|
+
let buffer = "";
|
|
186
|
+
try {
|
|
187
|
+
while (true) {
|
|
188
|
+
const { done, value } = await reader.read();
|
|
189
|
+
if (done) break;
|
|
190
|
+
buffer += decoder.decode(value, { stream: true });
|
|
191
|
+
const lines = buffer.split("\n");
|
|
192
|
+
buffer = lines.pop() || "";
|
|
193
|
+
for (const line of lines) {
|
|
194
|
+
if (line.startsWith("data: ")) {
|
|
195
|
+
const data = line.slice(6);
|
|
196
|
+
try {
|
|
197
|
+
const parsed = JSON.parse(data);
|
|
198
|
+
if (parsed.log) {
|
|
199
|
+
yield parsed.log;
|
|
200
|
+
} else if (parsed.error) {
|
|
201
|
+
throw new Error(parsed.error);
|
|
202
|
+
}
|
|
203
|
+
} catch (e) {
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
} finally {
|
|
209
|
+
reader.releaseLock();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Create deployment with source code upload
|
|
214
|
+
*/
|
|
215
|
+
async createDeploymentWithUpload(request, filePath) {
|
|
216
|
+
const { readFile } = await import("fs/promises");
|
|
217
|
+
const { basename } = await import("path");
|
|
218
|
+
const { stat } = await import("fs/promises");
|
|
219
|
+
const stats = await stat(filePath);
|
|
220
|
+
const maxSize = 2 * 1024 * 1024;
|
|
221
|
+
if (stats.size > maxSize) {
|
|
222
|
+
throw new Error(
|
|
223
|
+
`File size (${(stats.size / 1024 / 1024).toFixed(2)}MB) exceeds maximum of 2MB`
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
const fileBuffer = await readFile(filePath);
|
|
227
|
+
const filename = basename(filePath);
|
|
228
|
+
const formData = new FormData();
|
|
229
|
+
const blob = new Blob([fileBuffer], { type: "application/gzip" });
|
|
230
|
+
formData.append("source_file", blob, filename);
|
|
231
|
+
formData.append("name", request.name);
|
|
232
|
+
formData.append("source_type", "upload");
|
|
233
|
+
if (request.source.type === "upload") {
|
|
234
|
+
formData.append("runtime", request.source.runtime || "node");
|
|
235
|
+
formData.append("port", String(request.source.port || 3e3));
|
|
236
|
+
if (request.source.startCommand) {
|
|
237
|
+
formData.append("startCommand", request.source.startCommand);
|
|
238
|
+
}
|
|
239
|
+
if (request.source.buildCommand) {
|
|
240
|
+
formData.append("buildCommand", request.source.buildCommand);
|
|
241
|
+
}
|
|
242
|
+
if (request.source.env && Object.keys(request.source.env).length > 0) {
|
|
243
|
+
formData.append("env", JSON.stringify(request.source.env));
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
if (request.customDomain) {
|
|
247
|
+
formData.append("customDomain", request.customDomain);
|
|
248
|
+
}
|
|
249
|
+
if (request.healthCheckPath) {
|
|
250
|
+
formData.append("healthCheckPath", request.healthCheckPath);
|
|
251
|
+
}
|
|
252
|
+
const url = `${this.baseUrl}/deployments`;
|
|
253
|
+
const headers = {};
|
|
254
|
+
if (this.apiKey) {
|
|
255
|
+
headers["x-api-key"] = this.apiKey;
|
|
256
|
+
}
|
|
257
|
+
const response = await fetch(url, {
|
|
258
|
+
method: "POST",
|
|
259
|
+
headers,
|
|
260
|
+
body: formData
|
|
261
|
+
});
|
|
262
|
+
if (!response.ok) {
|
|
263
|
+
const error = await response.text();
|
|
264
|
+
throw new Error(`Deployment failed: ${error}`);
|
|
265
|
+
}
|
|
266
|
+
return response.json();
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
// src/commands/auth.ts
|
|
271
|
+
var LOGIN_TIMEOUT = 3e5;
|
|
272
|
+
async function findAvailablePort(startPort = 8765) {
|
|
273
|
+
for (let port = startPort; port < startPort + 100; port++) {
|
|
274
|
+
try {
|
|
275
|
+
await new Promise((resolve, reject) => {
|
|
276
|
+
const server = (0, import_node_http.createServer)();
|
|
277
|
+
server.once("error", reject);
|
|
278
|
+
server.once("listening", () => {
|
|
279
|
+
server.close();
|
|
280
|
+
resolve();
|
|
281
|
+
});
|
|
282
|
+
server.listen(port);
|
|
283
|
+
});
|
|
284
|
+
return port;
|
|
285
|
+
} catch {
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
throw new Error("No available ports found");
|
|
290
|
+
}
|
|
291
|
+
async function startCallbackServer(port) {
|
|
292
|
+
return new Promise((resolve, reject) => {
|
|
293
|
+
let tokenResolver = null;
|
|
294
|
+
const tokenPromise = new Promise((res) => {
|
|
295
|
+
tokenResolver = res;
|
|
296
|
+
});
|
|
297
|
+
const server = (0, import_node_http.createServer)((req, res) => {
|
|
298
|
+
if (req.url?.startsWith("/callback")) {
|
|
299
|
+
const url = new URL(req.url, `http://localhost:${port}`);
|
|
300
|
+
const token = url.searchParams.get("token");
|
|
301
|
+
if (token && tokenResolver) {
|
|
302
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
303
|
+
res.end(`
|
|
304
|
+
<!DOCTYPE html>
|
|
305
|
+
<html>
|
|
306
|
+
<head>
|
|
307
|
+
<title>Login Successful</title>
|
|
308
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
309
|
+
<style>
|
|
310
|
+
* {
|
|
311
|
+
margin: 0;
|
|
312
|
+
padding: 0;
|
|
313
|
+
box-sizing: border-box;
|
|
314
|
+
}
|
|
315
|
+
body {
|
|
316
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
317
|
+
display: flex;
|
|
318
|
+
justify-content: center;
|
|
319
|
+
align-items: center;
|
|
320
|
+
min-height: 100vh;
|
|
321
|
+
background: #000;
|
|
322
|
+
padding: 1rem;
|
|
323
|
+
}
|
|
324
|
+
.container {
|
|
325
|
+
width: 100%;
|
|
326
|
+
max-width: 28rem;
|
|
327
|
+
padding: 3rem;
|
|
328
|
+
text-align: center;
|
|
329
|
+
-webkit-backdrop-filter: blur(40px);
|
|
330
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
331
|
+
border-radius: 1.5rem;
|
|
332
|
+
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
|
|
333
|
+
}
|
|
334
|
+
.icon-container {
|
|
335
|
+
display: inline-flex;
|
|
336
|
+
align-items: center;
|
|
337
|
+
justify-content: center;
|
|
338
|
+
width: 6rem;
|
|
339
|
+
height: 6rem;
|
|
340
|
+
margin-bottom: 2rem;
|
|
341
|
+
background: rgba(255, 255, 255, 0.1);
|
|
342
|
+
backdrop-filter: blur(10px);
|
|
343
|
+
-webkit-backdrop-filter: blur(10px);
|
|
344
|
+
border-radius: 50%;
|
|
345
|
+
}
|
|
346
|
+
.checkmark {
|
|
347
|
+
font-size: 4rem;
|
|
348
|
+
color: #fff;
|
|
349
|
+
line-height: 1;
|
|
350
|
+
animation: scaleIn 0.5s ease-out;
|
|
351
|
+
}
|
|
352
|
+
@keyframes scaleIn {
|
|
353
|
+
from {
|
|
354
|
+
transform: scale(0);
|
|
355
|
+
opacity: 0;
|
|
356
|
+
}
|
|
357
|
+
to {
|
|
358
|
+
transform: scale(1);
|
|
359
|
+
opacity: 1;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
h1 {
|
|
363
|
+
color: #fff;
|
|
364
|
+
margin: 0 0 1rem 0;
|
|
365
|
+
font-size: 2.5rem;
|
|
366
|
+
font-weight: 700;
|
|
367
|
+
letter-spacing: -0.025em;
|
|
368
|
+
}
|
|
369
|
+
p {
|
|
370
|
+
color: rgba(255, 255, 255, 0.8);
|
|
371
|
+
margin: 0 0 2rem 0;
|
|
372
|
+
font-size: 1.125rem;
|
|
373
|
+
line-height: 1.5;
|
|
374
|
+
}
|
|
375
|
+
.spinner {
|
|
376
|
+
display: inline-block;
|
|
377
|
+
width: 2rem;
|
|
378
|
+
height: 2rem;
|
|
379
|
+
border: 3px solid rgba(255, 255, 255, 0.3);
|
|
380
|
+
border-top-color: #fff;
|
|
381
|
+
border-radius: 50%;
|
|
382
|
+
animation: spin 0.8s linear infinite;
|
|
383
|
+
}
|
|
384
|
+
@keyframes spin {
|
|
385
|
+
to { transform: rotate(360deg); }
|
|
386
|
+
}
|
|
387
|
+
.footer {
|
|
388
|
+
margin-top: 2rem;
|
|
389
|
+
color: rgba(255, 255, 255, 0.6);
|
|
390
|
+
font-size: 0.875rem;
|
|
391
|
+
}
|
|
392
|
+
</style>
|
|
393
|
+
</head>
|
|
394
|
+
<body>
|
|
395
|
+
<div class="container">
|
|
396
|
+
<h1>Authentication Successful!</h1>
|
|
397
|
+
<p>You can now close this window and return to the CLI.</p>
|
|
398
|
+
</div>
|
|
399
|
+
</body>
|
|
400
|
+
</html>
|
|
401
|
+
`);
|
|
402
|
+
tokenResolver(token);
|
|
403
|
+
} else {
|
|
404
|
+
res.writeHead(400, { "Content-Type": "text/html" });
|
|
405
|
+
res.end(`
|
|
406
|
+
<!DOCTYPE html>
|
|
407
|
+
<html>
|
|
408
|
+
<head>
|
|
409
|
+
<title>Login Failed</title>
|
|
410
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
411
|
+
<style>
|
|
412
|
+
* {
|
|
413
|
+
margin: 0;
|
|
414
|
+
padding: 0;
|
|
415
|
+
box-sizing: border-box;
|
|
416
|
+
}
|
|
417
|
+
body {
|
|
418
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
419
|
+
display: flex;
|
|
420
|
+
justify-content: center;
|
|
421
|
+
align-items: center;
|
|
422
|
+
min-height: 100vh;
|
|
423
|
+
background: #000;
|
|
424
|
+
padding: 1rem;
|
|
425
|
+
}
|
|
426
|
+
.container {
|
|
427
|
+
width: 100%;
|
|
428
|
+
max-width: 28rem;
|
|
429
|
+
padding: 3rem;
|
|
430
|
+
text-align: center;
|
|
431
|
+
background: rgba(255, 255, 255, 0.1);
|
|
432
|
+
backdrop-filter: blur(40px);
|
|
433
|
+
-webkit-backdrop-filter: blur(40px);
|
|
434
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
435
|
+
border-radius: 1.5rem;
|
|
436
|
+
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
|
|
437
|
+
}
|
|
438
|
+
.icon-container {
|
|
439
|
+
display: inline-flex;
|
|
440
|
+
align-items: center;
|
|
441
|
+
justify-content: center;
|
|
442
|
+
width: 6rem;
|
|
443
|
+
height: 6rem;
|
|
444
|
+
margin-bottom: 2rem;
|
|
445
|
+
background: rgba(255, 255, 255, 0.1);
|
|
446
|
+
backdrop-filter: blur(10px);
|
|
447
|
+
-webkit-backdrop-filter: blur(10px);
|
|
448
|
+
border-radius: 50%;
|
|
449
|
+
}
|
|
450
|
+
.cross {
|
|
451
|
+
font-size: 4rem;
|
|
452
|
+
color: #fff;
|
|
453
|
+
line-height: 1;
|
|
454
|
+
}
|
|
455
|
+
h1 {
|
|
456
|
+
color: #fff;
|
|
457
|
+
margin: 0 0 1rem 0;
|
|
458
|
+
font-size: 2.5rem;
|
|
459
|
+
font-weight: 700;
|
|
460
|
+
letter-spacing: -0.025em;
|
|
461
|
+
}
|
|
462
|
+
p {
|
|
463
|
+
color: rgba(255, 255, 255, 0.8);
|
|
464
|
+
margin: 0;
|
|
465
|
+
font-size: 1.125rem;
|
|
466
|
+
line-height: 1.5;
|
|
467
|
+
}
|
|
468
|
+
</style>
|
|
469
|
+
</head>
|
|
470
|
+
<body>
|
|
471
|
+
<div class="container">
|
|
472
|
+
<div class="icon-container">
|
|
473
|
+
<div class="cross">\u2717</div>
|
|
474
|
+
</div>
|
|
475
|
+
<h1>Login Failed</h1>
|
|
476
|
+
<p>No token received. Please try again.</p>
|
|
477
|
+
</div>
|
|
478
|
+
</body>
|
|
479
|
+
</html>
|
|
480
|
+
`);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
server.listen(port, () => {
|
|
485
|
+
resolve({ server, token: tokenPromise });
|
|
486
|
+
});
|
|
487
|
+
server.on("error", reject);
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
async function loginCommand() {
|
|
491
|
+
try {
|
|
492
|
+
if (await isLoggedIn()) {
|
|
493
|
+
console.log(
|
|
494
|
+
import_chalk.default.yellow(
|
|
495
|
+
"\u26A0\uFE0F You are already logged in. Run 'mcp-use logout' first if you want to login with a different account."
|
|
496
|
+
)
|
|
497
|
+
);
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
console.log(import_chalk.default.cyan.bold("\u{1F510} Logging in to mcp-use cloud...\n"));
|
|
501
|
+
const port = await findAvailablePort();
|
|
502
|
+
const redirectUri = `http://localhost:${port}/callback`;
|
|
503
|
+
console.log(import_chalk.default.gray(`Starting local server on port ${port}...`));
|
|
504
|
+
const { server, token } = await startCallbackServer(port);
|
|
505
|
+
const webUrl = await getWebUrl();
|
|
506
|
+
const loginUrl = `${webUrl}/auth/cli?redirect_uri=${encodeURIComponent(redirectUri)}`;
|
|
507
|
+
console.log(import_chalk.default.gray(`Opening browser to ${webUrl}/auth/cli...
|
|
508
|
+
`));
|
|
509
|
+
console.log(
|
|
510
|
+
import_chalk.default.white(
|
|
511
|
+
"If the browser doesn't open automatically, please visit:\n" + import_chalk.default.cyan(loginUrl)
|
|
512
|
+
)
|
|
513
|
+
);
|
|
514
|
+
await (0, import_open.default)(loginUrl);
|
|
515
|
+
console.log(
|
|
516
|
+
import_chalk.default.gray("\nWaiting for authentication... (this may take a moment)")
|
|
517
|
+
);
|
|
518
|
+
const jwtToken = await Promise.race([
|
|
519
|
+
token,
|
|
520
|
+
new Promise(
|
|
521
|
+
(_, reject) => setTimeout(
|
|
522
|
+
() => reject(new Error("Login timeout - please try again")),
|
|
523
|
+
LOGIN_TIMEOUT
|
|
524
|
+
)
|
|
525
|
+
)
|
|
526
|
+
]);
|
|
527
|
+
server.close();
|
|
528
|
+
console.log(
|
|
529
|
+
import_chalk.default.gray("Received authentication token, creating API key...")
|
|
530
|
+
);
|
|
531
|
+
const api = await McpUseAPI.create();
|
|
532
|
+
const apiKeyResponse = await api.createApiKey(jwtToken, "CLI");
|
|
533
|
+
await writeConfig({
|
|
534
|
+
apiKey: apiKeyResponse.api_key
|
|
535
|
+
});
|
|
536
|
+
console.log(import_chalk.default.green.bold("\n\u2713 Successfully logged in!"));
|
|
537
|
+
console.log(
|
|
538
|
+
import_chalk.default.gray(
|
|
539
|
+
`
|
|
540
|
+
Your API key has been saved to ${import_chalk.default.white("~/.mcp-use/config.json")}`
|
|
541
|
+
)
|
|
542
|
+
);
|
|
543
|
+
console.log(
|
|
544
|
+
import_chalk.default.gray(
|
|
545
|
+
"You can now deploy your MCP servers with " + import_chalk.default.white("mcp-use deploy")
|
|
546
|
+
)
|
|
547
|
+
);
|
|
548
|
+
process.exit(0);
|
|
549
|
+
} catch (error) {
|
|
550
|
+
console.error(
|
|
551
|
+
import_chalk.default.red.bold("\n\u2717 Login failed:"),
|
|
552
|
+
import_chalk.default.red(error instanceof Error ? error.message : "Unknown error")
|
|
553
|
+
);
|
|
554
|
+
process.exit(1);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
async function logoutCommand() {
|
|
558
|
+
try {
|
|
559
|
+
if (!await isLoggedIn()) {
|
|
560
|
+
console.log(import_chalk.default.yellow("\u26A0\uFE0F You are not logged in."));
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
console.log(import_chalk.default.cyan.bold("\u{1F513} Logging out...\n"));
|
|
564
|
+
await deleteConfig();
|
|
565
|
+
console.log(import_chalk.default.green.bold("\u2713 Successfully logged out!"));
|
|
566
|
+
console.log(
|
|
567
|
+
import_chalk.default.gray(
|
|
568
|
+
"\nYour local config has been deleted. The API key will remain active until revoked from the web interface."
|
|
569
|
+
)
|
|
570
|
+
);
|
|
571
|
+
} catch (error) {
|
|
572
|
+
console.error(
|
|
573
|
+
import_chalk.default.red.bold("\n\u2717 Logout failed:"),
|
|
574
|
+
import_chalk.default.red(error instanceof Error ? error.message : "Unknown error")
|
|
575
|
+
);
|
|
576
|
+
process.exit(1);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
async function whoamiCommand() {
|
|
580
|
+
try {
|
|
581
|
+
if (!await isLoggedIn()) {
|
|
582
|
+
console.log(import_chalk.default.yellow("\u26A0\uFE0F You are not logged in."));
|
|
583
|
+
console.log(
|
|
584
|
+
import_chalk.default.gray("Run " + import_chalk.default.white("mcp-use login") + " to get started.")
|
|
585
|
+
);
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
console.log(import_chalk.default.cyan.bold("\u{1F464} Current user:\n"));
|
|
589
|
+
const api = await McpUseAPI.create();
|
|
590
|
+
const authInfo = await api.testAuth();
|
|
591
|
+
console.log(import_chalk.default.white("Email: ") + import_chalk.default.cyan(authInfo.email));
|
|
592
|
+
console.log(import_chalk.default.white("User ID: ") + import_chalk.default.gray(authInfo.user_id));
|
|
593
|
+
const apiKey = await getApiKey();
|
|
594
|
+
if (apiKey) {
|
|
595
|
+
const masked = apiKey.substring(0, 8) + "..." + apiKey.substring(apiKey.length - 4);
|
|
596
|
+
console.log(import_chalk.default.white("API Key: ") + import_chalk.default.gray(masked));
|
|
597
|
+
}
|
|
598
|
+
} catch (error) {
|
|
599
|
+
console.error(
|
|
600
|
+
import_chalk.default.red.bold("\n\u2717 Failed to get user info:"),
|
|
601
|
+
import_chalk.default.red(error instanceof Error ? error.message : "Unknown error")
|
|
602
|
+
);
|
|
603
|
+
process.exit(1);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// src/commands/deploy.ts
|
|
608
|
+
var import_chalk2 = __toESM(require("chalk"));
|
|
609
|
+
var import_node_fs2 = require("fs");
|
|
610
|
+
var import_node_path2 = __toESM(require("path"));
|
|
611
|
+
var import_node_os2 = __toESM(require("os"));
|
|
612
|
+
var import_node_child_process2 = require("child_process");
|
|
613
|
+
var import_node_util2 = require("util");
|
|
614
|
+
|
|
615
|
+
// src/utils/git.ts
|
|
616
|
+
var import_node_child_process = require("child_process");
|
|
617
|
+
var import_node_util = require("util");
|
|
618
|
+
var execAsync = (0, import_node_util.promisify)(import_node_child_process.exec);
|
|
619
|
+
async function gitCommand(command, cwd = process.cwd()) {
|
|
620
|
+
try {
|
|
621
|
+
const { stdout } = await execAsync(command, { cwd });
|
|
622
|
+
return stdout.trim();
|
|
623
|
+
} catch (error) {
|
|
624
|
+
return null;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
async function isGitRepo(cwd = process.cwd()) {
|
|
628
|
+
const result = await gitCommand("git rev-parse --is-inside-work-tree", cwd);
|
|
629
|
+
return result === "true";
|
|
630
|
+
}
|
|
631
|
+
async function getRemoteUrl(cwd = process.cwd()) {
|
|
632
|
+
return gitCommand("git config --get remote.origin.url", cwd);
|
|
633
|
+
}
|
|
634
|
+
function parseGitHubUrl(url) {
|
|
635
|
+
const sshMatch = url.match(/git@github\.com:([^/]+)\/(.+?)(?:\.git)?$/);
|
|
636
|
+
const httpsMatch = url.match(
|
|
637
|
+
/https:\/\/github\.com\/([^/]+)\/(.+?)(?:\.git)?$/
|
|
638
|
+
);
|
|
639
|
+
const match = sshMatch || httpsMatch;
|
|
640
|
+
if (!match) return null;
|
|
641
|
+
return {
|
|
642
|
+
owner: match[1],
|
|
643
|
+
repo: match[2]
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
async function getCurrentBranch(cwd = process.cwd()) {
|
|
647
|
+
return gitCommand("git rev-parse --abbrev-ref HEAD", cwd);
|
|
648
|
+
}
|
|
649
|
+
async function getCommitSha(cwd = process.cwd()) {
|
|
650
|
+
return gitCommand("git rev-parse HEAD", cwd);
|
|
651
|
+
}
|
|
652
|
+
async function getCommitMessage(cwd = process.cwd()) {
|
|
653
|
+
return gitCommand("git log -1 --pretty=%B", cwd);
|
|
654
|
+
}
|
|
655
|
+
async function getGitInfo(cwd = process.cwd()) {
|
|
656
|
+
const isRepo = await isGitRepo(cwd);
|
|
657
|
+
if (!isRepo) {
|
|
658
|
+
return { isGitRepo: false };
|
|
659
|
+
}
|
|
660
|
+
const remoteUrl = await getRemoteUrl(cwd);
|
|
661
|
+
const branch = await getCurrentBranch(cwd);
|
|
662
|
+
const commitSha = await getCommitSha(cwd);
|
|
663
|
+
const commitMessage = await getCommitMessage(cwd);
|
|
664
|
+
let owner;
|
|
665
|
+
let repo;
|
|
666
|
+
if (remoteUrl) {
|
|
667
|
+
const parsed = parseGitHubUrl(remoteUrl);
|
|
668
|
+
if (parsed) {
|
|
669
|
+
owner = parsed.owner;
|
|
670
|
+
repo = parsed.repo;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
return {
|
|
674
|
+
isGitRepo: true,
|
|
675
|
+
remoteUrl: remoteUrl || void 0,
|
|
676
|
+
owner,
|
|
677
|
+
repo,
|
|
678
|
+
branch: branch || void 0,
|
|
679
|
+
commitSha: commitSha || void 0,
|
|
680
|
+
commitMessage: commitMessage || void 0
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
function isGitHubUrl(url) {
|
|
684
|
+
return url.includes("github.com");
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// src/commands/deploy.ts
|
|
688
|
+
var import_open2 = __toESM(require("open"));
|
|
689
|
+
var execAsync2 = (0, import_node_util2.promisify)(import_node_child_process2.exec);
|
|
690
|
+
async function isMcpProject(cwd = process.cwd()) {
|
|
691
|
+
try {
|
|
692
|
+
const packageJsonPath = import_node_path2.default.join(cwd, "package.json");
|
|
693
|
+
const content = await import_node_fs2.promises.readFile(packageJsonPath, "utf-8");
|
|
694
|
+
const packageJson2 = JSON.parse(content);
|
|
695
|
+
const hasMcpDeps = packageJson2.dependencies?.["mcp-use"] || packageJson2.dependencies?.["@modelcontextprotocol/sdk"] || packageJson2.devDependencies?.["mcp-use"] || packageJson2.devDependencies?.["@modelcontextprotocol/sdk"];
|
|
696
|
+
const hasMcpScripts = packageJson2.scripts?.mcp || packageJson2.scripts?.["mcp:dev"];
|
|
697
|
+
return !!(hasMcpDeps || hasMcpScripts);
|
|
698
|
+
} catch {
|
|
699
|
+
return false;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
async function getProjectName(cwd = process.cwd()) {
|
|
703
|
+
try {
|
|
704
|
+
const packageJsonPath = import_node_path2.default.join(cwd, "package.json");
|
|
705
|
+
const content = await import_node_fs2.promises.readFile(packageJsonPath, "utf-8");
|
|
706
|
+
const packageJson2 = JSON.parse(content);
|
|
707
|
+
if (packageJson2.name) {
|
|
708
|
+
return packageJson2.name;
|
|
709
|
+
}
|
|
710
|
+
} catch {
|
|
711
|
+
}
|
|
712
|
+
return import_node_path2.default.basename(cwd);
|
|
713
|
+
}
|
|
714
|
+
async function detectBuildCommand(cwd = process.cwd()) {
|
|
715
|
+
try {
|
|
716
|
+
const packageJsonPath = import_node_path2.default.join(cwd, "package.json");
|
|
717
|
+
const content = await import_node_fs2.promises.readFile(packageJsonPath, "utf-8");
|
|
718
|
+
const packageJson2 = JSON.parse(content);
|
|
719
|
+
if (packageJson2.scripts?.build) {
|
|
720
|
+
return "npm run build";
|
|
721
|
+
}
|
|
722
|
+
} catch {
|
|
723
|
+
}
|
|
724
|
+
return void 0;
|
|
725
|
+
}
|
|
726
|
+
async function detectStartCommand(cwd = process.cwd()) {
|
|
727
|
+
try {
|
|
728
|
+
const packageJsonPath = import_node_path2.default.join(cwd, "package.json");
|
|
729
|
+
const content = await import_node_fs2.promises.readFile(packageJsonPath, "utf-8");
|
|
730
|
+
const packageJson2 = JSON.parse(content);
|
|
731
|
+
if (packageJson2.scripts?.start) {
|
|
732
|
+
return "npm start";
|
|
733
|
+
}
|
|
734
|
+
if (packageJson2.main) {
|
|
735
|
+
return `node ${packageJson2.main}`;
|
|
736
|
+
}
|
|
737
|
+
} catch {
|
|
738
|
+
}
|
|
739
|
+
return void 0;
|
|
740
|
+
}
|
|
741
|
+
async function detectRuntime(cwd = process.cwd()) {
|
|
742
|
+
try {
|
|
743
|
+
const pythonFiles = ["requirements.txt", "pyproject.toml", "setup.py"];
|
|
744
|
+
for (const file of pythonFiles) {
|
|
745
|
+
try {
|
|
746
|
+
await import_node_fs2.promises.access(import_node_path2.default.join(cwd, file));
|
|
747
|
+
return "python";
|
|
748
|
+
} catch {
|
|
749
|
+
continue;
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
try {
|
|
753
|
+
await import_node_fs2.promises.access(import_node_path2.default.join(cwd, "package.json"));
|
|
754
|
+
return "node";
|
|
755
|
+
} catch {
|
|
756
|
+
}
|
|
757
|
+
} catch {
|
|
758
|
+
}
|
|
759
|
+
return "node";
|
|
760
|
+
}
|
|
761
|
+
async function prompt(question) {
|
|
762
|
+
const readline = await import("readline");
|
|
763
|
+
const rl = readline.createInterface({
|
|
764
|
+
input: process.stdin,
|
|
765
|
+
output: process.stdout
|
|
766
|
+
});
|
|
767
|
+
return new Promise((resolve) => {
|
|
768
|
+
rl.question(question, (answer) => {
|
|
769
|
+
rl.close();
|
|
770
|
+
resolve(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
|
|
771
|
+
});
|
|
772
|
+
});
|
|
773
|
+
}
|
|
774
|
+
async function createTarball(cwd) {
|
|
775
|
+
const tmpDir = import_node_os2.default.tmpdir();
|
|
776
|
+
const tarballPath = import_node_path2.default.join(tmpDir, `mcp-deploy-${Date.now()}.tar.gz`);
|
|
777
|
+
const excludePatterns = [
|
|
778
|
+
"node_modules",
|
|
779
|
+
".git",
|
|
780
|
+
"dist",
|
|
781
|
+
"build",
|
|
782
|
+
".next",
|
|
783
|
+
".venv",
|
|
784
|
+
"__pycache__",
|
|
785
|
+
"*.pyc",
|
|
786
|
+
".DS_Store",
|
|
787
|
+
".env",
|
|
788
|
+
".env.local",
|
|
789
|
+
"*.log"
|
|
790
|
+
];
|
|
791
|
+
const excludeFlags = excludePatterns.map((pattern) => `--exclude='${pattern}'`).join(" ");
|
|
792
|
+
const command = `tar ${excludeFlags} -czf "${tarballPath}" -C "${cwd}" .`;
|
|
793
|
+
try {
|
|
794
|
+
await execAsync2(command);
|
|
795
|
+
return tarballPath;
|
|
796
|
+
} catch (error) {
|
|
797
|
+
throw new Error(
|
|
798
|
+
`Failed to create tarball: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
799
|
+
);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
function formatFileSize(bytes) {
|
|
803
|
+
if (bytes === 0) return "0 B";
|
|
804
|
+
const k = 1024;
|
|
805
|
+
const sizes = ["B", "KB", "MB", "GB"];
|
|
806
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
807
|
+
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
|
|
808
|
+
}
|
|
809
|
+
async function displayDeploymentProgress(api, deployment) {
|
|
810
|
+
const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
811
|
+
let frameIndex = 0;
|
|
812
|
+
let spinnerInterval = null;
|
|
813
|
+
let lastStep = "";
|
|
814
|
+
const startSpinner = (message) => {
|
|
815
|
+
if (spinnerInterval) {
|
|
816
|
+
clearInterval(spinnerInterval);
|
|
817
|
+
}
|
|
818
|
+
process.stdout.write("\r\x1B[K");
|
|
819
|
+
spinnerInterval = setInterval(() => {
|
|
820
|
+
const frame = frames[frameIndex];
|
|
821
|
+
frameIndex = (frameIndex + 1) % frames.length;
|
|
822
|
+
process.stdout.write(
|
|
823
|
+
"\r" + import_chalk2.default.cyan(frame) + " " + import_chalk2.default.gray(message)
|
|
824
|
+
);
|
|
825
|
+
}, 80);
|
|
826
|
+
};
|
|
827
|
+
const stopSpinner = () => {
|
|
828
|
+
if (spinnerInterval) {
|
|
829
|
+
clearInterval(spinnerInterval);
|
|
830
|
+
spinnerInterval = null;
|
|
831
|
+
process.stdout.write("\r\x1B[K");
|
|
832
|
+
}
|
|
833
|
+
};
|
|
834
|
+
console.log();
|
|
835
|
+
startSpinner("Deploying...");
|
|
836
|
+
try {
|
|
837
|
+
for await (const log of api.streamDeploymentLogs(deployment.id)) {
|
|
838
|
+
try {
|
|
839
|
+
const logData = JSON.parse(log);
|
|
840
|
+
if (logData.step && logData.step !== lastStep) {
|
|
841
|
+
lastStep = logData.step;
|
|
842
|
+
const stepMessages = {
|
|
843
|
+
clone: "Preparing source code...",
|
|
844
|
+
analyze: "Analyzing project...",
|
|
845
|
+
build: "Building container image...",
|
|
846
|
+
deploy: "Deploying to cloud..."
|
|
847
|
+
};
|
|
848
|
+
const message = stepMessages[logData.step] || "Deploying...";
|
|
849
|
+
startSpinner(message);
|
|
850
|
+
}
|
|
851
|
+
if (logData.line) {
|
|
852
|
+
stopSpinner();
|
|
853
|
+
const levelColor = logData.level === "error" ? import_chalk2.default.red : logData.level === "warn" ? import_chalk2.default.yellow : import_chalk2.default.gray;
|
|
854
|
+
const stepPrefix = logData.step ? import_chalk2.default.cyan(`[${logData.step}]`) + " " : "";
|
|
855
|
+
console.log(stepPrefix + levelColor(logData.line));
|
|
856
|
+
}
|
|
857
|
+
} catch {
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
} catch (error) {
|
|
861
|
+
stopSpinner();
|
|
862
|
+
}
|
|
863
|
+
let checkCount = 0;
|
|
864
|
+
const maxChecks = 60;
|
|
865
|
+
let delay = 3e3;
|
|
866
|
+
const maxDelay = 1e4;
|
|
867
|
+
let lastDisplayedLogLength = 0;
|
|
868
|
+
while (checkCount < maxChecks) {
|
|
869
|
+
const currentDelay = delay;
|
|
870
|
+
await new Promise((resolve) => setTimeout(resolve, currentDelay));
|
|
871
|
+
const finalDeployment = await api.getDeployment(deployment.id);
|
|
872
|
+
if (finalDeployment.buildLogs && finalDeployment.buildLogs.length > lastDisplayedLogLength) {
|
|
873
|
+
const newLogs = finalDeployment.buildLogs.substring(
|
|
874
|
+
lastDisplayedLogLength
|
|
875
|
+
);
|
|
876
|
+
const logLines = newLogs.split("\n").filter((l) => l.trim());
|
|
877
|
+
for (const line of logLines) {
|
|
878
|
+
try {
|
|
879
|
+
const logData = JSON.parse(line);
|
|
880
|
+
if (logData.line) {
|
|
881
|
+
stopSpinner();
|
|
882
|
+
const levelColor = logData.level === "error" ? import_chalk2.default.red : logData.level === "warn" ? import_chalk2.default.yellow : import_chalk2.default.gray;
|
|
883
|
+
const stepPrefix = logData.step ? import_chalk2.default.cyan(`[${logData.step}]`) + " " : "";
|
|
884
|
+
console.log(stepPrefix + levelColor(logData.line));
|
|
885
|
+
}
|
|
886
|
+
} catch {
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
lastDisplayedLogLength = finalDeployment.buildLogs.length;
|
|
890
|
+
}
|
|
891
|
+
if (finalDeployment.status === "running") {
|
|
892
|
+
const mcpUrl = `https://${finalDeployment.domain}/mcp`;
|
|
893
|
+
const inspectorUrl = `https://inspector.mcp-use.com/inspect?autoConnect=${encodeURIComponent(mcpUrl)}`;
|
|
894
|
+
console.log(import_chalk2.default.green.bold("\u2713 Deployment successful!\n"));
|
|
895
|
+
console.log(import_chalk2.default.white("\u{1F310} MCP Server URL:"));
|
|
896
|
+
console.log(import_chalk2.default.cyan.bold(` ${mcpUrl}
|
|
897
|
+
`));
|
|
898
|
+
console.log(import_chalk2.default.white("\u{1F50D} Inspector URL:"));
|
|
899
|
+
console.log(import_chalk2.default.cyan.bold(` ${inspectorUrl}
|
|
900
|
+
`));
|
|
901
|
+
if (finalDeployment.customDomain) {
|
|
902
|
+
const customMcpUrl = `https://${finalDeployment.customDomain}/mcp`;
|
|
903
|
+
const customInspectorUrl = `https://inspector.mcp-use.com/inspect?autoConnect=${encodeURIComponent(customMcpUrl)}`;
|
|
904
|
+
console.log(import_chalk2.default.white("\u{1F517} Custom Domain:"));
|
|
905
|
+
console.log(import_chalk2.default.cyan.bold(` ${customMcpUrl}
|
|
906
|
+
`));
|
|
907
|
+
console.log(import_chalk2.default.white("\u{1F50D} Custom Inspector:"));
|
|
908
|
+
console.log(import_chalk2.default.cyan.bold(` ${customInspectorUrl}
|
|
909
|
+
`));
|
|
910
|
+
}
|
|
911
|
+
console.log(
|
|
912
|
+
import_chalk2.default.gray("Deployment ID: ") + import_chalk2.default.white(finalDeployment.id)
|
|
913
|
+
);
|
|
914
|
+
return;
|
|
915
|
+
} else if (finalDeployment.status === "failed") {
|
|
916
|
+
console.log(import_chalk2.default.red.bold("\u2717 Deployment failed\n"));
|
|
917
|
+
if (finalDeployment.error) {
|
|
918
|
+
console.log(import_chalk2.default.red("Error: ") + finalDeployment.error);
|
|
919
|
+
}
|
|
920
|
+
if (finalDeployment.buildLogs) {
|
|
921
|
+
console.log(import_chalk2.default.gray("\nBuild logs:"));
|
|
922
|
+
try {
|
|
923
|
+
const logs = finalDeployment.buildLogs.split("\n").filter((l) => l.trim());
|
|
924
|
+
for (const log of logs) {
|
|
925
|
+
try {
|
|
926
|
+
const logData = JSON.parse(log);
|
|
927
|
+
if (logData.line) {
|
|
928
|
+
console.log(import_chalk2.default.gray(` ${logData.line}`));
|
|
929
|
+
}
|
|
930
|
+
} catch {
|
|
931
|
+
console.log(import_chalk2.default.gray(` ${log}`));
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
} catch {
|
|
935
|
+
console.log(import_chalk2.default.gray(finalDeployment.buildLogs));
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
process.exit(1);
|
|
939
|
+
} else if (finalDeployment.status === "building") {
|
|
940
|
+
startSpinner("Building and deploying...");
|
|
941
|
+
checkCount++;
|
|
942
|
+
delay = Math.min(delay * 1.2, maxDelay);
|
|
943
|
+
} else {
|
|
944
|
+
console.log(
|
|
945
|
+
import_chalk2.default.yellow("\u26A0\uFE0F Deployment status: ") + finalDeployment.status
|
|
946
|
+
);
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
stopSpinner();
|
|
951
|
+
console.log(import_chalk2.default.yellow("\u26A0\uFE0F Deployment is taking longer than expected."));
|
|
952
|
+
console.log(
|
|
953
|
+
import_chalk2.default.gray("Check status with: ") + import_chalk2.default.white(`mcp-use status ${deployment.id}`)
|
|
954
|
+
);
|
|
955
|
+
}
|
|
956
|
+
async function deployCommand(options) {
|
|
957
|
+
try {
|
|
958
|
+
const cwd = process.cwd();
|
|
959
|
+
if (!await isLoggedIn()) {
|
|
960
|
+
console.log(import_chalk2.default.red("\u2717 You are not logged in."));
|
|
961
|
+
console.log(
|
|
962
|
+
import_chalk2.default.gray("Run " + import_chalk2.default.white("mcp-use login") + " to get started.")
|
|
963
|
+
);
|
|
964
|
+
process.exit(1);
|
|
965
|
+
}
|
|
966
|
+
console.log(import_chalk2.default.cyan.bold("\u{1F680} Deploying to mcp-use cloud...\n"));
|
|
967
|
+
const isMcp = await isMcpProject(cwd);
|
|
968
|
+
if (!isMcp) {
|
|
969
|
+
console.log(
|
|
970
|
+
import_chalk2.default.yellow(
|
|
971
|
+
"\u26A0\uFE0F This doesn't appear to be an MCP server project (no mcp-use or @modelcontextprotocol/sdk dependency found)."
|
|
972
|
+
)
|
|
973
|
+
);
|
|
974
|
+
const shouldContinue = await prompt(
|
|
975
|
+
import_chalk2.default.white("Continue anyway? (y/n): ")
|
|
976
|
+
);
|
|
977
|
+
if (!shouldContinue) {
|
|
978
|
+
console.log(import_chalk2.default.gray("Deployment cancelled."));
|
|
979
|
+
process.exit(0);
|
|
980
|
+
}
|
|
981
|
+
console.log();
|
|
982
|
+
}
|
|
983
|
+
const gitInfo = await getGitInfo(cwd);
|
|
984
|
+
if (!options.fromSource && gitInfo.isGitRepo && gitInfo.remoteUrl && isGitHubUrl(gitInfo.remoteUrl)) {
|
|
985
|
+
if (!gitInfo.owner || !gitInfo.repo) {
|
|
986
|
+
console.log(
|
|
987
|
+
import_chalk2.default.red(
|
|
988
|
+
"\u2717 Could not parse GitHub repository information from remote URL."
|
|
989
|
+
)
|
|
990
|
+
);
|
|
991
|
+
process.exit(1);
|
|
992
|
+
}
|
|
993
|
+
console.log(import_chalk2.default.white("GitHub repository detected:"));
|
|
994
|
+
console.log(
|
|
995
|
+
import_chalk2.default.gray(` Repository: `) + import_chalk2.default.cyan(`${gitInfo.owner}/${gitInfo.repo}`)
|
|
996
|
+
);
|
|
997
|
+
console.log(
|
|
998
|
+
import_chalk2.default.gray(` Branch: `) + import_chalk2.default.cyan(gitInfo.branch || "main")
|
|
999
|
+
);
|
|
1000
|
+
if (gitInfo.commitSha) {
|
|
1001
|
+
console.log(
|
|
1002
|
+
import_chalk2.default.gray(` Commit: `) + import_chalk2.default.gray(gitInfo.commitSha.substring(0, 7))
|
|
1003
|
+
);
|
|
1004
|
+
}
|
|
1005
|
+
if (gitInfo.commitMessage) {
|
|
1006
|
+
console.log(
|
|
1007
|
+
import_chalk2.default.gray(` Message: `) + import_chalk2.default.gray(gitInfo.commitMessage.split("\n")[0])
|
|
1008
|
+
);
|
|
1009
|
+
}
|
|
1010
|
+
console.log();
|
|
1011
|
+
const shouldDeploy = await prompt(
|
|
1012
|
+
import_chalk2.default.white(
|
|
1013
|
+
`Deploy from GitHub repository ${gitInfo.owner}/${gitInfo.repo}? (y/n): `
|
|
1014
|
+
)
|
|
1015
|
+
);
|
|
1016
|
+
if (!shouldDeploy) {
|
|
1017
|
+
console.log(import_chalk2.default.gray("Deployment cancelled."));
|
|
1018
|
+
process.exit(0);
|
|
1019
|
+
}
|
|
1020
|
+
const projectName = options.name || await getProjectName(cwd);
|
|
1021
|
+
const runtime = options.runtime || await detectRuntime(cwd);
|
|
1022
|
+
const port = options.port || 3e3;
|
|
1023
|
+
const buildCommand = await detectBuildCommand(cwd);
|
|
1024
|
+
const startCommand = await detectStartCommand(cwd);
|
|
1025
|
+
console.log();
|
|
1026
|
+
console.log(import_chalk2.default.white("Deployment configuration:"));
|
|
1027
|
+
console.log(import_chalk2.default.gray(` Name: `) + import_chalk2.default.cyan(projectName));
|
|
1028
|
+
console.log(import_chalk2.default.gray(` Runtime: `) + import_chalk2.default.cyan(runtime));
|
|
1029
|
+
console.log(import_chalk2.default.gray(` Port: `) + import_chalk2.default.cyan(port));
|
|
1030
|
+
if (buildCommand) {
|
|
1031
|
+
console.log(import_chalk2.default.gray(` Build command: `) + import_chalk2.default.cyan(buildCommand));
|
|
1032
|
+
}
|
|
1033
|
+
if (startCommand) {
|
|
1034
|
+
console.log(import_chalk2.default.gray(` Start command: `) + import_chalk2.default.cyan(startCommand));
|
|
1035
|
+
}
|
|
1036
|
+
console.log();
|
|
1037
|
+
const deploymentRequest = {
|
|
1038
|
+
name: projectName,
|
|
1039
|
+
source: {
|
|
1040
|
+
type: "github",
|
|
1041
|
+
repo: `${gitInfo.owner}/${gitInfo.repo}`,
|
|
1042
|
+
branch: gitInfo.branch || "main",
|
|
1043
|
+
runtime,
|
|
1044
|
+
port,
|
|
1045
|
+
buildCommand,
|
|
1046
|
+
startCommand
|
|
1047
|
+
},
|
|
1048
|
+
healthCheckPath: "/healthz"
|
|
1049
|
+
};
|
|
1050
|
+
console.log(import_chalk2.default.gray("Creating deployment..."));
|
|
1051
|
+
const api = await McpUseAPI.create();
|
|
1052
|
+
const deployment = await api.createDeployment(deploymentRequest);
|
|
1053
|
+
console.log(
|
|
1054
|
+
import_chalk2.default.green("\u2713 Deployment created: ") + import_chalk2.default.gray(deployment.id)
|
|
1055
|
+
);
|
|
1056
|
+
await displayDeploymentProgress(api, deployment);
|
|
1057
|
+
if (options.open && deployment.domain) {
|
|
1058
|
+
console.log();
|
|
1059
|
+
console.log(import_chalk2.default.gray("Opening deployment in browser..."));
|
|
1060
|
+
await (0, import_open2.default)(`https://${deployment.domain}`);
|
|
1061
|
+
}
|
|
1062
|
+
} else {
|
|
1063
|
+
if (options.fromSource) {
|
|
1064
|
+
console.log(
|
|
1065
|
+
import_chalk2.default.white("\u{1F4E6} Deploying from local source code (--from-source)...")
|
|
1066
|
+
);
|
|
1067
|
+
} else {
|
|
1068
|
+
console.log(
|
|
1069
|
+
import_chalk2.default.yellow(
|
|
1070
|
+
"\u26A0\uFE0F This is not a GitHub repository or no remote is configured."
|
|
1071
|
+
)
|
|
1072
|
+
);
|
|
1073
|
+
console.log(import_chalk2.default.white("Deploying from local source code instead..."));
|
|
1074
|
+
}
|
|
1075
|
+
console.log();
|
|
1076
|
+
const projectName = options.name || await getProjectName(cwd);
|
|
1077
|
+
const runtime = options.runtime || await detectRuntime(cwd);
|
|
1078
|
+
const port = options.port || 3e3;
|
|
1079
|
+
const buildCommand = await detectBuildCommand(cwd);
|
|
1080
|
+
const startCommand = await detectStartCommand(cwd);
|
|
1081
|
+
console.log(import_chalk2.default.white("Deployment configuration:"));
|
|
1082
|
+
console.log(import_chalk2.default.gray(` Name: `) + import_chalk2.default.cyan(projectName));
|
|
1083
|
+
console.log(import_chalk2.default.gray(` Runtime: `) + import_chalk2.default.cyan(runtime));
|
|
1084
|
+
console.log(import_chalk2.default.gray(` Port: `) + import_chalk2.default.cyan(port));
|
|
1085
|
+
if (buildCommand) {
|
|
1086
|
+
console.log(import_chalk2.default.gray(` Build command: `) + import_chalk2.default.cyan(buildCommand));
|
|
1087
|
+
}
|
|
1088
|
+
if (startCommand) {
|
|
1089
|
+
console.log(import_chalk2.default.gray(` Start command: `) + import_chalk2.default.cyan(startCommand));
|
|
1090
|
+
}
|
|
1091
|
+
console.log();
|
|
1092
|
+
const shouldDeploy = await prompt(
|
|
1093
|
+
import_chalk2.default.white("Deploy from local source? (y/n): ")
|
|
1094
|
+
);
|
|
1095
|
+
if (!shouldDeploy) {
|
|
1096
|
+
console.log(import_chalk2.default.gray("Deployment cancelled."));
|
|
1097
|
+
process.exit(0);
|
|
1098
|
+
}
|
|
1099
|
+
console.log();
|
|
1100
|
+
console.log(import_chalk2.default.gray("Packaging source code..."));
|
|
1101
|
+
const tarballPath = await createTarball(cwd);
|
|
1102
|
+
const stats = await import_node_fs2.promises.stat(tarballPath);
|
|
1103
|
+
console.log(
|
|
1104
|
+
import_chalk2.default.green("\u2713 Packaged: ") + import_chalk2.default.gray(formatFileSize(stats.size))
|
|
1105
|
+
);
|
|
1106
|
+
const maxSize = 2 * 1024 * 1024;
|
|
1107
|
+
if (stats.size > maxSize) {
|
|
1108
|
+
console.log(
|
|
1109
|
+
import_chalk2.default.red(
|
|
1110
|
+
`\u2717 File size (${formatFileSize(stats.size)}) exceeds maximum of 2MB`
|
|
1111
|
+
)
|
|
1112
|
+
);
|
|
1113
|
+
await import_node_fs2.promises.unlink(tarballPath);
|
|
1114
|
+
process.exit(1);
|
|
1115
|
+
}
|
|
1116
|
+
const deploymentRequest = {
|
|
1117
|
+
name: projectName,
|
|
1118
|
+
source: {
|
|
1119
|
+
type: "upload",
|
|
1120
|
+
runtime,
|
|
1121
|
+
port,
|
|
1122
|
+
buildCommand,
|
|
1123
|
+
startCommand
|
|
1124
|
+
},
|
|
1125
|
+
healthCheckPath: "/healthz"
|
|
1126
|
+
};
|
|
1127
|
+
console.log(import_chalk2.default.gray("Creating deployment..."));
|
|
1128
|
+
const api = await McpUseAPI.create();
|
|
1129
|
+
const deployment = await api.createDeploymentWithUpload(
|
|
1130
|
+
deploymentRequest,
|
|
1131
|
+
tarballPath
|
|
1132
|
+
);
|
|
1133
|
+
await import_node_fs2.promises.unlink(tarballPath);
|
|
1134
|
+
console.log(
|
|
1135
|
+
import_chalk2.default.green("\u2713 Deployment created: ") + import_chalk2.default.gray(deployment.id)
|
|
1136
|
+
);
|
|
1137
|
+
await displayDeploymentProgress(api, deployment);
|
|
1138
|
+
if (options.open && deployment.domain) {
|
|
1139
|
+
console.log();
|
|
1140
|
+
console.log(import_chalk2.default.gray("Opening deployment in browser..."));
|
|
1141
|
+
await (0, import_open2.default)(`https://${deployment.domain}`);
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
} catch (error) {
|
|
1145
|
+
console.error(
|
|
1146
|
+
import_chalk2.default.red.bold("\n\u2717 Deployment failed:"),
|
|
1147
|
+
import_chalk2.default.red(error instanceof Error ? error.message : "Unknown error")
|
|
1148
|
+
);
|
|
1149
|
+
process.exit(1);
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
// src/index.ts
|
|
35
1154
|
var program = new import_commander.Command();
|
|
36
|
-
var packageContent = (0,
|
|
37
|
-
|
|
1155
|
+
var packageContent = (0, import_node_fs3.readFileSync)(
|
|
1156
|
+
import_node_path3.default.join(__dirname, "../package.json"),
|
|
38
1157
|
"utf-8"
|
|
39
1158
|
);
|
|
40
1159
|
var packageJson = JSON.parse(packageContent);
|
|
@@ -48,7 +1167,7 @@ async function isPortAvailable(port, host = "localhost") {
|
|
|
48
1167
|
return true;
|
|
49
1168
|
}
|
|
50
1169
|
}
|
|
51
|
-
async function
|
|
1170
|
+
async function findAvailablePort2(startPort, host = "localhost") {
|
|
52
1171
|
for (let port = startPort; port < startPort + 100; port++) {
|
|
53
1172
|
if (await isPortAvailable(port, host)) {
|
|
54
1173
|
return port;
|
|
@@ -70,7 +1189,7 @@ async function waitForServer(port, host = "localhost", maxAttempts = 30) {
|
|
|
70
1189
|
return false;
|
|
71
1190
|
}
|
|
72
1191
|
function runCommand(command, args, cwd, env, filterStderr = false) {
|
|
73
|
-
const proc = (0,
|
|
1192
|
+
const proc = (0, import_node_child_process3.spawn)(command, args, {
|
|
74
1193
|
cwd,
|
|
75
1194
|
stdio: filterStderr ? ["inherit", "inherit", "pipe"] : "inherit",
|
|
76
1195
|
shell: false,
|
|
@@ -98,8 +1217,8 @@ function runCommand(command, args, cwd, env, filterStderr = false) {
|
|
|
98
1217
|
}
|
|
99
1218
|
async function startTunnel(port) {
|
|
100
1219
|
return new Promise((resolve, reject) => {
|
|
101
|
-
console.log(
|
|
102
|
-
const proc = (0,
|
|
1220
|
+
console.log(import_chalk3.default.gray(`Starting tunnel for port ${port}...`));
|
|
1221
|
+
const proc = (0, import_node_child_process3.spawn)("npx", ["--yes", "@mcp-use/tunnel", String(port)], {
|
|
103
1222
|
stdio: ["ignore", "pipe", "pipe"],
|
|
104
1223
|
shell: false
|
|
105
1224
|
});
|
|
@@ -113,7 +1232,7 @@ async function startTunnel(port) {
|
|
|
113
1232
|
const subdomain = url;
|
|
114
1233
|
resolved = true;
|
|
115
1234
|
clearTimeout(setupTimeout);
|
|
116
|
-
console.log(
|
|
1235
|
+
console.log(import_chalk3.default.green.bold(`\u2713 Tunnel established: ${url}/mcp`));
|
|
117
1236
|
resolve({ url, subdomain, process: proc });
|
|
118
1237
|
}
|
|
119
1238
|
});
|
|
@@ -144,7 +1263,7 @@ async function findServerFile(projectPath) {
|
|
|
144
1263
|
const candidates = ["index.ts", "src/index.ts", "server.ts", "src/server.ts"];
|
|
145
1264
|
for (const candidate of candidates) {
|
|
146
1265
|
try {
|
|
147
|
-
await (0, import_promises.access)(
|
|
1266
|
+
await (0, import_promises.access)(import_node_path3.default.join(projectPath, candidate));
|
|
148
1267
|
return candidate;
|
|
149
1268
|
} catch {
|
|
150
1269
|
continue;
|
|
@@ -153,18 +1272,18 @@ async function findServerFile(projectPath) {
|
|
|
153
1272
|
throw new Error("No server file found");
|
|
154
1273
|
}
|
|
155
1274
|
async function buildWidgets(projectPath) {
|
|
156
|
-
const { promises:
|
|
1275
|
+
const { promises: fs3 } = await import("fs");
|
|
157
1276
|
const { build } = await import("vite");
|
|
158
|
-
const resourcesDir =
|
|
1277
|
+
const resourcesDir = import_node_path3.default.join(projectPath, "resources");
|
|
159
1278
|
const mcpUrl = process.env.MCP_URL;
|
|
160
1279
|
if (!mcpUrl) {
|
|
161
1280
|
console.log(
|
|
162
|
-
|
|
1281
|
+
import_chalk3.default.yellow(
|
|
163
1282
|
"\u26A0\uFE0F MCP_URL not set - using relative paths (widgets may not work correctly)"
|
|
164
1283
|
)
|
|
165
1284
|
);
|
|
166
1285
|
console.log(
|
|
167
|
-
|
|
1286
|
+
import_chalk3.default.gray(
|
|
168
1287
|
" Set MCP_URL environment variable for production builds (e.g., https://myserver.com)"
|
|
169
1288
|
)
|
|
170
1289
|
);
|
|
@@ -173,39 +1292,39 @@ async function buildWidgets(projectPath) {
|
|
|
173
1292
|
await (0, import_promises.access)(resourcesDir);
|
|
174
1293
|
} catch {
|
|
175
1294
|
console.log(
|
|
176
|
-
|
|
1295
|
+
import_chalk3.default.gray("No resources/ directory found - skipping widget build")
|
|
177
1296
|
);
|
|
178
1297
|
return [];
|
|
179
1298
|
}
|
|
180
1299
|
let entries = [];
|
|
181
1300
|
try {
|
|
182
|
-
const files = await
|
|
183
|
-
entries = files.filter((f) => f.endsWith(".tsx") || f.endsWith(".ts")).map((f) =>
|
|
1301
|
+
const files = await fs3.readdir(resourcesDir);
|
|
1302
|
+
entries = files.filter((f) => f.endsWith(".tsx") || f.endsWith(".ts")).map((f) => import_node_path3.default.join(resourcesDir, f));
|
|
184
1303
|
} catch (error) {
|
|
185
|
-
console.log(
|
|
1304
|
+
console.log(import_chalk3.default.gray("No widgets found in resources/ directory"));
|
|
186
1305
|
return [];
|
|
187
1306
|
}
|
|
188
1307
|
if (entries.length === 0) {
|
|
189
|
-
console.log(
|
|
1308
|
+
console.log(import_chalk3.default.gray("No widgets found in resources/ directory"));
|
|
190
1309
|
return [];
|
|
191
1310
|
}
|
|
192
|
-
console.log(
|
|
1311
|
+
console.log(import_chalk3.default.gray(`Building ${entries.length} widget(s)...`));
|
|
193
1312
|
const react = (await import("@vitejs/plugin-react")).default;
|
|
194
1313
|
const tailwindcss = (await import("@tailwindcss/vite")).default;
|
|
195
1314
|
const builtWidgets = [];
|
|
196
1315
|
for (const entry of entries) {
|
|
197
|
-
const baseName =
|
|
1316
|
+
const baseName = import_node_path3.default.basename(entry).replace(/\.tsx?$/, "");
|
|
198
1317
|
const widgetName = baseName;
|
|
199
|
-
console.log(
|
|
200
|
-
const tempDir =
|
|
201
|
-
await
|
|
202
|
-
const relativeResourcesPath =
|
|
1318
|
+
console.log(import_chalk3.default.gray(` - Building ${widgetName}...`));
|
|
1319
|
+
const tempDir = import_node_path3.default.join(projectPath, ".mcp-use", widgetName);
|
|
1320
|
+
await fs3.mkdir(tempDir, { recursive: true });
|
|
1321
|
+
const relativeResourcesPath = import_node_path3.default.relative(tempDir, resourcesDir).replace(/\\/g, "/");
|
|
203
1322
|
const cssContent = `@import "tailwindcss";
|
|
204
1323
|
|
|
205
1324
|
/* Configure Tailwind to scan the resources directory */
|
|
206
1325
|
@source "${relativeResourcesPath}";
|
|
207
1326
|
`;
|
|
208
|
-
await
|
|
1327
|
+
await fs3.writeFile(import_node_path3.default.join(tempDir, "styles.css"), cssContent, "utf8");
|
|
209
1328
|
const entryContent = `import React from 'react'
|
|
210
1329
|
import { createRoot } from 'react-dom/client'
|
|
211
1330
|
import './styles.css'
|
|
@@ -229,9 +1348,9 @@ if (container && Component) {
|
|
|
229
1348
|
<script type="module" src="/entry.tsx"></script>
|
|
230
1349
|
</body>
|
|
231
1350
|
</html>`;
|
|
232
|
-
await
|
|
233
|
-
await
|
|
234
|
-
const outDir =
|
|
1351
|
+
await fs3.writeFile(import_node_path3.default.join(tempDir, "entry.tsx"), entryContent, "utf8");
|
|
1352
|
+
await fs3.writeFile(import_node_path3.default.join(tempDir, "index.html"), htmlContent, "utf8");
|
|
1353
|
+
const outDir = import_node_path3.default.join(
|
|
235
1354
|
projectPath,
|
|
236
1355
|
"dist",
|
|
237
1356
|
"resources",
|
|
@@ -241,16 +1360,16 @@ if (container && Component) {
|
|
|
241
1360
|
const baseUrl = mcpUrl ? `${mcpUrl}/${widgetName}/` : `/mcp-use/widgets/${widgetName}/`;
|
|
242
1361
|
let widgetMetadata = {};
|
|
243
1362
|
try {
|
|
244
|
-
const metadataTempDir =
|
|
1363
|
+
const metadataTempDir = import_node_path3.default.join(
|
|
245
1364
|
projectPath,
|
|
246
1365
|
".mcp-use",
|
|
247
1366
|
`${widgetName}-metadata`
|
|
248
1367
|
);
|
|
249
|
-
await
|
|
250
|
-
const { createServer } = await import("vite");
|
|
251
|
-
const metadataServer = await
|
|
1368
|
+
await fs3.mkdir(metadataTempDir, { recursive: true });
|
|
1369
|
+
const { createServer: createServer2 } = await import("vite");
|
|
1370
|
+
const metadataServer = await createServer2({
|
|
252
1371
|
root: metadataTempDir,
|
|
253
|
-
cacheDir:
|
|
1372
|
+
cacheDir: import_node_path3.default.join(metadataTempDir, ".vite-cache"),
|
|
254
1373
|
plugins: [tailwindcss(), react()],
|
|
255
1374
|
resolve: {
|
|
256
1375
|
alias: {
|
|
@@ -290,12 +1409,12 @@ if (container && Component) {
|
|
|
290
1409
|
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
291
1410
|
} catch (error) {
|
|
292
1411
|
console.warn(
|
|
293
|
-
|
|
1412
|
+
import_chalk3.default.yellow(` \u26A0 Could not extract metadata for ${widgetName}`)
|
|
294
1413
|
);
|
|
295
1414
|
} finally {
|
|
296
1415
|
await metadataServer.close();
|
|
297
1416
|
try {
|
|
298
|
-
await
|
|
1417
|
+
await fs3.rm(metadataTempDir, { recursive: true, force: true });
|
|
299
1418
|
} catch {
|
|
300
1419
|
}
|
|
301
1420
|
}
|
|
@@ -326,7 +1445,7 @@ if (container && Component) {
|
|
|
326
1445
|
outDir,
|
|
327
1446
|
emptyOutDir: true,
|
|
328
1447
|
rollupOptions: {
|
|
329
|
-
input:
|
|
1448
|
+
input: import_node_path3.default.join(tempDir, "index.html")
|
|
330
1449
|
}
|
|
331
1450
|
}
|
|
332
1451
|
});
|
|
@@ -334,23 +1453,23 @@ if (container && Component) {
|
|
|
334
1453
|
name: widgetName,
|
|
335
1454
|
metadata: widgetMetadata
|
|
336
1455
|
});
|
|
337
|
-
console.log(
|
|
1456
|
+
console.log(import_chalk3.default.green(` \u2713 Built ${widgetName}`));
|
|
338
1457
|
} catch (error) {
|
|
339
|
-
console.error(
|
|
1458
|
+
console.error(import_chalk3.default.red(` \u2717 Failed to build ${widgetName}:`), error);
|
|
340
1459
|
}
|
|
341
1460
|
}
|
|
342
1461
|
return builtWidgets;
|
|
343
1462
|
}
|
|
344
1463
|
program.command("build").description("Build TypeScript and MCP UI widgets").option("-p, --path <path>", "Path to project directory", process.cwd()).option("--with-inspector", "Include inspector in production build").action(async (options) => {
|
|
345
1464
|
try {
|
|
346
|
-
const projectPath =
|
|
347
|
-
const { promises:
|
|
348
|
-
console.log(
|
|
1465
|
+
const projectPath = import_node_path3.default.resolve(options.path);
|
|
1466
|
+
const { promises: fs3 } = await import("fs");
|
|
1467
|
+
console.log(import_chalk3.default.cyan.bold(`mcp-use v${packageJson.version}`));
|
|
349
1468
|
const builtWidgets = await buildWidgets(projectPath);
|
|
350
|
-
console.log(
|
|
1469
|
+
console.log(import_chalk3.default.gray("Building TypeScript..."));
|
|
351
1470
|
await runCommand("npx", ["tsc"], projectPath);
|
|
352
|
-
console.log(
|
|
353
|
-
const manifestPath =
|
|
1471
|
+
console.log(import_chalk3.default.green("\u2713 TypeScript build complete!"));
|
|
1472
|
+
const manifestPath = import_node_path3.default.join(projectPath, "dist", "mcp-use.json");
|
|
354
1473
|
const widgetsData = {};
|
|
355
1474
|
for (const widget of builtWidgets) {
|
|
356
1475
|
widgetsData[widget.name] = widget.metadata;
|
|
@@ -361,36 +1480,36 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
361
1480
|
buildTime: (/* @__PURE__ */ new Date()).toISOString(),
|
|
362
1481
|
widgets: widgetsData
|
|
363
1482
|
};
|
|
364
|
-
await
|
|
365
|
-
await
|
|
1483
|
+
await fs3.mkdir(import_node_path3.default.dirname(manifestPath), { recursive: true });
|
|
1484
|
+
await fs3.writeFile(
|
|
366
1485
|
manifestPath,
|
|
367
1486
|
JSON.stringify(manifest, null, 2),
|
|
368
1487
|
"utf8"
|
|
369
1488
|
);
|
|
370
|
-
console.log(
|
|
371
|
-
console.log(
|
|
1489
|
+
console.log(import_chalk3.default.green("\u2713 Build manifest created"));
|
|
1490
|
+
console.log(import_chalk3.default.green.bold(`
|
|
372
1491
|
\u2713 Build complete!`));
|
|
373
1492
|
if (builtWidgets.length > 0) {
|
|
374
|
-
console.log(
|
|
1493
|
+
console.log(import_chalk3.default.gray(` ${builtWidgets.length} widget(s) built`));
|
|
375
1494
|
}
|
|
376
1495
|
if (options.withInspector) {
|
|
377
|
-
console.log(
|
|
1496
|
+
console.log(import_chalk3.default.gray(" Inspector included"));
|
|
378
1497
|
}
|
|
379
1498
|
} catch (error) {
|
|
380
|
-
console.error(
|
|
1499
|
+
console.error(import_chalk3.default.red("Build failed:"), error);
|
|
381
1500
|
process.exit(1);
|
|
382
1501
|
}
|
|
383
1502
|
});
|
|
384
1503
|
program.command("dev").description("Run development server with auto-reload and inspector").option("-p, --path <path>", "Path to project directory", process.cwd()).option("--port <port>", "Server port", "3000").option("--host <host>", "Server host", "localhost").option("--no-open", "Do not auto-open inspector").action(async (options) => {
|
|
385
1504
|
try {
|
|
386
|
-
const projectPath =
|
|
1505
|
+
const projectPath = import_node_path3.default.resolve(options.path);
|
|
387
1506
|
let port = parseInt(options.port, 10);
|
|
388
1507
|
const host = options.host;
|
|
389
|
-
console.log(
|
|
1508
|
+
console.log(import_chalk3.default.cyan.bold(`mcp-use v${packageJson.version}`));
|
|
390
1509
|
if (!await isPortAvailable(port, host)) {
|
|
391
|
-
console.log(
|
|
392
|
-
const availablePort = await
|
|
393
|
-
console.log(
|
|
1510
|
+
console.log(import_chalk3.default.yellow.bold(`\u26A0\uFE0F Port ${port} is already in use`));
|
|
1511
|
+
const availablePort = await findAvailablePort2(port, host);
|
|
1512
|
+
console.log(import_chalk3.default.green.bold(`\u2713 Using port ${availablePort} instead`));
|
|
394
1513
|
port = availablePort;
|
|
395
1514
|
}
|
|
396
1515
|
let mcpUrl;
|
|
@@ -422,20 +1541,20 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
422
1541
|
inspectorUrl += `&tunnelUrl=${encodeURIComponent(mcpUrl)}`;
|
|
423
1542
|
}
|
|
424
1543
|
const readyTime = Date.now() - startTime;
|
|
425
|
-
console.log(
|
|
426
|
-
console.log(
|
|
427
|
-
console.log(
|
|
1544
|
+
console.log(import_chalk3.default.green.bold(`\u2713 Ready in ${readyTime}ms`));
|
|
1545
|
+
console.log(import_chalk3.default.whiteBright(`Local: http://${host}:${port}`));
|
|
1546
|
+
console.log(import_chalk3.default.whiteBright(`Network: http://${host}:${port}`));
|
|
428
1547
|
if (mcpUrl) {
|
|
429
|
-
console.log(
|
|
1548
|
+
console.log(import_chalk3.default.whiteBright(`Tunnel: ${mcpUrl}`));
|
|
430
1549
|
}
|
|
431
|
-
console.log(
|
|
432
|
-
console.log(
|
|
1550
|
+
console.log(import_chalk3.default.whiteBright(`MCP: ${mcpEndpoint}`));
|
|
1551
|
+
console.log(import_chalk3.default.whiteBright(`Inspector: ${inspectorUrl}
|
|
433
1552
|
`));
|
|
434
|
-
await (0,
|
|
1553
|
+
await (0, import_open3.default)(inspectorUrl);
|
|
435
1554
|
}
|
|
436
1555
|
}
|
|
437
1556
|
const cleanup = () => {
|
|
438
|
-
console.log(
|
|
1557
|
+
console.log(import_chalk3.default.gray("\n\nShutting down..."));
|
|
439
1558
|
const processesToKill = processes.length;
|
|
440
1559
|
let killedCount = 0;
|
|
441
1560
|
const checkAndExit = () => {
|
|
@@ -466,13 +1585,13 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
466
1585
|
await new Promise(() => {
|
|
467
1586
|
});
|
|
468
1587
|
} catch (error) {
|
|
469
|
-
console.error(
|
|
1588
|
+
console.error(import_chalk3.default.red("Dev mode failed:"), error);
|
|
470
1589
|
process.exit(1);
|
|
471
1590
|
}
|
|
472
1591
|
});
|
|
473
1592
|
program.command("start").description("Start production server").option("-p, --path <path>", "Path to project directory", process.cwd()).option("--port <port>", "Server port", "3000").option("--tunnel", "Expose server through a tunnel").action(async (options) => {
|
|
474
1593
|
try {
|
|
475
|
-
const projectPath =
|
|
1594
|
+
const projectPath = import_node_path3.default.resolve(options.path);
|
|
476
1595
|
const port = parseInt(options.port, 10);
|
|
477
1596
|
console.log(
|
|
478
1597
|
`\x1B[36m\x1B[1mmcp-use\x1B[0m \x1B[90mVersion: ${packageJson.version}\x1B[0m
|
|
@@ -486,13 +1605,13 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
486
1605
|
mcpUrl = tunnelInfo.subdomain;
|
|
487
1606
|
tunnelProcess = tunnelInfo.process;
|
|
488
1607
|
} catch (error) {
|
|
489
|
-
console.error(
|
|
1608
|
+
console.error(import_chalk3.default.red("Failed to start tunnel:"), error);
|
|
490
1609
|
process.exit(1);
|
|
491
1610
|
}
|
|
492
1611
|
}
|
|
493
1612
|
let serverFile = "dist/index.js";
|
|
494
1613
|
try {
|
|
495
|
-
await (0, import_promises.access)(
|
|
1614
|
+
await (0, import_promises.access)(import_node_path3.default.join(projectPath, serverFile));
|
|
496
1615
|
} catch {
|
|
497
1616
|
serverFile = "dist/server.js";
|
|
498
1617
|
}
|
|
@@ -504,9 +1623,9 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
504
1623
|
};
|
|
505
1624
|
if (mcpUrl) {
|
|
506
1625
|
env.MCP_URL = mcpUrl;
|
|
507
|
-
console.log(
|
|
1626
|
+
console.log(import_chalk3.default.whiteBright(`Tunnel: ${mcpUrl}`));
|
|
508
1627
|
}
|
|
509
|
-
const serverProc = (0,
|
|
1628
|
+
const serverProc = (0, import_node_child_process3.spawn)("node", [serverFile], {
|
|
510
1629
|
cwd: projectPath,
|
|
511
1630
|
stdio: "inherit",
|
|
512
1631
|
env
|
|
@@ -549,4 +1668,25 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
549
1668
|
process.exit(1);
|
|
550
1669
|
}
|
|
551
1670
|
});
|
|
1671
|
+
program.command("login").description("Login to mcp-use cloud").action(async () => {
|
|
1672
|
+
await loginCommand();
|
|
1673
|
+
});
|
|
1674
|
+
program.command("logout").description("Logout from mcp-use cloud").action(async () => {
|
|
1675
|
+
await logoutCommand();
|
|
1676
|
+
});
|
|
1677
|
+
program.command("whoami").description("Show current user information").action(async () => {
|
|
1678
|
+
await whoamiCommand();
|
|
1679
|
+
});
|
|
1680
|
+
program.command("deploy").description("Deploy MCP server to mcp-use cloud").option("--open", "Open deployment in browser after successful deploy").option("--name <name>", "Custom deployment name").option("--port <port>", "Server port", "3000").option("--runtime <runtime>", "Runtime (node or python)").option(
|
|
1681
|
+
"--from-source",
|
|
1682
|
+
"Deploy from local source code (even for GitHub repos)"
|
|
1683
|
+
).action(async (options) => {
|
|
1684
|
+
await deployCommand({
|
|
1685
|
+
open: options.open,
|
|
1686
|
+
name: options.name,
|
|
1687
|
+
port: options.port ? parseInt(options.port, 10) : void 0,
|
|
1688
|
+
runtime: options.runtime,
|
|
1689
|
+
fromSource: options.fromSource
|
|
1690
|
+
});
|
|
1691
|
+
});
|
|
552
1692
|
program.parse();
|