@mcp-use/cli 3.1.0-canary.2 → 3.1.0-canary.4
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/commands/deploy.d.ts.map +1 -1
- package/dist/index.cjs +581 -179
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +576 -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(
|
|
@@ -3575,12 +3575,16 @@ async function deployCommand(options) {
|
|
|
3575
3575
|
}
|
|
3576
3576
|
let api = await McpUseAPI.create();
|
|
3577
3577
|
let resolvedOrgId;
|
|
3578
|
+
let resolvedOrgName;
|
|
3579
|
+
let resolvedOrgSlug;
|
|
3578
3580
|
if (options.org) {
|
|
3579
3581
|
const authInfo = await api.testAuth();
|
|
3580
3582
|
const match = resolveOrgFromOption(authInfo.orgs ?? [], options.org);
|
|
3581
3583
|
if (match) {
|
|
3582
3584
|
api.setOrgId(match.id);
|
|
3583
3585
|
resolvedOrgId = match.id;
|
|
3586
|
+
resolvedOrgName = match.name;
|
|
3587
|
+
resolvedOrgSlug = match.slug ?? void 0;
|
|
3584
3588
|
const slug = match.slug ? source_default.gray(` (${match.slug})`) : "";
|
|
3585
3589
|
console.log(
|
|
3586
3590
|
source_default.gray("Organization: ") + source_default.cyan(match.name) + slug
|
|
@@ -3620,6 +3624,8 @@ async function deployCommand(options) {
|
|
|
3620
3624
|
}
|
|
3621
3625
|
api.setOrgId(selectedOrg.id);
|
|
3622
3626
|
resolvedOrgId = selectedOrg.id;
|
|
3627
|
+
resolvedOrgName = selectedOrg.name;
|
|
3628
|
+
resolvedOrgSlug = selectedOrg.slug ?? void 0;
|
|
3623
3629
|
await writeConfig({
|
|
3624
3630
|
...config,
|
|
3625
3631
|
orgId: selectedOrg.id,
|
|
@@ -3631,6 +3637,8 @@ async function deployCommand(options) {
|
|
|
3631
3637
|
);
|
|
3632
3638
|
} else {
|
|
3633
3639
|
resolvedOrgId = config.orgId;
|
|
3640
|
+
resolvedOrgName = config.orgName;
|
|
3641
|
+
resolvedOrgSlug = config.orgSlug;
|
|
3634
3642
|
api.setOrgId(config.orgId);
|
|
3635
3643
|
if (config.orgName) {
|
|
3636
3644
|
const slug = config.orgSlug ? source_default.gray(` (${config.orgSlug})`) : "";
|
|
@@ -4027,6 +4035,22 @@ async function deployCommand(options) {
|
|
|
4027
4035
|
}
|
|
4028
4036
|
const existingLink = !options.new ? await getProjectLink(cwd) : null;
|
|
4029
4037
|
let serverId = existingLink?.serverId;
|
|
4038
|
+
if (serverId && resolvedOrgId) {
|
|
4039
|
+
try {
|
|
4040
|
+
const linkedServer = await api.getServer(serverId);
|
|
4041
|
+
if (linkedServer.organizationId !== resolvedOrgId) {
|
|
4042
|
+
const target = resolvedOrgName ? `${resolvedOrgName}${resolvedOrgSlug ? ` (${resolvedOrgSlug})` : ""}` : resolvedOrgId;
|
|
4043
|
+
console.log(
|
|
4044
|
+
source_default.yellow(
|
|
4045
|
+
`\u26A0\uFE0F Linked server belongs to a different organization. Creating a new server in ${target}...
|
|
4046
|
+
`
|
|
4047
|
+
)
|
|
4048
|
+
);
|
|
4049
|
+
serverId = void 0;
|
|
4050
|
+
}
|
|
4051
|
+
} catch {
|
|
4052
|
+
}
|
|
4053
|
+
}
|
|
4030
4054
|
if (existingLink && serverId) {
|
|
4031
4055
|
try {
|
|
4032
4056
|
const existingDep = await api.getDeployment(existingLink.deploymentId);
|
|
@@ -5230,7 +5254,7 @@ async function addSkillsToProject(projectPath) {
|
|
|
5230
5254
|
Readable.fromWeb(response.body),
|
|
5231
5255
|
extract({
|
|
5232
5256
|
cwd: tempDir,
|
|
5233
|
-
filter: (
|
|
5257
|
+
filter: (path9) => path9.includes("/skills/"),
|
|
5234
5258
|
strip: 1
|
|
5235
5259
|
})
|
|
5236
5260
|
);
|
|
@@ -5295,14 +5319,114 @@ function createSkillsCommand() {
|
|
|
5295
5319
|
return skills;
|
|
5296
5320
|
}
|
|
5297
5321
|
|
|
5322
|
+
// src/utils/next-shims.ts
|
|
5323
|
+
import { existsSync as existsSync3, promises as fs10 } from "fs";
|
|
5324
|
+
import path6 from "path";
|
|
5325
|
+
import { fileURLToPath as fileURLToPath3, pathToFileURL } from "url";
|
|
5326
|
+
async function detectNextJsProject(projectPath) {
|
|
5327
|
+
try {
|
|
5328
|
+
const pkgPath = path6.join(projectPath, "package.json");
|
|
5329
|
+
const content = await fs10.readFile(pkgPath, "utf-8");
|
|
5330
|
+
const pkg = JSON.parse(content);
|
|
5331
|
+
const deps = pkg.dependencies ?? {};
|
|
5332
|
+
const devDeps = pkg.devDependencies ?? {};
|
|
5333
|
+
return "next" in deps || "next" in devDeps;
|
|
5334
|
+
} catch {
|
|
5335
|
+
return false;
|
|
5336
|
+
}
|
|
5337
|
+
}
|
|
5338
|
+
async function loadNextJsEnvFiles(projectPath) {
|
|
5339
|
+
const files = [
|
|
5340
|
+
".env",
|
|
5341
|
+
".env.development",
|
|
5342
|
+
".env.local",
|
|
5343
|
+
".env.development.local"
|
|
5344
|
+
];
|
|
5345
|
+
const dotenv = await import("dotenv");
|
|
5346
|
+
for (const file of files) {
|
|
5347
|
+
const abs = path6.join(projectPath, file);
|
|
5348
|
+
try {
|
|
5349
|
+
await fs10.access(abs);
|
|
5350
|
+
} catch {
|
|
5351
|
+
continue;
|
|
5352
|
+
}
|
|
5353
|
+
dotenv.config({ path: abs, override: true, quiet: true });
|
|
5354
|
+
}
|
|
5355
|
+
}
|
|
5356
|
+
function getThisDir() {
|
|
5357
|
+
if (typeof __dirname === "string") return __dirname;
|
|
5358
|
+
const url = import.meta.url;
|
|
5359
|
+
return path6.dirname(fileURLToPath3(url));
|
|
5360
|
+
}
|
|
5361
|
+
function resolveShimPath(filename) {
|
|
5362
|
+
const thisDir = getThisDir();
|
|
5363
|
+
const candidates = [
|
|
5364
|
+
// Production: `dist/` next to this module
|
|
5365
|
+
path6.join(thisDir, "shims", filename),
|
|
5366
|
+
// Test / dev: one level up (e.g., from `dist/utils/` back to `src/shims/`)
|
|
5367
|
+
path6.join(thisDir, "..", "shims", filename),
|
|
5368
|
+
path6.join(thisDir, "..", "..", "src", "shims", filename),
|
|
5369
|
+
path6.join(thisDir, "..", "src", "shims", filename)
|
|
5370
|
+
];
|
|
5371
|
+
for (const candidate of candidates) {
|
|
5372
|
+
if (existsSync3(candidate)) return candidate;
|
|
5373
|
+
}
|
|
5374
|
+
return void 0;
|
|
5375
|
+
}
|
|
5376
|
+
function getShimRegisterPath() {
|
|
5377
|
+
return resolveShimPath("next-shims-register.mjs");
|
|
5378
|
+
}
|
|
5379
|
+
function getShimLoaderPath() {
|
|
5380
|
+
return resolveShimPath("next-shims-loader.mjs");
|
|
5381
|
+
}
|
|
5382
|
+
function getShimCjsPreloadPath() {
|
|
5383
|
+
return resolveShimPath("next-shims-cjs.cjs");
|
|
5384
|
+
}
|
|
5385
|
+
async function registerNextShimsInProcess() {
|
|
5386
|
+
let anyRegistered = false;
|
|
5387
|
+
const cjsPath = getShimCjsPreloadPath();
|
|
5388
|
+
if (cjsPath) {
|
|
5389
|
+
const { createRequire: createRequire3 } = await import("module");
|
|
5390
|
+
const req = createRequire3(pathToFileURL(getThisDir() + path6.sep).href);
|
|
5391
|
+
req(cjsPath);
|
|
5392
|
+
anyRegistered = true;
|
|
5393
|
+
}
|
|
5394
|
+
const loaderPath = getShimLoaderPath();
|
|
5395
|
+
if (loaderPath) {
|
|
5396
|
+
const { register } = await import("module");
|
|
5397
|
+
const loaderUrl = pathToFileURL(loaderPath).href;
|
|
5398
|
+
register(loaderUrl, pathToFileURL(getThisDir() + path6.sep).href);
|
|
5399
|
+
anyRegistered = true;
|
|
5400
|
+
}
|
|
5401
|
+
return anyRegistered;
|
|
5402
|
+
}
|
|
5403
|
+
function withNextShimsEnv(baseEnv) {
|
|
5404
|
+
const additions = [];
|
|
5405
|
+
const cjsPath = getShimCjsPreloadPath();
|
|
5406
|
+
if (cjsPath) additions.push(`-r ${quoteNodeOption(cjsPath)}`);
|
|
5407
|
+
const registerPath = getShimRegisterPath();
|
|
5408
|
+
if (registerPath)
|
|
5409
|
+
additions.push(`--import=${pathToFileURL(registerPath).href}`);
|
|
5410
|
+
if (additions.length === 0) return baseEnv;
|
|
5411
|
+
const existing = baseEnv.NODE_OPTIONS ?? "";
|
|
5412
|
+
const prepended = additions.join(" ");
|
|
5413
|
+
return {
|
|
5414
|
+
...baseEnv,
|
|
5415
|
+
NODE_OPTIONS: existing ? `${prepended} ${existing}` : prepended
|
|
5416
|
+
};
|
|
5417
|
+
}
|
|
5418
|
+
function quoteNodeOption(value) {
|
|
5419
|
+
return /\s/.test(value) ? `"${value}"` : value;
|
|
5420
|
+
}
|
|
5421
|
+
|
|
5298
5422
|
// src/utils/update-check.ts
|
|
5299
5423
|
import { readFileSync } from "fs";
|
|
5300
5424
|
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
5301
5425
|
import { createRequire } from "module";
|
|
5302
5426
|
import os4 from "os";
|
|
5303
|
-
import
|
|
5304
|
-
var CACHE_DIR =
|
|
5305
|
-
var CACHE_FILE =
|
|
5427
|
+
import path7 from "path";
|
|
5428
|
+
var CACHE_DIR = path7.join(os4.homedir(), ".mcp-use");
|
|
5429
|
+
var CACHE_FILE = path7.join(CACHE_DIR, "update-check.json");
|
|
5306
5430
|
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
5307
5431
|
var FETCH_TIMEOUT_MS = 3e3;
|
|
5308
5432
|
var PACKAGE_NAME = "mcp-use";
|
|
@@ -5385,12 +5509,12 @@ function resolveInstalledVersion(projectPath) {
|
|
|
5385
5509
|
if (projectPath) {
|
|
5386
5510
|
attempts.push(() => {
|
|
5387
5511
|
const projectRequire = createRequire(
|
|
5388
|
-
|
|
5512
|
+
path7.join(projectPath, "package.json")
|
|
5389
5513
|
);
|
|
5390
5514
|
return projectRequire.resolve(`${PACKAGE_NAME}/package.json`);
|
|
5391
5515
|
});
|
|
5392
5516
|
}
|
|
5393
|
-
attempts.push(() =>
|
|
5517
|
+
attempts.push(() => path7.join(__dirname, "../../mcp-use/package.json"));
|
|
5394
5518
|
for (const attempt of attempts) {
|
|
5395
5519
|
try {
|
|
5396
5520
|
const pkgPath = attempt();
|
|
@@ -5428,7 +5552,7 @@ A new release of ${source_default.bold(PACKAGE_NAME)} is available: ${source_def
|
|
|
5428
5552
|
// src/index.ts
|
|
5429
5553
|
var program = new Command6();
|
|
5430
5554
|
var packageContent = readFileSync2(
|
|
5431
|
-
|
|
5555
|
+
path8.join(__dirname, "../package.json"),
|
|
5432
5556
|
"utf-8"
|
|
5433
5557
|
);
|
|
5434
5558
|
var packageJson = JSON.parse(packageContent);
|
|
@@ -5459,14 +5583,14 @@ function displayPackageVersions(projectPath) {
|
|
|
5459
5583
|
if (projectPath) {
|
|
5460
5584
|
try {
|
|
5461
5585
|
const projectRequire = createRequire2(
|
|
5462
|
-
|
|
5586
|
+
path8.join(projectPath, "package.json")
|
|
5463
5587
|
);
|
|
5464
5588
|
pkgPath = projectRequire.resolve(`${pkg.name}/package.json`);
|
|
5465
5589
|
} catch (resolveError) {
|
|
5466
|
-
pkgPath =
|
|
5590
|
+
pkgPath = path8.join(__dirname, pkg.relativePath);
|
|
5467
5591
|
}
|
|
5468
5592
|
} else {
|
|
5469
|
-
pkgPath =
|
|
5593
|
+
pkgPath = path8.join(__dirname, pkg.relativePath);
|
|
5470
5594
|
}
|
|
5471
5595
|
const pkgContent = readFileSync2(pkgPath, "utf-8");
|
|
5472
5596
|
const pkgJson = JSON.parse(pkgContent);
|
|
@@ -5618,20 +5742,92 @@ async function startTunnel(port, subdomain) {
|
|
|
5618
5742
|
}, 3e4);
|
|
5619
5743
|
});
|
|
5620
5744
|
}
|
|
5621
|
-
async function
|
|
5745
|
+
async function resolveEntryFile(projectPath, cliEntry, mcpDir) {
|
|
5746
|
+
if (cliEntry) {
|
|
5747
|
+
await access(path8.join(projectPath, cliEntry)).catch(() => {
|
|
5748
|
+
throw new Error(`File not found: ${cliEntry}`);
|
|
5749
|
+
});
|
|
5750
|
+
return cliEntry;
|
|
5751
|
+
}
|
|
5752
|
+
if (mcpDir) {
|
|
5753
|
+
const mcpCandidates = [
|
|
5754
|
+
path8.join(mcpDir, "index.ts"),
|
|
5755
|
+
path8.join(mcpDir, "index.tsx"),
|
|
5756
|
+
path8.join(mcpDir, "server.ts"),
|
|
5757
|
+
path8.join(mcpDir, "server.tsx")
|
|
5758
|
+
];
|
|
5759
|
+
for (const candidate of mcpCandidates) {
|
|
5760
|
+
try {
|
|
5761
|
+
await access(path8.join(projectPath, candidate));
|
|
5762
|
+
return candidate;
|
|
5763
|
+
} catch {
|
|
5764
|
+
continue;
|
|
5765
|
+
}
|
|
5766
|
+
}
|
|
5767
|
+
throw new Error(
|
|
5768
|
+
`No entry file found inside ${mcpDir}.
|
|
5769
|
+
|
|
5770
|
+
Expected one of: ${mcpCandidates.map((c) => path8.relative(projectPath, path8.join(projectPath, c))).join(", ")}
|
|
5771
|
+
|
|
5772
|
+
Fix this by either:
|
|
5773
|
+
1. Creating ${path8.join(mcpDir, "index.ts")}, or
|
|
5774
|
+
2. Passing --entry <file> on the command line`
|
|
5775
|
+
);
|
|
5776
|
+
}
|
|
5622
5777
|
const candidates = ["index.ts", "src/index.ts", "server.ts", "src/server.ts"];
|
|
5623
5778
|
for (const candidate of candidates) {
|
|
5624
5779
|
try {
|
|
5625
|
-
await access(
|
|
5780
|
+
await access(path8.join(projectPath, candidate));
|
|
5626
5781
|
return candidate;
|
|
5627
5782
|
} catch {
|
|
5628
5783
|
continue;
|
|
5629
5784
|
}
|
|
5630
5785
|
}
|
|
5631
|
-
throw new Error(
|
|
5786
|
+
throw new Error(
|
|
5787
|
+
`No entry file found.
|
|
5788
|
+
|
|
5789
|
+
Expected one of: ${candidates.join(", ")}
|
|
5790
|
+
|
|
5791
|
+
Fix this by either:
|
|
5792
|
+
1. Creating one of the default entry files above, or
|
|
5793
|
+
2. Passing --entry <file> or --mcp-dir <dir> on the command line`
|
|
5794
|
+
);
|
|
5795
|
+
}
|
|
5796
|
+
function resolveWidgetsDir(cliWidgetsDir, mcpDir) {
|
|
5797
|
+
if (cliWidgetsDir) return cliWidgetsDir;
|
|
5798
|
+
if (mcpDir) return path8.join(mcpDir, "resources");
|
|
5799
|
+
return "resources";
|
|
5800
|
+
}
|
|
5801
|
+
function makeWidgetServerOnlyGuard(widgetName) {
|
|
5802
|
+
const rejected = /* @__PURE__ */ new Set([
|
|
5803
|
+
"server-only",
|
|
5804
|
+
"client-only",
|
|
5805
|
+
"next/cache",
|
|
5806
|
+
"next/headers",
|
|
5807
|
+
"next/navigation",
|
|
5808
|
+
"next/server"
|
|
5809
|
+
]);
|
|
5810
|
+
return {
|
|
5811
|
+
name: "mcp-use-widget-server-only-guard",
|
|
5812
|
+
enforce: "pre",
|
|
5813
|
+
resolveId(id, importer) {
|
|
5814
|
+
if (!rejected.has(id)) return null;
|
|
5815
|
+
const from = importer ? ` (imported from ${importer})` : "";
|
|
5816
|
+
throw new Error(
|
|
5817
|
+
`Widget "${widgetName}" imports "${id}"${from}, which is a Next.js server-only module. Widgets run in a browser iframe and cannot use server APIs.
|
|
5818
|
+
|
|
5819
|
+
To fix:
|
|
5820
|
+
\u2022 Remove the import from the widget (or from any module the widget transitively imports)
|
|
5821
|
+
\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`
|
|
5822
|
+
);
|
|
5823
|
+
}
|
|
5824
|
+
};
|
|
5825
|
+
}
|
|
5826
|
+
async function findServerFile(projectPath, cliEntry, cliMcpDir) {
|
|
5827
|
+
return resolveEntryFile(projectPath, cliEntry, cliMcpDir);
|
|
5632
5828
|
}
|
|
5633
5829
|
async function generateToolRegistryTypesForServer(projectPath, serverFileRelative) {
|
|
5634
|
-
const serverFile =
|
|
5830
|
+
const serverFile = path8.join(projectPath, serverFileRelative);
|
|
5635
5831
|
const serverFileExists = await access(serverFile).then(() => true).catch(() => false);
|
|
5636
5832
|
if (!serverFileExists) {
|
|
5637
5833
|
throw new Error(`Server file not found: ${serverFile}`);
|
|
@@ -5640,19 +5836,48 @@ async function generateToolRegistryTypesForServer(projectPath, serverFileRelativ
|
|
|
5640
5836
|
try {
|
|
5641
5837
|
globalThis.__mcpUseHmrMode = true;
|
|
5642
5838
|
globalThis.__mcpUseLastServer = void 0;
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5839
|
+
if (await detectNextJsProject(projectPath)) {
|
|
5840
|
+
await loadNextJsEnvFiles(projectPath);
|
|
5841
|
+
await registerNextShimsInProcess();
|
|
5842
|
+
}
|
|
5843
|
+
const projectTsconfigPath = path8.join(projectPath, "tsconfig.json");
|
|
5844
|
+
const hasTsconfig = await access(projectTsconfigPath).then(() => true).catch(() => false);
|
|
5845
|
+
if (hasTsconfig) {
|
|
5846
|
+
process.env.TSX_TSCONFIG_PATH = projectTsconfigPath;
|
|
5847
|
+
}
|
|
5848
|
+
const previousCwd = process.cwd();
|
|
5849
|
+
if (previousCwd !== projectPath) process.chdir(projectPath);
|
|
5850
|
+
try {
|
|
5851
|
+
const projectRequire = createRequire2(
|
|
5852
|
+
path8.join(projectPath, "package.json")
|
|
5853
|
+
);
|
|
5854
|
+
const tsxEsmApiPath = projectRequire.resolve("tsx/esm/api");
|
|
5855
|
+
const tsxEsmApi = await import(pathToFileURL2(tsxEsmApiPath).href);
|
|
5856
|
+
if (typeof tsxEsmApi.register === "function") {
|
|
5857
|
+
tsxEsmApi.register({
|
|
5858
|
+
tsconfig: hasTsconfig ? projectTsconfigPath : void 0
|
|
5859
|
+
});
|
|
5860
|
+
}
|
|
5861
|
+
try {
|
|
5862
|
+
const tsxCjsApiPath = projectRequire.resolve("tsx/cjs/api");
|
|
5863
|
+
const tsxCjsApi = await import(pathToFileURL2(tsxCjsApiPath).href);
|
|
5864
|
+
if (typeof tsxCjsApi.register === "function") {
|
|
5865
|
+
tsxCjsApi.register();
|
|
5866
|
+
}
|
|
5867
|
+
} catch {
|
|
5868
|
+
}
|
|
5869
|
+
await import(`${pathToFileURL2(serverFile).href}?t=${Date.now()}`);
|
|
5870
|
+
} finally {
|
|
5871
|
+
if (process.cwd() !== previousCwd) process.chdir(previousCwd);
|
|
5872
|
+
}
|
|
5648
5873
|
const server = globalThis.__mcpUseLastServer;
|
|
5649
5874
|
if (!server) {
|
|
5650
5875
|
throw new Error(
|
|
5651
5876
|
"No MCPServer instance found. Make sure your server file creates an MCPServer instance."
|
|
5652
5877
|
);
|
|
5653
5878
|
}
|
|
5654
|
-
const mcpUsePath =
|
|
5655
|
-
const { generateToolRegistryTypes } = await import(
|
|
5879
|
+
const mcpUsePath = path8.join(projectPath, "node_modules", "mcp-use");
|
|
5880
|
+
const { generateToolRegistryTypes } = await import(pathToFileURL2(path8.join(mcpUsePath, "dist", "src", "server", "index.js")).href).then((mod) => mod);
|
|
5656
5881
|
if (!generateToolRegistryTypes) {
|
|
5657
5882
|
throw new Error("generateToolRegistryTypes not found in mcp-use package");
|
|
5658
5883
|
}
|
|
@@ -5667,21 +5892,24 @@ async function generateToolRegistryTypesForServer(projectPath, serverFileRelativ
|
|
|
5667
5892
|
}
|
|
5668
5893
|
async function buildWidgets(projectPath, options = {}) {
|
|
5669
5894
|
const { inline = true } = options;
|
|
5670
|
-
const { promises:
|
|
5895
|
+
const { promises: fs11 } = await import("fs");
|
|
5671
5896
|
const { build } = await import("vite");
|
|
5672
|
-
const
|
|
5897
|
+
const widgetsDirRelative = options.widgetsDir ?? "resources";
|
|
5898
|
+
const resourcesDir = path8.resolve(projectPath, widgetsDirRelative);
|
|
5673
5899
|
const mcpUrl = process.env.MCP_URL;
|
|
5674
5900
|
try {
|
|
5675
5901
|
await access(resourcesDir);
|
|
5676
5902
|
} catch {
|
|
5677
5903
|
console.log(
|
|
5678
|
-
source_default.gray(
|
|
5904
|
+
source_default.gray(
|
|
5905
|
+
`No ${widgetsDirRelative}/ directory found - skipping widget build`
|
|
5906
|
+
)
|
|
5679
5907
|
);
|
|
5680
5908
|
return [];
|
|
5681
5909
|
}
|
|
5682
5910
|
const entries = [];
|
|
5683
5911
|
try {
|
|
5684
|
-
const files = await
|
|
5912
|
+
const files = await fs11.readdir(resourcesDir, { withFileTypes: true });
|
|
5685
5913
|
for (const dirent of files) {
|
|
5686
5914
|
if (dirent.name.startsWith("._") || dirent.name.startsWith(".DS_Store")) {
|
|
5687
5915
|
continue;
|
|
@@ -5689,12 +5917,12 @@ async function buildWidgets(projectPath, options = {}) {
|
|
|
5689
5917
|
if (dirent.isFile() && (dirent.name.endsWith(".tsx") || dirent.name.endsWith(".ts"))) {
|
|
5690
5918
|
entries.push({
|
|
5691
5919
|
name: dirent.name.replace(/\.tsx?$/, ""),
|
|
5692
|
-
path:
|
|
5920
|
+
path: path8.join(resourcesDir, dirent.name)
|
|
5693
5921
|
});
|
|
5694
5922
|
} else if (dirent.isDirectory()) {
|
|
5695
|
-
const widgetPath =
|
|
5923
|
+
const widgetPath = path8.join(resourcesDir, dirent.name, "widget.tsx");
|
|
5696
5924
|
try {
|
|
5697
|
-
await
|
|
5925
|
+
await fs11.access(widgetPath);
|
|
5698
5926
|
entries.push({
|
|
5699
5927
|
name: dirent.name,
|
|
5700
5928
|
path: widgetPath
|
|
@@ -5704,11 +5932,15 @@ async function buildWidgets(projectPath, options = {}) {
|
|
|
5704
5932
|
}
|
|
5705
5933
|
}
|
|
5706
5934
|
} catch (error) {
|
|
5707
|
-
console.log(
|
|
5935
|
+
console.log(
|
|
5936
|
+
source_default.gray(`No widgets found in ${widgetsDirRelative}/ directory`)
|
|
5937
|
+
);
|
|
5708
5938
|
return [];
|
|
5709
5939
|
}
|
|
5710
5940
|
if (entries.length === 0) {
|
|
5711
|
-
console.log(
|
|
5941
|
+
console.log(
|
|
5942
|
+
source_default.gray(`No widgets found in ${widgetsDirRelative}/ directory`)
|
|
5943
|
+
);
|
|
5712
5944
|
return [];
|
|
5713
5945
|
}
|
|
5714
5946
|
console.log(
|
|
@@ -5718,10 +5950,17 @@ async function buildWidgets(projectPath, options = {}) {
|
|
|
5718
5950
|
);
|
|
5719
5951
|
const react = (await import("@vitejs/plugin-react")).default;
|
|
5720
5952
|
const tailwindcss = (await import("@tailwindcss/vite")).default;
|
|
5721
|
-
const
|
|
5953
|
+
const projectTsconfigPath = path8.join(projectPath, "tsconfig.json");
|
|
5954
|
+
let hasProjectTsconfig = false;
|
|
5955
|
+
try {
|
|
5956
|
+
await access(projectTsconfigPath);
|
|
5957
|
+
hasProjectTsconfig = true;
|
|
5958
|
+
} catch {
|
|
5959
|
+
}
|
|
5960
|
+
const packageJsonPath = path8.join(projectPath, "package.json");
|
|
5722
5961
|
let favicon = "";
|
|
5723
5962
|
try {
|
|
5724
|
-
const pkgContent = await
|
|
5963
|
+
const pkgContent = await fs11.readFile(packageJsonPath, "utf-8");
|
|
5725
5964
|
const pkg = JSON.parse(pkgContent);
|
|
5726
5965
|
favicon = pkg.mcpUse?.favicon || "";
|
|
5727
5966
|
} catch {
|
|
@@ -5730,18 +5969,27 @@ async function buildWidgets(projectPath, options = {}) {
|
|
|
5730
5969
|
const widgetName = entry.name;
|
|
5731
5970
|
const entryPath = entry.path.replace(/\\/g, "/");
|
|
5732
5971
|
console.log(source_default.gray(` - Building ${widgetName}...`));
|
|
5733
|
-
const tempDir =
|
|
5734
|
-
await
|
|
5735
|
-
const relativeResourcesPath =
|
|
5736
|
-
const mcpUsePath =
|
|
5737
|
-
const relativeMcpUsePath =
|
|
5972
|
+
const tempDir = path8.join(projectPath, ".mcp-use", widgetName);
|
|
5973
|
+
await fs11.mkdir(tempDir, { recursive: true });
|
|
5974
|
+
const relativeResourcesPath = path8.relative(tempDir, resourcesDir).replace(/\\/g, "/");
|
|
5975
|
+
const mcpUsePath = path8.join(projectPath, "node_modules", "mcp-use");
|
|
5976
|
+
const relativeMcpUsePath = path8.relative(tempDir, mcpUsePath).replace(/\\/g, "/");
|
|
5977
|
+
const projectSrcDir = path8.join(projectPath, "src");
|
|
5978
|
+
let projectSrcSourceLine = "";
|
|
5979
|
+
try {
|
|
5980
|
+
await access(projectSrcDir);
|
|
5981
|
+
const relativeProjectSrcPath = path8.relative(tempDir, projectSrcDir).replace(/\\/g, "/");
|
|
5982
|
+
projectSrcSourceLine = `@source "${relativeProjectSrcPath}";
|
|
5983
|
+
`;
|
|
5984
|
+
} catch {
|
|
5985
|
+
}
|
|
5738
5986
|
const cssContent = `@import "tailwindcss";
|
|
5739
5987
|
|
|
5740
5988
|
/* Configure Tailwind to scan the resources directory and mcp-use package */
|
|
5741
5989
|
@source "${relativeResourcesPath}";
|
|
5742
5990
|
@source "${relativeMcpUsePath}/**/*.{ts,tsx,js,jsx}";
|
|
5743
|
-
`;
|
|
5744
|
-
await
|
|
5991
|
+
${projectSrcSourceLine}`;
|
|
5992
|
+
await fs11.writeFile(path8.join(tempDir, "styles.css"), cssContent, "utf8");
|
|
5745
5993
|
const entryContent = `import React from 'react'
|
|
5746
5994
|
import { createRoot } from 'react-dom/client'
|
|
5747
5995
|
import './styles.css'
|
|
@@ -5766,9 +6014,9 @@ if (container && Component) {
|
|
|
5766
6014
|
<script type="module" src="/entry.tsx"></script>
|
|
5767
6015
|
</body>
|
|
5768
6016
|
</html>`;
|
|
5769
|
-
await
|
|
5770
|
-
await
|
|
5771
|
-
const outDir =
|
|
6017
|
+
await fs11.writeFile(path8.join(tempDir, "entry.tsx"), entryContent, "utf8");
|
|
6018
|
+
await fs11.writeFile(path8.join(tempDir, "index.html"), htmlContent, "utf8");
|
|
6019
|
+
const outDir = path8.join(
|
|
5772
6020
|
projectPath,
|
|
5773
6021
|
"dist",
|
|
5774
6022
|
"resources",
|
|
@@ -5778,12 +6026,12 @@ if (container && Component) {
|
|
|
5778
6026
|
const baseUrl = mcpUrl ? `${mcpUrl}/${widgetName}/` : `/mcp-use/widgets/${widgetName}/`;
|
|
5779
6027
|
let widgetMetadata = {};
|
|
5780
6028
|
try {
|
|
5781
|
-
const metadataTempDir =
|
|
6029
|
+
const metadataTempDir = path8.join(
|
|
5782
6030
|
projectPath,
|
|
5783
6031
|
".mcp-use",
|
|
5784
6032
|
`${widgetName}-metadata`
|
|
5785
6033
|
);
|
|
5786
|
-
await
|
|
6034
|
+
await fs11.mkdir(metadataTempDir, { recursive: true });
|
|
5787
6035
|
const { createServer } = await import("vite");
|
|
5788
6036
|
const nodeStubsPlugin = {
|
|
5789
6037
|
name: "node-stubs",
|
|
@@ -5811,15 +6059,16 @@ export default PostHog;
|
|
|
5811
6059
|
return null;
|
|
5812
6060
|
}
|
|
5813
6061
|
};
|
|
6062
|
+
const serverOnlyGuard = makeWidgetServerOnlyGuard(widgetName);
|
|
5814
6063
|
const metadataServer = await createServer({
|
|
5815
6064
|
root: metadataTempDir,
|
|
5816
|
-
cacheDir:
|
|
5817
|
-
plugins: [nodeStubsPlugin, tailwindcss(), react()],
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
},
|
|
6065
|
+
cacheDir: path8.join(metadataTempDir, ".vite-cache"),
|
|
6066
|
+
plugins: [serverOnlyGuard, nodeStubsPlugin, tailwindcss(), react()],
|
|
6067
|
+
// When the project has a tsconfig, enable Vite's native tsconfig-paths
|
|
6068
|
+
// resolver so `@/*` (or any custom alias) resolves through the
|
|
6069
|
+
// project's own paths config. Without a tsconfig, fall back to the
|
|
6070
|
+
// legacy hardcoded alias.
|
|
6071
|
+
resolve: hasProjectTsconfig ? { tsconfigPaths: true } : { alias: { "@": resourcesDir } },
|
|
5823
6072
|
server: {
|
|
5824
6073
|
middlewareMode: true
|
|
5825
6074
|
},
|
|
@@ -5898,7 +6147,7 @@ export default PostHog;
|
|
|
5898
6147
|
} finally {
|
|
5899
6148
|
await metadataServer.close();
|
|
5900
6149
|
try {
|
|
5901
|
-
await
|
|
6150
|
+
await fs11.rm(metadataTempDir, { recursive: true, force: true });
|
|
5902
6151
|
} catch {
|
|
5903
6152
|
}
|
|
5904
6153
|
}
|
|
@@ -5993,12 +6242,14 @@ export default {
|
|
|
5993
6242
|
return null;
|
|
5994
6243
|
}
|
|
5995
6244
|
};
|
|
6245
|
+
const buildServerOnlyGuard = makeWidgetServerOnlyGuard(widgetName);
|
|
5996
6246
|
const buildPlugins = inline ? [
|
|
6247
|
+
buildServerOnlyGuard,
|
|
5997
6248
|
buildNodeStubsPlugin,
|
|
5998
6249
|
tailwindcss(),
|
|
5999
6250
|
react(),
|
|
6000
6251
|
viteSingleFile({ removeViteModuleLoader: true })
|
|
6001
|
-
] : [buildNodeStubsPlugin, tailwindcss(), react()];
|
|
6252
|
+
] : [buildServerOnlyGuard, buildNodeStubsPlugin, tailwindcss(), react()];
|
|
6002
6253
|
await build({
|
|
6003
6254
|
root: tempDir,
|
|
6004
6255
|
base: baseUrl,
|
|
@@ -6017,11 +6268,10 @@ export default {
|
|
|
6017
6268
|
}
|
|
6018
6269
|
}
|
|
6019
6270
|
},
|
|
6020
|
-
resolve
|
|
6021
|
-
|
|
6022
|
-
|
|
6023
|
-
|
|
6024
|
-
},
|
|
6271
|
+
// When a tsconfig exists, enable Vite's native `resolve.tsconfigPaths`
|
|
6272
|
+
// so the project's path aliases resolve naturally. Otherwise fall
|
|
6273
|
+
// back to the legacy `@` → resourcesDir alias.
|
|
6274
|
+
resolve: hasProjectTsconfig ? { tsconfigPaths: true } : { alias: { "@": resourcesDir } },
|
|
6025
6275
|
optimizeDeps: {
|
|
6026
6276
|
// Exclude Node.js-only packages from browser bundling
|
|
6027
6277
|
exclude: ["posthog-node"]
|
|
@@ -6043,7 +6293,7 @@ export default {
|
|
|
6043
6293
|
// Inline all assets under 100MB (effectively all)
|
|
6044
6294
|
} : {},
|
|
6045
6295
|
rolldownOptions: {
|
|
6046
|
-
input:
|
|
6296
|
+
input: path8.join(tempDir, "index.html"),
|
|
6047
6297
|
external: (id) => {
|
|
6048
6298
|
return false;
|
|
6049
6299
|
}
|
|
@@ -6051,12 +6301,12 @@ export default {
|
|
|
6051
6301
|
}
|
|
6052
6302
|
});
|
|
6053
6303
|
try {
|
|
6054
|
-
const assetsDir =
|
|
6055
|
-
const assetFiles = await
|
|
6304
|
+
const assetsDir = path8.join(outDir, "assets");
|
|
6305
|
+
const assetFiles = await fs11.readdir(assetsDir);
|
|
6056
6306
|
const jsFiles = assetFiles.filter((f) => f.endsWith(".js"));
|
|
6057
6307
|
for (const jsFile of jsFiles) {
|
|
6058
|
-
const jsPath =
|
|
6059
|
-
let content = await
|
|
6308
|
+
const jsPath = path8.join(assetsDir, jsFile);
|
|
6309
|
+
let content = await fs11.readFile(jsPath, "utf8");
|
|
6060
6310
|
const zodConfigPatterns = [
|
|
6061
6311
|
// Non-minified: export const globalConfig = {}
|
|
6062
6312
|
/export\s+const\s+globalConfig\s*=\s*\{\s*\}/g,
|
|
@@ -6075,7 +6325,7 @@ export default {
|
|
|
6075
6325
|
}
|
|
6076
6326
|
}
|
|
6077
6327
|
if (patched) {
|
|
6078
|
-
await
|
|
6328
|
+
await fs11.writeFile(jsPath, content, "utf8");
|
|
6079
6329
|
console.log(source_default.gray(` \u2192 Patched Zod JIT in ${jsFile}`));
|
|
6080
6330
|
}
|
|
6081
6331
|
}
|
|
@@ -6087,8 +6337,8 @@ export default {
|
|
|
6087
6337
|
const mcpServerUrl = process.env.MCP_SERVER_URL;
|
|
6088
6338
|
if (mcpServerUrl) {
|
|
6089
6339
|
try {
|
|
6090
|
-
const htmlPath =
|
|
6091
|
-
let html = await
|
|
6340
|
+
const htmlPath = path8.join(outDir, "index.html");
|
|
6341
|
+
let html = await fs11.readFile(htmlPath, "utf8");
|
|
6092
6342
|
const injectionScript = `<script>window.__getFile = (filename) => { return "${mcpUrl}/${widgetName}/"+filename }; window.__mcpPublicUrl = "${mcpServerUrl}/mcp-use/public"; window.__mcpPublicAssetsUrl = "${mcpUrl}/public";</script>`;
|
|
6093
6343
|
if (!html.includes("window.__mcpPublicUrl")) {
|
|
6094
6344
|
html = html.replace(
|
|
@@ -6109,7 +6359,7 @@ export default {
|
|
|
6109
6359
|
<base href="${mcpServerUrl}">`
|
|
6110
6360
|
);
|
|
6111
6361
|
}
|
|
6112
|
-
await
|
|
6362
|
+
await fs11.writeFile(htmlPath, html, "utf8");
|
|
6113
6363
|
console.log(
|
|
6114
6364
|
source_default.gray(` \u2192 Injected MCP_SERVER_URL into ${widgetName}`)
|
|
6115
6365
|
);
|
|
@@ -6123,22 +6373,32 @@ export default {
|
|
|
6123
6373
|
}
|
|
6124
6374
|
}
|
|
6125
6375
|
console.log(source_default.green(` \u2713 Built ${widgetName}`));
|
|
6126
|
-
return {
|
|
6376
|
+
return {
|
|
6377
|
+
status: "built",
|
|
6378
|
+
name: widgetName,
|
|
6379
|
+
metadata: widgetMetadata
|
|
6380
|
+
};
|
|
6127
6381
|
} catch (error) {
|
|
6128
6382
|
console.error(source_default.red(` \u2717 Failed to build ${widgetName}:`), error);
|
|
6129
|
-
return
|
|
6383
|
+
return { status: "failed", name: widgetName };
|
|
6130
6384
|
}
|
|
6131
6385
|
};
|
|
6132
6386
|
const buildResults = await Promise.all(
|
|
6133
6387
|
entries.map((entry) => buildSingleWidget(entry))
|
|
6134
6388
|
);
|
|
6135
|
-
const
|
|
6136
|
-
|
|
6389
|
+
const failed = buildResults.filter((r) => r.status === "failed");
|
|
6390
|
+
if (failed.length > 0) {
|
|
6391
|
+
const names = failed.map((f) => f.name).join(", ");
|
|
6392
|
+
throw new Error(
|
|
6393
|
+
`${failed.length} widget(s) failed to build: ${names}. See errors above.`
|
|
6394
|
+
);
|
|
6395
|
+
}
|
|
6396
|
+
return buildResults.flatMap(
|
|
6397
|
+
(r) => r.status === "built" ? [{ name: r.name, metadata: r.metadata }] : []
|
|
6137
6398
|
);
|
|
6138
|
-
return builtWidgets;
|
|
6139
6399
|
}
|
|
6140
6400
|
async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
|
|
6141
|
-
const { promises:
|
|
6401
|
+
const { promises: fs11 } = await import("fs");
|
|
6142
6402
|
const literalFiles = [];
|
|
6143
6403
|
const dirPrefixes = [];
|
|
6144
6404
|
for (const pattern of includePatterns) {
|
|
@@ -6153,7 +6413,7 @@ async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
|
|
|
6153
6413
|
for (const file of literalFiles) {
|
|
6154
6414
|
if (/\.tsx?$/.test(file) && !file.endsWith(".d.ts")) {
|
|
6155
6415
|
try {
|
|
6156
|
-
await access(
|
|
6416
|
+
await access(path8.join(projectPath, file));
|
|
6157
6417
|
files.push(file);
|
|
6158
6418
|
} catch {
|
|
6159
6419
|
}
|
|
@@ -6161,13 +6421,13 @@ async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
|
|
|
6161
6421
|
}
|
|
6162
6422
|
const excludeSet = new Set(excludePatterns.map((e) => e.replace(/\*+/g, "")));
|
|
6163
6423
|
for (const prefix of dirPrefixes) {
|
|
6164
|
-
const dirPath =
|
|
6424
|
+
const dirPath = path8.join(projectPath, prefix);
|
|
6165
6425
|
try {
|
|
6166
|
-
const entries = await
|
|
6426
|
+
const entries = await fs11.readdir(dirPath, { recursive: true });
|
|
6167
6427
|
for (const entry of entries) {
|
|
6168
6428
|
const entryStr = String(entry);
|
|
6169
|
-
const rel =
|
|
6170
|
-
if (/\.tsx?$/.test(entryStr) && !entryStr.endsWith(".d.ts") && !excludeSet.has(rel.split(
|
|
6429
|
+
const rel = path8.join(prefix, entryStr);
|
|
6430
|
+
if (/\.tsx?$/.test(entryStr) && !entryStr.endsWith(".d.ts") && !excludeSet.has(rel.split(path8.sep)[0])) {
|
|
6171
6431
|
files.push(rel);
|
|
6172
6432
|
}
|
|
6173
6433
|
}
|
|
@@ -6178,11 +6438,11 @@ async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
|
|
|
6178
6438
|
}
|
|
6179
6439
|
async function transpileWithEsbuild(projectPath) {
|
|
6180
6440
|
const esbuild = await import("esbuild");
|
|
6181
|
-
const { promises:
|
|
6182
|
-
const tsconfigPath =
|
|
6441
|
+
const { promises: fs11 } = await import("fs");
|
|
6442
|
+
const tsconfigPath = path8.join(projectPath, "tsconfig.json");
|
|
6183
6443
|
let tsconfig = {};
|
|
6184
6444
|
try {
|
|
6185
|
-
const raw = await
|
|
6445
|
+
const raw = await fs11.readFile(tsconfigPath, "utf-8");
|
|
6186
6446
|
tsconfig = JSON.parse(raw);
|
|
6187
6447
|
} catch {
|
|
6188
6448
|
}
|
|
@@ -6209,10 +6469,10 @@ async function transpileWithEsbuild(projectPath) {
|
|
|
6209
6469
|
const target = (compilerOptions.target || "ES2022").toLowerCase();
|
|
6210
6470
|
const moduleStr = (compilerOptions.module || "ESNext").toLowerCase();
|
|
6211
6471
|
const format = moduleStr.includes("commonjs") ? "cjs" : "esm";
|
|
6212
|
-
const outbase = compilerOptions.rootDir ?
|
|
6472
|
+
const outbase = compilerOptions.rootDir ? path8.resolve(projectPath, compilerOptions.rootDir) : projectPath;
|
|
6213
6473
|
await esbuild.build({
|
|
6214
|
-
entryPoints: files.map((f) =>
|
|
6215
|
-
outdir:
|
|
6474
|
+
entryPoints: files.map((f) => path8.join(projectPath, f)),
|
|
6475
|
+
outdir: path8.join(projectPath, outDir),
|
|
6216
6476
|
outbase,
|
|
6217
6477
|
bundle: false,
|
|
6218
6478
|
format,
|
|
@@ -6224,21 +6484,42 @@ async function transpileWithEsbuild(projectPath) {
|
|
|
6224
6484
|
logLevel: "warning"
|
|
6225
6485
|
});
|
|
6226
6486
|
}
|
|
6227
|
-
program.command("build").description("Build TypeScript and MCP UI widgets").option("-p, --path <path>", "Path to project directory", process.cwd()).option(
|
|
6487
|
+
program.command("build").description("Build TypeScript and MCP UI widgets").option("-p, --path <path>", "Path to project directory", process.cwd()).option(
|
|
6488
|
+
"--entry <file>",
|
|
6489
|
+
"Path to MCP server entry file (relative to project)"
|
|
6490
|
+
).option(
|
|
6491
|
+
"--widgets-dir <dir>",
|
|
6492
|
+
"Path to widgets directory (relative to project)"
|
|
6493
|
+
).option(
|
|
6494
|
+
"--mcp-dir <dir>",
|
|
6495
|
+
"Folder holding the MCP entry + resources (e.g. 'src/mcp' for Next.js apps)"
|
|
6496
|
+
).option("--with-inspector", "Include inspector in production build").option(
|
|
6228
6497
|
"--inline",
|
|
6229
6498
|
"Inline all JS/CSS into HTML (required for VS Code MCP Apps)"
|
|
6230
6499
|
).option("--no-inline", "Keep JS/CSS as separate files (default)").option("--no-typecheck", "Skip TypeScript type checking (faster builds)").action(async (options) => {
|
|
6231
6500
|
try {
|
|
6232
|
-
const projectPath =
|
|
6233
|
-
const { promises:
|
|
6501
|
+
const projectPath = path8.resolve(options.path);
|
|
6502
|
+
const { promises: fs11 } = await import("fs");
|
|
6234
6503
|
displayPackageVersions(projectPath);
|
|
6504
|
+
const mcpDir = options.mcpDir;
|
|
6505
|
+
const widgetsDir = resolveWidgetsDir(options.widgetsDir, mcpDir);
|
|
6235
6506
|
const builtWidgets = await buildWidgets(projectPath, {
|
|
6236
|
-
inline: options.inline ?? false
|
|
6507
|
+
inline: options.inline ?? false,
|
|
6508
|
+
widgetsDir
|
|
6237
6509
|
});
|
|
6238
6510
|
let sourceServerFile;
|
|
6239
6511
|
try {
|
|
6240
|
-
sourceServerFile = await findServerFile(
|
|
6241
|
-
|
|
6512
|
+
sourceServerFile = await findServerFile(
|
|
6513
|
+
projectPath,
|
|
6514
|
+
options.entry,
|
|
6515
|
+
options.mcpDir
|
|
6516
|
+
);
|
|
6517
|
+
} catch (err) {
|
|
6518
|
+
console.log(
|
|
6519
|
+
source_default.yellow(
|
|
6520
|
+
`\u26A0 Could not locate a server entry file: ${err instanceof Error ? err.message : String(err)}`
|
|
6521
|
+
)
|
|
6522
|
+
);
|
|
6242
6523
|
}
|
|
6243
6524
|
if (sourceServerFile) {
|
|
6244
6525
|
console.log(source_default.gray("Generating tool registry types..."));
|
|
@@ -6256,17 +6537,25 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
6256
6537
|
);
|
|
6257
6538
|
}
|
|
6258
6539
|
}
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
|
|
6540
|
+
if (!mcpDir) {
|
|
6541
|
+
console.log(source_default.gray("Building TypeScript..."));
|
|
6542
|
+
await transpileWithEsbuild(projectPath);
|
|
6543
|
+
console.log(source_default.green("\u2713 TypeScript build complete!"));
|
|
6544
|
+
} else {
|
|
6545
|
+
console.log(
|
|
6546
|
+
source_default.gray(
|
|
6547
|
+
"Skipping TypeScript transpile (--mcp-dir mode runs source via tsx at start time)"
|
|
6548
|
+
)
|
|
6549
|
+
);
|
|
6550
|
+
}
|
|
6551
|
+
if (options.typecheck !== false && !mcpDir) {
|
|
6263
6552
|
console.log(source_default.gray("Type checking..."));
|
|
6264
6553
|
try {
|
|
6265
6554
|
await runCommand(
|
|
6266
6555
|
"node",
|
|
6267
6556
|
[
|
|
6268
6557
|
"--max-old-space-size=4096",
|
|
6269
|
-
|
|
6558
|
+
path8.join(
|
|
6270
6559
|
projectPath,
|
|
6271
6560
|
"node_modules",
|
|
6272
6561
|
"typescript",
|
|
@@ -6287,39 +6576,43 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
6287
6576
|
}
|
|
6288
6577
|
let entryPoint;
|
|
6289
6578
|
if (sourceServerFile) {
|
|
6290
|
-
|
|
6291
|
-
|
|
6292
|
-
|
|
6293
|
-
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
|
|
6297
|
-
|
|
6298
|
-
|
|
6299
|
-
|
|
6300
|
-
|
|
6301
|
-
|
|
6302
|
-
|
|
6303
|
-
|
|
6304
|
-
|
|
6305
|
-
|
|
6579
|
+
if (mcpDir) {
|
|
6580
|
+
entryPoint = sourceServerFile;
|
|
6581
|
+
} else {
|
|
6582
|
+
const baseName = path8.basename(sourceServerFile, ".ts") + ".js";
|
|
6583
|
+
const possibleOutputs = [
|
|
6584
|
+
`dist/${baseName}`,
|
|
6585
|
+
// rootDir set to project root or src
|
|
6586
|
+
`dist/src/${baseName}`,
|
|
6587
|
+
// no rootDir, source in src/
|
|
6588
|
+
`dist/${sourceServerFile.replace(/\.ts$/, ".js")}`
|
|
6589
|
+
// exact path preserved
|
|
6590
|
+
];
|
|
6591
|
+
for (const candidate of possibleOutputs) {
|
|
6592
|
+
try {
|
|
6593
|
+
await access(path8.join(projectPath, candidate));
|
|
6594
|
+
entryPoint = candidate;
|
|
6595
|
+
break;
|
|
6596
|
+
} catch {
|
|
6597
|
+
continue;
|
|
6598
|
+
}
|
|
6306
6599
|
}
|
|
6307
6600
|
}
|
|
6308
6601
|
}
|
|
6309
|
-
const publicDir =
|
|
6602
|
+
const publicDir = path8.join(projectPath, "public");
|
|
6310
6603
|
try {
|
|
6311
|
-
await
|
|
6604
|
+
await fs11.access(publicDir);
|
|
6312
6605
|
console.log(source_default.gray("Copying public assets..."));
|
|
6313
|
-
await
|
|
6606
|
+
await fs11.cp(publicDir, path8.join(projectPath, "dist", "public"), {
|
|
6314
6607
|
recursive: true
|
|
6315
6608
|
});
|
|
6316
6609
|
console.log(source_default.green("\u2713 Public assets copied"));
|
|
6317
6610
|
} catch {
|
|
6318
6611
|
}
|
|
6319
|
-
const manifestPath =
|
|
6612
|
+
const manifestPath = path8.join(projectPath, "dist", "mcp-use.json");
|
|
6320
6613
|
let existingManifest = {};
|
|
6321
6614
|
try {
|
|
6322
|
-
const existingContent = await
|
|
6615
|
+
const existingContent = await fs11.readFile(manifestPath, "utf-8");
|
|
6323
6616
|
existingManifest = JSON.parse(existingContent);
|
|
6324
6617
|
} catch {
|
|
6325
6618
|
}
|
|
@@ -6341,8 +6634,8 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
6341
6634
|
// Server entry point for `mcp-use start`
|
|
6342
6635
|
widgets: widgetsData
|
|
6343
6636
|
};
|
|
6344
|
-
await
|
|
6345
|
-
await
|
|
6637
|
+
await fs11.mkdir(path8.dirname(manifestPath), { recursive: true });
|
|
6638
|
+
await fs11.writeFile(
|
|
6346
6639
|
manifestPath,
|
|
6347
6640
|
JSON.stringify(manifest, null, 2),
|
|
6348
6641
|
"utf8"
|
|
@@ -6362,14 +6655,23 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
6362
6655
|
process.exit(1);
|
|
6363
6656
|
}
|
|
6364
6657
|
});
|
|
6365
|
-
program.command("dev").description("Run development server with auto-reload and inspector").option("-p, --path <path>", "Path to project directory", process.cwd()).option(
|
|
6658
|
+
program.command("dev").description("Run development server with auto-reload and inspector").option("-p, --path <path>", "Path to project directory", process.cwd()).option(
|
|
6659
|
+
"--entry <file>",
|
|
6660
|
+
"Path to MCP server entry file (relative to project)"
|
|
6661
|
+
).option(
|
|
6662
|
+
"--widgets-dir <dir>",
|
|
6663
|
+
"Path to widgets directory (relative to project)"
|
|
6664
|
+
).option(
|
|
6665
|
+
"--mcp-dir <dir>",
|
|
6666
|
+
"Folder holding the MCP entry + resources (e.g. 'src/mcp' for Next.js apps)"
|
|
6667
|
+
).option("--port <port>", "Server port", "3000").option(
|
|
6366
6668
|
"--host <host>",
|
|
6367
6669
|
"Server host (use 0.0.0.0 to listen on all interfaces)",
|
|
6368
6670
|
"0.0.0.0"
|
|
6369
6671
|
).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
6672
|
try {
|
|
6371
6673
|
process.env.MCP_USE_CLI_DEV = "1";
|
|
6372
|
-
const projectPath =
|
|
6674
|
+
const projectPath = path8.resolve(options.path);
|
|
6373
6675
|
let port = parseInt(options.port, 10);
|
|
6374
6676
|
const host = options.host;
|
|
6375
6677
|
const useHmr = options.hmr !== false;
|
|
@@ -6380,13 +6682,24 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6380
6682
|
console.log(source_default.green.bold(`\u2713 Using port ${availablePort} instead`));
|
|
6381
6683
|
port = availablePort;
|
|
6382
6684
|
}
|
|
6383
|
-
const serverFile = await findServerFile(
|
|
6685
|
+
const serverFile = await findServerFile(
|
|
6686
|
+
projectPath,
|
|
6687
|
+
options.entry,
|
|
6688
|
+
options.mcpDir
|
|
6689
|
+
);
|
|
6690
|
+
{
|
|
6691
|
+
const devMcpDir = options.mcpDir;
|
|
6692
|
+
const devWidgetsDir = resolveWidgetsDir(options.widgetsDir, devMcpDir);
|
|
6693
|
+
if (devWidgetsDir !== "resources") {
|
|
6694
|
+
process.env.MCP_USE_WIDGETS_DIR = devWidgetsDir;
|
|
6695
|
+
}
|
|
6696
|
+
}
|
|
6384
6697
|
let tunnelProcess = void 0;
|
|
6385
6698
|
let tunnelSubdomain = void 0;
|
|
6386
6699
|
let tunnelUrl = void 0;
|
|
6387
6700
|
if (options.tunnel) {
|
|
6388
6701
|
try {
|
|
6389
|
-
const manifestPath =
|
|
6702
|
+
const manifestPath = path8.join(projectPath, "dist", "mcp-use.json");
|
|
6390
6703
|
let existingSubdomain;
|
|
6391
6704
|
try {
|
|
6392
6705
|
const manifestContent = await readFile3(manifestPath, "utf-8");
|
|
@@ -6435,7 +6748,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6435
6748
|
manifest.tunnel = {};
|
|
6436
6749
|
}
|
|
6437
6750
|
manifest.tunnel.subdomain = tunnelSubdomain;
|
|
6438
|
-
await mkdir3(
|
|
6751
|
+
await mkdir3(path8.dirname(manifestPath), { recursive: true });
|
|
6439
6752
|
await writeFile3(
|
|
6440
6753
|
manifestPath,
|
|
6441
6754
|
JSON.stringify(manifest, null, 2),
|
|
@@ -6462,22 +6775,35 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6462
6775
|
} else if (!process.env.MCP_URL) {
|
|
6463
6776
|
process.env.MCP_URL = mcpUrl;
|
|
6464
6777
|
}
|
|
6778
|
+
const isNextJsProject = await detectNextJsProject(projectPath);
|
|
6779
|
+
if (isNextJsProject) {
|
|
6780
|
+
console.log(
|
|
6781
|
+
source_default.gray(
|
|
6782
|
+
"Next.js detected \u2014 installing server-runtime shims (server-only, next/cache, next/headers, next/navigation, next/server)"
|
|
6783
|
+
)
|
|
6784
|
+
);
|
|
6785
|
+
await loadNextJsEnvFiles(projectPath);
|
|
6786
|
+
}
|
|
6465
6787
|
if (!useHmr) {
|
|
6466
6788
|
console.log(source_default.gray("HMR disabled, using tsx watch (full restart)"));
|
|
6467
6789
|
const processes = [];
|
|
6468
|
-
const
|
|
6790
|
+
const baseEnv = {
|
|
6791
|
+
// Inherit parent env (PATH, HOME, etc.) — without it, tsx can't
|
|
6792
|
+
// resolve its own tooling in some setups.
|
|
6793
|
+
...process.env,
|
|
6469
6794
|
PORT: String(port),
|
|
6470
6795
|
HOST: host,
|
|
6471
6796
|
NODE_ENV: "development",
|
|
6472
6797
|
// Preserve user-provided MCP_URL (e.g., for reverse proxy setups)
|
|
6473
6798
|
MCP_URL: process.env.MCP_URL || mcpUrl
|
|
6474
6799
|
};
|
|
6800
|
+
const env2 = isNextJsProject ? withNextShimsEnv(baseEnv) : baseEnv;
|
|
6475
6801
|
const { createRequire: createRequire4 } = await import("module");
|
|
6476
6802
|
let cmd;
|
|
6477
6803
|
let args;
|
|
6478
6804
|
try {
|
|
6479
6805
|
const projectRequire = createRequire4(
|
|
6480
|
-
|
|
6806
|
+
path8.join(projectPath, "package.json")
|
|
6481
6807
|
);
|
|
6482
6808
|
const tsxPkgPath = projectRequire.resolve("tsx/package.json");
|
|
6483
6809
|
const tsxPkg = JSON.parse(await readFile3(tsxPkgPath, "utf-8"));
|
|
@@ -6489,7 +6815,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6489
6815
|
} else {
|
|
6490
6816
|
throw new Error("No bin field found in tsx package.json");
|
|
6491
6817
|
}
|
|
6492
|
-
const tsxBin =
|
|
6818
|
+
const tsxBin = path8.resolve(path8.dirname(tsxPkgPath), binPath);
|
|
6493
6819
|
cmd = "node";
|
|
6494
6820
|
args = [tsxBin, "watch", serverFile];
|
|
6495
6821
|
} catch (error) {
|
|
@@ -6564,18 +6890,56 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6564
6890
|
"HMR enabled - changes will hot reload without dropping connections"
|
|
6565
6891
|
)
|
|
6566
6892
|
);
|
|
6893
|
+
if (isNextJsProject) {
|
|
6894
|
+
const registered = await registerNextShimsInProcess();
|
|
6895
|
+
if (!registered) {
|
|
6896
|
+
console.warn(
|
|
6897
|
+
source_default.yellow(
|
|
6898
|
+
"[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."
|
|
6899
|
+
)
|
|
6900
|
+
);
|
|
6901
|
+
}
|
|
6902
|
+
}
|
|
6567
6903
|
const chokidarModule = await import("chokidar");
|
|
6568
6904
|
const chokidar = chokidarModule.default || chokidarModule;
|
|
6569
|
-
const { fileURLToPath:
|
|
6905
|
+
const { fileURLToPath: fileURLToPath4 } = await import("url");
|
|
6570
6906
|
const { createRequire: createRequire3 } = await import("module");
|
|
6571
|
-
|
|
6907
|
+
const projectTsconfigPath = path8.join(projectPath, "tsconfig.json");
|
|
6908
|
+
let tsconfigAvailable = false;
|
|
6909
|
+
try {
|
|
6910
|
+
await access(projectTsconfigPath);
|
|
6911
|
+
tsconfigAvailable = true;
|
|
6912
|
+
process.env.TSX_TSCONFIG_PATH = projectTsconfigPath;
|
|
6913
|
+
if (process.cwd() !== projectPath) process.chdir(projectPath);
|
|
6914
|
+
} catch {
|
|
6915
|
+
}
|
|
6916
|
+
let tsxLoaderActive = false;
|
|
6572
6917
|
try {
|
|
6573
6918
|
const projectRequire = createRequire3(
|
|
6574
|
-
|
|
6919
|
+
path8.join(projectPath, "package.json")
|
|
6575
6920
|
);
|
|
6576
|
-
const
|
|
6577
|
-
const
|
|
6578
|
-
|
|
6921
|
+
const tsxEsmApiPath = projectRequire.resolve("tsx/esm/api");
|
|
6922
|
+
const tsxEsmApi = await import(pathToFileURL2(tsxEsmApiPath).href);
|
|
6923
|
+
if (typeof tsxEsmApi.register === "function") {
|
|
6924
|
+
tsxEsmApi.register({
|
|
6925
|
+
tsconfig: tsconfigAvailable ? projectTsconfigPath : void 0,
|
|
6926
|
+
onImport: (url) => {
|
|
6927
|
+
const filePath = url.startsWith("file://") ? fileURLToPath4(url) : url;
|
|
6928
|
+
if (!filePath.includes("node_modules") && filePath.startsWith(projectPath)) {
|
|
6929
|
+
console.debug(`[HMR] Loaded: ${url}`);
|
|
6930
|
+
}
|
|
6931
|
+
}
|
|
6932
|
+
});
|
|
6933
|
+
tsxLoaderActive = true;
|
|
6934
|
+
}
|
|
6935
|
+
try {
|
|
6936
|
+
const tsxCjsApiPath = projectRequire.resolve("tsx/cjs/api");
|
|
6937
|
+
const tsxCjsApi = await import(pathToFileURL2(tsxCjsApiPath).href);
|
|
6938
|
+
if (typeof tsxCjsApi.register === "function") {
|
|
6939
|
+
tsxCjsApi.register();
|
|
6940
|
+
}
|
|
6941
|
+
} catch {
|
|
6942
|
+
}
|
|
6579
6943
|
} catch {
|
|
6580
6944
|
console.log(
|
|
6581
6945
|
source_default.yellow(
|
|
@@ -6583,25 +6947,15 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6583
6947
|
)
|
|
6584
6948
|
);
|
|
6585
6949
|
}
|
|
6586
|
-
const serverFilePath =
|
|
6587
|
-
const serverFileUrl =
|
|
6950
|
+
const serverFilePath = path8.join(projectPath, serverFile);
|
|
6951
|
+
const serverFileUrl = pathToFileURL2(serverFilePath).href;
|
|
6588
6952
|
globalThis.__mcpUseHmrMode = true;
|
|
6589
6953
|
const importServerModule = async () => {
|
|
6590
6954
|
const previousServer = globalThis.__mcpUseLastServer;
|
|
6591
6955
|
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()}`);
|
|
6956
|
+
if (!tsxLoaderActive) {
|
|
6604
6957
|
}
|
|
6958
|
+
await import(`${serverFileUrl}?t=${Date.now()}`);
|
|
6605
6959
|
const instance = globalThis.__mcpUseLastServer;
|
|
6606
6960
|
if (!instance) {
|
|
6607
6961
|
globalThis.__mcpUseLastServer = previousServer;
|
|
@@ -6615,7 +6969,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6615
6969
|
if (instance === previousServer) {
|
|
6616
6970
|
console.warn(
|
|
6617
6971
|
source_default.yellow(
|
|
6618
|
-
"[HMR] Warning: Module re-import returned the same server instance. The module may not have been re-evaluated. " + (!
|
|
6972
|
+
"[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
6973
|
)
|
|
6620
6974
|
);
|
|
6621
6975
|
return null;
|
|
@@ -6690,8 +7044,8 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6690
7044
|
}
|
|
6691
7045
|
let watcher = chokidar.watch(".", {
|
|
6692
7046
|
cwd: projectPath,
|
|
6693
|
-
ignored: (
|
|
6694
|
-
const normalizedPath =
|
|
7047
|
+
ignored: (path9, stats) => {
|
|
7048
|
+
const normalizedPath = path9.replace(/\\/g, "/");
|
|
6695
7049
|
if (/(^|\/)\.[^/]/.test(normalizedPath)) {
|
|
6696
7050
|
return true;
|
|
6697
7051
|
}
|
|
@@ -6865,7 +7219,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6865
7219
|
}
|
|
6866
7220
|
tunnelUrl = void 0;
|
|
6867
7221
|
if (withTunnel) {
|
|
6868
|
-
const manifestPath =
|
|
7222
|
+
const manifestPath = path8.join(projectPath, "dist", "mcp-use.json");
|
|
6869
7223
|
let existingSubdomain;
|
|
6870
7224
|
try {
|
|
6871
7225
|
const manifestContent = await readFile3(manifestPath, "utf-8");
|
|
@@ -6902,7 +7256,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6902
7256
|
tunnelSubdomain = tunnelInfo.subdomain;
|
|
6903
7257
|
process.env.MCP_URL = tunnelUrl;
|
|
6904
7258
|
try {
|
|
6905
|
-
const mPath =
|
|
7259
|
+
const mPath = path8.join(projectPath, "dist", "mcp-use.json");
|
|
6906
7260
|
let manifest = {};
|
|
6907
7261
|
try {
|
|
6908
7262
|
manifest = JSON.parse(await readFile3(mPath, "utf-8"));
|
|
@@ -6910,7 +7264,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6910
7264
|
}
|
|
6911
7265
|
if (!manifest.tunnel) manifest.tunnel = {};
|
|
6912
7266
|
manifest.tunnel.subdomain = tunnelSubdomain;
|
|
6913
|
-
await mkdir3(
|
|
7267
|
+
await mkdir3(path8.dirname(mPath), { recursive: true });
|
|
6914
7268
|
await writeFile3(mPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
6915
7269
|
} catch {
|
|
6916
7270
|
}
|
|
@@ -7006,9 +7360,15 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
7006
7360
|
process.exit(1);
|
|
7007
7361
|
}
|
|
7008
7362
|
});
|
|
7009
|
-
program.command("start").description("Start production server").option("-p, --path <path>", "Path to project directory", process.cwd()).option(
|
|
7363
|
+
program.command("start").description("Start production server").option("-p, --path <path>", "Path to project directory", process.cwd()).option(
|
|
7364
|
+
"--entry <file>",
|
|
7365
|
+
"Path to MCP server entry file (relative to project)"
|
|
7366
|
+
).option(
|
|
7367
|
+
"--mcp-dir <dir>",
|
|
7368
|
+
"Folder holding the MCP entry + resources (e.g. 'src/mcp' for Next.js apps)"
|
|
7369
|
+
).option("--port <port>", "Server port", "3000").option("--tunnel", "Expose server through a tunnel").action(async (options) => {
|
|
7010
7370
|
try {
|
|
7011
|
-
const projectPath =
|
|
7371
|
+
const projectPath = path8.resolve(options.path);
|
|
7012
7372
|
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
7373
|
let port = portFlagProvided ? parseInt(options.port, 10) : parseInt(process.env.PORT || options.port || "3000", 10);
|
|
7014
7374
|
if (!await isPortAvailable(port)) {
|
|
@@ -7026,7 +7386,7 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
7026
7386
|
let tunnelSubdomain = void 0;
|
|
7027
7387
|
if (options.tunnel) {
|
|
7028
7388
|
try {
|
|
7029
|
-
const manifestPath2 =
|
|
7389
|
+
const manifestPath2 = path8.join(projectPath, "dist", "mcp-use.json");
|
|
7030
7390
|
let existingSubdomain;
|
|
7031
7391
|
try {
|
|
7032
7392
|
const manifestContent = await readFile3(manifestPath2, "utf-8");
|
|
@@ -7081,7 +7441,7 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
7081
7441
|
manifest.tunnel = {};
|
|
7082
7442
|
}
|
|
7083
7443
|
manifest.tunnel.subdomain = subdomain;
|
|
7084
|
-
await mkdir3(
|
|
7444
|
+
await mkdir3(path8.dirname(manifestPath2), { recursive: true });
|
|
7085
7445
|
await writeFile3(
|
|
7086
7446
|
manifestPath2,
|
|
7087
7447
|
JSON.stringify(manifest, null, 2),
|
|
@@ -7100,18 +7460,25 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
7100
7460
|
}
|
|
7101
7461
|
}
|
|
7102
7462
|
let serverFile;
|
|
7103
|
-
const manifestPath =
|
|
7463
|
+
const manifestPath = path8.join(projectPath, "dist", "mcp-use.json");
|
|
7104
7464
|
try {
|
|
7105
7465
|
const manifestContent = await readFile3(manifestPath, "utf-8");
|
|
7106
7466
|
const manifest = JSON.parse(manifestContent);
|
|
7107
7467
|
if (manifest.entryPoint) {
|
|
7108
|
-
await access(
|
|
7468
|
+
await access(path8.join(projectPath, manifest.entryPoint));
|
|
7109
7469
|
serverFile = manifest.entryPoint;
|
|
7110
7470
|
}
|
|
7111
7471
|
} catch {
|
|
7112
7472
|
}
|
|
7113
7473
|
if (!serverFile) {
|
|
7474
|
+
const startMcpDir = options.mcpDir;
|
|
7114
7475
|
const serverCandidates = [
|
|
7476
|
+
...startMcpDir ? [
|
|
7477
|
+
`${startMcpDir}/index.ts`,
|
|
7478
|
+
`${startMcpDir}/index.tsx`,
|
|
7479
|
+
`dist/${startMcpDir}/index.js`,
|
|
7480
|
+
`dist/${startMcpDir}/server.js`
|
|
7481
|
+
] : [],
|
|
7115
7482
|
"dist/index.js",
|
|
7116
7483
|
"dist/server.js",
|
|
7117
7484
|
"dist/src/index.js",
|
|
@@ -7119,7 +7486,7 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
7119
7486
|
];
|
|
7120
7487
|
for (const candidate of serverCandidates) {
|
|
7121
7488
|
try {
|
|
7122
|
-
await access(
|
|
7489
|
+
await access(path8.join(projectPath, candidate));
|
|
7123
7490
|
serverFile = candidate;
|
|
7124
7491
|
break;
|
|
7125
7492
|
} catch {
|
|
@@ -7143,18 +7510,53 @@ Looked for:
|
|
|
7143
7510
|
process.exit(1);
|
|
7144
7511
|
}
|
|
7145
7512
|
console.log("Starting production server...");
|
|
7146
|
-
const
|
|
7513
|
+
const isNextJsProject = await detectNextJsProject(projectPath);
|
|
7514
|
+
if (isNextJsProject) {
|
|
7515
|
+
console.log(
|
|
7516
|
+
source_default.gray(
|
|
7517
|
+
"Next.js detected \u2014 installing server-runtime shims for the production server"
|
|
7518
|
+
)
|
|
7519
|
+
);
|
|
7520
|
+
await loadNextJsEnvFiles(projectPath);
|
|
7521
|
+
}
|
|
7522
|
+
const baseEnv = {
|
|
7147
7523
|
...process.env,
|
|
7148
7524
|
PORT: String(port),
|
|
7149
7525
|
NODE_ENV: "production"
|
|
7150
7526
|
};
|
|
7151
7527
|
if (mcpUrl) {
|
|
7152
|
-
|
|
7528
|
+
baseEnv.MCP_URL = mcpUrl;
|
|
7153
7529
|
console.log(source_default.whiteBright(`Tunnel: ${mcpUrl}/mcp`));
|
|
7154
|
-
} else if (!
|
|
7155
|
-
|
|
7530
|
+
} else if (!baseEnv.MCP_URL) {
|
|
7531
|
+
baseEnv.MCP_URL = `http://localhost:${port}`;
|
|
7532
|
+
}
|
|
7533
|
+
const env2 = isNextJsProject ? withNextShimsEnv(baseEnv) : baseEnv;
|
|
7534
|
+
const isTsEntry = /\.(ts|tsx|mts|cts)$/.test(serverFile);
|
|
7535
|
+
let spawnCmd = "node";
|
|
7536
|
+
let spawnArgs = [serverFile];
|
|
7537
|
+
if (isTsEntry) {
|
|
7538
|
+
try {
|
|
7539
|
+
const projectRequire = createRequire2(
|
|
7540
|
+
path8.join(projectPath, "package.json")
|
|
7541
|
+
);
|
|
7542
|
+
const tsxPkgPath = projectRequire.resolve("tsx/package.json");
|
|
7543
|
+
const tsxPkg = JSON.parse(await readFile3(tsxPkgPath, "utf-8"));
|
|
7544
|
+
const binField = typeof tsxPkg.bin === "string" ? tsxPkg.bin : tsxPkg.bin?.tsx ?? Object.values(tsxPkg.bin ?? {})[0];
|
|
7545
|
+
if (!binField) throw new Error("tsx bin entry not found");
|
|
7546
|
+
const tsxBin = path8.resolve(path8.dirname(tsxPkgPath), binField);
|
|
7547
|
+
spawnCmd = "node";
|
|
7548
|
+
spawnArgs = [tsxBin, serverFile];
|
|
7549
|
+
} catch (error) {
|
|
7550
|
+
console.log(
|
|
7551
|
+
source_default.yellow(
|
|
7552
|
+
`Could not resolve local tsx (${error instanceof Error ? error.message : String(error)}); falling back to npx`
|
|
7553
|
+
)
|
|
7554
|
+
);
|
|
7555
|
+
spawnCmd = "npx";
|
|
7556
|
+
spawnArgs = ["tsx", serverFile];
|
|
7557
|
+
}
|
|
7156
7558
|
}
|
|
7157
|
-
const serverProc = spawn(
|
|
7559
|
+
const serverProc = spawn(spawnCmd, spawnArgs, {
|
|
7158
7560
|
cwd: projectPath,
|
|
7159
7561
|
stdio: "inherit",
|
|
7160
7562
|
env: env2
|
|
@@ -7290,7 +7692,7 @@ program.addCommand(createSkillsCommand());
|
|
|
7290
7692
|
program.command("generate-types").description(
|
|
7291
7693
|
"Generate TypeScript type definitions for tools (writes .mcp-use/tool-registry.d.ts)"
|
|
7292
7694
|
).option("-p, --path <path>", "Path to project directory", process.cwd()).option("--server <file>", "Server entry file", "index.ts").action(async (options) => {
|
|
7293
|
-
const projectPath =
|
|
7695
|
+
const projectPath = path8.resolve(options.path);
|
|
7294
7696
|
try {
|
|
7295
7697
|
console.log(source_default.blue("Generating tool registry types..."));
|
|
7296
7698
|
const success = await generateToolRegistryTypesForServer(
|