@cloudbase/cloudbase-mcp 2.34.7 → 2.34.8
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 +1 -1
- package/dist/index.cjs +317 -25
- package/dist/index.js +317 -25
- package/package.json +1 -1
- package/server.json +2 -2
package/dist/index.js
CHANGED
|
@@ -653,6 +653,7 @@ const logger_js_1 = __webpack_require__(781);
|
|
|
653
653
|
const tool_result_js_1 = __webpack_require__(9645);
|
|
654
654
|
const site_map_js_1 = __webpack_require__(4533);
|
|
655
655
|
const project_config_js_1 = __webpack_require__(9175);
|
|
656
|
+
const local_endpoint_js_1 = __webpack_require__(6156);
|
|
656
657
|
// Timeout for envId auto-resolution flow.
|
|
657
658
|
// 10 minutes (600 seconds) - matches InteractiveServer timeout
|
|
658
659
|
const ENV_ID_TIMEOUT = 600000;
|
|
@@ -814,7 +815,7 @@ async function listAvailableEnvCandidates(options) {
|
|
|
814
815
|
}
|
|
815
816
|
// When CLOUDBASE_ENV_ID is set and credentials are not explicit, skip DescribeEnvs.
|
|
816
817
|
const hasExplicitCredentials = !!(cloudBaseOptions?.secretId && cloudBaseOptions?.secretKey);
|
|
817
|
-
if (process.env.CLOUDBASE_ENV_ID && !hasExplicitCredentials) {
|
|
818
|
+
if (process.env.CLOUDBASE_ENV_ID && !hasExplicitCredentials && !cloudBaseOptions?.requestFn && !process.env.CLOUDBASE_LOCAL_ENDPOINT) {
|
|
818
819
|
return [{
|
|
819
820
|
envId: process.env.CLOUDBASE_ENV_ID,
|
|
820
821
|
}];
|
|
@@ -825,7 +826,7 @@ async function listAvailableEnvCandidates(options) {
|
|
|
825
826
|
...(regionOverride ? { region: regionOverride } : {}),
|
|
826
827
|
}).region;
|
|
827
828
|
let cloudbase;
|
|
828
|
-
if (cloudBaseOptions?.secretId && cloudBaseOptions?.secretKey) {
|
|
829
|
+
if (cloudBaseOptions?.requestFn || (cloudBaseOptions?.secretId && cloudBaseOptions?.secretKey)) {
|
|
829
830
|
cloudbase = createCloudBaseManagerWithOptions({
|
|
830
831
|
...cloudBaseOptions,
|
|
831
832
|
region,
|
|
@@ -1064,11 +1065,13 @@ const envManager = new EnvironmentManager();
|
|
|
1064
1065
|
exports.envManager = envManager;
|
|
1065
1066
|
// 导出环境ID获取函数
|
|
1066
1067
|
async function getEnvId(cloudBaseOptions) {
|
|
1067
|
-
// 如果传入了 cloudBaseOptions 且包含 envId,直接返回
|
|
1068
1068
|
if (cloudBaseOptions?.envId) {
|
|
1069
1069
|
(0, logger_js_1.debug)('使用传入的 envId:', { envId: cloudBaseOptions.envId });
|
|
1070
1070
|
return cloudBaseOptions.envId;
|
|
1071
1071
|
}
|
|
1072
|
+
if ((0, local_endpoint_js_1.resolveLocalEndpoint)()) {
|
|
1073
|
+
return 'local';
|
|
1074
|
+
}
|
|
1072
1075
|
const cachedEnvId = envManager.getCachedEnvId() || process.env.CLOUDBASE_ENV_ID;
|
|
1073
1076
|
if (cachedEnvId) {
|
|
1074
1077
|
(0, logger_js_1.debug)('使用缓存中的 envId:', { envId: cachedEnvId });
|
|
@@ -1173,7 +1176,16 @@ async function getDatabaseInstanceId(options) {
|
|
|
1173
1176
|
* 每次都实时获取最新的 token/secretId/secretKey
|
|
1174
1177
|
*/
|
|
1175
1178
|
async function getCloudBaseManager(options = {}) {
|
|
1176
|
-
const { requireEnvId = true,
|
|
1179
|
+
const { requireEnvId = true, authStrategy = 'fail_fast', } = options;
|
|
1180
|
+
let cloudBaseOptions = options.cloudBaseOptions;
|
|
1181
|
+
const localEndpoint = (0, local_endpoint_js_1.resolveLocalEndpoint)();
|
|
1182
|
+
if (localEndpoint && !cloudBaseOptions?.requestFn) {
|
|
1183
|
+
cloudBaseOptions = {
|
|
1184
|
+
...cloudBaseOptions,
|
|
1185
|
+
envId: cloudBaseOptions?.envId || 'local',
|
|
1186
|
+
requestFn: (0, local_endpoint_js_1.createLocalCloudApiRequestFn)(localEndpoint),
|
|
1187
|
+
};
|
|
1188
|
+
}
|
|
1177
1189
|
const hasDirectCredentials = !!(cloudBaseOptions?.secretId && cloudBaseOptions?.secretKey);
|
|
1178
1190
|
const hasRequestFn = !!(cloudBaseOptions?.requestFn);
|
|
1179
1191
|
// 如果传入了完整凭据或 requestFn,优先使用显式 CloudBase 配置
|
|
@@ -2451,7 +2463,7 @@ const types_js_1 = __webpack_require__(9921);
|
|
|
2451
2463
|
exports.apps = (0, types_js_1.defineModule)({
|
|
2452
2464
|
queryTitle: "查询 CloudBase 应用部署状态",
|
|
2453
2465
|
queryDescription: "查询 CloudBase 应用部署的应用和版本。可查应用列表/详情、版本列表/详情;部署后用 getAppVersion 按 buildId 轮询构建状态;getBuildLog 可查询构建日志用于诊断失败原因。\n" +
|
|
2454
|
-
"action=getUploadUrl(只读)可获取预签名上传 URL:无本地文件系统时(cloud mode),先拿到 uploadUrl 自行 PUT 代码 zip,再用返回的 unixTimestamp 调 manageApps(action=deployApp, cosTimestamp) 触发部署。",
|
|
2466
|
+
"action=getUploadUrl(只读)可获取预签名上传 URL:无本地文件系统时(cloud mode),先拿到 uploadUrl 自行 PUT 代码 zip,再用返回的 unixTimestamp 调 manageApps(action=deployApp, cosTimestamp) 触发部署。uploadUrl 是一次性上传凭据,不要外传或写进工单。",
|
|
2455
2467
|
manageTitle: "部署应用到 CloudBase(独立子域名)",
|
|
2456
2468
|
manageDescription: "部署 Web 应用到 CloudBase(构建前后端,部署到独立子域名)。\n" +
|
|
2457
2469
|
"云端上传通道(cloud mode,无本地文件系统):queryApps(action=getUploadUrl) 或 manageApps(action=getUploadUrl) 获取预签名上传 URL → agent 自行 PUT 代码 zip 到 uploadUrl(带 uploadHeaders 与 Content-Type: application/zip)→ 用返回的 unixTimestamp 作为 cosTimestamp 调 deployApp 触发部署。\n" +
|
|
@@ -2484,7 +2496,7 @@ exports.apps = (0, types_js_1.defineModule)({
|
|
|
2484
2496
|
uploadStep1: "1. 将代码打包为 zip(排除 node_modules/.git)",
|
|
2485
2497
|
uploadStep2: "2. 用 PUT 方法把 zip 上传到 uploadUrl,请求头带 Content-Type: application/zip 以及 uploadHeaders 中的每个 header",
|
|
2486
2498
|
uploadStep3: "3. 调用 manageApps(action=\"deployApp\", serviceName=\"{serviceName}\", cosTimestamp=<unixTimestamp>) 触发部署",
|
|
2487
|
-
getUploadUrlSuccess: "预签名上传 URL 获取成功。请将代码 zip PUT 上传到 uploadUrl(携带 uploadHeaders 与 Content-Type: application/zip),然后用返回的 unixTimestamp 作为 cosTimestamp 调用 manageApps(action=deployApp) 触发部署。",
|
|
2499
|
+
getUploadUrlSuccess: "预签名上传 URL 获取成功。请将代码 zip PUT 上传到 uploadUrl(携带 uploadHeaders 与 Content-Type: application/zip),然后用返回的 unixTimestamp 作为 cosTimestamp 调用 manageApps(action=deployApp) 触发部署。uploadUrl 是一次性上传凭据,不要外传或写进工单。",
|
|
2488
2500
|
getSuccess: "CloudBase 应用详情查询成功",
|
|
2489
2501
|
listVersionsSuccess: "CloudBase 应用版本列表查询成功",
|
|
2490
2502
|
buildIdRequired: "action=getBuildLog 时必须提供 buildId",
|
|
@@ -2547,7 +2559,7 @@ exports.apps = (0, types_js_1.defineModule)({
|
|
|
2547
2559
|
}, {
|
|
2548
2560
|
queryTitle: "Query CloudBase app deployment status",
|
|
2549
2561
|
queryDescription: "Query CloudBase deployed apps and versions. Supports app list/detail and version list/detail; after deployment, poll build status by buildId with getAppVersion; getBuildLog retrieves build logs to diagnose failures.\n" +
|
|
2550
|
-
"action=getUploadUrl (read-only) returns a pre-signed upload URL: without a local filesystem (cloud mode), fetch the uploadUrl, PUT the code zip yourself, then call manageApps(action=deployApp, cosTimestamp) with the returned unixTimestamp to trigger deployment.",
|
|
2562
|
+
"action=getUploadUrl (read-only) returns a pre-signed upload URL: without a local filesystem (cloud mode), fetch the uploadUrl, PUT the code zip yourself, then call manageApps(action=deployApp, cosTimestamp) with the returned unixTimestamp to trigger deployment. The uploadUrl is a one-time upload credential; do not forward it or paste it into tickets.",
|
|
2551
2563
|
manageTitle: "Deploy app to CloudBase (dedicated subdomain)",
|
|
2552
2564
|
manageDescription: "Deploy web apps to CloudBase (builds frontend and backend, deploys to a dedicated subdomain).\n" +
|
|
2553
2565
|
"Cloud upload channel (cloud mode, no local filesystem): queryApps(action=getUploadUrl) or manageApps(action=getUploadUrl) returns a pre-signed upload URL → agent PUTs the code zip to uploadUrl itself (with uploadHeaders and Content-Type: application/zip) → call deployApp with the returned unixTimestamp as cosTimestamp to trigger deployment.\n" +
|
|
@@ -2580,7 +2592,7 @@ exports.apps = (0, types_js_1.defineModule)({
|
|
|
2580
2592
|
uploadStep1: "1. Pack the code into a zip (exclude node_modules/.git)",
|
|
2581
2593
|
uploadStep2: "2. PUT the zip to uploadUrl with header Content-Type: application/zip and every header from uploadHeaders",
|
|
2582
2594
|
uploadStep3: "3. Call manageApps(action=\"deployApp\", serviceName=\"{serviceName}\", cosTimestamp=<unixTimestamp>) to trigger deployment",
|
|
2583
|
-
getUploadUrlSuccess: "Pre-signed upload URL obtained. PUT the code zip to uploadUrl (with uploadHeaders and Content-Type: application/zip), then call manageApps(action=deployApp) with the returned unixTimestamp as cosTimestamp to trigger deployment.",
|
|
2595
|
+
getUploadUrlSuccess: "Pre-signed upload URL obtained. PUT the code zip to uploadUrl (with uploadHeaders and Content-Type: application/zip), then call manageApps(action=deployApp) with the returned unixTimestamp as cosTimestamp to trigger deployment. The uploadUrl is a one-time upload credential; do not forward it or paste it into tickets.",
|
|
2584
2596
|
getSuccess: "CloudBase app details retrieved successfully",
|
|
2585
2597
|
listVersionsSuccess: "CloudBase app version list retrieved successfully",
|
|
2586
2598
|
buildIdRequired: "buildId is required when action=getBuildLog",
|
|
@@ -5159,6 +5171,7 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
5159
5171
|
unsupportedAction: "不支持的操作类型: {action}",
|
|
5160
5172
|
storageMissing: "当前环境没有可用的对象存储桶(DescribeEnvs 未返回 Storages),无法使用 COS 两段式部署。请检查环境存储配置,或改用本地模式部署。共享存储桶(ExternalStorage)环境同样不支持该通道。",
|
|
5161
5173
|
credentialMissing: "当前凭据缺少 SecretId/SecretKey(如 IDE 代理模式),无法本地铸造 COS 预签名上传地址。请改用本地模式或包含永久密钥/临时密钥的登录方式。",
|
|
5174
|
+
uploadTargetNotFound: "代码包上传目标不在本进程的登记里:{objectName}。ZIP 两段式部署要求 code 三元组来自本进程刚返回的 getFunctionUploadUrl(同一个 MCP 进程、同一个环境);MCP Server 已重启、换了环境、或自行拼装 cosObjectName / cosBucketName 都会落到这里。请重新调用 queryFunctions action=getFunctionUploadUrl 取地址,按返回值上传代码包,再用返回的三元组调用本 action。",
|
|
5162
5175
|
// ---- nextActions reasons ----
|
|
5163
5176
|
"reason.continuePolling": "继续查询云函数部署状态",
|
|
5164
5177
|
"reason.getDetail": "查看单个函数详情",
|
|
@@ -5217,7 +5230,7 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
5217
5230
|
gotLayerVersionDetail: "已获取层 {layerName} 版本 {layerVersion} 的详情",
|
|
5218
5231
|
gotFunctionTriggers: "已获取函数 {fnName} 的触发器列表",
|
|
5219
5232
|
gotDownloadUrl: "已获取函数 {fnName} 的代码下载链接",
|
|
5220
|
-
gotUploadUrl: "已生成函数代码包上传地址({seconds} 秒内有效)。下一步:PUT 代码 zip 到 uploadUrl(uploadHeaders 非空时须随请求携带),再调用 manageFunctions createFunction/updateFunctionCode 并传入 code 三元组(cosBucketName/cosObjectName/cosBucketRegion
|
|
5233
|
+
gotUploadUrl: "已生成函数代码包上传地址({seconds} 秒内有效)。下一步:PUT 代码 zip 到 uploadUrl(uploadHeaders 非空时须随请求携带),再调用 manageFunctions createFunction/updateFunctionCode 并传入 code 三元组(cosBucketName/cosObjectName/cosBucketRegion)完成部署。该 uploadUrl 等同一次性上传凭据,不要外传或写进工单;若上传前已过期,重新调用 getFunctionUploadUrl 取新地址",
|
|
5221
5234
|
gotFunctionVersions: "已获取函数 {fnName} 的版本列表",
|
|
5222
5235
|
gotFunctionAlias: "已获取函数 {fnName} 的别名 {aliasName}",
|
|
5223
5236
|
publishedVersion: "已发布函数 {fnName} 的新版本 {version}",
|
|
@@ -5291,7 +5304,7 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
5291
5304
|
"schema.create.layers": "Layer 配置",
|
|
5292
5305
|
"schema.manageLayer.name": "层名称",
|
|
5293
5306
|
"schema.manageLayer.version": "层版本号",
|
|
5294
|
-
"schema.query.action": "只读操作类型:\n- `listFunctions`: 列出所有 CloudBase 云函数\n- `getFunctionDetail`: 获取 CloudBase 云函数详情(需要 functionName)\n- `listFunctionLogs`: 查询 CloudBase 云函数执行日志(需要 functionName)\n- `getFunctionLogDetail`: 获取日志详情(需要 requestId)\n- `listFunctionLayers`: 列出函数绑定的层\n- `listLayers`: 列出所有层(账号级视图,含其他环境创建的层)\n- `listLayerVersions`: 列出层的版本(注意:是 Versions 不是 Version;账号级视图)\n- `getLayerVersionDetail`: 获取层版本详情(账号级视图)\n- `listFunctionTriggers`: 列出函数触发器(用于查看定时任务 / cron / timer 配置)\n- `getFunctionDownloadUrl`: 获取函数代码下载地址\n- `getFunctionDeployStatus`: 按 taskId 查询异步部署状态、阶段进度和最终结果。返回 data.build(构建子状态)、data.deploy(部署子状态)、data.progress(阶段事件);status=running 时 data.result 与 data.error 一律为 null,不得报告部署完成。调用方必须持续轮询直到 status=succeeded/failed;status=expired 表示任务超过最长保留时间(2 小时)被终结,云端可能仍在部署,需用 getFunctionDetail 确认。任务只保存在 MCP 进程内存中,过期或 MCP Server 重启后返回 errorCode=DEPLOY_TASK_NOT_FOUND;任务按环境隔离,只能查到当前环境自己发起的部署。cloud mode 下本 action 不可用:异步任务只由 buildStrategy=cloud/local 的真实部署创建,而这两种策略在 cloud mode 下都不支持真实执行,image 策略则走同步部署不产生 taskId。\n- `listVersionByFunction`: 列出函数已发布版本(对齐 tcb fn list-function-versions / SDK listVersionByFunction;需要 functionName)\n- `getFunctionAlias`: 查询函数别名与流量路由(对齐 tcb fn get-route / SDK getFunctionAlias;需要 functionName;aliasName 默认 $DEFAULT)\n- `getFunctionUploadUrl`: 获取函数代码包的 COS 预签名上传地址(ZIP 两段式部署阶段 A):PUT 代码 zip 到 uploadUrl(uploadHeaders 非空时须随请求携带对应请求头),再调用 manageFunctions 的 createFunction/updateFunctionCode 并传 code 三元组(阶段 B)。functionName 可选,仅用于生成上传对象 key。返回的 uploadUrl
|
|
5307
|
+
"schema.query.action": "只读操作类型:\n- `listFunctions`: 列出所有 CloudBase 云函数\n- `getFunctionDetail`: 获取 CloudBase 云函数详情(需要 functionName)\n- `listFunctionLogs`: 查询 CloudBase 云函数执行日志(需要 functionName)\n- `getFunctionLogDetail`: 获取日志详情(需要 requestId)\n- `listFunctionLayers`: 列出函数绑定的层\n- `listLayers`: 列出所有层(账号级视图,含其他环境创建的层)\n- `listLayerVersions`: 列出层的版本(注意:是 Versions 不是 Version;账号级视图)\n- `getLayerVersionDetail`: 获取层版本详情(账号级视图)\n- `listFunctionTriggers`: 列出函数触发器(用于查看定时任务 / cron / timer 配置)\n- `getFunctionDownloadUrl`: 获取函数代码下载地址\n- `getFunctionDeployStatus`: 按 taskId 查询异步部署状态、阶段进度和最终结果。返回 data.build(构建子状态)、data.deploy(部署子状态)、data.progress(阶段事件);status=running 时 data.result 与 data.error 一律为 null,不得报告部署完成。调用方必须持续轮询直到 status=succeeded/failed;status=expired 表示任务超过最长保留时间(2 小时)被终结,云端可能仍在部署,需用 getFunctionDetail 确认。任务只保存在 MCP 进程内存中,过期或 MCP Server 重启后返回 errorCode=DEPLOY_TASK_NOT_FOUND;任务按环境隔离,只能查到当前环境自己发起的部署。cloud mode 下本 action 不可用:异步任务只由 buildStrategy=cloud/local 的真实部署创建,而这两种策略在 cloud mode 下都不支持真实执行,image 策略则走同步部署不产生 taskId。\n- `listVersionByFunction`: 列出函数已发布版本(对齐 tcb fn list-function-versions / SDK listVersionByFunction;需要 functionName)\n- `getFunctionAlias`: 查询函数别名与流量路由(对齐 tcb fn get-route / SDK getFunctionAlias;需要 functionName;aliasName 默认 $DEFAULT)\n- `getFunctionUploadUrl`: 获取函数代码包的 COS 预签名上传地址(ZIP 两段式部署阶段 A):PUT 代码 zip 到 uploadUrl(uploadHeaders 非空时须随请求携带对应请求头),再调用 manageFunctions 的 createFunction/updateFunctionCode 并传 code 三元组(阶段 B)。functionName 可选,仅用于生成上传对象 key。返回的 uploadUrl 含凭据签名,不得写入日志或持久化;阶段 A 与阶段 B 必须落在同一个 MCP 进程(MCP Server 重启后需重新取地址并重新上传);地址默认 300 秒内有效",
|
|
5295
5308
|
"schema.query.functionName": "CloudBase 云函数名称。`getFunctionDetail`、`listFunctionLogs`、`listFunctionLayers`、`listFunctionTriggers`、`getFunctionDownloadUrl`、`listVersionByFunction`、`getFunctionAlias` 时必填;`getFunctionUploadUrl` 可选(仅用于生成上传对象 key)",
|
|
5296
5309
|
"schema.query.limit": "分页数量(limit)。列表类 action 可选,默认值由后端决定",
|
|
5297
5310
|
"schema.query.offset": "分页偏移(offset)。列表类 action 可选,默认 0",
|
|
@@ -5315,7 +5328,7 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
5315
5328
|
"schema.manage.force": "createFunction 时是否覆盖",
|
|
5316
5329
|
"schema.manage.functionName": "目标函数名称(顶层)。updateFunctionCode / updateFunctionConfig / invokeFunction / publishVersion / updateFunctionAliasConfig 等 action 使用此字段。不要只写在 func.name:createFunction 用 func.name,其它 action 用顶层 functionName。若误传 func.name,也会被识别为 functionName。",
|
|
5317
5330
|
"schema.manage.zipFile": "仅兼容特殊场景:预先准备好的代码包 base64 编码。普通 createFunction/updateFunctionCode 默认不要先压缩 zip,优先使用 functionRootPath。",
|
|
5318
|
-
"schema.manage.code": "ZIP 两段式部署阶段 B:代码包已通过 queryFunctions action=getFunctionUploadUrl 上传到环境 COS 桶。三元组(cosBucketName/cosObjectName/cosBucketRegion)直接使用 getFunctionUploadUrl 返回值原样透传。传入 code 后 createFunction/updateFunctionCode 不再读取本地目录(functionRootPath/zipFile 均不需要),默认不触发云端依赖安装(可用 func.installDependency 覆盖)。",
|
|
5331
|
+
"schema.manage.code": "ZIP 两段式部署阶段 B:代码包已通过 queryFunctions action=getFunctionUploadUrl 上传到环境 COS 桶。三元组(cosBucketName/cosObjectName/cosBucketRegion)直接使用 getFunctionUploadUrl 返回值原样透传。传入 code 后 createFunction/updateFunctionCode 不再读取本地目录(functionRootPath/zipFile 均不需要),默认不触发云端依赖安装(可用 func.installDependency 覆盖)。code 三元组必须是同一个 MCP 进程的 getFunctionUploadUrl 刚返回的那一组(该 process 会在阶段 A 登记上传目标),自行拼装或跨环境复用会被拒绝并要求重新取地址。",
|
|
5319
5332
|
"schema.code.cosBucketName": "环境存储桶短名(不含 -appid 后缀),直接使用 getFunctionUploadUrl 返回的 cosBucketName,不要自填",
|
|
5320
5333
|
"schema.code.cosObjectName": "上传对象 key,直接使用 getFunctionUploadUrl 返回的 cosObjectName",
|
|
5321
5334
|
"schema.code.cosBucketRegion": "存储桶地域,省略时自动使用当前环境存储桶地域",
|
|
@@ -5439,6 +5452,7 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
5439
5452
|
unsupportedAction: "Unsupported action: {action}",
|
|
5440
5453
|
storageMissing: "The current environment has no usable object storage bucket (DescribeEnvs returned no Storages), so COS two-phase deployment is unavailable. Check the environment storage configuration, or deploy in local mode. Environments with a shared bucket (ExternalStorage) are not supported either.",
|
|
5441
5454
|
credentialMissing: "The current credential lacks SecretId/SecretKey (e.g. IDE proxy mode), so a COS presigned upload URL cannot be minted locally. Use local mode or a login method with permanent/temporary keys.",
|
|
5455
|
+
uploadTargetNotFound: "The code package upload target is not registered in this process: {objectName}. Two-phase ZIP deployment requires the code triplet to come from a getFunctionUploadUrl response minted by this same MCP process and environment; a restarted MCP Server, a different environment, or a hand-built cosObjectName / cosBucketName all land here. Call queryFunctions action=getFunctionUploadUrl again, upload the code package to the returned address, then call this action with the returned triplet.",
|
|
5442
5456
|
// ---- nextActions reasons ----
|
|
5443
5457
|
"reason.continuePolling": "Keep polling the cloud function deployment status",
|
|
5444
5458
|
"reason.getDetail": "View details of a single function",
|
|
@@ -5497,7 +5511,7 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
5497
5511
|
gotLayerVersionDetail: "Retrieved details of layer {layerName} version {layerVersion}",
|
|
5498
5512
|
gotFunctionTriggers: "Retrieved the trigger list of function {fnName}",
|
|
5499
5513
|
gotDownloadUrl: "Retrieved the code download URL of function {fnName}",
|
|
5500
|
-
gotUploadUrl: "Generated the code package upload URL (valid for {seconds} seconds). Next: PUT the code zip to uploadUrl (include the uploadHeaders when non-empty), then call manageFunctions createFunction/updateFunctionCode with the code triplet (cosBucketName/cosObjectName/cosBucketRegion) to deploy",
|
|
5514
|
+
gotUploadUrl: "Generated the code package upload URL (valid for {seconds} seconds). Next: PUT the code zip to uploadUrl (include the uploadHeaders when non-empty), then call manageFunctions createFunction/updateFunctionCode with the code triplet (cosBucketName/cosObjectName/cosBucketRegion) to deploy. Treat the uploadUrl as a one-time upload credential: do not forward it or paste it into tickets; if it expires before the upload, call getFunctionUploadUrl again for a fresh address",
|
|
5501
5515
|
gotFunctionVersions: "Retrieved the version list of function {fnName}",
|
|
5502
5516
|
gotFunctionAlias: "Retrieved alias {aliasName} of function {fnName}",
|
|
5503
5517
|
publishedVersion: "Published new version {version} of function {fnName}",
|
|
@@ -5571,7 +5585,7 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
5571
5585
|
"schema.create.layers": "Layer configuration",
|
|
5572
5586
|
"schema.manageLayer.name": "Layer name",
|
|
5573
5587
|
"schema.manageLayer.version": "Layer version number",
|
|
5574
|
-
"schema.query.action": "Read-only action type:\n- `listFunctions`: list all CloudBase cloud functions\n- `getFunctionDetail`: get function details (requires functionName)\n- `listFunctionLogs`: query function execution logs (requires functionName)\n- `getFunctionLogDetail`: get log details (requires requestId)\n- `listFunctionLayers`: list layers bound to a function\n- `listLayers`: list all layers (account-level view, including layers from other environments)\n- `listLayerVersions`: list layer versions (Versions, not Version; account-level view)\n- `getLayerVersionDetail`: get layer version details (account-level view)\n- `listFunctionTriggers`: list function triggers (scheduled task / cron / timer configuration)\n- `getFunctionDownloadUrl`: get the function code download URL\n- `getFunctionDeployStatus`: query async deployment status, stage progress, and final result by taskId. Returns data.build, data.deploy, and data.progress. While status=running, data.result and data.error are null and deployment must not be reported as complete. Keep polling until status=succeeded/failed. status=expired means the task exceeded the 2-hour retention limit; cloud deployment may still be running, so confirm with getFunctionDetail. Tasks exist only in MCP process memory; expired tasks or a restarted MCP Server return errorCode=DEPLOY_TASK_NOT_FOUND. Tasks are isolated by environment. This action is unavailable in cloud mode because real cloud/local builds cannot run there, while image deployment is synchronous and creates no taskId.\n- `listVersionByFunction`: list published function versions (aligns with tcb fn list-function-versions / SDK listVersionByFunction; requires functionName)\n- `getFunctionAlias`: get function alias and traffic routing (aligns with tcb fn get-route / SDK getFunctionAlias; requires functionName; aliasName defaults to $DEFAULT)\n- `getFunctionUploadUrl`: get a COS presigned upload URL for a function code package (two-phase ZIP deployment phase A): PUT the code zip to uploadUrl (include the corresponding request headers when uploadHeaders is non-empty), then call manageFunctions createFunction/updateFunctionCode with the code triplet (phase B). functionName is optional and only shapes the upload object key. The uploadUrl carries credential-bound signatures; never log or persist it",
|
|
5588
|
+
"schema.query.action": "Read-only action type:\n- `listFunctions`: list all CloudBase cloud functions\n- `getFunctionDetail`: get function details (requires functionName)\n- `listFunctionLogs`: query function execution logs (requires functionName)\n- `getFunctionLogDetail`: get log details (requires requestId)\n- `listFunctionLayers`: list layers bound to a function\n- `listLayers`: list all layers (account-level view, including layers from other environments)\n- `listLayerVersions`: list layer versions (Versions, not Version; account-level view)\n- `getLayerVersionDetail`: get layer version details (account-level view)\n- `listFunctionTriggers`: list function triggers (scheduled task / cron / timer configuration)\n- `getFunctionDownloadUrl`: get the function code download URL\n- `getFunctionDeployStatus`: query async deployment status, stage progress, and final result by taskId. Returns data.build, data.deploy, and data.progress. While status=running, data.result and data.error are null and deployment must not be reported as complete. Keep polling until status=succeeded/failed. status=expired means the task exceeded the 2-hour retention limit; cloud deployment may still be running, so confirm with getFunctionDetail. Tasks exist only in MCP process memory; expired tasks or a restarted MCP Server return errorCode=DEPLOY_TASK_NOT_FOUND. Tasks are isolated by environment. This action is unavailable in cloud mode because real cloud/local builds cannot run there, while image deployment is synchronous and creates no taskId.\n- `listVersionByFunction`: list published function versions (aligns with tcb fn list-function-versions / SDK listVersionByFunction; requires functionName)\n- `getFunctionAlias`: get function alias and traffic routing (aligns with tcb fn get-route / SDK getFunctionAlias; requires functionName; aliasName defaults to $DEFAULT)\n- `getFunctionUploadUrl`: get a COS presigned upload URL for a function code package (two-phase ZIP deployment phase A): PUT the code zip to uploadUrl (include the corresponding request headers when uploadHeaders is non-empty), then call manageFunctions createFunction/updateFunctionCode with the code triplet (phase B). functionName is optional and only shapes the upload object key. The uploadUrl carries credential-bound signatures; never log or persist it; phase A and phase B must run in the same MCP process (after an MCP Server restart, fetch a new address and upload again); the address is valid for 300 seconds by default",
|
|
5575
5589
|
"schema.query.functionName": "CloudBase cloud function name. Required for `getFunctionDetail`, `listFunctionLogs`, `listFunctionLayers`, `listFunctionTriggers`, `getFunctionDownloadUrl`, `listVersionByFunction`, and `getFunctionAlias`. Optional for `getFunctionUploadUrl` (only used to generate the upload object key).",
|
|
5576
5590
|
"schema.query.limit": "Page size (limit). Optional for list actions; the backend determines the default.",
|
|
5577
5591
|
"schema.query.offset": "Pagination offset. Optional for list actions; defaults to 0.",
|
|
@@ -5595,7 +5609,7 @@ exports.functions = (0, types_js_1.defineModule)({
|
|
|
5595
5609
|
"schema.manage.force": "Whether createFunction overwrites an existing function.",
|
|
5596
5610
|
"schema.manage.functionName": "Target function name at the top level. Used by updateFunctionCode, updateFunctionConfig, invokeFunction, publishVersion, updateFunctionAliasConfig, and similar actions. createFunction uses func.name; other actions use top-level functionName. A mistakenly supplied func.name is also recognized as functionName.",
|
|
5597
5611
|
"schema.manage.zipFile": "Compatibility only: base64-encoded prebuilt code package. For ordinary createFunction/updateFunctionCode, do not create a ZIP first; prefer functionRootPath.",
|
|
5598
|
-
"schema.manage.code": "Two-phase ZIP deployment phase B: the code package has been uploaded to the environment COS bucket via queryFunctions action=getFunctionUploadUrl. Pass the triplet (cosBucketName/cosObjectName/cosBucketRegion) through unchanged from the getFunctionUploadUrl response. With code provided, createFunction/updateFunctionCode no longer reads local directories (functionRootPath/zipFile are unnecessary), and cloud dependency installation is skipped by default (override with func.installDependency).",
|
|
5612
|
+
"schema.manage.code": "Two-phase ZIP deployment phase B: the code package has been uploaded to the environment COS bucket via queryFunctions action=getFunctionUploadUrl. Pass the triplet (cosBucketName/cosObjectName/cosBucketRegion) through unchanged from the getFunctionUploadUrl response. With code provided, createFunction/updateFunctionCode no longer reads local directories (functionRootPath/zipFile are unnecessary), and cloud dependency installation is skipped by default (override with func.installDependency). The code triplet must be the one just returned by getFunctionUploadUrl in the same MCP process (that process registers the upload target in phase A); hand-built triplets or cross-environment reuse are rejected and require fetching a new address.",
|
|
5599
5613
|
"schema.code.cosBucketName": "Environment bucket short name (without the -appid suffix); pass through the cosBucketName returned by getFunctionUploadUrl, do not invent one",
|
|
5600
5614
|
"schema.code.cosObjectName": "Uploaded object key; pass through the cosObjectName returned by getFunctionUploadUrl",
|
|
5601
5615
|
"schema.code.cosBucketRegion": "Bucket region; defaults to the current environment bucket region when omitted",
|
|
@@ -7380,6 +7394,107 @@ function localizeZodSchemaShape(shape, lang, seen = new WeakMap()) {
|
|
|
7380
7394
|
}
|
|
7381
7395
|
|
|
7382
7396
|
|
|
7397
|
+
/***/ },
|
|
7398
|
+
|
|
7399
|
+
/***/ 6156
|
|
7400
|
+
(__unused_webpack_module, exports, __webpack_require__) {
|
|
7401
|
+
|
|
7402
|
+
var __webpack_unused_export__;
|
|
7403
|
+
|
|
7404
|
+
__webpack_unused_export__ = ({ value: true });
|
|
7405
|
+
__webpack_unused_export__ = assertLocalEndpoint;
|
|
7406
|
+
exports.resolveLocalEndpoint = resolveLocalEndpoint;
|
|
7407
|
+
exports.createLocalCloudApiRequestFn = createLocalCloudApiRequestFn;
|
|
7408
|
+
const logger_js_1 = __webpack_require__(781);
|
|
7409
|
+
/** Loopback hosts only. WHATWG URL keeps the brackets on IPv6 hostnames. */
|
|
7410
|
+
const ALLOWED_HOSTS = new Set(['127.0.0.1', '[::1]', 'localhost']);
|
|
7411
|
+
/** Upper bound for one cloud API call, so a hung endpoint cannot block a tool call forever. */
|
|
7412
|
+
const ENDPOINT_TIMEOUT_MS = 30_000;
|
|
7413
|
+
let announcedEndpoint;
|
|
7414
|
+
/**
|
|
7415
|
+
* Validate and normalise CLOUDBASE_LOCAL_ENDPOINT.
|
|
7416
|
+
*
|
|
7417
|
+
* Setting this variable makes cloud API calls skip the login and credential
|
|
7418
|
+
* checks, so it must never point off the local machine.
|
|
7419
|
+
*/
|
|
7420
|
+
function assertLocalEndpoint(endpoint) {
|
|
7421
|
+
let parsed;
|
|
7422
|
+
try {
|
|
7423
|
+
parsed = new URL(endpoint);
|
|
7424
|
+
}
|
|
7425
|
+
catch {
|
|
7426
|
+
throw new Error('CLOUDBASE_LOCAL_ENDPOINT is not a valid URL');
|
|
7427
|
+
}
|
|
7428
|
+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
7429
|
+
throw new Error('CLOUDBASE_LOCAL_ENDPOINT must use http or https');
|
|
7430
|
+
}
|
|
7431
|
+
if (!ALLOWED_HOSTS.has(parsed.hostname)) {
|
|
7432
|
+
throw new Error('CLOUDBASE_LOCAL_ENDPOINT must point at a loopback host');
|
|
7433
|
+
}
|
|
7434
|
+
return endpoint.replace(/\/+$/, '');
|
|
7435
|
+
}
|
|
7436
|
+
/**
|
|
7437
|
+
* Read and validate CLOUDBASE_LOCAL_ENDPOINT. Returns undefined when unset.
|
|
7438
|
+
*
|
|
7439
|
+
* A malformed value throws instead of silently falling back, so a bad config
|
|
7440
|
+
* surfaces as a config error rather than looking like an auth failure.
|
|
7441
|
+
*/
|
|
7442
|
+
function resolveLocalEndpoint() {
|
|
7443
|
+
const raw = process.env.CLOUDBASE_LOCAL_ENDPOINT;
|
|
7444
|
+
if (!raw) {
|
|
7445
|
+
return undefined;
|
|
7446
|
+
}
|
|
7447
|
+
const base = assertLocalEndpoint(raw);
|
|
7448
|
+
if (announcedEndpoint !== base) {
|
|
7449
|
+
announcedEndpoint = base;
|
|
7450
|
+
(0, logger_js_1.warn)(`CLOUDBASE_LOCAL_ENDPOINT is set: cloud API calls go to ${base} and the login/credential check is skipped`);
|
|
7451
|
+
}
|
|
7452
|
+
return base;
|
|
7453
|
+
}
|
|
7454
|
+
/**
|
|
7455
|
+
* manager-node 5.8.8 routes both DatabaseService.executePGSql and
|
|
7456
|
+
* commonService().call through CloudService.request. That method delegates
|
|
7457
|
+
* to context.requestFn and skips TC3 when the function is set.
|
|
7458
|
+
*/
|
|
7459
|
+
function createLocalCloudApiRequestFn(endpoint) {
|
|
7460
|
+
const base = assertLocalEndpoint(endpoint);
|
|
7461
|
+
return async ({ service, action, version, region, payload }) => {
|
|
7462
|
+
const response = await fetch(`${base}/capi`, {
|
|
7463
|
+
method: 'POST',
|
|
7464
|
+
headers: {
|
|
7465
|
+
'content-type': 'application/json',
|
|
7466
|
+
'x-tc-action': action,
|
|
7467
|
+
'x-tc-version': version,
|
|
7468
|
+
'x-tc-region': region,
|
|
7469
|
+
'x-tc-service': service,
|
|
7470
|
+
},
|
|
7471
|
+
body: JSON.stringify(payload ?? {}),
|
|
7472
|
+
signal: AbortSignal.timeout(ENDPOINT_TIMEOUT_MS),
|
|
7473
|
+
redirect: 'manual',
|
|
7474
|
+
});
|
|
7475
|
+
// With redirect: 'manual' a 3xx comes back as an opaque redirect (status 0)
|
|
7476
|
+
// instead of being followed, so both shapes must be rejected explicitly.
|
|
7477
|
+
if (response.type === 'opaqueredirect' || (response.status >= 300 && response.status < 400)) {
|
|
7478
|
+
throw new Error('CLOUDBASE_LOCAL_ENDPOINT responded with a redirect; redirects are not followed');
|
|
7479
|
+
}
|
|
7480
|
+
const body = await response.json();
|
|
7481
|
+
const inner = body.Response;
|
|
7482
|
+
if (!inner) {
|
|
7483
|
+
const error = new Error('missing Response');
|
|
7484
|
+
error.code = 'InternalError';
|
|
7485
|
+
throw error;
|
|
7486
|
+
}
|
|
7487
|
+
const apiError = inner.Error;
|
|
7488
|
+
if (apiError) {
|
|
7489
|
+
const error = new Error(apiError.Message || apiError.Code || 'cloud api error');
|
|
7490
|
+
error.code = apiError.Code;
|
|
7491
|
+
throw error;
|
|
7492
|
+
}
|
|
7493
|
+
return inner;
|
|
7494
|
+
};
|
|
7495
|
+
}
|
|
7496
|
+
|
|
7497
|
+
|
|
7383
7498
|
/***/ },
|
|
7384
7499
|
|
|
7385
7500
|
/***/ 6324
|
|
@@ -21901,6 +22016,7 @@ function registerEnvTools(server) {
|
|
|
21901
22016
|
typeof cloudBaseOptions?.envId === "string" &&
|
|
21902
22017
|
cloudBaseOptions.envId.length > 0;
|
|
21903
22018
|
const envIdFromEnv = !cloudBaseOptions?.requestFn &&
|
|
22019
|
+
!process.env.CLOUDBASE_LOCAL_ENDPOINT &&
|
|
21904
22020
|
(process.env.CLOUDBASE_ENV_ID ||
|
|
21905
22021
|
(isEnvScopedCredential ? cloudBaseOptions.envId : undefined));
|
|
21906
22022
|
const shouldPinToEnvVar = Boolean(envIdFromEnv &&
|
|
@@ -22922,7 +23038,7 @@ function resolveMcpVersion(declared, packageVersion) {
|
|
|
22922
23038
|
return fromPackage;
|
|
22923
23039
|
}
|
|
22924
23040
|
function readDeclaredMcpVersion() {
|
|
22925
|
-
return true ? "2.34.
|
|
23041
|
+
return true ? "2.34.8" : 0;
|
|
22926
23042
|
}
|
|
22927
23043
|
function blank(value, lang) {
|
|
22928
23044
|
return value.trim().length > 0 ? value.trim() : (lang === "en" ? "blank" : "留空");
|
|
@@ -23281,7 +23397,7 @@ function encodeKv(obj) {
|
|
|
23281
23397
|
* Host 头始终签入(对齐 SDK ForceSignHost 默认 true),query 为空故 q-url-param-list 为空。
|
|
23282
23398
|
*/
|
|
23283
23399
|
function buildCosPutAuthorization(options) {
|
|
23284
|
-
const { secretId, secretKey, bucket, region, objectKey, securityToken, expiresInSeconds =
|
|
23400
|
+
const { secretId, secretKey, bucket, region, objectKey, securityToken, expiresInSeconds = 300, } = options;
|
|
23285
23401
|
if (!secretId)
|
|
23286
23402
|
throw new Error("missing param SecretId");
|
|
23287
23403
|
if (!secretKey)
|
|
@@ -23329,15 +23445,20 @@ function buildCosPutAuthorization(options) {
|
|
|
23329
23445
|
}
|
|
23330
23446
|
/**
|
|
23331
23447
|
* 生成两段式部署阶段 A 的完整返回体:预签名 PUT URL + 阶段 B 所需的 COS 三元组。
|
|
23332
|
-
* 对象 key 形如 `fnzip-upload/{ts}-{rand}/{functionName|code}.zip
|
|
23333
|
-
*
|
|
23448
|
+
* 对象 key 形如 `fnzip-upload/{ts}-{rand}/{functionName|code}.zip`。functionName 会被
|
|
23449
|
+
* 收窄到 COS 签名安全字符(字母数字与 -_),保证签名 pathname 与请求 URL 一致。
|
|
23334
23450
|
*/
|
|
23335
23451
|
function buildFunctionZipUpload(params) {
|
|
23336
23452
|
const { storage, credential, functionName } = params;
|
|
23337
|
-
const expiresIn = params.expiresIn ??
|
|
23453
|
+
const expiresIn = params.expiresIn ?? 300;
|
|
23338
23454
|
const ts = params.now ?? Math.floor(Date.now() / 1000);
|
|
23339
23455
|
const rand = params.randomSuffix ?? (0, crypto_1.randomBytes)(8).toString("hex");
|
|
23340
|
-
|
|
23456
|
+
// functionName 只用于让对象 key 可读,必须收窄:否则 "../" 之类能把对象写到
|
|
23457
|
+
// fnzip-upload/ 前缀之外
|
|
23458
|
+
const safeFunctionName = functionName && /^[A-Za-z0-9_-]{1,64}$/.test(functionName)
|
|
23459
|
+
? functionName
|
|
23460
|
+
: "code";
|
|
23461
|
+
const objectKey = `fnzip-upload/${ts}-${rand}/${safeFunctionName}.zip`;
|
|
23341
23462
|
const keyTime = params.keyTime ?? `${ts - 1};${ts + expiresIn}`;
|
|
23342
23463
|
const authorization = buildCosPutAuthorization({
|
|
23343
23464
|
secretId: credential.secretId,
|
|
@@ -24717,6 +24838,127 @@ async function waitUntilFunctionActive(getStatus, options = {}) {
|
|
|
24717
24838
|
}
|
|
24718
24839
|
|
|
24719
24840
|
|
|
24841
|
+
/***/ },
|
|
24842
|
+
|
|
24843
|
+
/***/ 7499
|
|
24844
|
+
(__unused_webpack_module, exports, __webpack_require__) {
|
|
24845
|
+
|
|
24846
|
+
var __webpack_unused_export__;
|
|
24847
|
+
|
|
24848
|
+
__webpack_unused_export__ = ({ value: true });
|
|
24849
|
+
exports.FUNCTION_UPLOAD_TARGET_NOT_FOUND_ERROR_CODE = exports.S1 = void 0;
|
|
24850
|
+
exports.registerFunctionUploadTarget = registerFunctionUploadTarget;
|
|
24851
|
+
exports.findFunctionUploadTarget = findFunctionUploadTarget;
|
|
24852
|
+
__webpack_unused_export__ = getFunctionUploadTargetCount;
|
|
24853
|
+
__webpack_unused_export__ = resetFunctionUploadTargets;
|
|
24854
|
+
const function_cos_upload_js_1 = __webpack_require__(5735);
|
|
24855
|
+
/**
|
|
24856
|
+
* 云函数 ZIP 两段式部署的「上传目标」进程内登记。
|
|
24857
|
+
*
|
|
24858
|
+
* 阶段 A(queryFunctions action=getFunctionUploadUrl)铸造预签名上传地址时,
|
|
24859
|
+
* 在本进程登记这次铸造出来的 (envId, bucket, region, objectKey);阶段 B
|
|
24860
|
+
* (manageFunctions createFunction / updateFunctionCode 带 code 三元组)只接受
|
|
24861
|
+
* 登记过的组合。
|
|
24862
|
+
*
|
|
24863
|
+
* 为什么需要它:code.cosObjectName 是模型可以自由填写的字符串,如果不校验,
|
|
24864
|
+
* 它可以指向环境桶里的任意对象,也可以指向另一个桶(包括调用方自己的桶)——
|
|
24865
|
+
* SCF 会用环境角色去拉取那个对象。登记把可用面收窄成「本进程刚为当前环境铸造
|
|
24866
|
+
* 出来的那个 key」。
|
|
24867
|
+
*
|
|
24868
|
+
* 取舍(刻意不做的事):
|
|
24869
|
+
* - 不做「用一次即作废」:同一个 key 在保留期内可以重复提交。上传失败重试、
|
|
24870
|
+
* updateFunctionCode 撞上 ResourceInUse 后的重试、以及同一份代码包重复部署
|
|
24871
|
+
* 都要能重放,收窄的只是「谁能成为目标」,不是「能用几次」。
|
|
24872
|
+
* - 不区分「没登记」与「登记在别的环境」:登记按 envId 隔离,跨环境查询直接
|
|
24873
|
+
* 未命中,调用方只需要知道「这个目标不在登记里,请重新取地址」。
|
|
24874
|
+
*
|
|
24875
|
+
* 登记只保存在当前 MCP 进程内存中,MCP Server 重启即丢失 —— 此时重新调用
|
|
24876
|
+
* getFunctionUploadUrl 取地址、重新上传即可。这与 function-deploy-task-store
|
|
24877
|
+
* 的语义一致(异步部署任务同样只活在进程内)。
|
|
24878
|
+
*/
|
|
24879
|
+
exports.S1 = {
|
|
24880
|
+
/**
|
|
24881
|
+
* 登记的保留时间。远长于上传地址本身的有效期(默认 300 秒):地址过期只影响
|
|
24882
|
+
* 「还能不能 PUT」,而登记要覆盖「取地址 → 上传 → 提交部署」整条链在客户端
|
|
24883
|
+
* 可能的等待(大包上传、人工确认、agent 多轮编排)。
|
|
24884
|
+
*/
|
|
24885
|
+
ttlMs: 60 * 60 * 1000,
|
|
24886
|
+
/** 最大登记数,超出时淘汰最旧的 */
|
|
24887
|
+
maxTargets: 500,
|
|
24888
|
+
};
|
|
24889
|
+
exports.FUNCTION_UPLOAD_TARGET_NOT_FOUND_ERROR_CODE = "FUNCTION_UPLOAD_TARGET_NOT_FOUND";
|
|
24890
|
+
const uploadTargets = new Map();
|
|
24891
|
+
/**
|
|
24892
|
+
* envId 与 objectKey 都不可能含 NUL,用它拼主键不会产生歧义;
|
|
24893
|
+
* 反过来,跨环境的查询无法构造出同一主键(前缀 envId 由服务端解析,调用方改不了)。
|
|
24894
|
+
*/
|
|
24895
|
+
function targetKey(envId, objectKey) {
|
|
24896
|
+
return `${envId}\u0000${objectKey}`;
|
|
24897
|
+
}
|
|
24898
|
+
function cleanupUploadTargets(now) {
|
|
24899
|
+
for (const [key, target] of uploadTargets) {
|
|
24900
|
+
if (now - target.createdAtMs > exports.S1.ttlMs) {
|
|
24901
|
+
uploadTargets.delete(key);
|
|
24902
|
+
}
|
|
24903
|
+
}
|
|
24904
|
+
}
|
|
24905
|
+
/**
|
|
24906
|
+
* 达到上限时淘汰最旧的登记。
|
|
24907
|
+
*
|
|
24908
|
+
* 与部署任务表不同,这里每一条登记都可以淘汰 —— 淘汰最坏的结果是调用方重新
|
|
24909
|
+
* 取一次上传地址,不会影响任何正在进行中的云端操作,因此不需要 warn。
|
|
24910
|
+
*/
|
|
24911
|
+
function enforceMaxTargets() {
|
|
24912
|
+
const { maxTargets } = exports.S1;
|
|
24913
|
+
if (uploadTargets.size < maxTargets) {
|
|
24914
|
+
return;
|
|
24915
|
+
}
|
|
24916
|
+
const oldestFirst = [...uploadTargets.entries()].sort((left, right) => left[1].createdAtMs - right[1].createdAtMs);
|
|
24917
|
+
for (const [key] of oldestFirst) {
|
|
24918
|
+
if (uploadTargets.size < maxTargets) {
|
|
24919
|
+
return;
|
|
24920
|
+
}
|
|
24921
|
+
uploadTargets.delete(key);
|
|
24922
|
+
}
|
|
24923
|
+
}
|
|
24924
|
+
/** 阶段 A 登记本次铸造的上传目标。 */
|
|
24925
|
+
function registerFunctionUploadTarget(input) {
|
|
24926
|
+
const now = input.now ?? Date.now();
|
|
24927
|
+
cleanupUploadTargets(now);
|
|
24928
|
+
enforceMaxTargets();
|
|
24929
|
+
uploadTargets.set(targetKey(input.envId, input.objectKey), {
|
|
24930
|
+
envId: input.envId,
|
|
24931
|
+
bucket: input.bucket,
|
|
24932
|
+
region: input.region,
|
|
24933
|
+
objectKey: input.objectKey,
|
|
24934
|
+
createdAtMs: now,
|
|
24935
|
+
});
|
|
24936
|
+
}
|
|
24937
|
+
/**
|
|
24938
|
+
* 阶段 B 校验:命中登记且桶、地域都对得上才返回目标,否则返回 undefined。
|
|
24939
|
+
*
|
|
24940
|
+
* 地域与桶都要比对 —— 只比对象 key 的话,仍然可以把同一个 key 指到别的桶或
|
|
24941
|
+
* 别的地域(例如把代码指到调用方自己的桶)上。
|
|
24942
|
+
*/
|
|
24943
|
+
function findFunctionUploadTarget(input) {
|
|
24944
|
+
const now = input.now ?? Date.now();
|
|
24945
|
+
cleanupUploadTargets(now);
|
|
24946
|
+
const target = uploadTargets.get(targetKey(input.envId, input.objectKey));
|
|
24947
|
+
if (!target) {
|
|
24948
|
+
return undefined;
|
|
24949
|
+
}
|
|
24950
|
+
const bucketMatches = (0, function_cos_upload_js_1.stripAppIdSuffix)(input.bucketName) === (0, function_cos_upload_js_1.stripAppIdSuffix)(target.bucket);
|
|
24951
|
+
return bucketMatches && input.region === target.region ? target : undefined;
|
|
24952
|
+
}
|
|
24953
|
+
function getFunctionUploadTargetCount() {
|
|
24954
|
+
return uploadTargets.size;
|
|
24955
|
+
}
|
|
24956
|
+
/** 测试用:清空登记表 */
|
|
24957
|
+
function resetFunctionUploadTargets() {
|
|
24958
|
+
uploadTargets.clear();
|
|
24959
|
+
}
|
|
24960
|
+
|
|
24961
|
+
|
|
24720
24962
|
/***/ },
|
|
24721
24963
|
|
|
24722
24964
|
/***/ 1546
|
|
@@ -24748,10 +24990,35 @@ const tool_result_js_1 = __webpack_require__(9645);
|
|
|
24748
24990
|
const function_deploy_js_1 = __webpack_require__(9151);
|
|
24749
24991
|
const function_deploy_schema_js_1 = __webpack_require__(6427);
|
|
24750
24992
|
const function_cos_upload_js_1 = __webpack_require__(5735);
|
|
24993
|
+
const function_upload_target_store_js_1 = __webpack_require__(7499);
|
|
24751
24994
|
const function_updating_js_1 = __webpack_require__(326);
|
|
24752
24995
|
const index_js_1 = __webpack_require__(4908);
|
|
24753
24996
|
const fs_1 = __webpack_require__(4421);
|
|
24754
24997
|
const path_1 = __importDefault(__webpack_require__(2521));
|
|
24998
|
+
/**
|
|
24999
|
+
* 阶段 B 校验:code 三元组必须是本进程阶段 A 登记过的上传目标。
|
|
25000
|
+
*
|
|
25001
|
+
* 未命中时统一按「目标不在登记里」返回,不区分「没登记」与「登记在别的环境」——
|
|
25002
|
+
* 与部署任务表同款取舍,调用方只需要知道下一步该重新取上传地址。
|
|
25003
|
+
*/
|
|
25004
|
+
function assertFunctionUploadTarget(input) {
|
|
25005
|
+
if ((0, function_upload_target_store_js_1.findFunctionUploadTarget)(input)) {
|
|
25006
|
+
return;
|
|
25007
|
+
}
|
|
25008
|
+
(0, tool_result_js_1.throwToolPayloadError)({
|
|
25009
|
+
success: false,
|
|
25010
|
+
errorCode: function_upload_target_store_js_1.FUNCTION_UPLOAD_TARGET_NOT_FOUND_ERROR_CODE,
|
|
25011
|
+
data: {
|
|
25012
|
+
action: input.action,
|
|
25013
|
+
cosBucketName: input.bucketName,
|
|
25014
|
+
cosBucketRegion: input.region,
|
|
25015
|
+
cosObjectName: input.objectKey,
|
|
25016
|
+
},
|
|
25017
|
+
message: (0, index_js_1.t)("functions.uploadTargetNotFound", {
|
|
25018
|
+
objectName: input.objectKey,
|
|
25019
|
+
}),
|
|
25020
|
+
});
|
|
25021
|
+
}
|
|
24755
25022
|
exports.SUPPORTED_RUNTIMES = {
|
|
24756
25023
|
nodejs: [
|
|
24757
25024
|
"Nodejs20.19",
|
|
@@ -25267,7 +25534,8 @@ function registerFunctionTools(server) {
|
|
|
25267
25534
|
if (!bucket || !region) {
|
|
25268
25535
|
throw new Error((0, index_js_1.t)("functions.storageMissing"));
|
|
25269
25536
|
}
|
|
25270
|
-
|
|
25537
|
+
// envId 一并返回:阶段 A 的上传目标登记与阶段 B 的校验都按环境隔离
|
|
25538
|
+
return { bucket, region, envId };
|
|
25271
25539
|
};
|
|
25272
25540
|
const ensureActionAllowedInCloudMode = (input) => {
|
|
25273
25541
|
if (!(0, cloud_mode_js_1.isCloudMode)()) {
|
|
@@ -25658,7 +25926,9 @@ function registerFunctionTools(server) {
|
|
|
25658
25926
|
}
|
|
25659
25927
|
const cloudbase = await getManager();
|
|
25660
25928
|
const result = await cloudbase.functions.getFunctionDownloadUrl(input.functionName, input.codeSecret);
|
|
25661
|
-
|
|
25929
|
+
// downloadUrl 是带凭据签名的临时链接:与 apps getUploadUrl 同款处理,只落 RequestId,
|
|
25930
|
+
// 避免整条 URL 随宿主日志持久化
|
|
25931
|
+
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, { RequestId: result.RequestId });
|
|
25662
25932
|
return buildEnvelope({
|
|
25663
25933
|
action: input.action,
|
|
25664
25934
|
functionName: input.functionName,
|
|
@@ -25759,6 +26029,14 @@ function registerFunctionTools(server) {
|
|
|
25759
26029
|
},
|
|
25760
26030
|
functionName: input.functionName,
|
|
25761
26031
|
});
|
|
26032
|
+
// 阶段 A 在进程内登记本次铸造的上传目标:阶段 B 只接受登记过的
|
|
26033
|
+
// (envId, bucket, region, objectKey),cosObjectName 因此不再是任意字符串。
|
|
26034
|
+
(0, function_upload_target_store_js_1.registerFunctionUploadTarget)({
|
|
26035
|
+
envId: storage.envId,
|
|
26036
|
+
bucket: storage.bucket,
|
|
26037
|
+
region: storage.region,
|
|
26038
|
+
objectKey: upload.cosObjectName,
|
|
26039
|
+
});
|
|
25762
26040
|
// uploadUrl 内含凭据绑定的签名(临时凭据还绑定 token),禁止落日志
|
|
25763
26041
|
(0, logger_js_1.debug)(`[getFunctionUploadUrl] envId=${authConfig.envId ?? "n/a"}, cosObjectName=${upload.cosObjectName}, expiresIn=${upload.expiresInSeconds}s`);
|
|
25764
26042
|
return buildEnvelope({
|
|
@@ -26040,6 +26318,13 @@ function registerFunctionTools(server) {
|
|
|
26040
26318
|
const storage = await resolveEnvFunctionCosStorage();
|
|
26041
26319
|
const cosBucketName = (0, function_cos_upload_js_1.stripAppIdSuffix)(input.code.cosBucketName || storage.bucket);
|
|
26042
26320
|
const cosBucketRegion = input.code.cosBucketRegion ?? storage.region;
|
|
26321
|
+
assertFunctionUploadTarget({
|
|
26322
|
+
envId: storage.envId,
|
|
26323
|
+
bucketName: input.code.cosBucketName || storage.bucket,
|
|
26324
|
+
region: cosBucketRegion,
|
|
26325
|
+
objectKey: input.code.cosObjectName,
|
|
26326
|
+
action: input.action,
|
|
26327
|
+
});
|
|
26043
26328
|
const codeFunc = { ...func };
|
|
26044
26329
|
// 用户 zip 自带依赖语义(装没装由上传方决定),默认不触发云端依赖安装
|
|
26045
26330
|
delete codeFunc.installDependency;
|
|
@@ -26305,6 +26590,13 @@ function registerFunctionTools(server) {
|
|
|
26305
26590
|
const storage = await resolveEnvFunctionCosStorage();
|
|
26306
26591
|
const cosBucketName = (0, function_cos_upload_js_1.stripAppIdSuffix)(input.code.cosBucketName || storage.bucket);
|
|
26307
26592
|
const cosBucketRegion = input.code.cosBucketRegion ?? storage.region;
|
|
26593
|
+
assertFunctionUploadTarget({
|
|
26594
|
+
envId: storage.envId,
|
|
26595
|
+
bucketName: input.code.cosBucketName || storage.bucket,
|
|
26596
|
+
region: cosBucketRegion,
|
|
26597
|
+
objectKey: input.code.cosObjectName,
|
|
26598
|
+
action: input.action,
|
|
26599
|
+
});
|
|
26308
26600
|
let cosUpdateResult;
|
|
26309
26601
|
try {
|
|
26310
26602
|
cosUpdateResult = await cloudbase.functions.updateFunctionCode({
|
|
@@ -35991,7 +36283,7 @@ class TelemetryReporter {
|
|
|
35991
36283
|
const arch = os_1.default.arch(); // 系统架构
|
|
35992
36284
|
// Build-time injected version; guard for vitest / non-webpack runtimes.
|
|
35993
36285
|
const mcpVersion = process.env.npm_package_version ||
|
|
35994
|
-
( true ? "2.34.
|
|
36286
|
+
( true ? "2.34.8" : 0);
|
|
35995
36287
|
return {
|
|
35996
36288
|
userAgent: `${osType} ${osRelease} ${arch} ${nodeVersion} CloudBase-MCP/${mcpVersion}`,
|
|
35997
36289
|
deviceId: this.deviceId,
|
|
@@ -36714,7 +37006,7 @@ ${envIdSection}
|
|
|
36714
37006
|
## 环境信息
|
|
36715
37007
|
- 操作系统: ${os_1.default.type()} ${os_1.default.release()}
|
|
36716
37008
|
- Node.js版本: ${process.version}
|
|
36717
|
-
- MCP 版本:${( true ? "2.34.
|
|
37009
|
+
- MCP 版本:${( true ? "2.34.8" : 0) || 0 || 0}
|
|
36718
37010
|
- 系统架构: ${os_1.default.arch()}
|
|
36719
37011
|
- 时间: ${new Date().toISOString()}
|
|
36720
37012
|
- 请求ID: ${requestId}
|
|
@@ -36812,7 +37104,7 @@ function createWrappedHandler(name, handler, server) {
|
|
|
36812
37104
|
requestId,
|
|
36813
37105
|
ide: server.ide || process.env.INTEGRATION_IDE || ''
|
|
36814
37106
|
});
|
|
36815
|
-
const mcpVersion = true ? "2.34.
|
|
37107
|
+
const mcpVersion = true ? "2.34.8" : 0;
|
|
36816
37108
|
const requestIdSuffix = requestId ? `\n🆔 RequestId: ${requestId}` : '';
|
|
36817
37109
|
const enhancedErrorMessage = `${errorMessage}${requestIdSuffix}\n\n📦 CloudBase MCP v${mcpVersion}\n🔗 遇到问题?请复制以下链接到浏览器打开\n即可自动携带错误详情快速创建 GitHub Issue:\n${issueLink}`;
|
|
36818
37110
|
// 创建新的错误对象,保持原有的错误类型但更新消息
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudbase/cloudbase-mcp",
|
|
3
|
-
"version": "2.34.
|
|
3
|
+
"version": "2.34.8",
|
|
4
4
|
"mcpName": "io.github.TencentCloudBase/cloudbase-mcp",
|
|
5
5
|
"packageManager": "pnpm@10.8.0",
|
|
6
6
|
"description": "CloudBase MCP Server — operate Tencent CloudBase (database, auth, functions, storage, hosting) from AI coding tools via the Model Context Protocol. Part of CloudBase AI Toolkit.",
|
package/server.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "io.github.TencentCloudBase/cloudbase-mcp",
|
|
4
4
|
"title": "CloudBase",
|
|
5
5
|
"description": "CloudBase MCP: DB, functions, storage, hosting via @cloudbase/cloudbase-mcp",
|
|
6
|
-
"version": "2.34.
|
|
6
|
+
"version": "2.34.8",
|
|
7
7
|
"websiteUrl": "https://github.com/TencentCloudBase/CloudBase-AI-Toolkit",
|
|
8
8
|
"repository": {
|
|
9
9
|
"url": "https://github.com/TencentCloudBase/CloudBase-AI-Toolkit",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"registryType": "npm",
|
|
26
26
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
27
27
|
"identifier": "@cloudbase/cloudbase-mcp",
|
|
28
|
-
"version": "2.34.
|
|
28
|
+
"version": "2.34.8",
|
|
29
29
|
"runtimeHint": "npx",
|
|
30
30
|
"transport": {
|
|
31
31
|
"type": "stdio"
|