@cloudbase/cloudbase-mcp 2.32.3 → 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 +284 -168
- package/dist/index.d.ts +8 -0
- package/dist/index.js +284 -168
- 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) {
|
|
@@ -33460,8 +33556,9 @@ const SUPABASE_LIKE_SDK_HINTS = {
|
|
|
33460
33556
|
emailOtp: "auth.signInWithOtp({ email })",
|
|
33461
33557
|
password: "auth.signInWithPassword({ username|email|phone, password })",
|
|
33462
33558
|
signup: "auth.signUp({ phone|email, ... })",
|
|
33463
|
-
verifyOtp: "verifyOtp({ token })",
|
|
33559
|
+
verifyOtp: "const { data, error } = await auth.signInWithOtp({ email })\nconst { data: loginData, error: loginError } = await data.verifyOtp({ token })",
|
|
33464
33560
|
anonymous: "auth.signInAnonymously()",
|
|
33561
|
+
caution: "verifyOtp is a callback on the signInWithOtp / signUp result: call data.verifyOtp({ token }) with only the token. Do NOT call a standalone auth.verifyOtp({ token }) — it requires an extra messageId and fails with 'messageId is required' when the messageId is missing. Error 'messageId is required' means you used the standalone call instead of the callback.",
|
|
33465
33562
|
};
|
|
33466
33563
|
function buildErrorEnvelope(error) {
|
|
33467
33564
|
return {
|
|
@@ -95077,10 +95174,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
95077
95174
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
95078
95175
|
};
|
|
95079
95176
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
95080
|
-
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;
|
|
95081
95178
|
exports.formatRuntimeList = formatRuntimeList;
|
|
95082
95179
|
exports.layerNameIncludesEnvId = layerNameIncludesEnvId;
|
|
95083
95180
|
exports.buildCreateLayerNameWarning = buildCreateLayerNameWarning;
|
|
95181
|
+
exports.maskFunctionDetailEnvValues = maskFunctionDetailEnvValues;
|
|
95084
95182
|
exports.validateTimerCron = validateTimerCron;
|
|
95085
95183
|
exports.pickManageFunctionName = pickManageFunctionName;
|
|
95086
95184
|
exports.shouldInstallDependencyForFunction = shouldInstallDependencyForFunction;
|
|
@@ -95205,8 +95303,33 @@ function buildCreateLayerNameWarning(layerName, envId) {
|
|
|
95205
95303
|
}
|
|
95206
95304
|
return exports.LAYER_SOFT_WARN.createNameFormat(envId);
|
|
95207
95305
|
}
|
|
95208
|
-
|
|
95209
|
-
|
|
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
|
|
95210
95333
|
.string()
|
|
95211
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."),
|
|
95212
95335
|
subnetId: zod_1.z
|
|
@@ -95576,15 +95699,19 @@ function registerFunctionTools(server) {
|
|
|
95576
95699
|
}
|
|
95577
95700
|
const cloudbase = await getManager();
|
|
95578
95701
|
const result = await cloudbase.functions.getFunctionDetail(input.functionName, input.codeSecret);
|
|
95579
|
-
|
|
95702
|
+
// 日志侧一律脱敏(持久化,不提供明文口子);工具返回侧按 revealEnvValues 决定
|
|
95703
|
+
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, maskFunctionDetailEnvValues(result));
|
|
95704
|
+
const functionDetail = input.revealEnvValues === true
|
|
95705
|
+
? result
|
|
95706
|
+
: maskFunctionDetailEnvValues(result);
|
|
95580
95707
|
return buildEnvelope({
|
|
95581
95708
|
action: input.action,
|
|
95582
95709
|
functionName: input.functionName,
|
|
95583
|
-
functionDetail
|
|
95710
|
+
functionDetail,
|
|
95584
95711
|
layers: normalizeFunctionLayers(result.Layers),
|
|
95585
95712
|
triggers: result.Triggers || [],
|
|
95586
95713
|
requestId: result.RequestId,
|
|
95587
|
-
raw:
|
|
95714
|
+
raw: functionDetail,
|
|
95588
95715
|
}, `已获取函数 ${input.functionName} 的详情`, [
|
|
95589
95716
|
{
|
|
95590
95717
|
tool: "queryFunctions",
|
|
@@ -95802,13 +95929,16 @@ function registerFunctionTools(server) {
|
|
|
95802
95929
|
}
|
|
95803
95930
|
const cloudbase = await getManager();
|
|
95804
95931
|
const result = await cloudbase.functions.getFunctionDetail(input.functionName, input.codeSecret);
|
|
95805
|
-
(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);
|
|
95806
95936
|
return buildEnvelope({
|
|
95807
95937
|
action: input.action,
|
|
95808
95938
|
functionName: input.functionName,
|
|
95809
|
-
triggers:
|
|
95810
|
-
requestId:
|
|
95811
|
-
raw:
|
|
95939
|
+
triggers: detail.Triggers || [],
|
|
95940
|
+
requestId: detail.RequestId,
|
|
95941
|
+
raw: detail,
|
|
95812
95942
|
}, `已获取函数 ${input.functionName} 的触发器列表`, [
|
|
95813
95943
|
{
|
|
95814
95944
|
tool: "manageFunctions",
|
|
@@ -96562,6 +96692,10 @@ function registerFunctionTools(server) {
|
|
|
96562
96692
|
limit: zod_1.z.number().optional().describe("分页数量(limit)。列表类 action 可选,默认值由后端决定"),
|
|
96563
96693
|
offset: zod_1.z.number().optional().describe("分页偏移(offset)。列表类 action 可选,默认 0"),
|
|
96564
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"),
|
|
96565
96699
|
startTime: zod_1.z
|
|
96566
96700
|
.string()
|
|
96567
96701
|
.optional()
|
|
@@ -121606,7 +121740,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
121606
121740
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
121607
121741
|
};
|
|
121608
121742
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
121609
|
-
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;
|
|
121610
121745
|
exports.buildManageCloudRunErrorMessage = buildManageCloudRunErrorMessage;
|
|
121611
121746
|
exports.isValidCloudRunBuildId = isValidCloudRunBuildId;
|
|
121612
121747
|
exports.isValidCloudRunRunId = isValidCloudRunRunId;
|
|
@@ -121640,6 +121775,40 @@ exports.CLOUDRUN_SERVICE_TYPES = ['function', 'container'];
|
|
|
121640
121775
|
exports.CLOUDRUN_ACCESS_TYPES = ['OA', 'PUBLIC', 'MINIAPP', 'VPC'];
|
|
121641
121776
|
// CloudRun env package types (CreateCloudRunEnv.PackageType)
|
|
121642
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
|
+
}
|
|
121643
121812
|
// Input schema for queryCloudRun tool
|
|
121644
121813
|
const queryCloudRunInputSchema = {
|
|
121645
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之前确认环境是否就绪'),
|
|
@@ -121653,6 +121822,7 @@ const queryCloudRunInputSchema = {
|
|
|
121653
121822
|
detailServerName: zod_1.z.string().optional().describe('要查询详细信息、部署记录、构建日志或运行日志的服务名称。当action为detail、getDeployLog、getProcessLog或getDeployRecords时建议提供,必须是已存在的服务名称。可通过list操作获取可用的服务名称列表'),
|
|
121654
121823
|
buildId: zod_1.z.number().optional().describe('构建ID,仅在action=getDeployLog时使用(构建日志,仅云端源码构建)。不传时默认返回最近一次部署的构建日志'),
|
|
121655
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)可能暴露给模型上下文,谨慎使用'),
|
|
121656
121826
|
};
|
|
121657
121827
|
// Input schema for manageCloudRun tool
|
|
121658
121828
|
const ManageCloudRunInputSchema = {
|
|
@@ -122518,7 +122688,8 @@ function registerCloudRunTools(server) {
|
|
|
122518
122688
|
text: JSON.stringify({
|
|
122519
122689
|
success: true,
|
|
122520
122690
|
data: {
|
|
122521
|
-
|
|
122691
|
+
// 默认脱敏 ServerConfig.EnvParams 的值(保留 key);revealEnvParams=true 时返回明文
|
|
122692
|
+
service: input.revealEnvParams === true ? result : maskCloudRunDetailEnvParams(result),
|
|
122522
122693
|
latestDeploy,
|
|
122523
122694
|
// 若最新部署记录带镜像信息(镜像部署),透出便于展示
|
|
122524
122695
|
...(extractCloudRunImageInfo(result, latestDeploy)
|
|
@@ -129797,10 +129968,33 @@ function buildFailureResult(action, error) {
|
|
|
129797
129968
|
message: enrichRateLimitMessage(error instanceof Error ? error.message : String(error)),
|
|
129798
129969
|
});
|
|
129799
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
|
+
}
|
|
129800
129996
|
function normalizeFileFields(files) {
|
|
129801
|
-
|
|
129802
|
-
return [];
|
|
129803
|
-
return files.map(file => {
|
|
129997
|
+
return extractFileList(files).map((file) => {
|
|
129804
129998
|
if (typeof file !== 'object' || file === null)
|
|
129805
129999
|
return file;
|
|
129806
130000
|
const record = file;
|
|
@@ -129889,6 +130083,8 @@ function registerHostingTools(server) {
|
|
|
129889
130083
|
});
|
|
129890
130084
|
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
|
|
129891
130085
|
const normalizedFiles = normalizeFileFields(result);
|
|
130086
|
+
// findFiles 的 marker 是 COS 游标字符串,与 listFiles 的数字 offset 语义不同,此处只透传不做解析
|
|
130087
|
+
const { isTruncated, nextMarker } = extractFilePagination(result);
|
|
129892
130088
|
return (0, tool_result_js_1.buildJsonToolResult)({
|
|
129893
130089
|
success: true,
|
|
129894
130090
|
data: {
|
|
@@ -129897,9 +130093,11 @@ function registerHostingTools(server) {
|
|
|
129897
130093
|
marker: input.marker,
|
|
129898
130094
|
maxKeys: input.maxKeys,
|
|
129899
130095
|
files: normalizedFiles,
|
|
130096
|
+
nextMarker,
|
|
130097
|
+
isTruncated,
|
|
129900
130098
|
result,
|
|
129901
130099
|
},
|
|
129902
|
-
message: `已按前缀 \`${input.prefix}\` 查询静态托管文件,共 ${
|
|
130100
|
+
message: `已按前缀 \`${input.prefix}\` 查询静态托管文件,共 ${normalizedFiles.length} 个。${nextMarker ? ' 还有更多文件,可使用 nextMarker 继续查询。' : ''}`,
|
|
129903
130101
|
});
|
|
129904
130102
|
}
|
|
129905
130103
|
case 'listFiles': {
|
|
@@ -149547,7 +149745,7 @@ class TelemetryReporter {
|
|
|
149547
149745
|
const arch = os_1.default.arch(); // 系统架构
|
|
149548
149746
|
// Build-time injected version; guard for vitest / non-webpack runtimes.
|
|
149549
149747
|
const mcpVersion = process.env.npm_package_version ||
|
|
149550
|
-
( true ? "2.32.
|
|
149748
|
+
( true ? "2.32.5" : 0);
|
|
149551
149749
|
return {
|
|
149552
149750
|
userAgent: `${osType} ${osRelease} ${arch} ${nodeVersion} CloudBase-MCP/${mcpVersion}`,
|
|
149553
149751
|
deviceId: this.deviceId,
|
|
@@ -178605,7 +178803,7 @@ async function handleReadOnlySql(args, context, deps) {
|
|
|
178605
178803
|
message: `PostgreSQL read-only SQL execution failed: ${reason}`,
|
|
178606
178804
|
data: {
|
|
178607
178805
|
role: context.role,
|
|
178608
|
-
sqlPreview:
|
|
178806
|
+
sqlPreview: args.sql.trim().slice(0, 500),
|
|
178609
178807
|
},
|
|
178610
178808
|
});
|
|
178611
178809
|
}
|
|
@@ -217979,8 +218177,7 @@ const cloudbase_manager_js_1 = __webpack_require__(3431);
|
|
|
217979
218177
|
const json_content_js_1 = __webpack_require__(4365);
|
|
217980
218178
|
const logger_js_1 = __webpack_require__(13039);
|
|
217981
218179
|
// 1. 枚举定义
|
|
217982
|
-
const
|
|
217983
|
-
const SearchKnowledgeModeEnum = zod_1.z.enum(["vector", "skill", "openapi", "docs"]);
|
|
218180
|
+
const SearchKnowledgeModeEnum = zod_1.z.enum(["skill", "openapi", "docs"]);
|
|
217984
218181
|
const CloudBaseDocsActionEnum = zod_1.z.enum([
|
|
217985
218182
|
"listModules",
|
|
217986
218183
|
"listModuleDocs",
|
|
@@ -217988,12 +218185,6 @@ const CloudBaseDocsActionEnum = zod_1.z.enum([
|
|
|
217988
218185
|
"readDoc",
|
|
217989
218186
|
"searchDocs",
|
|
217990
218187
|
]);
|
|
217991
|
-
// 2. 枚举到后端 id 的映射
|
|
217992
|
-
const KnowledgeBaseIdMap = {
|
|
217993
|
-
cloudbase: "ykfzskv4_ad28",
|
|
217994
|
-
scf: "scfsczskzyws_4bdc",
|
|
217995
|
-
miniprogram: "xcxzskws_25d8",
|
|
217996
|
-
};
|
|
217997
218188
|
// ============ 缓存配置 ============
|
|
217998
218189
|
const CACHE_BASE_DIR = path.join(os.homedir(), ".cloudbase-mcp");
|
|
217999
218190
|
const CACHE_META_FILE = path.join(CACHE_BASE_DIR, "cache-meta.json");
|
|
@@ -218117,32 +218308,6 @@ async function updateCache() {
|
|
|
218117
218308
|
await fs.mkdir(CACHE_BASE_DIR, { recursive: true });
|
|
218118
218309
|
await fs.writeFile(CACHE_META_FILE, JSON.stringify({ timestamp: Date.now() }, null, 2), "utf8");
|
|
218119
218310
|
}
|
|
218120
|
-
// 安全 JSON.parse
|
|
218121
|
-
function safeParse(str) {
|
|
218122
|
-
try {
|
|
218123
|
-
return JSON.parse(str);
|
|
218124
|
-
}
|
|
218125
|
-
catch (e) {
|
|
218126
|
-
return {};
|
|
218127
|
-
}
|
|
218128
|
-
}
|
|
218129
|
-
// 安全 JSON.stringify,处理循环引用
|
|
218130
|
-
function safeStringify(obj) {
|
|
218131
|
-
const seen = new WeakSet();
|
|
218132
|
-
try {
|
|
218133
|
-
return JSON.stringify(obj, function (key, value) {
|
|
218134
|
-
if (typeof value === "object" && value !== null) {
|
|
218135
|
-
if (seen.has(value))
|
|
218136
|
-
return;
|
|
218137
|
-
seen.add(value);
|
|
218138
|
-
}
|
|
218139
|
-
return value;
|
|
218140
|
-
});
|
|
218141
|
-
}
|
|
218142
|
-
catch (e) {
|
|
218143
|
-
return "";
|
|
218144
|
-
}
|
|
218145
|
-
}
|
|
218146
218311
|
function buildDocsEnvelope(action, data, message) {
|
|
218147
218312
|
return {
|
|
218148
218313
|
success: true,
|
|
@@ -218404,9 +218569,13 @@ async function registerRagTools(server) {
|
|
|
218404
218569
|
?.docs;
|
|
218405
218570
|
server.registerTool?.("searchKnowledgeBase", {
|
|
218406
218571
|
title: "云开发知识库检索",
|
|
218407
|
-
description:
|
|
218572
|
+
description: `云开发知识库检索工具,支持 CloudBase 官方文档 (docs)、固定技能文档 (skill) 和 OpenAPI 文档 (openapi) 查询。
|
|
218408
218573
|
|
|
218409
|
-
|
|
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
|
|
218410
218579
|
|
|
218411
218580
|
⚠️ 重要:当 CloudBase skills 处于禁用状态或当前 IDE 不支持 skill 文件读取时,必须使用 searchKnowledgeBase(mode=skill, skillName=...) 来获取 CloudBase 技能文档内容,而不是尝试直接读取 skill 文件。直接读取可能返回 400 错误。示例:
|
|
218412
218581
|
- 需要最小 Web+数据库 Demo 路径时:searchKnowledgeBase(mode=skill, skillName=minimal-web-baas-demo)
|
|
@@ -218444,37 +218613,13 @@ async function registerRagTools(server) {
|
|
|
218444
218613
|
.string()
|
|
218445
218614
|
.optional()
|
|
218446
218615
|
.describe("mode=docs 且 action=searchDocs 时指定。全文检索关键词。"),
|
|
218447
|
-
threshold: zod_1.z
|
|
218448
|
-
.number()
|
|
218449
|
-
.default(0.5)
|
|
218450
|
-
.optional()
|
|
218451
|
-
.describe("mode=vector 时指定。相似性检索阈值"),
|
|
218452
|
-
id: KnowledgeBaseEnum.default("cloudbase").optional().describe("mode=vector 时指定。知识库范围,默认 cloudbase。cloudbase=云开发全量知识,scf=云开发的云函数知识, miniprogram=小程序知识(不包含云开发与云函数知识)"),
|
|
218453
|
-
content: zod_1.z.string().describe("mode=vector 时指定。检索内容").optional(),
|
|
218454
|
-
options: zod_1.z
|
|
218455
|
-
.object({
|
|
218456
|
-
chunkExpand: zod_1.z
|
|
218457
|
-
.array(zod_1.z.number())
|
|
218458
|
-
.min(2)
|
|
218459
|
-
.max(2)
|
|
218460
|
-
.default([3, 3])
|
|
218461
|
-
.describe("指定返回的文档内容的展开长度,例如 [3,3]代表前后展开长度"),
|
|
218462
|
-
})
|
|
218463
|
-
.optional()
|
|
218464
|
-
.describe("mode=vector 时指定。其他选项"),
|
|
218465
|
-
limit: zod_1.z
|
|
218466
|
-
.number()
|
|
218467
|
-
.default(5)
|
|
218468
|
-
.optional()
|
|
218469
|
-
.describe("mode=vector 时指定。指定返回最相似的 Top K 的 K 的值"),
|
|
218470
218616
|
},
|
|
218471
218617
|
annotations: {
|
|
218472
218618
|
readOnlyHint: true,
|
|
218473
218619
|
openWorldHint: true,
|
|
218474
218620
|
category: "rag",
|
|
218475
218621
|
},
|
|
218476
|
-
}, async ({
|
|
218477
|
-
const chunkExpand = options?.chunkExpand ?? [3, 3];
|
|
218622
|
+
}, async ({ mode, skillName, apiName, action, moduleName, input, docPath, query, }) => {
|
|
218478
218623
|
if (mode === "docs") {
|
|
218479
218624
|
try {
|
|
218480
218625
|
const resolvedAction = action;
|
|
@@ -218554,76 +218699,8 @@ async function registerRagTools(server) {
|
|
|
218554
218699
|
],
|
|
218555
218700
|
};
|
|
218556
218701
|
}
|
|
218557
|
-
//
|
|
218558
|
-
|
|
218559
|
-
if (mode === "vector") {
|
|
218560
|
-
if (!content || !content.trim()) {
|
|
218561
|
-
throw new Error("检索内容不能为空: please provide non-empty `content` when mode=vector.");
|
|
218562
|
-
}
|
|
218563
|
-
}
|
|
218564
|
-
// 枚举到后端 id 映射
|
|
218565
|
-
const backendId = KnowledgeBaseIdMap[vectorKnowledgeBaseId] ||
|
|
218566
|
-
vectorKnowledgeBaseId;
|
|
218567
|
-
const signInRes = await fetch("https://tcb-advanced-a656fc.api.tcloudbasegateway.com/auth/v1/signin/anonymously", {
|
|
218568
|
-
method: "POST",
|
|
218569
|
-
headers: {
|
|
218570
|
-
"Content-Type": "application/json",
|
|
218571
|
-
Accept: "application/json",
|
|
218572
|
-
"x-device-id": "cloudbase-ai-toolkit",
|
|
218573
|
-
},
|
|
218574
|
-
body: safeStringify({
|
|
218575
|
-
collectionView: backendId,
|
|
218576
|
-
options: {
|
|
218577
|
-
chunkExpand,
|
|
218578
|
-
},
|
|
218579
|
-
search: {
|
|
218580
|
-
content: content,
|
|
218581
|
-
limit,
|
|
218582
|
-
},
|
|
218583
|
-
}),
|
|
218584
|
-
});
|
|
218585
|
-
const token = (await signInRes.json()).access_token;
|
|
218586
|
-
const res = await fetch(`https://tcb-advanced-a656fc.api.tcloudbasegateway.com/v1/knowledge/search`, {
|
|
218587
|
-
method: "POST",
|
|
218588
|
-
headers: {
|
|
218589
|
-
"Content-Type": "application/json",
|
|
218590
|
-
Authorization: `Bearer ${token}`,
|
|
218591
|
-
},
|
|
218592
|
-
body: safeStringify({
|
|
218593
|
-
collectionView: backendId,
|
|
218594
|
-
options: {
|
|
218595
|
-
chunkExpand,
|
|
218596
|
-
},
|
|
218597
|
-
search: {
|
|
218598
|
-
content: content,
|
|
218599
|
-
limit,
|
|
218600
|
-
},
|
|
218601
|
-
}),
|
|
218602
|
-
});
|
|
218603
|
-
const result = await res.json();
|
|
218604
|
-
if (result.code) {
|
|
218605
|
-
throw new Error(result.message);
|
|
218606
|
-
}
|
|
218607
|
-
return {
|
|
218608
|
-
content: [
|
|
218609
|
-
{
|
|
218610
|
-
type: "text",
|
|
218611
|
-
text: safeStringify(result.data.documents
|
|
218612
|
-
.filter((item) => item.score >= threshold)
|
|
218613
|
-
.map((item) => {
|
|
218614
|
-
return {
|
|
218615
|
-
score: item.score,
|
|
218616
|
-
fileTile: item.documentSet.fileTitle,
|
|
218617
|
-
url: safeParse(item.documentSet.fileMetaData).url,
|
|
218618
|
-
paragraphTitle: item.data.paragraphTitle,
|
|
218619
|
-
text: `${item.data.pre?.join("\n") || ""}
|
|
218620
|
-
${item.data.text}
|
|
218621
|
-
${item.data.next?.join("\n") || ""}`,
|
|
218622
|
-
};
|
|
218623
|
-
})),
|
|
218624
|
-
},
|
|
218625
|
-
],
|
|
218626
|
-
};
|
|
218702
|
+
// mode 是枚举,docs / skill / openapi 三个分支已在上面全部返回,这里不可达
|
|
218703
|
+
throw new Error(`unsupported mode: ${String(mode)}`);
|
|
218627
218704
|
});
|
|
218628
218705
|
}
|
|
218629
218706
|
function extractDescriptionFromFrontMatter(content) {
|
|
@@ -227824,6 +227901,7 @@ exports.TCB_QUERY_REGIONS = exports.SITE_IDS = exports.SITE_REGION_MAP = void 0;
|
|
|
227824
227901
|
exports.isSiteId = isSiteId;
|
|
227825
227902
|
exports.normalizeSite = normalizeSite;
|
|
227826
227903
|
exports.getSite = getSite;
|
|
227904
|
+
exports.resolveApiKeyExchangeRegion = resolveApiKeyExchangeRegion;
|
|
227827
227905
|
exports.resolveSite = resolveSite;
|
|
227828
227906
|
exports.resolveSiteAndRegion = resolveSiteAndRegion;
|
|
227829
227907
|
const project_config_js_1 = __webpack_require__(68445);
|
|
@@ -227833,6 +227911,7 @@ exports.SITE_REGION_MAP = {
|
|
|
227833
227911
|
label: "国内站",
|
|
227834
227912
|
authHost: "tcb.cloud.tencent.com",
|
|
227835
227913
|
consoleHost: "tcb.cloud.tencent.com",
|
|
227914
|
+
oauthEndpoint: "https://tcb-api.cloud.tencent.com/qcloud-tcb/v1/oauth",
|
|
227836
227915
|
defaultRegion: "ap-shanghai",
|
|
227837
227916
|
regions: ["ap-shanghai", "ap-guangzhou", "ap-singapore"],
|
|
227838
227917
|
capabilities: { noSql: true },
|
|
@@ -227842,6 +227921,9 @@ exports.SITE_REGION_MAP = {
|
|
|
227842
227921
|
label: "国际站",
|
|
227843
227922
|
authHost: "tcb.tencentcloud.com",
|
|
227844
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",
|
|
227845
227927
|
defaultRegion: "ap-singapore",
|
|
227846
227928
|
regions: ["ap-singapore"],
|
|
227847
227929
|
capabilities: { noSql: false },
|
|
@@ -227896,8 +227978,24 @@ function getSite(region, explicitSite) {
|
|
|
227896
227978
|
return "domestic";
|
|
227897
227979
|
}
|
|
227898
227980
|
/**
|
|
227899
|
-
*
|
|
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 网关导致换取失败
|
|
227900
227994
|
*/
|
|
227995
|
+
function resolveApiKeyExchangeRegion(opts = {}) {
|
|
227996
|
+
const resolved = resolveSiteAndRegion(opts);
|
|
227997
|
+
return resolved.site === "intl" && !resolved.ambiguous ? resolved.region : undefined;
|
|
227998
|
+
}
|
|
227901
227999
|
function resolveSite(region, explicitSite) {
|
|
227902
228000
|
const site = getSite(region, explicitSite);
|
|
227903
228001
|
return site === "ambiguous" ? "intl" : site;
|
|
@@ -233413,7 +233511,7 @@ ${envIdSection}
|
|
|
233413
233511
|
## 环境信息
|
|
233414
233512
|
- 操作系统: ${os_1.default.type()} ${os_1.default.release()}
|
|
233415
233513
|
- Node.js版本: ${process.version}
|
|
233416
|
-
- MCP 版本:${process.env.npm_package_version || ( true ? "2.32.
|
|
233514
|
+
- MCP 版本:${process.env.npm_package_version || ( true ? "2.32.5" : 0)}
|
|
233417
233515
|
- 系统架构: ${os_1.default.arch()}
|
|
233418
233516
|
- 时间: ${new Date().toISOString()}
|
|
233419
233517
|
- 请求ID: ${requestId}
|
|
@@ -233498,7 +233596,7 @@ function createWrappedHandler(name, handler, server) {
|
|
|
233498
233596
|
requestId: (typeof error === 'object' && error && 'requestId' in error) ? error.requestId : '',
|
|
233499
233597
|
ide: server.ide || process.env.INTEGRATION_IDE || ''
|
|
233500
233598
|
});
|
|
233501
|
-
const mcpVersion = true ? "2.32.
|
|
233599
|
+
const mcpVersion = true ? "2.32.5" : 0;
|
|
233502
233600
|
const requestIdSuffix = requestId ? `\n🆔 RequestId: ${requestId}` : '';
|
|
233503
233601
|
const enhancedErrorMessage = `${errorMessage}${requestIdSuffix}\n\n📦 CloudBase MCP v${mcpVersion}\n🔗 遇到问题?请复制以下链接到浏览器打开\n即可自动携带错误详情快速创建 GitHub Issue:\n${issueLink}`;
|
|
233504
233602
|
// 创建新的错误对象,保持原有的错误类型但更新消息
|
|
@@ -252887,7 +252985,7 @@ function registerSetupTools(server) {
|
|
|
252887
252985
|
server.registerTool("downloadTemplate", {
|
|
252888
252986
|
title: "下载项目模板",
|
|
252889
252987
|
description: `自动下载并部署CloudBase项目模板。
|
|
252890
|
-
**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)`,
|
|
252891
252989
|
inputSchema: {
|
|
252892
252990
|
template: zod_1.z
|
|
252893
252991
|
.enum(["react", "vue", "miniprogram", "uniapp", "rules"])
|
|
@@ -255297,7 +255395,13 @@ async function peekLoginState(options) {
|
|
|
255297
255395
|
try {
|
|
255298
255396
|
// 优先使用 IDE 注入的工作目录,其次 process.cwd()
|
|
255299
255397
|
const projectCwd = process.env.WORKSPACE_FOLDER_PATHS || process.cwd();
|
|
255300
|
-
|
|
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 } : {}) });
|
|
255301
255405
|
return credential;
|
|
255302
255406
|
}
|
|
255303
255407
|
catch (e) {
|
|
@@ -255392,6 +255496,18 @@ async function ensureLogin(options) {
|
|
|
255392
255496
|
if (resolvedAuthOptions.oauthEndpoint) {
|
|
255393
255497
|
loginOptions.getOAuthEndpoint = () => resolvedAuthOptions.oauthEndpoint;
|
|
255394
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
|
+
}
|
|
255395
255511
|
if (resolvedAuthOptions.oauthCustom) {
|
|
255396
255512
|
loginOptions.custom = true;
|
|
255397
255513
|
}
|