@mcp-use/cli 2.2.1 → 2.2.2-canary.1

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