@mcp-use/cli 3.1.0-canary.1 → 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/README.md +3 -0
- package/dist/commands/auth.d.ts +6 -0
- package/dist/commands/auth.d.ts.map +1 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/servers.d.ts.map +1 -1
- package/dist/index.cjs +594 -198
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +589 -193
- 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(
|
|
@@ -1569,6 +1569,14 @@ async function pollForDeviceToken(authBaseUrl, deviceCode, intervalSeconds) {
|
|
|
1569
1569
|
}
|
|
1570
1570
|
throw new Error("Login timed out. Please try again.");
|
|
1571
1571
|
}
|
|
1572
|
+
function resolveOrgFromOption(orgs, identifier) {
|
|
1573
|
+
const needle = identifier.trim();
|
|
1574
|
+
if (!needle) return null;
|
|
1575
|
+
const lower = needle.toLowerCase();
|
|
1576
|
+
return orgs.find(
|
|
1577
|
+
(o) => o.slug === needle || o.id === needle || o.name.toLowerCase() === lower
|
|
1578
|
+
) ?? null;
|
|
1579
|
+
}
|
|
1572
1580
|
async function promptOrgSelection(orgs, defaultOrgId) {
|
|
1573
1581
|
if (orgs.length === 0) return null;
|
|
1574
1582
|
if (orgs.length === 1) {
|
|
@@ -1615,8 +1623,8 @@ async function loginCommand(options) {
|
|
|
1615
1623
|
console.log(source_default.green.bold("\u2713 API key saved."));
|
|
1616
1624
|
try {
|
|
1617
1625
|
const api2 = await McpUseAPI.create();
|
|
1618
|
-
const
|
|
1619
|
-
console.log(source_default.gray(` Authenticated as ${
|
|
1626
|
+
const authInfo2 = await api2.testAuth();
|
|
1627
|
+
console.log(source_default.gray(` Authenticated as ${authInfo2.email}`));
|
|
1620
1628
|
} catch {
|
|
1621
1629
|
console.log(
|
|
1622
1630
|
source_default.gray(
|
|
@@ -1668,9 +1676,19 @@ async function loginCommand(options) {
|
|
|
1668
1676
|
const keyResp = await api.createApiKeyWithAccessToken(accessToken, "CLI");
|
|
1669
1677
|
await writeConfig({ apiKey: keyResp.key });
|
|
1670
1678
|
console.log(source_default.green.bold("\n\u2713 Successfully logged in!"));
|
|
1679
|
+
let authInfo = null;
|
|
1671
1680
|
try {
|
|
1672
1681
|
const freshApi = await McpUseAPI.create();
|
|
1673
|
-
|
|
1682
|
+
authInfo = await freshApi.testAuth();
|
|
1683
|
+
} catch {
|
|
1684
|
+
console.log(
|
|
1685
|
+
source_default.gray(
|
|
1686
|
+
`
|
|
1687
|
+
Your API key has been saved to ${source_default.white("~/.mcp-use/config.json")}`
|
|
1688
|
+
)
|
|
1689
|
+
);
|
|
1690
|
+
}
|
|
1691
|
+
if (authInfo) {
|
|
1674
1692
|
console.log(source_default.cyan.bold("\nCurrent user:\n"));
|
|
1675
1693
|
console.log(source_default.white(" Email: ") + source_default.cyan(authInfo.email));
|
|
1676
1694
|
console.log(source_default.white(" User ID: ") + source_default.gray(authInfo.user_id));
|
|
@@ -1682,8 +1700,19 @@ async function loginCommand(options) {
|
|
|
1682
1700
|
const orgs = authInfo.orgs ?? [];
|
|
1683
1701
|
if (orgs.length > 0) {
|
|
1684
1702
|
let selectedOrg = null;
|
|
1685
|
-
if (
|
|
1703
|
+
if (options?.org) {
|
|
1704
|
+
selectedOrg = resolveOrgFromOption(orgs, options.org);
|
|
1705
|
+
if (!selectedOrg) {
|
|
1706
|
+
throw new Error(
|
|
1707
|
+
`Organization "${options.org}" not found. Run 'npx mcp-use org list' after logging in to see available organizations.`
|
|
1708
|
+
);
|
|
1709
|
+
}
|
|
1710
|
+
} else if (orgs.length === 1) {
|
|
1686
1711
|
selectedOrg = orgs[0];
|
|
1712
|
+
} else if (!process.stdin.isTTY) {
|
|
1713
|
+
throw new Error(
|
|
1714
|
+
"Multiple organizations available and no TTY for interactive selection. Re-run with --org <slug|id|name> to pick one non-interactively."
|
|
1715
|
+
);
|
|
1687
1716
|
} else {
|
|
1688
1717
|
selectedOrg = await promptOrgSelection(orgs, authInfo.default_org_id);
|
|
1689
1718
|
}
|
|
@@ -1701,13 +1730,6 @@ async function loginCommand(options) {
|
|
|
1701
1730
|
);
|
|
1702
1731
|
}
|
|
1703
1732
|
}
|
|
1704
|
-
} catch {
|
|
1705
|
-
console.log(
|
|
1706
|
-
source_default.gray(
|
|
1707
|
-
`
|
|
1708
|
-
Your API key has been saved to ${source_default.white("~/.mcp-use/config.json")}`
|
|
1709
|
-
)
|
|
1710
|
-
);
|
|
1711
1733
|
}
|
|
1712
1734
|
console.log(
|
|
1713
1735
|
source_default.gray(
|
|
@@ -3555,9 +3577,7 @@ async function deployCommand(options) {
|
|
|
3555
3577
|
let resolvedOrgId;
|
|
3556
3578
|
if (options.org) {
|
|
3557
3579
|
const authInfo = await api.testAuth();
|
|
3558
|
-
const match = (authInfo.orgs ?? [])
|
|
3559
|
-
(o) => o.slug === options.org || o.id === options.org || o.name.toLowerCase() === options.org.toLowerCase()
|
|
3560
|
-
);
|
|
3580
|
+
const match = resolveOrgFromOption(authInfo.orgs ?? [], options.org);
|
|
3561
3581
|
if (match) {
|
|
3562
3582
|
api.setOrgId(match.id);
|
|
3563
3583
|
resolvedOrgId = match.id;
|
|
@@ -4781,9 +4801,7 @@ function pickStr(obj, key) {
|
|
|
4781
4801
|
async function applyOrgOption(api, org) {
|
|
4782
4802
|
if (!org) return;
|
|
4783
4803
|
const authInfo = await api.testAuth();
|
|
4784
|
-
const match = (authInfo.orgs ?? [])
|
|
4785
|
-
(o) => o.slug === org || o.id === org || o.name.toLowerCase() === org.toLowerCase()
|
|
4786
|
-
);
|
|
4804
|
+
const match = resolveOrgFromOption(authInfo.orgs ?? [], org);
|
|
4787
4805
|
if (!match) {
|
|
4788
4806
|
console.error(
|
|
4789
4807
|
source_default.red(
|
|
@@ -5212,7 +5230,7 @@ async function addSkillsToProject(projectPath) {
|
|
|
5212
5230
|
Readable.fromWeb(response.body),
|
|
5213
5231
|
extract({
|
|
5214
5232
|
cwd: tempDir,
|
|
5215
|
-
filter: (
|
|
5233
|
+
filter: (path9) => path9.includes("/skills/"),
|
|
5216
5234
|
strip: 1
|
|
5217
5235
|
})
|
|
5218
5236
|
);
|
|
@@ -5277,14 +5295,114 @@ function createSkillsCommand() {
|
|
|
5277
5295
|
return skills;
|
|
5278
5296
|
}
|
|
5279
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
|
+
|
|
5280
5398
|
// src/utils/update-check.ts
|
|
5281
5399
|
import { readFileSync } from "fs";
|
|
5282
5400
|
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
5283
5401
|
import { createRequire } from "module";
|
|
5284
5402
|
import os4 from "os";
|
|
5285
|
-
import
|
|
5286
|
-
var CACHE_DIR =
|
|
5287
|
-
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");
|
|
5288
5406
|
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
5289
5407
|
var FETCH_TIMEOUT_MS = 3e3;
|
|
5290
5408
|
var PACKAGE_NAME = "mcp-use";
|
|
@@ -5367,12 +5485,12 @@ function resolveInstalledVersion(projectPath) {
|
|
|
5367
5485
|
if (projectPath) {
|
|
5368
5486
|
attempts.push(() => {
|
|
5369
5487
|
const projectRequire = createRequire(
|
|
5370
|
-
|
|
5488
|
+
path7.join(projectPath, "package.json")
|
|
5371
5489
|
);
|
|
5372
5490
|
return projectRequire.resolve(`${PACKAGE_NAME}/package.json`);
|
|
5373
5491
|
});
|
|
5374
5492
|
}
|
|
5375
|
-
attempts.push(() =>
|
|
5493
|
+
attempts.push(() => path7.join(__dirname, "../../mcp-use/package.json"));
|
|
5376
5494
|
for (const attempt of attempts) {
|
|
5377
5495
|
try {
|
|
5378
5496
|
const pkgPath = attempt();
|
|
@@ -5410,7 +5528,7 @@ A new release of ${source_default.bold(PACKAGE_NAME)} is available: ${source_def
|
|
|
5410
5528
|
// src/index.ts
|
|
5411
5529
|
var program = new Command6();
|
|
5412
5530
|
var packageContent = readFileSync2(
|
|
5413
|
-
|
|
5531
|
+
path8.join(__dirname, "../package.json"),
|
|
5414
5532
|
"utf-8"
|
|
5415
5533
|
);
|
|
5416
5534
|
var packageJson = JSON.parse(packageContent);
|
|
@@ -5441,14 +5559,14 @@ function displayPackageVersions(projectPath) {
|
|
|
5441
5559
|
if (projectPath) {
|
|
5442
5560
|
try {
|
|
5443
5561
|
const projectRequire = createRequire2(
|
|
5444
|
-
|
|
5562
|
+
path8.join(projectPath, "package.json")
|
|
5445
5563
|
);
|
|
5446
5564
|
pkgPath = projectRequire.resolve(`${pkg.name}/package.json`);
|
|
5447
5565
|
} catch (resolveError) {
|
|
5448
|
-
pkgPath =
|
|
5566
|
+
pkgPath = path8.join(__dirname, pkg.relativePath);
|
|
5449
5567
|
}
|
|
5450
5568
|
} else {
|
|
5451
|
-
pkgPath =
|
|
5569
|
+
pkgPath = path8.join(__dirname, pkg.relativePath);
|
|
5452
5570
|
}
|
|
5453
5571
|
const pkgContent = readFileSync2(pkgPath, "utf-8");
|
|
5454
5572
|
const pkgJson = JSON.parse(pkgContent);
|
|
@@ -5600,20 +5718,92 @@ async function startTunnel(port, subdomain) {
|
|
|
5600
5718
|
}, 3e4);
|
|
5601
5719
|
});
|
|
5602
5720
|
}
|
|
5603
|
-
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
|
+
}
|
|
5604
5753
|
const candidates = ["index.ts", "src/index.ts", "server.ts", "src/server.ts"];
|
|
5605
5754
|
for (const candidate of candidates) {
|
|
5606
5755
|
try {
|
|
5607
|
-
await access(
|
|
5756
|
+
await access(path8.join(projectPath, candidate));
|
|
5608
5757
|
return candidate;
|
|
5609
5758
|
} catch {
|
|
5610
5759
|
continue;
|
|
5611
5760
|
}
|
|
5612
5761
|
}
|
|
5613
|
-
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);
|
|
5614
5804
|
}
|
|
5615
5805
|
async function generateToolRegistryTypesForServer(projectPath, serverFileRelative) {
|
|
5616
|
-
const serverFile =
|
|
5806
|
+
const serverFile = path8.join(projectPath, serverFileRelative);
|
|
5617
5807
|
const serverFileExists = await access(serverFile).then(() => true).catch(() => false);
|
|
5618
5808
|
if (!serverFileExists) {
|
|
5619
5809
|
throw new Error(`Server file not found: ${serverFile}`);
|
|
@@ -5622,19 +5812,48 @@ async function generateToolRegistryTypesForServer(projectPath, serverFileRelativ
|
|
|
5622
5812
|
try {
|
|
5623
5813
|
globalThis.__mcpUseHmrMode = true;
|
|
5624
5814
|
globalThis.__mcpUseLastServer = void 0;
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
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
|
+
}
|
|
5630
5849
|
const server = globalThis.__mcpUseLastServer;
|
|
5631
5850
|
if (!server) {
|
|
5632
5851
|
throw new Error(
|
|
5633
5852
|
"No MCPServer instance found. Make sure your server file creates an MCPServer instance."
|
|
5634
5853
|
);
|
|
5635
5854
|
}
|
|
5636
|
-
const mcpUsePath =
|
|
5637
|
-
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);
|
|
5638
5857
|
if (!generateToolRegistryTypes) {
|
|
5639
5858
|
throw new Error("generateToolRegistryTypes not found in mcp-use package");
|
|
5640
5859
|
}
|
|
@@ -5649,21 +5868,24 @@ async function generateToolRegistryTypesForServer(projectPath, serverFileRelativ
|
|
|
5649
5868
|
}
|
|
5650
5869
|
async function buildWidgets(projectPath, options = {}) {
|
|
5651
5870
|
const { inline = true } = options;
|
|
5652
|
-
const { promises:
|
|
5871
|
+
const { promises: fs11 } = await import("fs");
|
|
5653
5872
|
const { build } = await import("vite");
|
|
5654
|
-
const
|
|
5873
|
+
const widgetsDirRelative = options.widgetsDir ?? "resources";
|
|
5874
|
+
const resourcesDir = path8.resolve(projectPath, widgetsDirRelative);
|
|
5655
5875
|
const mcpUrl = process.env.MCP_URL;
|
|
5656
5876
|
try {
|
|
5657
5877
|
await access(resourcesDir);
|
|
5658
5878
|
} catch {
|
|
5659
5879
|
console.log(
|
|
5660
|
-
source_default.gray(
|
|
5880
|
+
source_default.gray(
|
|
5881
|
+
`No ${widgetsDirRelative}/ directory found - skipping widget build`
|
|
5882
|
+
)
|
|
5661
5883
|
);
|
|
5662
5884
|
return [];
|
|
5663
5885
|
}
|
|
5664
5886
|
const entries = [];
|
|
5665
5887
|
try {
|
|
5666
|
-
const files = await
|
|
5888
|
+
const files = await fs11.readdir(resourcesDir, { withFileTypes: true });
|
|
5667
5889
|
for (const dirent of files) {
|
|
5668
5890
|
if (dirent.name.startsWith("._") || dirent.name.startsWith(".DS_Store")) {
|
|
5669
5891
|
continue;
|
|
@@ -5671,12 +5893,12 @@ async function buildWidgets(projectPath, options = {}) {
|
|
|
5671
5893
|
if (dirent.isFile() && (dirent.name.endsWith(".tsx") || dirent.name.endsWith(".ts"))) {
|
|
5672
5894
|
entries.push({
|
|
5673
5895
|
name: dirent.name.replace(/\.tsx?$/, ""),
|
|
5674
|
-
path:
|
|
5896
|
+
path: path8.join(resourcesDir, dirent.name)
|
|
5675
5897
|
});
|
|
5676
5898
|
} else if (dirent.isDirectory()) {
|
|
5677
|
-
const widgetPath =
|
|
5899
|
+
const widgetPath = path8.join(resourcesDir, dirent.name, "widget.tsx");
|
|
5678
5900
|
try {
|
|
5679
|
-
await
|
|
5901
|
+
await fs11.access(widgetPath);
|
|
5680
5902
|
entries.push({
|
|
5681
5903
|
name: dirent.name,
|
|
5682
5904
|
path: widgetPath
|
|
@@ -5686,11 +5908,15 @@ async function buildWidgets(projectPath, options = {}) {
|
|
|
5686
5908
|
}
|
|
5687
5909
|
}
|
|
5688
5910
|
} catch (error) {
|
|
5689
|
-
console.log(
|
|
5911
|
+
console.log(
|
|
5912
|
+
source_default.gray(`No widgets found in ${widgetsDirRelative}/ directory`)
|
|
5913
|
+
);
|
|
5690
5914
|
return [];
|
|
5691
5915
|
}
|
|
5692
5916
|
if (entries.length === 0) {
|
|
5693
|
-
console.log(
|
|
5917
|
+
console.log(
|
|
5918
|
+
source_default.gray(`No widgets found in ${widgetsDirRelative}/ directory`)
|
|
5919
|
+
);
|
|
5694
5920
|
return [];
|
|
5695
5921
|
}
|
|
5696
5922
|
console.log(
|
|
@@ -5700,10 +5926,17 @@ async function buildWidgets(projectPath, options = {}) {
|
|
|
5700
5926
|
);
|
|
5701
5927
|
const react = (await import("@vitejs/plugin-react")).default;
|
|
5702
5928
|
const tailwindcss = (await import("@tailwindcss/vite")).default;
|
|
5703
|
-
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");
|
|
5704
5937
|
let favicon = "";
|
|
5705
5938
|
try {
|
|
5706
|
-
const pkgContent = await
|
|
5939
|
+
const pkgContent = await fs11.readFile(packageJsonPath, "utf-8");
|
|
5707
5940
|
const pkg = JSON.parse(pkgContent);
|
|
5708
5941
|
favicon = pkg.mcpUse?.favicon || "";
|
|
5709
5942
|
} catch {
|
|
@@ -5712,18 +5945,27 @@ async function buildWidgets(projectPath, options = {}) {
|
|
|
5712
5945
|
const widgetName = entry.name;
|
|
5713
5946
|
const entryPath = entry.path.replace(/\\/g, "/");
|
|
5714
5947
|
console.log(source_default.gray(` - Building ${widgetName}...`));
|
|
5715
|
-
const tempDir =
|
|
5716
|
-
await
|
|
5717
|
-
const relativeResourcesPath =
|
|
5718
|
-
const mcpUsePath =
|
|
5719
|
-
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
|
+
}
|
|
5720
5962
|
const cssContent = `@import "tailwindcss";
|
|
5721
5963
|
|
|
5722
5964
|
/* Configure Tailwind to scan the resources directory and mcp-use package */
|
|
5723
5965
|
@source "${relativeResourcesPath}";
|
|
5724
5966
|
@source "${relativeMcpUsePath}/**/*.{ts,tsx,js,jsx}";
|
|
5725
|
-
`;
|
|
5726
|
-
await
|
|
5967
|
+
${projectSrcSourceLine}`;
|
|
5968
|
+
await fs11.writeFile(path8.join(tempDir, "styles.css"), cssContent, "utf8");
|
|
5727
5969
|
const entryContent = `import React from 'react'
|
|
5728
5970
|
import { createRoot } from 'react-dom/client'
|
|
5729
5971
|
import './styles.css'
|
|
@@ -5748,9 +5990,9 @@ if (container && Component) {
|
|
|
5748
5990
|
<script type="module" src="/entry.tsx"></script>
|
|
5749
5991
|
</body>
|
|
5750
5992
|
</html>`;
|
|
5751
|
-
await
|
|
5752
|
-
await
|
|
5753
|
-
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(
|
|
5754
5996
|
projectPath,
|
|
5755
5997
|
"dist",
|
|
5756
5998
|
"resources",
|
|
@@ -5760,12 +6002,12 @@ if (container && Component) {
|
|
|
5760
6002
|
const baseUrl = mcpUrl ? `${mcpUrl}/${widgetName}/` : `/mcp-use/widgets/${widgetName}/`;
|
|
5761
6003
|
let widgetMetadata = {};
|
|
5762
6004
|
try {
|
|
5763
|
-
const metadataTempDir =
|
|
6005
|
+
const metadataTempDir = path8.join(
|
|
5764
6006
|
projectPath,
|
|
5765
6007
|
".mcp-use",
|
|
5766
6008
|
`${widgetName}-metadata`
|
|
5767
6009
|
);
|
|
5768
|
-
await
|
|
6010
|
+
await fs11.mkdir(metadataTempDir, { recursive: true });
|
|
5769
6011
|
const { createServer } = await import("vite");
|
|
5770
6012
|
const nodeStubsPlugin = {
|
|
5771
6013
|
name: "node-stubs",
|
|
@@ -5793,15 +6035,16 @@ export default PostHog;
|
|
|
5793
6035
|
return null;
|
|
5794
6036
|
}
|
|
5795
6037
|
};
|
|
6038
|
+
const serverOnlyGuard = makeWidgetServerOnlyGuard(widgetName);
|
|
5796
6039
|
const metadataServer = await createServer({
|
|
5797
6040
|
root: metadataTempDir,
|
|
5798
|
-
cacheDir:
|
|
5799
|
-
plugins: [nodeStubsPlugin, tailwindcss(), react()],
|
|
5800
|
-
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
},
|
|
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 } },
|
|
5805
6048
|
server: {
|
|
5806
6049
|
middlewareMode: true
|
|
5807
6050
|
},
|
|
@@ -5880,7 +6123,7 @@ export default PostHog;
|
|
|
5880
6123
|
} finally {
|
|
5881
6124
|
await metadataServer.close();
|
|
5882
6125
|
try {
|
|
5883
|
-
await
|
|
6126
|
+
await fs11.rm(metadataTempDir, { recursive: true, force: true });
|
|
5884
6127
|
} catch {
|
|
5885
6128
|
}
|
|
5886
6129
|
}
|
|
@@ -5975,12 +6218,14 @@ export default {
|
|
|
5975
6218
|
return null;
|
|
5976
6219
|
}
|
|
5977
6220
|
};
|
|
6221
|
+
const buildServerOnlyGuard = makeWidgetServerOnlyGuard(widgetName);
|
|
5978
6222
|
const buildPlugins = inline ? [
|
|
6223
|
+
buildServerOnlyGuard,
|
|
5979
6224
|
buildNodeStubsPlugin,
|
|
5980
6225
|
tailwindcss(),
|
|
5981
6226
|
react(),
|
|
5982
6227
|
viteSingleFile({ removeViteModuleLoader: true })
|
|
5983
|
-
] : [buildNodeStubsPlugin, tailwindcss(), react()];
|
|
6228
|
+
] : [buildServerOnlyGuard, buildNodeStubsPlugin, tailwindcss(), react()];
|
|
5984
6229
|
await build({
|
|
5985
6230
|
root: tempDir,
|
|
5986
6231
|
base: baseUrl,
|
|
@@ -5999,11 +6244,10 @@ export default {
|
|
|
5999
6244
|
}
|
|
6000
6245
|
}
|
|
6001
6246
|
},
|
|
6002
|
-
resolve
|
|
6003
|
-
|
|
6004
|
-
|
|
6005
|
-
|
|
6006
|
-
},
|
|
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 } },
|
|
6007
6251
|
optimizeDeps: {
|
|
6008
6252
|
// Exclude Node.js-only packages from browser bundling
|
|
6009
6253
|
exclude: ["posthog-node"]
|
|
@@ -6025,7 +6269,7 @@ export default {
|
|
|
6025
6269
|
// Inline all assets under 100MB (effectively all)
|
|
6026
6270
|
} : {},
|
|
6027
6271
|
rolldownOptions: {
|
|
6028
|
-
input:
|
|
6272
|
+
input: path8.join(tempDir, "index.html"),
|
|
6029
6273
|
external: (id) => {
|
|
6030
6274
|
return false;
|
|
6031
6275
|
}
|
|
@@ -6033,12 +6277,12 @@ export default {
|
|
|
6033
6277
|
}
|
|
6034
6278
|
});
|
|
6035
6279
|
try {
|
|
6036
|
-
const assetsDir =
|
|
6037
|
-
const assetFiles = await
|
|
6280
|
+
const assetsDir = path8.join(outDir, "assets");
|
|
6281
|
+
const assetFiles = await fs11.readdir(assetsDir);
|
|
6038
6282
|
const jsFiles = assetFiles.filter((f) => f.endsWith(".js"));
|
|
6039
6283
|
for (const jsFile of jsFiles) {
|
|
6040
|
-
const jsPath =
|
|
6041
|
-
let content = await
|
|
6284
|
+
const jsPath = path8.join(assetsDir, jsFile);
|
|
6285
|
+
let content = await fs11.readFile(jsPath, "utf8");
|
|
6042
6286
|
const zodConfigPatterns = [
|
|
6043
6287
|
// Non-minified: export const globalConfig = {}
|
|
6044
6288
|
/export\s+const\s+globalConfig\s*=\s*\{\s*\}/g,
|
|
@@ -6057,7 +6301,7 @@ export default {
|
|
|
6057
6301
|
}
|
|
6058
6302
|
}
|
|
6059
6303
|
if (patched) {
|
|
6060
|
-
await
|
|
6304
|
+
await fs11.writeFile(jsPath, content, "utf8");
|
|
6061
6305
|
console.log(source_default.gray(` \u2192 Patched Zod JIT in ${jsFile}`));
|
|
6062
6306
|
}
|
|
6063
6307
|
}
|
|
@@ -6069,8 +6313,8 @@ export default {
|
|
|
6069
6313
|
const mcpServerUrl = process.env.MCP_SERVER_URL;
|
|
6070
6314
|
if (mcpServerUrl) {
|
|
6071
6315
|
try {
|
|
6072
|
-
const htmlPath =
|
|
6073
|
-
let html = await
|
|
6316
|
+
const htmlPath = path8.join(outDir, "index.html");
|
|
6317
|
+
let html = await fs11.readFile(htmlPath, "utf8");
|
|
6074
6318
|
const injectionScript = `<script>window.__getFile = (filename) => { return "${mcpUrl}/${widgetName}/"+filename }; window.__mcpPublicUrl = "${mcpServerUrl}/mcp-use/public"; window.__mcpPublicAssetsUrl = "${mcpUrl}/public";</script>`;
|
|
6075
6319
|
if (!html.includes("window.__mcpPublicUrl")) {
|
|
6076
6320
|
html = html.replace(
|
|
@@ -6091,7 +6335,7 @@ export default {
|
|
|
6091
6335
|
<base href="${mcpServerUrl}">`
|
|
6092
6336
|
);
|
|
6093
6337
|
}
|
|
6094
|
-
await
|
|
6338
|
+
await fs11.writeFile(htmlPath, html, "utf8");
|
|
6095
6339
|
console.log(
|
|
6096
6340
|
source_default.gray(` \u2192 Injected MCP_SERVER_URL into ${widgetName}`)
|
|
6097
6341
|
);
|
|
@@ -6105,22 +6349,32 @@ export default {
|
|
|
6105
6349
|
}
|
|
6106
6350
|
}
|
|
6107
6351
|
console.log(source_default.green(` \u2713 Built ${widgetName}`));
|
|
6108
|
-
return {
|
|
6352
|
+
return {
|
|
6353
|
+
status: "built",
|
|
6354
|
+
name: widgetName,
|
|
6355
|
+
metadata: widgetMetadata
|
|
6356
|
+
};
|
|
6109
6357
|
} catch (error) {
|
|
6110
6358
|
console.error(source_default.red(` \u2717 Failed to build ${widgetName}:`), error);
|
|
6111
|
-
return
|
|
6359
|
+
return { status: "failed", name: widgetName };
|
|
6112
6360
|
}
|
|
6113
6361
|
};
|
|
6114
6362
|
const buildResults = await Promise.all(
|
|
6115
6363
|
entries.map((entry) => buildSingleWidget(entry))
|
|
6116
6364
|
);
|
|
6117
|
-
const
|
|
6118
|
-
|
|
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 }] : []
|
|
6119
6374
|
);
|
|
6120
|
-
return builtWidgets;
|
|
6121
6375
|
}
|
|
6122
6376
|
async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
|
|
6123
|
-
const { promises:
|
|
6377
|
+
const { promises: fs11 } = await import("fs");
|
|
6124
6378
|
const literalFiles = [];
|
|
6125
6379
|
const dirPrefixes = [];
|
|
6126
6380
|
for (const pattern of includePatterns) {
|
|
@@ -6135,7 +6389,7 @@ async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
|
|
|
6135
6389
|
for (const file of literalFiles) {
|
|
6136
6390
|
if (/\.tsx?$/.test(file) && !file.endsWith(".d.ts")) {
|
|
6137
6391
|
try {
|
|
6138
|
-
await access(
|
|
6392
|
+
await access(path8.join(projectPath, file));
|
|
6139
6393
|
files.push(file);
|
|
6140
6394
|
} catch {
|
|
6141
6395
|
}
|
|
@@ -6143,13 +6397,13 @@ async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
|
|
|
6143
6397
|
}
|
|
6144
6398
|
const excludeSet = new Set(excludePatterns.map((e) => e.replace(/\*+/g, "")));
|
|
6145
6399
|
for (const prefix of dirPrefixes) {
|
|
6146
|
-
const dirPath =
|
|
6400
|
+
const dirPath = path8.join(projectPath, prefix);
|
|
6147
6401
|
try {
|
|
6148
|
-
const entries = await
|
|
6402
|
+
const entries = await fs11.readdir(dirPath, { recursive: true });
|
|
6149
6403
|
for (const entry of entries) {
|
|
6150
6404
|
const entryStr = String(entry);
|
|
6151
|
-
const rel =
|
|
6152
|
-
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])) {
|
|
6153
6407
|
files.push(rel);
|
|
6154
6408
|
}
|
|
6155
6409
|
}
|
|
@@ -6160,11 +6414,11 @@ async function collectTsFiles(projectPath, includePatterns, excludePatterns) {
|
|
|
6160
6414
|
}
|
|
6161
6415
|
async function transpileWithEsbuild(projectPath) {
|
|
6162
6416
|
const esbuild = await import("esbuild");
|
|
6163
|
-
const { promises:
|
|
6164
|
-
const tsconfigPath =
|
|
6417
|
+
const { promises: fs11 } = await import("fs");
|
|
6418
|
+
const tsconfigPath = path8.join(projectPath, "tsconfig.json");
|
|
6165
6419
|
let tsconfig = {};
|
|
6166
6420
|
try {
|
|
6167
|
-
const raw = await
|
|
6421
|
+
const raw = await fs11.readFile(tsconfigPath, "utf-8");
|
|
6168
6422
|
tsconfig = JSON.parse(raw);
|
|
6169
6423
|
} catch {
|
|
6170
6424
|
}
|
|
@@ -6191,10 +6445,10 @@ async function transpileWithEsbuild(projectPath) {
|
|
|
6191
6445
|
const target = (compilerOptions.target || "ES2022").toLowerCase();
|
|
6192
6446
|
const moduleStr = (compilerOptions.module || "ESNext").toLowerCase();
|
|
6193
6447
|
const format = moduleStr.includes("commonjs") ? "cjs" : "esm";
|
|
6194
|
-
const outbase = compilerOptions.rootDir ?
|
|
6448
|
+
const outbase = compilerOptions.rootDir ? path8.resolve(projectPath, compilerOptions.rootDir) : projectPath;
|
|
6195
6449
|
await esbuild.build({
|
|
6196
|
-
entryPoints: files.map((f) =>
|
|
6197
|
-
outdir:
|
|
6450
|
+
entryPoints: files.map((f) => path8.join(projectPath, f)),
|
|
6451
|
+
outdir: path8.join(projectPath, outDir),
|
|
6198
6452
|
outbase,
|
|
6199
6453
|
bundle: false,
|
|
6200
6454
|
format,
|
|
@@ -6206,21 +6460,42 @@ async function transpileWithEsbuild(projectPath) {
|
|
|
6206
6460
|
logLevel: "warning"
|
|
6207
6461
|
});
|
|
6208
6462
|
}
|
|
6209
|
-
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(
|
|
6210
6473
|
"--inline",
|
|
6211
6474
|
"Inline all JS/CSS into HTML (required for VS Code MCP Apps)"
|
|
6212
6475
|
).option("--no-inline", "Keep JS/CSS as separate files (default)").option("--no-typecheck", "Skip TypeScript type checking (faster builds)").action(async (options) => {
|
|
6213
6476
|
try {
|
|
6214
|
-
const projectPath =
|
|
6215
|
-
const { promises:
|
|
6477
|
+
const projectPath = path8.resolve(options.path);
|
|
6478
|
+
const { promises: fs11 } = await import("fs");
|
|
6216
6479
|
displayPackageVersions(projectPath);
|
|
6480
|
+
const mcpDir = options.mcpDir;
|
|
6481
|
+
const widgetsDir = resolveWidgetsDir(options.widgetsDir, mcpDir);
|
|
6217
6482
|
const builtWidgets = await buildWidgets(projectPath, {
|
|
6218
|
-
inline: options.inline ?? false
|
|
6483
|
+
inline: options.inline ?? false,
|
|
6484
|
+
widgetsDir
|
|
6219
6485
|
});
|
|
6220
6486
|
let sourceServerFile;
|
|
6221
6487
|
try {
|
|
6222
|
-
sourceServerFile = await findServerFile(
|
|
6223
|
-
|
|
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
|
+
);
|
|
6224
6499
|
}
|
|
6225
6500
|
if (sourceServerFile) {
|
|
6226
6501
|
console.log(source_default.gray("Generating tool registry types..."));
|
|
@@ -6238,17 +6513,25 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
6238
6513
|
);
|
|
6239
6514
|
}
|
|
6240
6515
|
}
|
|
6241
|
-
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
|
|
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) {
|
|
6245
6528
|
console.log(source_default.gray("Type checking..."));
|
|
6246
6529
|
try {
|
|
6247
6530
|
await runCommand(
|
|
6248
6531
|
"node",
|
|
6249
6532
|
[
|
|
6250
6533
|
"--max-old-space-size=4096",
|
|
6251
|
-
|
|
6534
|
+
path8.join(
|
|
6252
6535
|
projectPath,
|
|
6253
6536
|
"node_modules",
|
|
6254
6537
|
"typescript",
|
|
@@ -6269,39 +6552,43 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
6269
6552
|
}
|
|
6270
6553
|
let entryPoint;
|
|
6271
6554
|
if (sourceServerFile) {
|
|
6272
|
-
|
|
6273
|
-
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
|
|
6277
|
-
|
|
6278
|
-
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6285
|
-
|
|
6286
|
-
|
|
6287
|
-
|
|
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
|
+
}
|
|
6288
6575
|
}
|
|
6289
6576
|
}
|
|
6290
6577
|
}
|
|
6291
|
-
const publicDir =
|
|
6578
|
+
const publicDir = path8.join(projectPath, "public");
|
|
6292
6579
|
try {
|
|
6293
|
-
await
|
|
6580
|
+
await fs11.access(publicDir);
|
|
6294
6581
|
console.log(source_default.gray("Copying public assets..."));
|
|
6295
|
-
await
|
|
6582
|
+
await fs11.cp(publicDir, path8.join(projectPath, "dist", "public"), {
|
|
6296
6583
|
recursive: true
|
|
6297
6584
|
});
|
|
6298
6585
|
console.log(source_default.green("\u2713 Public assets copied"));
|
|
6299
6586
|
} catch {
|
|
6300
6587
|
}
|
|
6301
|
-
const manifestPath =
|
|
6588
|
+
const manifestPath = path8.join(projectPath, "dist", "mcp-use.json");
|
|
6302
6589
|
let existingManifest = {};
|
|
6303
6590
|
try {
|
|
6304
|
-
const existingContent = await
|
|
6591
|
+
const existingContent = await fs11.readFile(manifestPath, "utf-8");
|
|
6305
6592
|
existingManifest = JSON.parse(existingContent);
|
|
6306
6593
|
} catch {
|
|
6307
6594
|
}
|
|
@@ -6323,8 +6610,8 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
6323
6610
|
// Server entry point for `mcp-use start`
|
|
6324
6611
|
widgets: widgetsData
|
|
6325
6612
|
};
|
|
6326
|
-
await
|
|
6327
|
-
await
|
|
6613
|
+
await fs11.mkdir(path8.dirname(manifestPath), { recursive: true });
|
|
6614
|
+
await fs11.writeFile(
|
|
6328
6615
|
manifestPath,
|
|
6329
6616
|
JSON.stringify(manifest, null, 2),
|
|
6330
6617
|
"utf8"
|
|
@@ -6344,14 +6631,23 @@ program.command("build").description("Build TypeScript and MCP UI widgets").opti
|
|
|
6344
6631
|
process.exit(1);
|
|
6345
6632
|
}
|
|
6346
6633
|
});
|
|
6347
|
-
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(
|
|
6348
6644
|
"--host <host>",
|
|
6349
6645
|
"Server host (use 0.0.0.0 to listen on all interfaces)",
|
|
6350
6646
|
"0.0.0.0"
|
|
6351
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) => {
|
|
6352
6648
|
try {
|
|
6353
6649
|
process.env.MCP_USE_CLI_DEV = "1";
|
|
6354
|
-
const projectPath =
|
|
6650
|
+
const projectPath = path8.resolve(options.path);
|
|
6355
6651
|
let port = parseInt(options.port, 10);
|
|
6356
6652
|
const host = options.host;
|
|
6357
6653
|
const useHmr = options.hmr !== false;
|
|
@@ -6362,13 +6658,24 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6362
6658
|
console.log(source_default.green.bold(`\u2713 Using port ${availablePort} instead`));
|
|
6363
6659
|
port = availablePort;
|
|
6364
6660
|
}
|
|
6365
|
-
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
|
+
}
|
|
6366
6673
|
let tunnelProcess = void 0;
|
|
6367
6674
|
let tunnelSubdomain = void 0;
|
|
6368
6675
|
let tunnelUrl = void 0;
|
|
6369
6676
|
if (options.tunnel) {
|
|
6370
6677
|
try {
|
|
6371
|
-
const manifestPath =
|
|
6678
|
+
const manifestPath = path8.join(projectPath, "dist", "mcp-use.json");
|
|
6372
6679
|
let existingSubdomain;
|
|
6373
6680
|
try {
|
|
6374
6681
|
const manifestContent = await readFile3(manifestPath, "utf-8");
|
|
@@ -6417,7 +6724,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6417
6724
|
manifest.tunnel = {};
|
|
6418
6725
|
}
|
|
6419
6726
|
manifest.tunnel.subdomain = tunnelSubdomain;
|
|
6420
|
-
await mkdir3(
|
|
6727
|
+
await mkdir3(path8.dirname(manifestPath), { recursive: true });
|
|
6421
6728
|
await writeFile3(
|
|
6422
6729
|
manifestPath,
|
|
6423
6730
|
JSON.stringify(manifest, null, 2),
|
|
@@ -6444,22 +6751,35 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6444
6751
|
} else if (!process.env.MCP_URL) {
|
|
6445
6752
|
process.env.MCP_URL = mcpUrl;
|
|
6446
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
|
+
}
|
|
6447
6763
|
if (!useHmr) {
|
|
6448
6764
|
console.log(source_default.gray("HMR disabled, using tsx watch (full restart)"));
|
|
6449
6765
|
const processes = [];
|
|
6450
|
-
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,
|
|
6451
6770
|
PORT: String(port),
|
|
6452
6771
|
HOST: host,
|
|
6453
6772
|
NODE_ENV: "development",
|
|
6454
6773
|
// Preserve user-provided MCP_URL (e.g., for reverse proxy setups)
|
|
6455
6774
|
MCP_URL: process.env.MCP_URL || mcpUrl
|
|
6456
6775
|
};
|
|
6776
|
+
const env2 = isNextJsProject ? withNextShimsEnv(baseEnv) : baseEnv;
|
|
6457
6777
|
const { createRequire: createRequire4 } = await import("module");
|
|
6458
6778
|
let cmd;
|
|
6459
6779
|
let args;
|
|
6460
6780
|
try {
|
|
6461
6781
|
const projectRequire = createRequire4(
|
|
6462
|
-
|
|
6782
|
+
path8.join(projectPath, "package.json")
|
|
6463
6783
|
);
|
|
6464
6784
|
const tsxPkgPath = projectRequire.resolve("tsx/package.json");
|
|
6465
6785
|
const tsxPkg = JSON.parse(await readFile3(tsxPkgPath, "utf-8"));
|
|
@@ -6471,7 +6791,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6471
6791
|
} else {
|
|
6472
6792
|
throw new Error("No bin field found in tsx package.json");
|
|
6473
6793
|
}
|
|
6474
|
-
const tsxBin =
|
|
6794
|
+
const tsxBin = path8.resolve(path8.dirname(tsxPkgPath), binPath);
|
|
6475
6795
|
cmd = "node";
|
|
6476
6796
|
args = [tsxBin, "watch", serverFile];
|
|
6477
6797
|
} catch (error) {
|
|
@@ -6546,18 +6866,56 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6546
6866
|
"HMR enabled - changes will hot reload without dropping connections"
|
|
6547
6867
|
)
|
|
6548
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
|
+
}
|
|
6549
6879
|
const chokidarModule = await import("chokidar");
|
|
6550
6880
|
const chokidar = chokidarModule.default || chokidarModule;
|
|
6551
|
-
const { fileURLToPath:
|
|
6881
|
+
const { fileURLToPath: fileURLToPath4 } = await import("url");
|
|
6552
6882
|
const { createRequire: createRequire3 } = await import("module");
|
|
6553
|
-
|
|
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;
|
|
6554
6893
|
try {
|
|
6555
6894
|
const projectRequire = createRequire3(
|
|
6556
|
-
|
|
6895
|
+
path8.join(projectPath, "package.json")
|
|
6557
6896
|
);
|
|
6558
|
-
const
|
|
6559
|
-
const
|
|
6560
|
-
|
|
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
|
+
}
|
|
6561
6919
|
} catch {
|
|
6562
6920
|
console.log(
|
|
6563
6921
|
source_default.yellow(
|
|
@@ -6565,25 +6923,15 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6565
6923
|
)
|
|
6566
6924
|
);
|
|
6567
6925
|
}
|
|
6568
|
-
const serverFilePath =
|
|
6569
|
-
const serverFileUrl =
|
|
6926
|
+
const serverFilePath = path8.join(projectPath, serverFile);
|
|
6927
|
+
const serverFileUrl = pathToFileURL2(serverFilePath).href;
|
|
6570
6928
|
globalThis.__mcpUseHmrMode = true;
|
|
6571
6929
|
const importServerModule = async () => {
|
|
6572
6930
|
const previousServer = globalThis.__mcpUseLastServer;
|
|
6573
6931
|
globalThis.__mcpUseLastServer = null;
|
|
6574
|
-
if (
|
|
6575
|
-
await tsImport(`${serverFileUrl}?t=${Date.now()}`, {
|
|
6576
|
-
parentURL: import.meta.url,
|
|
6577
|
-
onImport: (file) => {
|
|
6578
|
-
const filePath = file.startsWith("file://") ? fileURLToPath3(file) : file;
|
|
6579
|
-
if (!filePath.includes("node_modules") && filePath.startsWith(projectPath)) {
|
|
6580
|
-
console.debug(`[HMR] Loaded: ${file}`);
|
|
6581
|
-
}
|
|
6582
|
-
}
|
|
6583
|
-
});
|
|
6584
|
-
} else {
|
|
6585
|
-
await import(`${serverFileUrl}?t=${Date.now()}`);
|
|
6932
|
+
if (!tsxLoaderActive) {
|
|
6586
6933
|
}
|
|
6934
|
+
await import(`${serverFileUrl}?t=${Date.now()}`);
|
|
6587
6935
|
const instance = globalThis.__mcpUseLastServer;
|
|
6588
6936
|
if (!instance) {
|
|
6589
6937
|
globalThis.__mcpUseLastServer = previousServer;
|
|
@@ -6597,7 +6945,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6597
6945
|
if (instance === previousServer) {
|
|
6598
6946
|
console.warn(
|
|
6599
6947
|
source_default.yellow(
|
|
6600
|
-
"[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.")
|
|
6601
6949
|
)
|
|
6602
6950
|
);
|
|
6603
6951
|
return null;
|
|
@@ -6672,8 +7020,8 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6672
7020
|
}
|
|
6673
7021
|
let watcher = chokidar.watch(".", {
|
|
6674
7022
|
cwd: projectPath,
|
|
6675
|
-
ignored: (
|
|
6676
|
-
const normalizedPath =
|
|
7023
|
+
ignored: (path9, stats) => {
|
|
7024
|
+
const normalizedPath = path9.replace(/\\/g, "/");
|
|
6677
7025
|
if (/(^|\/)\.[^/]/.test(normalizedPath)) {
|
|
6678
7026
|
return true;
|
|
6679
7027
|
}
|
|
@@ -6847,7 +7195,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6847
7195
|
}
|
|
6848
7196
|
tunnelUrl = void 0;
|
|
6849
7197
|
if (withTunnel) {
|
|
6850
|
-
const manifestPath =
|
|
7198
|
+
const manifestPath = path8.join(projectPath, "dist", "mcp-use.json");
|
|
6851
7199
|
let existingSubdomain;
|
|
6852
7200
|
try {
|
|
6853
7201
|
const manifestContent = await readFile3(manifestPath, "utf-8");
|
|
@@ -6884,7 +7232,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6884
7232
|
tunnelSubdomain = tunnelInfo.subdomain;
|
|
6885
7233
|
process.env.MCP_URL = tunnelUrl;
|
|
6886
7234
|
try {
|
|
6887
|
-
const mPath =
|
|
7235
|
+
const mPath = path8.join(projectPath, "dist", "mcp-use.json");
|
|
6888
7236
|
let manifest = {};
|
|
6889
7237
|
try {
|
|
6890
7238
|
manifest = JSON.parse(await readFile3(mPath, "utf-8"));
|
|
@@ -6892,7 +7240,7 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6892
7240
|
}
|
|
6893
7241
|
if (!manifest.tunnel) manifest.tunnel = {};
|
|
6894
7242
|
manifest.tunnel.subdomain = tunnelSubdomain;
|
|
6895
|
-
await mkdir3(
|
|
7243
|
+
await mkdir3(path8.dirname(mPath), { recursive: true });
|
|
6896
7244
|
await writeFile3(mPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
6897
7245
|
} catch {
|
|
6898
7246
|
}
|
|
@@ -6988,9 +7336,15 @@ program.command("dev").description("Run development server with auto-reload and
|
|
|
6988
7336
|
process.exit(1);
|
|
6989
7337
|
}
|
|
6990
7338
|
});
|
|
6991
|
-
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) => {
|
|
6992
7346
|
try {
|
|
6993
|
-
const projectPath =
|
|
7347
|
+
const projectPath = path8.resolve(options.path);
|
|
6994
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="));
|
|
6995
7349
|
let port = portFlagProvided ? parseInt(options.port, 10) : parseInt(process.env.PORT || options.port || "3000", 10);
|
|
6996
7350
|
if (!await isPortAvailable(port)) {
|
|
@@ -7008,7 +7362,7 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
7008
7362
|
let tunnelSubdomain = void 0;
|
|
7009
7363
|
if (options.tunnel) {
|
|
7010
7364
|
try {
|
|
7011
|
-
const manifestPath2 =
|
|
7365
|
+
const manifestPath2 = path8.join(projectPath, "dist", "mcp-use.json");
|
|
7012
7366
|
let existingSubdomain;
|
|
7013
7367
|
try {
|
|
7014
7368
|
const manifestContent = await readFile3(manifestPath2, "utf-8");
|
|
@@ -7063,7 +7417,7 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
7063
7417
|
manifest.tunnel = {};
|
|
7064
7418
|
}
|
|
7065
7419
|
manifest.tunnel.subdomain = subdomain;
|
|
7066
|
-
await mkdir3(
|
|
7420
|
+
await mkdir3(path8.dirname(manifestPath2), { recursive: true });
|
|
7067
7421
|
await writeFile3(
|
|
7068
7422
|
manifestPath2,
|
|
7069
7423
|
JSON.stringify(manifest, null, 2),
|
|
@@ -7082,18 +7436,25 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
7082
7436
|
}
|
|
7083
7437
|
}
|
|
7084
7438
|
let serverFile;
|
|
7085
|
-
const manifestPath =
|
|
7439
|
+
const manifestPath = path8.join(projectPath, "dist", "mcp-use.json");
|
|
7086
7440
|
try {
|
|
7087
7441
|
const manifestContent = await readFile3(manifestPath, "utf-8");
|
|
7088
7442
|
const manifest = JSON.parse(manifestContent);
|
|
7089
7443
|
if (manifest.entryPoint) {
|
|
7090
|
-
await access(
|
|
7444
|
+
await access(path8.join(projectPath, manifest.entryPoint));
|
|
7091
7445
|
serverFile = manifest.entryPoint;
|
|
7092
7446
|
}
|
|
7093
7447
|
} catch {
|
|
7094
7448
|
}
|
|
7095
7449
|
if (!serverFile) {
|
|
7450
|
+
const startMcpDir = options.mcpDir;
|
|
7096
7451
|
const serverCandidates = [
|
|
7452
|
+
...startMcpDir ? [
|
|
7453
|
+
`${startMcpDir}/index.ts`,
|
|
7454
|
+
`${startMcpDir}/index.tsx`,
|
|
7455
|
+
`dist/${startMcpDir}/index.js`,
|
|
7456
|
+
`dist/${startMcpDir}/server.js`
|
|
7457
|
+
] : [],
|
|
7097
7458
|
"dist/index.js",
|
|
7098
7459
|
"dist/server.js",
|
|
7099
7460
|
"dist/src/index.js",
|
|
@@ -7101,7 +7462,7 @@ program.command("start").description("Start production server").option("-p, --pa
|
|
|
7101
7462
|
];
|
|
7102
7463
|
for (const candidate of serverCandidates) {
|
|
7103
7464
|
try {
|
|
7104
|
-
await access(
|
|
7465
|
+
await access(path8.join(projectPath, candidate));
|
|
7105
7466
|
serverFile = candidate;
|
|
7106
7467
|
break;
|
|
7107
7468
|
} catch {
|
|
@@ -7125,18 +7486,53 @@ Looked for:
|
|
|
7125
7486
|
process.exit(1);
|
|
7126
7487
|
}
|
|
7127
7488
|
console.log("Starting production server...");
|
|
7128
|
-
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 = {
|
|
7129
7499
|
...process.env,
|
|
7130
7500
|
PORT: String(port),
|
|
7131
7501
|
NODE_ENV: "production"
|
|
7132
7502
|
};
|
|
7133
7503
|
if (mcpUrl) {
|
|
7134
|
-
|
|
7504
|
+
baseEnv.MCP_URL = mcpUrl;
|
|
7135
7505
|
console.log(source_default.whiteBright(`Tunnel: ${mcpUrl}/mcp`));
|
|
7136
|
-
} else if (!
|
|
7137
|
-
|
|
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
|
+
}
|
|
7138
7534
|
}
|
|
7139
|
-
const serverProc = spawn(
|
|
7535
|
+
const serverProc = spawn(spawnCmd, spawnArgs, {
|
|
7140
7536
|
cwd: projectPath,
|
|
7141
7537
|
stdio: "inherit",
|
|
7142
7538
|
env: env2
|
|
@@ -7202,9 +7598,9 @@ Looked for:
|
|
|
7202
7598
|
program.command("login").description("Login to mcp-use cloud").option(
|
|
7203
7599
|
"--api-key <key>",
|
|
7204
7600
|
"Login with an API key directly (non-interactive, for CI/CD)"
|
|
7205
|
-
).action(async (opts) => {
|
|
7601
|
+
).option("--org <slug|id|name>", "Select an organization non-interactively").action(async (opts) => {
|
|
7206
7602
|
try {
|
|
7207
|
-
await loginCommand({ apiKey: opts.apiKey });
|
|
7603
|
+
await loginCommand({ apiKey: opts.apiKey, org: opts.org });
|
|
7208
7604
|
process.exit(0);
|
|
7209
7605
|
} catch (error) {
|
|
7210
7606
|
console.error(
|
|
@@ -7272,7 +7668,7 @@ program.addCommand(createSkillsCommand());
|
|
|
7272
7668
|
program.command("generate-types").description(
|
|
7273
7669
|
"Generate TypeScript type definitions for tools (writes .mcp-use/tool-registry.d.ts)"
|
|
7274
7670
|
).option("-p, --path <path>", "Path to project directory", process.cwd()).option("--server <file>", "Server entry file", "index.ts").action(async (options) => {
|
|
7275
|
-
const projectPath =
|
|
7671
|
+
const projectPath = path8.resolve(options.path);
|
|
7276
7672
|
try {
|
|
7277
7673
|
console.log(source_default.blue("Generating tool registry types..."));
|
|
7278
7674
|
const success = await generateToolRegistryTypesForServer(
|