@mcp-use/cli 3.3.2 → 3.4.0-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.
@@ -15,6 +15,13 @@ export declare function loginCommand(options?: {
15
15
  silent?: boolean;
16
16
  apiKey?: string;
17
17
  org?: string;
18
+ /**
19
+ * A pre-approved OAuth device code (RFC 8628). When provided, skip requesting
20
+ * a new code + opening a browser and poll the token endpoint directly. Used by
21
+ * the web onboarding flow, which creates and approves the code, then embeds it
22
+ * in the agent's prompt.
23
+ */
24
+ deviceCode?: string;
18
25
  }): Promise<void>;
19
26
  /**
20
27
  * Logout command - revokes API key and deletes config
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAoB,OAAO,EAAE,MAAM,iBAAiB,CAAC;AA8FjE;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,OAAO,EAAE,EACf,UAAU,EAAE,MAAM,GACjB,OAAO,GAAG,IAAI,CAUhB;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,OAAO,EAAE,EACf,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAC3B,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CA2CzB;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,OAAO,CAAC,EAAE;IAC3C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC,IAAI,CAAC,CAiLhB;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAwBnD;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAqDnD"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAoB,OAAO,EAAE,MAAM,iBAAiB,CAAC;AA8FjE;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,OAAO,EAAE,EACf,UAAU,EAAE,MAAM,GACjB,OAAO,GAAG,IAAI,CAUhB;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,OAAO,EAAE,EACf,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAC3B,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CA2CzB;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,OAAO,CAAC,EAAE;IAC3C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2LhB;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAwBnD;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAqDnD"}
@@ -26,6 +26,11 @@ interface DeployOptions {
26
26
  region?: "US" | "EU" | "APAC";
27
27
  buildCommand?: string;
28
28
  startCommand?: string;
29
+ /**
30
+ * Upload local source without connecting the user's GitHub. Uses the
31
+ * platform-managed org and a tarball instead of pushing to a user repo.
32
+ */
33
+ noGithub?: boolean;
29
34
  }
30
35
  export declare function deployCommand(options: DeployOptions): Promise<void>;
31
36
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,SAAS,EACV,MAAM,iBAAiB,CAAC;AA+FzB;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,SAAS,EACd,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAuB/C;AA0CD,UAAU,aAAa;IACrB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC5B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAueD,wBAAsB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA2vBzE"}
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,SAAS,EACV,MAAM,iBAAiB,CAAC;AAgGzB;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,SAAS,EACd,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAuB/C;AA0CD,UAAU,aAAa;IACrB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC5B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAmmBD,wBAAsB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAixBzE"}
package/dist/index.cjs CHANGED
@@ -1389,6 +1389,80 @@ var McpUseAPI = class _McpUseAPI {
1389
1389
  body: JSON.stringify(body)
1390
1390
  });
1391
1391
  }
1392
+ /** Multipart helper: POST/PUT a tarball + fields without the JSON Content-Type. */
1393
+ async uploadMultipart(endpoint, form, timeout = 12e4) {
1394
+ const url = `${this.baseUrl}${endpoint}`;
1395
+ const headers = {
1396
+ "x-mcp-creation-location": "cli"
1397
+ };
1398
+ if (this.apiKey) headers["x-api-key"] = this.apiKey;
1399
+ if (this.orgId) headers["x-profile-id"] = this.orgId;
1400
+ const controller = new AbortController();
1401
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
1402
+ try {
1403
+ const response = await fetch(url, {
1404
+ method: "POST",
1405
+ headers,
1406
+ body: form,
1407
+ signal: controller.signal
1408
+ });
1409
+ clearTimeout(timeoutId);
1410
+ if (response.status === 401) throw new ApiUnauthorizedError();
1411
+ if (!response.ok) {
1412
+ const errorText = await response.text();
1413
+ throw new Error(`API request failed: ${response.status} ${errorText}`);
1414
+ }
1415
+ return response.json();
1416
+ } catch (error) {
1417
+ clearTimeout(timeoutId);
1418
+ if (error.name === "AbortError") {
1419
+ throw new Error(`Request timeout after ${timeout / 1e3}s.`);
1420
+ }
1421
+ throw error;
1422
+ }
1423
+ }
1424
+ /**
1425
+ * Create a server from a source tarball deployed into the platform-managed
1426
+ * GitHub org (no user GitHub connection required).
1427
+ */
1428
+ async createServerFromManagedUpload(input) {
1429
+ const form = new FormData();
1430
+ form.set(
1431
+ "sourceFile",
1432
+ new Blob([new Uint8Array(input.tarball)], { type: "application/gzip" }),
1433
+ "source.tar.gz"
1434
+ );
1435
+ form.set("organizationId", input.organizationId);
1436
+ form.set("managed", "true");
1437
+ form.set("name", input.name);
1438
+ form.set("repoName", input.repoName);
1439
+ form.set("private", "true");
1440
+ form.set("branch", input.branch ?? "main");
1441
+ form.set("commitMessage", input.commitMessage ?? "Deploy from mcp-use CLI");
1442
+ if (input.port != null) form.set("port", String(input.port));
1443
+ if (input.env && Object.keys(input.env).length > 0) {
1444
+ form.set("env", JSON.stringify(input.env));
1445
+ }
1446
+ return this.uploadMultipart("/servers", form);
1447
+ }
1448
+ /** Push a new source tarball as a commit on an existing server's repo. */
1449
+ async pushSourceToServer(serverId, input) {
1450
+ const form = new FormData();
1451
+ form.set(
1452
+ "sourceFile",
1453
+ new Blob([new Uint8Array(input.tarball)], { type: "application/gzip" }),
1454
+ "source.tar.gz"
1455
+ );
1456
+ form.set("branch", input.branch ?? "main");
1457
+ form.set(
1458
+ "commitMessage",
1459
+ input.commitMessage ?? "Redeploy from mcp-use CLI"
1460
+ );
1461
+ return this.uploadMultipart(
1462
+ `/servers/${encodeURIComponent(serverId)}/source`,
1463
+ form
1464
+ );
1465
+ }
1392
1466
  async listServers(params) {
1393
1467
  const response = await this.request(`/servers${buildPaginationQuery(params)}`);
1394
1468
  return normalizePaginatedResponse(response, params);
@@ -1707,7 +1781,7 @@ async function loginCommand(options) {
1707
1781
  }
1708
1782
  return;
1709
1783
  }
1710
- if (await isLoggedIn()) {
1784
+ if (!options?.deviceCode && await isLoggedIn()) {
1711
1785
  let needsReauth = false;
1712
1786
  try {
1713
1787
  await (await McpUseAPI.create()).testAuth();
@@ -1737,29 +1811,33 @@ async function loginCommand(options) {
1737
1811
  }
1738
1812
  console.log(source_default.cyan.bold("Logging in to Manufact cloud...\n"));
1739
1813
  const authBaseUrl = await getAuthBaseUrl();
1740
- const deviceResp = await requestDeviceCode(authBaseUrl);
1741
- const {
1742
- device_code,
1743
- user_code,
1744
- verification_uri,
1745
- verification_uri_complete,
1746
- interval
1747
- } = deviceResp;
1748
- const displayCode = user_code.length === 8 ? `${user_code.slice(0, 4)}-${user_code.slice(4)}` : user_code;
1749
- console.log(source_default.white(" Visit: ") + source_default.cyan(verification_uri));
1750
- console.log(source_default.white(" Code: ") + source_default.bold.white(displayCode));
1751
- console.log();
1752
- const urlToOpen = verification_uri_complete || verification_uri;
1753
- try {
1754
- await open_default(urlToOpen);
1755
- console.log(source_default.gray(" Browser opened. Waiting for approval..."));
1756
- } catch {
1757
- console.log(source_default.gray(" Open the URL above in your browser."));
1814
+ let device_code;
1815
+ let interval;
1816
+ if (options?.deviceCode) {
1817
+ device_code = options.deviceCode.trim();
1818
+ interval = 2;
1819
+ console.log(source_default.gray(" Authenticating with provided device code..."));
1820
+ } else {
1821
+ const deviceResp = await requestDeviceCode(authBaseUrl);
1822
+ device_code = deviceResp.device_code;
1823
+ interval = deviceResp.interval || 5;
1824
+ const { user_code, verification_uri, verification_uri_complete } = deviceResp;
1825
+ const displayCode = user_code.length === 8 ? `${user_code.slice(0, 4)}-${user_code.slice(4)}` : user_code;
1826
+ console.log(source_default.white(" Visit: ") + source_default.cyan(verification_uri));
1827
+ console.log(source_default.white(" Code: ") + source_default.bold.white(displayCode));
1828
+ console.log();
1829
+ const urlToOpen = verification_uri_complete || verification_uri;
1830
+ try {
1831
+ await open_default(urlToOpen);
1832
+ console.log(source_default.gray(" Browser opened. Waiting for approval..."));
1833
+ } catch {
1834
+ console.log(source_default.gray(" Open the URL above in your browser."));
1835
+ }
1758
1836
  }
1759
1837
  const accessToken = await pollForDeviceToken(
1760
1838
  authBaseUrl,
1761
1839
  device_code,
1762
- interval || 5
1840
+ interval
1763
1841
  );
1764
1842
  console.log(source_default.gray("\n Creating persistent API key..."));
1765
1843
  const api = await McpUseAPI.create();
@@ -4714,6 +4792,49 @@ ${MCP_USE_DIR}
4714
4792
  }
4715
4793
  }
4716
4794
 
4795
+ // src/utils/tarball.ts
4796
+ var import_tar = require("tar");
4797
+ var EXCLUDE_DIRS = /* @__PURE__ */ new Set([
4798
+ ".git",
4799
+ "node_modules",
4800
+ "dist",
4801
+ "build",
4802
+ ".next",
4803
+ ".turbo",
4804
+ ".vercel",
4805
+ ".cache",
4806
+ "coverage",
4807
+ ".mcp-use"
4808
+ ]);
4809
+ async function packProjectTarball(projectDir, prefix = "app") {
4810
+ const stream = (0, import_tar.create)(
4811
+ {
4812
+ gzip: true,
4813
+ cwd: projectDir,
4814
+ prefix,
4815
+ portable: true,
4816
+ filter: (entryPath) => {
4817
+ const segments = entryPath.split(/[/\\]/).filter((s) => s && s !== ".");
4818
+ if (segments.some((seg) => EXCLUDE_DIRS.has(seg))) return false;
4819
+ const base = segments[segments.length - 1] ?? "";
4820
+ if (base === ".DS_Store") return false;
4821
+ if (base === ".env" || base.startsWith(".env.")) return false;
4822
+ return true;
4823
+ }
4824
+ },
4825
+ ["."]
4826
+ );
4827
+ const chunks = [];
4828
+ for await (const chunk of stream) {
4829
+ chunks.push(Buffer.from(chunk));
4830
+ }
4831
+ return Buffer.concat(chunks);
4832
+ }
4833
+ function sanitizeRepoName(name) {
4834
+ const cleaned = name.trim().replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^[-.]+|[-.]+$/g, "").slice(0, 80);
4835
+ return cleaned || "mcp-server";
4836
+ }
4837
+
4717
4838
  // src/commands/deploy.ts
4718
4839
  async function parseEnvFile(filePath) {
4719
4840
  try {
@@ -5215,6 +5336,106 @@ Opening browser...`));
5215
5336
  return { ok: false, api: client };
5216
5337
  }
5217
5338
  }
5339
+ async function deployViaManagedUpload(api, options, ctx) {
5340
+ const { cwd, organizationId } = ctx;
5341
+ const projectDir = options.rootDir ? import_node_path8.default.resolve(cwd, options.rootDir) : cwd;
5342
+ try {
5343
+ await import_node_fs10.promises.access(projectDir);
5344
+ } catch {
5345
+ console.log(source_default.red(`\u2717 Project directory not found: ${projectDir}`));
5346
+ process.exit(1);
5347
+ }
5348
+ const isMcp = await isMcpProject(projectDir);
5349
+ if (!isMcp && !options.yes) {
5350
+ console.log(
5351
+ source_default.yellow("\u26A0\uFE0F This doesn't look like an MCP server project.")
5352
+ );
5353
+ const shouldContinue = await prompt(
5354
+ source_default.white("Continue anyway? (y/n): ")
5355
+ );
5356
+ if (!shouldContinue) process.exit(0);
5357
+ console.log();
5358
+ }
5359
+ const envVars = await buildEnvVars(options);
5360
+ const branch = "main";
5361
+ const projectName = options.name || await getProjectName(projectDir);
5362
+ console.log(source_default.gray("Packaging project source..."));
5363
+ const tarball = await packProjectTarball(projectDir);
5364
+ console.log(
5365
+ source_default.gray(
5366
+ ` Archive size: ${(tarball.length / 1024 / 1024).toFixed(2)} MB`
5367
+ )
5368
+ );
5369
+ if (tarball.length > 80 * 1024 * 1024) {
5370
+ console.log(
5371
+ source_default.red(
5372
+ "\u2717 Project archive exceeds 80 MB. Add large/derived files to .gitignore and retry."
5373
+ )
5374
+ );
5375
+ process.exit(1);
5376
+ }
5377
+ const existingLink = !options.new ? await getProjectLink(cwd) : null;
5378
+ let serverId = existingLink?.serverId;
5379
+ if (serverId) {
5380
+ try {
5381
+ const linked = await api.getServer(serverId);
5382
+ if (linked.organizationId !== organizationId) serverId = void 0;
5383
+ } catch {
5384
+ serverId = void 0;
5385
+ }
5386
+ }
5387
+ let deploymentId;
5388
+ if (serverId) {
5389
+ console.log(source_default.gray("Uploading source and redeploying..."));
5390
+ if (Object.keys(envVars).length > 0) {
5391
+ await syncEnvVarsToServer(api, serverId, envVars);
5392
+ }
5393
+ await api.pushSourceToServer(serverId, {
5394
+ tarball,
5395
+ branch,
5396
+ commitMessage: "Redeploy from mcp-use CLI"
5397
+ });
5398
+ const dep = await api.createDeployment({
5399
+ serverId,
5400
+ branch,
5401
+ trigger: "redeploy"
5402
+ });
5403
+ deploymentId = dep.id;
5404
+ await saveProjectLink(cwd, {
5405
+ deploymentId: dep.id,
5406
+ deploymentName: projectName,
5407
+ serverId,
5408
+ linkedAt: (/* @__PURE__ */ new Date()).toISOString()
5409
+ });
5410
+ } else {
5411
+ console.log(source_default.gray("Uploading source (no GitHub required)..."));
5412
+ const result = await api.createServerFromManagedUpload({
5413
+ organizationId,
5414
+ name: projectName,
5415
+ repoName: sanitizeRepoName(projectName),
5416
+ tarball,
5417
+ branch,
5418
+ commitMessage: "Deploy from mcp-use CLI",
5419
+ port: options.port,
5420
+ env: Object.keys(envVars).length > 0 ? envVars : void 0
5421
+ });
5422
+ deploymentId = result.deploymentId ?? void 0;
5423
+ if (result.server?.id && deploymentId) {
5424
+ await saveProjectLink(cwd, {
5425
+ deploymentId,
5426
+ deploymentName: projectName,
5427
+ serverId: result.server.id,
5428
+ linkedAt: (/* @__PURE__ */ new Date()).toISOString()
5429
+ });
5430
+ }
5431
+ }
5432
+ if (!deploymentId) {
5433
+ console.log(source_default.red("\u2717 No deployment was created."));
5434
+ process.exit(1);
5435
+ }
5436
+ console.log(source_default.green("\u2713 Deployment created: ") + source_default.gray(deploymentId));
5437
+ await displayDeploymentProgress(api, deploymentId, { yes: options.yes });
5438
+ }
5218
5439
  async function deployCommand(options) {
5219
5440
  try {
5220
5441
  const cwd = process.cwd();
@@ -5332,6 +5553,22 @@ async function deployCommand(options) {
5332
5553
  }
5333
5554
  api = await ensureApiSessionForDeploy(api, options, resolvedOrgId);
5334
5555
  console.log(source_default.cyan.bold("\n\u{1F680} Deploying to Manufact cloud...\n"));
5556
+ let useNoGithubDeploy = !!options.noGithub;
5557
+ if (!useNoGithubDeploy && !options.new) {
5558
+ const link = await getProjectLink(cwd);
5559
+ if (link?.serverId) {
5560
+ try {
5561
+ const linked = await api.getServer(link.serverId);
5562
+ if (linked.connectedRepository?.isManaged) useNoGithubDeploy = true;
5563
+ } catch {
5564
+ }
5565
+ }
5566
+ }
5567
+ if (useNoGithubDeploy) {
5568
+ const organizationId = resolvedOrgId ?? await api.resolveOrganizationId();
5569
+ await deployViaManagedUpload(api, options, { cwd, organizationId });
5570
+ return;
5571
+ }
5335
5572
  const reauth = () => promptReauthenticateOn401(options, resolvedOrgId);
5336
5573
  let ghConn = await getGitHubConnectionStatusWith401Retry(
5337
5574
  api,
@@ -6953,7 +7190,7 @@ var import_node_os6 = require("os");
6953
7190
  var import_node_path9 = require("path");
6954
7191
  var import_node_stream = require("stream");
6955
7192
  var import_promises6 = require("stream/promises");
6956
- var import_tar = require("tar");
7193
+ var import_tar2 = require("tar");
6957
7194
  var REPO_OWNER = "mcp-use";
6958
7195
  var REPO_NAME = "mcp-use";
6959
7196
  var REPO_BRANCH = "main";
@@ -6995,7 +7232,7 @@ async function addSkillsToProject(projectPath) {
6995
7232
  }
6996
7233
  await (0, import_promises6.pipeline)(
6997
7234
  import_node_stream.Readable.fromWeb(response.body),
6998
- (0, import_tar.extract)({
7235
+ (0, import_tar2.extract)({
6999
7236
  cwd: tempDir,
7000
7237
  filter: (path11) => path11.includes("/skills/"),
7001
7238
  strip: 1
@@ -9396,18 +9633,27 @@ Looked for:
9396
9633
  program.command("login").description("Login to Manufact cloud").option(
9397
9634
  "--api-key <key>",
9398
9635
  "Login with an API key directly (non-interactive, for CI/CD)"
9399
- ).option("--org <slug|id|name>", "Select an organization non-interactively").action(async (opts) => {
9400
- try {
9401
- await loginCommand({ apiKey: opts.apiKey, org: opts.org });
9402
- process.exit(0);
9403
- } catch (error) {
9404
- console.error(
9405
- source_default.red.bold("\n\u2717 Login failed:"),
9406
- source_default.red(error instanceof Error ? error.message : "Unknown error")
9407
- );
9408
- process.exit(1);
9636
+ ).option("--org <slug|id|name>", "Select an organization non-interactively").option(
9637
+ "--device-code <code>",
9638
+ "Authenticate with a pre-approved device code (non-interactive; e.g. from the web onboarding flow)"
9639
+ ).action(
9640
+ async (opts) => {
9641
+ try {
9642
+ await loginCommand({
9643
+ apiKey: opts.apiKey,
9644
+ org: opts.org,
9645
+ deviceCode: opts.deviceCode
9646
+ });
9647
+ process.exit(0);
9648
+ } catch (error) {
9649
+ console.error(
9650
+ source_default.red.bold("\n\u2717 Login failed:"),
9651
+ source_default.red(error instanceof Error ? error.message : "Unknown error")
9652
+ );
9653
+ process.exit(1);
9654
+ }
9409
9655
  }
9410
- });
9656
+ );
9411
9657
  program.command("logout").description("Logout from Manufact cloud").action(async () => {
9412
9658
  await logoutCommand();
9413
9659
  });
@@ -9442,6 +9688,9 @@ program.command("deploy").description("Deploy MCP server from GitHub to Manufact
9442
9688
  ).option(
9443
9689
  "--start-command <cmd>",
9444
9690
  "Custom start command (overrides auto-detection)"
9691
+ ).option(
9692
+ "--no-github",
9693
+ "Upload local source without connecting GitHub (repo hosted in the platform-managed org)"
9445
9694
  ).action(async (options) => {
9446
9695
  await deployCommand({
9447
9696
  open: options.open,
@@ -9456,7 +9705,8 @@ program.command("deploy").description("Deploy MCP server from GitHub to Manufact
9456
9705
  yes: options.yes,
9457
9706
  region: options.region,
9458
9707
  buildCommand: options.buildCommand,
9459
- startCommand: options.startCommand
9708
+ startCommand: options.startCommand,
9709
+ noGithub: options.github === false
9460
9710
  });
9461
9711
  });
9462
9712
  program.addCommand(createClientCommand());