@mcp-use/cli 3.1.0-canary.2 → 3.1.0-canary.3

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.cjs CHANGED
@@ -526,11 +526,11 @@ var source_default = chalk;
526
526
  var import_commander6 = require("commander");
527
527
  var import_config8 = require("dotenv/config");
528
528
  var import_node_child_process9 = require("child_process");
529
- var import_node_fs10 = require("fs");
529
+ var import_node_fs11 = require("fs");
530
530
  var import_promises7 = require("fs/promises");
531
531
  var import_node_module2 = require("module");
532
- var import_node_path8 = __toESM(require("path"), 1);
533
- var import_node_url2 = require("url");
532
+ var import_node_path9 = __toESM(require("path"), 1);
533
+ var import_node_url3 = require("url");
534
534
 
535
535
  // ../../node_modules/.pnpm/open@11.0.0/node_modules/open/index.js
536
536
  var import_node_process8 = __toESM(require("process"), 1);
@@ -716,15 +716,15 @@ var wslDefaultBrowser = async () => {
716
716
  const { stdout } = await executePowerShell(command, { powerShellPath: psPath });
717
717
  return stdout.trim();
718
718
  };
719
- var convertWslPathToWindows = async (path7) => {
720
- if (/^[a-z]+:\/\//i.test(path7)) {
721
- return path7;
719
+ var convertWslPathToWindows = async (path8) => {
720
+ if (/^[a-z]+:\/\//i.test(path8)) {
721
+ return path8;
722
722
  }
723
723
  try {
724
- const { stdout } = await execFile2("wslpath", ["-aw", path7], { encoding: "utf8" });
724
+ const { stdout } = await execFile2("wslpath", ["-aw", path8], { encoding: "utf8" });
725
725
  return stdout.trim();
726
726
  } catch {
727
- return path7;
727
+ return path8;
728
728
  }
729
729
  };
730
730
 
@@ -1374,8 +1374,8 @@ var McpUseAPI = class _McpUseAPI {
1374
1374
  return this.request(`/servers${q ? `?${q}` : ""}`);
1375
1375
  }
1376
1376
  async getServer(idOrSlug) {
1377
- const path7 = encodeURIComponent(idOrSlug);
1378
- return this.request(`/servers/${path7}`);
1377
+ const path8 = encodeURIComponent(idOrSlug);
1378
+ return this.request(`/servers/${path8}`);
1379
1379
  }
1380
1380
  async deleteServer(id) {
1381
1381
  await this.request(
@@ -5250,7 +5250,7 @@ async function addSkillsToProject(projectPath) {
5250
5250
  import_node_stream.Readable.fromWeb(response.body),
5251
5251
  (0, import_tar.extract)({
5252
5252
  cwd: tempDir,
5253
- filter: (path7) => path7.includes("/skills/"),
5253
+ filter: (path8) => path8.includes("/skills/"),
5254
5254
  strip: 1
5255
5255
  })
5256
5256
  );
@@ -5315,14 +5315,114 @@ function createSkillsCommand() {
5315
5315
  return skills;
5316
5316
  }
5317
5317
 
5318
- // src/utils/update-check.ts
5318
+ // src/utils/next-shims.ts
5319
5319
  var import_node_fs9 = require("fs");
5320
+ var import_node_path7 = __toESM(require("path"), 1);
5321
+ var import_node_url2 = require("url");
5322
+ async function detectNextJsProject(projectPath) {
5323
+ try {
5324
+ const pkgPath = import_node_path7.default.join(projectPath, "package.json");
5325
+ const content = await import_node_fs9.promises.readFile(pkgPath, "utf-8");
5326
+ const pkg = JSON.parse(content);
5327
+ const deps = pkg.dependencies ?? {};
5328
+ const devDeps = pkg.devDependencies ?? {};
5329
+ return "next" in deps || "next" in devDeps;
5330
+ } catch {
5331
+ return false;
5332
+ }
5333
+ }
5334
+ async function loadNextJsEnvFiles(projectPath) {
5335
+ const files = [
5336
+ ".env",
5337
+ ".env.development",
5338
+ ".env.local",
5339
+ ".env.development.local"
5340
+ ];
5341
+ const dotenv = await import("dotenv");
5342
+ for (const file of files) {
5343
+ const abs = import_node_path7.default.join(projectPath, file);
5344
+ try {
5345
+ await import_node_fs9.promises.access(abs);
5346
+ } catch {
5347
+ continue;
5348
+ }
5349
+ dotenv.config({ path: abs, override: true, quiet: true });
5350
+ }
5351
+ }
5352
+ function getThisDir() {
5353
+ if (typeof __dirname === "string") return __dirname;
5354
+ const url = importMetaUrl;
5355
+ return import_node_path7.default.dirname((0, import_node_url2.fileURLToPath)(url));
5356
+ }
5357
+ function resolveShimPath(filename) {
5358
+ const thisDir = getThisDir();
5359
+ const candidates = [
5360
+ // Production: `dist/` next to this module
5361
+ import_node_path7.default.join(thisDir, "shims", filename),
5362
+ // Test / dev: one level up (e.g., from `dist/utils/` back to `src/shims/`)
5363
+ import_node_path7.default.join(thisDir, "..", "shims", filename),
5364
+ import_node_path7.default.join(thisDir, "..", "..", "src", "shims", filename),
5365
+ import_node_path7.default.join(thisDir, "..", "src", "shims", filename)
5366
+ ];
5367
+ for (const candidate of candidates) {
5368
+ if ((0, import_node_fs9.existsSync)(candidate)) return candidate;
5369
+ }
5370
+ return void 0;
5371
+ }
5372
+ function getShimRegisterPath() {
5373
+ return resolveShimPath("next-shims-register.mjs");
5374
+ }
5375
+ function getShimLoaderPath() {
5376
+ return resolveShimPath("next-shims-loader.mjs");
5377
+ }
5378
+ function getShimCjsPreloadPath() {
5379
+ return resolveShimPath("next-shims-cjs.cjs");
5380
+ }
5381
+ async function registerNextShimsInProcess() {
5382
+ let anyRegistered = false;
5383
+ const cjsPath = getShimCjsPreloadPath();
5384
+ if (cjsPath) {
5385
+ const { createRequire: createRequire3 } = await import("module");
5386
+ const req = createRequire3((0, import_node_url2.pathToFileURL)(getThisDir() + import_node_path7.default.sep).href);
5387
+ req(cjsPath);
5388
+ anyRegistered = true;
5389
+ }
5390
+ const loaderPath = getShimLoaderPath();
5391
+ if (loaderPath) {
5392
+ const { register } = await import("module");
5393
+ const loaderUrl = (0, import_node_url2.pathToFileURL)(loaderPath).href;
5394
+ register(loaderUrl, (0, import_node_url2.pathToFileURL)(getThisDir() + import_node_path7.default.sep).href);
5395
+ anyRegistered = true;
5396
+ }
5397
+ return anyRegistered;
5398
+ }
5399
+ function withNextShimsEnv(baseEnv) {
5400
+ const additions = [];
5401
+ const cjsPath = getShimCjsPreloadPath();
5402
+ if (cjsPath) additions.push(`-r ${quoteNodeOption(cjsPath)}`);
5403
+ const registerPath = getShimRegisterPath();
5404
+ if (registerPath)
5405
+ additions.push(`--import=${(0, import_node_url2.pathToFileURL)(registerPath).href}`);
5406
+ if (additions.length === 0) return baseEnv;
5407
+ const existing = baseEnv.NODE_OPTIONS ?? "";
5408
+ const prepended = additions.join(" ");
5409
+ return {
5410
+ ...baseEnv,
5411
+ NODE_OPTIONS: existing ? `${prepended} ${existing}` : prepended
5412
+ };
5413
+ }
5414
+ function quoteNodeOption(value) {
5415
+ return /\s/.test(value) ? `"${value}"` : value;
5416
+ }
5417
+
5418
+ // src/utils/update-check.ts
5419
+ var import_node_fs10 = require("fs");
5320
5420
  var import_promises6 = require("fs/promises");
5321
5421
  var import_node_module = require("module");
5322
5422
  var import_node_os6 = __toESM(require("os"), 1);
5323
- var import_node_path7 = __toESM(require("path"), 1);
5324
- var CACHE_DIR = import_node_path7.default.join(import_node_os6.default.homedir(), ".mcp-use");
5325
- var CACHE_FILE = import_node_path7.default.join(CACHE_DIR, "update-check.json");
5423
+ var import_node_path8 = __toESM(require("path"), 1);
5424
+ var CACHE_DIR = import_node_path8.default.join(import_node_os6.default.homedir(), ".mcp-use");
5425
+ var CACHE_FILE = import_node_path8.default.join(CACHE_DIR, "update-check.json");
5326
5426
  var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
5327
5427
  var FETCH_TIMEOUT_MS = 3e3;
5328
5428
  var PACKAGE_NAME = "mcp-use";
@@ -5405,16 +5505,16 @@ function resolveInstalledVersion(projectPath) {
5405
5505
  if (projectPath) {
5406
5506
  attempts.push(() => {
5407
5507
  const projectRequire = (0, import_node_module.createRequire)(
5408
- import_node_path7.default.join(projectPath, "package.json")
5508
+ import_node_path8.default.join(projectPath, "package.json")
5409
5509
  );
5410
5510
  return projectRequire.resolve(`${PACKAGE_NAME}/package.json`);
5411
5511
  });
5412
5512
  }
5413
- attempts.push(() => import_node_path7.default.join(__dirname, "../../mcp-use/package.json"));
5513
+ attempts.push(() => import_node_path8.default.join(__dirname, "../../mcp-use/package.json"));
5414
5514
  for (const attempt of attempts) {
5415
5515
  try {
5416
5516
  const pkgPath = attempt();
5417
- const json = JSON.parse((0, import_node_fs9.readFileSync)(pkgPath, "utf-8"));
5517
+ const json = JSON.parse((0, import_node_fs10.readFileSync)(pkgPath, "utf-8"));
5418
5518
  if (typeof json.version === "string") return json.version;
5419
5519
  } catch {
5420
5520
  }
@@ -5447,8 +5547,8 @@ A new release of ${source_default.bold(PACKAGE_NAME)} is available: ${source_def
5447
5547
 
5448
5548
  // src/index.ts
5449
5549
  var program = new import_commander6.Command();
5450
- var packageContent = (0, import_node_fs10.readFileSync)(
5451
- import_node_path8.default.join(__dirname, "../package.json"),
5550
+ var packageContent = (0, import_node_fs11.readFileSync)(
5551
+ import_node_path9.default.join(__dirname, "../package.json"),
5452
5552
  "utf-8"
5453
5553
  );
5454
5554
  var packageJson = JSON.parse(packageContent);
@@ -5479,16 +5579,16 @@ function displayPackageVersions(projectPath) {
5479
5579
  if (projectPath) {
5480
5580
  try {
5481
5581
  const projectRequire = (0, import_node_module2.createRequire)(
5482
- import_node_path8.default.join(projectPath, "package.json")
5582
+ import_node_path9.default.join(projectPath, "package.json")
5483
5583
  );
5484
5584
  pkgPath = projectRequire.resolve(`${pkg.name}/package.json`);
5485
5585
  } catch (resolveError) {
5486
- pkgPath = import_node_path8.default.join(__dirname, pkg.relativePath);
5586
+ pkgPath = import_node_path9.default.join(__dirname, pkg.relativePath);
5487
5587
  }
5488
5588
  } else {
5489
- pkgPath = import_node_path8.default.join(__dirname, pkg.relativePath);
5589
+ pkgPath = import_node_path9.default.join(__dirname, pkg.relativePath);
5490
5590
  }
5491
- const pkgContent = (0, import_node_fs10.readFileSync)(pkgPath, "utf-8");
5591
+ const pkgContent = (0, import_node_fs11.readFileSync)(pkgPath, "utf-8");
5492
5592
  const pkgJson = JSON.parse(pkgContent);
5493
5593
  const version = pkgJson.version || "unknown";
5494
5594
  if (pkg.highlight) {
@@ -5638,20 +5738,92 @@ async function startTunnel(port, subdomain) {
5638
5738
  }, 3e4);
5639
5739
  });
5640
5740
  }
5641
- async function findServerFile(projectPath) {
5741
+ async function resolveEntryFile(projectPath, cliEntry, mcpDir) {
5742
+ if (cliEntry) {
5743
+ await (0, import_promises7.access)(import_node_path9.default.join(projectPath, cliEntry)).catch(() => {
5744
+ throw new Error(`File not found: ${cliEntry}`);
5745
+ });
5746
+ return cliEntry;
5747
+ }
5748
+ if (mcpDir) {
5749
+ const mcpCandidates = [
5750
+ import_node_path9.default.join(mcpDir, "index.ts"),
5751
+ import_node_path9.default.join(mcpDir, "index.tsx"),
5752
+ import_node_path9.default.join(mcpDir, "server.ts"),
5753
+ import_node_path9.default.join(mcpDir, "server.tsx")
5754
+ ];
5755
+ for (const candidate of mcpCandidates) {
5756
+ try {
5757
+ await (0, import_promises7.access)(import_node_path9.default.join(projectPath, candidate));
5758
+ return candidate;
5759
+ } catch {
5760
+ continue;
5761
+ }
5762
+ }
5763
+ throw new Error(
5764
+ `No entry file found inside ${mcpDir}.
5765
+
5766
+ Expected one of: ${mcpCandidates.map((c) => import_node_path9.default.relative(projectPath, import_node_path9.default.join(projectPath, c))).join(", ")}
5767
+
5768
+ Fix this by either:
5769
+ 1. Creating ${import_node_path9.default.join(mcpDir, "index.ts")}, or
5770
+ 2. Passing --entry <file> on the command line`
5771
+ );
5772
+ }
5642
5773
  const candidates = ["index.ts", "src/index.ts", "server.ts", "src/server.ts"];
5643
5774
  for (const candidate of candidates) {
5644
5775
  try {
5645
- await (0, import_promises7.access)(import_node_path8.default.join(projectPath, candidate));
5776
+ await (0, import_promises7.access)(import_node_path9.default.join(projectPath, candidate));
5646
5777
  return candidate;
5647
5778
  } catch {
5648
5779
  continue;
5649
5780
  }
5650
5781
  }
5651
- throw new Error("No server file found");
5782
+ throw new Error(
5783
+ `No entry file found.
5784
+
5785
+ Expected one of: ${candidates.join(", ")}
5786
+
5787
+ Fix this by either:
5788
+ 1. Creating one of the default entry files above, or
5789
+ 2. Passing --entry <file> or --mcp-dir <dir> on the command line`
5790
+ );
5791
+ }
5792
+ function resolveWidgetsDir(cliWidgetsDir, mcpDir) {
5793
+ if (cliWidgetsDir) return cliWidgetsDir;
5794
+ if (mcpDir) return import_node_path9.default.join(mcpDir, "resources");
5795
+ return "resources";
5796
+ }
5797
+ function makeWidgetServerOnlyGuard(widgetName) {
5798
+ const rejected = /* @__PURE__ */ new Set([
5799
+ "server-only",
5800
+ "client-only",
5801
+ "next/cache",
5802
+ "next/headers",
5803
+ "next/navigation",
5804
+ "next/server"
5805
+ ]);
5806
+ return {
5807
+ name: "mcp-use-widget-server-only-guard",
5808
+ enforce: "pre",
5809
+ resolveId(id, importer) {
5810
+ if (!rejected.has(id)) return null;
5811
+ const from = importer ? ` (imported from ${importer})` : "";
5812
+ throw new Error(
5813
+ `Widget "${widgetName}" imports "${id}"${from}, which is a Next.js server-only module. Widgets run in a browser iframe and cannot use server APIs.
5814
+
5815
+ To fix:
5816
+ \u2022 Remove the import from the widget (or from any module the widget transitively imports)
5817
+ \u2022 If the widget needs data from ${id}, read it inside an MCP tool in your server and pass the result through the widget's props`
5818
+ );
5819
+ }
5820
+ };
5821
+ }
5822
+ async function findServerFile(projectPath, cliEntry, cliMcpDir) {
5823
+ return resolveEntryFile(projectPath, cliEntry, cliMcpDir);
5652
5824
  }
5653
5825
  async function generateToolRegistryTypesForServer(projectPath, serverFileRelative) {
5654
- const serverFile = import_node_path8.default.join(projectPath, serverFileRelative);
5826
+ const serverFile = import_node_path9.default.join(projectPath, serverFileRelative);
5655
5827
  const serverFileExists = await (0, import_promises7.access)(serverFile).then(() => true).catch(() => false);
5656
5828
  if (!serverFileExists) {
5657
5829
  throw new Error(`Server file not found: ${serverFile}`);
@@ -5660,19 +5832,48 @@ async function generateToolRegistryTypesForServer(projectPath, serverFileRelativ
5660
5832
  try {
5661
5833
  globalThis.__mcpUseHmrMode = true;
5662
5834
  globalThis.__mcpUseLastServer = void 0;
5663
- const { tsImport } = await import("tsx/esm/api");
5664
- await tsImport((0, import_node_url2.pathToFileURL)(serverFile).href, {
5665
- parentURL: importMetaUrl,
5666
- tsconfig: import_node_path8.default.join(projectPath, "tsconfig.json")
5667
- });
5835
+ if (await detectNextJsProject(projectPath)) {
5836
+ await loadNextJsEnvFiles(projectPath);
5837
+ await registerNextShimsInProcess();
5838
+ }
5839
+ const projectTsconfigPath = import_node_path9.default.join(projectPath, "tsconfig.json");
5840
+ const hasTsconfig = await (0, import_promises7.access)(projectTsconfigPath).then(() => true).catch(() => false);
5841
+ if (hasTsconfig) {
5842
+ process.env.TSX_TSCONFIG_PATH = projectTsconfigPath;
5843
+ }
5844
+ const previousCwd = process.cwd();
5845
+ if (previousCwd !== projectPath) process.chdir(projectPath);
5846
+ try {
5847
+ const projectRequire = (0, import_node_module2.createRequire)(
5848
+ import_node_path9.default.join(projectPath, "package.json")
5849
+ );
5850
+ const tsxEsmApiPath = projectRequire.resolve("tsx/esm/api");
5851
+ const tsxEsmApi = await import((0, import_node_url3.pathToFileURL)(tsxEsmApiPath).href);
5852
+ if (typeof tsxEsmApi.register === "function") {
5853
+ tsxEsmApi.register({
5854
+ tsconfig: hasTsconfig ? projectTsconfigPath : void 0
5855
+ });
5856
+ }
5857
+ try {
5858
+ const tsxCjsApiPath = projectRequire.resolve("tsx/cjs/api");
5859
+ const tsxCjsApi = await import((0, import_node_url3.pathToFileURL)(tsxCjsApiPath).href);
5860
+ if (typeof tsxCjsApi.register === "function") {
5861
+ tsxCjsApi.register();
5862
+ }
5863
+ } catch {
5864
+ }
5865
+ await import(`${(0, import_node_url3.pathToFileURL)(serverFile).href}?t=${Date.now()}`);
5866
+ } finally {
5867
+ if (process.cwd() !== previousCwd) process.chdir(previousCwd);
5868
+ }
5668
5869
  const server = globalThis.__mcpUseLastServer;
5669
5870
  if (!server) {
5670
5871
  throw new Error(
5671
5872
  "No MCPServer instance found. Make sure your server file creates an MCPServer instance."
5672
5873
  );
5673
5874
  }
5674
- const mcpUsePath = import_node_path8.default.join(projectPath, "node_modules", "mcp-use");
5675
- const { generateToolRegistryTypes } = await import((0, import_node_url2.pathToFileURL)(import_node_path8.default.join(mcpUsePath, "dist", "src", "server", "index.js")).href).then((mod) => mod);
5875
+ const mcpUsePath = import_node_path9.default.join(projectPath, "node_modules", "mcp-use");
5876
+ const { generateToolRegistryTypes } = await import((0, import_node_url3.pathToFileURL)(import_node_path9.default.join(mcpUsePath, "dist", "src", "server", "index.js")).href).then((mod) => mod);
5676
5877
  if (!generateToolRegistryTypes) {
5677
5878
  throw new Error("generateToolRegistryTypes not found in mcp-use package");
5678
5879
  }
@@ -5687,21 +5888,24 @@ async function generateToolRegistryTypesForServer(projectPath, serverFileRelativ
5687
5888
  }
5688
5889
  async function buildWidgets(projectPath, options = {}) {
5689
5890
  const { inline = true } = options;
5690
- const { promises: fs10 } = await import("fs");
5891
+ const { promises: fs11 } = await import("fs");
5691
5892
  const { build } = await import("vite");
5692
- const resourcesDir = import_node_path8.default.join(projectPath, "resources");
5893
+ const widgetsDirRelative = options.widgetsDir ?? "resources";
5894
+ const resourcesDir = import_node_path9.default.resolve(projectPath, widgetsDirRelative);
5693
5895
  const mcpUrl = process.env.MCP_URL;
5694
5896
  try {
5695
5897
  await (0, import_promises7.access)(resourcesDir);
5696
5898
  } catch {
5697
5899
  console.log(
5698
- source_default.gray("No resources/ directory found - skipping widget build")
5900
+ source_default.gray(
5901
+ `No ${widgetsDirRelative}/ directory found - skipping widget build`
5902
+ )
5699
5903
  );
5700
5904
  return [];
5701
5905
  }
5702
5906
  const entries = [];
5703
5907
  try {
5704
- const files = await fs10.readdir(resourcesDir, { withFileTypes: true });
5908
+ const files = await fs11.readdir(resourcesDir, { withFileTypes: true });
5705
5909
  for (const dirent of files) {
5706
5910
  if (dirent.name.startsWith("._") || dirent.name.startsWith(".DS_Store")) {
5707
5911
  continue;
@@ -5709,12 +5913,12 @@ async function buildWidgets(projectPath, options = {}) {
5709
5913
  if (dirent.isFile() && (dirent.name.endsWith(".tsx") || dirent.name.endsWith(".ts"))) {
5710
5914
  entries.push({
5711
5915
  name: dirent.name.replace(/\.tsx?$/, ""),
5712
- path: import_node_path8.default.join(resourcesDir, dirent.name)
5916
+ path: import_node_path9.default.join(resourcesDir, dirent.name)
5713
5917
  });
5714
5918
  } else if (dirent.isDirectory()) {
5715
- const widgetPath = import_node_path8.default.join(resourcesDir, dirent.name, "widget.tsx");
5919
+ const widgetPath = import_node_path9.default.join(resourcesDir, dirent.name, "widget.tsx");
5716
5920
  try {
5717
- await fs10.access(widgetPath);
5921
+ await fs11.access(widgetPath);
5718
5922
  entries.push({
5719
5923
  name: dirent.name,
5720
5924
  path: widgetPath
@@ -5724,11 +5928,15 @@ async function buildWidgets(projectPath, options = {}) {
5724
5928
  }
5725
5929
  }
5726
5930
  } catch (error) {
5727
- console.log(source_default.gray("No widgets found in resources/ directory"));
5931
+ console.log(
5932
+ source_default.gray(`No widgets found in ${widgetsDirRelative}/ directory`)
5933
+ );
5728
5934
  return [];
5729
5935
  }
5730
5936
  if (entries.length === 0) {
5731
- console.log(source_default.gray("No widgets found in resources/ directory"));
5937
+ console.log(
5938
+ source_default.gray(`No widgets found in ${widgetsDirRelative}/ directory`)
5939
+ );
5732
5940
  return [];
5733
5941
  }
5734
5942
  console.log(
@@ -5738,10 +5946,17 @@ async function buildWidgets(projectPath, options = {}) {
5738
5946
  );
5739
5947
  const react = (await import("@vitejs/plugin-react")).default;
5740
5948
  const tailwindcss = (await import("@tailwindcss/vite")).default;
5741
- const packageJsonPath = import_node_path8.default.join(projectPath, "package.json");
5949
+ const projectTsconfigPath = import_node_path9.default.join(projectPath, "tsconfig.json");
5950
+ let hasProjectTsconfig = false;
5951
+ try {
5952
+ await (0, import_promises7.access)(projectTsconfigPath);
5953
+ hasProjectTsconfig = true;
5954
+ } catch {
5955
+ }
5956
+ const packageJsonPath = import_node_path9.default.join(projectPath, "package.json");
5742
5957
  let favicon = "";
5743
5958
  try {
5744
- const pkgContent = await fs10.readFile(packageJsonPath, "utf-8");
5959
+ const pkgContent = await fs11.readFile(packageJsonPath, "utf-8");
5745
5960
  const pkg = JSON.parse(pkgContent);
5746
5961
  favicon = pkg.mcpUse?.favicon || "";
5747
5962
  } catch {
@@ -5750,18 +5965,27 @@ async function buildWidgets(projectPath, options = {}) {
5750
5965
  const widgetName = entry.name;
5751
5966
  const entryPath = entry.path.replace(/\\/g, "/");
5752
5967
  console.log(source_default.gray(` - Building ${widgetName}...`));
5753
- const tempDir = import_node_path8.default.join(projectPath, ".mcp-use", widgetName);
5754
- await fs10.mkdir(tempDir, { recursive: true });
5755
- const relativeResourcesPath = import_node_path8.default.relative(tempDir, resourcesDir).replace(/\\/g, "/");
5756
- const mcpUsePath = import_node_path8.default.join(projectPath, "node_modules", "mcp-use");
5757
- const relativeMcpUsePath = import_node_path8.default.relative(tempDir, mcpUsePath).replace(/\\/g, "/");
5968
+ const tempDir = import_node_path9.default.join(projectPath, ".mcp-use", widgetName);
5969
+ await fs11.mkdir(tempDir, { recursive: true });
5970
+ const relativeResourcesPath = import_node_path9.default.relative(tempDir, resourcesDir).replace(/\\/g, "/");
5971
+ const mcpUsePath = import_node_path9.default.join(projectPath, "node_modules", "mcp-use");
5972
+ const relativeMcpUsePath = import_node_path9.default.relative(tempDir, mcpUsePath).replace(/\\/g, "/");
5973
+ const projectSrcDir = import_node_path9.default.join(projectPath, "src");
5974
+ let projectSrcSourceLine = "";
5975
+ try {
5976
+ await (0, import_promises7.access)(projectSrcDir);
5977
+ const relativeProjectSrcPath = import_node_path9.default.relative(tempDir, projectSrcDir).replace(/\\/g, "/");
5978
+ projectSrcSourceLine = `@source "${relativeProjectSrcPath}";
5979
+ `;
5980
+ } catch {
5981
+ }
5758
5982
  const cssContent = `@import "tailwindcss";
5759
5983
 
5760
5984
  /* Configure Tailwind to scan the resources directory and mcp-use package */
5761
5985
  @source "${relativeResourcesPath}";
5762
5986
  @source "${relativeMcpUsePath}/**/*.{ts,tsx,js,jsx}";
5763
- `;
5764
- await fs10.writeFile(import_node_path8.default.join(tempDir, "styles.css"), cssContent, "utf8");
5987
+ ${projectSrcSourceLine}`;
5988
+ await fs11.writeFile(import_node_path9.default.join(tempDir, "styles.css"), cssContent, "utf8");
5765
5989
  const entryContent = `import React from 'react'
5766
5990
  import { createRoot } from 'react-dom/client'
5767
5991
  import './styles.css'
@@ -5786,9 +6010,9 @@ if (container && Component) {
5786
6010
  <script type="module" src="/entry.tsx"></script>
5787
6011
  </body>
5788
6012
  </html>`;
5789
- await fs10.writeFile(import_node_path8.default.join(tempDir, "entry.tsx"), entryContent, "utf8");
5790
- await fs10.writeFile(import_node_path8.default.join(tempDir, "index.html"), htmlContent, "utf8");
5791
- const outDir = import_node_path8.default.join(
6013
+ await fs11.writeFile(import_node_path9.default.join(tempDir, "entry.tsx"), entryContent, "utf8");
6014
+ await fs11.writeFile(import_node_path9.default.join(tempDir, "index.html"), htmlContent, "utf8");
6015
+ const outDir = import_node_path9.default.join(
5792
6016
  projectPath,
5793
6017
  "dist",
5794
6018
  "resources",
@@ -5798,12 +6022,12 @@ if (container && Component) {
5798
6022
  const baseUrl = mcpUrl ? `${mcpUrl}/${widgetName}/` : `/mcp-use/widgets/${widgetName}/`;
5799
6023
  let widgetMetadata = {};
5800
6024
  try {
5801
- const metadataTempDir = import_node_path8.default.join(
6025
+ const metadataTempDir = import_node_path9.default.join(
5802
6026
  projectPath,
5803
6027
  ".mcp-use",
5804
6028
  `${widgetName}-metadata`
5805
6029
  );
5806
- await fs10.mkdir(metadataTempDir, { recursive: true });
6030
+ await fs11.mkdir(metadataTempDir, { recursive: true });
5807
6031
  const { createServer } = await import("vite");
5808
6032
  const nodeStubsPlugin = {
5809
6033
  name: "node-stubs",
@@ -5831,15 +6055,16 @@ export default PostHog;
5831
6055
  return null;
5832
6056
  }
5833
6057
  };
6058
+ const serverOnlyGuard = makeWidgetServerOnlyGuard(widgetName);
5834
6059
  const metadataServer = await createServer({
5835
6060
  root: metadataTempDir,
5836
- cacheDir: import_node_path8.default.join(metadataTempDir, ".vite-cache"),
5837
- plugins: [nodeStubsPlugin, tailwindcss(), react()],
5838
- resolve: {
5839
- alias: {
5840
- "@": resourcesDir
5841
- }
5842
- },
6061
+ cacheDir: import_node_path9.default.join(metadataTempDir, ".vite-cache"),
6062
+ plugins: [serverOnlyGuard, nodeStubsPlugin, tailwindcss(), react()],
6063
+ // When the project has a tsconfig, enable Vite's native tsconfig-paths
6064
+ // resolver so `@/*` (or any custom alias) resolves through the
6065
+ // project's own paths config. Without a tsconfig, fall back to the
6066
+ // legacy hardcoded alias.
6067
+ resolve: hasProjectTsconfig ? { tsconfigPaths: true } : { alias: { "@": resourcesDir } },
5843
6068
  server: {
5844
6069
  middlewareMode: true
5845
6070
  },
@@ -5918,7 +6143,7 @@ export default PostHog;
5918
6143
  } finally {
5919
6144
  await metadataServer.close();
5920
6145
  try {
5921
- await fs10.rm(metadataTempDir, { recursive: true, force: true });
6146
+ await fs11.rm(metadataTempDir, { recursive: true, force: true });
5922
6147
  } catch {
5923
6148
  }
5924
6149
  }
@@ -6013,12 +6238,14 @@ export default {
6013
6238
  return null;
6014
6239
  }
6015
6240
  };
6241
+ const buildServerOnlyGuard = makeWidgetServerOnlyGuard(widgetName);
6016
6242
  const buildPlugins = inline ? [
6243
+ buildServerOnlyGuard,
6017
6244
  buildNodeStubsPlugin,
6018
6245
  tailwindcss(),
6019
6246
  react(),
6020
6247
  (0, import_vite_plugin_singlefile.viteSingleFile)({ removeViteModuleLoader: true })
6021
- ] : [buildNodeStubsPlugin, tailwindcss(), react()];
6248
+ ] : [buildServerOnlyGuard, buildNodeStubsPlugin, tailwindcss(), react()];
6022
6249
  await build({
6023
6250
  root: tempDir,
6024
6251
  base: baseUrl,
@@ -6037,11 +6264,10 @@ export default {
6037
6264
  }
6038
6265
  }
6039
6266
  },
6040
- resolve: {
6041
- alias: {
6042
- "@": resourcesDir
6043
- }
6044
- },
6267
+ // When a tsconfig exists, enable Vite's native `resolve.tsconfigPaths`
6268
+ // so the project's path aliases resolve naturally. Otherwise fall
6269
+ // back to the legacy `@` → resourcesDir alias.
6270
+ resolve: hasProjectTsconfig ? { tsconfigPaths: true } : { alias: { "@": resourcesDir } },
6045
6271
  optimizeDeps: {
6046
6272
  // Exclude Node.js-only packages from browser bundling
6047
6273
  exclude: ["posthog-node"]
@@ -6063,7 +6289,7 @@ export default {
6063
6289
  // Inline all assets under 100MB (effectively all)
6064
6290
  } : {},
6065
6291
  rolldownOptions: {
6066
- input: import_node_path8.default.join(tempDir, "index.html"),
6292
+ input: import_node_path9.default.join(tempDir, "index.html"),
6067
6293
  external: (id) => {
6068
6294
  return false;
6069
6295
  }
@@ -6071,12 +6297,12 @@ export default {
6071
6297
  }
6072
6298
  });
6073
6299
  try {
6074
- const assetsDir = import_node_path8.default.join(outDir, "assets");
6075
- const assetFiles = await fs10.readdir(assetsDir);
6300
+ const assetsDir = import_node_path9.default.join(outDir, "assets");
6301
+ const assetFiles = await fs11.readdir(assetsDir);
6076
6302
  const jsFiles = assetFiles.filter((f) => f.endsWith(".js"));
6077
6303
  for (const jsFile of jsFiles) {
6078
- const jsPath = import_node_path8.default.join(assetsDir, jsFile);
6079
- let content = await fs10.readFile(jsPath, "utf8");
6304
+ const jsPath = import_node_path9.default.join(assetsDir, jsFile);
6305
+ let content = await fs11.readFile(jsPath, "utf8");
6080
6306
  const zodConfigPatterns = [
6081
6307
  // Non-minified: export const globalConfig = {}
6082
6308
  /export\s+const\s+globalConfig\s*=\s*\{\s*\}/g,
@@ -6095,7 +6321,7 @@ export default {
6095
6321
  }
6096
6322
  }
6097
6323
  if (patched) {
6098
- await fs10.writeFile(jsPath, content, "utf8");
6324
+ await fs11.writeFile(jsPath, content, "utf8");
6099
6325
  console.log(source_default.gray(` \u2192 Patched Zod JIT in ${jsFile}`));
6100
6326
  }
6101
6327
  }
@@ -6107,8 +6333,8 @@ export default {
6107
6333
  const mcpServerUrl = process.env.MCP_SERVER_URL;
6108
6334
  if (mcpServerUrl) {
6109
6335
  try {
6110
- const htmlPath = import_node_path8.default.join(outDir, "index.html");
6111
- let html = await fs10.readFile(htmlPath, "utf8");
6336
+ const htmlPath = import_node_path9.default.join(outDir, "index.html");
6337
+ let html = await fs11.readFile(htmlPath, "utf8");
6112
6338
  const injectionScript = `<script>window.__getFile = (filename) => { return "${mcpUrl}/${widgetName}/"+filename }; window.__mcpPublicUrl = "${mcpServerUrl}/mcp-use/public"; window.__mcpPublicAssetsUrl = "${mcpUrl}/public";</script>`;
6113
6339
  if (!html.includes("window.__mcpPublicUrl")) {
6114
6340
  html = html.replace(
@@ -6129,7 +6355,7 @@ export default {
6129
6355
  <base href="${mcpServerUrl}">`
6130
6356
  );
6131
6357
  }
6132
- await fs10.writeFile(htmlPath, html, "utf8");
6358
+ await fs11.writeFile(htmlPath, html, "utf8");
6133
6359
  console.log(
6134
6360
  source_default.gray(` \u2192 Injected MCP_SERVER_URL into ${widgetName}`)
6135
6361
  );
@@ -6143,22 +6369,32 @@ export default {
6143
6369
  }
6144
6370
  }
6145
6371
  console.log(source_default.green(` \u2713 Built ${widgetName}`));
6146
- return { name: widgetName, metadata: widgetMetadata };
6372
+ return {
6373
+ status: "built",
6374
+ name: widgetName,
6375
+ metadata: widgetMetadata
6376
+ };
6147
6377
  } catch (error) {
6148
6378
  console.error(source_default.red(` \u2717 Failed to build ${widgetName}:`), error);
6149
- return null;
6379
+ return { status: "failed", name: widgetName };
6150
6380
  }
6151
6381
  };
6152
6382
  const buildResults = await Promise.all(
6153
6383
  entries.map((entry) => buildSingleWidget(entry))
6154
6384
  );
6155
- const builtWidgets = buildResults.filter(
6156
- (result) => result !== null
6385
+ const failed = buildResults.filter((r) => r.status === "failed");
6386
+ if (failed.length > 0) {
6387
+ const names = failed.map((f) => f.name).join(", ");
6388
+ throw new Error(
6389
+ `${failed.length} widget(s) failed to build: ${names}. See errors above.`
6390
+ );
6391
+ }
6392
+ return buildResults.flatMap(
6393
+ (r) => r.status === "built" ? [{ name: r.name, metadata: r.metadata }] : []
6157
6394
  );
6158
- return builtWidgets;
6159
6395
  }
6160
6396
  async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
6161
- const { promises: fs10 } = await import("fs");
6397
+ const { promises: fs11 } = await import("fs");
6162
6398
  const literalFiles = [];
6163
6399
  const dirPrefixes = [];
6164
6400
  for (const pattern of includePatterns) {
@@ -6173,7 +6409,7 @@ async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
6173
6409
  for (const file of literalFiles) {
6174
6410
  if (/\.tsx?$/.test(file) && !file.endsWith(".d.ts")) {
6175
6411
  try {
6176
- await (0, import_promises7.access)(import_node_path8.default.join(projectPath, file));
6412
+ await (0, import_promises7.access)(import_node_path9.default.join(projectPath, file));
6177
6413
  files.push(file);
6178
6414
  } catch {
6179
6415
  }
@@ -6181,13 +6417,13 @@ async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
6181
6417
  }
6182
6418
  const excludeSet = new Set(excludePatterns.map((e) => e.replace(/\*+/g, "")));
6183
6419
  for (const prefix of dirPrefixes) {
6184
- const dirPath = import_node_path8.default.join(projectPath, prefix);
6420
+ const dirPath = import_node_path9.default.join(projectPath, prefix);
6185
6421
  try {
6186
- const entries = await fs10.readdir(dirPath, { recursive: true });
6422
+ const entries = await fs11.readdir(dirPath, { recursive: true });
6187
6423
  for (const entry of entries) {
6188
6424
  const entryStr = String(entry);
6189
- const rel = import_node_path8.default.join(prefix, entryStr);
6190
- if (/\.tsx?$/.test(entryStr) && !entryStr.endsWith(".d.ts") && !excludeSet.has(rel.split(import_node_path8.default.sep)[0])) {
6425
+ const rel = import_node_path9.default.join(prefix, entryStr);
6426
+ if (/\.tsx?$/.test(entryStr) && !entryStr.endsWith(".d.ts") && !excludeSet.has(rel.split(import_node_path9.default.sep)[0])) {
6191
6427
  files.push(rel);
6192
6428
  }
6193
6429
  }
@@ -6198,11 +6434,11 @@ async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
6198
6434
  }
6199
6435
  async function transpileWithEsbuild(projectPath) {
6200
6436
  const esbuild = await import("esbuild");
6201
- const { promises: fs10 } = await import("fs");
6202
- const tsconfigPath = import_node_path8.default.join(projectPath, "tsconfig.json");
6437
+ const { promises: fs11 } = await import("fs");
6438
+ const tsconfigPath = import_node_path9.default.join(projectPath, "tsconfig.json");
6203
6439
  let tsconfig = {};
6204
6440
  try {
6205
- const raw = await fs10.readFile(tsconfigPath, "utf-8");
6441
+ const raw = await fs11.readFile(tsconfigPath, "utf-8");
6206
6442
  tsconfig = JSON.parse(raw);
6207
6443
  } catch {
6208
6444
  }
@@ -6229,10 +6465,10 @@ async function transpileWithEsbuild(projectPath) {
6229
6465
  const target = (compilerOptions.target || "ES2022").toLowerCase();
6230
6466
  const moduleStr = (compilerOptions.module || "ESNext").toLowerCase();
6231
6467
  const format = moduleStr.includes("commonjs") ? "cjs" : "esm";
6232
- const outbase = compilerOptions.rootDir ? import_node_path8.default.resolve(projectPath, compilerOptions.rootDir) : projectPath;
6468
+ const outbase = compilerOptions.rootDir ? import_node_path9.default.resolve(projectPath, compilerOptions.rootDir) : projectPath;
6233
6469
  await esbuild.build({
6234
- entryPoints: files.map((f) => import_node_path8.default.join(projectPath, f)),
6235
- outdir: import_node_path8.default.join(projectPath, outDir),
6470
+ entryPoints: files.map((f) => import_node_path9.default.join(projectPath, f)),
6471
+ outdir: import_node_path9.default.join(projectPath, outDir),
6236
6472
  outbase,
6237
6473
  bundle: false,
6238
6474
  format,
@@ -6244,21 +6480,42 @@ async function transpileWithEsbuild(projectPath) {
6244
6480
  logLevel: "warning"
6245
6481
  });
6246
6482
  }
6247
- 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").option(
6483
+ program.command("build").description("Build TypeScript and MCP UI widgets").option("-p, --path <path>", "Path to project directory", process.cwd()).option(
6484
+ "--entry <file>",
6485
+ "Path to MCP server entry file (relative to project)"
6486
+ ).option(
6487
+ "--widgets-dir <dir>",
6488
+ "Path to widgets directory (relative to project)"
6489
+ ).option(
6490
+ "--mcp-dir <dir>",
6491
+ "Folder holding the MCP entry + resources (e.g. 'src/mcp' for Next.js apps)"
6492
+ ).option("--with-inspector", "Include inspector in production build").option(
6248
6493
  "--inline",
6249
6494
  "Inline all JS/CSS into HTML (required for VS Code MCP Apps)"
6250
6495
  ).option("--no-inline", "Keep JS/CSS as separate files (default)").option("--no-typecheck", "Skip TypeScript type checking (faster builds)").action(async (options) => {
6251
6496
  try {
6252
- const projectPath = import_node_path8.default.resolve(options.path);
6253
- const { promises: fs10 } = await import("fs");
6497
+ const projectPath = import_node_path9.default.resolve(options.path);
6498
+ const { promises: fs11 } = await import("fs");
6254
6499
  displayPackageVersions(projectPath);
6500
+ const mcpDir = options.mcpDir;
6501
+ const widgetsDir = resolveWidgetsDir(options.widgetsDir, mcpDir);
6255
6502
  const builtWidgets = await buildWidgets(projectPath, {
6256
- inline: options.inline ?? false
6503
+ inline: options.inline ?? false,
6504
+ widgetsDir
6257
6505
  });
6258
6506
  let sourceServerFile;
6259
6507
  try {
6260
- sourceServerFile = await findServerFile(projectPath);
6261
- } catch {
6508
+ sourceServerFile = await findServerFile(
6509
+ projectPath,
6510
+ options.entry,
6511
+ options.mcpDir
6512
+ );
6513
+ } catch (err) {
6514
+ console.log(
6515
+ source_default.yellow(
6516
+ `\u26A0 Could not locate a server entry file: ${err instanceof Error ? err.message : String(err)}`
6517
+ )
6518
+ );
6262
6519
  }
6263
6520
  if (sourceServerFile) {
6264
6521
  console.log(source_default.gray("Generating tool registry types..."));
@@ -6276,17 +6533,25 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
6276
6533
  );
6277
6534
  }
6278
6535
  }
6279
- console.log(source_default.gray("Building TypeScript..."));
6280
- await transpileWithEsbuild(projectPath);
6281
- console.log(source_default.green("\u2713 TypeScript build complete!"));
6282
- if (options.typecheck !== false) {
6536
+ if (!mcpDir) {
6537
+ console.log(source_default.gray("Building TypeScript..."));
6538
+ await transpileWithEsbuild(projectPath);
6539
+ console.log(source_default.green("\u2713 TypeScript build complete!"));
6540
+ } else {
6541
+ console.log(
6542
+ source_default.gray(
6543
+ "Skipping TypeScript transpile (--mcp-dir mode runs source via tsx at start time)"
6544
+ )
6545
+ );
6546
+ }
6547
+ if (options.typecheck !== false && !mcpDir) {
6283
6548
  console.log(source_default.gray("Type checking..."));
6284
6549
  try {
6285
6550
  await runCommand(
6286
6551
  "node",
6287
6552
  [
6288
6553
  "--max-old-space-size=4096",
6289
- import_node_path8.default.join(
6554
+ import_node_path9.default.join(
6290
6555
  projectPath,
6291
6556
  "node_modules",
6292
6557
  "typescript",
@@ -6307,39 +6572,43 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
6307
6572
  }
6308
6573
  let entryPoint;
6309
6574
  if (sourceServerFile) {
6310
- const baseName = import_node_path8.default.basename(sourceServerFile, ".ts") + ".js";
6311
- const possibleOutputs = [
6312
- `dist/${baseName}`,
6313
- // rootDir set to project root or src
6314
- `dist/src/${baseName}`,
6315
- // no rootDir, source in src/
6316
- `dist/${sourceServerFile.replace(/\.ts$/, ".js")}`
6317
- // exact path preserved
6318
- ];
6319
- for (const candidate of possibleOutputs) {
6320
- try {
6321
- await (0, import_promises7.access)(import_node_path8.default.join(projectPath, candidate));
6322
- entryPoint = candidate;
6323
- break;
6324
- } catch {
6325
- continue;
6575
+ if (mcpDir) {
6576
+ entryPoint = sourceServerFile;
6577
+ } else {
6578
+ const baseName = import_node_path9.default.basename(sourceServerFile, ".ts") + ".js";
6579
+ const possibleOutputs = [
6580
+ `dist/${baseName}`,
6581
+ // rootDir set to project root or src
6582
+ `dist/src/${baseName}`,
6583
+ // no rootDir, source in src/
6584
+ `dist/${sourceServerFile.replace(/\.ts$/, ".js")}`
6585
+ // exact path preserved
6586
+ ];
6587
+ for (const candidate of possibleOutputs) {
6588
+ try {
6589
+ await (0, import_promises7.access)(import_node_path9.default.join(projectPath, candidate));
6590
+ entryPoint = candidate;
6591
+ break;
6592
+ } catch {
6593
+ continue;
6594
+ }
6326
6595
  }
6327
6596
  }
6328
6597
  }
6329
- const publicDir = import_node_path8.default.join(projectPath, "public");
6598
+ const publicDir = import_node_path9.default.join(projectPath, "public");
6330
6599
  try {
6331
- await fs10.access(publicDir);
6600
+ await fs11.access(publicDir);
6332
6601
  console.log(source_default.gray("Copying public assets..."));
6333
- await fs10.cp(publicDir, import_node_path8.default.join(projectPath, "dist", "public"), {
6602
+ await fs11.cp(publicDir, import_node_path9.default.join(projectPath, "dist", "public"), {
6334
6603
  recursive: true
6335
6604
  });
6336
6605
  console.log(source_default.green("\u2713 Public assets copied"));
6337
6606
  } catch {
6338
6607
  }
6339
- const manifestPath = import_node_path8.default.join(projectPath, "dist", "mcp-use.json");
6608
+ const manifestPath = import_node_path9.default.join(projectPath, "dist", "mcp-use.json");
6340
6609
  let existingManifest = {};
6341
6610
  try {
6342
- const existingContent = await fs10.readFile(manifestPath, "utf-8");
6611
+ const existingContent = await fs11.readFile(manifestPath, "utf-8");
6343
6612
  existingManifest = JSON.parse(existingContent);
6344
6613
  } catch {
6345
6614
  }
@@ -6361,8 +6630,8 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
6361
6630
  // Server entry point for `mcp-use start`
6362
6631
  widgets: widgetsData
6363
6632
  };
6364
- await fs10.mkdir(import_node_path8.default.dirname(manifestPath), { recursive: true });
6365
- await fs10.writeFile(
6633
+ await fs11.mkdir(import_node_path9.default.dirname(manifestPath), { recursive: true });
6634
+ await fs11.writeFile(
6366
6635
  manifestPath,
6367
6636
  JSON.stringify(manifest, null, 2),
6368
6637
  "utf8"
@@ -6382,14 +6651,23 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
6382
6651
  process.exit(1);
6383
6652
  }
6384
6653
  });
6385
- 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(
6654
+ program.command("dev").description("Run development server with auto-reload and inspector").option("-p, --path <path>", "Path to project directory", process.cwd()).option(
6655
+ "--entry <file>",
6656
+ "Path to MCP server entry file (relative to project)"
6657
+ ).option(
6658
+ "--widgets-dir <dir>",
6659
+ "Path to widgets directory (relative to project)"
6660
+ ).option(
6661
+ "--mcp-dir <dir>",
6662
+ "Folder holding the MCP entry + resources (e.g. 'src/mcp' for Next.js apps)"
6663
+ ).option("--port <port>", "Server port", "3000").option(
6386
6664
  "--host <host>",
6387
6665
  "Server host (use 0.0.0.0 to listen on all interfaces)",
6388
6666
  "0.0.0.0"
6389
6667
  ).option("--no-open", "Do not auto-open inspector").option("--no-hmr", "Disable hot module reloading (use tsx watch instead)").option("--tunnel", "Expose server through a tunnel").action(async (options) => {
6390
6668
  try {
6391
6669
  process.env.MCP_USE_CLI_DEV = "1";
6392
- const projectPath = import_node_path8.default.resolve(options.path);
6670
+ const projectPath = import_node_path9.default.resolve(options.path);
6393
6671
  let port = parseInt(options.port, 10);
6394
6672
  const host = options.host;
6395
6673
  const useHmr = options.hmr !== false;
@@ -6400,13 +6678,24 @@ program.command("dev").description("Run development server with auto-reload and
6400
6678
  console.log(source_default.green.bold(`\u2713 Using port ${availablePort} instead`));
6401
6679
  port = availablePort;
6402
6680
  }
6403
- const serverFile = await findServerFile(projectPath);
6681
+ const serverFile = await findServerFile(
6682
+ projectPath,
6683
+ options.entry,
6684
+ options.mcpDir
6685
+ );
6686
+ {
6687
+ const devMcpDir = options.mcpDir;
6688
+ const devWidgetsDir = resolveWidgetsDir(options.widgetsDir, devMcpDir);
6689
+ if (devWidgetsDir !== "resources") {
6690
+ process.env.MCP_USE_WIDGETS_DIR = devWidgetsDir;
6691
+ }
6692
+ }
6404
6693
  let tunnelProcess = void 0;
6405
6694
  let tunnelSubdomain = void 0;
6406
6695
  let tunnelUrl = void 0;
6407
6696
  if (options.tunnel) {
6408
6697
  try {
6409
- const manifestPath = import_node_path8.default.join(projectPath, "dist", "mcp-use.json");
6698
+ const manifestPath = import_node_path9.default.join(projectPath, "dist", "mcp-use.json");
6410
6699
  let existingSubdomain;
6411
6700
  try {
6412
6701
  const manifestContent = await (0, import_promises7.readFile)(manifestPath, "utf-8");
@@ -6455,7 +6744,7 @@ program.command("dev").description("Run development server with auto-reload and
6455
6744
  manifest.tunnel = {};
6456
6745
  }
6457
6746
  manifest.tunnel.subdomain = tunnelSubdomain;
6458
- await (0, import_promises7.mkdir)(import_node_path8.default.dirname(manifestPath), { recursive: true });
6747
+ await (0, import_promises7.mkdir)(import_node_path9.default.dirname(manifestPath), { recursive: true });
6459
6748
  await (0, import_promises7.writeFile)(
6460
6749
  manifestPath,
6461
6750
  JSON.stringify(manifest, null, 2),
@@ -6482,22 +6771,35 @@ program.command("dev").description("Run development server with auto-reload and
6482
6771
  } else if (!process.env.MCP_URL) {
6483
6772
  process.env.MCP_URL = mcpUrl;
6484
6773
  }
6774
+ const isNextJsProject = await detectNextJsProject(projectPath);
6775
+ if (isNextJsProject) {
6776
+ console.log(
6777
+ source_default.gray(
6778
+ "Next.js detected \u2014 installing server-runtime shims (server-only, next/cache, next/headers, next/navigation, next/server)"
6779
+ )
6780
+ );
6781
+ await loadNextJsEnvFiles(projectPath);
6782
+ }
6485
6783
  if (!useHmr) {
6486
6784
  console.log(source_default.gray("HMR disabled, using tsx watch (full restart)"));
6487
6785
  const processes = [];
6488
- const env2 = {
6786
+ const baseEnv = {
6787
+ // Inherit parent env (PATH, HOME, etc.) — without it, tsx can't
6788
+ // resolve its own tooling in some setups.
6789
+ ...process.env,
6489
6790
  PORT: String(port),
6490
6791
  HOST: host,
6491
6792
  NODE_ENV: "development",
6492
6793
  // Preserve user-provided MCP_URL (e.g., for reverse proxy setups)
6493
6794
  MCP_URL: process.env.MCP_URL || mcpUrl
6494
6795
  };
6796
+ const env2 = isNextJsProject ? withNextShimsEnv(baseEnv) : baseEnv;
6495
6797
  const { createRequire: createRequire4 } = await import("module");
6496
6798
  let cmd;
6497
6799
  let args;
6498
6800
  try {
6499
6801
  const projectRequire = createRequire4(
6500
- import_node_path8.default.join(projectPath, "package.json")
6802
+ import_node_path9.default.join(projectPath, "package.json")
6501
6803
  );
6502
6804
  const tsxPkgPath = projectRequire.resolve("tsx/package.json");
6503
6805
  const tsxPkg = JSON.parse(await (0, import_promises7.readFile)(tsxPkgPath, "utf-8"));
@@ -6509,7 +6811,7 @@ program.command("dev").description("Run development server with auto-reload and
6509
6811
  } else {
6510
6812
  throw new Error("No bin field found in tsx package.json");
6511
6813
  }
6512
- const tsxBin = import_node_path8.default.resolve(import_node_path8.default.dirname(tsxPkgPath), binPath);
6814
+ const tsxBin = import_node_path9.default.resolve(import_node_path9.default.dirname(tsxPkgPath), binPath);
6513
6815
  cmd = "node";
6514
6816
  args = [tsxBin, "watch", serverFile];
6515
6817
  } catch (error) {
@@ -6584,18 +6886,56 @@ program.command("dev").description("Run development server with auto-reload and
6584
6886
  "HMR enabled - changes will hot reload without dropping connections"
6585
6887
  )
6586
6888
  );
6889
+ if (isNextJsProject) {
6890
+ const registered = await registerNextShimsInProcess();
6891
+ if (!registered) {
6892
+ console.warn(
6893
+ source_default.yellow(
6894
+ "[HMR] Warning: Next.js shim loader could not be found on disk. Importing server-only / next/cache / etc. will throw. Reinstall @mcp-use/cli to fix."
6895
+ )
6896
+ );
6897
+ }
6898
+ }
6587
6899
  const chokidarModule = await import("chokidar");
6588
6900
  const chokidar = chokidarModule.default || chokidarModule;
6589
- const { fileURLToPath: fileURLToPath2 } = await import("url");
6901
+ const { fileURLToPath: fileURLToPath3 } = await import("url");
6590
6902
  const { createRequire: createRequire3 } = await import("module");
6591
- let tsImport = null;
6903
+ const projectTsconfigPath = import_node_path9.default.join(projectPath, "tsconfig.json");
6904
+ let tsconfigAvailable = false;
6905
+ try {
6906
+ await (0, import_promises7.access)(projectTsconfigPath);
6907
+ tsconfigAvailable = true;
6908
+ process.env.TSX_TSCONFIG_PATH = projectTsconfigPath;
6909
+ if (process.cwd() !== projectPath) process.chdir(projectPath);
6910
+ } catch {
6911
+ }
6912
+ let tsxLoaderActive = false;
6592
6913
  try {
6593
6914
  const projectRequire = createRequire3(
6594
- import_node_path8.default.join(projectPath, "package.json")
6915
+ import_node_path9.default.join(projectPath, "package.json")
6595
6916
  );
6596
- const tsxApiPath = projectRequire.resolve("tsx/esm/api");
6597
- const tsxApi = await import((0, import_node_url2.pathToFileURL)(tsxApiPath).href);
6598
- tsImport = tsxApi.tsImport;
6917
+ const tsxEsmApiPath = projectRequire.resolve("tsx/esm/api");
6918
+ const tsxEsmApi = await import((0, import_node_url3.pathToFileURL)(tsxEsmApiPath).href);
6919
+ if (typeof tsxEsmApi.register === "function") {
6920
+ tsxEsmApi.register({
6921
+ tsconfig: tsconfigAvailable ? projectTsconfigPath : void 0,
6922
+ onImport: (url) => {
6923
+ const filePath = url.startsWith("file://") ? fileURLToPath3(url) : url;
6924
+ if (!filePath.includes("node_modules") && filePath.startsWith(projectPath)) {
6925
+ console.debug(`[HMR] Loaded: ${url}`);
6926
+ }
6927
+ }
6928
+ });
6929
+ tsxLoaderActive = true;
6930
+ }
6931
+ try {
6932
+ const tsxCjsApiPath = projectRequire.resolve("tsx/cjs/api");
6933
+ const tsxCjsApi = await import((0, import_node_url3.pathToFileURL)(tsxCjsApiPath).href);
6934
+ if (typeof tsxCjsApi.register === "function") {
6935
+ tsxCjsApi.register();
6936
+ }
6937
+ } catch {
6938
+ }
6599
6939
  } catch {
6600
6940
  console.log(
6601
6941
  source_default.yellow(
@@ -6603,25 +6943,15 @@ program.command("dev").description("Run development server with auto-reload and
6603
6943
  )
6604
6944
  );
6605
6945
  }
6606
- const serverFilePath = import_node_path8.default.join(projectPath, serverFile);
6607
- const serverFileUrl = (0, import_node_url2.pathToFileURL)(serverFilePath).href;
6946
+ const serverFilePath = import_node_path9.default.join(projectPath, serverFile);
6947
+ const serverFileUrl = (0, import_node_url3.pathToFileURL)(serverFilePath).href;
6608
6948
  globalThis.__mcpUseHmrMode = true;
6609
6949
  const importServerModule = async () => {
6610
6950
  const previousServer = globalThis.__mcpUseLastServer;
6611
6951
  globalThis.__mcpUseLastServer = null;
6612
- if (tsImport) {
6613
- await tsImport(`${serverFileUrl}?t=${Date.now()}`, {
6614
- parentURL: importMetaUrl,
6615
- onImport: (file) => {
6616
- const filePath = file.startsWith("file://") ? fileURLToPath2(file) : file;
6617
- if (!filePath.includes("node_modules") && filePath.startsWith(projectPath)) {
6618
- console.debug(`[HMR] Loaded: ${file}`);
6619
- }
6620
- }
6621
- });
6622
- } else {
6623
- await import(`${serverFileUrl}?t=${Date.now()}`);
6952
+ if (!tsxLoaderActive) {
6624
6953
  }
6954
+ await import(`${serverFileUrl}?t=${Date.now()}`);
6625
6955
  const instance = globalThis.__mcpUseLastServer;
6626
6956
  if (!instance) {
6627
6957
  globalThis.__mcpUseLastServer = previousServer;
@@ -6635,7 +6965,7 @@ program.command("dev").description("Run development server with auto-reload and
6635
6965
  if (instance === previousServer) {
6636
6966
  console.warn(
6637
6967
  source_default.yellow(
6638
- "[HMR] Warning: Module re-import returned the same server instance. The module may not have been re-evaluated. " + (!tsImport ? "Install tsx as a devDependency for reliable TypeScript HMR." : "This may be a tsx caching issue.")
6968
+ "[HMR] Warning: Module re-import returned the same server instance. The module may not have been re-evaluated. " + (!tsxLoaderActive ? "Install tsx as a devDependency for reliable TypeScript HMR." : "This may be a module cache issue.")
6639
6969
  )
6640
6970
  );
6641
6971
  return null;
@@ -6710,8 +7040,8 @@ program.command("dev").description("Run development server with auto-reload and
6710
7040
  }
6711
7041
  let watcher = chokidar.watch(".", {
6712
7042
  cwd: projectPath,
6713
- ignored: (path7, stats) => {
6714
- const normalizedPath = path7.replace(/\\/g, "/");
7043
+ ignored: (path8, stats) => {
7044
+ const normalizedPath = path8.replace(/\\/g, "/");
6715
7045
  if (/(^|\/)\.[^/]/.test(normalizedPath)) {
6716
7046
  return true;
6717
7047
  }
@@ -6885,7 +7215,7 @@ program.command("dev").description("Run development server with auto-reload and
6885
7215
  }
6886
7216
  tunnelUrl = void 0;
6887
7217
  if (withTunnel) {
6888
- const manifestPath = import_node_path8.default.join(projectPath, "dist", "mcp-use.json");
7218
+ const manifestPath = import_node_path9.default.join(projectPath, "dist", "mcp-use.json");
6889
7219
  let existingSubdomain;
6890
7220
  try {
6891
7221
  const manifestContent = await (0, import_promises7.readFile)(manifestPath, "utf-8");
@@ -6922,7 +7252,7 @@ program.command("dev").description("Run development server with auto-reload and
6922
7252
  tunnelSubdomain = tunnelInfo.subdomain;
6923
7253
  process.env.MCP_URL = tunnelUrl;
6924
7254
  try {
6925
- const mPath = import_node_path8.default.join(projectPath, "dist", "mcp-use.json");
7255
+ const mPath = import_node_path9.default.join(projectPath, "dist", "mcp-use.json");
6926
7256
  let manifest = {};
6927
7257
  try {
6928
7258
  manifest = JSON.parse(await (0, import_promises7.readFile)(mPath, "utf-8"));
@@ -6930,7 +7260,7 @@ program.command("dev").description("Run development server with auto-reload and
6930
7260
  }
6931
7261
  if (!manifest.tunnel) manifest.tunnel = {};
6932
7262
  manifest.tunnel.subdomain = tunnelSubdomain;
6933
- await (0, import_promises7.mkdir)(import_node_path8.default.dirname(mPath), { recursive: true });
7263
+ await (0, import_promises7.mkdir)(import_node_path9.default.dirname(mPath), { recursive: true });
6934
7264
  await (0, import_promises7.writeFile)(mPath, JSON.stringify(manifest, null, 2), "utf-8");
6935
7265
  } catch {
6936
7266
  }
@@ -7026,9 +7356,15 @@ program.command("dev").description("Run development server with auto-reload and
7026
7356
  process.exit(1);
7027
7357
  }
7028
7358
  });
7029
- 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) => {
7359
+ program.command("start").description("Start production server").option("-p, --path <path>", "Path to project directory", process.cwd()).option(
7360
+ "--entry <file>",
7361
+ "Path to MCP server entry file (relative to project)"
7362
+ ).option(
7363
+ "--mcp-dir <dir>",
7364
+ "Folder holding the MCP entry + resources (e.g. 'src/mcp' for Next.js apps)"
7365
+ ).option("--port <port>", "Server port", "3000").option("--tunnel", "Expose server through a tunnel").action(async (options) => {
7030
7366
  try {
7031
- const projectPath = import_node_path8.default.resolve(options.path);
7367
+ const projectPath = import_node_path9.default.resolve(options.path);
7032
7368
  const portFlagProvided = process.argv.includes("--port") || process.argv.includes("-p") || process.argv.some((arg) => arg.startsWith("--port=")) || process.argv.some((arg) => arg.startsWith("-p="));
7033
7369
  let port = portFlagProvided ? parseInt(options.port, 10) : parseInt(process.env.PORT || options.port || "3000", 10);
7034
7370
  if (!await isPortAvailable(port)) {
@@ -7046,7 +7382,7 @@ program.command("start").description("Start production server").option("-p, --pa
7046
7382
  let tunnelSubdomain = void 0;
7047
7383
  if (options.tunnel) {
7048
7384
  try {
7049
- const manifestPath2 = import_node_path8.default.join(projectPath, "dist", "mcp-use.json");
7385
+ const manifestPath2 = import_node_path9.default.join(projectPath, "dist", "mcp-use.json");
7050
7386
  let existingSubdomain;
7051
7387
  try {
7052
7388
  const manifestContent = await (0, import_promises7.readFile)(manifestPath2, "utf-8");
@@ -7101,7 +7437,7 @@ program.command("start").description("Start production server").option("-p, --pa
7101
7437
  manifest.tunnel = {};
7102
7438
  }
7103
7439
  manifest.tunnel.subdomain = subdomain;
7104
- await (0, import_promises7.mkdir)(import_node_path8.default.dirname(manifestPath2), { recursive: true });
7440
+ await (0, import_promises7.mkdir)(import_node_path9.default.dirname(manifestPath2), { recursive: true });
7105
7441
  await (0, import_promises7.writeFile)(
7106
7442
  manifestPath2,
7107
7443
  JSON.stringify(manifest, null, 2),
@@ -7120,18 +7456,25 @@ program.command("start").description("Start production server").option("-p, --pa
7120
7456
  }
7121
7457
  }
7122
7458
  let serverFile;
7123
- const manifestPath = import_node_path8.default.join(projectPath, "dist", "mcp-use.json");
7459
+ const manifestPath = import_node_path9.default.join(projectPath, "dist", "mcp-use.json");
7124
7460
  try {
7125
7461
  const manifestContent = await (0, import_promises7.readFile)(manifestPath, "utf-8");
7126
7462
  const manifest = JSON.parse(manifestContent);
7127
7463
  if (manifest.entryPoint) {
7128
- await (0, import_promises7.access)(import_node_path8.default.join(projectPath, manifest.entryPoint));
7464
+ await (0, import_promises7.access)(import_node_path9.default.join(projectPath, manifest.entryPoint));
7129
7465
  serverFile = manifest.entryPoint;
7130
7466
  }
7131
7467
  } catch {
7132
7468
  }
7133
7469
  if (!serverFile) {
7470
+ const startMcpDir = options.mcpDir;
7134
7471
  const serverCandidates = [
7472
+ ...startMcpDir ? [
7473
+ `${startMcpDir}/index.ts`,
7474
+ `${startMcpDir}/index.tsx`,
7475
+ `dist/${startMcpDir}/index.js`,
7476
+ `dist/${startMcpDir}/server.js`
7477
+ ] : [],
7135
7478
  "dist/index.js",
7136
7479
  "dist/server.js",
7137
7480
  "dist/src/index.js",
@@ -7139,7 +7482,7 @@ program.command("start").description("Start production server").option("-p, --pa
7139
7482
  ];
7140
7483
  for (const candidate of serverCandidates) {
7141
7484
  try {
7142
- await (0, import_promises7.access)(import_node_path8.default.join(projectPath, candidate));
7485
+ await (0, import_promises7.access)(import_node_path9.default.join(projectPath, candidate));
7143
7486
  serverFile = candidate;
7144
7487
  break;
7145
7488
  } catch {
@@ -7163,18 +7506,53 @@ Looked for:
7163
7506
  process.exit(1);
7164
7507
  }
7165
7508
  console.log("Starting production server...");
7166
- const env2 = {
7509
+ const isNextJsProject = await detectNextJsProject(projectPath);
7510
+ if (isNextJsProject) {
7511
+ console.log(
7512
+ source_default.gray(
7513
+ "Next.js detected \u2014 installing server-runtime shims for the production server"
7514
+ )
7515
+ );
7516
+ await loadNextJsEnvFiles(projectPath);
7517
+ }
7518
+ const baseEnv = {
7167
7519
  ...process.env,
7168
7520
  PORT: String(port),
7169
7521
  NODE_ENV: "production"
7170
7522
  };
7171
7523
  if (mcpUrl) {
7172
- env2.MCP_URL = mcpUrl;
7524
+ baseEnv.MCP_URL = mcpUrl;
7173
7525
  console.log(source_default.whiteBright(`Tunnel: ${mcpUrl}/mcp`));
7174
- } else if (!env2.MCP_URL) {
7175
- env2.MCP_URL = `http://localhost:${port}`;
7526
+ } else if (!baseEnv.MCP_URL) {
7527
+ baseEnv.MCP_URL = `http://localhost:${port}`;
7528
+ }
7529
+ const env2 = isNextJsProject ? withNextShimsEnv(baseEnv) : baseEnv;
7530
+ const isTsEntry = /\.(ts|tsx|mts|cts)$/.test(serverFile);
7531
+ let spawnCmd = "node";
7532
+ let spawnArgs = [serverFile];
7533
+ if (isTsEntry) {
7534
+ try {
7535
+ const projectRequire = (0, import_node_module2.createRequire)(
7536
+ import_node_path9.default.join(projectPath, "package.json")
7537
+ );
7538
+ const tsxPkgPath = projectRequire.resolve("tsx/package.json");
7539
+ const tsxPkg = JSON.parse(await (0, import_promises7.readFile)(tsxPkgPath, "utf-8"));
7540
+ const binField = typeof tsxPkg.bin === "string" ? tsxPkg.bin : tsxPkg.bin?.tsx ?? Object.values(tsxPkg.bin ?? {})[0];
7541
+ if (!binField) throw new Error("tsx bin entry not found");
7542
+ const tsxBin = import_node_path9.default.resolve(import_node_path9.default.dirname(tsxPkgPath), binField);
7543
+ spawnCmd = "node";
7544
+ spawnArgs = [tsxBin, serverFile];
7545
+ } catch (error) {
7546
+ console.log(
7547
+ source_default.yellow(
7548
+ `Could not resolve local tsx (${error instanceof Error ? error.message : String(error)}); falling back to npx`
7549
+ )
7550
+ );
7551
+ spawnCmd = "npx";
7552
+ spawnArgs = ["tsx", serverFile];
7553
+ }
7176
7554
  }
7177
- const serverProc = (0, import_node_child_process9.spawn)("node", [serverFile], {
7555
+ const serverProc = (0, import_node_child_process9.spawn)(spawnCmd, spawnArgs, {
7178
7556
  cwd: projectPath,
7179
7557
  stdio: "inherit",
7180
7558
  env: env2
@@ -7310,7 +7688,7 @@ program.addCommand(createSkillsCommand());
7310
7688
  program.command("generate-types").description(
7311
7689
  "Generate TypeScript type definitions for tools (writes .mcp-use/tool-registry.d.ts)"
7312
7690
  ).option("-p, --path <path>", "Path to project directory", process.cwd()).option("--server <file>", "Server entry file", "index.ts").action(async (options) => {
7313
- const projectPath = import_node_path8.default.resolve(options.path);
7691
+ const projectPath = import_node_path9.default.resolve(options.path);
7314
7692
  try {
7315
7693
  console.log(source_default.blue("Generating tool registry types..."));
7316
7694
  const success = await generateToolRegistryTypesForServer(