@cloudbase/cloudbase-mcp 2.23.3 → 2.23.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -593,7 +593,7 @@ async function enrichEnvInfoWithBilling(params) {
593
593
  * for new code, including an explicit `MysqlNotAvailable` line when
594
594
  * MySQL is absent — that one IS a hard "do not use" signal.
595
595
  */
596
- function enrichEnvInfoWithRuntimeMode(result) {
596
+ async function enrichEnvInfoWithRuntimeMode(result, manager) {
597
597
  const envInfo = result?.EnvInfo;
598
598
  if (!envInfo || typeof envInfo !== "object") {
599
599
  return result;
@@ -623,7 +623,29 @@ function enrichEnvInfoWithRuntimeMode(result) {
623
623
  }
624
624
  return [];
625
625
  })();
626
- const hasMysql = mysqlList.length > 0;
626
+ let hasMysql = mysqlList.length > 0;
627
+ // Fallback: if MySQL not detected from DescribeEnvInfo fields, probe via
628
+ // DescribeMySQLClusterDetail (dedicated MySQL API). This covers cases where
629
+ // the SDK strips MySQL fields from the DescribeEnvInfo response.
630
+ if (!hasMysql && manager?.commonService) {
631
+ try {
632
+ const probeResult = await manager
633
+ .commonService("tcb", "2018-06-08")
634
+ .call({
635
+ Action: "DescribeMySQLClusterDetail",
636
+ Param: { EnvId: envInfo.EnvId },
637
+ });
638
+ const clusterId = probeResult?.DbClusterId ||
639
+ probeResult?.Response?.DbClusterId ||
640
+ probeResult?.Data?.DbClusterId;
641
+ if (clusterId) {
642
+ hasMysql = true;
643
+ }
644
+ }
645
+ catch {
646
+ // Probe failure means MySQL is not provisioned — keep hasMysql = false
647
+ }
648
+ }
627
649
  // Primary mode: prefer PG when it is provisioned, otherwise fall back to
628
650
  // legacy NoSQL labeling. This drives "what skill to read first / what API
629
651
  // to reach for when starting new business code".
@@ -641,7 +663,7 @@ function enrichEnvInfoWithRuntimeMode(result) {
641
663
  : "No legacy NoSQL Database/Storage observed in this env.",
642
664
  MysqlNotAvailable: hasMysql
643
665
  ? "MySQL instance(s) detected — see EnvInfo.MysqlInstances."
644
- : "No MySQL instance is provisioned for this env. Do NOT use `manageSqlDatabase` / `querySqlDatabase` (those are MySQL-specific) and do NOT read the `relational-database-tool` skill — that family targets MySQL, not CloudBase PG.",
666
+ : "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
667
  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
668
  }
647
669
  : {
@@ -651,7 +673,7 @@ function enrichEnvInfoWithRuntimeMode(result) {
651
673
  Storage: "Browser uploads use `app.uploadFile()` against the bucket exposed in `EnvInfo.Storages[].Bucket`.",
652
674
  MysqlNotAvailable: hasMysql
653
675
  ? "MySQL instance(s) detected — see EnvInfo.MysqlInstances."
654
- : "No MySQL instance in this env. `manageSqlDatabase` / `querySqlDatabase` and the `relational-database-tool` skill are not applicable.",
676
+ : "No MySQL instance in this env. `manageMysqlDatabase` / `queryMysqlDatabase` and the `relational-database-tool` skill are not applicable.",
655
677
  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
678
  };
657
679
  return {
@@ -1415,7 +1437,7 @@ function registerEnvTools(server) {
1415
1437
  if (envId) {
1416
1438
  result = await enrichEnvInfoWithMissingFields(cloudbaseInfo, result, envId);
1417
1439
  }
1418
- result = enrichEnvInfoWithRuntimeMode(result);
1440
+ result = await enrichEnvInfoWithRuntimeMode(result, cloudbaseInfo);
1419
1441
  break;
1420
1442
  case "domains":
1421
1443
  const cloudbaseDomains = await getManager();
@@ -1483,7 +1505,7 @@ function registerEnvTools(server) {
1483
1505
  // Register primary tool name (queryEnv)
1484
1506
  const queryEnvToolSchema = {
1485
1507
  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` 时,`manageSqlDatabase` / `querySqlDatabase` / `relational-database-tool` skill 都不该使用。",
1508
+ 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
1509
  inputSchema: {
1488
1510
  action: zod_1.z
1489
1511
  .enum(["list", "info", "domains"])
@@ -1585,9 +1607,9 @@ function registerEnvTools(server) {
1585
1607
  .optional()
1586
1608
  .describe("环境地域(action=create 时可选)。默认 ap-shanghai,可选 ap-guangzhou、ap-beijing 等"),
1587
1609
  resources: zod_1.z
1588
- .array(zod_1.z.enum(["flexdb", "storage", "function"]))
1610
+ .array(zod_1.z.enum(["flexdb", "storage", "function", "postgresql"]))
1589
1611
  .optional()
1590
- .describe("启用的资源类型(action=create 时可选)。默认启用全部三项:flexdb(文档数据库)、storage(存储)、function(云函数)"),
1612
+ .describe("启用的资源类型(action=create 时可选)。默认启用全部四项:flexdb(文档数据库)、storage(存储)、function(云函数)、postgresql(PostgreSQL 数据库)"),
1591
1613
  duration: zod_1.z
1592
1614
  .number()
1593
1615
  .int()
@@ -1640,7 +1662,7 @@ function registerEnvTools(server) {
1640
1662
  return (0, tool_result_js_1.buildJsonToolResult)({
1641
1663
  ok: false,
1642
1664
  code: "CONFIRM_REQUIRED",
1643
- message: `创建环境需要您确认。请确认以下配置信息后传入 confirm="yes":\n别名: ${alias}\n套餐: ${packageId}\n地域: ${region}\n资源类型: ${resources?.join(", ") ?? "flexdb, storage, function"}\n时长: ${duration} 个月`,
1665
+ message: `创建环境需要您确认。请确认以下配置信息后传入 confirm="yes":\n别名: ${alias}\n套餐: ${packageId}\n地域: ${region}\n资源类型: ${resources?.join(", ") ?? "flexdb, storage, function, postgresql"}\n时长: ${duration} 个月`,
1644
1666
  next_step: {
1645
1667
  tool: "manageEnv",
1646
1668
  action: "create",
@@ -1767,6 +1789,7 @@ function registerEnvTools(server) {
1767
1789
 
1768
1790
 
1769
1791
  Object.defineProperty(exports, "__esModule", ({ value: true }));
1792
+ exports.removeEmptyStringParams = removeEmptyStringParams;
1770
1793
  exports.buildCapiErrorMessage = buildCapiErrorMessage;
1771
1794
  exports.registerCapiTools = registerCapiTools;
1772
1795
  const zod_1 = __webpack_require__(2971);
@@ -1802,6 +1825,19 @@ function levenshteinDistance(left, right) {
1802
1825
  }
1803
1826
  return matrix[left.length][right.length];
1804
1827
  }
1828
+ /**
1829
+ * Remove empty string parameters from the params object.
1830
+ * Tencent Cloud APIs reject empty strings for required parameters like StartTime/EndTime.
1831
+ */
1832
+ function removeEmptyStringParams(params) {
1833
+ const cleaned = {};
1834
+ for (const [key, value] of Object.entries(params)) {
1835
+ if (value !== "") {
1836
+ cleaned[key] = value;
1837
+ }
1838
+ }
1839
+ return cleaned;
1840
+ }
1805
1841
  function findTcbActionEntry(action) {
1806
1842
  if (tcb_action_index_js_1.TCB_ACTION_INDEX_MAP[action]) {
1807
1843
  return tcb_action_index_js_1.TCB_ACTION_INDEX_MAP[action];
@@ -1988,9 +2024,10 @@ function registerCapiTools(server) {
1988
2024
  }
1989
2025
  let result;
1990
2026
  try {
2027
+ const cleanedParams = params ? removeEmptyStringParams(params) : {};
1991
2028
  result = await cloudbase.commonService(service).call({
1992
2029
  Action: action,
1993
- Param: params ?? {},
2030
+ Param: cleanedParams,
1994
2031
  });
1995
2032
  }
1996
2033
  catch (error) {
@@ -2080,7 +2117,7 @@ ${envIdSection}
2080
2117
  ## 环境信息
2081
2118
  - 操作系统: ${os_1.default.type()} ${os_1.default.release()}
2082
2119
  - Node.js版本: ${process.version}
2083
- - MCP 版本:${process.env.npm_package_version || "2.23.3" || 0}
2120
+ - MCP 版本:${process.env.npm_package_version || "2.23.6" || 0}
2084
2121
  - 系统架构: ${os_1.default.arch()}
2085
2122
  - 时间: ${new Date().toISOString()}
2086
2123
  - 请求ID: ${requestId}
@@ -2161,7 +2198,7 @@ function createWrappedHandler(name, handler, server) {
2161
2198
  requestId: (typeof error === 'object' && error && 'requestId' in error) ? error.requestId : '',
2162
2199
  ide: server.ide || process.env.INTEGRATION_IDE || ''
2163
2200
  });
2164
- const mcpVersion = true ? "2.23.3" : 0;
2201
+ const mcpVersion = true ? "2.23.6" : 0;
2165
2202
  const requestIdSuffix = requestId ? `\n🆔 RequestId: ${requestId}` : '';
2166
2203
  const enhancedErrorMessage = `${errorMessage}${requestIdSuffix}\n\n📦 CloudBase MCP v${mcpVersion}\n🔗 遇到问题?请复制以下链接到浏览器打开\n即可自动携带错误详情快速创建 GitHub Issue:\n${issueLink}`;
2167
2204
  // 创建新的错误对象,保持原有的错误类型但更新消息
@@ -2346,6 +2383,7 @@ const DEFAULT_PLUGINS = [
2346
2383
  "database",
2347
2384
  "pg_database",
2348
2385
  "pg_storage",
2386
+ "mysql_database",
2349
2387
  "functions",
2350
2388
  "hosting",
2351
2389
  "storage",
@@ -2368,10 +2406,6 @@ function registerDatabase(server) {
2368
2406
  if (!(0, tencent_cloud_js_1.isInternationalRegion)(region)) {
2369
2407
  (0, databaseNoSQL_js_1.registerDatabaseTools)(server);
2370
2408
  }
2371
- const pgPluginEnabled = server.enabledPlugins?.some((pluginName) => pluginName === "pg_database" || pluginName === "pg_storage");
2372
- if (!pgPluginEnabled) {
2373
- (0, databaseSQL_js_1.registerSQLDatabaseTools)(server);
2374
- }
2375
2409
  (0, dataModel_js_1.registerDataModelTools)(server);
2376
2410
  }
2377
2411
  function registerMysqlDatabase(server) {
@@ -7644,7 +7678,7 @@ const queryStorageInputSchema = {
7644
7678
  // Input schema for manageStorage tool
7645
7679
  const manageStorageInputSchema = {
7646
7680
  action: zod_1.z.enum(['upload', 'download', 'delete']).describe('管理操作类型:upload=上传文件或目录,download=下载文件或目录,delete=删除文件或目录'),
7647
- localPath: zod_1.z.string().describe('本地文件路径,建议传入绝对路径,例如 /tmp/files/data.txt'),
7681
+ localPath: zod_1.z.string().optional().describe('本地文件路径,建议传入绝对路径,例如 /tmp/files/data.txt;upload/download 操作时必填,delete 操作时不需要传该参数'),
7648
7682
  cloudPath: zod_1.z.string().describe('云端文件路径,例如 files/data.txt'),
7649
7683
  force: zod_1.z.boolean().optional().default(false).describe('强制操作开关,删除操作时建议设置为true以确认删除,默认false'),
7650
7684
  isDirectory: zod_1.z.boolean().optional().default(false).describe('是否为目录操作,true=目录操作,false=文件操作,默认false')
@@ -7894,14 +7928,16 @@ function registerStorageTools(server) {
7894
7928
  const storageService = manager.storage;
7895
7929
  switch (input.action) {
7896
7930
  case 'upload': {
7931
+ const localPath = input.localPath;
7932
+ const cloudPath = input.cloudPath;
7897
7933
  if (input.isDirectory) {
7898
7934
  if (storageOverrides?.uploadDirectory) {
7899
- await storageOverrides.uploadDirectory({ localPath: input.localPath, cloudPath: input.cloudPath });
7935
+ await storageOverrides.uploadDirectory({ localPath, cloudPath });
7900
7936
  }
7901
7937
  else {
7902
7938
  await storageService.uploadDirectory({
7903
- localPath: input.localPath,
7904
- cloudPath: input.cloudPath,
7939
+ localPath,
7940
+ cloudPath,
7905
7941
  onProgress: (progressData) => {
7906
7942
  console.log("Upload directory progress:", progressData);
7907
7943
  }
@@ -7910,12 +7946,12 @@ function registerStorageTools(server) {
7910
7946
  }
7911
7947
  else {
7912
7948
  if (storageOverrides?.uploadFile) {
7913
- await storageOverrides.uploadFile({ localPath: input.localPath, cloudPath: input.cloudPath });
7949
+ await storageOverrides.uploadFile({ localPath, cloudPath });
7914
7950
  }
7915
7951
  else {
7916
7952
  await storageService.uploadFile({
7917
- localPath: input.localPath,
7918
- cloudPath: input.cloudPath,
7953
+ localPath,
7954
+ cloudPath,
7919
7955
  onProgress: (progressData) => {
7920
7956
  console.log("Upload file progress:", progressData);
7921
7957
  }
@@ -7982,25 +8018,27 @@ function registerStorageTools(server) {
7982
8018
  };
7983
8019
  }
7984
8020
  case 'download': {
8021
+ const dlCloudPath = input.cloudPath;
8022
+ const dlLocalPath = input.localPath;
7985
8023
  if (input.isDirectory) {
7986
8024
  if (storageOverrides?.downloadDirectory) {
7987
- await storageOverrides.downloadDirectory({ cloudPath: input.cloudPath, localPath: input.localPath });
8025
+ await storageOverrides.downloadDirectory({ cloudPath: dlCloudPath, localPath: dlLocalPath });
7988
8026
  }
7989
8027
  else {
7990
8028
  await storageService.downloadDirectory({
7991
- cloudPath: input.cloudPath,
7992
- localPath: input.localPath
8029
+ cloudPath: dlCloudPath,
8030
+ localPath: dlLocalPath
7993
8031
  });
7994
8032
  }
7995
8033
  }
7996
8034
  else {
7997
8035
  if (storageOverrides?.downloadFile) {
7998
- await storageOverrides.downloadFile({ cloudPath: input.cloudPath, localPath: input.localPath });
8036
+ await storageOverrides.downloadFile({ cloudPath: dlCloudPath, localPath: dlLocalPath });
7999
8037
  }
8000
8038
  else {
8001
8039
  await storageService.downloadFile({
8002
- cloudPath: input.cloudPath,
8003
- localPath: input.localPath
8040
+ cloudPath: dlCloudPath,
8041
+ localPath: dlLocalPath
8004
8042
  });
8005
8043
  }
8006
8044
  }
@@ -9737,7 +9775,7 @@ class TelemetryReporter {
9737
9775
  const nodeVersion = process.version; // Node.js版本
9738
9776
  const arch = os_1.default.arch(); // 系统架构
9739
9777
  // 从构建时注入的版本号获取MCP版本信息
9740
- const mcpVersion = process.env.npm_package_version || "2.23.3" || 0;
9778
+ const mcpVersion = process.env.npm_package_version || "2.23.6" || 0;
9741
9779
  return {
9742
9780
  userAgent: `${osType} ${osRelease} ${arch} ${nodeVersion} CloudBase-MCP/${mcpVersion}`,
9743
9781
  deviceId: this.deviceId,
@@ -10026,7 +10064,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
10026
10064
  return (mod && mod.__esModule) ? mod : { "default": mod };
10027
10065
  };
10028
10066
  Object.defineProperty(exports, "__esModule", ({ value: true }));
10029
- exports.MANAGE_FUNCTION_ACTIONS = exports.QUERY_FUNCTION_ACTIONS = exports.TRIGGER_CONFIG_EXAMPLES = exports.SUPPORTED_TRIGGER_TYPES = exports.DEFAULT_NODEJS_RUNTIME = exports.SUPPORTED_NODEJS_RUNTIMES = exports.RECOMMENDED_RUNTIMES = exports.DEFAULT_RUNTIME = exports.ALL_SUPPORTED_RUNTIMES = exports.SUPPORTED_RUNTIMES = void 0;
10067
+ exports.CUSTOM_IMAGE_RUNTIME = exports.MANAGE_FUNCTION_ACTIONS = exports.QUERY_FUNCTION_ACTIONS = exports.TRIGGER_CONFIG_EXAMPLES = exports.SUPPORTED_TRIGGER_TYPES = exports.DEFAULT_NODEJS_RUNTIME = exports.SUPPORTED_NODEJS_RUNTIMES = exports.RECOMMENDED_RUNTIMES = exports.DEFAULT_RUNTIME = exports.ALL_SUPPORTED_RUNTIMES = exports.SUPPORTED_RUNTIMES = void 0;
10030
10068
  exports.formatRuntimeList = formatRuntimeList;
10031
10069
  exports.validateTimerCron = validateTimerCron;
10032
10070
  exports.shouldInstallDependencyForFunction = shouldInstallDependencyForFunction;
@@ -10134,6 +10172,41 @@ const VPC_SCHEMA = zod_1.z.object({
10134
10172
  vpcId: zod_1.z.string(),
10135
10173
  subnetId: zod_1.z.string(),
10136
10174
  });
10175
+ // 镜像部署值,对应 SCF Runtime=CustomImage
10176
+ exports.CUSTOM_IMAGE_RUNTIME = "CustomImage";
10177
+ // HTTP 函数镜像部署配置,对应 Manager SDK 的 IFunctionImageConfig(camelCase)。
10178
+ // 用于 zip→COS→CloudApp custom 构建→TCR→SCF 镜像部署链路的「阶段 B」:基于已推送到 TCR 的镜像创建/更新函数。
10179
+ const IMAGE_CONFIG_SCHEMA = zod_1.z.object({
10180
+ imageType: zod_1.z
10181
+ .enum(["enterprise", "personal"])
10182
+ .optional()
10183
+ .describe("镜像仓库类型:enterprise(企业版 TCR)或 personal(个人版)。省略时默认 enterprise。"),
10184
+ imageUri: zod_1.z
10185
+ .string()
10186
+ .describe("完整镜像地址(必须含 tag),格式 {domain}/{namespace}/{image}:{tag}," +
10187
+ "例如 ccr.ccs.tencentyun.com/your-ns/demo-app:demo-app-001。不要使用 :latest。"),
10188
+ registryId: zod_1.z
10189
+ .string()
10190
+ .optional()
10191
+ .describe("TCR 实例 ID,形如 tcr-xxxxxxxx。imageType=enterprise 时必填。"),
10192
+ command: zod_1.z
10193
+ .string()
10194
+ .optional()
10195
+ .describe("覆盖镜像 ENTRYPOINT。不填则使用 Dockerfile 默认值,例如 python。"),
10196
+ args: zod_1.z
10197
+ .string()
10198
+ .optional()
10199
+ .describe("覆盖镜像 CMD,空格分隔,例如 -u app.py。"),
10200
+ entryPoint: zod_1.z.string().optional().describe("镜像入口点,一般不需要单独设置。"),
10201
+ imagePort: zod_1.z
10202
+ .number()
10203
+ .optional()
10204
+ .describe("容器监听端口。Web Server 函数填 9000(默认),Job 型镜像填 -1。"),
10205
+ containerImageAccelerate: zod_1.z
10206
+ .boolean()
10207
+ .optional()
10208
+ .describe("是否开启镜像加速。镜像较大时建议开启以缩短冷启动时间。"),
10209
+ });
10137
10210
  const SEVEN_FIELD_CRON_REGEX = /^\s*\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s*$/;
10138
10211
  function validateTimerCron(config) {
10139
10212
  const trimmed = config.trim();
@@ -10193,7 +10266,11 @@ const CREATE_FUNCTION_SCHEMA = zod_1.z.object({
10193
10266
  ` Python: ${exports.RECOMMENDED_RUNTIMES.python}\n` +
10194
10267
  ` PHP: ${exports.RECOMMENDED_RUNTIMES.php}\n` +
10195
10268
  ` Java: ${exports.RECOMMENDED_RUNTIMES.java}\n` +
10196
- ` Go: ${exports.RECOMMENDED_RUNTIMES.golang}`),
10269
+ ` Go: ${exports.RECOMMENDED_RUNTIMES.golang}\n\n` +
10270
+ `镜像部署(基于 TCR 镜像创建函数)时填 "${exports.CUSTOM_IMAGE_RUNTIME}",并提供 imageConfig;此时无需 functionRootPath/zipFile。`),
10271
+ imageConfig: IMAGE_CONFIG_SCHEMA.optional().describe("镜像部署配置(仅 runtime=CustomImage 时使用)。" +
10272
+ "用于 zip→COS→CloudApp custom 构建→TCR→SCF 的「阶段 B」:基于已推送到 TCR 的镜像创建 HTTP 函数。" +
10273
+ "传入 imageConfig 后即按镜像部署处理,函数无需打包本地代码、scf_bootstrap 或 Handler。"),
10197
10274
  triggers: zod_1.z.array(TRIGGER_SCHEMA).optional().describe("触发器配置数组"),
10198
10275
  handler: zod_1.z.string().optional().describe("函数入口"),
10199
10276
  ignore: zod_1.z.union([zod_1.z.string(), zod_1.z.array(zod_1.z.string())]).optional().describe("忽略文件"),
@@ -10342,7 +10419,12 @@ function registerFunctionTools(server) {
10342
10419
  return;
10343
10420
  }
10344
10421
  if (input.action === "createFunction" || input.action === "updateFunctionCode") {
10345
- throw new Error(`${input.action} 在 cloud mode 下不可用,因为该操作依赖本地函数代码目录。请改用本地模式执行。`);
10422
+ // 镜像部署不依赖本地代码目录(代码已在 TCR),cloud mode 下可用。
10423
+ const hasImageConfig = Boolean(input.imageConfig ?? input.func?.imageConfig);
10424
+ if (hasImageConfig) {
10425
+ return;
10426
+ }
10427
+ throw new Error(`${input.action} 在 cloud mode 下不可用,因为该操作依赖本地函数代码目录。请改用本地模式执行,或使用镜像部署(runtime=CustomImage + imageConfig)。`);
10346
10428
  }
10347
10429
  if (input.action === "createLayerVersion" && input.contentPath) {
10348
10430
  throw new Error("createLayerVersion 在 cloud mode 下不支持 contentPath,本地文件内容请改为 base64Content 或改用本地模式执行。");
@@ -10692,6 +10774,70 @@ function registerFunctionTools(server) {
10692
10774
  const func = { ...input.func };
10693
10775
  const functionName = String(func.name);
10694
10776
  (0, logger_js_1.debug)(`[createFunction] name=${functionName}, type=${String(func.type || "Event")}`);
10777
+ // 镜像部署分支(Runtime=CustomImage):基于已推送到 TCR 的镜像创建 HTTP 函数。
10778
+ // 对应 zip→COS→CloudApp custom 构建→TCR→SCF 链路的「阶段 B」。
10779
+ const createImageConfig = input.imageConfig ??
10780
+ func.imageConfig;
10781
+ const isImageRuntime = typeof func.runtime === "string" &&
10782
+ func.runtime.replace(/\s+/g, "").toLowerCase() ===
10783
+ exports.CUSTOM_IMAGE_RUNTIME.toLowerCase();
10784
+ if (createImageConfig || isImageRuntime) {
10785
+ if (!createImageConfig?.imageUri) {
10786
+ throw new Error("镜像部署(runtime=CustomImage)时,imageConfig.imageUri 是必需的," +
10787
+ "格式为 {domain}/{namespace}/{image}:{tag}(含 tag,不要用 :latest)。");
10788
+ }
10789
+ if ((createImageConfig.imageType ?? "enterprise") === "enterprise" &&
10790
+ !createImageConfig.registryId) {
10791
+ throw new Error("imageType=enterprise(企业版 TCR)时,imageConfig.registryId(tcr-xxxxxxxx)是必需的。");
10792
+ }
10793
+ // 镜像函数即 HTTP 函数;Manager SDK 会自动补 ImageType=enterprise、ImagePort=9000,
10794
+ // 并在镜像部署时剥离 Handler / InstallDependency,故此处不需要 functionRootPath。
10795
+ const imageFunc = {
10796
+ ...func,
10797
+ type: func.type ?? "HTTP",
10798
+ runtime: exports.CUSTOM_IMAGE_RUNTIME,
10799
+ imageConfig: createImageConfig,
10800
+ };
10801
+ delete imageFunc.installDependency;
10802
+ let imageResult;
10803
+ try {
10804
+ imageResult = await cloudbase.functions.createFunction({
10805
+ func: imageFunc,
10806
+ deployMode: "image",
10807
+ force: Boolean(input.force),
10808
+ });
10809
+ }
10810
+ catch (error) {
10811
+ throw wrapFunctionOperationError("createFunction", functionName, undefined, error);
10812
+ }
10813
+ (0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, imageResult);
10814
+ return buildEnvelope({
10815
+ action: input.action,
10816
+ functionName,
10817
+ deployMode: "image",
10818
+ imageUri: createImageConfig.imageUri,
10819
+ raw: imageResult,
10820
+ }, `已基于镜像 ${createImageConfig.imageUri} 创建 HTTP 函数 ${functionName}。` +
10821
+ `请确认 TCR、SCF 与构建管道处于同一地域;如需通过 URL 访问,请显式调用 ` +
10822
+ `manageGateway(action="createAccess", type="HTTP") 并按需调整函数安全规则。` +
10823
+ `部署后可用 queryFunctions(action="getFunctionDetail") 确认函数已就绪。`, [
10824
+ {
10825
+ tool: "queryFunctions",
10826
+ action: "getFunctionDetail",
10827
+ reason: "确认镜像函数已就绪(Active)",
10828
+ },
10829
+ {
10830
+ tool: "manageFunctions",
10831
+ action: "updateFunctionCode",
10832
+ reason: "后续迭代只需用新镜像 tag 调用 updateFunctionCode 更新镜像",
10833
+ },
10834
+ {
10835
+ tool: "manageGateway",
10836
+ action: "createAccess",
10837
+ reason: "如需通过 URL 访问镜像 HTTP 函数,显式创建网关访问入口并传 type=\"HTTP\"",
10838
+ },
10839
+ ]);
10840
+ }
10695
10841
  if (func.type !== "HTTP") {
10696
10842
  const originalRuntime = typeof func.runtime === "string" ? func.runtime : undefined;
10697
10843
  func.runtime = resolveEventFunctionRuntime(func.runtime);
@@ -10785,6 +10931,42 @@ function registerFunctionTools(server) {
10785
10931
  throw new Error("updateFunctionCode 操作时,functionName 参数是必需的");
10786
10932
  }
10787
10933
  const cloudbase = await getManager();
10934
+ // 镜像更新分支:后续迭代只需用新镜像 tag 更新函数。
10935
+ const updateImageConfig = input.imageConfig ??
10936
+ input.func?.imageConfig;
10937
+ if (updateImageConfig) {
10938
+ if (!updateImageConfig.imageUri) {
10939
+ throw new Error("镜像更新时,imageConfig.imageUri 是必需的,格式为 {domain}/{namespace}/{image}:{tag}(含 tag,不要用 :latest)。");
10940
+ }
10941
+ let imageResult;
10942
+ try {
10943
+ imageResult = await cloudbase.functions.updateFunctionCode({
10944
+ func: {
10945
+ name: input.functionName,
10946
+ imageConfig: updateImageConfig,
10947
+ },
10948
+ deployMode: "image",
10949
+ });
10950
+ }
10951
+ catch (error) {
10952
+ throw wrapFunctionOperationError("updateFunctionCode", input.functionName, undefined, error);
10953
+ }
10954
+ (0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, imageResult);
10955
+ return buildEnvelope({
10956
+ action: input.action,
10957
+ functionName: input.functionName,
10958
+ deployMode: "image",
10959
+ imageUri: updateImageConfig.imageUri,
10960
+ raw: imageResult,
10961
+ }, `已将函数 ${input.functionName} 的镜像更新为 ${updateImageConfig.imageUri}。` +
10962
+ `部署后可用 queryFunctions(action="getFunctionDetail") 确认函数已就绪(Active)。`, [
10963
+ {
10964
+ tool: "queryFunctions",
10965
+ action: "getFunctionDetail",
10966
+ reason: "确认镜像更新后函数已就绪(Active)",
10967
+ },
10968
+ ]);
10969
+ }
10788
10970
  const processedRootPath = processFunctionRootPath(input.functionRootPath, input.functionName);
10789
10971
  const updateParams = {
10790
10972
  func: {
@@ -11195,6 +11377,8 @@ function registerFunctionTools(server) {
11195
11377
  title: "管理 CloudBase 云函数",
11196
11378
  description: "CloudBase 云函数统一写入口。支持创建函数、更新代码、更新配置、调用函数、管理定时跑 / 定时任务 / scheduled job 的 timer 触发器和层绑定。" +
11197
11379
  "如果要创建 cron 定时任务,先用 createFunction 创建函数,再用 createFunctionTrigger 创建 timer 触发器(支持7段cron表达式),deleteFunctionTrigger 删除触发器。" +
11380
+ "镜像部署(Runtime=CustomImage):先把代码经 zip→COS→CloudApp custom 构建→TCR 推镜像(这一阶段为裸腾讯云 API,本工具不覆盖)," +
11381
+ "再用 createFunction(func.runtime=\"CustomImage\", imageConfig) 基于 TCR 镜像创建 HTTP 函数;后续迭代用 updateFunctionCode + imageConfig 换镜像 tag。" +
11198
11382
  "危险操作需要显式 confirm=true。",
11199
11383
  inputSchema: {
11200
11384
  action: zod_1.z
@@ -11234,6 +11418,9 @@ function registerFunctionTools(server) {
11234
11418
  .optional()
11235
11419
  .describe("updateFunctionLayers 的目标层列表,顺序即最终顺序"),
11236
11420
  codeSecret: zod_1.z.string().optional().describe("层绑定时的代码保护密钥"),
11421
+ imageConfig: IMAGE_CONFIG_SCHEMA.optional().describe("镜像部署配置(Runtime=CustomImage)。createFunction 时基于 TCR 镜像创建 HTTP 函数," +
11422
+ "updateFunctionCode 时仅更换镜像 tag。需提供 imageUri(含 tag),企业版 TCR 还需 registryId。" +
11423
+ "也可在 func.imageConfig 中提供;两处都传时以顶层 imageConfig 优先。"),
11237
11424
  confirm: zod_1.z.boolean().optional().describe("危险操作确认开关。deleteFunction、deleteFunctionTrigger、deleteLayerVersion、detachLayer 等删除类操作需要显式传入 confirm=true"),
11238
11425
  incrementalFile: zod_1.z.string().optional().describe("incrementalDeployFunction 增量部署时的变更文件路径"),
11239
11426
  },
@@ -12909,7 +13096,7 @@ function registerPermissionTools(server) {
12909
13096
  }));
12910
13097
  server.registerTool?.("managePermissions", {
12911
13098
  title: "管理 CloudBase 权限与用户配置",
12912
- 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 语句(通过 `manageSqlDatabase`)。",
13099
+ 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`)。",
12913
13100
  inputSchema: {
12914
13101
  action: zod_1.z.enum(MANAGE_PERMISSION_ACTIONS),
12915
13102
  resourceType: zod_1.z
@@ -13599,7 +13786,7 @@ function registerSetupTools(server) {
13599
13786
  server.registerTool("downloadTemplate", {
13600
13787
  title: "下载项目模板",
13601
13788
  description: `自动下载并部署CloudBase项目模板。
13602
- **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.3" : 0}),便于后续维护和版本追踪\n- 下载 rules 模板时,如果项目中已存在 README.md 文件,系统会自动保护该文件不被覆盖(除非设置 overwrite=true)`,
13789
+ **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.6" : 0}),便于后续维护和版本追踪\n- 下载 rules 模板时,如果项目中已存在 README.md 文件,系统会自动保护该文件不被覆盖(除非设置 overwrite=true)`,
13603
13790
  inputSchema: {
13604
13791
  template: zod_1.z
13605
13792
  .enum(["react", "vue", "miniprogram", "uniapp", "rules"])
@@ -16879,6 +17066,8 @@ function registerAgentTools(server) {
16879
17066
  category: "agents",
16880
17067
  },
16881
17068
  }, async ({ action, agentId, name, description, runtime, timeout, memorySize, installDependency, zipFile, cosBucketRegion, tempCosObjectName, sessionConfig, cwd, params, }) => {
17069
+ let _agentName;
17070
+ let _agentRuntime;
16882
17071
  try {
16883
17072
  const cloudbase = await getManager();
16884
17073
  const payload = normalizeAgentPayload({
@@ -16895,11 +17084,19 @@ function registerAgentTools(server) {
16895
17084
  cwd,
16896
17085
  ...(params ?? {}),
16897
17086
  });
17087
+ _agentName = payload?.Name;
17088
+ _agentRuntime = payload?.Runtime;
16898
17089
  if (action === "createAgent") {
16899
17090
  const normalizedName = normalizeString(payload.Name);
16900
17091
  if (!normalizedName) {
16901
17092
  throw new Error("action=createAgent 时必须提供 name(可通过顶层 name 或 params.name 传入)");
16902
17093
  }
17094
+ // CloudBase 后端在创建 Agent 时会同步创建云函数,函数名/别名长度受 SCF 限制(最大 64 字符)。
17095
+ // envId 可能被用作前缀或别名的一部分,因此这里预留足够余量,避免后端 CreateFunction 失败。
17096
+ if (normalizedName.length > 30) {
17097
+ throw new Error(`agent name 过长(当前 ${normalizedName.length} 字符)。CloudBase 创建 Agent 时会同步创建云函数,` +
17098
+ `函数名/别名受 SCF 64 字符限制,且 envId 可能作为前缀拼接。请将 name 控制在 30 字符以内。`);
17099
+ }
16903
17100
  const createPayload = {
16904
17101
  ...payload,
16905
17102
  Name: normalizedName,
@@ -16938,6 +17135,17 @@ function registerAgentTools(server) {
16938
17135
  }, "Agent 删除成功"));
16939
17136
  }
16940
17137
  catch (error) {
17138
+ // 对后端 InternalError 提供更有意义的错误信息
17139
+ const errMsg = error instanceof Error ? error.message : String(error);
17140
+ if (errMsg.includes("InternalError") || errMsg.includes("服务处理出错")) {
17141
+ server.logger?.({
17142
+ type: "createAgentError",
17143
+ message: "createAgent 后端返回 InternalError,可能是云函数创建失败",
17144
+ originalError: errMsg,
17145
+ name: _agentName,
17146
+ runtime: _agentRuntime,
17147
+ });
17148
+ }
16941
17149
  return (0, json_content_js_1.jsonContent)(buildErrorEnvelope(error));
16942
17150
  }
16943
17151
  });
@@ -17075,7 +17283,7 @@ async function checkMysqlGate(server) {
17075
17283
  success: false,
17076
17284
  errorCode: "MYSQL_NOT_AVAILABLE",
17077
17285
  message: `This environment (${envId}) does not have MySQL. Use managePgDatabase / queryPgDatabase instead.`,
17078
- nextActions: [{ tool: "managePgDatabase", params: { action: "execute" }, description: "Use managePgDatabase" }],
17286
+ nextActions: [{ tool: "managePgDatabase", params: { action: "execute" }, description: "Use managePgDatabase for PostgreSQL operations" }],
17079
17287
  });
17080
17288
  }
17081
17289
  try {
@@ -17087,7 +17295,7 @@ async function checkMysqlGate(server) {
17087
17295
  return (0, tool_result_js_1.buildJsonToolResult)({
17088
17296
  success: false,
17089
17297
  errorCode: "MYSQL_NOT_AVAILABLE",
17090
- message: `This environment (${envId}) has PostgreSQL enabled but MySQL is NOT available. Use managePgDatabase / queryPgDatabase instead of manageSqlDatabase / querySqlDatabase.`,
17298
+ message: `This environment (${envId}) has PostgreSQL enabled but MySQL is NOT available. Use managePgDatabase / queryPgDatabase instead of manageMysqlDatabase / queryMysqlDatabase.`,
17091
17299
  nextActions: [{ tool: "managePgDatabase", params: { action: "execute" }, description: "Use managePgDatabase for PostgreSQL operations" }],
17092
17300
  });
17093
17301
  }
@@ -17096,8 +17304,8 @@ async function checkMysqlGate(server) {
17096
17304
  MYSQL_GATE_CACHE.set(envId, true);
17097
17305
  return null;
17098
17306
  }
17099
- const QUERY_SQL_DATABASE = "querySqlDatabase";
17100
- const MANAGE_SQL_DATABASE = "manageSqlDatabase";
17307
+ const QUERY_MYSQL_DATABASE = "queryMysqlDatabase";
17308
+ const MANAGE_MYSQL_DATABASE = "manageMysqlDatabase";
17101
17309
  const QUERY_PERMISSIONS = "queryPermissions";
17102
17310
  const MANAGE_PERMISSIONS = "managePermissions";
17103
17311
  const QUERY_ACTIONS = [
@@ -17389,14 +17597,14 @@ async function getSqlInstanceInfo({ getManager, cloudBaseOptions, server, }) {
17389
17597
  function buildProvisionNextActions(status, request) {
17390
17598
  if (status === "READY") {
17391
17599
  return [
17392
- buildNextAction(MANAGE_SQL_DATABASE, "initializeSchema", "MySQL is ready. Initialize tables and indexes next."),
17600
+ buildNextAction(MANAGE_MYSQL_DATABASE, "initializeSchema", "MySQL is ready. Initialize tables and indexes next."),
17393
17601
  ];
17394
17602
  }
17395
17603
  if (status === "FAILED") {
17396
17604
  return [];
17397
17605
  }
17398
17606
  return [
17399
- buildNextAction(QUERY_SQL_DATABASE, "describeCreateResult", "MySQL provisioning is still running. Check the create result again before initializing schema.", request
17607
+ buildNextAction(QUERY_MYSQL_DATABASE, "describeCreateResult", "MySQL provisioning is still running. Check the create result again before initializing schema.", request
17400
17608
  ? { action: "describeCreateResult", request }
17401
17609
  : { action: "describeCreateResult" }),
17402
17610
  ];
@@ -17415,15 +17623,15 @@ function buildTaskStatusNextActions(status, request) {
17415
17623
  if (status === "READY") {
17416
17624
  if (inferTaskKind(request) === "destroy") {
17417
17625
  return [
17418
- buildNextAction(QUERY_SQL_DATABASE, "getInstanceInfo", "The destroy task completed. Confirm whether the MySQL instance no longer exists."),
17626
+ buildNextAction(QUERY_MYSQL_DATABASE, "getInstanceInfo", "The destroy task completed. Confirm whether the MySQL instance no longer exists."),
17419
17627
  ];
17420
17628
  }
17421
17629
  return [
17422
- buildNextAction(MANAGE_SQL_DATABASE, "initializeSchema", "MySQL is ready. Initialize tables and indexes next."),
17630
+ buildNextAction(MANAGE_MYSQL_DATABASE, "initializeSchema", "MySQL is ready. Initialize tables and indexes next."),
17423
17631
  ];
17424
17632
  }
17425
17633
  return [
17426
- buildNextAction(QUERY_SQL_DATABASE, "describeTaskStatus", "MySQL task is still running. Check task status again before continuing.", request ? { action: "describeTaskStatus", request } : { action: "describeTaskStatus" }),
17634
+ buildNextAction(QUERY_MYSQL_DATABASE, "describeTaskStatus", "MySQL task is still running. Check task status again before continuing.", request ? { action: "describeTaskStatus", request } : { action: "describeTaskStatus" }),
17427
17635
  ];
17428
17636
  }
17429
17637
  async function handleRunQuery(args, context) {
@@ -17433,7 +17641,7 @@ async function handleRunQuery(args, context) {
17433
17641
  errorCode: "SQL_REQUIRED",
17434
17642
  message: "`sql` is required when action is `runQuery`.",
17435
17643
  nextActions: [
17436
- buildNextAction(QUERY_SQL_DATABASE, "runQuery", "Provide a read-only SQL statement such as SELECT/SHOW/DESCRIBE."),
17644
+ buildNextAction(QUERY_MYSQL_DATABASE, "runQuery", "Provide a read-only SQL statement such as SELECT/SHOW/DESCRIBE."),
17437
17645
  ],
17438
17646
  });
17439
17647
  }
@@ -17441,9 +17649,9 @@ async function handleRunQuery(args, context) {
17441
17649
  return buildSqlToolResult({
17442
17650
  success: false,
17443
17651
  errorCode: "READ_ONLY_SQL_REQUIRED",
17444
- message: "`querySqlDatabase(action=runQuery)` only accepts read-only SQL statements.",
17652
+ message: "`queryMysqlDatabase(action=runQuery)` only accepts read-only SQL statements.",
17445
17653
  nextActions: [
17446
- buildNextAction(MANAGE_SQL_DATABASE, "runStatement", "Use the manage tool for INSERT/UPDATE/DELETE/DDL statements."),
17654
+ buildNextAction(MANAGE_MYSQL_DATABASE, "runStatement", "Use the manage tool for INSERT/UPDATE/DELETE/DDL statements."),
17447
17655
  ],
17448
17656
  });
17449
17657
  }
@@ -17471,7 +17679,7 @@ async function handleRunQuery(args, context) {
17471
17679
  errorCode: "MYSQL_NOT_CREATED",
17472
17680
  message: "MySQL is not provisioned yet or not found. Please provision MySQL before running queries.",
17473
17681
  nextActions: [
17474
- buildNextAction(MANAGE_SQL_DATABASE, "provisionMySQL", "Provision MySQL before querying data.", { action: "provisionMySQL", confirm: true }),
17682
+ buildNextAction(MANAGE_MYSQL_DATABASE, "provisionMySQL", "Provision MySQL before querying data.", { action: "provisionMySQL", confirm: true }),
17475
17683
  ],
17476
17684
  });
17477
17685
  }
@@ -17570,7 +17778,7 @@ async function handleGetInstanceInfo(context) {
17570
17778
  nextActions: instanceInfo.exists
17571
17779
  ? undefined
17572
17780
  : [
17573
- buildNextAction(MANAGE_SQL_DATABASE, "provisionMySQL", "Provision MySQL before running SQL statements or schema initialization.", { action: "provisionMySQL", confirm: true }),
17781
+ buildNextAction(MANAGE_MYSQL_DATABASE, "provisionMySQL", "Provision MySQL before running SQL statements or schema initialization.", { action: "provisionMySQL", confirm: true }),
17574
17782
  ],
17575
17783
  });
17576
17784
  }
@@ -17581,7 +17789,7 @@ async function handleProvisionMySQL(args, context) {
17581
17789
  errorCode: "CONFIRM_REQUIRED",
17582
17790
  message: "Provisioning MySQL creates billable resources. Re-run with `confirm: true` to continue.",
17583
17791
  nextActions: [
17584
- buildNextAction(MANAGE_SQL_DATABASE, "provisionMySQL", "Explicit confirmation is required before provisioning MySQL.", { action: "provisionMySQL", confirm: true }),
17792
+ buildNextAction(MANAGE_MYSQL_DATABASE, "provisionMySQL", "Explicit confirmation is required before provisioning MySQL.", { action: "provisionMySQL", confirm: true }),
17585
17793
  ],
17586
17794
  });
17587
17795
  }
@@ -17595,7 +17803,7 @@ async function handleProvisionMySQL(args, context) {
17595
17803
  message: "A SQL database instance already exists for the current environment.",
17596
17804
  nextActions: existing.status === "READY"
17597
17805
  ? [
17598
- buildNextAction(MANAGE_SQL_DATABASE, "initializeSchema", "The instance already exists. You can initialize schema next if needed."),
17806
+ buildNextAction(MANAGE_MYSQL_DATABASE, "initializeSchema", "The instance already exists. You can initialize schema next if needed."),
17599
17807
  ]
17600
17808
  : undefined,
17601
17809
  });
@@ -17641,7 +17849,7 @@ async function handleDestroyMySQL(args, context) {
17641
17849
  errorCode: "CONFIRM_REQUIRED",
17642
17850
  message: "Destroying MySQL removes database resources. Re-run with `confirm: true` to continue.",
17643
17851
  nextActions: [
17644
- buildNextAction(MANAGE_SQL_DATABASE, "destroyMySQL", "Explicit confirmation is required before destroying MySQL.", { action: "destroyMySQL", confirm: true }),
17852
+ buildNextAction(MANAGE_MYSQL_DATABASE, "destroyMySQL", "Explicit confirmation is required before destroying MySQL.", { action: "destroyMySQL", confirm: true }),
17645
17853
  ],
17646
17854
  });
17647
17855
  }
@@ -17688,7 +17896,7 @@ async function handleDestroyMySQL(args, context) {
17688
17896
  : "MySQL destroy request was rejected.",
17689
17897
  nextActions: isSuccess
17690
17898
  ? [
17691
- buildNextAction(QUERY_SQL_DATABASE, "describeTaskStatus", "Check the MySQL destroy task status before assuming the instance is gone.", {
17899
+ buildNextAction(QUERY_MYSQL_DATABASE, "describeTaskStatus", "Check the MySQL destroy task status before assuming the instance is gone.", {
17692
17900
  action: "describeTaskStatus",
17693
17901
  request: taskRequest,
17694
17902
  }),
@@ -17711,7 +17919,7 @@ async function handleRunStatement(args, context) {
17711
17919
  errorCode: "MYSQL_NOT_CREATED",
17712
17920
  message: "MySQL is not provisioned for the current environment yet.",
17713
17921
  nextActions: [
17714
- buildNextAction(MANAGE_SQL_DATABASE, "provisionMySQL", "Provision MySQL before executing write statements or DDL.", { action: "provisionMySQL", confirm: true }),
17922
+ buildNextAction(MANAGE_MYSQL_DATABASE, "provisionMySQL", "Provision MySQL before executing write statements or DDL.", { action: "provisionMySQL", confirm: true }),
17715
17923
  ],
17716
17924
  });
17717
17925
  }
@@ -17721,7 +17929,7 @@ async function handleRunStatement(args, context) {
17721
17929
  errorCode: "MYSQL_NOT_READY",
17722
17930
  message: `MySQL is not ready yet (current status: ${instanceInfo.status}).`,
17723
17931
  nextActions: [
17724
- buildNextAction(QUERY_SQL_DATABASE, "getInstanceInfo", "Check current instance status before retrying the statement."),
17932
+ buildNextAction(QUERY_MYSQL_DATABASE, "getInstanceInfo", "Check current instance status before retrying the statement."),
17725
17933
  ],
17726
17934
  });
17727
17935
  }
@@ -17748,7 +17956,7 @@ async function handleRunStatement(args, context) {
17748
17956
  errorCode: "MYSQL_NOT_CREATED",
17749
17957
  message: "MySQL is not provisioned yet or not found. Please provision MySQL before running statements.",
17750
17958
  nextActions: [
17751
- buildNextAction(MANAGE_SQL_DATABASE, "provisionMySQL", "Provision MySQL before executing statements.", { action: "provisionMySQL", confirm: true }),
17959
+ buildNextAction(MANAGE_MYSQL_DATABASE, "provisionMySQL", "Provision MySQL before executing statements.", { action: "provisionMySQL", confirm: true }),
17752
17960
  ],
17753
17961
  });
17754
17962
  }
@@ -17777,7 +17985,7 @@ async function resolveInitializationReadiness(args, context) {
17777
17985
  errorCode: "MYSQL_NOT_CREATED",
17778
17986
  message: "MySQL is not provisioned yet. Initialize schema only after provisioning completes.",
17779
17987
  nextActions: [
17780
- buildNextAction(MANAGE_SQL_DATABASE, "provisionMySQL", "Provision MySQL before schema initialization.", { action: "provisionMySQL", confirm: true }),
17988
+ buildNextAction(MANAGE_MYSQL_DATABASE, "provisionMySQL", "Provision MySQL before schema initialization.", { action: "provisionMySQL", confirm: true }),
17781
17989
  ],
17782
17990
  }),
17783
17991
  };
@@ -17817,7 +18025,7 @@ async function resolveInitializationReadiness(args, context) {
17817
18025
  rawStatus,
17818
18026
  },
17819
18027
  nextActions: [
17820
- buildNextAction(QUERY_SQL_DATABASE, "describeTaskStatus", "Check MySQL task status until the instance becomes ready.", args.statusContext?.taskStatusRequest
18028
+ buildNextAction(QUERY_MYSQL_DATABASE, "describeTaskStatus", "Check MySQL task status until the instance becomes ready.", args.statusContext?.taskStatusRequest
17821
18029
  ? {
17822
18030
  action: "describeTaskStatus",
17823
18031
  request: args.statusContext.taskStatusRequest,
@@ -17874,7 +18082,7 @@ async function handleInitializeSchema(args, context) {
17874
18082
  errorCode: "MYSQL_NOT_CREATED",
17875
18083
  message: "MySQL is not provisioned yet or not found. Please provision MySQL before initializing schema.",
17876
18084
  nextActions: [
17877
- buildNextAction(MANAGE_SQL_DATABASE, "provisionMySQL", "Provision MySQL before executing statements.", { action: "provisionMySQL", confirm: true }),
18085
+ buildNextAction(MANAGE_MYSQL_DATABASE, "provisionMySQL", "Provision MySQL before executing statements.", { action: "provisionMySQL", confirm: true }),
17878
18086
  ],
17879
18087
  });
17880
18088
  }
@@ -17922,7 +18130,7 @@ function registerSQLDatabaseTools(server) {
17922
18130
  cloudBaseOptions,
17923
18131
  server,
17924
18132
  };
17925
- server.registerTool?.(QUERY_SQL_DATABASE, {
18133
+ server.registerTool?.(QUERY_MYSQL_DATABASE, {
17926
18134
  title: "查询 CloudBase MySQL 数据库状态或执行只读 SQL",
17927
18135
  description: "查询 CloudBase MySQL 数据库信息。支持执行只读 SQL、查询 MySQL 开通结果、查询 MySQL 任务状态,以及获取当前实例上下文信息。",
17928
18136
  inputSchema: {
@@ -17968,7 +18176,7 @@ function registerSQLDatabaseTools(server) {
17968
18176
  throw new Error(`Unsupported SQL query action: ${args.action}`);
17969
18177
  }
17970
18178
  });
17971
- server.registerTool?.(MANAGE_SQL_DATABASE, {
18179
+ server.registerTool?.(MANAGE_MYSQL_DATABASE, {
17972
18180
  title: "管理 CloudBase MySQL 数据库生命周期或执行写入 SQL",
17973
18181
  description: "管理 CloudBase MySQL 数据库资源。支持开通 MySQL、销毁 MySQL、执行写入 SQL/DDL,以及初始化数据库 Schema。注意:必须先开通 MySQL(action=provisionMySQL,confirm=true)才能执行 runStatement 或 initializeSchema。若 MySQL 尚未开通,工具会返回 MYSQL_NOT_CREATED 并给出开通的 nextAction 提示。",
17974
18182
  inputSchema: {