@cloudbase/cloudbase-mcp 2.23.5 → 2.23.7
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 +207 -57
- package/dist/index.js +207 -57
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -261,13 +261,14 @@ async function fetchAvailableEnvCandidates(cloudBaseOptions, server) {
|
|
|
261
261
|
return [];
|
|
262
262
|
}
|
|
263
263
|
}
|
|
264
|
-
const CODEBUDDY_AUTH_ACTIONS = ["status", "set_env"];
|
|
264
|
+
const CODEBUDDY_AUTH_ACTIONS = ["status", "set_env", "login_by_api_key"];
|
|
265
265
|
const DEFAULT_AUTH_ACTIONS = [
|
|
266
266
|
"status",
|
|
267
267
|
"start_auth",
|
|
268
268
|
"set_env",
|
|
269
269
|
"logout",
|
|
270
270
|
"get_temp_credentials",
|
|
271
|
+
"login_by_api_key",
|
|
271
272
|
];
|
|
272
273
|
function maskSensitiveValue(value) {
|
|
273
274
|
if (value.length <= 4) {
|
|
@@ -593,7 +594,7 @@ async function enrichEnvInfoWithBilling(params) {
|
|
|
593
594
|
* for new code, including an explicit `MysqlNotAvailable` line when
|
|
594
595
|
* MySQL is absent — that one IS a hard "do not use" signal.
|
|
595
596
|
*/
|
|
596
|
-
function enrichEnvInfoWithRuntimeMode(result) {
|
|
597
|
+
async function enrichEnvInfoWithRuntimeMode(result, manager) {
|
|
597
598
|
const envInfo = result?.EnvInfo;
|
|
598
599
|
if (!envInfo || typeof envInfo !== "object") {
|
|
599
600
|
return result;
|
|
@@ -623,7 +624,29 @@ function enrichEnvInfoWithRuntimeMode(result) {
|
|
|
623
624
|
}
|
|
624
625
|
return [];
|
|
625
626
|
})();
|
|
626
|
-
|
|
627
|
+
let hasMysql = mysqlList.length > 0;
|
|
628
|
+
// Fallback: if MySQL not detected from DescribeEnvInfo fields, probe via
|
|
629
|
+
// DescribeMySQLClusterDetail (dedicated MySQL API). This covers cases where
|
|
630
|
+
// the SDK strips MySQL fields from the DescribeEnvInfo response.
|
|
631
|
+
if (!hasMysql && manager?.commonService) {
|
|
632
|
+
try {
|
|
633
|
+
const probeResult = await manager
|
|
634
|
+
.commonService("tcb", "2018-06-08")
|
|
635
|
+
.call({
|
|
636
|
+
Action: "DescribeMySQLClusterDetail",
|
|
637
|
+
Param: { EnvId: envInfo.EnvId },
|
|
638
|
+
});
|
|
639
|
+
const clusterId = probeResult?.DbClusterId ||
|
|
640
|
+
probeResult?.Response?.DbClusterId ||
|
|
641
|
+
probeResult?.Data?.DbClusterId;
|
|
642
|
+
if (clusterId) {
|
|
643
|
+
hasMysql = true;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
catch {
|
|
647
|
+
// Probe failure means MySQL is not provisioned — keep hasMysql = false
|
|
648
|
+
}
|
|
649
|
+
}
|
|
627
650
|
// Primary mode: prefer PG when it is provisioned, otherwise fall back to
|
|
628
651
|
// legacy NoSQL labeling. This drives "what skill to read first / what API
|
|
629
652
|
// to reach for when starting new business code".
|
|
@@ -641,7 +664,7 @@ function enrichEnvInfoWithRuntimeMode(result) {
|
|
|
641
664
|
: "No legacy NoSQL Database/Storage observed in this env.",
|
|
642
665
|
MysqlNotAvailable: hasMysql
|
|
643
666
|
? "MySQL instance(s) detected — see EnvInfo.MysqlInstances."
|
|
644
|
-
: "No MySQL instance is provisioned for this env. Do NOT use `
|
|
667
|
+
: "No MySQL instance is provisioned for this env. Do NOT use `manageMysqlDatabase` / `queryMysqlDatabase` (those are MySQL-specific) and do NOT read the `relational-database-tool` skill — that family targets MySQL, not CloudBase PG.",
|
|
645
668
|
RecommendedSkills: "Read `postgresql-development` first for new PG code. `no-sql-web-sdk` is still applicable for existing NoSQL collections in this env. Skip `relational-database-tool` (MySQL-only) entirely.",
|
|
646
669
|
}
|
|
647
670
|
: {
|
|
@@ -651,7 +674,7 @@ function enrichEnvInfoWithRuntimeMode(result) {
|
|
|
651
674
|
Storage: "Browser uploads use `app.uploadFile()` against the bucket exposed in `EnvInfo.Storages[].Bucket`.",
|
|
652
675
|
MysqlNotAvailable: hasMysql
|
|
653
676
|
? "MySQL instance(s) detected — see EnvInfo.MysqlInstances."
|
|
654
|
-
: "No MySQL instance in this env. `
|
|
677
|
+
: "No MySQL instance in this env. `manageMysqlDatabase` / `queryMysqlDatabase` and the `relational-database-tool` skill are not applicable.",
|
|
655
678
|
RecommendedSkills: "Read `no-sql-web-sdk` (and `cloud-storage-web` for uploads). `postgresql-development` and `relational-database-tool` are not applicable to this env.",
|
|
656
679
|
};
|
|
657
680
|
return {
|
|
@@ -802,12 +825,12 @@ function registerEnvTools(server) {
|
|
|
802
825
|
if (server.ide !== 'wxide') {
|
|
803
826
|
server.registerTool?.("auth", {
|
|
804
827
|
title: "CloudBase 开发阶段登录与环境",
|
|
805
|
-
description: "CloudBase(腾讯云开发)开发阶段登录与环境绑定。登录后即可访问云资源;环境(env)是云函数、数据库、静态托管等资源的隔离单元,绑定环境后其他 MCP
|
|
828
|
+
description: "CloudBase(腾讯云开发)开发阶段登录与环境绑定。登录后即可访问云资源;环境(env)是云函数、数据库、静态托管等资源的隔离单元,绑定环境后其他 MCP 工具才能操作该环境。支持:查询状态、发起登录、API Key登录、绑定环境(set_env)、退出登录。",
|
|
806
829
|
inputSchema: {
|
|
807
830
|
action: zod_1.z
|
|
808
831
|
.enum(authActionEnum)
|
|
809
832
|
.optional()
|
|
810
|
-
.describe("动作:status=查询状态,start_auth=发起登录,set_env=绑定环境(传envId),logout=退出登录"),
|
|
833
|
+
.describe("动作:status=查询状态,start_auth=发起登录,login_by_api_key=API Key登录,set_env=绑定环境(传envId),logout=退出登录"),
|
|
811
834
|
...(supportedAuthActions.includes("start_auth")
|
|
812
835
|
? {
|
|
813
836
|
authMode: zod_1.z
|
|
@@ -832,6 +855,18 @@ function registerEnvTools(server) {
|
|
|
832
855
|
.string()
|
|
833
856
|
.optional()
|
|
834
857
|
.describe("环境ID(CloudBase 环境唯一标识),绑定后工具将操作该环境。action=set_env 时必填"),
|
|
858
|
+
...(supportedAuthActions.includes("login_by_api_key")
|
|
859
|
+
? {
|
|
860
|
+
apiKey: zod_1.z
|
|
861
|
+
.string()
|
|
862
|
+
.optional()
|
|
863
|
+
.describe("CloudBase API Key,action=login_by_api_key 时必填"),
|
|
864
|
+
apiKeyEnvId: zod_1.z
|
|
865
|
+
.string()
|
|
866
|
+
.optional()
|
|
867
|
+
.describe("CloudBase 环境ID(EnvId),action=login_by_api_key 时必填,用于指定 API Key 所属环境"),
|
|
868
|
+
}
|
|
869
|
+
: {}),
|
|
835
870
|
...(supportedAuthActions.includes("logout")
|
|
836
871
|
? {
|
|
837
872
|
confirm: zod_1.z
|
|
@@ -1147,6 +1182,78 @@ function registerEnvTools(server) {
|
|
|
1147
1182
|
next_step: envPreparation.nextStep,
|
|
1148
1183
|
});
|
|
1149
1184
|
}
|
|
1185
|
+
if (action === "login_by_api_key") {
|
|
1186
|
+
const toolApiKey = normalizeOptionalToolString(rawArgs.apiKey);
|
|
1187
|
+
const toolApiKeyEnvId = normalizeOptionalToolString(rawArgs.apiKeyEnvId);
|
|
1188
|
+
if (!toolApiKey || !toolApiKeyEnvId) {
|
|
1189
|
+
return (0, tool_result_js_1.buildJsonToolResult)({
|
|
1190
|
+
ok: false,
|
|
1191
|
+
code: "INVALID_ARGS",
|
|
1192
|
+
message: "action=login_by_api_key 时必须同时提供 apiKey 和 envId。",
|
|
1193
|
+
next_step: (0, tool_result_js_1.buildAuthNextStep)("login_by_api_key", {
|
|
1194
|
+
suggestedArgs: { action: "login_by_api_key", apiKey: "<your-api-key>", envId: "<your-env-id>" },
|
|
1195
|
+
}),
|
|
1196
|
+
});
|
|
1197
|
+
}
|
|
1198
|
+
// 写入 process.env(与 cli.ts 处理 --api-key/--env-id 的逻辑一致)
|
|
1199
|
+
process.env.CLOUDBASE_API_KEY = toolApiKey;
|
|
1200
|
+
process.env.CLOUDBASE_ENV_ID = toolApiKeyEnvId;
|
|
1201
|
+
try {
|
|
1202
|
+
const loginState = await (0, auth_js_1.peekLoginState)();
|
|
1203
|
+
if (loginState) {
|
|
1204
|
+
const envPreparation = await prepareAuthEnvironment({
|
|
1205
|
+
server,
|
|
1206
|
+
cloudBaseOptions,
|
|
1207
|
+
loginState,
|
|
1208
|
+
});
|
|
1209
|
+
return (0, tool_result_js_1.buildJsonToolResult)({
|
|
1210
|
+
ok: true,
|
|
1211
|
+
code: "AUTH_READY",
|
|
1212
|
+
message: "API Key 认证成功,已获取临时密钥。",
|
|
1213
|
+
auth_mode: "api_key",
|
|
1214
|
+
...buildAuthEnvSetupPayload(envPreparation),
|
|
1215
|
+
next_step: envPreparation.nextStep,
|
|
1216
|
+
});
|
|
1217
|
+
}
|
|
1218
|
+
// API Key 换取失败:清理 env vars 并返回诊断信息
|
|
1219
|
+
delete process.env.CLOUDBASE_API_KEY;
|
|
1220
|
+
delete process.env.CLOUDBASE_ENV_ID;
|
|
1221
|
+
let diagMessage = "API Key 换取临时密钥失败。";
|
|
1222
|
+
diagMessage += `\n\n诊断信息:`;
|
|
1223
|
+
diagMessage += `\n- CLOUDBASE_ENV_ID: ${toolApiKeyEnvId}`;
|
|
1224
|
+
diagMessage += `\n- CLOUDBASE_API_KEY: ${toolApiKey.slice(0, 20)}...(已截断)`;
|
|
1225
|
+
diagMessage += `\n\n可能原因:`;
|
|
1226
|
+
diagMessage += `\n1. API Key 已过期或被删除`;
|
|
1227
|
+
diagMessage += `\n2. CLOUDBASE_ENV_ID 与 API Key 所属环境不匹配`;
|
|
1228
|
+
diagMessage += `\n3. 网络连接问题`;
|
|
1229
|
+
diagMessage += `\n\n建议:请检查 API Key 和环境 ID 是否正确。`;
|
|
1230
|
+
return (0, tool_result_js_1.buildJsonToolResult)({
|
|
1231
|
+
ok: false,
|
|
1232
|
+
code: "API_KEY_AUTH_FAILED",
|
|
1233
|
+
message: diagMessage,
|
|
1234
|
+
auth_mode: "api_key",
|
|
1235
|
+
envId: toolApiKeyEnvId,
|
|
1236
|
+
next_step: (0, tool_result_js_1.buildAuthNextStep)("login_by_api_key", {
|
|
1237
|
+
suggestedArgs: { action: "login_by_api_key", apiKey: "<your-api-key>", envId: "<your-env-id>" },
|
|
1238
|
+
}),
|
|
1239
|
+
});
|
|
1240
|
+
}
|
|
1241
|
+
catch (error) {
|
|
1242
|
+
// 异常时清理 env vars
|
|
1243
|
+
delete process.env.CLOUDBASE_API_KEY;
|
|
1244
|
+
delete process.env.CLOUDBASE_ENV_ID;
|
|
1245
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1246
|
+
return (0, tool_result_js_1.buildJsonToolResult)({
|
|
1247
|
+
ok: false,
|
|
1248
|
+
code: "API_KEY_AUTH_FAILED",
|
|
1249
|
+
message: `API Key 认证异常: ${message}`,
|
|
1250
|
+
auth_mode: "api_key",
|
|
1251
|
+
next_step: (0, tool_result_js_1.buildAuthNextStep)("login_by_api_key", {
|
|
1252
|
+
suggestedArgs: { action: "login_by_api_key", apiKey: "<your-api-key>", envId: "<your-env-id>" },
|
|
1253
|
+
}),
|
|
1254
|
+
});
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1150
1257
|
if (action === "set_env") {
|
|
1151
1258
|
const loginState = await (0, auth_js_1.peekLoginState)();
|
|
1152
1259
|
if (!loginState) {
|
|
@@ -1415,7 +1522,7 @@ function registerEnvTools(server) {
|
|
|
1415
1522
|
if (envId) {
|
|
1416
1523
|
result = await enrichEnvInfoWithMissingFields(cloudbaseInfo, result, envId);
|
|
1417
1524
|
}
|
|
1418
|
-
result = enrichEnvInfoWithRuntimeMode(result);
|
|
1525
|
+
result = await enrichEnvInfoWithRuntimeMode(result, cloudbaseInfo);
|
|
1419
1526
|
break;
|
|
1420
1527
|
case "domains":
|
|
1421
1528
|
const cloudbaseDomains = await getManager();
|
|
@@ -1483,7 +1590,7 @@ function registerEnvTools(server) {
|
|
|
1483
1590
|
// Register primary tool name (queryEnv)
|
|
1484
1591
|
const queryEnvToolSchema = {
|
|
1485
1592
|
title: "CloudBase 环境查询",
|
|
1486
|
-
description: "查询 CloudBase 环境相关信息,支持查询环境列表、指定环境详情和安全域名。(曾用名:envQuery、listEnvs、getEnvInfo、getEnvAuthDomains)当 action=list 时,会按 DescribeEnvs 语义做列表/筛选,标准返回字段为 EnvId、Alias、Status、EnvType、Region、PackageId、PackageName、IsDefault,并支持通过 fields 白名单裁剪这些字段;aliasExact=true 时会按别名精确筛选,避免把前缀相近的环境误当作候选;即使传入 envId,action=list 也只返回摘要,不会返回完整资源明细或 expiry。如需查询某个已知 EnvId 对应环境的详细信息(包括资源字段和计费信息),必须使用 action=info 并传入目标环境的 envId 参数。action=info 会在可用时补充 BillingInfo(如 ExpireTime、PayMode、IsAutoRenew 等计费字段)。\n\n🔍 action=info 还会派生三个用于后端选型的字段:\n- `EnvInfo.RuntimeMode`:'postgresql' 或 'nosql',表示新业务建议默认使用的后端(PG 已开通时为 postgresql,否则为 nosql)。\n- `EnvInfo.RuntimeBackends`:`{postgresql, nosql, mysql}` 三个布尔值,描述当前环境实际并存的后端。\n- `EnvInfo.RuntimeModeHints`:每个后端对应的 API/工具/skill 提示。\n\nAI 在写业务/权限/存储代码前必须先看这三项:PG 模式下新业务推荐 `app.rdb()` + RLS(`managePgDatabase action=execute` 跑 `CREATE POLICY`)+ pgstore;已存在的 NoSQL 集合 / 旧 storage / `managePermissions(resourceType=\"noSqlDatabase\")` 在 PG 环境下仍然有效。真正不适用的是 MySQL:当 `RuntimeBackends.mysql === false` 时,`
|
|
1593
|
+
description: "查询 CloudBase 环境相关信息,支持查询环境列表、指定环境详情和安全域名。(曾用名:envQuery、listEnvs、getEnvInfo、getEnvAuthDomains)当 action=list 时,会按 DescribeEnvs 语义做列表/筛选,标准返回字段为 EnvId、Alias、Status、EnvType、Region、PackageId、PackageName、IsDefault,并支持通过 fields 白名单裁剪这些字段;aliasExact=true 时会按别名精确筛选,避免把前缀相近的环境误当作候选;即使传入 envId,action=list 也只返回摘要,不会返回完整资源明细或 expiry。如需查询某个已知 EnvId 对应环境的详细信息(包括资源字段和计费信息),必须使用 action=info 并传入目标环境的 envId 参数。action=info 会在可用时补充 BillingInfo(如 ExpireTime、PayMode、IsAutoRenew 等计费字段)。\n\n🔍 action=info 还会派生三个用于后端选型的字段:\n- `EnvInfo.RuntimeMode`:'postgresql' 或 'nosql',表示新业务建议默认使用的后端(PG 已开通时为 postgresql,否则为 nosql)。\n- `EnvInfo.RuntimeBackends`:`{postgresql, nosql, mysql}` 三个布尔值,描述当前环境实际并存的后端。\n- `EnvInfo.RuntimeModeHints`:每个后端对应的 API/工具/skill 提示。\n\nAI 在写业务/权限/存储代码前必须先看这三项:PG 模式下新业务推荐 `app.rdb()` + RLS(`managePgDatabase action=execute` 跑 `CREATE POLICY`)+ pgstore;已存在的 NoSQL 集合 / 旧 storage / `managePermissions(resourceType=\"noSqlDatabase\")` 在 PG 环境下仍然有效。真正不适用的是 MySQL:当 `RuntimeBackends.mysql === false` 时,`manageMysqlDatabase` / `queryMysqlDatabase` / `relational-database-tool` skill 都不该使用。",
|
|
1487
1594
|
inputSchema: {
|
|
1488
1595
|
action: zod_1.z
|
|
1489
1596
|
.enum(["list", "info", "domains"])
|
|
@@ -2095,7 +2202,7 @@ ${envIdSection}
|
|
|
2095
2202
|
## 环境信息
|
|
2096
2203
|
- 操作系统: ${os_1.default.type()} ${os_1.default.release()}
|
|
2097
2204
|
- Node.js版本: ${process.version}
|
|
2098
|
-
- MCP 版本:${process.env.npm_package_version || "2.23.
|
|
2205
|
+
- MCP 版本:${process.env.npm_package_version || "2.23.7" || 0}
|
|
2099
2206
|
- 系统架构: ${os_1.default.arch()}
|
|
2100
2207
|
- 时间: ${new Date().toISOString()}
|
|
2101
2208
|
- 请求ID: ${requestId}
|
|
@@ -2176,7 +2283,7 @@ function createWrappedHandler(name, handler, server) {
|
|
|
2176
2283
|
requestId: (typeof error === 'object' && error && 'requestId' in error) ? error.requestId : '',
|
|
2177
2284
|
ide: server.ide || process.env.INTEGRATION_IDE || ''
|
|
2178
2285
|
});
|
|
2179
|
-
const mcpVersion = true ? "2.23.
|
|
2286
|
+
const mcpVersion = true ? "2.23.7" : 0;
|
|
2180
2287
|
const requestIdSuffix = requestId ? `\n🆔 RequestId: ${requestId}` : '';
|
|
2181
2288
|
const enhancedErrorMessage = `${errorMessage}${requestIdSuffix}\n\n📦 CloudBase MCP v${mcpVersion}\n🔗 遇到问题?请复制以下链接到浏览器打开\n即可自动携带错误详情快速创建 GitHub Issue:\n${issueLink}`;
|
|
2182
2289
|
// 创建新的错误对象,保持原有的错误类型但更新消息
|
|
@@ -2361,6 +2468,7 @@ const DEFAULT_PLUGINS = [
|
|
|
2361
2468
|
"database",
|
|
2362
2469
|
"pg_database",
|
|
2363
2470
|
"pg_storage",
|
|
2471
|
+
"mysql_database",
|
|
2364
2472
|
"functions",
|
|
2365
2473
|
"hosting",
|
|
2366
2474
|
"storage",
|
|
@@ -2383,10 +2491,6 @@ function registerDatabase(server) {
|
|
|
2383
2491
|
if (!(0, tencent_cloud_js_1.isInternationalRegion)(region)) {
|
|
2384
2492
|
(0, databaseNoSQL_js_1.registerDatabaseTools)(server);
|
|
2385
2493
|
}
|
|
2386
|
-
const pgPluginEnabled = server.enabledPlugins?.some((pluginName) => pluginName === "pg_database" || pluginName === "pg_storage");
|
|
2387
|
-
if (!pgPluginEnabled) {
|
|
2388
|
-
(0, databaseSQL_js_1.registerSQLDatabaseTools)(server);
|
|
2389
|
-
}
|
|
2390
2494
|
(0, dataModel_js_1.registerDataModelTools)(server);
|
|
2391
2495
|
}
|
|
2392
2496
|
function registerMysqlDatabase(server) {
|
|
@@ -7348,6 +7452,7 @@ function registerGatewayTools(server) {
|
|
|
7348
7452
|
const cloudbase = await getManager();
|
|
7349
7453
|
const accessPath = input.path ? normalizeAccessPath(input.path) : undefined;
|
|
7350
7454
|
let resolvedAccessId = input.accessId;
|
|
7455
|
+
let resolvedName;
|
|
7351
7456
|
if (!resolvedAccessId) {
|
|
7352
7457
|
if (!input.targetName && !accessPath) {
|
|
7353
7458
|
throw new Error("action=deleteAccess 时至少需要提供 accessId,或提供 targetName/path 用于定位入口");
|
|
@@ -7369,18 +7474,32 @@ function registerGatewayTools(server) {
|
|
|
7369
7474
|
throw new Error("匹配到多个访问入口,请补充 path 或直接传 accessId");
|
|
7370
7475
|
}
|
|
7371
7476
|
resolvedAccessId = candidates[0]?.APIId;
|
|
7477
|
+
resolvedName = candidates[0]?.Name;
|
|
7478
|
+
}
|
|
7479
|
+
else {
|
|
7480
|
+
// 仅传入 accessId 时,先查询获取 name 等信息,确保删除参数完整
|
|
7481
|
+
try {
|
|
7482
|
+
const accessList = await cloudbase.access.getAccessList({});
|
|
7483
|
+
const match = (accessList.APISet ?? []).find((item) => item.APIId === resolvedAccessId);
|
|
7484
|
+
if (match) {
|
|
7485
|
+
resolvedName = match.Name;
|
|
7486
|
+
}
|
|
7487
|
+
}
|
|
7488
|
+
catch {
|
|
7489
|
+
// 查询失败不影响主流程,继续用 accessId 删除
|
|
7490
|
+
}
|
|
7372
7491
|
}
|
|
7373
7492
|
if (!resolvedAccessId) {
|
|
7374
7493
|
throw new Error("无法解析访问入口 accessId,请改为显式传入 accessId");
|
|
7375
7494
|
}
|
|
7376
7495
|
const result = await cloudbase.access.deleteAccess({
|
|
7377
|
-
...(
|
|
7496
|
+
...(resolvedName ? { name: resolvedName } : {}),
|
|
7378
7497
|
apiId: resolvedAccessId,
|
|
7379
7498
|
});
|
|
7380
7499
|
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
|
|
7381
7500
|
return buildEnvelope({
|
|
7382
7501
|
action: input.action,
|
|
7383
|
-
targetName: input.targetName ?? null,
|
|
7502
|
+
targetName: resolvedName ?? input.targetName ?? null,
|
|
7384
7503
|
path: accessPath ?? null,
|
|
7385
7504
|
accessId: resolvedAccessId,
|
|
7386
7505
|
raw: result,
|
|
@@ -8212,18 +8331,31 @@ function checkIfAgentProject(projectPath) {
|
|
|
8212
8331
|
}
|
|
8213
8332
|
}
|
|
8214
8333
|
/**
|
|
8215
|
-
* Validate and normalize file path
|
|
8334
|
+
* Validate and normalize file path.
|
|
8335
|
+
* Accepts absolute paths as-is; for relative paths, resolves against CWD and
|
|
8336
|
+
* ensures the result does not escape the CWD (path-traversal protection).
|
|
8216
8337
|
* @param inputPath User provided path
|
|
8217
8338
|
* @returns Absolute path
|
|
8218
8339
|
*/
|
|
8219
8340
|
function validateAndNormalizePath(inputPath) {
|
|
8220
|
-
|
|
8221
|
-
//
|
|
8341
|
+
const normalizedPath = path_1.default.resolve(inputPath);
|
|
8342
|
+
// On Windows, path.resolve may return a path on a different drive/UNC share.
|
|
8343
|
+
// That is safe — the user explicitly provided an absolute path there.
|
|
8344
|
+
// Only apply the traversal check when the resolved path shares the same root
|
|
8345
|
+
// as CWD (i.e. the path was relative or on the same drive).
|
|
8222
8346
|
const cwd = process.cwd();
|
|
8223
|
-
const
|
|
8224
|
-
|
|
8225
|
-
|
|
8226
|
-
|
|
8347
|
+
const cwdRoot = path_1.default.parse(cwd).root;
|
|
8348
|
+
const pathRoot = path_1.default.parse(normalizedPath).root;
|
|
8349
|
+
if (cwdRoot === pathRoot) {
|
|
8350
|
+
// Same filesystem root — ensure the resolved path is still inside CWD
|
|
8351
|
+
// (or is exactly CWD) to block "../" traversal.
|
|
8352
|
+
const prefix = cwd.endsWith(path_1.default.sep) ? cwd : cwd + path_1.default.sep;
|
|
8353
|
+
if (!normalizedPath.startsWith(prefix) && normalizedPath !== cwd) {
|
|
8354
|
+
throw new Error(`Path must be within current working directory: ${cwd}`);
|
|
8355
|
+
}
|
|
8356
|
+
}
|
|
8357
|
+
// Cross-root absolute paths (e.g. D:\ on Windows when CWD is C:\) are
|
|
8358
|
+
// allowed — the user own the machine and the path is explicitly absolute.
|
|
8227
8359
|
return normalizedPath;
|
|
8228
8360
|
}
|
|
8229
8361
|
function buildManageCloudRunErrorMessage(action, serverName, error) {
|
|
@@ -9756,7 +9888,7 @@ class TelemetryReporter {
|
|
|
9756
9888
|
const nodeVersion = process.version; // Node.js版本
|
|
9757
9889
|
const arch = os_1.default.arch(); // 系统架构
|
|
9758
9890
|
// 从构建时注入的版本号获取MCP版本信息
|
|
9759
|
-
const mcpVersion = process.env.npm_package_version || "2.23.
|
|
9891
|
+
const mcpVersion = process.env.npm_package_version || "2.23.7" || 0;
|
|
9760
9892
|
return {
|
|
9761
9893
|
userAgent: `${osType} ${osRelease} ${arch} ${nodeVersion} CloudBase-MCP/${mcpVersion}`,
|
|
9762
9894
|
deviceId: this.deviceId,
|
|
@@ -13077,7 +13209,7 @@ function registerPermissionTools(server) {
|
|
|
13077
13209
|
}));
|
|
13078
13210
|
server.registerTool?.("managePermissions", {
|
|
13079
13211
|
title: "管理 CloudBase 权限与用户配置",
|
|
13080
|
-
description: "管理 CloudBase 权限与用户配置,支持修改资源权限(数据库/云函数/存储桶等)、角色管理、成员与策略增删、应用用户 CRUD。\n\n示例:\n- 设置存储桶为私有:`action=\"updateResourcePermission\", resourceType=\"storage\", resourceId=\"bucket-name\", permission=\"PRIVATE\"`\n- 创建角色:`action=\"createRole\", roleName=\"admin\", roleIdentity=\"admin\"`\n\n注意:`createUser` / `updateUser` 是环境侧应用用户管理能力,适合测试账号、管理员或预置用户,不应替代浏览器里的 Web SDK 注册表单;前端用户名密码注册应使用 `auth.signUp({ username, password })`,登录应使用 `auth.signInWithPassword({ username, password })`。直接在浏览器里用 `auth.signUp` 创建用户名密码用户取决于 SDK/provider 支持,使用前必须验证;不支持时应走后端或管理端边界,不能在浏览器暴露密钥。`securityRule` 的详细语义取决于 `resourceType`:`doc._openid`、`auth.openid`、查询条件子集校验,以及 `create` / `update` / `delete` JSON 模板仅适用于 `resourceType=\"noSqlDatabase\"` 的文档数据库安全规则;配置 `function` 或 `storage` 时,请参考各自官方安全规则文档,而不是复用 NoSQL 模板。\n\n📌 跨后端边界提示:调用前先用 `envQuery(action=\"info\", envId=...)` 看 `EnvInfo.RuntimeBackends`:\n- `resourceType=\"noSqlDatabase\"` 仅作用于 CloudBase NoSQL 文档数据库的集合;CloudBase PostgreSQL(PG)表的行级权限**不**受它控制——PG 表请改用 RLS:`managePgDatabase(action=\"execute\", confirm=true)` 跑 `ALTER TABLE ... ENABLE ROW LEVEL SECURITY` 与 `CREATE POLICY ...`。同一个 PG 环境里如果还有 NoSQL 集合在用,对那些**集合**继续使用 `noSqlDatabase` 规则是正确的——不是\"PG 环境就禁用本工具\"。\n- `resourceType=\"storage\"` 控制的是 NoSQL/COS 存储桶 ACL;PG 的 `pgstore` bucket 不在此 `resourceType` 覆盖范围内。\n- 本工具不涉及 MySQL;MySQL 数据库权限请走 MySQL 自身的 GRANT/REVOKE 语句(通过 `
|
|
13212
|
+
description: "管理 CloudBase 权限与用户配置,支持修改资源权限(数据库/云函数/存储桶等)、角色管理、成员与策略增删、应用用户 CRUD。\n\n示例:\n- 设置存储桶为私有:`action=\"updateResourcePermission\", resourceType=\"storage\", resourceId=\"bucket-name\", permission=\"PRIVATE\"`\n- 创建角色:`action=\"createRole\", roleName=\"admin\", roleIdentity=\"admin\"`\n\n注意:`createUser` / `updateUser` 是环境侧应用用户管理能力,适合测试账号、管理员或预置用户,不应替代浏览器里的 Web SDK 注册表单;前端用户名密码注册应使用 `auth.signUp({ username, password })`,登录应使用 `auth.signInWithPassword({ username, password })`。直接在浏览器里用 `auth.signUp` 创建用户名密码用户取决于 SDK/provider 支持,使用前必须验证;不支持时应走后端或管理端边界,不能在浏览器暴露密钥。`securityRule` 的详细语义取决于 `resourceType`:`doc._openid`、`auth.openid`、查询条件子集校验,以及 `create` / `update` / `delete` JSON 模板仅适用于 `resourceType=\"noSqlDatabase\"` 的文档数据库安全规则;配置 `function` 或 `storage` 时,请参考各自官方安全规则文档,而不是复用 NoSQL 模板。\n\n📌 跨后端边界提示:调用前先用 `envQuery(action=\"info\", envId=...)` 看 `EnvInfo.RuntimeBackends`:\n- `resourceType=\"noSqlDatabase\"` 仅作用于 CloudBase NoSQL 文档数据库的集合;CloudBase PostgreSQL(PG)表的行级权限**不**受它控制——PG 表请改用 RLS:`managePgDatabase(action=\"execute\", confirm=true)` 跑 `ALTER TABLE ... ENABLE ROW LEVEL SECURITY` 与 `CREATE POLICY ...`。同一个 PG 环境里如果还有 NoSQL 集合在用,对那些**集合**继续使用 `noSqlDatabase` 规则是正确的——不是\"PG 环境就禁用本工具\"。\n- `resourceType=\"storage\"` 控制的是 NoSQL/COS 存储桶 ACL;PG 的 `pgstore` bucket 不在此 `resourceType` 覆盖范围内。\n- 本工具不涉及 MySQL;MySQL 数据库权限请走 MySQL 自身的 GRANT/REVOKE 语句(通过 `manageMysqlDatabase`)。",
|
|
13081
13213
|
inputSchema: {
|
|
13082
13214
|
action: zod_1.z.enum(MANAGE_PERMISSION_ACTIONS),
|
|
13083
13215
|
resourceType: zod_1.z
|
|
@@ -13767,7 +13899,7 @@ function registerSetupTools(server) {
|
|
|
13767
13899
|
server.registerTool("downloadTemplate", {
|
|
13768
13900
|
title: "下载项目模板",
|
|
13769
13901
|
description: `自动下载并部署CloudBase项目模板。
|
|
13770
|
-
**Note**: Call this tool when the user requests to create a new project using a CloudBase template.\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.23.
|
|
13902
|
+
**Note**: Call this tool when the user requests to create a new project using a CloudBase template.\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.23.7" : 0}),便于后续维护和版本追踪\n- 下载 rules 模板时,如果项目中已存在 README.md 文件,系统会自动保护该文件不被覆盖(除非设置 overwrite=true)`,
|
|
13771
13903
|
inputSchema: {
|
|
13772
13904
|
template: zod_1.z
|
|
13773
13905
|
.enum(["react", "vue", "miniprogram", "uniapp", "rules"])
|
|
@@ -16920,6 +17052,18 @@ function buildErrorEnvelope(error) {
|
|
|
16920
17052
|
function normalizeString(value) {
|
|
16921
17053
|
return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
|
|
16922
17054
|
}
|
|
17055
|
+
/**
|
|
17056
|
+
* Sanitize agent name for CloudBase backend.
|
|
17057
|
+
* The backend creates a cloud function alias from the agent name (e.g. "agent-{name}"),
|
|
17058
|
+
* and SCF aliases only allow alphanumeric characters and hyphens.
|
|
17059
|
+
* This function replaces any character that is not [a-zA-Z0-9] with a hyphen,
|
|
17060
|
+
* then collapses consecutive hyphens into one.
|
|
17061
|
+
*/
|
|
17062
|
+
function sanitizeAgentName(name) {
|
|
17063
|
+
return name
|
|
17064
|
+
.replace(/[^a-zA-Z0-9]+/g, "-")
|
|
17065
|
+
.replace(/^-+|-+$/g, "");
|
|
17066
|
+
}
|
|
16923
17067
|
function normalizeNumber(value) {
|
|
16924
17068
|
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
16925
17069
|
}
|
|
@@ -17074,13 +17218,19 @@ function registerAgentTools(server) {
|
|
|
17074
17218
|
}
|
|
17075
17219
|
// CloudBase 后端在创建 Agent 时会同步创建云函数,函数名/别名长度受 SCF 限制(最大 64 字符)。
|
|
17076
17220
|
// envId 可能被用作前缀或别名的一部分,因此这里预留足够余量,避免后端 CreateFunction 失败。
|
|
17077
|
-
|
|
17078
|
-
|
|
17079
|
-
|
|
17221
|
+
// 同时,后端会用 name 生成云函数 alias(如 "agent-{name}"),而 SCF alias 只允许字母、数字和连字符,
|
|
17222
|
+
// 因此需要对 name 做 sanitize,将非法字符(如下划线)替换为连字符。
|
|
17223
|
+
const sanitizedName = sanitizeAgentName(normalizedName);
|
|
17224
|
+
if (!sanitizedName) {
|
|
17225
|
+
throw new Error(`name "${normalizedName}" 经 sanitize 后为空,请使用包含字母或数字的 name`);
|
|
17226
|
+
}
|
|
17227
|
+
if (sanitizedName.length > 30) {
|
|
17228
|
+
throw new Error(`agent name 过长(当前 ${sanitizedName.length} 字符)。CloudBase 创建 Agent 时会同步创建云函数,` +
|
|
17229
|
+
`函数名/别名受 SCF 64 字符长度限制,且 envId 可能作为前缀拼接。请将 name 控制在 30 字符以内。`);
|
|
17080
17230
|
}
|
|
17081
17231
|
const createPayload = {
|
|
17082
17232
|
...payload,
|
|
17083
|
-
Name:
|
|
17233
|
+
Name: sanitizedName,
|
|
17084
17234
|
Runtime: normalizeString(payload.Runtime) ?? "Nodejs20.19",
|
|
17085
17235
|
};
|
|
17086
17236
|
const result = await cloudbase.agent.createAgent(createPayload);
|
|
@@ -17264,7 +17414,7 @@ async function checkMysqlGate(server) {
|
|
|
17264
17414
|
success: false,
|
|
17265
17415
|
errorCode: "MYSQL_NOT_AVAILABLE",
|
|
17266
17416
|
message: `This environment (${envId}) does not have MySQL. Use managePgDatabase / queryPgDatabase instead.`,
|
|
17267
|
-
nextActions: [{ tool: "managePgDatabase", params: { action: "execute" }, description: "Use managePgDatabase" }],
|
|
17417
|
+
nextActions: [{ tool: "managePgDatabase", params: { action: "execute" }, description: "Use managePgDatabase for PostgreSQL operations" }],
|
|
17268
17418
|
});
|
|
17269
17419
|
}
|
|
17270
17420
|
try {
|
|
@@ -17276,7 +17426,7 @@ async function checkMysqlGate(server) {
|
|
|
17276
17426
|
return (0, tool_result_js_1.buildJsonToolResult)({
|
|
17277
17427
|
success: false,
|
|
17278
17428
|
errorCode: "MYSQL_NOT_AVAILABLE",
|
|
17279
|
-
message: `This environment (${envId}) has PostgreSQL enabled but MySQL is NOT available. Use managePgDatabase / queryPgDatabase instead of
|
|
17429
|
+
message: `This environment (${envId}) has PostgreSQL enabled but MySQL is NOT available. Use managePgDatabase / queryPgDatabase instead of manageMysqlDatabase / queryMysqlDatabase.`,
|
|
17280
17430
|
nextActions: [{ tool: "managePgDatabase", params: { action: "execute" }, description: "Use managePgDatabase for PostgreSQL operations" }],
|
|
17281
17431
|
});
|
|
17282
17432
|
}
|
|
@@ -17285,8 +17435,8 @@ async function checkMysqlGate(server) {
|
|
|
17285
17435
|
MYSQL_GATE_CACHE.set(envId, true);
|
|
17286
17436
|
return null;
|
|
17287
17437
|
}
|
|
17288
|
-
const
|
|
17289
|
-
const
|
|
17438
|
+
const QUERY_MYSQL_DATABASE = "queryMysqlDatabase";
|
|
17439
|
+
const MANAGE_MYSQL_DATABASE = "manageMysqlDatabase";
|
|
17290
17440
|
const QUERY_PERMISSIONS = "queryPermissions";
|
|
17291
17441
|
const MANAGE_PERMISSIONS = "managePermissions";
|
|
17292
17442
|
const QUERY_ACTIONS = [
|
|
@@ -17578,14 +17728,14 @@ async function getSqlInstanceInfo({ getManager, cloudBaseOptions, server, }) {
|
|
|
17578
17728
|
function buildProvisionNextActions(status, request) {
|
|
17579
17729
|
if (status === "READY") {
|
|
17580
17730
|
return [
|
|
17581
|
-
buildNextAction(
|
|
17731
|
+
buildNextAction(MANAGE_MYSQL_DATABASE, "initializeSchema", "MySQL is ready. Initialize tables and indexes next."),
|
|
17582
17732
|
];
|
|
17583
17733
|
}
|
|
17584
17734
|
if (status === "FAILED") {
|
|
17585
17735
|
return [];
|
|
17586
17736
|
}
|
|
17587
17737
|
return [
|
|
17588
|
-
buildNextAction(
|
|
17738
|
+
buildNextAction(QUERY_MYSQL_DATABASE, "describeCreateResult", "MySQL provisioning is still running. Check the create result again before initializing schema.", request
|
|
17589
17739
|
? { action: "describeCreateResult", request }
|
|
17590
17740
|
: { action: "describeCreateResult" }),
|
|
17591
17741
|
];
|
|
@@ -17604,15 +17754,15 @@ function buildTaskStatusNextActions(status, request) {
|
|
|
17604
17754
|
if (status === "READY") {
|
|
17605
17755
|
if (inferTaskKind(request) === "destroy") {
|
|
17606
17756
|
return [
|
|
17607
|
-
buildNextAction(
|
|
17757
|
+
buildNextAction(QUERY_MYSQL_DATABASE, "getInstanceInfo", "The destroy task completed. Confirm whether the MySQL instance no longer exists."),
|
|
17608
17758
|
];
|
|
17609
17759
|
}
|
|
17610
17760
|
return [
|
|
17611
|
-
buildNextAction(
|
|
17761
|
+
buildNextAction(MANAGE_MYSQL_DATABASE, "initializeSchema", "MySQL is ready. Initialize tables and indexes next."),
|
|
17612
17762
|
];
|
|
17613
17763
|
}
|
|
17614
17764
|
return [
|
|
17615
|
-
buildNextAction(
|
|
17765
|
+
buildNextAction(QUERY_MYSQL_DATABASE, "describeTaskStatus", "MySQL task is still running. Check task status again before continuing.", request ? { action: "describeTaskStatus", request } : { action: "describeTaskStatus" }),
|
|
17616
17766
|
];
|
|
17617
17767
|
}
|
|
17618
17768
|
async function handleRunQuery(args, context) {
|
|
@@ -17622,7 +17772,7 @@ async function handleRunQuery(args, context) {
|
|
|
17622
17772
|
errorCode: "SQL_REQUIRED",
|
|
17623
17773
|
message: "`sql` is required when action is `runQuery`.",
|
|
17624
17774
|
nextActions: [
|
|
17625
|
-
buildNextAction(
|
|
17775
|
+
buildNextAction(QUERY_MYSQL_DATABASE, "runQuery", "Provide a read-only SQL statement such as SELECT/SHOW/DESCRIBE."),
|
|
17626
17776
|
],
|
|
17627
17777
|
});
|
|
17628
17778
|
}
|
|
@@ -17630,9 +17780,9 @@ async function handleRunQuery(args, context) {
|
|
|
17630
17780
|
return buildSqlToolResult({
|
|
17631
17781
|
success: false,
|
|
17632
17782
|
errorCode: "READ_ONLY_SQL_REQUIRED",
|
|
17633
|
-
message: "`
|
|
17783
|
+
message: "`queryMysqlDatabase(action=runQuery)` only accepts read-only SQL statements.",
|
|
17634
17784
|
nextActions: [
|
|
17635
|
-
buildNextAction(
|
|
17785
|
+
buildNextAction(MANAGE_MYSQL_DATABASE, "runStatement", "Use the manage tool for INSERT/UPDATE/DELETE/DDL statements."),
|
|
17636
17786
|
],
|
|
17637
17787
|
});
|
|
17638
17788
|
}
|
|
@@ -17660,7 +17810,7 @@ async function handleRunQuery(args, context) {
|
|
|
17660
17810
|
errorCode: "MYSQL_NOT_CREATED",
|
|
17661
17811
|
message: "MySQL is not provisioned yet or not found. Please provision MySQL before running queries.",
|
|
17662
17812
|
nextActions: [
|
|
17663
|
-
buildNextAction(
|
|
17813
|
+
buildNextAction(MANAGE_MYSQL_DATABASE, "provisionMySQL", "Provision MySQL before querying data.", { action: "provisionMySQL", confirm: true }),
|
|
17664
17814
|
],
|
|
17665
17815
|
});
|
|
17666
17816
|
}
|
|
@@ -17759,7 +17909,7 @@ async function handleGetInstanceInfo(context) {
|
|
|
17759
17909
|
nextActions: instanceInfo.exists
|
|
17760
17910
|
? undefined
|
|
17761
17911
|
: [
|
|
17762
|
-
buildNextAction(
|
|
17912
|
+
buildNextAction(MANAGE_MYSQL_DATABASE, "provisionMySQL", "Provision MySQL before running SQL statements or schema initialization.", { action: "provisionMySQL", confirm: true }),
|
|
17763
17913
|
],
|
|
17764
17914
|
});
|
|
17765
17915
|
}
|
|
@@ -17770,7 +17920,7 @@ async function handleProvisionMySQL(args, context) {
|
|
|
17770
17920
|
errorCode: "CONFIRM_REQUIRED",
|
|
17771
17921
|
message: "Provisioning MySQL creates billable resources. Re-run with `confirm: true` to continue.",
|
|
17772
17922
|
nextActions: [
|
|
17773
|
-
buildNextAction(
|
|
17923
|
+
buildNextAction(MANAGE_MYSQL_DATABASE, "provisionMySQL", "Explicit confirmation is required before provisioning MySQL.", { action: "provisionMySQL", confirm: true }),
|
|
17774
17924
|
],
|
|
17775
17925
|
});
|
|
17776
17926
|
}
|
|
@@ -17784,7 +17934,7 @@ async function handleProvisionMySQL(args, context) {
|
|
|
17784
17934
|
message: "A SQL database instance already exists for the current environment.",
|
|
17785
17935
|
nextActions: existing.status === "READY"
|
|
17786
17936
|
? [
|
|
17787
|
-
buildNextAction(
|
|
17937
|
+
buildNextAction(MANAGE_MYSQL_DATABASE, "initializeSchema", "The instance already exists. You can initialize schema next if needed."),
|
|
17788
17938
|
]
|
|
17789
17939
|
: undefined,
|
|
17790
17940
|
});
|
|
@@ -17830,7 +17980,7 @@ async function handleDestroyMySQL(args, context) {
|
|
|
17830
17980
|
errorCode: "CONFIRM_REQUIRED",
|
|
17831
17981
|
message: "Destroying MySQL removes database resources. Re-run with `confirm: true` to continue.",
|
|
17832
17982
|
nextActions: [
|
|
17833
|
-
buildNextAction(
|
|
17983
|
+
buildNextAction(MANAGE_MYSQL_DATABASE, "destroyMySQL", "Explicit confirmation is required before destroying MySQL.", { action: "destroyMySQL", confirm: true }),
|
|
17834
17984
|
],
|
|
17835
17985
|
});
|
|
17836
17986
|
}
|
|
@@ -17877,7 +18027,7 @@ async function handleDestroyMySQL(args, context) {
|
|
|
17877
18027
|
: "MySQL destroy request was rejected.",
|
|
17878
18028
|
nextActions: isSuccess
|
|
17879
18029
|
? [
|
|
17880
|
-
buildNextAction(
|
|
18030
|
+
buildNextAction(QUERY_MYSQL_DATABASE, "describeTaskStatus", "Check the MySQL destroy task status before assuming the instance is gone.", {
|
|
17881
18031
|
action: "describeTaskStatus",
|
|
17882
18032
|
request: taskRequest,
|
|
17883
18033
|
}),
|
|
@@ -17900,7 +18050,7 @@ async function handleRunStatement(args, context) {
|
|
|
17900
18050
|
errorCode: "MYSQL_NOT_CREATED",
|
|
17901
18051
|
message: "MySQL is not provisioned for the current environment yet.",
|
|
17902
18052
|
nextActions: [
|
|
17903
|
-
buildNextAction(
|
|
18053
|
+
buildNextAction(MANAGE_MYSQL_DATABASE, "provisionMySQL", "Provision MySQL before executing write statements or DDL.", { action: "provisionMySQL", confirm: true }),
|
|
17904
18054
|
],
|
|
17905
18055
|
});
|
|
17906
18056
|
}
|
|
@@ -17910,7 +18060,7 @@ async function handleRunStatement(args, context) {
|
|
|
17910
18060
|
errorCode: "MYSQL_NOT_READY",
|
|
17911
18061
|
message: `MySQL is not ready yet (current status: ${instanceInfo.status}).`,
|
|
17912
18062
|
nextActions: [
|
|
17913
|
-
buildNextAction(
|
|
18063
|
+
buildNextAction(QUERY_MYSQL_DATABASE, "getInstanceInfo", "Check current instance status before retrying the statement."),
|
|
17914
18064
|
],
|
|
17915
18065
|
});
|
|
17916
18066
|
}
|
|
@@ -17937,7 +18087,7 @@ async function handleRunStatement(args, context) {
|
|
|
17937
18087
|
errorCode: "MYSQL_NOT_CREATED",
|
|
17938
18088
|
message: "MySQL is not provisioned yet or not found. Please provision MySQL before running statements.",
|
|
17939
18089
|
nextActions: [
|
|
17940
|
-
buildNextAction(
|
|
18090
|
+
buildNextAction(MANAGE_MYSQL_DATABASE, "provisionMySQL", "Provision MySQL before executing statements.", { action: "provisionMySQL", confirm: true }),
|
|
17941
18091
|
],
|
|
17942
18092
|
});
|
|
17943
18093
|
}
|
|
@@ -17966,7 +18116,7 @@ async function resolveInitializationReadiness(args, context) {
|
|
|
17966
18116
|
errorCode: "MYSQL_NOT_CREATED",
|
|
17967
18117
|
message: "MySQL is not provisioned yet. Initialize schema only after provisioning completes.",
|
|
17968
18118
|
nextActions: [
|
|
17969
|
-
buildNextAction(
|
|
18119
|
+
buildNextAction(MANAGE_MYSQL_DATABASE, "provisionMySQL", "Provision MySQL before schema initialization.", { action: "provisionMySQL", confirm: true }),
|
|
17970
18120
|
],
|
|
17971
18121
|
}),
|
|
17972
18122
|
};
|
|
@@ -18006,7 +18156,7 @@ async function resolveInitializationReadiness(args, context) {
|
|
|
18006
18156
|
rawStatus,
|
|
18007
18157
|
},
|
|
18008
18158
|
nextActions: [
|
|
18009
|
-
buildNextAction(
|
|
18159
|
+
buildNextAction(QUERY_MYSQL_DATABASE, "describeTaskStatus", "Check MySQL task status until the instance becomes ready.", args.statusContext?.taskStatusRequest
|
|
18010
18160
|
? {
|
|
18011
18161
|
action: "describeTaskStatus",
|
|
18012
18162
|
request: args.statusContext.taskStatusRequest,
|
|
@@ -18063,7 +18213,7 @@ async function handleInitializeSchema(args, context) {
|
|
|
18063
18213
|
errorCode: "MYSQL_NOT_CREATED",
|
|
18064
18214
|
message: "MySQL is not provisioned yet or not found. Please provision MySQL before initializing schema.",
|
|
18065
18215
|
nextActions: [
|
|
18066
|
-
buildNextAction(
|
|
18216
|
+
buildNextAction(MANAGE_MYSQL_DATABASE, "provisionMySQL", "Provision MySQL before executing statements.", { action: "provisionMySQL", confirm: true }),
|
|
18067
18217
|
],
|
|
18068
18218
|
});
|
|
18069
18219
|
}
|
|
@@ -18111,7 +18261,7 @@ function registerSQLDatabaseTools(server) {
|
|
|
18111
18261
|
cloudBaseOptions,
|
|
18112
18262
|
server,
|
|
18113
18263
|
};
|
|
18114
|
-
server.registerTool?.(
|
|
18264
|
+
server.registerTool?.(QUERY_MYSQL_DATABASE, {
|
|
18115
18265
|
title: "查询 CloudBase MySQL 数据库状态或执行只读 SQL",
|
|
18116
18266
|
description: "查询 CloudBase MySQL 数据库信息。支持执行只读 SQL、查询 MySQL 开通结果、查询 MySQL 任务状态,以及获取当前实例上下文信息。",
|
|
18117
18267
|
inputSchema: {
|
|
@@ -18157,7 +18307,7 @@ function registerSQLDatabaseTools(server) {
|
|
|
18157
18307
|
throw new Error(`Unsupported SQL query action: ${args.action}`);
|
|
18158
18308
|
}
|
|
18159
18309
|
});
|
|
18160
|
-
server.registerTool?.(
|
|
18310
|
+
server.registerTool?.(MANAGE_MYSQL_DATABASE, {
|
|
18161
18311
|
title: "管理 CloudBase MySQL 数据库生命周期或执行写入 SQL",
|
|
18162
18312
|
description: "管理 CloudBase MySQL 数据库资源。支持开通 MySQL、销毁 MySQL、执行写入 SQL/DDL,以及初始化数据库 Schema。注意:必须先开通 MySQL(action=provisionMySQL,confirm=true)才能执行 runStatement 或 initializeSchema。若 MySQL 尚未开通,工具会返回 MYSQL_NOT_CREATED 并给出开通的 nextAction 提示。",
|
|
18163
18313
|
inputSchema: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudbase/cloudbase-mcp",
|
|
3
|
-
"version": "2.23.
|
|
3
|
+
"version": "2.23.7",
|
|
4
4
|
"packageManager": "pnpm@10.8.0",
|
|
5
5
|
"description": "腾讯云开发 MCP Server,通过AI提示词和MCP协议+云开发,让开发更智能、更高效,当你在Cursor/ VSCode GitHub Copilot/WinSurf/CodeBuddy/Augment Code/Claude Code等AI编程工具里写代码时,它能自动帮你生成可直接部署的前后端应用+小程序,并一键发布到腾讯云开发 CloudBase。",
|
|
6
6
|
"main": "./dist/index.cjs",
|