@cloudbase/cloudbase-mcp 2.21.0 → 2.21.1-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1914,17 +1914,17 @@ function buildEnvDomainManagementResult(params) {
1914
1914
  operation: action,
1915
1915
  targetDomains: domains,
1916
1916
  asyncState: "PENDING",
1917
- message: '安全域名已提交添加请求。该变更通常需要约 10 分钟传播,请继续轮询 envQuery(action="domains"),直到目标域名状态为 ENABLE。',
1917
+ message: '安全域名已提交添加请求。该变更通常需要约 10 分钟传播,请继续轮询 queryEnv(action="domains"),直到目标域名状态为 ENABLE。',
1918
1918
  propagation: {
1919
1919
  requiresPolling: true,
1920
- pollTool: "envQuery",
1920
+ pollTool: "queryEnv",
1921
1921
  pollAction: "domains",
1922
1922
  pollIntervalSuggestionSeconds: 10,
1923
1923
  timeoutSuggestionSeconds: 600,
1924
- successCondition: '目标域名出现在 envQuery(action="domains") 返回中,且 Status 为 ENABLE。',
1924
+ successCondition: '目标域名出现在 queryEnv(action="domains") 返回中,且 Status 为 ENABLE。',
1925
1925
  },
1926
1926
  next_step: {
1927
- tool: "envQuery",
1927
+ tool: "queryEnv",
1928
1928
  action: "domains",
1929
1929
  suggested_args: {
1930
1930
  action: "domains",
@@ -1939,17 +1939,17 @@ function buildEnvDomainManagementResult(params) {
1939
1939
  operation: action,
1940
1940
  targetDomains: domains,
1941
1941
  asyncState: "PENDING",
1942
- message: '安全域名已提交删除请求。该变更可能需要数分钟传播,请继续轮询 envQuery(action="domains"),直到目标域名不再出现。',
1942
+ message: '安全域名已提交删除请求。该变更可能需要数分钟传播,请继续轮询 queryEnv(action="domains"),直到目标域名不再出现。',
1943
1943
  propagation: {
1944
1944
  requiresPolling: true,
1945
- pollTool: "envQuery",
1945
+ pollTool: "queryEnv",
1946
1946
  pollAction: "domains",
1947
1947
  pollIntervalSuggestionSeconds: 10,
1948
1948
  timeoutSuggestionSeconds: 600,
1949
- successCondition: '目标域名不再出现在 envQuery(action="domains") 返回中。',
1949
+ successCondition: '目标域名不再出现在 queryEnv(action="domains") 返回中。',
1950
1950
  },
1951
1951
  next_step: {
1952
- tool: "envQuery",
1952
+ tool: "queryEnv",
1953
1953
  action: "domains",
1954
1954
  suggested_args: {
1955
1955
  action: "domains",
@@ -2223,7 +2223,7 @@ function buildEnvQueryListResult(params) {
2223
2223
  const paginated = paginateEnvList(filteredList, params.filters.offset, params.filters.limit);
2224
2224
  const exactEnvIdSummaryHint = params.filters.envId
2225
2225
  ? {
2226
- tool: "envQuery",
2226
+ tool: "queryEnv",
2227
2227
  action: "info",
2228
2228
  reason: "action=list with envId only returns a concise summary. Use action=info to fetch detailed environment information such as full resource metadata and additional environment details.",
2229
2229
  }
@@ -2294,7 +2294,7 @@ function normalizeOptionalToolString(value) {
2294
2294
  : undefined;
2295
2295
  }
2296
2296
  /**
2297
- * Build enhanced error message for envQuery tool errors
2297
+ * Build enhanced error message for queryEnv tool errors
2298
2298
  * Provides actionable guidance based on error patterns
2299
2299
  */
2300
2300
  function buildEnvQueryErrorMessage(error, action) {
@@ -2310,7 +2310,7 @@ function buildEnvQueryErrorMessage(error, action) {
2310
2310
  suggestions.push("参数错误:可能是认证信息无效或已过期,请尝试以下步骤:");
2311
2311
  suggestions.push("1. 先调用 auth(action=\"status\") 检查当前登录状态");
2312
2312
  suggestions.push("2. 如果未登录,调用 auth(action=\"start_auth\", authMode=\"device\") 完成登录");
2313
- suggestions.push("3. 登录完成后再次调用 envQuery(action=\"list\")");
2313
+ suggestions.push("3. 登录完成后再次调用 queryEnv(action=\"list\")");
2314
2314
  }
2315
2315
  if (hasAuthError) {
2316
2316
  suggestions.push("认证错误:当前未登录或认证已过期。");
@@ -2322,7 +2322,7 @@ function buildEnvQueryErrorMessage(error, action) {
2322
2322
  }
2323
2323
  if (hasEnvNotFoundError) {
2324
2324
  suggestions.push("环境错误:指定的环境不存在或无法访问。");
2325
- suggestions.push("请使用 envQuery(action=\"list\") 查看可用的环境列表。");
2325
+ suggestions.push("请使用 queryEnv(action=\"list\") 查看可用的环境列表。");
2326
2326
  }
2327
2327
  if (hasNetworkError) {
2328
2328
  suggestions.push("网络错误:请检查网络连接,稍后重试。");
@@ -2334,7 +2334,7 @@ function buildEnvQueryErrorMessage(error, action) {
2334
2334
  suggestions.push("2. 如未登录,执行 auth(action=\"start_auth\") 完成认证");
2335
2335
  suggestions.push("3. 确认环境 ID 正确且可访问");
2336
2336
  }
2337
- return `[envQuery/${action}] 调用失败: ${baseMessage}\n\n解决建议:\n${suggestions.join("\n")}`;
2337
+ return `[queryEnv/${action}] 调用失败: ${baseMessage}\n\n解决建议:\n${suggestions.join("\n")}`;
2338
2338
  }
2339
2339
  function normalizeOptionalToolBoolean(value) {
2340
2340
  return typeof value === "boolean" ? value : undefined;
@@ -2363,519 +2363,500 @@ function registerEnvTools(server) {
2363
2363
  const supportedAuthActions = getSupportedAuthActions(server);
2364
2364
  const authActionEnum = [...supportedAuthActions];
2365
2365
  // auth - CloudBase (云开发) 开发阶段登录与环境绑定
2366
- server.registerTool?.("auth", {
2367
- title: "CloudBase 开发阶段登录与环境",
2368
- description: "CloudBase(腾讯云开发)开发阶段登录与环境绑定。登录后即可访问云资源;环境(env)是云函数、数据库、静态托管等资源的隔离单元,绑定环境后其他 MCP 工具才能操作该环境。支持:查询状态、发起登录、绑定环境(set_env)、退出登录。",
2369
- inputSchema: {
2370
- action: zod_1.z
2371
- .enum(authActionEnum)
2372
- .optional()
2373
- .describe("动作:status=查询状态,start_auth=发起登录,set_env=绑定环境(传envId),logout=退出登录"),
2374
- ...(supportedAuthActions.includes("start_auth")
2375
- ? {
2376
- authMode: zod_1.z
2377
- .enum(["device", "web"])
2378
- .optional()
2379
- .describe("认证模式:device=设备码授权,web=浏览器回调授权"),
2380
- oauthEndpoint: zod_1.z
2381
- .string()
2382
- .optional()
2383
- .describe("高级可选:自定义 device-code 登录 endpoint。配置后 oauthCustom 默认按 true 处理"),
2384
- clientId: zod_1.z
2385
- .string()
2386
- .optional()
2387
- .describe("高级可选:自定义 device-code 登录 client_id,不传则使用默认值"),
2388
- oauthCustom: zod_1.z
2389
- .boolean()
2390
- .optional()
2391
- .describe("高级可选:自定义 endpoint 返回格式开关。未配置 endpoint 时默认 false;配置 endpoint 后默认 true,且不能设为 false"),
2392
- }
2393
- : {}),
2394
- envId: zod_1.z
2395
- .string()
2396
- .optional()
2397
- .describe("环境ID(CloudBase 环境唯一标识),绑定后工具将操作该环境。action=set_env 时必填"),
2398
- ...(supportedAuthActions.includes("logout")
2399
- ? {
2400
- confirm: zod_1.z
2401
- .literal("yes")
2402
- .optional()
2403
- .describe("action=logout 时确认操作,传 yes"),
2404
- }
2405
- : {}),
2406
- ...(supportedAuthActions.includes("get_temp_credentials")
2407
- ? {
2408
- reveal: zod_1.z
2409
- .boolean()
2410
- .optional()
2411
- .describe("action=get_temp_credentials 时可选。true=返回明文临时密钥;默认 false 仅返回脱敏结果"),
2412
- }
2413
- : {}),
2414
- },
2415
- annotations: {
2416
- readOnlyHint: false,
2417
- destructiveHint: false,
2418
- idempotentHint: false,
2419
- openWorldHint: true,
2420
- category: "env",
2421
- },
2422
- }, async (rawArgs) => {
2423
- const action = rawArgs.action ?? "status";
2424
- const authMode = rawArgs.authMode === "device" || rawArgs.authMode === "web"
2425
- ? rawArgs.authMode
2426
- : undefined;
2427
- const oauthEndpoint = normalizeOptionalToolString(rawArgs.oauthEndpoint);
2428
- const clientId = normalizeOptionalToolString(rawArgs.clientId);
2429
- const oauthCustom = normalizeOptionalToolBoolean(rawArgs.oauthCustom);
2430
- const envId = rawArgs.envId;
2431
- const confirm = rawArgs.confirm === "yes" ? "yes" : undefined;
2432
- const reveal = normalizeOptionalToolBoolean(rawArgs.reveal) === true;
2433
- const resolvedAuthOptions = resolveToolAuthOptions(server, {
2434
- authMode,
2435
- oauthEndpoint,
2436
- clientId,
2437
- oauthCustom,
2438
- });
2439
- const authConfigSummary = (0, auth_js_1.buildAuthConfigSummary)(resolvedAuthOptions);
2440
- let deviceAuthInfo;
2441
- const onDeviceCode = (info) => {
2442
- deviceAuthInfo = info;
2443
- (0, auth_js_1.setPendingAuthProgressState)(info, "device");
2444
- // emitDeviceAuthNotice(server, info);
2445
- };
2446
- const authChallenge = () => (0, auth_js_1.buildDeviceAuthChallengePayload)(deviceAuthInfo);
2447
- try {
2448
- if (!supportedAuthActions.includes(action)) {
2449
- return (0, tool_result_js_1.buildJsonToolResult)({
2450
- ok: false,
2451
- code: "NOT_SUPPORTED",
2452
- message: `当前 IDE 不支持 auth(action="${action}")。`,
2453
- next_step: (0, tool_result_js_1.buildAuthNextStep)("status", {
2454
- suggestedArgs: { action: "status" },
2455
- }),
2456
- });
2457
- }
2458
- if (action === "status") {
2459
- const loginState = await (0, auth_js_1.peekLoginState)();
2460
- const authFlowState = await (0, auth_js_1.getAuthProgressState)();
2461
- // 判断是否为 API Key 模式
2462
- const isApiKeyMode = !!(process.env.CLOUDBASE_API_KEY && process.env.CLOUDBASE_ENV_ID);
2463
- const authStatus = loginState
2464
- ? "READY"
2465
- : authFlowState.status === "PENDING"
2466
- ? "PENDING"
2467
- : "REQUIRED";
2468
- let envPreparation;
2469
- const message = authStatus === "READY"
2470
- ? undefined
2471
- : authStatus === "PENDING"
2472
- ? "设备码授权进行中,请完成浏览器授权后再次调用 auth(action=\"status\")"
2473
- : isCodeBuddyIde(server)
2474
- ? "当前未登录。CodeBuddy 暂不支持在 tool 内发起认证,请在外部完成认证后再次调用 auth(action=\"status\")。"
2475
- : "当前未登录,请先执行 auth(action=\"start_auth\")";
2476
- if (authStatus === "READY" && loginState) {
2477
- envPreparation = await prepareAuthEnvironment({
2478
- server,
2479
- cloudBaseOptions,
2480
- loginState,
2481
- });
2482
- }
2483
- return (0, tool_result_js_1.buildJsonToolResult)({
2484
- ok: true,
2485
- code: "STATUS",
2486
- auth_status: authStatus,
2487
- ...(isApiKeyMode ? { auth_mode: "api_key" } : {}),
2488
- auth_config: authConfigSummary,
2489
- ...(envPreparation
2490
- ? buildAuthEnvSetupPayload(envPreparation)
2491
- : {
2492
- env_status: "NONE",
2493
- current_env_id: null,
2494
- ...buildEnvCandidatePayload([]),
2495
- }),
2496
- auth_challenge: authFlowState.status === "PENDING"
2497
- ? (0, auth_js_1.buildDeviceAuthChallengePayload)(authFlowState.authChallenge)
2498
- : undefined,
2499
- message,
2500
- next_step: authStatus === "REQUIRED"
2501
- ? buildAuthRequiredNextStep(server)
2502
- : authStatus === "PENDING"
2503
- ? (0, tool_result_js_1.buildAuthNextStep)("status", {
2504
- suggestedArgs: { action: "status" },
2505
- })
2506
- : envPreparation?.nextStep,
2507
- });
2508
- }
2509
- if (action === "start_auth") {
2510
- // API Key 模式:尝试换取临时密钥
2511
- if (process.env.CLOUDBASE_API_KEY && process.env.CLOUDBASE_ENV_ID) {
2512
- try {
2513
- const existingLoginState = await (0, auth_js_1.peekLoginState)();
2514
- if (existingLoginState) {
2515
- return (0, tool_result_js_1.buildJsonToolResult)({
2516
- ok: true,
2517
- code: "AUTH_READY",
2518
- message: "当前使用 API Key 认证模式,已自动完成登录,无需手动授权。",
2519
- auth_mode: "api_key",
2520
- envId: process.env.CLOUDBASE_ENV_ID,
2521
- });
2522
- }
2366
+ // 微信 IDE 使用票据认证,不需要登录工具
2367
+ if (server.ide !== 'wxide') {
2368
+ server.registerTool?.("auth", {
2369
+ title: "CloudBase 开发阶段登录与环境",
2370
+ description: "CloudBase(腾讯云开发)开发阶段登录与环境绑定。登录后即可访问云资源;环境(env)是云函数、数据库、静态托管等资源的隔离单元,绑定环境后其他 MCP 工具才能操作该环境。支持:查询状态、发起登录、绑定环境(set_env)、退出登录。",
2371
+ inputSchema: {
2372
+ action: zod_1.z
2373
+ .enum(authActionEnum)
2374
+ .optional()
2375
+ .describe("动作:status=查询状态,start_auth=发起登录,set_env=绑定环境(传envId),logout=退出登录"),
2376
+ ...(supportedAuthActions.includes("start_auth")
2377
+ ? {
2378
+ authMode: zod_1.z
2379
+ .enum(["device", "web"])
2380
+ .optional()
2381
+ .describe("认证模式:device=设备码授权,web=浏览器回调授权"),
2382
+ oauthEndpoint: zod_1.z
2383
+ .string()
2384
+ .optional()
2385
+ .describe("高级可选:自定义 device-code 登录 endpoint。配置后 oauthCustom 默认按 true 处理"),
2386
+ clientId: zod_1.z
2387
+ .string()
2388
+ .optional()
2389
+ .describe("高级可选:自定义 device-code 登录 client_id,不传则使用默认值"),
2390
+ oauthCustom: zod_1.z
2391
+ .boolean()
2392
+ .optional()
2393
+ .describe("高级可选:自定义 endpoint 返回格式开关。未配置 endpoint 时默认 false;配置 endpoint 后默认 true,且不能设为 false"),
2523
2394
  }
2524
- catch (e) {
2525
- // peekLoginState 内部异常,记录后 fall through
2526
- (0, logger_js_1.debug)("start_auth: peekLoginState threw", { error: e instanceof Error ? e.message : String(e) });
2395
+ : {}),
2396
+ envId: zod_1.z
2397
+ .string()
2398
+ .optional()
2399
+ .describe("环境ID(CloudBase 环境唯一标识),绑定后工具将操作该环境。action=set_env 时必填"),
2400
+ ...(supportedAuthActions.includes("logout")
2401
+ ? {
2402
+ confirm: zod_1.z
2403
+ .literal("yes")
2404
+ .optional()
2405
+ .describe("action=logout 时确认操作,传 yes"),
2406
+ }
2407
+ : {}),
2408
+ ...(supportedAuthActions.includes("get_temp_credentials")
2409
+ ? {
2410
+ reveal: zod_1.z
2411
+ .boolean()
2412
+ .optional()
2413
+ .describe("action=get_temp_credentials 时可选。true=返回明文临时密钥;默认 false 仅返回脱敏结果"),
2527
2414
  }
2528
- // API Key 换取失败:返回详细诊断信息
2529
- // 尝试获取更详细的错误信息
2530
- let diagMessage = "当前配置了 API Key 认证模式,但换取临时密钥失败。";
2531
- const endpoint = process.env.CLOUDBASE_API_ENDPOINT || `https://${process.env.CLOUDBASE_ENV_ID}.ap-shanghai.tcb-api.tencentcloudapi.com`;
2532
- diagMessage += `\n\n诊断信息:`;
2533
- diagMessage += `\n- CLOUDBASE_ENV_ID: ${process.env.CLOUDBASE_ENV_ID}`;
2534
- diagMessage += `\n- CLOUDBASE_API_KEY: ${process.env.CLOUDBASE_API_KEY.slice(0, 20)}...(已截断)`;
2535
- diagMessage += `\n- Endpoint: ${endpoint}`;
2536
- diagMessage += `\n\n可能原因:`;
2537
- diagMessage += `\n1. API Key 已过期或被删除`;
2538
- diagMessage += `\n2. Endpoint 不可达(网络/DNS 问题)`;
2539
- diagMessage += `\n3. CLOUDBASE_ENV_ID 与 API Key 所属环境不匹配`;
2540
- diagMessage += `\n\n建议:检查 MCP 配置中的 CLOUDBASE_API_KEY 和 CLOUDBASE_ENV_ID 环境变量是否正确。`;
2415
+ : {}),
2416
+ },
2417
+ annotations: {
2418
+ readOnlyHint: false,
2419
+ destructiveHint: false,
2420
+ idempotentHint: false,
2421
+ openWorldHint: true,
2422
+ category: "env",
2423
+ },
2424
+ }, async (rawArgs) => {
2425
+ const action = rawArgs.action ?? "status";
2426
+ const authMode = rawArgs.authMode === "device" || rawArgs.authMode === "web"
2427
+ ? rawArgs.authMode
2428
+ : undefined;
2429
+ const oauthEndpoint = normalizeOptionalToolString(rawArgs.oauthEndpoint);
2430
+ const clientId = normalizeOptionalToolString(rawArgs.clientId);
2431
+ const oauthCustom = normalizeOptionalToolBoolean(rawArgs.oauthCustom);
2432
+ const envId = rawArgs.envId;
2433
+ const confirm = rawArgs.confirm === "yes" ? "yes" : undefined;
2434
+ const reveal = normalizeOptionalToolBoolean(rawArgs.reveal) === true;
2435
+ const resolvedAuthOptions = resolveToolAuthOptions(server, {
2436
+ authMode,
2437
+ oauthEndpoint,
2438
+ clientId,
2439
+ oauthCustom,
2440
+ });
2441
+ const authConfigSummary = (0, auth_js_1.buildAuthConfigSummary)(resolvedAuthOptions);
2442
+ let deviceAuthInfo;
2443
+ const onDeviceCode = (info) => {
2444
+ deviceAuthInfo = info;
2445
+ (0, auth_js_1.setPendingAuthProgressState)(info, "device");
2446
+ // emitDeviceAuthNotice(server, info);
2447
+ };
2448
+ const authChallenge = () => (0, auth_js_1.buildDeviceAuthChallengePayload)(deviceAuthInfo);
2449
+ try {
2450
+ if (!supportedAuthActions.includes(action)) {
2541
2451
  return (0, tool_result_js_1.buildJsonToolResult)({
2542
2452
  ok: false,
2543
- code: "API_KEY_AUTH_FAILED",
2544
- message: diagMessage,
2545
- auth_mode: "api_key",
2546
- envId: process.env.CLOUDBASE_ENV_ID,
2547
- endpoint,
2548
- });
2549
- }
2550
- const region = server.cloudBaseOptions?.region || process.env.TCB_REGION;
2551
- const auth = toolbox_1.AuthSupervisor.getInstance({});
2552
- const authFlowState = await (0, auth_js_1.getAuthProgressState)();
2553
- if (authFlowState.status === "PENDING" && authFlowState.authChallenge) {
2554
- return (0, tool_result_js_1.buildJsonToolResult)({
2555
- ok: true,
2556
- code: "AUTH_PENDING",
2557
- message: "设备码授权进行中,请在浏览器中打开 verification_uri 并输入 user_code 完成授权。",
2558
- auth_challenge: (0, auth_js_1.buildDeviceAuthChallengePayload)(authFlowState.authChallenge),
2453
+ code: "NOT_SUPPORTED",
2454
+ message: `当前 IDE 不支持 auth(action="${action}")。`,
2559
2455
  next_step: (0, tool_result_js_1.buildAuthNextStep)("status", {
2560
2456
  suggestedArgs: { action: "status" },
2561
2457
  }),
2562
2458
  });
2563
2459
  }
2564
- // 1. 如果已经有登录态,直接返回 AUTH_READY
2565
- try {
2566
- const existingLoginState = await (0, auth_js_1.peekLoginState)();
2567
- if (existingLoginState) {
2568
- const envPreparation = await prepareAuthEnvironment({
2460
+ if (action === "status") {
2461
+ const loginState = await (0, auth_js_1.peekLoginState)();
2462
+ const authFlowState = await (0, auth_js_1.getAuthProgressState)();
2463
+ // 判断是否为 API Key 模式
2464
+ const isApiKeyMode = !!(process.env.CLOUDBASE_API_KEY && process.env.CLOUDBASE_ENV_ID);
2465
+ const authStatus = loginState
2466
+ ? "READY"
2467
+ : authFlowState.status === "PENDING"
2468
+ ? "PENDING"
2469
+ : "REQUIRED";
2470
+ let envPreparation;
2471
+ const message = authStatus === "READY"
2472
+ ? undefined
2473
+ : authStatus === "PENDING"
2474
+ ? "设备码授权进行中,请完成浏览器授权后再次调用 auth(action=\"status\")"
2475
+ : isCodeBuddyIde(server)
2476
+ ? "当前未登录。CodeBuddy 暂不支持在 tool 内发起认证,请在外部完成认证后再次调用 auth(action=\"status\")。"
2477
+ : "当前未登录,请先执行 auth(action=\"start_auth\")";
2478
+ if (authStatus === "READY" && loginState) {
2479
+ envPreparation = await prepareAuthEnvironment({
2569
2480
  server,
2570
2481
  cloudBaseOptions,
2571
- loginState: existingLoginState,
2572
- });
2573
- return (0, tool_result_js_1.buildJsonToolResult)({
2574
- ok: true,
2575
- code: "AUTH_READY",
2576
- message: envPreparation.message,
2577
- auth_challenge: authChallenge(),
2578
- ...buildAuthEnvSetupPayload(envPreparation),
2579
- next_step: envPreparation.nextStep,
2482
+ loginState,
2580
2483
  });
2581
2484
  }
2582
- }
2583
- catch {
2584
- // 忽略 getLoginState 错误,继续尝试发起登录
2585
- }
2586
- const validationError = (0, auth_js_1.getAuthConfigValidationError)(resolvedAuthOptions);
2587
- if (validationError) {
2588
2485
  return (0, tool_result_js_1.buildJsonToolResult)({
2589
- ok: false,
2590
- code: "INVALID_ARGS",
2591
- message: validationError,
2486
+ ok: true,
2487
+ code: "STATUS",
2488
+ auth_status: authStatus,
2489
+ ...(isApiKeyMode ? { auth_mode: "api_key" } : {}),
2592
2490
  auth_config: authConfigSummary,
2593
- next_step: (0, tool_result_js_1.buildAuthNextStep)("start_auth", {
2594
- suggestedArgs: { action: "start_auth", authMode: "device" },
2595
- }),
2491
+ ...(envPreparation
2492
+ ? buildAuthEnvSetupPayload(envPreparation)
2493
+ : {
2494
+ env_status: "NONE",
2495
+ current_env_id: null,
2496
+ ...buildEnvCandidatePayload([]),
2497
+ }),
2498
+ auth_challenge: authFlowState.status === "PENDING"
2499
+ ? (0, auth_js_1.buildDeviceAuthChallengePayload)(authFlowState.authChallenge)
2500
+ : undefined,
2501
+ message,
2502
+ next_step: authStatus === "REQUIRED"
2503
+ ? buildAuthRequiredNextStep(server)
2504
+ : authStatus === "PENDING"
2505
+ ? (0, tool_result_js_1.buildAuthNextStep)("status", {
2506
+ suggestedArgs: { action: "status" },
2507
+ })
2508
+ : envPreparation?.nextStep,
2596
2509
  });
2597
2510
  }
2598
- // 2. 设备码模式:监听到 device code 即返回 AUTH_PENDING,后续由 toolbox 异步轮询并更新本地 credential
2599
- const effectiveMode = resolvedAuthOptions.authMode;
2600
- if (effectiveMode === "device") {
2601
- let resolveCode;
2602
- let rejectCode;
2603
- const codeReady = new Promise((resolve, reject) => {
2604
- resolveCode = resolve;
2605
- rejectCode = reject;
2606
- });
2607
- const deviceOnCode = (info) => {
2608
- onDeviceCode(info);
2609
- if (resolveCode) {
2610
- resolveCode();
2611
- }
2612
- };
2613
- try {
2614
- // 启动 Device Flow,全流程由 toolbox 负责轮询和写入 credential,这里不等待完成
2615
- auth
2616
- .loginByWebAuth({
2617
- flow: "device",
2618
- ...(resolvedAuthOptions.clientId
2619
- ? { client_id: resolvedAuthOptions.clientId }
2620
- : {}),
2621
- ...(resolvedAuthOptions.oauthEndpoint
2622
- ? { getOAuthEndpoint: () => resolvedAuthOptions.oauthEndpoint }
2623
- : {}),
2624
- ...(resolvedAuthOptions.oauthCustom
2625
- ? { custom: true }
2626
- : {}),
2627
- onDeviceCode: deviceOnCode,
2628
- })
2629
- .then(() => {
2630
- (0, auth_js_1.resolveAuthProgressState)();
2631
- })
2632
- .catch((err) => {
2633
- (0, auth_js_1.rejectAuthProgressState)(err);
2634
- // 如果在拿到 device code 之前就失败,则唤醒当前调用并返回错误
2635
- if (!deviceAuthInfo && rejectCode) {
2636
- rejectCode(err);
2511
+ if (action === "start_auth") {
2512
+ // API Key 模式:尝试换取临时密钥
2513
+ if (process.env.CLOUDBASE_API_KEY && process.env.CLOUDBASE_ENV_ID) {
2514
+ try {
2515
+ const existingLoginState = await (0, auth_js_1.peekLoginState)();
2516
+ if (existingLoginState) {
2517
+ return (0, tool_result_js_1.buildJsonToolResult)({
2518
+ ok: true,
2519
+ code: "AUTH_READY",
2520
+ message: "当前使用 API Key 认证模式,已自动完成登录,无需手动授权。",
2521
+ auth_mode: "api_key",
2522
+ envId: process.env.CLOUDBASE_ENV_ID,
2523
+ });
2637
2524
  }
2525
+ }
2526
+ catch (e) {
2527
+ // peekLoginState 内部异常,记录后 fall through
2528
+ (0, logger_js_1.debug)("start_auth: peekLoginState threw", { error: e instanceof Error ? e.message : String(e) });
2529
+ }
2530
+ // API Key 换取失败:返回详细诊断信息
2531
+ // 尝试获取更详细的错误信息
2532
+ let diagMessage = "当前配置了 API Key 认证模式,但换取临时密钥失败。";
2533
+ const endpoint = process.env.CLOUDBASE_API_ENDPOINT || `https://${process.env.CLOUDBASE_ENV_ID}.ap-shanghai.tcb-api.tencentcloudapi.com`;
2534
+ diagMessage += `\n\n诊断信息:`;
2535
+ diagMessage += `\n- CLOUDBASE_ENV_ID: ${process.env.CLOUDBASE_ENV_ID}`;
2536
+ diagMessage += `\n- CLOUDBASE_API_KEY: ${process.env.CLOUDBASE_API_KEY.slice(0, 20)}...(已截断)`;
2537
+ diagMessage += `\n- Endpoint: ${endpoint}`;
2538
+ diagMessage += `\n\n可能原因:`;
2539
+ diagMessage += `\n1. API Key 已过期或被删除`;
2540
+ diagMessage += `\n2. Endpoint 不可达(网络/DNS 问题)`;
2541
+ diagMessage += `\n3. CLOUDBASE_ENV_ID 与 API Key 所属环境不匹配`;
2542
+ diagMessage += `\n\n建议:检查 MCP 配置中的 CLOUDBASE_API_KEY 和 CLOUDBASE_ENV_ID 环境变量是否正确。`;
2543
+ return (0, tool_result_js_1.buildJsonToolResult)({
2544
+ ok: false,
2545
+ code: "API_KEY_AUTH_FAILED",
2546
+ message: diagMessage,
2547
+ auth_mode: "api_key",
2548
+ envId: process.env.CLOUDBASE_ENV_ID,
2549
+ endpoint,
2638
2550
  });
2639
2551
  }
2640
- catch (err) {
2641
- if (rejectCode) {
2642
- rejectCode(err);
2643
- }
2552
+ const region = server.cloudBaseOptions?.region || process.env.TCB_REGION;
2553
+ const auth = toolbox_1.AuthSupervisor.getInstance({});
2554
+ const authFlowState = await (0, auth_js_1.getAuthProgressState)();
2555
+ if (authFlowState.status === "PENDING" && authFlowState.authChallenge) {
2556
+ return (0, tool_result_js_1.buildJsonToolResult)({
2557
+ ok: true,
2558
+ code: "AUTH_PENDING",
2559
+ message: "设备码授权进行中,请在浏览器中打开 verification_uri 并输入 user_code 完成授权。",
2560
+ auth_challenge: (0, auth_js_1.buildDeviceAuthChallengePayload)(authFlowState.authChallenge),
2561
+ next_step: (0, tool_result_js_1.buildAuthNextStep)("status", {
2562
+ suggestedArgs: { action: "status" },
2563
+ }),
2564
+ });
2644
2565
  }
2566
+ // 1. 如果已经有登录态,直接返回 AUTH_READY
2645
2567
  try {
2646
- await codeReady;
2568
+ const existingLoginState = await (0, auth_js_1.peekLoginState)();
2569
+ if (existingLoginState) {
2570
+ const envPreparation = await prepareAuthEnvironment({
2571
+ server,
2572
+ cloudBaseOptions,
2573
+ loginState: existingLoginState,
2574
+ });
2575
+ return (0, tool_result_js_1.buildJsonToolResult)({
2576
+ ok: true,
2577
+ code: "AUTH_READY",
2578
+ message: envPreparation.message,
2579
+ auth_challenge: authChallenge(),
2580
+ ...buildAuthEnvSetupPayload(envPreparation),
2581
+ next_step: envPreparation.nextStep,
2582
+ });
2583
+ }
2647
2584
  }
2648
- catch (err) {
2649
- const message = err instanceof Error ? err.message : String(err ?? "unknown error");
2585
+ catch {
2586
+ // 忽略 getLoginState 错误,继续尝试发起登录
2587
+ }
2588
+ const validationError = (0, auth_js_1.getAuthConfigValidationError)(resolvedAuthOptions);
2589
+ if (validationError) {
2650
2590
  return (0, tool_result_js_1.buildJsonToolResult)({
2651
2591
  ok: false,
2652
- code: "AUTH_REQUIRED",
2653
- message: `设备码登录初始化失败: ${message}`,
2592
+ code: "INVALID_ARGS",
2593
+ message: validationError,
2594
+ auth_config: authConfigSummary,
2654
2595
  next_step: (0, tool_result_js_1.buildAuthNextStep)("start_auth", {
2655
2596
  suggestedArgs: { action: "start_auth", authMode: "device" },
2656
2597
  }),
2657
2598
  });
2658
2599
  }
2659
- if (!deviceAuthInfo) {
2600
+ // 2. 设备码模式:监听到 device code 即返回 AUTH_PENDING,后续由 toolbox 异步轮询并更新本地 credential
2601
+ const effectiveMode = resolvedAuthOptions.authMode;
2602
+ if (effectiveMode === "device") {
2603
+ let resolveCode;
2604
+ let rejectCode;
2605
+ const codeReady = new Promise((resolve, reject) => {
2606
+ resolveCode = resolve;
2607
+ rejectCode = reject;
2608
+ });
2609
+ const deviceOnCode = (info) => {
2610
+ onDeviceCode(info);
2611
+ if (resolveCode) {
2612
+ resolveCode();
2613
+ }
2614
+ };
2615
+ try {
2616
+ // 启动 Device Flow,全流程由 toolbox 负责轮询和写入 credential,这里不等待完成
2617
+ auth
2618
+ .loginByWebAuth({
2619
+ flow: "device",
2620
+ ...(resolvedAuthOptions.clientId
2621
+ ? { client_id: resolvedAuthOptions.clientId }
2622
+ : {}),
2623
+ ...(resolvedAuthOptions.oauthEndpoint
2624
+ ? { getOAuthEndpoint: () => resolvedAuthOptions.oauthEndpoint }
2625
+ : {}),
2626
+ ...(resolvedAuthOptions.oauthCustom
2627
+ ? { custom: true }
2628
+ : {}),
2629
+ onDeviceCode: deviceOnCode,
2630
+ })
2631
+ .then(() => {
2632
+ (0, auth_js_1.resolveAuthProgressState)();
2633
+ })
2634
+ .catch((err) => {
2635
+ (0, auth_js_1.rejectAuthProgressState)(err);
2636
+ // 如果在拿到 device code 之前就失败,则唤醒当前调用并返回错误
2637
+ if (!deviceAuthInfo && rejectCode) {
2638
+ rejectCode(err);
2639
+ }
2640
+ });
2641
+ }
2642
+ catch (err) {
2643
+ if (rejectCode) {
2644
+ rejectCode(err);
2645
+ }
2646
+ }
2647
+ try {
2648
+ await codeReady;
2649
+ }
2650
+ catch (err) {
2651
+ const message = err instanceof Error ? err.message : String(err ?? "unknown error");
2652
+ return (0, tool_result_js_1.buildJsonToolResult)({
2653
+ ok: false,
2654
+ code: "AUTH_REQUIRED",
2655
+ message: `设备码登录初始化失败: ${message}`,
2656
+ next_step: (0, tool_result_js_1.buildAuthNextStep)("start_auth", {
2657
+ suggestedArgs: { action: "start_auth", authMode: "device" },
2658
+ }),
2659
+ });
2660
+ }
2661
+ if (!deviceAuthInfo) {
2662
+ return (0, tool_result_js_1.buildJsonToolResult)({
2663
+ ok: false,
2664
+ code: "AUTH_REQUIRED",
2665
+ message: "未获取到设备码信息,请重试设备码登录",
2666
+ next_step: (0, tool_result_js_1.buildAuthNextStep)("start_auth", {
2667
+ suggestedArgs: { action: "start_auth", authMode: "device" },
2668
+ }),
2669
+ });
2670
+ }
2671
+ const envCandidates = await fetchAvailableEnvCandidates(cloudBaseOptions, server);
2672
+ return (0, tool_result_js_1.buildJsonToolResult)({
2673
+ ok: true,
2674
+ code: "AUTH_PENDING",
2675
+ message: "已发起设备码登录,请在浏览器中打开 verification_uri 并输入 user_code 完成授权。授权完成后请再次调用 auth(action=\"status\")。",
2676
+ auth_challenge: authChallenge(),
2677
+ ...buildEnvCandidatePayload(envCandidates),
2678
+ next_step: (0, tool_result_js_1.buildAuthNextStep)("status", {
2679
+ suggestedArgs: { action: "status" },
2680
+ }),
2681
+ });
2682
+ }
2683
+ // 3. 非 Device Flow(显式 web 模式)仍然使用 getLoginState 阻塞等待
2684
+ const loginState = await (0, auth_js_1.ensureLogin)({
2685
+ region,
2686
+ authMode: effectiveMode,
2687
+ clientId: resolvedAuthOptions.clientId,
2688
+ oauthEndpoint: resolvedAuthOptions.oauthEndpoint,
2689
+ oauthCustom: resolvedAuthOptions.oauthCustom,
2690
+ });
2691
+ if (!loginState) {
2660
2692
  return (0, tool_result_js_1.buildJsonToolResult)({
2661
2693
  ok: false,
2662
2694
  code: "AUTH_REQUIRED",
2663
- message: "未获取到设备码信息,请重试设备码登录",
2695
+ message: "未获取到登录态,请先完成认证",
2664
2696
  next_step: (0, tool_result_js_1.buildAuthNextStep)("start_auth", {
2665
- suggestedArgs: { action: "start_auth", authMode: "device" },
2697
+ suggestedArgs: { action: "start_auth", authMode: effectiveMode },
2666
2698
  }),
2667
2699
  });
2668
2700
  }
2669
- const envCandidates = await fetchAvailableEnvCandidates(cloudBaseOptions, server);
2701
+ const envPreparation = await prepareAuthEnvironment({
2702
+ server,
2703
+ cloudBaseOptions,
2704
+ loginState,
2705
+ });
2670
2706
  return (0, tool_result_js_1.buildJsonToolResult)({
2671
2707
  ok: true,
2672
- code: "AUTH_PENDING",
2673
- message: "已发起设备码登录,请在浏览器中打开 verification_uri 并输入 user_code 完成授权。授权完成后请再次调用 auth(action=\"status\")。",
2708
+ code: "AUTH_READY",
2709
+ message: envPreparation.message,
2674
2710
  auth_challenge: authChallenge(),
2675
- ...buildEnvCandidatePayload(envCandidates),
2676
- next_step: (0, tool_result_js_1.buildAuthNextStep)("status", {
2677
- suggestedArgs: { action: "status" },
2678
- }),
2711
+ ...buildAuthEnvSetupPayload(envPreparation),
2712
+ next_step: envPreparation.nextStep,
2679
2713
  });
2680
2714
  }
2681
- // 3. 非 Device Flow(显式 web 模式)仍然使用 getLoginState 阻塞等待
2682
- const loginState = await (0, auth_js_1.ensureLogin)({
2683
- region,
2684
- authMode: effectiveMode,
2685
- clientId: resolvedAuthOptions.clientId,
2686
- oauthEndpoint: resolvedAuthOptions.oauthEndpoint,
2687
- oauthCustom: resolvedAuthOptions.oauthCustom,
2688
- });
2689
- if (!loginState) {
2690
- return (0, tool_result_js_1.buildJsonToolResult)({
2691
- ok: false,
2692
- code: "AUTH_REQUIRED",
2693
- message: "未获取到登录态,请先完成认证",
2694
- next_step: (0, tool_result_js_1.buildAuthNextStep)("start_auth", {
2695
- suggestedArgs: { action: "start_auth", authMode: effectiveMode },
2696
- }),
2697
- });
2698
- }
2699
- const envPreparation = await prepareAuthEnvironment({
2700
- server,
2701
- cloudBaseOptions,
2702
- loginState,
2703
- });
2704
- return (0, tool_result_js_1.buildJsonToolResult)({
2705
- ok: true,
2706
- code: "AUTH_READY",
2707
- message: envPreparation.message,
2708
- auth_challenge: authChallenge(),
2709
- ...buildAuthEnvSetupPayload(envPreparation),
2710
- next_step: envPreparation.nextStep,
2711
- });
2712
- }
2713
- if (action === "set_env") {
2714
- const loginState = await (0, auth_js_1.peekLoginState)();
2715
- if (!loginState) {
2716
- return (0, tool_result_js_1.buildJsonToolResult)({
2717
- ok: false,
2718
- code: "AUTH_REQUIRED",
2719
- message: isCodeBuddyIde(server)
2720
- ? "当前未登录。CodeBuddy 暂不支持在 tool 内发起认证,请在外部完成认证后再次调用 auth(action=\"status\")。"
2721
- : "当前未登录,请先执行 auth(action=\"start_auth\")。",
2722
- next_step: buildAuthRequiredNextStep(server),
2723
- });
2724
- }
2725
- const envCandidates = await fetchAvailableEnvCandidates(cloudBaseOptions, server);
2726
- if (!envId) {
2727
- return (0, tool_result_js_1.buildJsonToolResult)({
2728
- ok: false,
2729
- code: "INVALID_ARGS",
2730
- message: "action=set_env 时必须提供 envId",
2731
- ...buildEnvCandidatePayload(envCandidates),
2732
- next_step: buildSetEnvNextStep(envCandidates),
2733
- });
2734
- }
2735
- const target = envCandidates.find((item) => item.envId === envId);
2736
- if (envCandidates.length > 0 && !target) {
2715
+ if (action === "set_env") {
2716
+ const loginState = await (0, auth_js_1.peekLoginState)();
2717
+ if (!loginState) {
2718
+ return (0, tool_result_js_1.buildJsonToolResult)({
2719
+ ok: false,
2720
+ code: "AUTH_REQUIRED",
2721
+ message: isCodeBuddyIde(server)
2722
+ ? "当前未登录。CodeBuddy 暂不支持在 tool 内发起认证,请在外部完成认证后再次调用 auth(action=\"status\")。"
2723
+ : "当前未登录,请先执行 auth(action=\"start_auth\")。",
2724
+ next_step: buildAuthRequiredNextStep(server),
2725
+ });
2726
+ }
2727
+ const envCandidates = await fetchAvailableEnvCandidates(cloudBaseOptions, server);
2728
+ if (!envId) {
2729
+ return (0, tool_result_js_1.buildJsonToolResult)({
2730
+ ok: false,
2731
+ code: "INVALID_ARGS",
2732
+ message: "action=set_env 时必须提供 envId",
2733
+ ...buildEnvCandidatePayload(envCandidates),
2734
+ next_step: buildSetEnvNextStep(envCandidates),
2735
+ });
2736
+ }
2737
+ const target = envCandidates.find((item) => item.envId === envId);
2738
+ if (envCandidates.length > 0 && !target) {
2739
+ return (0, tool_result_js_1.buildJsonToolResult)({
2740
+ ok: false,
2741
+ code: "INVALID_ARGS",
2742
+ message: `未找到环境: ${envId}`,
2743
+ ...buildEnvCandidatePayload(envCandidates),
2744
+ next_step: buildSetEnvNextStep(envCandidates),
2745
+ });
2746
+ }
2747
+ await cloudbase_manager_js_1.envManager.setEnvId(envId);
2737
2748
  return (0, tool_result_js_1.buildJsonToolResult)({
2738
- ok: false,
2739
- code: "INVALID_ARGS",
2740
- message: `未找到环境: ${envId}`,
2741
- ...buildEnvCandidatePayload(envCandidates),
2742
- next_step: buildSetEnvNextStep(envCandidates),
2749
+ ok: true,
2750
+ code: "ENV_READY",
2751
+ message: `环境设置成功,当前环境: ${envId}`,
2752
+ current_env_id: envId,
2743
2753
  });
2744
2754
  }
2745
- await cloudbase_manager_js_1.envManager.setEnvId(envId);
2746
- return (0, tool_result_js_1.buildJsonToolResult)({
2747
- ok: true,
2748
- code: "ENV_READY",
2749
- message: `环境设置成功,当前环境: ${envId}`,
2750
- current_env_id: envId,
2751
- });
2752
- }
2753
- if (action === "logout") {
2754
- // API Key 模式下不允许 logout
2755
- if (process.env.CLOUDBASE_API_KEY && process.env.CLOUDBASE_ENV_ID) {
2755
+ if (action === "logout") {
2756
+ // API Key 模式下不允许 logout
2757
+ if (process.env.CLOUDBASE_API_KEY && process.env.CLOUDBASE_ENV_ID) {
2758
+ return (0, tool_result_js_1.buildJsonToolResult)({
2759
+ ok: false,
2760
+ code: "LOGOUT_NOT_ALLOWED",
2761
+ message: "当前使用 API Key 认证模式,不支持退出登录。如需切换认证方式,请移除 CLOUDBASE_API_KEY 环境变量后重启。",
2762
+ auth_mode: "api_key",
2763
+ });
2764
+ }
2765
+ if (confirm !== "yes") {
2766
+ return (0, tool_result_js_1.buildJsonToolResult)({
2767
+ ok: false,
2768
+ code: "INVALID_ARGS",
2769
+ message: "action=logout 时必须传 confirm=\"yes\"",
2770
+ next_step: (0, tool_result_js_1.buildAuthNextStep)("logout", {
2771
+ suggestedArgs: { action: "logout", confirm: "yes" },
2772
+ }),
2773
+ });
2774
+ }
2775
+ await (0, auth_js_1.logout)();
2776
+ (0, cloudbase_manager_js_1.resetCloudBaseManagerCache)();
2756
2777
  return (0, tool_result_js_1.buildJsonToolResult)({
2757
- ok: false,
2758
- code: "LOGOUT_NOT_ALLOWED",
2759
- message: "当前使用 API Key 认证模式,不支持退出登录。如需切换认证方式,请移除 CLOUDBASE_API_KEY 环境变量后重启。",
2760
- auth_mode: "api_key",
2778
+ ok: true,
2779
+ code: "LOGGED_OUT",
2780
+ message: "✅ 已退出登录",
2761
2781
  });
2762
2782
  }
2763
- if (confirm !== "yes") {
2783
+ if (action === "get_temp_credentials") {
2784
+ const loginState = (await (0, auth_js_1.peekLoginState)());
2785
+ if (!loginState) {
2786
+ return (0, tool_result_js_1.buildJsonToolResult)({
2787
+ ok: false,
2788
+ code: "AUTH_REQUIRED",
2789
+ message: "当前未登录,请先完成管理端认证后再获取临时密钥。",
2790
+ next_step: buildAuthRequiredNextStep(server),
2791
+ });
2792
+ }
2793
+ if (confirm !== "yes") {
2794
+ return (0, tool_result_js_1.buildJsonToolResult)({
2795
+ ok: false,
2796
+ code: "INVALID_ARGS",
2797
+ message: "action=get_temp_credentials 时必须显式传 confirm=\"yes\",以确认你要导出当前管理端临时密钥。",
2798
+ next_step: (0, tool_result_js_1.buildAuthNextStep)("get_temp_credentials", {
2799
+ suggestedArgs: { action: "get_temp_credentials", confirm: "yes" },
2800
+ }),
2801
+ });
2802
+ }
2803
+ if (!isTemporaryCredentialLoginState(loginState)) {
2804
+ return (0, tool_result_js_1.buildJsonToolResult)({
2805
+ ok: false,
2806
+ code: "UNSUPPORTED_CREDENTIAL_TYPE",
2807
+ message: "当前登录态不是可导出的临时密钥。仅支持通过 Web / device 登录得到的临时密钥,永久密钥登录不允许导出。",
2808
+ });
2809
+ }
2810
+ const secretId = normalizeOptionalToolString(loginState.secretId);
2811
+ const secretKey = normalizeOptionalToolString(loginState.secretKey);
2812
+ const token = normalizeOptionalToolString(loginState.token);
2813
+ if (!secretId || !secretKey || !token) {
2814
+ return (0, tool_result_js_1.buildJsonToolResult)({
2815
+ ok: false,
2816
+ code: "INTERNAL_ERROR",
2817
+ message: "当前登录态缺少完整的临时密钥字段,请重新登录后再试。",
2818
+ });
2819
+ }
2764
2820
  return (0, tool_result_js_1.buildJsonToolResult)({
2765
- ok: false,
2766
- code: "INVALID_ARGS",
2767
- message: "action=logout 时必须传 confirm=\"yes\"",
2768
- next_step: (0, tool_result_js_1.buildAuthNextStep)("logout", {
2769
- suggestedArgs: { action: "logout", confirm: "yes" },
2770
- }),
2821
+ ok: true,
2822
+ code: "TEMP_CREDENTIALS_READY",
2823
+ message: reveal
2824
+ ? "当前管理端临时密钥已准备好,请注意避免泄露。"
2825
+ : "当前管理端临时密钥已准备好,默认仅返回脱敏结果。",
2826
+ env_id: normalizeOptionalToolString(loginState.envId) ?? null,
2827
+ credentials: {
2828
+ secretId: reveal ? secretId : maskSensitiveValue(secretId),
2829
+ secretKey: reveal ? secretKey : maskSensitiveValue(secretKey),
2830
+ token: reveal ? token : maskSensitiveValue(token),
2831
+ masked: !reveal,
2832
+ },
2771
2833
  });
2772
2834
  }
2773
- await (0, auth_js_1.logout)();
2774
- (0, cloudbase_manager_js_1.resetCloudBaseManagerCache)();
2775
2835
  return (0, tool_result_js_1.buildJsonToolResult)({
2776
- ok: true,
2777
- code: "LOGGED_OUT",
2778
- message: "✅ 已退出登录",
2836
+ ok: false,
2837
+ code: "NOT_SUPPORTED",
2838
+ message: `不支持的 auth action: ${action}`,
2839
+ next_step: (0, tool_result_js_1.buildAuthNextStep)("status", {
2840
+ suggestedArgs: { action: "status" },
2841
+ }),
2779
2842
  });
2780
2843
  }
2781
- if (action === "get_temp_credentials") {
2782
- const loginState = (await (0, auth_js_1.peekLoginState)());
2783
- if (!loginState) {
2784
- return (0, tool_result_js_1.buildJsonToolResult)({
2785
- ok: false,
2786
- code: "AUTH_REQUIRED",
2787
- message: "当前未登录,请先完成管理端认证后再获取临时密钥。",
2788
- next_step: buildAuthRequiredNextStep(server),
2789
- });
2790
- }
2791
- if (confirm !== "yes") {
2792
- return (0, tool_result_js_1.buildJsonToolResult)({
2793
- ok: false,
2794
- code: "INVALID_ARGS",
2795
- message: "action=get_temp_credentials 时必须显式传 confirm=\"yes\",以确认你要导出当前管理端临时密钥。",
2796
- next_step: (0, tool_result_js_1.buildAuthNextStep)("get_temp_credentials", {
2797
- suggestedArgs: { action: "get_temp_credentials", confirm: "yes" },
2798
- }),
2799
- });
2800
- }
2801
- if (!isTemporaryCredentialLoginState(loginState)) {
2802
- return (0, tool_result_js_1.buildJsonToolResult)({
2803
- ok: false,
2804
- code: "UNSUPPORTED_CREDENTIAL_TYPE",
2805
- message: "当前登录态不是可导出的临时密钥。仅支持通过 Web / device 登录得到的临时密钥,永久密钥登录不允许导出。",
2806
- });
2807
- }
2808
- const secretId = normalizeOptionalToolString(loginState.secretId);
2809
- const secretKey = normalizeOptionalToolString(loginState.secretKey);
2810
- const token = normalizeOptionalToolString(loginState.token);
2811
- if (!secretId || !secretKey || !token) {
2812
- return (0, tool_result_js_1.buildJsonToolResult)({
2813
- ok: false,
2814
- code: "INTERNAL_ERROR",
2815
- message: "当前登录态缺少完整的临时密钥字段,请重新登录后再试。",
2816
- });
2817
- }
2844
+ catch (error) {
2845
+ const message = error instanceof Error ? error.message : String(error);
2818
2846
  return (0, tool_result_js_1.buildJsonToolResult)({
2819
- ok: true,
2820
- code: "TEMP_CREDENTIALS_READY",
2821
- message: reveal
2822
- ? "当前管理端临时密钥已准备好,请注意避免泄露。"
2823
- : "当前管理端临时密钥已准备好,默认仅返回脱敏结果。",
2824
- env_id: normalizeOptionalToolString(loginState.envId) ?? null,
2825
- credentials: {
2826
- secretId: reveal ? secretId : maskSensitiveValue(secretId),
2827
- secretKey: reveal ? secretKey : maskSensitiveValue(secretKey),
2828
- token: reveal ? token : maskSensitiveValue(token),
2829
- masked: !reveal,
2830
- },
2847
+ ok: false,
2848
+ code: "INTERNAL_ERROR",
2849
+ message: `auth 执行失败: ${message}`,
2850
+ auth_challenge: authChallenge(),
2851
+ next_step: (0, tool_result_js_1.buildAuthNextStep)("status", {
2852
+ suggestedArgs: { action: "status" },
2853
+ }),
2831
2854
  });
2832
2855
  }
2833
- return (0, tool_result_js_1.buildJsonToolResult)({
2834
- ok: false,
2835
- code: "NOT_SUPPORTED",
2836
- message: `不支持的 auth action: ${action}`,
2837
- next_step: (0, tool_result_js_1.buildAuthNextStep)("status", {
2838
- suggestedArgs: { action: "status" },
2839
- }),
2840
- });
2841
- }
2842
- catch (error) {
2843
- const message = error instanceof Error ? error.message : String(error);
2844
- return (0, tool_result_js_1.buildJsonToolResult)({
2845
- ok: false,
2846
- code: "INTERNAL_ERROR",
2847
- message: `auth 执行失败: ${message}`,
2848
- auth_challenge: authChallenge(),
2849
- next_step: (0, tool_result_js_1.buildAuthNextStep)("status", {
2850
- suggestedArgs: { action: "status" },
2851
- }),
2852
- });
2853
- }
2854
- });
2855
- // envQuery - 环境查询(合并 listEnvs + getEnvInfo + getEnvAuthDomains)
2856
- server.registerTool?.("envQuery", {
2857
- title: "CloudBase 环境查询",
2858
- description: "查询 CloudBase 环境相关信息,支持查询环境列表、指定环境详情和安全域名。(原工具名:listEnvs/getEnvInfo/getEnvAuthDomains,为兼容旧AI规则可继续使用这些名称)当 action=list 时,会按 DescribeEnvs 语义做列表/筛选,标准返回字段为 EnvId、Alias、Status、EnvType、Region、PackageId、PackageName、IsDefault,并支持通过 fields 白名单裁剪这些字段;aliasExact=true 时会按别名精确筛选,避免把前缀相近的环境误当作候选;即使传入 envId,action=list 也只返回摘要,不会返回完整资源明细或 expiry。如需查询某个已知 EnvId 对应环境的详细信息(包括资源字段和计费信息),必须使用 action=info 并传入目标环境的 envId 参数。action=info 会在可用时补充 BillingInfo(如 ExpireTime、PayMode、IsAutoRenew 等计费字段)。",
2859
- inputSchema: {
2860
- action: zod_1.z
2861
- .enum(["list", "info", "domains"])
2862
- .describe("查询类型:list=环境列表/摘要筛选(按 DescribeEnvs 语义筛选,支持通过 envId 筛选,返回 EnvId、Alias、Status、EnvType、Region、PackageId、PackageName、IsDefault,不支持 expiry),info=指定环境的详细信息(必须传入 envId,返回资源字段和计费信息),domains=安全域名列表"),
2863
- alias: zod_1.z.string().optional().describe("按环境别名筛选。action=list 时可选"),
2864
- aliasExact: zod_1.z.boolean().optional().describe("按环境别名精确筛选。action=list 时可选;与 alias 配合使用"),
2865
- envId: zod_1.z.string().optional().describe("按环境 ID 筛选。action=list 时可选(仅按 DescribeEnvs 语义做筛选,仍返回摘要);action=info 时必填(返回该环境的详细信息,包含资源字段和计费信息)。如果任务已经给出了明确的 EnvId 并要求查询详情,请直接使用 action=info + envId,而不是 action=list"),
2866
- limit: zod_1.z.number().int().positive().optional().describe("返回数量上限。action=list 时可选"),
2867
- offset: zod_1.z.number().int().min(0).optional().describe("分页偏移。action=list 时可选"),
2868
- fields: zod_1.z
2869
- .array(zod_1.z.enum(DEFAULT_ENV_FIELDS))
2870
- .optional()
2871
- .describe("返回字段白名单。仅支持 EnvId、Alias、Status、EnvType、Region、PackageId、PackageName、IsDefault。action=list 时可选"),
2872
- },
2873
- annotations: {
2874
- readOnlyHint: true,
2875
- openWorldHint: true,
2876
- category: "env",
2877
- },
2878
- }, async ({ action, alias, aliasExact, envId, limit, offset, fields, }) => {
2856
+ });
2857
+ } // end: wxide guard for auth tool
2858
+ // queryEnv - 环境查询(合并 listEnvs + getEnvInfo + getEnvAuthDomains)
2859
+ const queryEnvHandler = async ({ action, alias, aliasExact, envId, limit, offset, fields, }) => {
2879
2860
  try {
2880
2861
  let result;
2881
2862
  switch (action) {
@@ -2889,7 +2870,8 @@ function registerEnvTools(server) {
2889
2870
  // 当环境变量设置了 CLOUDBASE_ENV_ID 时(如 API Key 模式),
2890
2871
  // 避免调用 DescribeEnvs(临时密钥可能不支持该接口),
2891
2872
  // 改为通过 DescribeEnvInfo 获取单环境信息
2892
- const envIdFromEnv = process.env.CLOUDBASE_ENV_ID;
2873
+ // 注意:requestFn 模式(如微信 IDE)使用 DescribeEnvs,不走此分支
2874
+ const envIdFromEnv = !cloudBaseOptions?.requestFn && process.env.CLOUDBASE_ENV_ID;
2893
2875
  if (envIdFromEnv) {
2894
2876
  try {
2895
2877
  const envInfo = await cloudbaseList.env.describeEnvInfo({ EnvId: envIdFromEnv });
@@ -3056,61 +3038,91 @@ function registerEnvTools(server) {
3056
3038
  ],
3057
3039
  };
3058
3040
  }
3059
- });
3060
- // envDomainManagement - 环境域名管理(合并 createEnvDomain + deleteEnvDomain)
3061
- server.registerTool?.("envDomainManagement", {
3062
- title: "CloudBase 环境域名管理(安全域名 / CORS 白名单)",
3063
- description: "管理 CloudBase 环境的安全域名(安全域名 / CORS 白名单),支持添加和删除操作。(原工具名:createEnvDomain/deleteEnvDomain,为兼容旧AI规则可继续使用这些名称)当浏览器 Web 应用需要从本地 Vite / dev server 直接访问 CloudBase 资源时,应先用 envQuery(action=domains) 检查当前实际浏览器 origin 对应的 host:port 是否已在白名单中,再按该实际值添加。新增或删除后通常需要继续轮询 envQuery(action=domains) 确认状态收敛;安全域名一般约 10 分钟生效。⚠️ 重要:此工具仅用于 CORS/请求来源验证,不涉及 SSL 证书。如需绑定自定义域名供公网 HTTPS 访问,请使用 manageGateway(action=\"bindCustomDomain\")。",
3041
+ };
3042
+ // Register primary tool name (queryEnv)
3043
+ const queryEnvToolSchema = {
3044
+ title: "CloudBase 环境查询",
3045
+ description: "查询 CloudBase 环境相关信息,支持查询环境列表、指定环境详情和安全域名。(曾用名:envQuery、listEnvs、getEnvInfo、getEnvAuthDomains)当 action=list 时,会按 DescribeEnvs 语义做列表/筛选,标准返回字段为 EnvId、Alias、Status、EnvType、Region、PackageId、PackageName、IsDefault,并支持通过 fields 白名单裁剪这些字段;aliasExact=true 时会按别名精确筛选,避免把前缀相近的环境误当作候选;即使传入 envId,action=list 也只返回摘要,不会返回完整资源明细或 expiry。如需查询某个已知 EnvId 对应环境的详细信息(包括资源字段和计费信息),必须使用 action=info 并传入目标环境的 envId 参数。action=info 会在可用时补充 BillingInfo(如 ExpireTime、PayMode、IsAutoRenew 等计费字段)。",
3064
3046
  inputSchema: {
3065
3047
  action: zod_1.z
3066
- .enum(["create", "delete"])
3067
- .describe("操作类型:create=添加安全域名,delete=删除安全域名"),
3068
- domains: zod_1.z.array(zod_1.z.string()).describe("安全域名数组(格式:host:port,例如 localhost:5173 或 127.0.0.1:4173)。注意:不是自定义域名,不需要证书。"),
3048
+ .enum(["list", "info", "domains"])
3049
+ .describe("查询类型:list=环境列表/摘要筛选(按 DescribeEnvs 语义筛选,支持通过 envId 筛选,返回 EnvId、Alias、Status、EnvType、Region、PackageId、PackageName、IsDefault,不支持 expiry),info=指定环境的详细信息(必须传入 envId,返回资源字段和计费信息),domains=安全域名列表"),
3050
+ alias: zod_1.z.string().optional().describe("按环境别名筛选。action=list 时可选"),
3051
+ aliasExact: zod_1.z.boolean().optional().describe("按环境别名精确筛选。action=list 时可选;与 alias 配合使用"),
3052
+ envId: zod_1.z.string().optional().describe("按环境 ID 筛选。action=list 时可选(仅按 DescribeEnvs 语义做筛选,仍返回摘要);action=info 时必填(返回该环境的详细信息,包含资源字段和计费信息)。如果任务已经给出了明确的 EnvId 并要求查询详情,请直接使用 action=info + envId,而不是 action=list"),
3053
+ limit: zod_1.z.number().int().positive().optional().describe("返回数量上限。action=list 时可选"),
3054
+ offset: zod_1.z.number().int().min(0).optional().describe("分页偏移。action=list 时可选"),
3055
+ fields: zod_1.z
3056
+ .array(zod_1.z.enum(DEFAULT_ENV_FIELDS))
3057
+ .optional()
3058
+ .describe("返回字段白名单。仅支持 EnvId、Alias、Status、EnvType、Region、PackageId、PackageName、IsDefault。action=list 时可选"),
3069
3059
  },
3070
3060
  annotations: {
3071
- readOnlyHint: false,
3072
- destructiveHint: false, // 注意:delete操作虽然是破坏性的,但这里采用较宽松的标注
3073
- idempotentHint: false,
3061
+ readOnlyHint: true,
3074
3062
  openWorldHint: true,
3075
3063
  category: "env",
3076
3064
  },
3077
- }, async ({ action, domains, }) => {
3078
- try {
3079
- const cloudbase = await getManager();
3080
- let result;
3081
- switch (action) {
3082
- case "create":
3083
- result = await cloudbase.env.createEnvDomain(domains);
3084
- (0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
3085
- break;
3086
- case "delete":
3087
- result = await cloudbase.env.deleteEnvDomain(domains);
3088
- (0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
3089
- break;
3090
- default:
3091
- throw new Error(`不支持的操作类型: ${action}`);
3065
+ };
3066
+ server.registerTool?.("queryEnv", queryEnvToolSchema, queryEnvHandler);
3067
+ // 向后兼容:envQuery 作为 queryEnv 的别名注册
3068
+ server.registerTool?.("envQuery", queryEnvToolSchema, queryEnvHandler);
3069
+ // envDomainManagement - 环境域名管理(合并 createEnvDomain + deleteEnvDomain)
3070
+ // 微信 IDE 场景不需要域名管理
3071
+ if (server.ide !== 'wxide') {
3072
+ server.registerTool?.("envDomainManagement", {
3073
+ title: "CloudBase 环境域名管理(安全域名 / CORS 白名单)",
3074
+ description: "管理 CloudBase 环境的安全域名(安全域名 / CORS 白名单),支持添加和删除操作。(原工具名:createEnvDomain/deleteEnvDomain,为兼容旧AI规则可继续使用这些名称)当浏览器 Web 应用需要从本地 Vite / dev server 直接访问 CloudBase 资源时,应先用 queryEnv(action=domains) 检查当前实际浏览器 origin 对应的 host:port 是否已在白名单中,再按该实际值添加。新增或删除后通常需要继续轮询 queryEnv(action=domains) 确认状态收敛;安全域名一般约 10 分钟生效。⚠️ 重要:此工具仅用于 CORS/请求来源验证,不涉及 SSL 证书。如需绑定自定义域名供公网 HTTPS 访问,请使用 manageGateway(action=\"bindCustomDomain\")。",
3075
+ inputSchema: {
3076
+ action: zod_1.z
3077
+ .enum(["create", "delete"])
3078
+ .describe("操作类型:create=添加安全域名,delete=删除安全域名"),
3079
+ domains: zod_1.z.array(zod_1.z.string()).describe("安全域名数组(格式:host:port,例如 localhost:5173 或 127.0.0.1:4173)。注意:不是自定义域名,不需要证书。"),
3080
+ },
3081
+ annotations: {
3082
+ readOnlyHint: false,
3083
+ destructiveHint: false, // 注意:delete操作虽然是破坏性的,但这里采用较宽松的标注
3084
+ idempotentHint: false,
3085
+ openWorldHint: true,
3086
+ category: "env",
3087
+ },
3088
+ }, async ({ action, domains, }) => {
3089
+ try {
3090
+ const cloudbase = await getManager();
3091
+ let result;
3092
+ switch (action) {
3093
+ case "create":
3094
+ result = await cloudbase.env.createEnvDomain(domains);
3095
+ (0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
3096
+ break;
3097
+ case "delete":
3098
+ result = await cloudbase.env.deleteEnvDomain(domains);
3099
+ (0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
3100
+ break;
3101
+ default:
3102
+ throw new Error(`不支持的操作类型: ${action}`);
3103
+ }
3104
+ return (0, tool_result_js_1.buildJsonToolResult)(buildEnvDomainManagementResult({
3105
+ action,
3106
+ domains,
3107
+ result,
3108
+ }));
3092
3109
  }
3093
- return (0, tool_result_js_1.buildJsonToolResult)(buildEnvDomainManagementResult({
3094
- action,
3095
- domains,
3096
- result,
3097
- }));
3098
- }
3099
- catch (error) {
3100
- const toolPayloadResult = (0, tool_result_js_1.toolPayloadErrorToResult)(error);
3101
- if (toolPayloadResult) {
3102
- return toolPayloadResult;
3110
+ catch (error) {
3111
+ const toolPayloadResult = (0, tool_result_js_1.toolPayloadErrorToResult)(error);
3112
+ if (toolPayloadResult) {
3113
+ return toolPayloadResult;
3114
+ }
3115
+ return {
3116
+ content: [
3117
+ {
3118
+ type: "text",
3119
+ text: `域名管理操作失败: ${error instanceof Error ? error.message : String(error)}`,
3120
+ },
3121
+ ],
3122
+ };
3103
3123
  }
3104
- return {
3105
- content: [
3106
- {
3107
- type: "text",
3108
- text: `域名管理操作失败: ${error instanceof Error ? error.message : String(error)}`,
3109
- },
3110
- ],
3111
- };
3112
- }
3113
- });
3124
+ });
3125
+ } // end: wxide guard for envDomainManagement
3114
3126
  }
3115
3127
 
3116
3128
 
@@ -24985,8 +24997,9 @@ async function getDatabaseInstanceId(options) {
24985
24997
  async function getCloudBaseManager(options = {}) {
24986
24998
  const { requireEnvId = true, cloudBaseOptions, authStrategy = 'fail_fast', } = options;
24987
24999
  const hasDirectCredentials = !!(cloudBaseOptions?.secretId && cloudBaseOptions?.secretKey);
24988
- // 如果传入了完整凭据,优先使用显式 CloudBase 配置
24989
- if (cloudBaseOptions && hasDirectCredentials) {
25000
+ const hasRequestFn = !!(cloudBaseOptions?.requestFn);
25001
+ // 如果传入了完整凭据或 requestFn,优先使用显式 CloudBase 配置
25002
+ if (cloudBaseOptions && (hasDirectCredentials || hasRequestFn)) {
24990
25003
  let resolvedEnvId = cloudBaseOptions.envId;
24991
25004
  if (requireEnvId && !resolvedEnvId) {
24992
25005
  const envCandidates = await listAvailableEnvCandidates({ cloudBaseOptions });
@@ -40929,8 +40942,8 @@ function registerSQLDatabaseTools(server) {
40929
40942
  server,
40930
40943
  };
40931
40944
  server.registerTool?.(QUERY_SQL_DATABASE, {
40932
- title: "Query SQL database state or execute read-only SQL",
40933
- description: "Query SQL database information. Supports read-only SQL execution, MySQL provisioning result lookup, MySQL task status lookup, and current instance context discovery.",
40945
+ title: "查询 CloudBase MySQL 数据库状态或执行只读 SQL",
40946
+ description: "查询 CloudBase MySQL 数据库信息。支持执行只读 SQL、查询 MySQL 开通结果、查询 MySQL 任务状态,以及获取当前实例上下文信息。",
40934
40947
  inputSchema: {
40935
40948
  action: zod_1.z
40936
40949
  .enum(QUERY_ACTIONS)
@@ -40972,8 +40985,8 @@ function registerSQLDatabaseTools(server) {
40972
40985
  }
40973
40986
  });
40974
40987
  server.registerTool?.(MANAGE_SQL_DATABASE, {
40975
- title: "Manage SQL database lifecycle or execute write SQL",
40976
- description: "Manage SQL database resources. Supports MySQL provisioning, MySQL destruction, write SQL/DDL execution, and schema initialization. IMPORTANT: MySQL must be provisioned first (action=provisionMySQL with confirm=true) before any runStatement or initializeSchema call. If MySQL is not yet provisioned, the tool will return MYSQL_NOT_CREATED with a nextAction to provision first.",
40988
+ title: "管理 CloudBase MySQL 数据库生命周期或执行写入 SQL",
40989
+ description: "管理 CloudBase MySQL 数据库资源。支持开通 MySQL、销毁 MySQL、执行写入 SQL/DDL,以及初始化数据库 Schema。注意:必须先开通 MySQL(action=provisionMySQL,confirm=true)才能执行 runStatement 或 initializeSchema。若 MySQL 尚未开通,工具会返回 MYSQL_NOT_CREATED 并给出开通的 nextAction 提示。",
40977
40990
  inputSchema: {
40978
40991
  action: zod_1.z
40979
40992
  .enum(MANAGE_ACTIONS)
@@ -55763,7 +55776,7 @@ if (shouldUseConsole()) {
55763
55776
  stderrLevels: ['error', 'warn', 'info', 'debug'], // All logs go to stderr
55764
55777
  }));
55765
55778
  }
55766
- if (!(0, cloud_mode_js_1.isCloudMode)()) {
55779
+ if (!(0, cloud_mode_js_1.isCloudMode)() && process.env.CLOUDBASE_MCP_DISABLE_LOG_FILE !== 'true') {
55767
55780
  // File transport with daily rotation
55768
55781
  transports.push(new DailyRotateFile({
55769
55782
  dirname: logDir,
@@ -88853,6 +88866,7 @@ exports.MANAGE_FUNCTION_ACTIONS = [
88853
88866
  "attachLayer",
88854
88867
  "detachLayer",
88855
88868
  "updateFunctionLayers",
88869
+ "incrementalDeployFunction", // 增量部署,需通过 pluginOptions.functions 注入实现
88856
88870
  ];
88857
88871
  const VPC_SCHEMA = zod_1.z.object({
88858
88872
  vpcId: zod_1.z.string(),
@@ -89034,6 +89048,7 @@ function wrapFunctionOperationError(operation, functionName, functionRootPath, e
89034
89048
  }
89035
89049
  function registerFunctionTools(server) {
89036
89050
  const cloudBaseOptions = server.cloudBaseOptions;
89051
+ const deployOverrides = server.pluginOptions?.functions;
89037
89052
  const getManager = () => (0, cloudbase_manager_js_1.getCloudBaseManager)({ cloudBaseOptions });
89038
89053
  const buildEnvelope = (data, message, nextActions) => ({
89039
89054
  success: true,
@@ -89398,6 +89413,16 @@ function registerFunctionTools(server) {
89398
89413
  ensureActionAllowedInCloudMode(input);
89399
89414
  switch (input.action) {
89400
89415
  case "createFunction": {
89416
+ if (deployOverrides?.createFunction) {
89417
+ const result = await deployOverrides.createFunction({
89418
+ functionName: String(input.func?.name ?? input.functionName ?? ''),
89419
+ functionRootPath: input.functionRootPath ?? '',
89420
+ runtime: input.func?.runtime,
89421
+ force: input.force,
89422
+ installDependency: input.func?.installDependency,
89423
+ });
89424
+ return buildEnvelope({ action: input.action, result }, '云函数部署成功(override)');
89425
+ }
89401
89426
  if (!input.func?.name || typeof input.func.name !== "string") {
89402
89427
  throw new Error("createFunction 操作时,func.name 参数是必需的");
89403
89428
  }
@@ -89485,6 +89510,15 @@ function registerFunctionTools(server) {
89485
89510
  }, message, nextActions);
89486
89511
  }
89487
89512
  case "updateFunctionCode": {
89513
+ if (deployOverrides?.updateFunctionCode) {
89514
+ const result = await deployOverrides.updateFunctionCode({
89515
+ functionName: input.functionName ?? '',
89516
+ functionRootPath: input.functionRootPath ?? '',
89517
+ force: input.force,
89518
+ installDependency: input.func?.installDependency,
89519
+ });
89520
+ return buildEnvelope({ action: input.action, result }, '云函数代码更新成功(override)');
89521
+ }
89488
89522
  if (!input.functionName) {
89489
89523
  throw new Error("updateFunctionCode 操作时,functionName 参数是必需的");
89490
89524
  }
@@ -89818,6 +89852,19 @@ function registerFunctionTools(server) {
89818
89852
  ]);
89819
89853
  }
89820
89854
  default:
89855
+ // incrementalDeployFunction:无默认实现,必须通过 pluginOptions 注入
89856
+ if (input.action === 'incrementalDeployFunction') {
89857
+ const fn = deployOverrides?.incrementalDeployFunction;
89858
+ if (!fn) {
89859
+ throw new Error('incrementalDeployFunction 需要通过 pluginOptions.functions.incrementalDeployFunction 注入实现(仅在支持的 IDE 环境中可用)');
89860
+ }
89861
+ const result = await fn({
89862
+ functionName: input.functionName ?? '',
89863
+ functionRootPath: input.functionRootPath ?? '',
89864
+ incrementalFile: input.incrementalFile ?? '',
89865
+ });
89866
+ return buildEnvelope({ action: input.action, result }, '云函数增量部署成功');
89867
+ }
89821
89868
  throw new Error(`不支持的操作类型: ${input.action}`);
89822
89869
  }
89823
89870
  };
@@ -89890,7 +89937,7 @@ function registerFunctionTools(server) {
89890
89937
  inputSchema: {
89891
89938
  action: zod_1.z
89892
89939
  .enum(exports.MANAGE_FUNCTION_ACTIONS)
89893
- .describe("写操作类型,例如 createFunction、updateFunctionCode、invokeFunction、deleteFunction、" +
89940
+ .describe("写操作类型,例如 createFunction、updateFunctionCode、incrementalDeployFunction、invokeFunction、deleteFunction、" +
89894
89941
  "createFunctionTrigger(定时任务 / cron / timer)、deleteFunctionTrigger、attachLayer、detachLayer"),
89895
89942
  func: CREATE_FUNCTION_SCHEMA.optional().describe("createFunction 操作的函数配置"),
89896
89943
  functionRootPath: zod_1.z.string().optional().describe("创建或更新函数代码时默认推荐的本地目录方式。" +
@@ -89926,6 +89973,7 @@ function registerFunctionTools(server) {
89926
89973
  .describe("updateFunctionLayers 的目标层列表,顺序即最终顺序"),
89927
89974
  codeSecret: zod_1.z.string().optional().describe("层绑定时的代码保护密钥"),
89928
89975
  confirm: zod_1.z.boolean().optional().describe("危险操作确认开关。deleteFunction、deleteFunctionTrigger、deleteLayerVersion、detachLayer 等删除类操作需要显式传入 confirm=true"),
89976
+ incrementalFile: zod_1.z.string().optional().describe("incrementalDeployFunction 增量部署时的变更文件路径"),
89929
89977
  },
89930
89978
  annotations: {
89931
89979
  readOnlyHint: false,
@@ -102126,10 +102174,19 @@ function registerDatabase(server) {
102126
102174
  (0, databaseSQL_js_1.registerSQLDatabaseTools)(server);
102127
102175
  (0, dataModel_js_1.registerDataModelTools)(server);
102128
102176
  }
102177
+ function registerNoSQLDatabase(server) {
102178
+ const region = server.cloudBaseOptions?.region || process.env.TCB_REGION;
102179
+ if (!(0, tencent_cloud_js_1.isInternationalRegion)(region)) {
102180
+ (0, databaseNoSQL_js_1.registerDatabaseTools)(server);
102181
+ }
102182
+ }
102129
102183
  // 可用插件映射
102130
102184
  const AVAILABLE_PLUGINS = {
102131
102185
  env: { name: "env", register: env_js_1.registerEnvTools },
102132
102186
  database: { name: "database", register: registerDatabase },
102187
+ "database-nosql": { name: "database-nosql", register: registerNoSQLDatabase },
102188
+ "database-sql": { name: "database-sql", register: databaseSQL_js_1.registerSQLDatabaseTools },
102189
+ "data-model": { name: "data-model", register: dataModel_js_1.registerDataModelTools },
102133
102190
  functions: { name: "functions", register: functions_js_1.registerFunctionTools },
102134
102191
  hosting: { name: "hosting", register: hosting_js_1.registerHostingTools },
102135
102192
  storage: { name: "storage", register: storage_js_1.registerStorageTools },
@@ -102217,7 +102274,7 @@ function parseEnabledPlugins(pluginsEnabled, pluginsDisabled) {
102217
102274
  * await server.connect(transport);
102218
102275
  */
102219
102276
  async function createCloudBaseMcpServer(options) {
102220
- const { name = "cloudbase-mcp", version = "1.0.0", enableTelemetry = true, cloudBaseOptions, authOptions, cloudMode = false, ide, logger, pluginsEnabled, pluginsDisabled, } = options ?? {};
102277
+ const { name = "cloudbase-mcp", version = "1.0.0", enableTelemetry = true, cloudBaseOptions, authOptions, cloudMode = false, ide, logger, pluginsEnabled, pluginsDisabled, pluginOptions, } = options ?? {};
102221
102278
  // Enable cloud mode if specified
102222
102279
  if (cloudMode) {
102223
102280
  (0, cloud_mode_js_1.enableCloudMode)();
@@ -102232,20 +102289,31 @@ async function createCloudBaseMcpServer(options) {
102232
102289
  ...(ide === "CodeBuddy" ? { logging: {} } : {}),
102233
102290
  },
102234
102291
  });
102292
+ // 初始化 toolDefs,用于外部提取工具列表(如微信 IDE)
102293
+ server.toolDefs = [];
102235
102294
  const originalRegisterTool = server.registerTool.bind(server);
102236
- server.registerTool = ((name, meta, handler) => originalRegisterTool(name, meta, async (args) => {
102237
- try {
102238
- return await handler(args);
102239
- }
102240
- catch (error) {
102241
- if ((0, tool_result_js_1.isToolPayloadError)(error)) {
102242
- // 在结构化错误返回中注入 MCP 版本号
102243
- const payload = { ...error.payload, mcpVersion: version };
102244
- return (0, tool_result_js_1.buildJsonToolResult)(payload);
102295
+ server.registerTool = ((name, meta, handler) => {
102296
+ // 同步记录到 toolDefs
102297
+ server.toolDefs.push({
102298
+ name,
102299
+ description: meta?.description ?? meta?.title ?? '',
102300
+ inputSchema: meta?.inputSchema ?? {},
102301
+ handler,
102302
+ });
102303
+ return originalRegisterTool(name, meta, async (args) => {
102304
+ try {
102305
+ return await handler(args);
102245
102306
  }
102246
- throw error;
102247
- }
102248
- }));
102307
+ catch (error) {
102308
+ if ((0, tool_result_js_1.isToolPayloadError)(error)) {
102309
+ // 在结构化错误返回中注入 MCP 版本号
102310
+ const payload = { ...error.payload, mcpVersion: version };
102311
+ return (0, tool_result_js_1.buildJsonToolResult)(payload);
102312
+ }
102313
+ throw error;
102314
+ }
102315
+ });
102316
+ });
102249
102317
  // Only set logging handler if logging capability is declared
102250
102318
  if (ide === "CodeBuddy") {
102251
102319
  server.server.setRequestHandler(types_js_1.SetLevelRequestSchema, (request, extra) => {
@@ -102260,6 +102328,10 @@ async function createCloudBaseMcpServer(options) {
102260
102328
  if (authOptions) {
102261
102329
  server.authOptions = authOptions;
102262
102330
  }
102331
+ // Store pluginOptions in server instance for plugins to access
102332
+ if (pluginOptions) {
102333
+ server.pluginOptions = pluginOptions;
102334
+ }
102263
102335
  // Store ide in server instance for telemetry
102264
102336
  if (ide) {
102265
102337
  server.ide = ide;
@@ -117979,13 +118051,16 @@ async function resolveHostingStaticDomain(cloudbase, logger) {
117979
118051
  return undefined;
117980
118052
  }
117981
118053
  }
117982
- async function assertHostingUploadEnvironmentReady(cloudbase, cloudBaseOptions, logger) {
118054
+ // Returns the first hosting store record from DescribeStaticStore, which is
118055
+ // the authoritative source for Mini Program-sourced environments (those envs
118056
+ // do not populate StaticStorages in DescribeEnvs / getEnvInfo).
118057
+ // Throws when no valid store is found so upload can fail fast with a clear msg.
118058
+ async function getHostingStoreOrThrow(cloudbase, cloudBaseOptions, logger) {
117983
118059
  const envId = await (0, cloudbase_manager_js_1.getEnvId)(cloudBaseOptions);
117984
- const envInfo = await cloudbase.env.getEnvInfo();
117985
- (0, cloudbase_manager_js_1.logCloudBaseResult)(logger, envInfo);
117986
- const staticStorage = envInfo.EnvInfo?.StaticStorages?.[0];
117987
- if (staticStorage?.Bucket) {
117988
- return;
118060
+ const result = await callTcbHostingAction(cloudbase, 'DescribeStaticStore', { EnvId: envId }, logger);
118061
+ const hostingInfo = extractStaticStores(result);
118062
+ if (hostingInfo.length > 0 && hostingInfo[0].Bucket) {
118063
+ return hostingInfo[0];
117989
118064
  }
117990
118065
  throw new Error(`当前环境 ${envId} 未发现静态托管资源配置,无法上传文件。请先确认 MCP 已绑定到已开通静态托管的 CloudBase 环境;如需切换环境,请调用 auth(action="set_env", envId="目标环境ID") 后重试。`);
117991
118066
  }
@@ -118193,8 +118268,9 @@ function registerHostingTools(server) {
118193
118268
  throw new Error('manageHosting(action="upload") 需要提供 localPath + cloudPath,或提供 files 多文件上传列表。');
118194
118269
  }
118195
118270
  let result;
118271
+ let store;
118196
118272
  try {
118197
- await assertHostingUploadEnvironmentReady(cloudbase, cloudBaseOptions, server.logger);
118273
+ store = await getHostingStoreOrThrow(cloudbase, cloudBaseOptions, server.logger);
118198
118274
  result = await cloudbase.hosting.uploadFiles({
118199
118275
  localPath: input.localPath,
118200
118276
  cloudPath: input.cloudPath,
@@ -118206,7 +118282,11 @@ function registerHostingTools(server) {
118206
118282
  throw new Error(buildUploadErrorMessage(error, input.localPath));
118207
118283
  }
118208
118284
  (0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
118209
- const staticDomain = await resolveHostingStaticDomain(cloudbase, server.logger);
118285
+ // Prefer CdnDomain from the DescribeStaticStore result we already
118286
+ // fetched; fall back to getEnvInfo for environments that populate
118287
+ // StaticDomain there but not in DescribeStaticStore.
118288
+ const cdnFromStore = (store.CdnDomain ?? store.StaticDomain);
118289
+ const staticDomain = cdnFromStore || await resolveHostingStaticDomain(cloudbase, server.logger);
118210
118290
  const accessUrl = buildHostingAccessUrl(staticDomain, input.cloudPath, input.localPath);
118211
118291
  try {
118212
118292
  const envId = await (0, cloudbase_manager_js_1.getEnvId)(cloudBaseOptions);
@@ -135149,7 +135229,7 @@ class TelemetryReporter {
135149
135229
  const nodeVersion = process.version; // Node.js版本
135150
135230
  const arch = os_1.default.arch(); // 系统架构
135151
135231
  // 从构建时注入的版本号获取MCP版本信息
135152
- const mcpVersion = process.env.npm_package_version || "2.21.0" || 0;
135232
+ const mcpVersion = process.env.npm_package_version || "2.21.1-beta.1" || 0;
135153
135233
  return {
135154
135234
  userAgent: `${osType} ${osRelease} ${arch} ${nodeVersion} CloudBase-MCP/${mcpVersion}`,
135155
135235
  deviceId: this.deviceId,
@@ -180374,99 +180454,6 @@ async function downloadResources() {
180374
180454
  return resourceDownloadPromise;
180375
180455
  }
180376
180456
  async function registerRagTools(server) {
180377
- // 联网搜索
180378
- server.registerTool?.("searchWeb", {
180379
- title: "联网搜索",
180380
- description: "使用联网来进行信息检索,如查询最新的新闻、文章、股价、天气等。支持自然语言查询,也可以直接输入网址获取网页内容",
180381
- inputSchema: {
180382
- query: zod_1.z.string().describe("搜索关键词、问题或网址,支持自然语言"),
180383
- },
180384
- annotations: {
180385
- readOnlyHint: true,
180386
- openWorldHint: true,
180387
- category: "web",
180388
- },
180389
- }, async ({ query }) => {
180390
- try {
180391
- // 使用混元进行联网搜索
180392
- const signInRes = await fetch("https://tcb-advanced-a656fc.api.tcloudbasegateway.com/auth/v1/signin/anonymously", {
180393
- method: "POST",
180394
- headers: {
180395
- "Content-Type": "application/json",
180396
- Accept: "application/json",
180397
- "x-device-id": "cloudbase-ai-toolkit",
180398
- },
180399
- body: safeStringify({}),
180400
- });
180401
- const { access_token } = await signInRes.json();
180402
- // 调用混元API进行联网搜索
180403
- const searchRes = await fetch("https://tcb-advanced-a656fc.api.tcloudbasegateway.com/v1/ai/hunyuan-beta/openapi/v1/chat/completions", {
180404
- method: "POST",
180405
- headers: {
180406
- "Content-Type": "application/json",
180407
- Authorization: `Bearer ${access_token}`,
180408
- },
180409
- body: safeStringify({
180410
- model: "hunyuan",
180411
- messages: [
180412
- {
180413
- role: "user",
180414
- content: `你好,你将扮演一个知识库的角色,联网查询到问题的答案之后回答给我`,
180415
- },
180416
- {
180417
- role: "assistant",
180418
- content: "好的",
180419
- },
180420
- {
180421
- role: "user",
180422
- content: query,
180423
- },
180424
- ],
180425
- enable_enhancement: true,
180426
- search_info: true,
180427
- enable_speed_search: true,
180428
- force_search_enhancement: true,
180429
- }),
180430
- });
180431
- const result = await searchRes.json();
180432
- if (result.error) {
180433
- throw new Error(result.error.message || "联网搜索失败");
180434
- }
180435
- const content = result.choices?.[0]?.message?.content || "";
180436
- const searchResults = result.search_info?.search_results || [];
180437
- return {
180438
- content: [
180439
- {
180440
- type: "text",
180441
- text: safeStringify({
180442
- type: "web_search",
180443
- content: content,
180444
- search_results: searchResults.map((item) => ({
180445
- title: item.title,
180446
- url: item.url,
180447
- snippet: item.snippet,
180448
- })),
180449
- status: "success",
180450
- }),
180451
- },
180452
- ],
180453
- };
180454
- }
180455
- catch (error) {
180456
- return {
180457
- content: [
180458
- {
180459
- type: "text",
180460
- text: safeStringify({
180461
- type: "error",
180462
- message: error instanceof Error ? error.message : "联网搜索失败",
180463
- status: "error",
180464
- }),
180465
- },
180466
- ],
180467
- };
180468
- }
180469
- });
180470
180457
  let openapis = [];
180471
180458
  let skills = [];
180472
180459
  let fallbackSkillsRoot;
@@ -185849,7 +185836,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
185849
185836
  exports.CloudBaseContext = void 0;
185850
185837
  const constant_1 = __webpack_require__(40762);
185851
185838
  class CloudBaseContext {
185852
- constructor({ secretId = '', secretKey = '', token = '', proxy = '', region = '', envType = '', useInternalEndpoint = undefined, internalEndpointRegion = undefined }) {
185839
+ constructor({ secretId = '', secretKey = '', token = '', proxy = '', region = '', envType = '', useInternalEndpoint = undefined, internalEndpointRegion = undefined, requestFn = undefined }) {
185853
185840
  this.secretId = secretId;
185854
185841
  this.secretKey = secretKey;
185855
185842
  this.token = token;
@@ -185858,6 +185845,7 @@ class CloudBaseContext {
185858
185845
  this.envType = envType;
185859
185846
  this.useInternalEndpoint = useInternalEndpoint;
185860
185847
  this.internalEndpointRegion = internalEndpointRegion;
185848
+ this.requestFn = requestFn;
185861
185849
  }
185862
185850
  isInternalEndpoint() {
185863
185851
  return this.useInternalEndpoint !== undefined ? this.useInternalEndpoint : constant_1.USE_INTERNAL_ENDPOINT;
@@ -193754,7 +193742,7 @@ ${envIdSection}
193754
193742
  ## 环境信息
193755
193743
  - 操作系统: ${os_1.default.type()} ${os_1.default.release()}
193756
193744
  - Node.js版本: ${process.version}
193757
- - MCP 版本:${process.env.npm_package_version || "2.21.0" || 0}
193745
+ - MCP 版本:${process.env.npm_package_version || "2.21.1-beta.1" || 0}
193758
193746
  - 系统架构: ${os_1.default.arch()}
193759
193747
  - 时间: ${new Date().toISOString()}
193760
193748
  - 请求ID: ${requestId}
@@ -193835,7 +193823,7 @@ function createWrappedHandler(name, handler, server) {
193835
193823
  requestId: (typeof error === 'object' && error && 'requestId' in error) ? error.requestId : '',
193836
193824
  ide: server.ide || process.env.INTEGRATION_IDE || ''
193837
193825
  });
193838
- const mcpVersion = true ? "2.21.0" : 0;
193826
+ const mcpVersion = true ? "2.21.1-beta.1" : 0;
193839
193827
  const requestIdSuffix = requestId ? `\n🆔 RequestId: ${requestId}` : '';
193840
193828
  const enhancedErrorMessage = `${errorMessage}${requestIdSuffix}\n\n📦 CloudBase MCP v${mcpVersion}\n🔗 遇到问题?请复制以下链接到浏览器打开\n即可自动携带错误详情快速创建 GitHub Issue:\n${issueLink}`;
193841
193829
  // 创建新的错误对象,保持原有的错误类型但更新消息
@@ -203264,6 +203252,13 @@ async function callNoSqlContentApi(options) {
203264
203252
  instanceIdSource: "envId",
203265
203253
  requestId: result?.RequestId,
203266
203254
  });
203255
+ // 检查 API 层返回的业务错误(如集合不存在)并抛出
203256
+ if (result?.Error) {
203257
+ const err = new Error(`${result.Error.Code}: ${result.Error.Message}`);
203258
+ err.code = result.Error.Code;
203259
+ err.requestId = result.RequestId;
203260
+ throw err;
203261
+ }
203267
203262
  return result;
203268
203263
  }
203269
203264
  catch (error) {
@@ -203277,7 +203272,7 @@ async function callNoSqlContentApi(options) {
203277
203272
  throw error;
203278
203273
  }
203279
203274
  }
203280
- async function waitForCollectionReady({ cloudbase, collectionName, logger, timeoutMs = COLLECTION_READY_TIMEOUT_MS, pollIntervalMs = COLLECTION_READY_POLL_INTERVAL_MS, }) {
203275
+ async function waitForCollectionReady({ cloudbase, collectionName, logger, cloudBaseOptions, timeoutMs = COLLECTION_READY_TIMEOUT_MS, pollIntervalMs = COLLECTION_READY_POLL_INTERVAL_MS, }) {
203281
203276
  const startedAt = Date.now();
203282
203277
  const deadline = startedAt + timeoutMs;
203283
203278
  let lastError;
@@ -203291,17 +203286,40 @@ async function waitForCollectionReady({ cloudbase, collectionName, logger, timeo
203291
203286
  });
203292
203287
  while (Date.now() <= deadline) {
203293
203288
  try {
203294
- // 直接用 commonService 调用 DescribeTable 检查集合是否存在,避免 SDK lazyInit → DescribeEnvs
203295
- const envId = await (0, cloudbase_manager_js_1.getEnvId)();
203296
- const result = await cloudbase.commonService("tcb", "2018-06-08").call({
203297
- Action: "DescribeTable",
203289
+ // 用 PutItem 探测集合是否真正就绪(DescribeTable 可能误报),插入一个空占位文档
203290
+ // 如果成功,立即删除该文档;如果仍 ResourceNotFound,继续等待
203291
+ const envId = await (0, cloudbase_manager_js_1.getEnvId)(cloudBaseOptions);
203292
+ const probeDoc = JSON.stringify({ _readyProbe: true, _ts: Date.now() });
203293
+ const probeResult = await cloudbase.commonService("tcb", "2018-06-08").call({
203294
+ Action: "PutItem",
203298
203295
  Param: {
203299
203296
  EnvId: envId,
203300
203297
  TableName: collectionName,
203298
+ MgoDocs: [probeDoc],
203301
203299
  },
203302
203300
  });
203303
- (0, cloudbase_manager_js_1.logCloudBaseResult)(logger, result);
203304
- // DescribeTable 成功返回即表示集合存在
203301
+ (0, cloudbase_manager_js_1.logCloudBaseResult)(logger, probeResult);
203302
+ if (probeResult?.Error) {
203303
+ // 集合还未就绪,继续轮询
203304
+ throw new Error(probeResult.Error.Message);
203305
+ }
203306
+ // 集合就绪,清理探测文档
203307
+ if (Array.isArray(probeResult?.InsertedIds) && probeResult.InsertedIds.length > 0) {
203308
+ try {
203309
+ await cloudbase.commonService("tcb", "2018-06-08").call({
203310
+ Action: "DeleteItem",
203311
+ Param: {
203312
+ EnvId: envId,
203313
+ TableName: collectionName,
203314
+ MgoQuery: JSON.stringify({ _readyProbe: true }),
203315
+ MgoIsMulti: true,
203316
+ },
203317
+ });
203318
+ }
203319
+ catch {
203320
+ // 清理失败不影响主流程
203321
+ }
203322
+ }
203305
203323
  logger?.({
203306
203324
  type: "toolInfo",
203307
203325
  toolName: "writeNoSqlDatabaseStructure",
@@ -203340,8 +203358,8 @@ function registerDatabaseTools(server) {
203340
203358
  const getManager = () => (0, cloudbase_manager_js_1.getCloudBaseManager)({ cloudBaseOptions });
203341
203359
  // readNoSqlDatabaseStructure
203342
203360
  server.registerTool?.("readNoSqlDatabaseStructure", {
203343
- title: "读取 NoSQL 数据库结构",
203344
- description: "读取 NoSQL 数据库集合与索引结构,支持列出集合、查看集合详情、列出索引以及检查索引是否存在。本工具为服务端管理工具,用于管理端查询数据库结构,不用于编写客户端代码。",
203361
+ title: "读取 CloudBase NoSQL 数据库结构",
203362
+ description: "读取 CloudBase NoSQL 数据库集合与索引结构,支持列出集合、查看集合详情、列出索引以及检查索引是否存在。本工具为服务端管理工具,用于管理端查询数据库结构,不用于编写客户端代码。",
203345
203363
  inputSchema: {
203346
203364
  action: zod_1.z.enum([
203347
203365
  "listCollections",
@@ -203528,8 +203546,8 @@ checkIndex: 检查指定索引是否存在`),
203528
203546
  });
203529
203547
  // writeNoSqlDatabaseStructure
203530
203548
  server.registerTool?.("writeNoSqlDatabaseStructure", {
203531
- title: "创建并管理 NoSQL 数据库集合",
203532
- description: "创建、删除和管理 NoSQL 数据库集合(collection)。支持创建新集合、删除现有集合,以及通过 updateCollection 的 updateOptions.CreateIndexes / updateOptions.DropIndexes 添加索引和删除索引。当需要新建集合时,使用 action=createCollection。本工具为服务端管理工具,用于管理端操作集合和索引结构,不用于编写客户端代码。",
203549
+ title: "创建并管理 CloudBase NoSQL 数据库集合",
203550
+ description: "创建、删除和管理 CloudBase NoSQL 数据库集合(collection)。支持创建新集合、删除现有集合,以及通过 updateCollection 的 updateOptions.CreateIndexes / updateOptions.DropIndexes 添加索引和删除索引。当需要新建集合时,使用 action=createCollection。本工具为服务端管理工具,用于管理端操作集合和索引结构,不用于编写客户端代码。",
203533
203551
  inputSchema: {
203534
203552
  action: zod_1.z.enum([
203535
203553
  "createCollection",
@@ -203589,8 +203607,14 @@ deleteCollection: 删除集合`),
203589
203607
  Action: "DescribeTable",
203590
203608
  Param: { EnvId: envId, TableName: collectionName },
203591
203609
  });
203592
- collectionExists = true;
203593
- existsRequestId = descResult?.RequestId ?? "";
203610
+ if (descResult?.Error) {
203611
+ // 集合不存在(ResourceNotFound)或其他错误,继续创建
203612
+ existsRequestId = descResult.RequestId ?? "";
203613
+ }
203614
+ else {
203615
+ collectionExists = true;
203616
+ existsRequestId = descResult?.RequestId ?? "";
203617
+ }
203594
203618
  }
203595
203619
  catch (e) {
203596
203620
  existsRequestId = e?.requestId ?? "";
@@ -203623,6 +203647,7 @@ deleteCollection: 删除集合`),
203623
203647
  cloudbase,
203624
203648
  collectionName,
203625
203649
  logger: server.logger,
203650
+ cloudBaseOptions: server.cloudBaseOptions,
203626
203651
  });
203627
203652
  return {
203628
203653
  content: [
@@ -203705,8 +203730,8 @@ deleteCollection: 删除集合`),
203705
203730
  });
203706
203731
  // readNoSqlDatabaseContent
203707
203732
  server.registerTool?.("readNoSqlDatabaseContent", {
203708
- title: "查询并获取 NoSQL 数据库数据记录",
203709
- description: "查询并获取 NoSQL 数据库数据记录。⚠️ 本工具为服务端管理工具,用于管理端/运维端查询。当任务要求编写客户端应用代码时(例如「用 JS SDK 读取数据」),不应使用本工具,而应在项目代码中编写 @cloudbase/js-sdk 客户端代码(如 db.collection().where().get())。",
203733
+ title: "查询并获取 CloudBase NoSQL 数据库数据记录",
203734
+ description: "查询 CloudBase NoSQL 数据库中的数据记录。支持按条件筛选、分页、排序,适用于管理端数据查询与运维。",
203710
203735
  inputSchema: {
203711
203736
  collectionName: zod_1.z.string().describe("集合名称"),
203712
203737
  instanceId: zod_1.z
@@ -203792,8 +203817,10 @@ deleteCollection: 删除集合`),
203792
203817
  });
203793
203818
  // writeNoSqlDatabaseContent
203794
203819
  server.registerTool?.("writeNoSqlDatabaseContent", {
203795
- title: "修改 NoSQL 数据库数据记录",
203796
- description: "修改 NoSQL 数据库数据记录。⚠️ 本工具为服务端管理工具,用于管理端/运维端操作(如后台脚本、数据迁移、批量修改)。当任务要求编写客户端应用代码时(例如「用 JS SDK 登录并插入数据」、「在前端读写数据库」),不应使用本工具,而应在项目代码中编写 @cloudbase/js-sdk 客户端代码(如 app.database().collection().add()、db.collection().where().get() 等)。可按 MongoDB updateOne/updateMany 的心智模型理解:部分更新必须使用 `$set`、`$inc`、`$push` 等更新操作符;如果直接传「字段到值的普通对象」这类内容,底层会把它当作替换内容,存在覆盖整条文档的风险。⚠️ 嵌套对象部分更新务必使用点号路径:要更新 `shipping.city`,应传 `$set: {\"shipping.city\": \"guangzhou\"}`,绝不能传 `$set: {\"shipping\": {\"city\": \"guangzhou\"}}`(后者会丢失 shipping 下的其他字段)。若集合中的角色/档案文档会在前端通过 `db.collection(...).doc(uid)` 读取,请确保文档 `_id` 就是该 `uid`;不要用按 `uid` 条件查询再配合 `upsert=true` 的方式去更新 `users` / `profiles`,否则经常会生成一个不同的 `_id`,导致后续 `doc(uid)` 读取命中不到。",
203820
+ title: "修改 CloudBase NoSQL 数据库数据记录",
203821
+ description: "修改 CloudBase NoSQL 数据库中的数据记录。支持插入、更新(含 $set/$inc/$push 等操作符)、删除、upsert 等操作,适用于管理端数据写入与运维。" +
203822
+ "⚠️ 服务端写入不含 _openid:若集合依赖客户端 SDK(@cloudbase/js-sdk 或微信小程序 wx.cloud.database())的行级安全规则(如 doc._openid == auth.openid),服务端写入时需手动补充 _openid 字段,否则客户端将无法读取到该数据。" +
203823
+ "⚠️ 部分更新嵌套字段须使用点号路径,如 `$set: {\"shipping.city\": \"guangzhou\"}`,直接传嵌套对象会覆盖整个字段。",
203797
203824
  inputSchema: {
203798
203825
  action: zod_1.z
203799
203826
  .enum(["insert", "update", "delete"])
@@ -209808,7 +209835,7 @@ function registerSetupTools(server) {
209808
209835
  server.registerTool("downloadTemplate", {
209809
209836
  title: "下载项目模板",
209810
209837
  description: `自动下载并部署CloudBase项目模板。
209811
- **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.21.0" : 0}),便于后续维护和版本追踪\n- 下载 rules 模板时,如果项目中已存在 README.md 文件,系统会自动保护该文件不被覆盖(除非设置 overwrite=true)`,
209838
+ **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.21.1-beta.1" : 0}),便于后续维护和版本追踪\n- 下载 rules 模板时,如果项目中已存在 README.md 文件,系统会自动保护该文件不被覆盖(除非设置 overwrite=true)`,
209812
209839
  inputSchema: {
209813
209840
  template: zod_1.z
209814
209841
  .enum(["react", "vue", "miniprogram", "uniapp", "rules"])
@@ -219995,12 +220022,13 @@ function getDate(timestamp) {
219995
220022
  }
219996
220023
  class CloudService {
219997
220024
  /* eslint-disable-next-line */
219998
- constructor(context, service, version, baseParams) {
220025
+ constructor(context, service, version, baseParams, requestFn) {
219999
220026
  this.service = service;
220000
220027
  this.version = version;
220001
220028
  this.timeout = 60000;
220002
220029
  this.baseParams = baseParams || {};
220003
220030
  this.cloudBaseContext = context;
220031
+ this.requestFn = requestFn !== null && requestFn !== void 0 ? requestFn : context.requestFn;
220004
220032
  }
220005
220033
  get baseUrl() {
220006
220034
  const internalEndpoint = this.cloudBaseContext.isInternalEndpoint();
@@ -220032,8 +220060,31 @@ class CloudService {
220032
220060
  }
220033
220061
  }
220034
220062
  async request(action, data = {}, method = 'POST') {
220063
+ var _a;
220035
220064
  this.action = action;
220036
220065
  this.data = deepRemoveVoid(Object.assign(Object.assign({}, data), this.baseParams));
220066
+ // 如果注入了 requestFn,直接委托,跳过 TC3 签名逻辑
220067
+ if (this.requestFn) {
220068
+ try {
220069
+ const result = await this.requestFn({
220070
+ service: this.service,
220071
+ action,
220072
+ version: this.version,
220073
+ region: (_a = this.cloudBaseContext.region) !== null && _a !== void 0 ? _a : '',
220074
+ payload: this.data,
220075
+ });
220076
+ return result;
220077
+ }
220078
+ catch (e) {
220079
+ if (e.name === 'CloudBaseError') {
220080
+ throw e;
220081
+ }
220082
+ throw new error_1.CloudBaseError(e.message, {
220083
+ action,
220084
+ code: e.code
220085
+ });
220086
+ }
220087
+ }
220037
220088
  this.method = method;
220038
220089
  this.url = this.baseUrl;
220039
220090
  let { secretId, secretKey, token } = this.cloudBaseContext;
@@ -244772,8 +244823,8 @@ function registerLogTools(server) {
244772
244823
  const cloudBaseOptions = server.cloudBaseOptions;
244773
244824
  const getManager = () => (0, cloudbase_manager_js_1.getCloudBaseManager)({ cloudBaseOptions });
244774
244825
  server.registerTool?.("queryLogs", {
244775
- title: "查询日志服务",
244776
- description: "日志域统一只读入口。支持检查日志服务状态并搜索 CLS 日志。" +
244826
+ title: "查询 CloudBase 日志服务",
244827
+ description: "CloudBase 日志域统一只读入口。支持检查日志服务状态并搜索 CLS 日志。" +
244777
244828
  "\n\n**重要区分**:" +
244778
244829
  "\n- 查询云函数日志:使用 `queryFunctions(action=\"listFunctionLogs\", functionName=\"xxx\")`" +
244779
244830
  "\n- 查询 CLS 日志(跨服务日志聚合):使用本工具 `queryLogs(action=\"searchLogs\")`" +
@@ -250850,6 +250901,7 @@ async function resolveStoragePublicAccess(params) {
250850
250901
  function registerStorageTools(server) {
250851
250902
  // 获取 cloudBaseOptions,如果没有则为 undefined
250852
250903
  const cloudBaseOptions = server.cloudBaseOptions;
250904
+ const storageOverrides = server.pluginOptions?.storage;
250853
250905
  // 创建闭包函数来获取 CloudBase Manager
250854
250906
  const getManager = () => (0, cloudbase_manager_js_1.getCloudBaseManager)({ cloudBaseOptions });
250855
250907
  // Tool 1: queryStorage - 查询存储信息(只读操作)
@@ -250871,7 +250923,14 @@ function registerStorageTools(server) {
250871
250923
  const storageService = manager.storage;
250872
250924
  switch (input.action) {
250873
250925
  case 'list': {
250874
- const result = await storageService.listDirectoryFiles(input.cloudPath);
250926
+ let files;
250927
+ if (storageOverrides?.listFiles) {
250928
+ files = await storageOverrides.listFiles({ cloudPath: input.cloudPath });
250929
+ }
250930
+ else {
250931
+ const result = await storageService.listDirectoryFiles(input.cloudPath);
250932
+ files = result || [];
250933
+ }
250875
250934
  return {
250876
250935
  content: [
250877
250936
  {
@@ -250881,17 +250940,23 @@ function registerStorageTools(server) {
250881
250940
  data: {
250882
250941
  action: 'list',
250883
250942
  cloudPath: input.cloudPath,
250884
- files: result || [],
250885
- totalCount: result?.length || 0
250943
+ files,
250944
+ totalCount: files.length
250886
250945
  },
250887
- message: `Successfully listed ${result?.length || 0} files in directory '${input.cloudPath}'`
250946
+ message: `Successfully listed ${files.length} files in directory '${input.cloudPath}'`
250888
250947
  }, null, 2)
250889
250948
  }
250890
250949
  ]
250891
250950
  };
250892
250951
  }
250893
250952
  case 'info': {
250894
- const result = await storageService.getFileInfo(input.cloudPath);
250953
+ let fileInfo;
250954
+ if (storageOverrides?.getFileInfo) {
250955
+ fileInfo = await storageOverrides.getFileInfo({ cloudPath: input.cloudPath });
250956
+ }
250957
+ else {
250958
+ fileInfo = await storageService.getFileInfo(input.cloudPath);
250959
+ }
250895
250960
  return {
250896
250961
  content: [
250897
250962
  {
@@ -250901,7 +250966,7 @@ function registerStorageTools(server) {
250901
250966
  data: {
250902
250967
  action: 'info',
250903
250968
  cloudPath: input.cloudPath,
250904
- fileInfo: result
250969
+ fileInfo
250905
250970
  },
250906
250971
  message: `Successfully retrieved file info for '${input.cloudPath}'`
250907
250972
  }, null, 2)
@@ -250945,10 +251010,15 @@ function registerStorageTools(server) {
250945
251010
  const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), STORAGE_READ_TEMP_PREFIX));
250946
251011
  const localPath = path.join(tempDir, getStorageTempFileName(input.cloudPath));
250947
251012
  try {
250948
- await storageService.downloadFile({
250949
- cloudPath: input.cloudPath,
250950
- localPath
250951
- });
251013
+ if (storageOverrides?.downloadFile) {
251014
+ await storageOverrides.downloadFile({ cloudPath: input.cloudPath, localPath });
251015
+ }
251016
+ else {
251017
+ await storageService.downloadFile({
251018
+ cloudPath: input.cloudPath,
251019
+ localPath
251020
+ });
251021
+ }
250952
251022
  const buffer = await fs.readFile(localPath);
250953
251023
  const decoded = decodeInlineTextContent(buffer);
250954
251024
  return {
@@ -251003,22 +251073,32 @@ function registerStorageTools(server) {
251003
251073
  switch (input.action) {
251004
251074
  case 'upload': {
251005
251075
  if (input.isDirectory) {
251006
- await storageService.uploadDirectory({
251007
- localPath: input.localPath,
251008
- cloudPath: input.cloudPath,
251009
- onProgress: (progressData) => {
251010
- console.log("Upload directory progress:", progressData);
251011
- }
251012
- });
251076
+ if (storageOverrides?.uploadDirectory) {
251077
+ await storageOverrides.uploadDirectory({ localPath: input.localPath, cloudPath: input.cloudPath });
251078
+ }
251079
+ else {
251080
+ await storageService.uploadDirectory({
251081
+ localPath: input.localPath,
251082
+ cloudPath: input.cloudPath,
251083
+ onProgress: (progressData) => {
251084
+ console.log("Upload directory progress:", progressData);
251085
+ }
251086
+ });
251087
+ }
251013
251088
  }
251014
251089
  else {
251015
- await storageService.uploadFile({
251016
- localPath: input.localPath,
251017
- cloudPath: input.cloudPath,
251018
- onProgress: (progressData) => {
251019
- console.log("Upload file progress:", progressData);
251020
- }
251021
- });
251090
+ if (storageOverrides?.uploadFile) {
251091
+ await storageOverrides.uploadFile({ localPath: input.localPath, cloudPath: input.cloudPath });
251092
+ }
251093
+ else {
251094
+ await storageService.uploadFile({
251095
+ localPath: input.localPath,
251096
+ cloudPath: input.cloudPath,
251097
+ onProgress: (progressData) => {
251098
+ console.log("Upload file progress:", progressData);
251099
+ }
251100
+ });
251101
+ }
251022
251102
  }
251023
251103
  const fileUrls = await storageService.getTemporaryUrl([{
251024
251104
  cloudPath: input.cloudPath,
@@ -251054,16 +251134,26 @@ function registerStorageTools(server) {
251054
251134
  }
251055
251135
  case 'download': {
251056
251136
  if (input.isDirectory) {
251057
- await storageService.downloadDirectory({
251058
- cloudPath: input.cloudPath,
251059
- localPath: input.localPath
251060
- });
251137
+ if (storageOverrides?.downloadDirectory) {
251138
+ await storageOverrides.downloadDirectory({ cloudPath: input.cloudPath, localPath: input.localPath });
251139
+ }
251140
+ else {
251141
+ await storageService.downloadDirectory({
251142
+ cloudPath: input.cloudPath,
251143
+ localPath: input.localPath
251144
+ });
251145
+ }
251061
251146
  }
251062
251147
  else {
251063
- await storageService.downloadFile({
251064
- cloudPath: input.cloudPath,
251065
- localPath: input.localPath
251066
- });
251148
+ if (storageOverrides?.downloadFile) {
251149
+ await storageOverrides.downloadFile({ cloudPath: input.cloudPath, localPath: input.localPath });
251150
+ }
251151
+ else {
251152
+ await storageService.downloadFile({
251153
+ cloudPath: input.cloudPath,
251154
+ localPath: input.localPath
251155
+ });
251156
+ }
251067
251157
  }
251068
251158
  return {
251069
251159
  content: [
@@ -251099,10 +251189,20 @@ function registerStorageTools(server) {
251099
251189
  };
251100
251190
  }
251101
251191
  if (input.isDirectory) {
251102
- await storageService.deleteDirectory(input.cloudPath);
251192
+ if (storageOverrides?.deleteDirectory) {
251193
+ await storageOverrides.deleteDirectory({ cloudPath: input.cloudPath });
251194
+ }
251195
+ else {
251196
+ await storageService.deleteDirectory(input.cloudPath);
251197
+ }
251103
251198
  }
251104
251199
  else {
251105
- await storageService.deleteFile([input.cloudPath]);
251200
+ if (storageOverrides?.deleteFiles) {
251201
+ await storageOverrides.deleteFiles({ cloudPaths: [input.cloudPath] });
251202
+ }
251203
+ else {
251204
+ await storageService.deleteFile([input.cloudPath]);
251205
+ }
251106
251206
  }
251107
251207
  return {
251108
251208
  content: [
@@ -259387,9 +259487,9 @@ class CloudBase {
259387
259487
  }
259388
259488
  constructor(config = {}) {
259389
259489
  this.cloudBaseConfig = {};
259390
- let { secretId, secretKey, token, envId, proxy, region, envType, useInternalEndpoint, internalEndpointRegion } = config;
259391
- // config 中传入的 secretId secretkey 必须同时存在
259392
- if ((secretId && !secretKey) || (!secretId && secretKey)) {
259490
+ let { secretId, secretKey, token, envId, proxy, region, envType, useInternalEndpoint, internalEndpointRegion, requestFn } = config;
259491
+ // config 中传入的 secretId secretkey 必须同时存在(有 requestFn 时可以不传)
259492
+ if (!requestFn && ((secretId && !secretKey) || (!secretId && secretKey))) {
259393
259493
  throw new Error('secretId and secretKey must be a pair');
259394
259494
  }
259395
259495
  this.cloudBaseConfig = {
@@ -259402,6 +259502,7 @@ class CloudBase {
259402
259502
  region,
259403
259503
  useInternalEndpoint,
259404
259504
  internalEndpointRegion,
259505
+ requestFn,
259405
259506
  };
259406
259507
  // 初始化 context
259407
259508
  this.context = new context_1.CloudBaseContext(this.cloudBaseConfig);