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