@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 +557 -179
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +552 -174
- package/dist/index.js.map +1 -1
- package/dist/shims/next-shims-cjs.cjs +42 -0
- package/dist/shims/next-shims-loader.mjs +119 -0
- package/dist/shims/next-shims-noop.cjs +146 -0
- package/dist/shims/next-shims-register.mjs +14 -0
- package/dist/shims/next-shims-registry.json +11 -0
- package/dist/utils/next-shims.d.ts +77 -0
- package/dist/utils/next-shims.d.ts.map +1 -0
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -509,8 +509,8 @@ import { spawn } from "child_process";
|
|
|
509
509
|
import { readFileSync as readFileSync2 } from "fs";
|
|
510
510
|
import { access, mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
511
511
|
import { createRequire as createRequire2 } from "module";
|
|
512
|
-
import
|
|
513
|
-
import { pathToFileURL } from "url";
|
|
512
|
+
import path8 from "path";
|
|
513
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
514
514
|
|
|
515
515
|
// ../../node_modules/.pnpm/open@11.0.0/node_modules/open/index.js
|
|
516
516
|
import process9 from "process";
|
|
@@ -696,15 +696,15 @@ var wslDefaultBrowser = async () => {
|
|
|
696
696
|
const { stdout } = await executePowerShell(command, { powerShellPath: psPath });
|
|
697
697
|
return stdout.trim();
|
|
698
698
|
};
|
|
699
|
-
var convertWslPathToWindows = async (
|
|
700
|
-
if (/^[a-z]+:\/\//i.test(
|
|
701
|
-
return
|
|
699
|
+
var convertWslPathToWindows = async (path9) => {
|
|
700
|
+
if (/^[a-z]+:\/\//i.test(path9)) {
|
|
701
|
+
return path9;
|
|
702
702
|
}
|
|
703
703
|
try {
|
|
704
|
-
const { stdout } = await execFile2("wslpath", ["-aw",
|
|
704
|
+
const { stdout } = await execFile2("wslpath", ["-aw", path9], { encoding: "utf8" });
|
|
705
705
|
return stdout.trim();
|
|
706
706
|
} catch {
|
|
707
|
-
return
|
|
707
|
+
return path9;
|
|
708
708
|
}
|
|
709
709
|
};
|
|
710
710
|
|
|
@@ -1354,8 +1354,8 @@ var McpUseAPI = class _McpUseAPI {
|
|
|
1354
1354
|
return this.request(`/servers${q ? `?${q}` : ""}`);
|
|
1355
1355
|
}
|
|
1356
1356
|
async getServer(idOrSlug) {
|
|
1357
|
-
const
|
|
1358
|
-
return this.request(`/servers/${
|
|
1357
|
+
const path9 = encodeURIComponent(idOrSlug);
|
|
1358
|
+
return this.request(`/servers/${path9}`);
|
|
1359
1359
|
}
|
|
1360
1360
|
async deleteServer(id) {
|
|
1361
1361
|
await this.request(
|
|
@@ -5230,7 +5230,7 @@ async function addSkillsToProject(projectPath) {
|
|
|
5230
5230
|
Readable.fromWeb(response.body),
|
|
5231
5231
|
extract({
|
|
5232
5232
|
cwd: tempDir,
|
|
5233
|
-
filter: (
|
|
5233
|
+
filter: (path9) => path9.includes("/skills/"),
|
|
5234
5234
|
strip: 1
|
|
5235
5235
|
})
|
|
5236
5236
|
);
|
|
@@ -5295,14 +5295,114 @@ function createSkillsCommand() {
|
|
|
5295
5295
|
return skills;
|
|
5296
5296
|
}
|
|
5297
5297
|
|
|
5298
|
+
// src/utils/next-shims.ts
|
|
5299
|
+
import { existsSync as existsSync3, promises as fs10 } from "fs";
|
|
5300
|
+
import path6 from "path";
|
|
5301
|
+
import { fileURLToPath as fileURLToPath3, pathToFileURL } from "url";
|
|
5302
|
+
async function detectNextJsProject(projectPath) {
|
|
5303
|
+
try {
|
|
5304
|
+
const pkgPath = path6.join(projectPath, "package.json");
|
|
5305
|
+
const content = await fs10.readFile(pkgPath, "utf-8");
|
|
5306
|
+
const pkg = JSON.parse(content);
|
|
5307
|
+
const deps = pkg.dependencies ?? {};
|
|
5308
|
+
const devDeps = pkg.devDependencies ?? {};
|
|
5309
|
+
return "next" in deps || "next" in devDeps;
|
|
5310
|
+
} catch {
|
|
5311
|
+
return false;
|
|
5312
|
+
}
|
|
5313
|
+
}
|
|
5314
|
+
async function loadNextJsEnvFiles(projectPath) {
|
|
5315
|
+
const files = [
|
|
5316
|
+
".env",
|
|
5317
|
+
".env.development",
|
|
5318
|
+
".env.local",
|
|
5319
|
+
".env.development.local"
|
|
5320
|
+
];
|
|
5321
|
+
const dotenv = await import("dotenv");
|
|
5322
|
+
for (const file of files) {
|
|
5323
|
+
const abs = path6.join(projectPath, file);
|
|
5324
|
+
try {
|
|
5325
|
+
await fs10.access(abs);
|
|
5326
|
+
} catch {
|
|
5327
|
+
continue;
|
|
5328
|
+
}
|
|
5329
|
+
dotenv.config({ path: abs, override: true, quiet: true });
|
|
5330
|
+
}
|
|
5331
|
+
}
|
|
5332
|
+
function getThisDir() {
|
|
5333
|
+
if (typeof __dirname === "string") return __dirname;
|
|
5334
|
+
const url = import.meta.url;
|
|
5335
|
+
return path6.dirname(fileURLToPath3(url));
|
|
5336
|
+
}
|
|
5337
|
+
function resolveShimPath(filename) {
|
|
5338
|
+
const thisDir = getThisDir();
|
|
5339
|
+
const candidates = [
|
|
5340
|
+
// Production: `dist/` next to this module
|
|
5341
|
+
path6.join(thisDir, "shims", filename),
|
|
5342
|
+
// Test / dev: one level up (e.g., from `dist/utils/` back to `src/shims/`)
|
|
5343
|
+
path6.join(thisDir, "..", "shims", filename),
|
|
5344
|
+
path6.join(thisDir, "..", "..", "src", "shims", filename),
|
|
5345
|
+
path6.join(thisDir, "..", "src", "shims", filename)
|
|
5346
|
+
];
|
|
5347
|
+
for (const candidate of candidates) {
|
|
5348
|
+
if (existsSync3(candidate)) return candidate;
|
|
5349
|
+
}
|
|
5350
|
+
return void 0;
|
|
5351
|
+
}
|
|
5352
|
+
function getShimRegisterPath() {
|
|
5353
|
+
return resolveShimPath("next-shims-register.mjs");
|
|
5354
|
+
}
|
|
5355
|
+
function getShimLoaderPath() {
|
|
5356
|
+
return resolveShimPath("next-shims-loader.mjs");
|
|
5357
|
+
}
|
|
5358
|
+
function getShimCjsPreloadPath() {
|
|
5359
|
+
return resolveShimPath("next-shims-cjs.cjs");
|
|
5360
|
+
}
|
|
5361
|
+
async function registerNextShimsInProcess() {
|
|
5362
|
+
let anyRegistered = false;
|
|
5363
|
+
const cjsPath = getShimCjsPreloadPath();
|
|
5364
|
+
if (cjsPath) {
|
|
5365
|
+
const { createRequire: createRequire3 } = await import("module");
|
|
5366
|
+
const req = createRequire3(pathToFileURL(getThisDir() + path6.sep).href);
|
|
5367
|
+
req(cjsPath);
|
|
5368
|
+
anyRegistered = true;
|
|
5369
|
+
}
|
|
5370
|
+
const loaderPath = getShimLoaderPath();
|
|
5371
|
+
if (loaderPath) {
|
|
5372
|
+
const { register } = await import("module");
|
|
5373
|
+
const loaderUrl = pathToFileURL(loaderPath).href;
|
|
5374
|
+
register(loaderUrl, pathToFileURL(getThisDir() + path6.sep).href);
|
|
5375
|
+
anyRegistered = true;
|
|
5376
|
+
}
|
|
5377
|
+
return anyRegistered;
|
|
5378
|
+
}
|
|
5379
|
+
function withNextShimsEnv(baseEnv) {
|
|
5380
|
+
const additions = [];
|
|
5381
|
+
const cjsPath = getShimCjsPreloadPath();
|
|
5382
|
+
if (cjsPath) additions.push(`-r ${quoteNodeOption(cjsPath)}`);
|
|
5383
|
+
const registerPath = getShimRegisterPath();
|
|
5384
|
+
if (registerPath)
|
|
5385
|
+
additions.push(`--import=${pathToFileURL(registerPath).href}`);
|
|
5386
|
+
if (additions.length === 0) return baseEnv;
|
|
5387
|
+
const existing = baseEnv.NODE_OPTIONS ?? "";
|
|
5388
|
+
const prepended = additions.join(" ");
|
|
5389
|
+
return {
|
|
5390
|
+
...baseEnv,
|
|
5391
|
+
NODE_OPTIONS: existing ? `${prepended} ${existing}` : prepended
|
|
5392
|
+
};
|
|
5393
|
+
}
|
|
5394
|
+
function quoteNodeOption(value) {
|
|
5395
|
+
return /\s/.test(value) ? `"${value}"` : value;
|
|
5396
|
+
}
|
|
5397
|
+
|
|
5298
5398
|
// src/utils/update-check.ts
|
|
5299
5399
|
import { readFileSync } from "fs";
|
|
5300
5400
|
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
5301
5401
|
import { createRequire } from "module";
|
|
5302
5402
|
import os4 from "os";
|
|
5303
|
-
import
|
|
5304
|
-
var CACHE_DIR =
|
|
5305
|
-
var CACHE_FILE =
|
|
5403
|
+
import path7 from "path";
|
|
5404
|
+
var CACHE_DIR = path7.join(os4.homedir(), ".mcp-use");
|
|
5405
|
+
var CACHE_FILE = path7.join(CACHE_DIR, "update-check.json");
|
|
5306
5406
|
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
5307
5407
|
var FETCH_TIMEOUT_MS = 3e3;
|
|
5308
5408
|
var PACKAGE_NAME = "mcp-use";
|
|
@@ -5385,12 +5485,12 @@ function resolveInstalledVersion(projectPath) {
|
|
|
5385
5485
|
if (projectPath) {
|
|
5386
5486
|
attempts.push(() => {
|
|
5387
5487
|
const projectRequire = createRequire(
|
|
5388
|
-
|
|
5488
|
+
path7.join(projectPath, "package.json")
|
|
5389
5489
|
);
|
|
5390
5490
|
return projectRequire.resolve(`${PACKAGE_NAME}/package.json`);
|
|
5391
5491
|
});
|
|
5392
5492
|
}
|
|
5393
|
-
attempts.push(() =>
|
|
5493
|
+
attempts.push(() => path7.join(__dirname, "../../mcp-use/package.json"));
|
|
5394
5494
|
for (const attempt of attempts) {
|
|
5395
5495
|
try {
|
|
5396
5496
|
const pkgPath = attempt();
|
|
@@ -5428,7 +5528,7 @@ A new release of ${source_default.bold(PACKAGE_NAME)} is available: ${source_def
|
|
|
5428
5528
|
// src/index.ts
|
|
5429
5529
|
var program = new Command6();
|
|
5430
5530
|
var packageContent = readFileSync2(
|
|
5431
|
-
|
|
5531
|
+
path8.join(__dirname, "../package.json"),
|
|
5432
5532
|
"utf-8"
|
|
5433
5533
|
);
|
|
5434
5534
|
var packageJson = JSON.parse(packageContent);
|
|
@@ -5459,14 +5559,14 @@ function displayPackageVersions(projectPath) {
|
|
|
5459
5559
|
if (projectPath) {
|
|
5460
5560
|
try {
|
|
5461
5561
|
const projectRequire = createRequire2(
|
|
5462
|
-
|
|
5562
|
+
path8.join(projectPath, "package.json")
|
|
5463
5563
|
);
|
|
5464
5564
|
pkgPath = projectRequire.resolve(`${pkg.name}/package.json`);
|
|
5465
5565
|
} catch (resolveError) {
|
|
5466
|
-
pkgPath =
|
|
5566
|
+
pkgPath = path8.join(__dirname, pkg.relativePath);
|
|
5467
5567
|
}
|
|
5468
5568
|
} else {
|
|
5469
|
-
pkgPath =
|
|
5569
|
+
pkgPath = path8.join(__dirname, pkg.relativePath);
|
|
5470
5570
|
}
|
|
5471
5571
|
const pkgContent = readFileSync2(pkgPath, "utf-8");
|
|
5472
5572
|
const pkgJson = JSON.parse(pkgContent);
|
|
@@ -5618,20 +5718,92 @@ async function startTunnel(port, subdomain) {
|
|
|
5618
5718
|
}, 3e4);
|
|
5619
5719
|
});
|
|
5620
5720
|
}
|
|
5621
|
-
async function
|
|
5721
|
+
async function resolveEntryFile(projectPath, cliEntry, mcpDir) {
|
|
5722
|
+
if (cliEntry) {
|
|
5723
|
+
await access(path8.join(projectPath, cliEntry)).catch(() => {
|
|
5724
|
+
throw new Error(`File not found: ${cliEntry}`);
|
|
5725
|
+
});
|
|
5726
|
+
return cliEntry;
|
|
5727
|
+
}
|
|
5728
|
+
if (mcpDir) {
|
|
5729
|
+
const mcpCandidates = [
|
|
5730
|
+
path8.join(mcpDir, "index.ts"),
|
|
5731
|
+
path8.join(mcpDir, "index.tsx"),
|
|
5732
|
+
path8.join(mcpDir, "server.ts"),
|
|
5733
|
+
path8.join(mcpDir, "server.tsx")
|
|
5734
|
+
];
|
|
5735
|
+
for (const candidate of mcpCandidates) {
|
|
5736
|
+
try {
|
|
5737
|
+
await access(path8.join(projectPath, candidate));
|
|
5738
|
+
return candidate;
|
|
5739
|
+
} catch {
|
|
5740
|
+
continue;
|
|
5741
|
+
}
|
|
5742
|
+
}
|
|
5743
|
+
throw new Error(
|
|
5744
|
+
`No entry file found inside ${mcpDir}.
|
|
5745
|
+
|
|
5746
|
+
Expected one of: ${mcpCandidates.map((c) => path8.relative(projectPath, path8.join(projectPath, c))).join(", ")}
|
|
5747
|
+
|
|
5748
|
+
Fix this by either:
|
|
5749
|
+
1. Creating ${path8.join(mcpDir, "index.ts")}, or
|
|
5750
|
+
2. Passing --entry <file> on the command line`
|
|
5751
|
+
);
|
|
5752
|
+
}
|
|
5622
5753
|
const candidates = ["index.ts", "src/index.ts", "server.ts", "src/server.ts"];
|
|
5623
5754
|
for (const candidate of candidates) {
|
|
5624
5755
|
try {
|
|
5625
|
-
await access(
|
|
5756
|
+
await access(path8.join(projectPath, candidate));
|
|
5626
5757
|
return candidate;
|
|
5627
5758
|
} catch {
|
|
5628
5759
|
continue;
|
|
5629
5760
|
}
|
|
5630
5761
|
}
|
|
5631
|
-
throw new Error(
|
|
5762
|
+
throw new Error(
|
|
5763
|
+
`No entry file found.
|
|
5764
|
+
|
|
5765
|
+
Expected one of: ${candidates.join(", ")}
|
|
5766
|
+
|
|
5767
|
+
Fix this by either:
|
|
5768
|
+
1. Creating one of the default entry files above, or
|
|
5769
|
+
2. Passing --entry <file> or --mcp-dir <dir> on the command line`
|
|
5770
|
+
);
|
|
5771
|
+
}
|
|
5772
|
+
function resolveWidgetsDir(cliWidgetsDir, mcpDir) {
|
|
5773
|
+
if (cliWidgetsDir) return cliWidgetsDir;
|
|
5774
|
+
if (mcpDir) return path8.join(mcpDir, "resources");
|
|
5775
|
+
return "resources";
|
|
5776
|
+
}
|
|
5777
|
+
function makeWidgetServerOnlyGuard(widgetName) {
|
|
5778
|
+
const rejected = /* @__PURE__ */ new Set([
|
|
5779
|
+
"server-only",
|
|
5780
|
+
"client-only",
|
|
5781
|
+
"next/cache",
|
|
5782
|
+
"next/headers",
|
|
5783
|
+
"next/navigation",
|
|
5784
|
+
"next/server"
|
|
5785
|
+
]);
|
|
5786
|
+
return {
|
|
5787
|
+
name: "mcp-use-widget-server-only-guard",
|
|
5788
|
+
enforce: "pre",
|
|
5789
|
+
resolveId(id, importer) {
|
|
5790
|
+
if (!rejected.has(id)) return null;
|
|
5791
|
+
const from = importer ? ` (imported from ${importer})` : "";
|
|
5792
|
+
throw new Error(
|
|
5793
|
+
`Widget "${widgetName}" imports "${id}"${from}, which is a Next.js server-only module. Widgets run in a browser iframe and cannot use server APIs.
|
|
5794
|
+
|
|
5795
|
+
To fix:
|
|
5796
|
+
\u2022 Remove the import from the widget (or from any module the widget transitively imports)
|
|
5797
|
+
\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`
|
|
5798
|
+
);
|
|
5799
|
+
}
|
|
5800
|
+
};
|
|
5801
|
+
}
|
|
5802
|
+
async function findServerFile(projectPath, cliEntry, cliMcpDir) {
|
|
5803
|
+
return resolveEntryFile(projectPath, cliEntry, cliMcpDir);
|
|
5632
5804
|
}
|
|
5633
5805
|
async function generateToolRegistryTypesForServer(projectPath, serverFileRelative) {
|
|
5634
|
-
const serverFile =
|
|
5806
|
+
const serverFile = path8.join(projectPath, serverFileRelative);
|
|
5635
5807
|
const serverFileExists = await access(serverFile).then(() => true).catch(() => false);
|
|
5636
5808
|
if (!serverFileExists) {
|
|
5637
5809
|
throw new Error(`Server file not found: ${serverFile}`);
|
|
@@ -5640,19 +5812,48 @@ async function generateToolRegistryTypesForServer(projectPath, serverFileRelativ
|
|
|
5640
5812
|
try {
|
|
5641
5813
|
globalThis.__mcpUseHmrMode = true;
|
|
5642
5814
|
globalThis.__mcpUseLastServer = void 0;
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5815
|
+
if (await detectNextJsProject(projectPath)) {
|
|
5816
|
+
await loadNextJsEnvFiles(projectPath);
|
|
5817
|
+
await registerNextShimsInProcess();
|
|
5818
|
+
}
|
|
5819
|
+
const projectTsconfigPath = path8.join(projectPath, "tsconfig.json");
|
|
5820
|
+
const hasTsconfig = await access(projectTsconfigPath).then(() => true).catch(() => false);
|
|
5821
|
+
if (hasTsconfig) {
|
|
5822
|
+
process.env.TSX_TSCONFIG_PATH = projectTsconfigPath;
|
|
5823
|
+
}
|
|
5824
|
+
const previousCwd = process.cwd();
|
|
5825
|
+
if (previousCwd !== projectPath) process.chdir(projectPath);
|
|
5826
|
+
try {
|
|
5827
|
+
const projectRequire = createRequire2(
|
|
5828
|
+
path8.join(projectPath, "package.json")
|
|
5829
|
+
);
|
|
5830
|
+
const tsxEsmApiPath = projectRequire.resolve("tsx/esm/api");
|
|
5831
|
+
const tsxEsmApi = await import(pathToFileURL2(tsxEsmApiPath).href);
|
|
5832
|
+
if (typeof tsxEsmApi.register === "function") {
|
|
5833
|
+
tsxEsmApi.register({
|
|
5834
|
+
tsconfig: hasTsconfig ? projectTsconfigPath : void 0
|
|
5835
|
+
});
|
|
5836
|
+
}
|
|
5837
|
+
try {
|
|
5838
|
+
const tsxCjsApiPath = projectRequire.resolve("tsx/cjs/api");
|
|
5839
|
+
const tsxCjsApi = await import(pathToFileURL2(tsxCjsApiPath).href);
|
|
5840
|
+
if (typeof tsxCjsApi.register === "function") {
|
|
5841
|
+
tsxCjsApi.register();
|
|
5842
|
+
}
|
|
5843
|
+
} catch {
|
|
5844
|
+
}
|
|
5845
|
+
await import(`${pathToFileURL2(serverFile).href}?t=${Date.now()}`);
|
|
5846
|
+
} finally {
|
|
5847
|
+
if (process.cwd() !== previousCwd) process.chdir(previousCwd);
|
|
5848
|
+
}
|
|
5648
5849
|
const server = globalThis.__mcpUseLastServer;
|
|
5649
5850
|
if (!server) {
|
|
5650
5851
|
throw new Error(
|
|
5651
5852
|
"No MCPServer instance found. Make sure your server file creates an MCPServer instance."
|
|
5652
5853
|
);
|
|
5653
5854
|
}
|
|
5654
|
-
const mcpUsePath =
|
|
5655
|
-
const { generateToolRegistryTypes } = await import(
|
|
5855
|
+
const mcpUsePath = path8.join(projectPath, "node_modules", "mcp-use");
|
|
5856
|
+
const { generateToolRegistryTypes } = await import(pathToFileURL2(path8.join(mcpUsePath, "dist", "src", "server", "index.js")).href).then((mod) => mod);
|
|
5656
5857
|
if (!generateToolRegistryTypes) {
|
|
5657
5858
|
throw new Error("generateToolRegistryTypes not found in mcp-use package");
|
|
5658
5859
|
}
|
|
@@ -5667,21 +5868,24 @@ async function generateToolRegistryTypesForServer(projectPath, serverFileRelativ
|
|
|
5667
5868
|
}
|
|
5668
5869
|
async function buildWidgets(projectPath, options = {}) {
|
|
5669
5870
|
const { inline = true } = options;
|
|
5670
|
-
const { promises:
|
|
5871
|
+
const { promises: fs11 } = await import("fs");
|
|
5671
5872
|
const { build } = await import("vite");
|
|
5672
|
-
const
|
|
5873
|
+
const widgetsDirRelative = options.widgetsDir ?? "resources";
|
|
5874
|
+
const resourcesDir = path8.resolve(projectPath, widgetsDirRelative);
|
|
5673
5875
|
const mcpUrl = process.env.MCP_URL;
|
|
5674
5876
|
try {
|
|
5675
5877
|
await access(resourcesDir);
|
|
5676
5878
|
} catch {
|
|
5677
5879
|
console.log(
|
|
5678
|
-
source_default.gray(
|
|
5880
|
+
source_default.gray(
|
|
5881
|
+
`No ${widgetsDirRelative}/ directory found - skipping widget build`
|
|
5882
|
+
)
|
|
5679
5883
|
);
|
|
5680
5884
|
return [];
|
|
5681
5885
|
}
|
|
5682
5886
|
const entries = [];
|
|
5683
5887
|
try {
|
|
5684
|
-
const files = await
|
|
5888
|
+
const files = await fs11.readdir(resourcesDir, { withFileTypes: true });
|
|
5685
5889
|
for (const dirent of files) {
|
|
5686
5890
|
if (dirent.name.startsWith("._") || dirent.name.startsWith(".DS_Store")) {
|
|
5687
5891
|
continue;
|
|
@@ -5689,12 +5893,12 @@ async function buildWidgets(projectPath, options = {}) {
|
|
|
5689
5893
|
if (dirent.isFile() && (dirent.name.endsWith(".tsx") || dirent.name.endsWith(".ts"))) {
|
|
5690
5894
|
entries.push({
|
|
5691
5895
|
name: dirent.name.replace(/\.tsx?$/, ""),
|
|
5692
|
-
path:
|
|
5896
|
+
path: path8.join(resourcesDir, dirent.name)
|
|
5693
5897
|
});
|
|
5694
5898
|
} else if (dirent.isDirectory()) {
|
|
5695
|
-
const widgetPath =
|
|
5899
|
+
const widgetPath = path8.join(resourcesDir, dirent.name, "widget.tsx");
|
|
5696
5900
|
try {
|
|
5697
|
-
await
|
|
5901
|
+
await fs11.access(widgetPath);
|
|
5698
5902
|
entries.push({
|
|
5699
5903
|
name: dirent.name,
|
|
5700
5904
|
path: widgetPath
|
|
@@ -5704,11 +5908,15 @@ async function buildWidgets(projectPath, options = {}) {
|
|
|
5704
5908
|
}
|
|
5705
5909
|
}
|
|
5706
5910
|
} catch (error) {
|
|
5707
|
-
console.log(
|
|
5911
|
+
console.log(
|
|
5912
|
+
source_default.gray(`No widgets found in ${widgetsDirRelative}/ directory`)
|
|
5913
|
+
);
|
|
5708
5914
|
return [];
|
|
5709
5915
|
}
|
|
5710
5916
|
if (entries.length === 0) {
|
|
5711
|
-
console.log(
|
|
5917
|
+
console.log(
|
|
5918
|
+
source_default.gray(`No widgets found in ${widgetsDirRelative}/ directory`)
|
|
5919
|
+
);
|
|
5712
5920
|
return [];
|
|
5713
5921
|
}
|
|
5714
5922
|
console.log(
|
|
@@ -5718,10 +5926,17 @@ async function buildWidgets(projectPath, options = {}) {
|
|
|
5718
5926
|
);
|
|
5719
5927
|
const react = (await import("@vitejs/plugin-react")).default;
|
|
5720
5928
|
const tailwindcss = (await import("@tailwindcss/vite")).default;
|
|
5721
|
-
const
|
|
5929
|
+
const projectTsconfigPath = path8.join(projectPath, "tsconfig.json");
|
|
5930
|
+
let hasProjectTsconfig = false;
|
|
5931
|
+
try {
|
|
5932
|
+
await access(projectTsconfigPath);
|
|
5933
|
+
hasProjectTsconfig = true;
|
|
5934
|
+
} catch {
|
|
5935
|
+
}
|
|
5936
|
+
const packageJsonPath = path8.join(projectPath, "package.json");
|
|
5722
5937
|
let favicon = "";
|
|
5723
5938
|
try {
|
|
5724
|
-
const pkgContent = await
|
|
5939
|
+
const pkgContent = await fs11.readFile(packageJsonPath, "utf-8");
|
|
5725
5940
|
const pkg = JSON.parse(pkgContent);
|
|
5726
5941
|
favicon = pkg.mcpUse?.favicon || "";
|
|
5727
5942
|
} catch {
|
|
@@ -5730,18 +5945,27 @@ async function buildWidgets(projectPath, options = {}) {
|
|
|
5730
5945
|
const widgetName = entry.name;
|
|
5731
5946
|
const entryPath = entry.path.replace(/\\/g, "/");
|
|
5732
5947
|
console.log(source_default.gray(` - Building ${widgetName}...`));
|
|
5733
|
-
const tempDir =
|
|
5734
|
-
await
|
|
5735
|
-
const relativeResourcesPath =
|
|
5736
|
-
const mcpUsePath =
|
|
5737
|
-
const relativeMcpUsePath =
|
|
5948
|
+
const tempDir = path8.join(projectPath, ".mcp-use", widgetName);
|
|
5949
|
+
await fs11.mkdir(tempDir, { recursive: true });
|
|
5950
|
+
const relativeResourcesPath = path8.relative(tempDir, resourcesDir).replace(/\\/g, "/");
|
|
5951
|
+
const mcpUsePath = path8.join(projectPath, "node_modules", "mcp-use");
|
|
5952
|
+
const relativeMcpUsePath = path8.relative(tempDir, mcpUsePath).replace(/\\/g, "/");
|
|
5953
|
+
const projectSrcDir = path8.join(projectPath, "src");
|
|
5954
|
+
let projectSrcSourceLine = "";
|
|
5955
|
+
try {
|
|
5956
|
+
await access(projectSrcDir);
|
|
5957
|
+
const relativeProjectSrcPath = path8.relative(tempDir, projectSrcDir).replace(/\\/g, "/");
|
|
5958
|
+
projectSrcSourceLine = `@source "${relativeProjectSrcPath}";
|
|
5959
|
+
`;
|
|
5960
|
+
} catch {
|
|
5961
|
+
}
|
|
5738
5962
|
const cssContent = `@import "tailwindcss";
|
|
5739
5963
|
|
|
5740
5964
|
/* Configure Tailwind to scan the resources directory and mcp-use package */
|
|
5741
5965
|
@source "${relativeResourcesPath}";
|
|
5742
5966
|
@source "${relativeMcpUsePath}/**/*.{ts,tsx,js,jsx}";
|
|
5743
|
-
`;
|
|
5744
|
-
await
|
|
5967
|
+
${projectSrcSourceLine}`;
|
|
5968
|
+
await fs11.writeFile(path8.join(tempDir, "styles.css"), cssContent, "utf8");
|
|
5745
5969
|
const entryContent = `import React from 'react'
|
|
5746
5970
|
import { createRoot } from 'react-dom/client'
|
|
5747
5971
|
import './styles.css'
|
|
@@ -5766,9 +5990,9 @@ if (container && Component) {
|
|
|
5766
5990
|
<script type="module" src="/entry.tsx"></script>
|
|
5767
5991
|
</body>
|
|
5768
5992
|
</html>`;
|
|
5769
|
-
await
|
|
5770
|
-
await
|
|
5771
|
-
const outDir =
|
|
5993
|
+
await fs11.writeFile(path8.join(tempDir, "entry.tsx"), entryContent, "utf8");
|
|
5994
|
+
await fs11.writeFile(path8.join(tempDir, "index.html"), htmlContent, "utf8");
|
|
5995
|
+
const outDir = path8.join(
|
|
5772
5996
|
projectPath,
|
|
5773
5997
|
"dist",
|
|
5774
5998
|
"resources",
|
|
@@ -5778,12 +6002,12 @@ if (container && Component) {
|
|
|
5778
6002
|
const baseUrl = mcpUrl ? `${mcpUrl}/${widgetName}/` : `/mcp-use/widgets/${widgetName}/`;
|
|
5779
6003
|
let widgetMetadata = {};
|
|
5780
6004
|
try {
|
|
5781
|
-
const metadataTempDir =
|
|
6005
|
+
const metadataTempDir = path8.join(
|
|
5782
6006
|
projectPath,
|
|
5783
6007
|
".mcp-use",
|
|
5784
6008
|
`${widgetName}-metadata`
|
|
5785
6009
|
);
|
|
5786
|
-
await
|
|
6010
|
+
await fs11.mkdir(metadataTempDir, { recursive: true });
|
|
5787
6011
|
const { createServer } = await import("vite");
|
|
5788
6012
|
const nodeStubsPlugin = {
|
|
5789
6013
|
name: "node-stubs",
|
|
@@ -5811,15 +6035,16 @@ export default PostHog;
|
|
|
5811
6035
|
return null;
|
|
5812
6036
|
}
|
|
5813
6037
|
};
|
|
6038
|
+
const serverOnlyGuard = makeWidgetServerOnlyGuard(widgetName);
|
|
5814
6039
|
const metadataServer = await createServer({
|
|
5815
6040
|
root: metadataTempDir,
|
|
5816
|
-
cacheDir:
|
|
5817
|
-
plugins: [nodeStubsPlugin, tailwindcss(), react()],
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
},
|
|
6041
|
+
cacheDir: path8.join(metadataTempDir, ".vite-cache"),
|
|
6042
|
+
plugins: [serverOnlyGuard, nodeStubsPlugin, tailwindcss(), react()],
|
|
6043
|
+
// When the project has a tsconfig, enable Vite's native tsconfig-paths
|
|
6044
|
+
// resolver so `@/*` (or any custom alias) resolves through the
|
|
6045
|
+
// project's own paths config. Without a tsconfig, fall back to the
|
|
6046
|
+
// legacy hardcoded alias.
|
|
6047
|
+
resolve: hasProjectTsconfig ? { tsconfigPaths: true } : { alias: { "@": resourcesDir } },
|
|
5823
6048
|
server: {
|
|
5824
6049
|
middlewareMode: true
|
|
5825
6050
|
},
|
|
@@ -5898,7 +6123,7 @@ export default PostHog;
|
|
|
5898
6123
|
} finally {
|
|
5899
6124
|
await metadataServer.close();
|
|
5900
6125
|
try {
|
|
5901
|
-
await
|
|
6126
|
+
await fs11.rm(metadataTempDir, { recursive: true, force: true });
|
|
5902
6127
|
} catch {
|
|
5903
6128
|
}
|
|
5904
6129
|
}
|
|
@@ -5993,12 +6218,14 @@ export default {
|
|
|
5993
6218
|
return null;
|
|
5994
6219
|
}
|
|
5995
6220
|
};
|
|
6221
|
+
const buildServerOnlyGuard = makeWidgetServerOnlyGuard(widgetName);
|
|
5996
6222
|
const buildPlugins = inline ? [
|
|
6223
|
+
buildServerOnlyGuard,
|
|
5997
6224
|
buildNodeStubsPlugin,
|
|
5998
6225
|
tailwindcss(),
|
|
5999
6226
|
react(),
|
|
6000
6227
|
viteSingleFile({ removeViteModuleLoader: true })
|
|
6001
|
-
] : [buildNodeStubsPlugin, tailwindcss(), react()];
|
|
6228
|
+
] : [buildServerOnlyGuard, buildNodeStubsPlugin, tailwindcss(), react()];
|
|
6002
6229
|
await build({
|
|
6003
6230
|
root: tempDir,
|
|
6004
6231
|
base: baseUrl,
|
|
@@ -6017,11 +6244,10 @@ export default {
|
|
|
6017
6244
|
}
|
|
6018
6245
|
}
|
|
6019
6246
|
},
|
|
6020
|
-
resolve
|
|
6021
|
-
|
|
6022
|
-
|
|
6023
|
-
|
|
6024
|
-
},
|
|
6247
|
+
// When a tsconfig exists, enable Vite's native `resolve.tsconfigPaths`
|
|
6248
|
+
// so the project's path aliases resolve naturally. Otherwise fall
|
|
6249
|
+
// back to the legacy `@` → resourcesDir alias.
|
|
6250
|
+
resolve: hasProjectTsconfig ? { tsconfigPaths: true } : { alias: { "@": resourcesDir } },
|
|
6025
6251
|
optimizeDeps: {
|
|
6026
6252
|
// Exclude Node.js-only packages from browser bundling
|
|
6027
6253
|
exclude: ["posthog-node"]
|
|
@@ -6043,7 +6269,7 @@ export default {
|
|
|
6043
6269
|
// Inline all assets under 100MB (effectively all)
|
|
6044
6270
|
} : {},
|
|
6045
6271
|
rolldownOptions: {
|
|
6046
|
-
input:
|
|
6272
|
+
input: path8.join(tempDir, "index.html"),
|
|
6047
6273
|
external: (id) => {
|
|
6048
6274
|
return false;
|
|
6049
6275
|
}
|
|
@@ -6051,12 +6277,12 @@ export default {
|
|
|
6051
6277
|
}
|
|
6052
6278
|
});
|
|
6053
6279
|
try {
|
|
6054
|
-
const assetsDir =
|
|
6055
|
-
const assetFiles = await
|
|
6280
|
+
const assetsDir = path8.join(outDir, "assets");
|
|
6281
|
+
const assetFiles = await fs11.readdir(assetsDir);
|
|
6056
6282
|
const jsFiles = assetFiles.filter((f) => f.endsWith(".js"));
|
|
6057
6283
|
for (const jsFile of jsFiles) {
|
|
6058
|
-
const jsPath =
|
|
6059
|
-
let content = await
|
|
6284
|
+
const jsPath = path8.join(assetsDir, jsFile);
|
|
6285
|
+
let content = await fs11.readFile(jsPath, "utf8");
|
|
6060
6286
|
const zodConfigPatterns = [
|
|
6061
6287
|
// Non-minified: export const globalConfig = {}
|
|
6062
6288
|
/export\s+const\s+globalConfig\s*=\s*\{\s*\}/g,
|
|
@@ -6075,7 +6301,7 @@ export default {
|
|
|
6075
6301
|
}
|
|
6076
6302
|
}
|
|
6077
6303
|
if (patched) {
|
|
6078
|
-
await
|
|
6304
|
+
await fs11.writeFile(jsPath, content, "utf8");
|
|
6079
6305
|
console.log(source_default.gray(` \u2192 Patched Zod JIT in ${jsFile}`));
|
|
6080
6306
|
}
|
|
6081
6307
|
}
|
|
@@ -6087,8 +6313,8 @@ export default {
|
|
|
6087
6313
|
const mcpServerUrl = process.env.MCP_SERVER_URL;
|
|
6088
6314
|
if (mcpServerUrl) {
|
|
6089
6315
|
try {
|
|
6090
|
-
const htmlPath =
|
|
6091
|
-
let html = await
|
|
6316
|
+
const htmlPath = path8.join(outDir, "index.html");
|
|
6317
|
+
let html = await fs11.readFile(htmlPath, "utf8");
|
|
6092
6318
|
const injectionScript = `<script>window.__getFile = (filename) => { return "${mcpUrl}/${widgetName}/"+filename }; window.__mcpPublicUrl = "${mcpServerUrl}/mcp-use/public"; window.__mcpPublicAssetsUrl = "${mcpUrl}/public";</script>`;
|
|
6093
6319
|
if (!html.includes("window.__mcpPublicUrl")) {
|
|
6094
6320
|
html = html.replace(
|
|
@@ -6109,7 +6335,7 @@ export default {
|
|
|
6109
6335
|
<base href="${mcpServerUrl}">`
|
|
6110
6336
|
);
|
|
6111
6337
|
}
|
|
6112
|
-
await
|
|
6338
|
+
await fs11.writeFile(htmlPath, html, "utf8");
|
|
6113
6339
|
console.log(
|
|
6114
6340
|
source_default.gray(` \u2192 Injected MCP_SERVER_URL into ${widgetName}`)
|
|
6115
6341
|
);
|
|
@@ -6123,22 +6349,32 @@ export default {
|
|
|
6123
6349
|
}
|
|
6124
6350
|
}
|
|
6125
6351
|
console.log(source_default.green(` \u2713 Built ${widgetName}`));
|
|
6126
|
-
return {
|
|
6352
|
+
return {
|
|
6353
|
+
status: "built",
|
|
6354
|
+
name: widgetName,
|
|
6355
|
+
metadata: widgetMetadata
|
|
6356
|
+
};
|
|
6127
6357
|
} catch (error) {
|
|
6128
6358
|
console.error(source_default.red(` \u2717 Failed to build ${widgetName}:`), error);
|
|
6129
|
-
return
|
|
6359
|
+
return { status: "failed", name: widgetName };
|
|
6130
6360
|
}
|
|
6131
6361
|
};
|
|
6132
6362
|
const buildResults = await Promise.all(
|
|
6133
6363
|
entries.map((entry) => buildSingleWidget(entry))
|
|
6134
6364
|
);
|
|
6135
|
-
const
|
|
6136
|
-
|
|
6365
|
+
const failed = buildResults.filter((r) => r.status === "failed");
|
|
6366
|
+
if (failed.length > 0) {
|
|
6367
|
+
const names = failed.map((f) => f.name).join(", ");
|
|
6368
|
+
throw new Error(
|
|
6369
|
+
`${failed.length} widget(s) failed to build: ${names}. See errors above.`
|
|
6370
|
+
);
|
|
6371
|
+
}
|
|
6372
|
+
return buildResults.flatMap(
|
|
6373
|
+
(r) => r.status === "built" ? [{ name: r.name, metadata: r.metadata }] : []
|
|
6137
6374
|
);
|
|
6138
|
-
return builtWidgets;
|
|
6139
6375
|
}
|
|
6140
6376
|
async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
|
|
6141
|
-
const { promises:
|
|
6377
|
+
const { promises: fs11 } = await import("fs");
|
|
6142
6378
|
const literalFiles = [];
|
|
6143
6379
|
const dirPrefixes = [];
|
|
6144
6380
|
for (const pattern of includePatterns) {
|
|
@@ -6153,7 +6389,7 @@ async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
|
|
|
6153
6389
|
for (const file of literalFiles) {
|
|
6154
6390
|
if (/\.tsx?$/.test(file) && !file.endsWith(".d.ts")) {
|
|
6155
6391
|
try {
|
|
6156
|
-
await access(
|
|
6392
|
+
await access(path8.join(projectPath, file));
|
|
6157
6393
|
files.push(file);
|
|
6158
6394
|
} catch {
|
|
6159
6395
|
}
|
|
@@ -6161,13 +6397,13 @@ async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
|
|
|
6161
6397
|
}
|
|
6162
6398
|
const excludeSet = new Set(excludePatterns.map((e) => e.replace(/\*+/g, "")));
|
|
6163
6399
|
for (const prefix of dirPrefixes) {
|
|
6164
|
-
const dirPath =
|
|
6400
|
+
const dirPath = path8.join(projectPath, prefix);
|
|
6165
6401
|
try {
|
|
6166
|
-
const entries = await
|
|
6402
|
+
const entries = await fs11.readdir(dirPath, { recursive: true });
|
|
6167
6403
|
for (const entry of entries) {
|
|
6168
6404
|
const entryStr = String(entry);
|
|
6169
|
-
const rel =
|
|
6170
|
-
if (/\.tsx?$/.test(entryStr) && !entryStr.endsWith(".d.ts") && !excludeSet.has(rel.split(
|
|
6405
|
+
const rel = path8.join(prefix, entryStr);
|
|
6406
|
+
if (/\.tsx?$/.test(entryStr) && !entryStr.endsWith(".d.ts") && !excludeSet.has(rel.split(path8.sep)[0])) {
|
|
6171
6407
|
files.push(rel);
|
|
6172
6408
|
}
|
|
6173
6409
|
}
|
|
@@ -6178,11 +6414,11 @@ async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
|
|
|
6178
6414
|
}
|
|
6179
6415
|
async function transpileWithEsbuild(projectPath) {
|
|
6180
6416
|
const esbuild = await import("esbuild");
|
|
6181
|
-
const { promises:
|
|
6182
|
-
const tsconfigPath =
|
|
6417
|
+
const { promises: fs11 } = await import("fs");
|
|
6418
|
+
const tsconfigPath = path8.join(projectPath, "tsconfig.json");
|
|
6183
6419
|
let tsconfig = {};
|
|
6184
6420
|
try {
|
|
6185
|
-
const raw = await
|
|
6421
|
+
const raw = await fs11.readFile(tsconfigPath, "utf-8");
|
|
6186
6422
|
tsconfig = JSON.parse(raw);
|
|
6187
6423
|
} catch {
|
|
6188
6424
|
}
|
|
@@ -6209,10 +6445,10 @@ async function transpileWithEsbuild(projectPath) {
|
|
|
6209
6445
|
const target = (compilerOptions.target || "ES2022").toLowerCase();
|
|
6210
6446
|
const moduleStr = (compilerOptions.module || "ESNext").toLowerCase();
|
|
6211
6447
|
const format = moduleStr.includes("commonjs") ? "cjs" : "esm";
|
|
6212
|
-
const outbase = compilerOptions.rootDir ?
|
|
6448
|
+
const outbase = compilerOptions.rootDir ? path8.resolve(projectPath, compilerOptions.rootDir) : projectPath;
|
|
6213
6449
|
await esbuild.build({
|
|
6214
|
-
entryPoints: files.map((f) =>
|
|
6215
|
-
outdir:
|
|
6450
|
+
entryPoints: files.map((f) => path8.join(projectPath, f)),
|
|
6451
|
+
outdir: path8.join(projectPath, outDir),
|
|
6216
6452
|
outbase,
|
|
6217
6453
|
bundle: false,
|
|
6218
6454
|
format,
|
|
@@ -6224,21 +6460,42 @@ async function transpileWithEsbuild(projectPath) {
|
|
|
6224
6460
|
logLevel: "warning"
|
|
6225
6461
|
});
|
|
6226
6462
|
}
|
|
6227
|
-
program.command("build").description("Build TypeScript and MCP UI widgets").option("-p, --path <path>", "Path to project directory", process.cwd()).option(
|
|
6463
|
+
program.command("build").description("Build TypeScript and MCP UI widgets").option("-p, --path <path>", "Path to project directory", process.cwd()).option(
|
|
6464
|
+
"--entry <file>",
|
|
6465
|
+
"Path to MCP server entry file (relative to project)"
|
|
6466
|
+
).option(
|
|
6467
|
+
"--widgets-dir <dir>",
|
|
6468
|
+
"Path to widgets directory (relative to project)"
|
|
6469
|
+
).option(
|
|
6470
|
+
"--mcp-dir <dir>",
|
|
6471
|
+
"Folder holding the MCP entry + resources (e.g. 'src/mcp' for Next.js apps)"
|
|
6472
|
+
).option("--with-inspector", "Include inspector in production build").option(
|
|
6228
6473
|
"--inline",
|
|
6229
6474
|
"Inline all JS/CSS into HTML (required for VS Code MCP Apps)"
|
|
6230
6475
|
).option("--no-inline", "Keep JS/CSS as separate files (default)").option("--no-typecheck", "Skip TypeScript type checking (faster builds)").action(async (options) => {
|
|
6231
6476
|
try {
|
|
6232
|
-
const projectPath =
|
|
6233
|
-
const { promises:
|
|
6477
|
+
const projectPath = path8.resolve(options.path);
|
|
6478
|
+
const { promises: fs11 } = await import("fs");
|
|
6234
6479
|
displayPackageVersions(projectPath);
|
|
6480
|
+
const mcpDir = options.mcpDir;
|
|
6481
|
+
const widgetsDir = resolveWidgetsDir(options.widgetsDir, mcpDir);
|
|
6235
6482
|
const builtWidgets = await buildWidgets(projectPath, {
|
|
6236
|
-
inline: options.inline ?? false
|
|
6483
|
+
inline: options.inline ?? false,
|
|
6484
|
+
widgetsDir
|
|
6237
6485
|
});
|
|
6238
6486
|
let sourceServerFile;
|
|
6239
6487
|
try {
|
|
6240
|
-
sourceServerFile = await findServerFile(
|
|
6241
|
-
|
|
6488
|
+
sourceServerFile = await findServerFile(
|
|
6489
|
+
projectPath,
|
|
6490
|
+
options.entry,
|
|
6491
|
+
options.mcpDir
|
|
6492
|
+
);
|
|
6493
|
+
} catch (err) {
|
|
6494
|
+
console.log(
|
|
6495
|
+
source_default.yellow(
|
|
6496
|
+
`\u26A0 Could not locate a server entry file: ${err instanceof Error ? err.message : String(err)}`
|
|
6497
|
+
)
|
|
6498
|
+
);
|
|
6242
6499
|
}
|
|
6243
6500
|
if (sourceServerFile) {
|
|
6244
6501
|
console.log(source_default.gray("Generating tool registry types..."));
|
|
@@ -6256,17 +6513,25 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
6256
6513
|
);
|
|
6257
6514
|
}
|
|
6258
6515
|
}
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
|
|
6516
|
+
if (!mcpDir) {
|
|
6517
|
+
console.log(source_default.gray("Building TypeScript..."));
|
|
6518
|
+
await transpileWithEsbuild(projectPath);
|
|
6519
|
+
console.log(source_default.green("\u2713 TypeScript build complete!"));
|
|
6520
|
+
} else {
|
|
6521
|
+
console.log(
|
|
6522
|
+
source_default.gray(
|
|
6523
|
+
"Skipping TypeScript transpile (--mcp-dir mode runs source via tsx at start time)"
|
|
6524
|
+
)
|
|
6525
|
+
);
|
|
6526
|
+
}
|
|
6527
|
+
if (options.typecheck !== false && !mcpDir) {
|
|
6263
6528
|
console.log(source_default.gray("Type checking..."));
|
|
6264
6529
|
try {
|
|
6265
6530
|
await runCommand(
|
|
6266
6531
|
"node",
|
|
6267
6532
|
[
|
|
6268
6533
|
"--max-old-space-size=4096",
|
|
6269
|
-
|
|
6534
|
+
path8.join(
|
|
6270
6535
|
projectPath,
|
|
6271
6536
|
"node_modules",
|
|
6272
6537
|
"typescript",
|
|
@@ -6287,39 +6552,43 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
6287
6552
|
}
|
|
6288
6553
|
let entryPoint;
|
|
6289
6554
|
if (sourceServerFile) {
|
|
6290
|
-
|
|
6291
|
-
|
|
6292
|
-
|
|
6293
|
-
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
|
|
6297
|
-
|
|
6298
|
-
|
|
6299
|
-
|
|
6300
|
-
|
|
6301
|
-
|
|
6302
|
-
|
|
6303
|
-
|
|
6304
|
-
|
|
6305
|
-
|
|
6555
|
+
if (mcpDir) {
|
|
6556
|
+
entryPoint = sourceServerFile;
|
|
6557
|
+
} else {
|
|
6558
|
+
const baseName = path8.basename(sourceServerFile, ".ts") + ".js";
|
|
6559
|
+
const possibleOutputs = [
|
|
6560
|
+
`dist/${baseName}`,
|
|
6561
|
+
// rootDir set to project root or src
|
|
6562
|
+
`dist/src/${baseName}`,
|
|
6563
|
+
// no rootDir, source in src/
|
|
6564
|
+
`dist/${sourceServerFile.replace(/\.ts$/, ".js")}`
|
|
6565
|
+
// exact path preserved
|
|
6566
|
+
];
|
|
6567
|
+
for (const candidate of possibleOutputs) {
|
|
6568
|
+
try {
|
|
6569
|
+
await access(path8.join(projectPath, candidate));
|
|
6570
|
+
entryPoint = candidate;
|
|
6571
|
+
break;
|
|
6572
|
+
} catch {
|
|
6573
|
+
continue;
|
|
6574
|
+
}
|
|
6306
6575
|
}
|
|
6307
6576
|
}
|
|
6308
6577
|
}
|
|
6309
|
-
const publicDir =
|
|
6578
|
+
const publicDir = path8.join(projectPath, "public");
|
|
6310
6579
|
try {
|
|
6311
|
-
await
|
|
6580
|
+
await fs11.access(publicDir);
|
|
6312
6581
|
console.log(source_default.gray("Copying public assets..."));
|
|
6313
|
-
await
|
|
6582
|
+
await fs11.cp(publicDir, path8.join(projectPath, "dist", "public"), {
|
|
6314
6583
|
recursive: true
|
|
6315
6584
|
});
|
|
6316
6585
|
console.log(source_default.green("\u2713 Public assets copied"));
|
|
6317
6586
|
} catch {
|
|
6318
6587
|
}
|
|
6319
|
-
const manifestPath =
|
|
6588
|
+
const manifestPath = path8.join(projectPath, "dist", "mcp-use.json");
|
|
6320
6589
|
let existingManifest = {};
|
|
6321
6590
|
try {
|
|
6322
|
-
const existingContent = await
|
|
6591
|
+
const existingContent = await fs11.readFile(manifestPath, "utf-8");
|
|
6323
6592
|
existingManifest = JSON.parse(existingContent);
|
|
6324
6593
|
} catch {
|
|
6325
6594
|
}
|
|
@@ -6341,8 +6610,8 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
6341
6610
|
// Server entry point for `mcp-use start`
|
|
6342
6611
|
widgets: widgetsData
|
|
6343
6612
|
};
|
|
6344
|
-
await
|
|
6345
|
-
await
|
|
6613
|
+
await fs11.mkdir(path8.dirname(manifestPath), { recursive: true });
|
|
6614
|
+
await fs11.writeFile(
|
|
6346
6615
|
manifestPath,
|
|
6347
6616
|
JSON.stringify(manifest, null, 2),
|
|
6348
6617
|
"utf8"
|
|
@@ -6362,14 +6631,23 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
6362
6631
|
process.exit(1);
|
|
6363
6632
|
}
|
|
6364
6633
|
});
|
|
6365
|
-
program.command("dev").description("Run development server with auto-reload and inspector").option("-p, --path <path>", "Path to project directory", process.cwd()).option(
|
|
6634
|
+
program.command("dev").description("Run development server with auto-reload and inspector").option("-p, --path <path>", "Path to project directory", process.cwd()).option(
|
|
6635
|
+
"--entry <file>",
|
|
6636
|
+
"Path to MCP server entry file (relative to project)"
|
|
6637
|
+
).option(
|
|
6638
|
+
"--widgets-dir <dir>",
|
|
6639
|
+
"Path to widgets directory (relative to project)"
|
|
6640
|
+
).option(
|
|
6641
|
+
"--mcp-dir <dir>",
|
|
6642
|
+
"Folder holding the MCP entry + resources (e.g. 'src/mcp' for Next.js apps)"
|
|
6643
|
+
).option("--port <port>", "Server port", "3000").option(
|
|
6366
6644
|
"--host <host>",
|
|
6367
6645
|
"Server host (use 0.0.0.0 to listen on all interfaces)",
|
|
6368
6646
|
"0.0.0.0"
|
|
6369
6647
|
).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) => {
|
|
6370
6648
|
try {
|
|
6371
6649
|
process.env.MCP_USE_CLI_DEV = "1";
|
|
6372
|
-
const projectPath =
|
|
6650
|
+
const projectPath = path8.resolve(options.path);
|
|
6373
6651
|
let port = parseInt(options.port, 10);
|
|
6374
6652
|
const host = options.host;
|
|
6375
6653
|
const useHmr = options.hmr !== false;
|
|
@@ -6380,13 +6658,24 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6380
6658
|
console.log(source_default.green.bold(`\u2713 Using port ${availablePort} instead`));
|
|
6381
6659
|
port = availablePort;
|
|
6382
6660
|
}
|
|
6383
|
-
const serverFile = await findServerFile(
|
|
6661
|
+
const serverFile = await findServerFile(
|
|
6662
|
+
projectPath,
|
|
6663
|
+
options.entry,
|
|
6664
|
+
options.mcpDir
|
|
6665
|
+
);
|
|
6666
|
+
{
|
|
6667
|
+
const devMcpDir = options.mcpDir;
|
|
6668
|
+
const devWidgetsDir = resolveWidgetsDir(options.widgetsDir, devMcpDir);
|
|
6669
|
+
if (devWidgetsDir !== "resources") {
|
|
6670
|
+
process.env.MCP_USE_WIDGETS_DIR = devWidgetsDir;
|
|
6671
|
+
}
|
|
6672
|
+
}
|
|
6384
6673
|
let tunnelProcess = void 0;
|
|
6385
6674
|
let tunnelSubdomain = void 0;
|
|
6386
6675
|
let tunnelUrl = void 0;
|
|
6387
6676
|
if (options.tunnel) {
|
|
6388
6677
|
try {
|
|
6389
|
-
const manifestPath =
|
|
6678
|
+
const manifestPath = path8.join(projectPath, "dist", "mcp-use.json");
|
|
6390
6679
|
let existingSubdomain;
|
|
6391
6680
|
try {
|
|
6392
6681
|
const manifestContent = await readFile3(manifestPath, "utf-8");
|
|
@@ -6435,7 +6724,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6435
6724
|
manifest.tunnel = {};
|
|
6436
6725
|
}
|
|
6437
6726
|
manifest.tunnel.subdomain = tunnelSubdomain;
|
|
6438
|
-
await mkdir3(
|
|
6727
|
+
await mkdir3(path8.dirname(manifestPath), { recursive: true });
|
|
6439
6728
|
await writeFile3(
|
|
6440
6729
|
manifestPath,
|
|
6441
6730
|
JSON.stringify(manifest, null, 2),
|
|
@@ -6462,22 +6751,35 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6462
6751
|
} else if (!process.env.MCP_URL) {
|
|
6463
6752
|
process.env.MCP_URL = mcpUrl;
|
|
6464
6753
|
}
|
|
6754
|
+
const isNextJsProject = await detectNextJsProject(projectPath);
|
|
6755
|
+
if (isNextJsProject) {
|
|
6756
|
+
console.log(
|
|
6757
|
+
source_default.gray(
|
|
6758
|
+
"Next.js detected \u2014 installing server-runtime shims (server-only, next/cache, next/headers, next/navigation, next/server)"
|
|
6759
|
+
)
|
|
6760
|
+
);
|
|
6761
|
+
await loadNextJsEnvFiles(projectPath);
|
|
6762
|
+
}
|
|
6465
6763
|
if (!useHmr) {
|
|
6466
6764
|
console.log(source_default.gray("HMR disabled, using tsx watch (full restart)"));
|
|
6467
6765
|
const processes = [];
|
|
6468
|
-
const
|
|
6766
|
+
const baseEnv = {
|
|
6767
|
+
// Inherit parent env (PATH, HOME, etc.) — without it, tsx can't
|
|
6768
|
+
// resolve its own tooling in some setups.
|
|
6769
|
+
...process.env,
|
|
6469
6770
|
PORT: String(port),
|
|
6470
6771
|
HOST: host,
|
|
6471
6772
|
NODE_ENV: "development",
|
|
6472
6773
|
// Preserve user-provided MCP_URL (e.g., for reverse proxy setups)
|
|
6473
6774
|
MCP_URL: process.env.MCP_URL || mcpUrl
|
|
6474
6775
|
};
|
|
6776
|
+
const env2 = isNextJsProject ? withNextShimsEnv(baseEnv) : baseEnv;
|
|
6475
6777
|
const { createRequire: createRequire4 } = await import("module");
|
|
6476
6778
|
let cmd;
|
|
6477
6779
|
let args;
|
|
6478
6780
|
try {
|
|
6479
6781
|
const projectRequire = createRequire4(
|
|
6480
|
-
|
|
6782
|
+
path8.join(projectPath, "package.json")
|
|
6481
6783
|
);
|
|
6482
6784
|
const tsxPkgPath = projectRequire.resolve("tsx/package.json");
|
|
6483
6785
|
const tsxPkg = JSON.parse(await readFile3(tsxPkgPath, "utf-8"));
|
|
@@ -6489,7 +6791,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6489
6791
|
} else {
|
|
6490
6792
|
throw new Error("No bin field found in tsx package.json");
|
|
6491
6793
|
}
|
|
6492
|
-
const tsxBin =
|
|
6794
|
+
const tsxBin = path8.resolve(path8.dirname(tsxPkgPath), binPath);
|
|
6493
6795
|
cmd = "node";
|
|
6494
6796
|
args = [tsxBin, "watch", serverFile];
|
|
6495
6797
|
} catch (error) {
|
|
@@ -6564,18 +6866,56 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6564
6866
|
"HMR enabled - changes will hot reload without dropping connections"
|
|
6565
6867
|
)
|
|
6566
6868
|
);
|
|
6869
|
+
if (isNextJsProject) {
|
|
6870
|
+
const registered = await registerNextShimsInProcess();
|
|
6871
|
+
if (!registered) {
|
|
6872
|
+
console.warn(
|
|
6873
|
+
source_default.yellow(
|
|
6874
|
+
"[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."
|
|
6875
|
+
)
|
|
6876
|
+
);
|
|
6877
|
+
}
|
|
6878
|
+
}
|
|
6567
6879
|
const chokidarModule = await import("chokidar");
|
|
6568
6880
|
const chokidar = chokidarModule.default || chokidarModule;
|
|
6569
|
-
const { fileURLToPath:
|
|
6881
|
+
const { fileURLToPath: fileURLToPath4 } = await import("url");
|
|
6570
6882
|
const { createRequire: createRequire3 } = await import("module");
|
|
6571
|
-
|
|
6883
|
+
const projectTsconfigPath = path8.join(projectPath, "tsconfig.json");
|
|
6884
|
+
let tsconfigAvailable = false;
|
|
6885
|
+
try {
|
|
6886
|
+
await access(projectTsconfigPath);
|
|
6887
|
+
tsconfigAvailable = true;
|
|
6888
|
+
process.env.TSX_TSCONFIG_PATH = projectTsconfigPath;
|
|
6889
|
+
if (process.cwd() !== projectPath) process.chdir(projectPath);
|
|
6890
|
+
} catch {
|
|
6891
|
+
}
|
|
6892
|
+
let tsxLoaderActive = false;
|
|
6572
6893
|
try {
|
|
6573
6894
|
const projectRequire = createRequire3(
|
|
6574
|
-
|
|
6895
|
+
path8.join(projectPath, "package.json")
|
|
6575
6896
|
);
|
|
6576
|
-
const
|
|
6577
|
-
const
|
|
6578
|
-
|
|
6897
|
+
const tsxEsmApiPath = projectRequire.resolve("tsx/esm/api");
|
|
6898
|
+
const tsxEsmApi = await import(pathToFileURL2(tsxEsmApiPath).href);
|
|
6899
|
+
if (typeof tsxEsmApi.register === "function") {
|
|
6900
|
+
tsxEsmApi.register({
|
|
6901
|
+
tsconfig: tsconfigAvailable ? projectTsconfigPath : void 0,
|
|
6902
|
+
onImport: (url) => {
|
|
6903
|
+
const filePath = url.startsWith("file://") ? fileURLToPath4(url) : url;
|
|
6904
|
+
if (!filePath.includes("node_modules") && filePath.startsWith(projectPath)) {
|
|
6905
|
+
console.debug(`[HMR] Loaded: ${url}`);
|
|
6906
|
+
}
|
|
6907
|
+
}
|
|
6908
|
+
});
|
|
6909
|
+
tsxLoaderActive = true;
|
|
6910
|
+
}
|
|
6911
|
+
try {
|
|
6912
|
+
const tsxCjsApiPath = projectRequire.resolve("tsx/cjs/api");
|
|
6913
|
+
const tsxCjsApi = await import(pathToFileURL2(tsxCjsApiPath).href);
|
|
6914
|
+
if (typeof tsxCjsApi.register === "function") {
|
|
6915
|
+
tsxCjsApi.register();
|
|
6916
|
+
}
|
|
6917
|
+
} catch {
|
|
6918
|
+
}
|
|
6579
6919
|
} catch {
|
|
6580
6920
|
console.log(
|
|
6581
6921
|
source_default.yellow(
|
|
@@ -6583,25 +6923,15 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6583
6923
|
)
|
|
6584
6924
|
);
|
|
6585
6925
|
}
|
|
6586
|
-
const serverFilePath =
|
|
6587
|
-
const serverFileUrl =
|
|
6926
|
+
const serverFilePath = path8.join(projectPath, serverFile);
|
|
6927
|
+
const serverFileUrl = pathToFileURL2(serverFilePath).href;
|
|
6588
6928
|
globalThis.__mcpUseHmrMode = true;
|
|
6589
6929
|
const importServerModule = async () => {
|
|
6590
6930
|
const previousServer = globalThis.__mcpUseLastServer;
|
|
6591
6931
|
globalThis.__mcpUseLastServer = null;
|
|
6592
|
-
if (
|
|
6593
|
-
await tsImport(`${serverFileUrl}?t=${Date.now()}`, {
|
|
6594
|
-
parentURL: import.meta.url,
|
|
6595
|
-
onImport: (file) => {
|
|
6596
|
-
const filePath = file.startsWith("file://") ? fileURLToPath3(file) : file;
|
|
6597
|
-
if (!filePath.includes("node_modules") && filePath.startsWith(projectPath)) {
|
|
6598
|
-
console.debug(`[HMR] Loaded: ${file}`);
|
|
6599
|
-
}
|
|
6600
|
-
}
|
|
6601
|
-
});
|
|
6602
|
-
} else {
|
|
6603
|
-
await import(`${serverFileUrl}?t=${Date.now()}`);
|
|
6932
|
+
if (!tsxLoaderActive) {
|
|
6604
6933
|
}
|
|
6934
|
+
await import(`${serverFileUrl}?t=${Date.now()}`);
|
|
6605
6935
|
const instance = globalThis.__mcpUseLastServer;
|
|
6606
6936
|
if (!instance) {
|
|
6607
6937
|
globalThis.__mcpUseLastServer = previousServer;
|
|
@@ -6615,7 +6945,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6615
6945
|
if (instance === previousServer) {
|
|
6616
6946
|
console.warn(
|
|
6617
6947
|
source_default.yellow(
|
|
6618
|
-
"[HMR] Warning: Module re-import returned the same server instance. The module may not have been re-evaluated. " + (!
|
|
6948
|
+
"[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.")
|
|
6619
6949
|
)
|
|
6620
6950
|
);
|
|
6621
6951
|
return null;
|
|
@@ -6690,8 +7020,8 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6690
7020
|
}
|
|
6691
7021
|
let watcher = chokidar.watch(".", {
|
|
6692
7022
|
cwd: projectPath,
|
|
6693
|
-
ignored: (
|
|
6694
|
-
const normalizedPath =
|
|
7023
|
+
ignored: (path9, stats) => {
|
|
7024
|
+
const normalizedPath = path9.replace(/\\/g, "/");
|
|
6695
7025
|
if (/(^|\/)\.[^/]/.test(normalizedPath)) {
|
|
6696
7026
|
return true;
|
|
6697
7027
|
}
|
|
@@ -6865,7 +7195,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6865
7195
|
}
|
|
6866
7196
|
tunnelUrl = void 0;
|
|
6867
7197
|
if (withTunnel) {
|
|
6868
|
-
const manifestPath =
|
|
7198
|
+
const manifestPath = path8.join(projectPath, "dist", "mcp-use.json");
|
|
6869
7199
|
let existingSubdomain;
|
|
6870
7200
|
try {
|
|
6871
7201
|
const manifestContent = await readFile3(manifestPath, "utf-8");
|
|
@@ -6902,7 +7232,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6902
7232
|
tunnelSubdomain = tunnelInfo.subdomain;
|
|
6903
7233
|
process.env.MCP_URL = tunnelUrl;
|
|
6904
7234
|
try {
|
|
6905
|
-
const mPath =
|
|
7235
|
+
const mPath = path8.join(projectPath, "dist", "mcp-use.json");
|
|
6906
7236
|
let manifest = {};
|
|
6907
7237
|
try {
|
|
6908
7238
|
manifest = JSON.parse(await readFile3(mPath, "utf-8"));
|
|
@@ -6910,7 +7240,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6910
7240
|
}
|
|
6911
7241
|
if (!manifest.tunnel) manifest.tunnel = {};
|
|
6912
7242
|
manifest.tunnel.subdomain = tunnelSubdomain;
|
|
6913
|
-
await mkdir3(
|
|
7243
|
+
await mkdir3(path8.dirname(mPath), { recursive: true });
|
|
6914
7244
|
await writeFile3(mPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
6915
7245
|
} catch {
|
|
6916
7246
|
}
|
|
@@ -7006,9 +7336,15 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
7006
7336
|
process.exit(1);
|
|
7007
7337
|
}
|
|
7008
7338
|
});
|
|
7009
|
-
program.command("start").description("Start production server").option("-p, --path <path>", "Path to project directory", process.cwd()).option(
|
|
7339
|
+
program.command("start").description("Start production server").option("-p, --path <path>", "Path to project directory", process.cwd()).option(
|
|
7340
|
+
"--entry <file>",
|
|
7341
|
+
"Path to MCP server entry file (relative to project)"
|
|
7342
|
+
).option(
|
|
7343
|
+
"--mcp-dir <dir>",
|
|
7344
|
+
"Folder holding the MCP entry + resources (e.g. 'src/mcp' for Next.js apps)"
|
|
7345
|
+
).option("--port <port>", "Server port", "3000").option("--tunnel", "Expose server through a tunnel").action(async (options) => {
|
|
7010
7346
|
try {
|
|
7011
|
-
const projectPath =
|
|
7347
|
+
const projectPath = path8.resolve(options.path);
|
|
7012
7348
|
const portFlagProvided = process.argv.includes("--port") || process.argv.includes("-p") || process.argv.some((arg) => arg.startsWith("--port=")) || process.argv.some((arg) => arg.startsWith("-p="));
|
|
7013
7349
|
let port = portFlagProvided ? parseInt(options.port, 10) : parseInt(process.env.PORT || options.port || "3000", 10);
|
|
7014
7350
|
if (!await isPortAvailable(port)) {
|
|
@@ -7026,7 +7362,7 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
7026
7362
|
let tunnelSubdomain = void 0;
|
|
7027
7363
|
if (options.tunnel) {
|
|
7028
7364
|
try {
|
|
7029
|
-
const manifestPath2 =
|
|
7365
|
+
const manifestPath2 = path8.join(projectPath, "dist", "mcp-use.json");
|
|
7030
7366
|
let existingSubdomain;
|
|
7031
7367
|
try {
|
|
7032
7368
|
const manifestContent = await readFile3(manifestPath2, "utf-8");
|
|
@@ -7081,7 +7417,7 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
7081
7417
|
manifest.tunnel = {};
|
|
7082
7418
|
}
|
|
7083
7419
|
manifest.tunnel.subdomain = subdomain;
|
|
7084
|
-
await mkdir3(
|
|
7420
|
+
await mkdir3(path8.dirname(manifestPath2), { recursive: true });
|
|
7085
7421
|
await writeFile3(
|
|
7086
7422
|
manifestPath2,
|
|
7087
7423
|
JSON.stringify(manifest, null, 2),
|
|
@@ -7100,18 +7436,25 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
7100
7436
|
}
|
|
7101
7437
|
}
|
|
7102
7438
|
let serverFile;
|
|
7103
|
-
const manifestPath =
|
|
7439
|
+
const manifestPath = path8.join(projectPath, "dist", "mcp-use.json");
|
|
7104
7440
|
try {
|
|
7105
7441
|
const manifestContent = await readFile3(manifestPath, "utf-8");
|
|
7106
7442
|
const manifest = JSON.parse(manifestContent);
|
|
7107
7443
|
if (manifest.entryPoint) {
|
|
7108
|
-
await access(
|
|
7444
|
+
await access(path8.join(projectPath, manifest.entryPoint));
|
|
7109
7445
|
serverFile = manifest.entryPoint;
|
|
7110
7446
|
}
|
|
7111
7447
|
} catch {
|
|
7112
7448
|
}
|
|
7113
7449
|
if (!serverFile) {
|
|
7450
|
+
const startMcpDir = options.mcpDir;
|
|
7114
7451
|
const serverCandidates = [
|
|
7452
|
+
...startMcpDir ? [
|
|
7453
|
+
`${startMcpDir}/index.ts`,
|
|
7454
|
+
`${startMcpDir}/index.tsx`,
|
|
7455
|
+
`dist/${startMcpDir}/index.js`,
|
|
7456
|
+
`dist/${startMcpDir}/server.js`
|
|
7457
|
+
] : [],
|
|
7115
7458
|
"dist/index.js",
|
|
7116
7459
|
"dist/server.js",
|
|
7117
7460
|
"dist/src/index.js",
|
|
@@ -7119,7 +7462,7 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
7119
7462
|
];
|
|
7120
7463
|
for (const candidate of serverCandidates) {
|
|
7121
7464
|
try {
|
|
7122
|
-
await access(
|
|
7465
|
+
await access(path8.join(projectPath, candidate));
|
|
7123
7466
|
serverFile = candidate;
|
|
7124
7467
|
break;
|
|
7125
7468
|
} catch {
|
|
@@ -7143,18 +7486,53 @@ Looked for:
|
|
|
7143
7486
|
process.exit(1);
|
|
7144
7487
|
}
|
|
7145
7488
|
console.log("Starting production server...");
|
|
7146
|
-
const
|
|
7489
|
+
const isNextJsProject = await detectNextJsProject(projectPath);
|
|
7490
|
+
if (isNextJsProject) {
|
|
7491
|
+
console.log(
|
|
7492
|
+
source_default.gray(
|
|
7493
|
+
"Next.js detected \u2014 installing server-runtime shims for the production server"
|
|
7494
|
+
)
|
|
7495
|
+
);
|
|
7496
|
+
await loadNextJsEnvFiles(projectPath);
|
|
7497
|
+
}
|
|
7498
|
+
const baseEnv = {
|
|
7147
7499
|
...process.env,
|
|
7148
7500
|
PORT: String(port),
|
|
7149
7501
|
NODE_ENV: "production"
|
|
7150
7502
|
};
|
|
7151
7503
|
if (mcpUrl) {
|
|
7152
|
-
|
|
7504
|
+
baseEnv.MCP_URL = mcpUrl;
|
|
7153
7505
|
console.log(source_default.whiteBright(`Tunnel: ${mcpUrl}/mcp`));
|
|
7154
|
-
} else if (!
|
|
7155
|
-
|
|
7506
|
+
} else if (!baseEnv.MCP_URL) {
|
|
7507
|
+
baseEnv.MCP_URL = `http://localhost:${port}`;
|
|
7508
|
+
}
|
|
7509
|
+
const env2 = isNextJsProject ? withNextShimsEnv(baseEnv) : baseEnv;
|
|
7510
|
+
const isTsEntry = /\.(ts|tsx|mts|cts)$/.test(serverFile);
|
|
7511
|
+
let spawnCmd = "node";
|
|
7512
|
+
let spawnArgs = [serverFile];
|
|
7513
|
+
if (isTsEntry) {
|
|
7514
|
+
try {
|
|
7515
|
+
const projectRequire = createRequire2(
|
|
7516
|
+
path8.join(projectPath, "package.json")
|
|
7517
|
+
);
|
|
7518
|
+
const tsxPkgPath = projectRequire.resolve("tsx/package.json");
|
|
7519
|
+
const tsxPkg = JSON.parse(await readFile3(tsxPkgPath, "utf-8"));
|
|
7520
|
+
const binField = typeof tsxPkg.bin === "string" ? tsxPkg.bin : tsxPkg.bin?.tsx ?? Object.values(tsxPkg.bin ?? {})[0];
|
|
7521
|
+
if (!binField) throw new Error("tsx bin entry not found");
|
|
7522
|
+
const tsxBin = path8.resolve(path8.dirname(tsxPkgPath), binField);
|
|
7523
|
+
spawnCmd = "node";
|
|
7524
|
+
spawnArgs = [tsxBin, serverFile];
|
|
7525
|
+
} catch (error) {
|
|
7526
|
+
console.log(
|
|
7527
|
+
source_default.yellow(
|
|
7528
|
+
`Could not resolve local tsx (${error instanceof Error ? error.message : String(error)}); falling back to npx`
|
|
7529
|
+
)
|
|
7530
|
+
);
|
|
7531
|
+
spawnCmd = "npx";
|
|
7532
|
+
spawnArgs = ["tsx", serverFile];
|
|
7533
|
+
}
|
|
7156
7534
|
}
|
|
7157
|
-
const serverProc = spawn(
|
|
7535
|
+
const serverProc = spawn(spawnCmd, spawnArgs, {
|
|
7158
7536
|
cwd: projectPath,
|
|
7159
7537
|
stdio: "inherit",
|
|
7160
7538
|
env: env2
|
|
@@ -7290,7 +7668,7 @@ program.addCommand(createSkillsCommand());
|
|
|
7290
7668
|
program.command("generate-types").description(
|
|
7291
7669
|
"Generate TypeScript type definitions for tools (writes .mcp-use/tool-registry.d.ts)"
|
|
7292
7670
|
).option("-p, --path <path>", "Path to project directory", process.cwd()).option("--server <file>", "Server entry file", "index.ts").action(async (options) => {
|
|
7293
|
-
const projectPath =
|
|
7671
|
+
const projectPath = path8.resolve(options.path);
|
|
7294
7672
|
try {
|
|
7295
7673
|
console.log(source_default.blue("Generating tool registry types..."));
|
|
7296
7674
|
const success = await generateToolRegistryTypesForServer(
|