@cloudbase/cloudbase-mcp 2.32.4 → 2.32.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/cli.cjs +3 -3
- package/dist/index.cjs +282 -167
- package/dist/index.d.ts +8 -0
- package/dist/index.js +282 -167
- package/package.json +1 -1
- package/server.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -4195,15 +4195,20 @@ async function fetchAccountEnvCandidates(cloudBaseOptions) {
|
|
|
4195
4195
|
function isApiKeyCredentialMode() {
|
|
4196
4196
|
return Boolean((0, auth_js_1.getCloudBaseApiKeyFromEnv)() && process.env.CLOUDBASE_ENV_ID);
|
|
4197
4197
|
}
|
|
4198
|
-
function getCredentialScope() {
|
|
4198
|
+
function getCredentialScope(cloudBaseOptions) {
|
|
4199
|
+
// 只认宿主的显式声明 credentialScope: 'env'(如 tcb-bff hosted OAuth 签发的
|
|
4200
|
+
// 环境级 federated STS)。账号级 DescribeEnvs(不带 EnvId)会被后端拒绝(invalid token)。
|
|
4201
|
+
// 注意:不能用 token 字段的有无推断范围——sessionToken 本身不携带权限范围语义。
|
|
4202
|
+
if (cloudBaseOptions?.credentialScope === "env")
|
|
4203
|
+
return "single_env";
|
|
4199
4204
|
return isApiKeyCredentialMode() ? "single_env" : "account";
|
|
4200
4205
|
}
|
|
4201
4206
|
function buildCredentialBoundaryPayload(cloudBaseOptions) {
|
|
4202
|
-
const credentialScope = getCredentialScope();
|
|
4207
|
+
const credentialScope = getCredentialScope(cloudBaseOptions);
|
|
4203
4208
|
const currentRegion = (0, site_map_js_1.resolveSiteAndRegion)(cloudBaseOptions ?? {}).region;
|
|
4204
4209
|
const pinnedEnvId = process.env.CLOUDBASE_ENV_ID || cloudBaseOptions?.envId || null;
|
|
4205
4210
|
const scopeNote = credentialScope === "single_env"
|
|
4206
|
-
?
|
|
4211
|
+
? `当前为环境级凭证登录(单环境权限,API Key 或托管授权 token)。只能访问已绑定的 envId${pinnedEnvId ? ` ${pinnedEnvId}` : ""},看不到账号下其他环境或其他地域。这是凭据权限边界,不是环境不存在。queryEnv(action="list") 会自动降级为仅返回绑定环境的信息。`
|
|
4207
4212
|
: `当前为账号级登录。DescribeEnvs 按地域查询;未传 region 时使用当前地域 ${currentRegion}。其他地域请用 queryEnv(action="list", region="ap-singapore"),或 CLI: tcb env list -r ap-singapore。`;
|
|
4208
4213
|
return {
|
|
4209
4214
|
credential_scope: credentialScope,
|
|
@@ -4322,6 +4327,24 @@ function buildAuthEnvSetupPayload(preparation) {
|
|
|
4322
4327
|
...buildEnvCandidatePayload(preparation.envCandidates),
|
|
4323
4328
|
};
|
|
4324
4329
|
}
|
|
4330
|
+
// API Key 登录态 CAM 能力受限时的用户提示(实测:部分 API Key 换出的 STS 不带 CAM 策略)
|
|
4331
|
+
const API_KEY_CAM_LIMITATION_WARNING = "\n\n⚠️ 注意:该 API Key 换取的临时凭据无法调用管理面 API(CAM 鉴权不通过),管理类工具(queryEnv、queryAppAuth、manageAppAuth 等)将不可用。如需完整能力,请改用长期密钥 TENCENTCLOUD_SECRETID / TENCENTCLOUD_SECRETKEY 认证。";
|
|
4332
|
+
/**
|
|
4333
|
+
* API Key 登录态 AUTH_READY 出口统一追加 CAM 能力探测警告。
|
|
4334
|
+
* 仅在探测明确返回 limited(CAM 拒绝)时追加;capable/unknown 静默通过。
|
|
4335
|
+
*/
|
|
4336
|
+
async function appendApiKeyCamWarningIfNeeded(loginState, message) {
|
|
4337
|
+
try {
|
|
4338
|
+
const probe = await (0, cloudbase_manager_js_1.probeApiKeyCamCapability)(loginState);
|
|
4339
|
+
return probe === "limited" ? message + API_KEY_CAM_LIMITATION_WARNING : message;
|
|
4340
|
+
}
|
|
4341
|
+
catch (e) {
|
|
4342
|
+
(0, logger_js_1.debug)("appendApiKeyCamWarningIfNeeded: probe threw", {
|
|
4343
|
+
error: e instanceof Error ? e.message : String(e),
|
|
4344
|
+
});
|
|
4345
|
+
return message;
|
|
4346
|
+
}
|
|
4347
|
+
}
|
|
4325
4348
|
async function prepareAuthEnvironment(params) {
|
|
4326
4349
|
const { server, cloudBaseOptions, loginState } = params;
|
|
4327
4350
|
const currentEnvId = (0, cloudbase_manager_js_1.getCachedEnvId)() ||
|
|
@@ -4870,10 +4893,11 @@ function buildEnvQueryErrorMessage(error, action) {
|
|
|
4870
4893
|
const hasEnvNotFoundError = /env|environment|环境.*不存在|not found/i.test(baseMessage);
|
|
4871
4894
|
const suggestions = [];
|
|
4872
4895
|
if (hasInvalidParameterError) {
|
|
4873
|
-
suggestions.push("
|
|
4874
|
-
suggestions.push("1.
|
|
4875
|
-
suggestions.push("2.
|
|
4876
|
-
suggestions.push("3.
|
|
4896
|
+
suggestions.push("参数错误:请求未通过服务端的参数校验,请检查本次调用的入参:");
|
|
4897
|
+
suggestions.push("1. 各参数取值是否在允许范围内(枚举值、时间粒度、数量上限等)");
|
|
4898
|
+
suggestions.push("2. 各参数格式是否正确,需要成对传入的参数是否齐全");
|
|
4899
|
+
suggestions.push("3. 必填参数是否都已提供,参数名与类型是否正确");
|
|
4900
|
+
suggestions.push(`4. 修正参数后重新调用 queryEnv(action=\"${action}\")`);
|
|
4877
4901
|
}
|
|
4878
4902
|
if (hasAuthError) {
|
|
4879
4903
|
suggestions.push("认证错误:当前未登录或认证已过期。");
|
|
@@ -5409,7 +5433,7 @@ function registerEnvTools(server) {
|
|
|
5409
5433
|
return (0, tool_result_js_1.buildJsonToolResult)({
|
|
5410
5434
|
ok: true,
|
|
5411
5435
|
code: "AUTH_READY",
|
|
5412
|
-
message: "当前使用 API Key 认证模式,已自动完成登录,无需手动授权。",
|
|
5436
|
+
message: await appendApiKeyCamWarningIfNeeded(existingLoginState, "当前使用 API Key 认证模式,已自动完成登录,无需手动授权。"),
|
|
5413
5437
|
auth_mode: "api_key",
|
|
5414
5438
|
envId: process.env.CLOUDBASE_ENV_ID,
|
|
5415
5439
|
});
|
|
@@ -5420,16 +5444,21 @@ function registerEnvTools(server) {
|
|
|
5420
5444
|
(0, logger_js_1.debug)("start_auth: peekLoginState threw", { error: e instanceof Error ? e.message : String(e) });
|
|
5421
5445
|
}
|
|
5422
5446
|
// API Key exchange failed: return diagnostic details
|
|
5447
|
+
const exchangeRegion = (0, site_map_js_1.resolveApiKeyExchangeRegion)();
|
|
5423
5448
|
let diagMessage = "当前配置了 API Key 认证模式,但换取临时密钥失败。";
|
|
5424
|
-
const endpoint = process.env.CLOUDBASE_API_ENDPOINT ||
|
|
5449
|
+
const endpoint = process.env.CLOUDBASE_API_ENDPOINT ||
|
|
5450
|
+
`https://${process.env.CLOUDBASE_ENV_ID}.${exchangeRegion ?? "ap-shanghai"}.tcb-api.tencentcloudapi.com`;
|
|
5425
5451
|
diagMessage += `\n\n诊断信息:`;
|
|
5426
5452
|
diagMessage += `\n- CLOUDBASE_ENV_ID: ${process.env.CLOUDBASE_ENV_ID}`;
|
|
5427
5453
|
diagMessage += `\n- CLOUDBASE_API_KEY: ${apiKeyFromEnv.slice(0, 20)}...(已截断)`;
|
|
5454
|
+
diagMessage += `\n- TCB_SITE: ${process.env.TCB_SITE || "(未设置)"}`;
|
|
5455
|
+
diagMessage += `\n- 换取网关地域: ${exchangeRegion ?? "ap-shanghai(国内站默认,多地域环境均经其路由)"}`;
|
|
5428
5456
|
diagMessage += `\n- Endpoint: ${endpoint}`;
|
|
5429
5457
|
diagMessage += `\n\n可能原因:`;
|
|
5430
5458
|
diagMessage += `\n1. API Key 已过期或被删除`;
|
|
5431
5459
|
diagMessage += `\n2. Endpoint 不可达(网络/DNS 问题)`;
|
|
5432
5460
|
diagMessage += `\n3. CLOUDBASE_ENV_ID 与 API Key 所属环境不匹配`;
|
|
5461
|
+
diagMessage += `\n4. API Key 与站点不匹配:国际站环境的 Key 需配置 TCB_SITE=intl(走 ap-singapore 网关);国内站环境(含 ap-guangzhou/ap-singapore 地域)不要配置 intl`;
|
|
5433
5462
|
diagMessage += `\n\n建议:检查 MCP 配置中的 CLOUDBASE_API_KEY(或兼容的 CLOUDBASE_APIKEY)和 CLOUDBASE_ENV_ID 环境变量是否正确。`;
|
|
5434
5463
|
return (0, tool_result_js_1.buildJsonToolResult)({
|
|
5435
5464
|
ok: false,
|
|
@@ -5640,7 +5669,7 @@ function registerEnvTools(server) {
|
|
|
5640
5669
|
return (0, tool_result_js_1.buildJsonToolResult)({
|
|
5641
5670
|
ok: true,
|
|
5642
5671
|
code: "AUTH_READY",
|
|
5643
|
-
message: "API Key 认证成功,已获取临时密钥。",
|
|
5672
|
+
message: await appendApiKeyCamWarningIfNeeded(loginState, "API Key 认证成功,已获取临时密钥。"),
|
|
5644
5673
|
auth_mode: "api_key",
|
|
5645
5674
|
...buildAuthEnvSetupPayload(envPreparation),
|
|
5646
5675
|
next_step: envPreparation.nextStep,
|
|
@@ -5653,10 +5682,12 @@ function registerEnvTools(server) {
|
|
|
5653
5682
|
diagMessage += `\n\n诊断信息:`;
|
|
5654
5683
|
diagMessage += `\n- CLOUDBASE_ENV_ID: ${toolApiKeyEnvId}`;
|
|
5655
5684
|
diagMessage += `\n- CLOUDBASE_API_KEY: ${toolApiKey.slice(0, 20)}...(已截断)`;
|
|
5685
|
+
diagMessage += `\n- TCB_SITE: ${process.env.TCB_SITE || "(未设置)"}`;
|
|
5656
5686
|
diagMessage += `\n\n可能原因:`;
|
|
5657
5687
|
diagMessage += `\n1. API Key 已过期或被删除`;
|
|
5658
5688
|
diagMessage += `\n2. CLOUDBASE_ENV_ID 与 API Key 所属环境不匹配`;
|
|
5659
|
-
diagMessage += `\n3.
|
|
5689
|
+
diagMessage += `\n3. API Key 与站点不匹配:国际站环境的 Key 需配置 TCB_SITE=intl(走 ap-singapore 网关);国内站环境(含 ap-guangzhou/ap-singapore 地域)不要配置 intl`;
|
|
5690
|
+
diagMessage += `\n4. 网络连接问题`;
|
|
5660
5691
|
diagMessage += `\n\n建议:请检查 API Key 和环境 ID 是否正确。`;
|
|
5661
5692
|
return (0, tool_result_js_1.buildJsonToolResult)({
|
|
5662
5693
|
ok: false,
|
|
@@ -5880,9 +5911,19 @@ function registerEnvTools(server) {
|
|
|
5880
5911
|
// API Key / env-var pin: skip DescribeEnvs (STS often cannot list).
|
|
5881
5912
|
// Account-level sessions that only pinned CLOUDBASE_ENV_ID via set_env
|
|
5882
5913
|
// can still pass region/alias/envId to list other environments.
|
|
5883
|
-
|
|
5914
|
+
// Hosted OAuth: 宿主(tcb-bff)显式声明 credentialScope: 'env',签发的
|
|
5915
|
+
// 环境级 federated STS 调账号级 DescribeEnvs 会被拒("invalid token"),
|
|
5916
|
+
// 同样 pin 到绑定 envId 降级为 describeEnvInfo。
|
|
5917
|
+
const isEnvScopedCredential = cloudBaseOptions?.credentialScope === "env" &&
|
|
5918
|
+
typeof cloudBaseOptions?.envId === "string" &&
|
|
5919
|
+
cloudBaseOptions.envId.length > 0;
|
|
5920
|
+
const envIdFromEnv = !cloudBaseOptions?.requestFn &&
|
|
5921
|
+
(process.env.CLOUDBASE_ENV_ID ||
|
|
5922
|
+
(isEnvScopedCredential ? cloudBaseOptions.envId : undefined));
|
|
5884
5923
|
const shouldPinToEnvVar = Boolean(envIdFromEnv &&
|
|
5885
|
-
(isApiKeyCredentialMode() ||
|
|
5924
|
+
(isApiKeyCredentialMode() ||
|
|
5925
|
+
isEnvScopedCredential ||
|
|
5926
|
+
(!region && !alias && !envId)));
|
|
5886
5927
|
if (shouldPinToEnvVar && envIdFromEnv) {
|
|
5887
5928
|
try {
|
|
5888
5929
|
const envInfo = await cloudbaseList.env.describeEnvInfo({ EnvId: envIdFromEnv });
|
|
@@ -5905,6 +5946,13 @@ function registerEnvTools(server) {
|
|
|
5905
5946
|
(0, logger_js_1.debug)("DescribeEnvInfo 失败,返回基础环境信息:", envInfoError instanceof Error ? envInfoError : new Error(String(envInfoError)));
|
|
5906
5947
|
result = { EnvList: [{ EnvId: envIdFromEnv }] };
|
|
5907
5948
|
}
|
|
5949
|
+
// 给调用方 AI 说明降级原因,避免误判为"账号只有一个环境"
|
|
5950
|
+
if (isEnvScopedCredential) {
|
|
5951
|
+
result = {
|
|
5952
|
+
...result,
|
|
5953
|
+
scope_note: `当前凭证为环境级(托管授权凭证绑定 ${envIdFromEnv}),账号级环境列表接口无权限,已降级为仅返回绑定环境的信息。如需查看账号下全部环境,请用有账号级权限的凭证登录。`,
|
|
5954
|
+
};
|
|
5955
|
+
}
|
|
5908
5956
|
}
|
|
5909
5957
|
else {
|
|
5910
5958
|
// Use commonService to call DescribeEnvs with filter parameters
|
|
@@ -29421,6 +29469,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
29421
29469
|
};
|
|
29422
29470
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
29423
29471
|
exports.envManager = void 0;
|
|
29472
|
+
exports.probeApiKeyCamCapability = probeApiKeyCamCapability;
|
|
29424
29473
|
exports.listAvailableEnvCandidates = listAvailableEnvCandidates;
|
|
29425
29474
|
exports.resolveEnvCandidateByEnvId = resolveEnvCandidateByEnvId;
|
|
29426
29475
|
exports.getEnvId = getEnvId;
|
|
@@ -29465,6 +29514,53 @@ function createManagerFromLoginState(loginState, region) {
|
|
|
29465
29514
|
region: region ?? (0, site_map_js_1.resolveSiteAndRegion)().region,
|
|
29466
29515
|
});
|
|
29467
29516
|
}
|
|
29517
|
+
// 仅缓存确定性结果(capable/limited),unknown 不缓存以便下次重试
|
|
29518
|
+
const apiKeyCamProbeCache = new Map();
|
|
29519
|
+
const CAM_PROBE_TIMEOUT_MS = 8000;
|
|
29520
|
+
/**
|
|
29521
|
+
* 轻量探测 API Key 登录态能否调用管理面(CAM)API。
|
|
29522
|
+
* 背景:部分 API Key(如"AI 开发套件"形态的 JWT key)只能完成 tcb-api 网关的登录态换取,
|
|
29523
|
+
* 换出的 STS 凭据不带 CAM 策略,queryEnv/queryAppAuth 等管理类工具会全部失败。
|
|
29524
|
+
* 实测凭据:2026-09-01 国际站认证排查(specs/intl-auth-investigation)。
|
|
29525
|
+
*/
|
|
29526
|
+
async function probeApiKeyCamCapability(loginState) {
|
|
29527
|
+
if (!loginState.secretId || !loginState.secretKey || !loginState.envId) {
|
|
29528
|
+
return "unknown";
|
|
29529
|
+
}
|
|
29530
|
+
const cacheKey = `${loginState.secretId}:${loginState.envId}`;
|
|
29531
|
+
const cached = apiKeyCamProbeCache.get(cacheKey);
|
|
29532
|
+
if (cached !== undefined) {
|
|
29533
|
+
return cached ? "capable" : "limited";
|
|
29534
|
+
}
|
|
29535
|
+
try {
|
|
29536
|
+
const manager = createManagerFromLoginState(loginState);
|
|
29537
|
+
// 查询环境详情(DescribeEnvInfo):单环境、入参仅 EnvId,比 DescribeEnvs 更贴合
|
|
29538
|
+
// "登录后查环境" 的首个真实调用;Action 名已对照 CAM 资源级策略文档确认
|
|
29539
|
+
const probeCall = manager.commonService("tcb").call({
|
|
29540
|
+
Action: "DescribeEnvInfo",
|
|
29541
|
+
Param: { EnvId: loginState.envId },
|
|
29542
|
+
});
|
|
29543
|
+
const timeout = new Promise((_, reject) => {
|
|
29544
|
+
const timer = setTimeout(() => reject(new Error("probe timeout")), CAM_PROBE_TIMEOUT_MS);
|
|
29545
|
+
// 不阻塞进程退出
|
|
29546
|
+
timer.unref?.();
|
|
29547
|
+
});
|
|
29548
|
+
await Promise.race([probeCall, timeout]);
|
|
29549
|
+
apiKeyCamProbeCache.set(cacheKey, true);
|
|
29550
|
+
return "capable";
|
|
29551
|
+
}
|
|
29552
|
+
catch (e) {
|
|
29553
|
+
const code = e?.code ?? (e instanceof Error ? e.message : String(e));
|
|
29554
|
+
// 仅把 CAM 明确拒绝判定为 limited;超时/网络等 inconclusive 失败归为 unknown
|
|
29555
|
+
if (code.includes("UnauthorizedOperation") || code.includes("invalid token")) {
|
|
29556
|
+
(0, logger_js_1.debug)("probeApiKeyCamCapability: CAM rejected", { code });
|
|
29557
|
+
apiKeyCamProbeCache.set(cacheKey, false);
|
|
29558
|
+
return "limited";
|
|
29559
|
+
}
|
|
29560
|
+
(0, logger_js_1.debug)("probeApiKeyCamCapability: inconclusive failure", { code });
|
|
29561
|
+
return "unknown";
|
|
29562
|
+
}
|
|
29563
|
+
}
|
|
29468
29564
|
async function listAvailableEnvCandidates(options) {
|
|
29469
29565
|
const { cloudBaseOptions, loginState: providedLoginState, region: regionOverride, ignorePinnedEnvId, } = options ?? {};
|
|
29470
29566
|
if (!ignorePinnedEnvId) {
|
|
@@ -95078,10 +95174,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
95078
95174
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
95079
95175
|
};
|
|
95080
95176
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
95081
|
-
exports.CUSTOM_IMAGE_RUNTIME = exports.LAYER_SOFT_WARN = 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;
|
|
95177
|
+
exports.CUSTOM_IMAGE_RUNTIME = exports.MASKED_ENV_VALUE = exports.LAYER_SOFT_WARN = 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;
|
|
95082
95178
|
exports.formatRuntimeList = formatRuntimeList;
|
|
95083
95179
|
exports.layerNameIncludesEnvId = layerNameIncludesEnvId;
|
|
95084
95180
|
exports.buildCreateLayerNameWarning = buildCreateLayerNameWarning;
|
|
95181
|
+
exports.maskFunctionDetailEnvValues = maskFunctionDetailEnvValues;
|
|
95085
95182
|
exports.validateTimerCron = validateTimerCron;
|
|
95086
95183
|
exports.pickManageFunctionName = pickManageFunctionName;
|
|
95087
95184
|
exports.shouldInstallDependencyForFunction = shouldInstallDependencyForFunction;
|
|
@@ -95206,8 +95303,33 @@ function buildCreateLayerNameWarning(layerName, envId) {
|
|
|
95206
95303
|
}
|
|
95207
95304
|
return exports.LAYER_SOFT_WARN.createNameFormat(envId);
|
|
95208
95305
|
}
|
|
95209
|
-
|
|
95210
|
-
|
|
95306
|
+
/** 环境变量脱敏后的占位值(不保留任何明文片段)。 */
|
|
95307
|
+
exports.MASKED_ENV_VALUE = "***";
|
|
95308
|
+
/**
|
|
95309
|
+
* 对 getFunctionDetail 返回的 Environment.Variables 做脱敏:
|
|
95310
|
+
* 保留 Key 与原始值长度(ValueLength),Value 置为占位符。
|
|
95311
|
+
* 用于默认工具返回与日志落盘,避免明文进入模型上下文 / 持久化日志。
|
|
95312
|
+
*/
|
|
95313
|
+
function maskFunctionDetailEnvValues(detail) {
|
|
95314
|
+
const variables = detail?.Environment?.Variables;
|
|
95315
|
+
if (!Array.isArray(variables) || variables.length === 0) {
|
|
95316
|
+
return detail;
|
|
95317
|
+
}
|
|
95318
|
+
return {
|
|
95319
|
+
...detail,
|
|
95320
|
+
Environment: {
|
|
95321
|
+
...detail.Environment,
|
|
95322
|
+
Variables: variables.map((item) => ({
|
|
95323
|
+
...item,
|
|
95324
|
+
Value: exports.MASKED_ENV_VALUE,
|
|
95325
|
+
...(typeof item.Value === "string"
|
|
95326
|
+
? { ValueLength: item.Value.length }
|
|
95327
|
+
: {}),
|
|
95328
|
+
})),
|
|
95329
|
+
},
|
|
95330
|
+
};
|
|
95331
|
+
}
|
|
95332
|
+
const VPC_SCHEMA = zod_1.z.object({ vpcId: zod_1.z
|
|
95211
95333
|
.string()
|
|
95212
95334
|
.describe("VPC ID from the real database/network console (e.g. vpc-xxxxxxxx). Required for non-native TCP DB access. Do NOT invent or use placeholders."),
|
|
95213
95335
|
subnetId: zod_1.z
|
|
@@ -95577,15 +95699,19 @@ function registerFunctionTools(server) {
|
|
|
95577
95699
|
}
|
|
95578
95700
|
const cloudbase = await getManager();
|
|
95579
95701
|
const result = await cloudbase.functions.getFunctionDetail(input.functionName, input.codeSecret);
|
|
95580
|
-
|
|
95702
|
+
// 日志侧一律脱敏(持久化,不提供明文口子);工具返回侧按 revealEnvValues 决定
|
|
95703
|
+
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, maskFunctionDetailEnvValues(result));
|
|
95704
|
+
const functionDetail = input.revealEnvValues === true
|
|
95705
|
+
? result
|
|
95706
|
+
: maskFunctionDetailEnvValues(result);
|
|
95581
95707
|
return buildEnvelope({
|
|
95582
95708
|
action: input.action,
|
|
95583
95709
|
functionName: input.functionName,
|
|
95584
|
-
functionDetail
|
|
95710
|
+
functionDetail,
|
|
95585
95711
|
layers: normalizeFunctionLayers(result.Layers),
|
|
95586
95712
|
triggers: result.Triggers || [],
|
|
95587
95713
|
requestId: result.RequestId,
|
|
95588
|
-
raw:
|
|
95714
|
+
raw: functionDetail,
|
|
95589
95715
|
}, `已获取函数 ${input.functionName} 的详情`, [
|
|
95590
95716
|
{
|
|
95591
95717
|
tool: "queryFunctions",
|
|
@@ -95803,13 +95929,16 @@ function registerFunctionTools(server) {
|
|
|
95803
95929
|
}
|
|
95804
95930
|
const cloudbase = await getManager();
|
|
95805
95931
|
const result = await cloudbase.functions.getFunctionDetail(input.functionName, input.codeSecret);
|
|
95806
|
-
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
|
|
95932
|
+
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, maskFunctionDetailEnvValues(result));
|
|
95933
|
+
const detail = input.revealEnvValues === true
|
|
95934
|
+
? result
|
|
95935
|
+
: maskFunctionDetailEnvValues(result);
|
|
95807
95936
|
return buildEnvelope({
|
|
95808
95937
|
action: input.action,
|
|
95809
95938
|
functionName: input.functionName,
|
|
95810
|
-
triggers:
|
|
95811
|
-
requestId:
|
|
95812
|
-
raw:
|
|
95939
|
+
triggers: detail.Triggers || [],
|
|
95940
|
+
requestId: detail.RequestId,
|
|
95941
|
+
raw: detail,
|
|
95813
95942
|
}, `已获取函数 ${input.functionName} 的触发器列表`, [
|
|
95814
95943
|
{
|
|
95815
95944
|
tool: "manageFunctions",
|
|
@@ -96563,6 +96692,10 @@ function registerFunctionTools(server) {
|
|
|
96563
96692
|
limit: zod_1.z.number().optional().describe("分页数量(limit)。列表类 action 可选,默认值由后端决定"),
|
|
96564
96693
|
offset: zod_1.z.number().optional().describe("分页偏移(offset)。列表类 action 可选,默认 0"),
|
|
96565
96694
|
codeSecret: zod_1.z.string().optional().describe("代码保护密钥,用于解密函数代码"),
|
|
96695
|
+
revealEnvValues: zod_1.z
|
|
96696
|
+
.boolean()
|
|
96697
|
+
.optional()
|
|
96698
|
+
.describe("getFunctionDetail / listFunctionTriggers 时是否返回环境变量明文值。默认 false:Value 脱敏为 ***,仅保留 Key 与 ValueLength,足以确认配置了哪些变量及变更是否生效;true 时返回明文,敏感变量会进入模型上下文,谨慎使用。如需查看明文,建议优先使用控制台或 CLI"),
|
|
96566
96699
|
startTime: zod_1.z
|
|
96567
96700
|
.string()
|
|
96568
96701
|
.optional()
|
|
@@ -121607,7 +121740,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
121607
121740
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
121608
121741
|
};
|
|
121609
121742
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
121610
|
-
exports.CLOUDRUN_ENV_TYPE = exports.CLOUDRUN_DEPLOY_REGISTRATION_INTERVAL_MS = exports.CLOUDRUN_DEPLOY_REGISTRATION_MAX_WAIT_MS = exports.CLOUDRUN_PACKAGE_TYPES = exports.CLOUDRUN_ACCESS_TYPES = exports.CLOUDRUN_SERVICE_TYPES = void 0;
|
|
121743
|
+
exports.CLOUDRUN_ENV_TYPE = exports.CLOUDRUN_DEPLOY_REGISTRATION_INTERVAL_MS = exports.CLOUDRUN_DEPLOY_REGISTRATION_MAX_WAIT_MS = exports.MASKED_CLOUDRUN_ENV_VALUE = exports.CLOUDRUN_PACKAGE_TYPES = exports.CLOUDRUN_ACCESS_TYPES = exports.CLOUDRUN_SERVICE_TYPES = void 0;
|
|
121744
|
+
exports.maskCloudRunDetailEnvParams = maskCloudRunDetailEnvParams;
|
|
121611
121745
|
exports.buildManageCloudRunErrorMessage = buildManageCloudRunErrorMessage;
|
|
121612
121746
|
exports.isValidCloudRunBuildId = isValidCloudRunBuildId;
|
|
121613
121747
|
exports.isValidCloudRunRunId = isValidCloudRunRunId;
|
|
@@ -121641,6 +121775,40 @@ exports.CLOUDRUN_SERVICE_TYPES = ['function', 'container'];
|
|
|
121641
121775
|
exports.CLOUDRUN_ACCESS_TYPES = ['OA', 'PUBLIC', 'MINIAPP', 'VPC'];
|
|
121642
121776
|
// CloudRun env package types (CreateCloudRunEnv.PackageType)
|
|
121643
121777
|
exports.CLOUDRUN_PACKAGE_TYPES = ['Trial', 'Standard', 'Professional', 'Enterprise'];
|
|
121778
|
+
/** 环境变量脱敏后的占位值(不保留任何明文片段)。 */
|
|
121779
|
+
exports.MASKED_CLOUDRUN_ENV_VALUE = "***";
|
|
121780
|
+
/**
|
|
121781
|
+
* 对云托管 detail 返回的 ServerConfig.EnvParams(JSON 字符串)做脱敏:
|
|
121782
|
+
* 解析后把所有 value 置为占位符、保留 key,再序列化回 JSON 字符串。
|
|
121783
|
+
* 解析失败(非 JSON)时整串替换为占位符,避免任何明文片段外泄。
|
|
121784
|
+
* 用于默认工具返回,避免明文进入模型上下文。
|
|
121785
|
+
*/
|
|
121786
|
+
function maskCloudRunDetailEnvParams(detail) {
|
|
121787
|
+
const envParams = detail?.ServerConfig?.EnvParams;
|
|
121788
|
+
if (typeof envParams !== "string" || envParams === "") {
|
|
121789
|
+
return detail;
|
|
121790
|
+
}
|
|
121791
|
+
let masked;
|
|
121792
|
+
try {
|
|
121793
|
+
const parsed = JSON.parse(envParams);
|
|
121794
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
121795
|
+
masked = JSON.stringify(Object.fromEntries(Object.entries(parsed).map(([key]) => [key, exports.MASKED_CLOUDRUN_ENV_VALUE])));
|
|
121796
|
+
}
|
|
121797
|
+
else {
|
|
121798
|
+
masked = exports.MASKED_CLOUDRUN_ENV_VALUE;
|
|
121799
|
+
}
|
|
121800
|
+
}
|
|
121801
|
+
catch {
|
|
121802
|
+
masked = exports.MASKED_CLOUDRUN_ENV_VALUE;
|
|
121803
|
+
}
|
|
121804
|
+
return {
|
|
121805
|
+
...detail,
|
|
121806
|
+
ServerConfig: {
|
|
121807
|
+
...detail.ServerConfig,
|
|
121808
|
+
EnvParams: masked,
|
|
121809
|
+
},
|
|
121810
|
+
};
|
|
121811
|
+
}
|
|
121644
121812
|
// Input schema for queryCloudRun tool
|
|
121645
121813
|
const queryCloudRunInputSchema = {
|
|
121646
121814
|
action: zod_1.z.enum(['list', 'detail', 'templates', 'getDeployLog', 'getProcessLog', 'getDeployRecords', 'envStatus']).describe('查询操作类型:list=获取云托管服务列表(支持分页和筛选),detail=查询指定服务的详细信息(包含服务配置和最新部署状态),templates=获取可用的项目模板列表(用于初始化新项目),getDeployLog=获取构建日志(仅云端源码构建有意义,走 CODING/DescribeCloudRunBuildLog;已有镜像部署无构建过程;未登录 CODING 的账号会报错),getProcessLog=获取运行日志(部署阶段步骤+容器启动/运行日志,走 tcbr/DescribeCloudRunProcessLog;镜像部署与源码构建均可用,不依赖 CODING;RunId 来自 detail/getDeployRecords 的 latestDeploy.RunId),getDeployRecords=获取指定服务的部署记录列表(按部署时间倒序,含 BuildId/RunId/FlowRatio/Status 等字段,用于查看历史发布与回滚上下文),envStatus=查询当前环境云托管是否已开通及开通状态(Status=creating开通中/normal已开通),用于initEnv之后轮询进度或deploy之前确认环境是否就绪'),
|
|
@@ -121654,6 +121822,7 @@ const queryCloudRunInputSchema = {
|
|
|
121654
121822
|
detailServerName: zod_1.z.string().optional().describe('要查询详细信息、部署记录、构建日志或运行日志的服务名称。当action为detail、getDeployLog、getProcessLog或getDeployRecords时建议提供,必须是已存在的服务名称。可通过list操作获取可用的服务名称列表'),
|
|
121655
121823
|
buildId: zod_1.z.number().optional().describe('构建ID,仅在action=getDeployLog时使用(构建日志,仅云端源码构建)。不传时默认返回最近一次部署的构建日志'),
|
|
121656
121824
|
runId: zod_1.z.string().optional().describe('运行ID(RunId),仅在action=getProcessLog时使用。不传时默认取该服务最近一次部署记录的 RunId(与 detail/getDeployRecords 的 latestDeploy.RunId 同源)。镜像部署与源码构建均可查询运行日志'),
|
|
121825
|
+
revealEnvParams: zod_1.z.boolean().optional().default(false).describe('是否返回服务环境变量(ServerConfig.EnvParams)明文值(仅 action=detail 时生效)。默认 false,值脱敏为 "***"(保留 key,足够排查配置了哪些变量、变更是否生效);true 时返回明文,敏感变量(如带密码的 DATABASE_URL)可能暴露给模型上下文,谨慎使用'),
|
|
121657
121826
|
};
|
|
121658
121827
|
// Input schema for manageCloudRun tool
|
|
121659
121828
|
const ManageCloudRunInputSchema = {
|
|
@@ -122519,7 +122688,8 @@ function registerCloudRunTools(server) {
|
|
|
122519
122688
|
text: JSON.stringify({
|
|
122520
122689
|
success: true,
|
|
122521
122690
|
data: {
|
|
122522
|
-
|
|
122691
|
+
// 默认脱敏 ServerConfig.EnvParams 的值(保留 key);revealEnvParams=true 时返回明文
|
|
122692
|
+
service: input.revealEnvParams === true ? result : maskCloudRunDetailEnvParams(result),
|
|
122523
122693
|
latestDeploy,
|
|
122524
122694
|
// 若最新部署记录带镜像信息(镜像部署),透出便于展示
|
|
122525
122695
|
...(extractCloudRunImageInfo(result, latestDeploy)
|
|
@@ -129798,10 +129968,33 @@ function buildFailureResult(action, error) {
|
|
|
129798
129968
|
message: enrichRateLimitMessage(error instanceof Error ? error.message : String(error)),
|
|
129799
129969
|
});
|
|
129800
129970
|
}
|
|
129971
|
+
function extractFileList(files) {
|
|
129972
|
+
// hosting.listFiles 直接返回文件数组
|
|
129973
|
+
if (Array.isArray(files))
|
|
129974
|
+
return files;
|
|
129975
|
+
// hosting.findFiles 返回 COS 风格对象,文件列表在 Contents 里
|
|
129976
|
+
if (typeof files === 'object' && files !== null) {
|
|
129977
|
+
const record = files;
|
|
129978
|
+
if (Array.isArray(record.Contents))
|
|
129979
|
+
return record.Contents;
|
|
129980
|
+
if (Array.isArray(record.contents))
|
|
129981
|
+
return record.contents;
|
|
129982
|
+
}
|
|
129983
|
+
return [];
|
|
129984
|
+
}
|
|
129985
|
+
function extractFilePagination(result) {
|
|
129986
|
+
if (typeof result !== 'object' || result === null)
|
|
129987
|
+
return {};
|
|
129988
|
+
const record = result;
|
|
129989
|
+
const isTruncated = record.IsTruncated ?? record.isTruncated;
|
|
129990
|
+
const nextMarker = record.NextMarker ?? record.nextMarker;
|
|
129991
|
+
return {
|
|
129992
|
+
isTruncated: typeof isTruncated === 'boolean' ? isTruncated : undefined,
|
|
129993
|
+
nextMarker: typeof nextMarker === 'string' && nextMarker.length > 0 ? nextMarker : undefined,
|
|
129994
|
+
};
|
|
129995
|
+
}
|
|
129801
129996
|
function normalizeFileFields(files) {
|
|
129802
|
-
|
|
129803
|
-
return [];
|
|
129804
|
-
return files.map(file => {
|
|
129997
|
+
return extractFileList(files).map((file) => {
|
|
129805
129998
|
if (typeof file !== 'object' || file === null)
|
|
129806
129999
|
return file;
|
|
129807
130000
|
const record = file;
|
|
@@ -129890,6 +130083,8 @@ function registerHostingTools(server) {
|
|
|
129890
130083
|
});
|
|
129891
130084
|
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
|
|
129892
130085
|
const normalizedFiles = normalizeFileFields(result);
|
|
130086
|
+
// findFiles 的 marker 是 COS 游标字符串,与 listFiles 的数字 offset 语义不同,此处只透传不做解析
|
|
130087
|
+
const { isTruncated, nextMarker } = extractFilePagination(result);
|
|
129893
130088
|
return (0, tool_result_js_1.buildJsonToolResult)({
|
|
129894
130089
|
success: true,
|
|
129895
130090
|
data: {
|
|
@@ -129898,9 +130093,11 @@ function registerHostingTools(server) {
|
|
|
129898
130093
|
marker: input.marker,
|
|
129899
130094
|
maxKeys: input.maxKeys,
|
|
129900
130095
|
files: normalizedFiles,
|
|
130096
|
+
nextMarker,
|
|
130097
|
+
isTruncated,
|
|
129901
130098
|
result,
|
|
129902
130099
|
},
|
|
129903
|
-
message: `已按前缀 \`${input.prefix}\` 查询静态托管文件,共 ${
|
|
130100
|
+
message: `已按前缀 \`${input.prefix}\` 查询静态托管文件,共 ${normalizedFiles.length} 个。${nextMarker ? ' 还有更多文件,可使用 nextMarker 继续查询。' : ''}`,
|
|
129904
130101
|
});
|
|
129905
130102
|
}
|
|
129906
130103
|
case 'listFiles': {
|
|
@@ -149548,7 +149745,7 @@ class TelemetryReporter {
|
|
|
149548
149745
|
const arch = os_1.default.arch(); // 系统架构
|
|
149549
149746
|
// Build-time injected version; guard for vitest / non-webpack runtimes.
|
|
149550
149747
|
const mcpVersion = process.env.npm_package_version ||
|
|
149551
|
-
( true ? "2.32.
|
|
149748
|
+
( true ? "2.32.5" : 0);
|
|
149552
149749
|
return {
|
|
149553
149750
|
userAgent: `${osType} ${osRelease} ${arch} ${nodeVersion} CloudBase-MCP/${mcpVersion}`,
|
|
149554
149751
|
deviceId: this.deviceId,
|
|
@@ -178606,7 +178803,7 @@ async function handleReadOnlySql(args, context, deps) {
|
|
|
178606
178803
|
message: `PostgreSQL read-only SQL execution failed: ${reason}`,
|
|
178607
178804
|
data: {
|
|
178608
178805
|
role: context.role,
|
|
178609
|
-
sqlPreview:
|
|
178806
|
+
sqlPreview: args.sql.trim().slice(0, 500),
|
|
178610
178807
|
},
|
|
178611
178808
|
});
|
|
178612
178809
|
}
|
|
@@ -217980,8 +218177,7 @@ const cloudbase_manager_js_1 = __webpack_require__(3431);
|
|
|
217980
218177
|
const json_content_js_1 = __webpack_require__(4365);
|
|
217981
218178
|
const logger_js_1 = __webpack_require__(13039);
|
|
217982
218179
|
// 1. 枚举定义
|
|
217983
|
-
const
|
|
217984
|
-
const SearchKnowledgeModeEnum = zod_1.z.enum(["vector", "skill", "openapi", "docs"]);
|
|
218180
|
+
const SearchKnowledgeModeEnum = zod_1.z.enum(["skill", "openapi", "docs"]);
|
|
217985
218181
|
const CloudBaseDocsActionEnum = zod_1.z.enum([
|
|
217986
218182
|
"listModules",
|
|
217987
218183
|
"listModuleDocs",
|
|
@@ -217989,12 +218185,6 @@ const CloudBaseDocsActionEnum = zod_1.z.enum([
|
|
|
217989
218185
|
"readDoc",
|
|
217990
218186
|
"searchDocs",
|
|
217991
218187
|
]);
|
|
217992
|
-
// 2. 枚举到后端 id 的映射
|
|
217993
|
-
const KnowledgeBaseIdMap = {
|
|
217994
|
-
cloudbase: "ykfzskv4_ad28",
|
|
217995
|
-
scf: "scfsczskzyws_4bdc",
|
|
217996
|
-
miniprogram: "xcxzskws_25d8",
|
|
217997
|
-
};
|
|
217998
218188
|
// ============ 缓存配置 ============
|
|
217999
218189
|
const CACHE_BASE_DIR = path.join(os.homedir(), ".cloudbase-mcp");
|
|
218000
218190
|
const CACHE_META_FILE = path.join(CACHE_BASE_DIR, "cache-meta.json");
|
|
@@ -218118,32 +218308,6 @@ async function updateCache() {
|
|
|
218118
218308
|
await fs.mkdir(CACHE_BASE_DIR, { recursive: true });
|
|
218119
218309
|
await fs.writeFile(CACHE_META_FILE, JSON.stringify({ timestamp: Date.now() }, null, 2), "utf8");
|
|
218120
218310
|
}
|
|
218121
|
-
// 安全 JSON.parse
|
|
218122
|
-
function safeParse(str) {
|
|
218123
|
-
try {
|
|
218124
|
-
return JSON.parse(str);
|
|
218125
|
-
}
|
|
218126
|
-
catch (e) {
|
|
218127
|
-
return {};
|
|
218128
|
-
}
|
|
218129
|
-
}
|
|
218130
|
-
// 安全 JSON.stringify,处理循环引用
|
|
218131
|
-
function safeStringify(obj) {
|
|
218132
|
-
const seen = new WeakSet();
|
|
218133
|
-
try {
|
|
218134
|
-
return JSON.stringify(obj, function (key, value) {
|
|
218135
|
-
if (typeof value === "object" && value !== null) {
|
|
218136
|
-
if (seen.has(value))
|
|
218137
|
-
return;
|
|
218138
|
-
seen.add(value);
|
|
218139
|
-
}
|
|
218140
|
-
return value;
|
|
218141
|
-
});
|
|
218142
|
-
}
|
|
218143
|
-
catch (e) {
|
|
218144
|
-
return "";
|
|
218145
|
-
}
|
|
218146
|
-
}
|
|
218147
218311
|
function buildDocsEnvelope(action, data, message) {
|
|
218148
218312
|
return {
|
|
218149
218313
|
success: true,
|
|
@@ -218405,9 +218569,13 @@ async function registerRagTools(server) {
|
|
|
218405
218569
|
?.docs;
|
|
218406
218570
|
server.registerTool?.("searchKnowledgeBase", {
|
|
218407
218571
|
title: "云开发知识库检索",
|
|
218408
|
-
description:
|
|
218572
|
+
description: `云开发知识库检索工具,支持 CloudBase 官方文档 (docs)、固定技能文档 (skill) 和 OpenAPI 文档 (openapi) 查询。
|
|
218409
218573
|
|
|
218410
|
-
|
|
218574
|
+
按场景选择 mode:
|
|
218575
|
+
- 不确定答案在哪、需要对官方文档做全文检索时:mode=docs + action=searchDocs(传 query 关键词)
|
|
218576
|
+
- 已知文档标题、层级路径或 URL 时:mode=docs + action=findByName(传 input)或 action=readDoc(传 docPath)
|
|
218577
|
+
- 需要某个场景的落地指南 / 最佳实践时:mode=skill + skillName
|
|
218578
|
+
- 需要 HTTP API 的接口定义时:mode=openapi + apiName
|
|
218411
218579
|
|
|
218412
218580
|
⚠️ 重要:当 CloudBase skills 处于禁用状态或当前 IDE 不支持 skill 文件读取时,必须使用 searchKnowledgeBase(mode=skill, skillName=...) 来获取 CloudBase 技能文档内容,而不是尝试直接读取 skill 文件。直接读取可能返回 400 错误。示例:
|
|
218413
218581
|
- 需要最小 Web+数据库 Demo 路径时:searchKnowledgeBase(mode=skill, skillName=minimal-web-baas-demo)
|
|
@@ -218445,37 +218613,13 @@ async function registerRagTools(server) {
|
|
|
218445
218613
|
.string()
|
|
218446
218614
|
.optional()
|
|
218447
218615
|
.describe("mode=docs 且 action=searchDocs 时指定。全文检索关键词。"),
|
|
218448
|
-
threshold: zod_1.z
|
|
218449
|
-
.number()
|
|
218450
|
-
.default(0.5)
|
|
218451
|
-
.optional()
|
|
218452
|
-
.describe("mode=vector 时指定。相似性检索阈值"),
|
|
218453
|
-
id: KnowledgeBaseEnum.default("cloudbase").optional().describe("mode=vector 时指定。知识库范围,默认 cloudbase。cloudbase=云开发全量知识,scf=云开发的云函数知识, miniprogram=小程序知识(不包含云开发与云函数知识)"),
|
|
218454
|
-
content: zod_1.z.string().describe("mode=vector 时指定。检索内容").optional(),
|
|
218455
|
-
options: zod_1.z
|
|
218456
|
-
.object({
|
|
218457
|
-
chunkExpand: zod_1.z
|
|
218458
|
-
.array(zod_1.z.number())
|
|
218459
|
-
.min(2)
|
|
218460
|
-
.max(2)
|
|
218461
|
-
.default([3, 3])
|
|
218462
|
-
.describe("指定返回的文档内容的展开长度,例如 [3,3]代表前后展开长度"),
|
|
218463
|
-
})
|
|
218464
|
-
.optional()
|
|
218465
|
-
.describe("mode=vector 时指定。其他选项"),
|
|
218466
|
-
limit: zod_1.z
|
|
218467
|
-
.number()
|
|
218468
|
-
.default(5)
|
|
218469
|
-
.optional()
|
|
218470
|
-
.describe("mode=vector 时指定。指定返回最相似的 Top K 的 K 的值"),
|
|
218471
218616
|
},
|
|
218472
218617
|
annotations: {
|
|
218473
218618
|
readOnlyHint: true,
|
|
218474
218619
|
openWorldHint: true,
|
|
218475
218620
|
category: "rag",
|
|
218476
218621
|
},
|
|
218477
|
-
}, async ({
|
|
218478
|
-
const chunkExpand = options?.chunkExpand ?? [3, 3];
|
|
218622
|
+
}, async ({ mode, skillName, apiName, action, moduleName, input, docPath, query, }) => {
|
|
218479
218623
|
if (mode === "docs") {
|
|
218480
218624
|
try {
|
|
218481
218625
|
const resolvedAction = action;
|
|
@@ -218555,76 +218699,8 @@ async function registerRagTools(server) {
|
|
|
218555
218699
|
],
|
|
218556
218700
|
};
|
|
218557
218701
|
}
|
|
218558
|
-
//
|
|
218559
|
-
|
|
218560
|
-
if (mode === "vector") {
|
|
218561
|
-
if (!content || !content.trim()) {
|
|
218562
|
-
throw new Error("检索内容不能为空: please provide non-empty `content` when mode=vector.");
|
|
218563
|
-
}
|
|
218564
|
-
}
|
|
218565
|
-
// 枚举到后端 id 映射
|
|
218566
|
-
const backendId = KnowledgeBaseIdMap[vectorKnowledgeBaseId] ||
|
|
218567
|
-
vectorKnowledgeBaseId;
|
|
218568
|
-
const signInRes = await fetch("https://tcb-advanced-a656fc.api.tcloudbasegateway.com/auth/v1/signin/anonymously", {
|
|
218569
|
-
method: "POST",
|
|
218570
|
-
headers: {
|
|
218571
|
-
"Content-Type": "application/json",
|
|
218572
|
-
Accept: "application/json",
|
|
218573
|
-
"x-device-id": "cloudbase-ai-toolkit",
|
|
218574
|
-
},
|
|
218575
|
-
body: safeStringify({
|
|
218576
|
-
collectionView: backendId,
|
|
218577
|
-
options: {
|
|
218578
|
-
chunkExpand,
|
|
218579
|
-
},
|
|
218580
|
-
search: {
|
|
218581
|
-
content: content,
|
|
218582
|
-
limit,
|
|
218583
|
-
},
|
|
218584
|
-
}),
|
|
218585
|
-
});
|
|
218586
|
-
const token = (await signInRes.json()).access_token;
|
|
218587
|
-
const res = await fetch(`https://tcb-advanced-a656fc.api.tcloudbasegateway.com/v1/knowledge/search`, {
|
|
218588
|
-
method: "POST",
|
|
218589
|
-
headers: {
|
|
218590
|
-
"Content-Type": "application/json",
|
|
218591
|
-
Authorization: `Bearer ${token}`,
|
|
218592
|
-
},
|
|
218593
|
-
body: safeStringify({
|
|
218594
|
-
collectionView: backendId,
|
|
218595
|
-
options: {
|
|
218596
|
-
chunkExpand,
|
|
218597
|
-
},
|
|
218598
|
-
search: {
|
|
218599
|
-
content: content,
|
|
218600
|
-
limit,
|
|
218601
|
-
},
|
|
218602
|
-
}),
|
|
218603
|
-
});
|
|
218604
|
-
const result = await res.json();
|
|
218605
|
-
if (result.code) {
|
|
218606
|
-
throw new Error(result.message);
|
|
218607
|
-
}
|
|
218608
|
-
return {
|
|
218609
|
-
content: [
|
|
218610
|
-
{
|
|
218611
|
-
type: "text",
|
|
218612
|
-
text: safeStringify(result.data.documents
|
|
218613
|
-
.filter((item) => item.score >= threshold)
|
|
218614
|
-
.map((item) => {
|
|
218615
|
-
return {
|
|
218616
|
-
score: item.score,
|
|
218617
|
-
fileTile: item.documentSet.fileTitle,
|
|
218618
|
-
url: safeParse(item.documentSet.fileMetaData).url,
|
|
218619
|
-
paragraphTitle: item.data.paragraphTitle,
|
|
218620
|
-
text: `${item.data.pre?.join("\n") || ""}
|
|
218621
|
-
${item.data.text}
|
|
218622
|
-
${item.data.next?.join("\n") || ""}`,
|
|
218623
|
-
};
|
|
218624
|
-
})),
|
|
218625
|
-
},
|
|
218626
|
-
],
|
|
218627
|
-
};
|
|
218702
|
+
// mode 是枚举,docs / skill / openapi 三个分支已在上面全部返回,这里不可达
|
|
218703
|
+
throw new Error(`unsupported mode: ${String(mode)}`);
|
|
218628
218704
|
});
|
|
218629
218705
|
}
|
|
218630
218706
|
function extractDescriptionFromFrontMatter(content) {
|
|
@@ -227825,6 +227901,7 @@ exports.TCB_QUERY_REGIONS = exports.SITE_IDS = exports.SITE_REGION_MAP = void 0;
|
|
|
227825
227901
|
exports.isSiteId = isSiteId;
|
|
227826
227902
|
exports.normalizeSite = normalizeSite;
|
|
227827
227903
|
exports.getSite = getSite;
|
|
227904
|
+
exports.resolveApiKeyExchangeRegion = resolveApiKeyExchangeRegion;
|
|
227828
227905
|
exports.resolveSite = resolveSite;
|
|
227829
227906
|
exports.resolveSiteAndRegion = resolveSiteAndRegion;
|
|
227830
227907
|
const project_config_js_1 = __webpack_require__(68445);
|
|
@@ -227834,6 +227911,7 @@ exports.SITE_REGION_MAP = {
|
|
|
227834
227911
|
label: "国内站",
|
|
227835
227912
|
authHost: "tcb.cloud.tencent.com",
|
|
227836
227913
|
consoleHost: "tcb.cloud.tencent.com",
|
|
227914
|
+
oauthEndpoint: "https://tcb-api.cloud.tencent.com/qcloud-tcb/v1/oauth",
|
|
227837
227915
|
defaultRegion: "ap-shanghai",
|
|
227838
227916
|
regions: ["ap-shanghai", "ap-guangzhou", "ap-singapore"],
|
|
227839
227917
|
capabilities: { noSql: true },
|
|
@@ -227843,6 +227921,9 @@ exports.SITE_REGION_MAP = {
|
|
|
227843
227921
|
label: "国际站",
|
|
227844
227922
|
authHost: "tcb.tencentcloud.com",
|
|
227845
227923
|
consoleHost: "tcb.tencentcloud.com",
|
|
227924
|
+
// 2026-09-01 实测:device/code + token 端点可用,且 device-code 注册表与国内站隔离
|
|
227925
|
+
// (国内站有效期内的 code 在该端点轮询返回 expired_token)
|
|
227926
|
+
oauthEndpoint: "https://tcb-api.tencentcloud.com/qcloud-tcb/v1/oauth",
|
|
227846
227927
|
defaultRegion: "ap-singapore",
|
|
227847
227928
|
regions: ["ap-singapore"],
|
|
227848
227929
|
capabilities: { noSql: false },
|
|
@@ -227897,8 +227978,24 @@ function getSite(region, explicitSite) {
|
|
|
227897
227978
|
return "domestic";
|
|
227898
227979
|
}
|
|
227899
227980
|
/**
|
|
227900
|
-
*
|
|
227981
|
+
* API Key 换取网关(POST /capi/credential 的 host)地域选型。
|
|
227982
|
+
*
|
|
227983
|
+
* 2026-09-01 同一把国内站 key 三地域网关实测:
|
|
227984
|
+
* - ap-shanghai / ap-guangzhou host 均换取成功(国内站集群共享 key 注册表,
|
|
227985
|
+
* URL 中的 region 段在国内站内部等价,互换可用)
|
|
227986
|
+
* - ap-singapore host 拒绝(SIGN_PARAM_INVALID:sg 网关为国际站独立部署,
|
|
227987
|
+
* key 注册表与国内站隔离)
|
|
227988
|
+
*
|
|
227989
|
+
* 因此换取 host 按**站点**选择,而非按环境所属地域:
|
|
227990
|
+
* - 显式 intl 站点(如 TCB_SITE=intl)→ 返回 intl 地域(ap-singapore)
|
|
227991
|
+
* - domestic / 歧义(如仅设 TCB_REGION=ap-singapore)/ 未配置 → 返回 undefined,
|
|
227992
|
+
* toolbox 回落默认 ap-shanghai;国内站多地域环境(ap-guangzhou / ap-singapore)
|
|
227993
|
+
* 经默认域名均可换取,盲目传环境地域反而会把国内站 key 打到 sg 网关导致换取失败
|
|
227901
227994
|
*/
|
|
227995
|
+
function resolveApiKeyExchangeRegion(opts = {}) {
|
|
227996
|
+
const resolved = resolveSiteAndRegion(opts);
|
|
227997
|
+
return resolved.site === "intl" && !resolved.ambiguous ? resolved.region : undefined;
|
|
227998
|
+
}
|
|
227902
227999
|
function resolveSite(region, explicitSite) {
|
|
227903
228000
|
const site = getSite(region, explicitSite);
|
|
227904
228001
|
return site === "ambiguous" ? "intl" : site;
|
|
@@ -233414,7 +233511,7 @@ ${envIdSection}
|
|
|
233414
233511
|
## 环境信息
|
|
233415
233512
|
- 操作系统: ${os_1.default.type()} ${os_1.default.release()}
|
|
233416
233513
|
- Node.js版本: ${process.version}
|
|
233417
|
-
- MCP 版本:${process.env.npm_package_version || ( true ? "2.32.
|
|
233514
|
+
- MCP 版本:${process.env.npm_package_version || ( true ? "2.32.5" : 0)}
|
|
233418
233515
|
- 系统架构: ${os_1.default.arch()}
|
|
233419
233516
|
- 时间: ${new Date().toISOString()}
|
|
233420
233517
|
- 请求ID: ${requestId}
|
|
@@ -233499,7 +233596,7 @@ function createWrappedHandler(name, handler, server) {
|
|
|
233499
233596
|
requestId: (typeof error === 'object' && error && 'requestId' in error) ? error.requestId : '',
|
|
233500
233597
|
ide: server.ide || process.env.INTEGRATION_IDE || ''
|
|
233501
233598
|
});
|
|
233502
|
-
const mcpVersion = true ? "2.32.
|
|
233599
|
+
const mcpVersion = true ? "2.32.5" : 0;
|
|
233503
233600
|
const requestIdSuffix = requestId ? `\n🆔 RequestId: ${requestId}` : '';
|
|
233504
233601
|
const enhancedErrorMessage = `${errorMessage}${requestIdSuffix}\n\n📦 CloudBase MCP v${mcpVersion}\n🔗 遇到问题?请复制以下链接到浏览器打开\n即可自动携带错误详情快速创建 GitHub Issue:\n${issueLink}`;
|
|
233505
233602
|
// 创建新的错误对象,保持原有的错误类型但更新消息
|
|
@@ -252888,7 +252985,7 @@ function registerSetupTools(server) {
|
|
|
252888
252985
|
server.registerTool("downloadTemplate", {
|
|
252889
252986
|
title: "下载项目模板",
|
|
252890
252987
|
description: `自动下载并部署CloudBase项目模板。
|
|
252891
|
-
**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.32.
|
|
252988
|
+
**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.32.5" : 0}),便于后续维护和版本追踪\n- 下载 rules 模板时,如果项目中已存在 README.md 文件,系统会自动保护该文件不被覆盖(除非设置 overwrite=true)`,
|
|
252892
252989
|
inputSchema: {
|
|
252893
252990
|
template: zod_1.z
|
|
252894
252991
|
.enum(["react", "vue", "miniprogram", "uniapp", "rules"])
|
|
@@ -255298,7 +255395,13 @@ async function peekLoginState(options) {
|
|
|
255298
255395
|
try {
|
|
255299
255396
|
// 优先使用 IDE 注入的工作目录,其次 process.cwd()
|
|
255300
255397
|
const projectCwd = process.env.WORKSPACE_FOLDER_PATHS || process.cwd();
|
|
255301
|
-
|
|
255398
|
+
// 换取网关按站点选型:显式 intl → ap-singapore;domestic/歧义 → toolbox 默认
|
|
255399
|
+
// ap-shanghai(国内站多地域环境均经其全局路由,详见 resolveApiKeyExchangeRegion)
|
|
255400
|
+
const exchangeRegion = (0, site_map_js_1.resolveApiKeyExchangeRegion)({
|
|
255401
|
+
site: options?.site,
|
|
255402
|
+
region: options?.region,
|
|
255403
|
+
});
|
|
255404
|
+
const credential = await auth.loginByApiKey(envVarLoginState.apiKey, envVarLoginState.envId, { cwd: projectCwd, ...(exchangeRegion ? { region: exchangeRegion } : {}) });
|
|
255302
255405
|
return credential;
|
|
255303
255406
|
}
|
|
255304
255407
|
catch (e) {
|
|
@@ -255393,6 +255496,18 @@ async function ensureLogin(options) {
|
|
|
255393
255496
|
if (resolvedAuthOptions.oauthEndpoint) {
|
|
255394
255497
|
loginOptions.getOAuthEndpoint = () => resolvedAuthOptions.oauthEndpoint;
|
|
255395
255498
|
}
|
|
255499
|
+
else if (resolvedSite === "intl") {
|
|
255500
|
+
// 国际站 OAuth 后端独立部署(2026-09-01 实测 device/code+token 可用,注册表与国内站隔离);
|
|
255501
|
+
// 不覆写时 toolbox 默认打国内站端点,国际站账号无法完成授权
|
|
255502
|
+
loginOptions.getOAuthEndpoint = () => site_map_js_1.SITE_REGION_MAP.intl.oauthEndpoint;
|
|
255503
|
+
}
|
|
255504
|
+
if (resolvedSite === "intl") {
|
|
255505
|
+
// device 模式的 verification_uri 标准模式下由客户端拼接,指向国内站授权页;
|
|
255506
|
+
// 与 web 模式同款 host 改写,把授权页切到国际站
|
|
255507
|
+
loginOptions.getAuthUrl = (url) => url
|
|
255508
|
+
.replace(`${site_map_js_1.SITE_REGION_MAP.domestic.authHost}/dev`, `${site_map_js_1.SITE_REGION_MAP.intl.authHost}/dev`)
|
|
255509
|
+
.replace(site_map_js_1.SITE_REGION_MAP.domestic.authHost, site_map_js_1.SITE_REGION_MAP.intl.authHost);
|
|
255510
|
+
}
|
|
255396
255511
|
if (resolvedAuthOptions.oauthCustom) {
|
|
255397
255512
|
loginOptions.custom = true;
|
|
255398
255513
|
}
|