@cloudbase/cloudbase-mcp 2.10.0 → 2.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +3 -3
- package/dist/index.cjs +630 -76
- package/dist/index.js +108 -26
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -562,7 +562,7 @@ ${envIdSection}
|
|
|
562
562
|
## 环境信息
|
|
563
563
|
- 操作系统: ${os_1.default.type()} ${os_1.default.release()}
|
|
564
564
|
- Node.js版本: ${process.version}
|
|
565
|
-
- MCP 版本:${process.env.npm_package_version || "2.
|
|
565
|
+
- MCP 版本:${process.env.npm_package_version || "2.11.1" || 0}
|
|
566
566
|
- 系统架构: ${os_1.default.arch()}
|
|
567
567
|
- 时间: ${new Date().toISOString()}
|
|
568
568
|
- 请求ID: ${requestId}
|
|
@@ -971,11 +971,43 @@ exports.resetInteractiveServer = resetInteractiveServer;
|
|
|
971
971
|
exports.getInteractiveServerSafe = getInteractiveServerSafe;
|
|
972
972
|
const express_1 = __importDefault(__webpack_require__(2674));
|
|
973
973
|
const http_1 = __importDefault(__webpack_require__(3782));
|
|
974
|
+
const child_process_1 = __webpack_require__(5814);
|
|
974
975
|
const open_1 = __importDefault(__webpack_require__(1622));
|
|
975
976
|
const ws_1 = __webpack_require__(6220);
|
|
976
977
|
const index_js_1 = __webpack_require__(9529);
|
|
977
978
|
const logger_js_1 = __webpack_require__(3039);
|
|
978
|
-
|
|
979
|
+
function isVSCodeEnvironment() {
|
|
980
|
+
return Boolean(process.env.VSCODE_IPC_HOOK_CLI ||
|
|
981
|
+
process.env.VSCODE_PID ||
|
|
982
|
+
process.env.TERM_PROGRAM === "vscode");
|
|
983
|
+
}
|
|
984
|
+
function parseBrowserCommand(browser) {
|
|
985
|
+
const parts = browser.match(/(?:[^\s"]+|"[^"]*")+/g) || [];
|
|
986
|
+
return parts.map((item) => item.replace(/^"(.*)"$/, "$1"));
|
|
987
|
+
}
|
|
988
|
+
async function openUrlByBrowserEnv(url) {
|
|
989
|
+
const browser = process.env.BROWSER?.trim();
|
|
990
|
+
if (!browser) {
|
|
991
|
+
return false;
|
|
992
|
+
}
|
|
993
|
+
const [command, ...args] = parseBrowserCommand(browser);
|
|
994
|
+
if (!command) {
|
|
995
|
+
return false;
|
|
996
|
+
}
|
|
997
|
+
const finalArgs = args.map((arg) => (arg === "%s" ? url : arg));
|
|
998
|
+
if (!args.includes("%s")) {
|
|
999
|
+
finalArgs.push(url);
|
|
1000
|
+
}
|
|
1001
|
+
return new Promise((resolve) => {
|
|
1002
|
+
(0, child_process_1.execFile)(command, finalArgs, (execError) => {
|
|
1003
|
+
resolve(!execError);
|
|
1004
|
+
});
|
|
1005
|
+
});
|
|
1006
|
+
}
|
|
1007
|
+
function shouldUseBrowserEnvFallback() {
|
|
1008
|
+
return process.platform === "linux" && isVSCodeEnvironment();
|
|
1009
|
+
}
|
|
1010
|
+
// Dynamic open behavior with IDE awareness and VSCode/Linux fallback
|
|
979
1011
|
async function openUrl(url, options, mcpServer) {
|
|
980
1012
|
// mcpServer 是 ExtendedMcpServer 实例,它有 server 和 ide 属性
|
|
981
1013
|
// server 属性是 MCP server 的内部 server 实例,有 sendLoggingMessage 方法
|
|
@@ -1007,13 +1039,28 @@ async function openUrl(url, options, mcpServer) {
|
|
|
1007
1039
|
return;
|
|
1008
1040
|
}
|
|
1009
1041
|
}
|
|
1010
|
-
//
|
|
1042
|
+
// 默认行为:直接打开网页(带 VSCode/Linux 降级逻辑)
|
|
1011
1043
|
(0, logger_js_1.debug)(`[openUrl] Opening URL in browser: ${url}`);
|
|
1012
1044
|
try {
|
|
1013
|
-
|
|
1045
|
+
const openOptions = options ? { url: true, ...options } : { url: true };
|
|
1046
|
+
const child = await (0, open_1.default)(url, openOptions);
|
|
1047
|
+
if (child?.once) {
|
|
1048
|
+
child.once("error", async () => {
|
|
1049
|
+
if (shouldUseBrowserEnvFallback()) {
|
|
1050
|
+
(0, logger_js_1.debug)("[openUrl] open() failed, trying BROWSER fallback");
|
|
1051
|
+
await openUrlByBrowserEnv(url);
|
|
1052
|
+
}
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
1055
|
+
return;
|
|
1014
1056
|
}
|
|
1015
1057
|
catch (err) {
|
|
1016
1058
|
(0, logger_js_1.error)(`Failed to open ${url} ${options} ${err instanceof Error ? err.message : err} `, err instanceof Error ? err : new Error(String(err)));
|
|
1059
|
+
if (shouldUseBrowserEnvFallback()) {
|
|
1060
|
+
(0, logger_js_1.debug)("[openUrl] open() threw, trying BROWSER fallback");
|
|
1061
|
+
await openUrlByBrowserEnv(url);
|
|
1062
|
+
return;
|
|
1063
|
+
}
|
|
1017
1064
|
(0, logger_js_1.warn)(`Please manually open: ${url}`);
|
|
1018
1065
|
}
|
|
1019
1066
|
}
|
|
@@ -1038,10 +1085,15 @@ class InteractiveServer {
|
|
|
1038
1085
|
3722, 3723, 3724, 3725, 3726, 3727, 3728, 3729, 3730, 3731, 3732, 3733,
|
|
1039
1086
|
3734, 3735,
|
|
1040
1087
|
];
|
|
1088
|
+
/** Idle timeout for HTTP/WS connections (e.g. long login). Avoids "connection disconnected" after ~1 min. */
|
|
1089
|
+
static SERVER_IDLE_MS = 30 * 60 * 1000; // 30 minutes
|
|
1090
|
+
/** WebSocket ping interval to keep connection alive past proxies/firewalls. */
|
|
1091
|
+
static WS_PING_INTERVAL_MS = 25 * 1000; // 25 seconds
|
|
1041
1092
|
constructor(mcpServer) {
|
|
1042
1093
|
this._mcpServer = mcpServer;
|
|
1043
1094
|
this.app = (0, express_1.default)();
|
|
1044
1095
|
this.server = http_1.default.createServer(this.app);
|
|
1096
|
+
this.applyServerTimeouts();
|
|
1045
1097
|
this.wss = new ws_1.WebSocketServer({ server: this.server });
|
|
1046
1098
|
this.setupExpress();
|
|
1047
1099
|
this.setupWebSocket();
|
|
@@ -1057,6 +1109,16 @@ class InteractiveServer {
|
|
|
1057
1109
|
this.isRunning = false;
|
|
1058
1110
|
}
|
|
1059
1111
|
}
|
|
1112
|
+
/** Apply timeouts so long-lived login does not cause "connection disconnected". */
|
|
1113
|
+
applyServerTimeouts() {
|
|
1114
|
+
this.server.timeout = 0;
|
|
1115
|
+
if (typeof this.server.keepAliveTimeout === "number") {
|
|
1116
|
+
this.server.keepAliveTimeout = InteractiveServer.SERVER_IDLE_MS;
|
|
1117
|
+
}
|
|
1118
|
+
if (typeof this.server.headersTimeout === "number") {
|
|
1119
|
+
this.server.headersTimeout = Math.max(this.server.headersTimeout || 0, InteractiveServer.SERVER_IDLE_MS);
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1060
1122
|
setupExpress() {
|
|
1061
1123
|
this.app.use(express_1.default.json());
|
|
1062
1124
|
this.app.get("/env-setup/:sessionId", (req, res) => {
|
|
@@ -1160,6 +1222,16 @@ class InteractiveServer {
|
|
|
1160
1222
|
setupWebSocket() {
|
|
1161
1223
|
this.wss.on("connection", (ws) => {
|
|
1162
1224
|
(0, logger_js_1.debug)("WebSocket client connected");
|
|
1225
|
+
// Keep connection alive during long login so proxies/firewalls do not close it
|
|
1226
|
+
const pingInterval = setInterval(() => {
|
|
1227
|
+
if (ws.readyState === ws_1.WebSocket.OPEN) {
|
|
1228
|
+
ws.ping();
|
|
1229
|
+
}
|
|
1230
|
+
}, InteractiveServer.WS_PING_INTERVAL_MS);
|
|
1231
|
+
ws.on("close", () => {
|
|
1232
|
+
clearInterval(pingInterval);
|
|
1233
|
+
(0, logger_js_1.debug)("WebSocket client disconnected");
|
|
1234
|
+
});
|
|
1163
1235
|
ws.on("message", async (message) => {
|
|
1164
1236
|
try {
|
|
1165
1237
|
const data = JSON.parse(message.toString());
|
|
@@ -1269,9 +1341,6 @@ class InteractiveServer {
|
|
|
1269
1341
|
(0, logger_js_1.error)("WebSocket message parsing error", err instanceof Error ? err : new Error(String(err)));
|
|
1270
1342
|
}
|
|
1271
1343
|
});
|
|
1272
|
-
ws.on("close", () => {
|
|
1273
|
-
(0, logger_js_1.debug)("WebSocket client disconnected");
|
|
1274
|
-
});
|
|
1275
1344
|
});
|
|
1276
1345
|
}
|
|
1277
1346
|
async start() {
|
|
@@ -1313,13 +1382,15 @@ class InteractiveServer {
|
|
|
1313
1382
|
reject(err);
|
|
1314
1383
|
}
|
|
1315
1384
|
};
|
|
1385
|
+
// Host: default 0.0.0.0 so Cloud IDE / VSCode Remote port-forward can connect; set INTERACTIVE_SERVER_HOST=127.0.0.1 for local-only
|
|
1386
|
+
const host = process.env.INTERACTIVE_SERVER_HOST ?? "0.0.0.0";
|
|
1316
1387
|
// 设置成功监听处理
|
|
1317
1388
|
const listeningHandler = () => {
|
|
1318
1389
|
const address = this.server.address();
|
|
1319
1390
|
if (address && typeof address === "object") {
|
|
1320
1391
|
this.port = address.port;
|
|
1321
1392
|
this.isRunning = true;
|
|
1322
|
-
(0, logger_js_1.info)(`Interactive server started successfully on http
|
|
1393
|
+
(0, logger_js_1.info)(`Interactive server started successfully on http://${host}:${this.port}`);
|
|
1323
1394
|
// 移除临时监听器
|
|
1324
1395
|
this.server.removeListener("error", errorHandler);
|
|
1325
1396
|
this.server.removeListener("listening", listeningHandler);
|
|
@@ -1334,7 +1405,7 @@ class InteractiveServer {
|
|
|
1334
1405
|
this.server.once("error", errorHandler);
|
|
1335
1406
|
this.server.once("listening", listeningHandler);
|
|
1336
1407
|
try {
|
|
1337
|
-
this.server.listen(portToTry,
|
|
1408
|
+
this.server.listen(portToTry, host);
|
|
1338
1409
|
}
|
|
1339
1410
|
catch (err) {
|
|
1340
1411
|
(0, logger_js_1.error)(`Failed to bind to port ${portToTry}:`, err instanceof Error ? err : new Error(String(err)));
|
|
@@ -1375,6 +1446,7 @@ class InteractiveServer {
|
|
|
1375
1446
|
this.port = 0;
|
|
1376
1447
|
// 重新创建整个服务器实例以便下次使用
|
|
1377
1448
|
this.server = http_1.default.createServer(this.app);
|
|
1449
|
+
this.applyServerTimeouts();
|
|
1378
1450
|
this.wss = new ws_1.WebSocketServer({ server: this.server });
|
|
1379
1451
|
this.setupWebSocket();
|
|
1380
1452
|
(0, logger_js_1.debug)("HTTP and WebSocket servers recreated for next use");
|
|
@@ -1465,11 +1537,9 @@ class InteractiveServer {
|
|
|
1465
1537
|
(0, logger_js_1.warn)(`Please manually open: ${url}`);
|
|
1466
1538
|
}
|
|
1467
1539
|
(0, logger_js_1.info)("Waiting for user selection...");
|
|
1468
|
-
// Use
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
const timeoutDuration = (isCodeBuddy && notificationSent) ? 2 * 60 * 1000 : 10 * 60 * 1000;
|
|
1472
|
-
(0, logger_js_1.debug)(`[collectEnvId] Using timeout duration: ${timeoutDuration / 1000} seconds (CodeBuddy: ${isCodeBuddy}, notification sent: ${notificationSent})`);
|
|
1540
|
+
// Use same 10 minutes for all IDEs so long login (re-auth, switch account) does not close the server
|
|
1541
|
+
const timeoutDuration = 10 * 60 * 1000;
|
|
1542
|
+
(0, logger_js_1.debug)(`[collectEnvId] Using timeout duration: ${timeoutDuration / 1000} seconds`);
|
|
1473
1543
|
return new Promise((resolve) => {
|
|
1474
1544
|
this.currentResolver = (result) => {
|
|
1475
1545
|
// 用户选择完成后,关闭服务器
|
|
@@ -5267,8 +5337,11 @@ checkIndex: 检查索引是否存在`),
|
|
|
5267
5337
|
title: "修改 NoSQL 数据库结构",
|
|
5268
5338
|
description: "修改 NoSQL 数据库结构",
|
|
5269
5339
|
inputSchema: {
|
|
5270
|
-
action: zod_1.z.enum([
|
|
5271
|
-
|
|
5340
|
+
action: zod_1.z.enum([
|
|
5341
|
+
"createCollection",
|
|
5342
|
+
"updateCollection",
|
|
5343
|
+
"deleteCollection",
|
|
5344
|
+
]).describe(`createCollection: 创建集合
|
|
5272
5345
|
updateCollection: 更新集合
|
|
5273
5346
|
deleteCollection: 删除集合`),
|
|
5274
5347
|
collectionName: zod_1.z.string().describe("集合名称"),
|
|
@@ -5348,9 +5421,7 @@ deleteCollection: 删除集合`),
|
|
|
5348
5421
|
success: true,
|
|
5349
5422
|
requestId: result.RequestId,
|
|
5350
5423
|
action,
|
|
5351
|
-
message: result.Exists === false
|
|
5352
|
-
? "集合不存在"
|
|
5353
|
-
: "云开发数据库集合删除成功",
|
|
5424
|
+
message: result.Exists === false ? "集合不存在" : "云开发数据库集合删除成功",
|
|
5354
5425
|
};
|
|
5355
5426
|
if (result.Exists === false) {
|
|
5356
5427
|
body.exists = false;
|
|
@@ -5381,9 +5452,17 @@ deleteCollection: 删除集合`),
|
|
|
5381
5452
|
.optional()
|
|
5382
5453
|
.describe("返回字段投影(对象或字符串,推荐对象)"),
|
|
5383
5454
|
sort: zod_1.z
|
|
5384
|
-
.union([
|
|
5455
|
+
.union([
|
|
5456
|
+
zod_1.z.array(zod_1.z
|
|
5457
|
+
.object({
|
|
5458
|
+
key: zod_1.z.string().describe("sort 字段名"),
|
|
5459
|
+
direction: zod_1.z.number().describe("排序方向,1:升序,-1:降序"),
|
|
5460
|
+
})
|
|
5461
|
+
.passthrough()),
|
|
5462
|
+
zod_1.z.string(),
|
|
5463
|
+
])
|
|
5385
5464
|
.optional()
|
|
5386
|
-
.describe("
|
|
5465
|
+
.describe("排序条件,使用对象或字符串。"),
|
|
5387
5466
|
limit: zod_1.z.number().optional().describe("返回数量限制"),
|
|
5388
5467
|
offset: zod_1.z.number().optional().describe("跳过的记录数"),
|
|
5389
5468
|
},
|
|
@@ -5429,7 +5508,8 @@ deleteCollection: 删除集合`),
|
|
|
5429
5508
|
title: "修改 NoSQL 数据库数据记录",
|
|
5430
5509
|
description: "修改 NoSQL 数据库数据记录",
|
|
5431
5510
|
inputSchema: {
|
|
5432
|
-
action: zod_1.z
|
|
5511
|
+
action: zod_1.z
|
|
5512
|
+
.enum(["insert", "update", "delete"])
|
|
5433
5513
|
.describe(`insert: 插入数据(新增文档)\nupdate: 更新数据\ndelete: 删除数据`),
|
|
5434
5514
|
collectionName: zod_1.z.string().describe("集合名称"),
|
|
5435
5515
|
documents: zod_1.z
|
|
@@ -8606,7 +8686,7 @@ class TelemetryReporter {
|
|
|
8606
8686
|
const nodeVersion = process.version; // Node.js版本
|
|
8607
8687
|
const arch = os_1.default.arch(); // 系统架构
|
|
8608
8688
|
// 从构建时注入的版本号获取MCP版本信息
|
|
8609
|
-
const mcpVersion = process.env.npm_package_version || "2.
|
|
8689
|
+
const mcpVersion = process.env.npm_package_version || "2.11.1" || 0;
|
|
8610
8690
|
return {
|
|
8611
8691
|
userAgent: `${osType} ${osRelease} ${arch} ${nodeVersion} CloudBase-MCP/${mcpVersion}`,
|
|
8612
8692
|
deviceId: this.deviceId,
|
|
@@ -10039,7 +10119,7 @@ function registerSetupTools(server) {
|
|
|
10039
10119
|
title: "下载项目模板",
|
|
10040
10120
|
description: `自动下载并部署CloudBase项目模板。⚠️ **MANDATORY FOR NEW PROJECTS** ⚠️
|
|
10041
10121
|
|
|
10042
|
-
**CRITICAL**: This tool MUST be called FIRST when starting a new project.\n\n支持的模板:\n- react: React + CloudBase 全栈应用模板\n- vue: Vue + CloudBase 全栈应用模板\n- miniprogram: 微信小程序 + 云开发模板 \n- uniapp: UniApp + CloudBase 跨端应用模板\n- rules: 只包含AI编辑器配置文件(包含Cursor、WindSurf、CodeBuddy等所有主流编辑器配置),适合在已有项目中补充AI编辑器配置\n\n支持的IDE类型:\n- all: 下载所有IDE配置\n- cursor: Cursor AI编辑器\n- 其他IDE类型见下方列表\n\n注意:如果未传入 ide 参数且无法从环境变量检测到 IDE,将提示错误并要求传入 ide 参数\n- windsurf: WindSurf AI编辑器\n- codebuddy: CodeBuddy AI编辑器\n- claude-code: Claude Code AI编辑器\n- cline: Cline AI编辑器\n- gemini-cli: Gemini CLI\n- opencode: OpenCode AI编辑器\n- qwen-code: 通义灵码\n- baidu-comate: 百度Comate\n- openai-codex-cli: OpenAI Codex CLI\n- augment-code: Augment Code\n- github-copilot: GitHub Copilot\n- roocode: RooCode AI编辑器\n- tongyi-lingma: 通义灵码\n- trae: Trae AI编辑器\n- qoder: Qoder AI编辑器\n- antigravity: Google Antigravity AI编辑器\n- vscode: Visual Studio Code\n- kiro: Kiro AI编辑器\n- aider: Aider AI编辑器\n\n特别说明:\n- rules 模板会自动包含当前 mcp 版本号信息(版本号:${ true ? "2.
|
|
10122
|
+
**CRITICAL**: This tool MUST be called FIRST when starting a new project.\n\n支持的模板:\n- react: React + CloudBase 全栈应用模板\n- vue: Vue + CloudBase 全栈应用模板\n- miniprogram: 微信小程序 + 云开发模板 \n- uniapp: UniApp + CloudBase 跨端应用模板\n- rules: 只包含AI编辑器配置文件(包含Cursor、WindSurf、CodeBuddy等所有主流编辑器配置),适合在已有项目中补充AI编辑器配置\n\n支持的IDE类型:\n- all: 下载所有IDE配置\n- cursor: Cursor AI编辑器\n- 其他IDE类型见下方列表\n\n注意:如果未传入 ide 参数且无法从环境变量检测到 IDE,将提示错误并要求传入 ide 参数\n- windsurf: WindSurf AI编辑器\n- codebuddy: CodeBuddy AI编辑器\n- claude-code: Claude Code AI编辑器\n- cline: Cline AI编辑器\n- gemini-cli: Gemini CLI\n- opencode: OpenCode AI编辑器\n- qwen-code: 通义灵码\n- baidu-comate: 百度Comate\n- openai-codex-cli: OpenAI Codex CLI\n- augment-code: Augment Code\n- github-copilot: GitHub Copilot\n- roocode: RooCode AI编辑器\n- tongyi-lingma: 通义灵码\n- trae: Trae AI编辑器\n- qoder: Qoder AI编辑器\n- antigravity: Google Antigravity AI编辑器\n- vscode: Visual Studio Code\n- kiro: Kiro AI编辑器\n- aider: Aider AI编辑器\n\n特别说明:\n- rules 模板会自动包含当前 mcp 版本号信息(版本号:${ true ? "2.11.1" : 0}),便于后续维护和版本追踪\n- 下载 rules 模板时,如果项目中已存在 README.md 文件,系统会自动保护该文件不被覆盖(除非设置 overwrite=true)`,
|
|
10043
10123
|
inputSchema: {
|
|
10044
10124
|
template: zod_1.z
|
|
10045
10125
|
.enum(["react", "vue", "miniprogram", "uniapp", "rules"])
|
|
@@ -11448,8 +11528,10 @@ function getJavaScripts(wsPort) {
|
|
|
11448
11528
|
}
|
|
11449
11529
|
}
|
|
11450
11530
|
|
|
11451
|
-
// WebSocket
|
|
11452
|
-
const
|
|
11531
|
+
// WebSocket: same host as page so it works in remote VS Code / Cloud IDE (no localhost)
|
|
11532
|
+
const wsScheme = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
11533
|
+
const wsUrl = wsScheme + '//' + window.location.host;
|
|
11534
|
+
const ws = new WebSocket(wsUrl);
|
|
11453
11535
|
|
|
11454
11536
|
ws.onopen = () => {
|
|
11455
11537
|
console.log('[env-setup] WebSocket connected');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudbase/cloudbase-mcp",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.11.1",
|
|
4
4
|
"description": "腾讯云开发 MCP Server,通过AI提示词和MCP协议+云开发,让开发更智能、更高效,当你在Cursor/ VSCode GitHub Copilot/WinSurf/CodeBuddy/Augment Code/Claude Code等AI编程工具里写代码时,它能自动帮你生成可直接部署的前后端应用+小程序,并一键发布到腾讯云开发 CloudBase。",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.js",
|