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