@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.js CHANGED
@@ -183,17 +183,17 @@ function buildEnvDomainManagementResult(params) {
183
183
  operation: action,
184
184
  targetDomains: domains,
185
185
  asyncState: "PENDING",
186
- message: '安全域名已提交添加请求。该变更通常需要约 10 分钟传播,请继续轮询 envQuery(action="domains"),直到目标域名状态为 ENABLE。',
186
+ message: '安全域名已提交添加请求。该变更通常需要约 10 分钟传播,请继续轮询 queryEnv(action="domains"),直到目标域名状态为 ENABLE。',
187
187
  propagation: {
188
188
  requiresPolling: true,
189
- pollTool: "envQuery",
189
+ pollTool: "queryEnv",
190
190
  pollAction: "domains",
191
191
  pollIntervalSuggestionSeconds: 10,
192
192
  timeoutSuggestionSeconds: 600,
193
- successCondition: '目标域名出现在 envQuery(action="domains") 返回中,且 Status 为 ENABLE。',
193
+ successCondition: '目标域名出现在 queryEnv(action="domains") 返回中,且 Status 为 ENABLE。',
194
194
  },
195
195
  next_step: {
196
- tool: "envQuery",
196
+ tool: "queryEnv",
197
197
  action: "domains",
198
198
  suggested_args: {
199
199
  action: "domains",
@@ -208,17 +208,17 @@ function buildEnvDomainManagementResult(params) {
208
208
  operation: action,
209
209
  targetDomains: domains,
210
210
  asyncState: "PENDING",
211
- message: '安全域名已提交删除请求。该变更可能需要数分钟传播,请继续轮询 envQuery(action="domains"),直到目标域名不再出现。',
211
+ message: '安全域名已提交删除请求。该变更可能需要数分钟传播,请继续轮询 queryEnv(action="domains"),直到目标域名不再出现。',
212
212
  propagation: {
213
213
  requiresPolling: true,
214
- pollTool: "envQuery",
214
+ pollTool: "queryEnv",
215
215
  pollAction: "domains",
216
216
  pollIntervalSuggestionSeconds: 10,
217
217
  timeoutSuggestionSeconds: 600,
218
- successCondition: '目标域名不再出现在 envQuery(action="domains") 返回中。',
218
+ successCondition: '目标域名不再出现在 queryEnv(action="domains") 返回中。',
219
219
  },
220
220
  next_step: {
221
- tool: "envQuery",
221
+ tool: "queryEnv",
222
222
  action: "domains",
223
223
  suggested_args: {
224
224
  action: "domains",
@@ -492,7 +492,7 @@ function buildEnvQueryListResult(params) {
492
492
  const paginated = paginateEnvList(filteredList, params.filters.offset, params.filters.limit);
493
493
  const exactEnvIdSummaryHint = params.filters.envId
494
494
  ? {
495
- tool: "envQuery",
495
+ tool: "queryEnv",
496
496
  action: "info",
497
497
  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.",
498
498
  }
@@ -563,7 +563,7 @@ function normalizeOptionalToolString(value) {
563
563
  : undefined;
564
564
  }
565
565
  /**
566
- * Build enhanced error message for envQuery tool errors
566
+ * Build enhanced error message for queryEnv tool errors
567
567
  * Provides actionable guidance based on error patterns
568
568
  */
569
569
  function buildEnvQueryErrorMessage(error, action) {
@@ -579,7 +579,7 @@ function buildEnvQueryErrorMessage(error, action) {
579
579
  suggestions.push("参数错误:可能是认证信息无效或已过期,请尝试以下步骤:");
580
580
  suggestions.push("1. 先调用 auth(action=\"status\") 检查当前登录状态");
581
581
  suggestions.push("2. 如果未登录,调用 auth(action=\"start_auth\", authMode=\"device\") 完成登录");
582
- suggestions.push("3. 登录完成后再次调用 envQuery(action=\"list\")");
582
+ suggestions.push("3. 登录完成后再次调用 queryEnv(action=\"list\")");
583
583
  }
584
584
  if (hasAuthError) {
585
585
  suggestions.push("认证错误:当前未登录或认证已过期。");
@@ -591,7 +591,7 @@ function buildEnvQueryErrorMessage(error, action) {
591
591
  }
592
592
  if (hasEnvNotFoundError) {
593
593
  suggestions.push("环境错误:指定的环境不存在或无法访问。");
594
- suggestions.push("请使用 envQuery(action=\"list\") 查看可用的环境列表。");
594
+ suggestions.push("请使用 queryEnv(action=\"list\") 查看可用的环境列表。");
595
595
  }
596
596
  if (hasNetworkError) {
597
597
  suggestions.push("网络错误:请检查网络连接,稍后重试。");
@@ -603,7 +603,7 @@ function buildEnvQueryErrorMessage(error, action) {
603
603
  suggestions.push("2. 如未登录,执行 auth(action=\"start_auth\") 完成认证");
604
604
  suggestions.push("3. 确认环境 ID 正确且可访问");
605
605
  }
606
- return `[envQuery/${action}] 调用失败: ${baseMessage}\n\n解决建议:\n${suggestions.join("\n")}`;
606
+ return `[queryEnv/${action}] 调用失败: ${baseMessage}\n\n解决建议:\n${suggestions.join("\n")}`;
607
607
  }
608
608
  function normalizeOptionalToolBoolean(value) {
609
609
  return typeof value === "boolean" ? value : undefined;
@@ -632,519 +632,500 @@ function registerEnvTools(server) {
632
632
  const supportedAuthActions = getSupportedAuthActions(server);
633
633
  const authActionEnum = [...supportedAuthActions];
634
634
  // auth - CloudBase (云开发) 开发阶段登录与环境绑定
635
- server.registerTool?.("auth", {
636
- title: "CloudBase 开发阶段登录与环境",
637
- description: "CloudBase(腾讯云开发)开发阶段登录与环境绑定。登录后即可访问云资源;环境(env)是云函数、数据库、静态托管等资源的隔离单元,绑定环境后其他 MCP 工具才能操作该环境。支持:查询状态、发起登录、绑定环境(set_env)、退出登录。",
638
- inputSchema: {
639
- action: zod_1.z
640
- .enum(authActionEnum)
641
- .optional()
642
- .describe("动作:status=查询状态,start_auth=发起登录,set_env=绑定环境(传envId),logout=退出登录"),
643
- ...(supportedAuthActions.includes("start_auth")
644
- ? {
645
- authMode: zod_1.z
646
- .enum(["device", "web"])
647
- .optional()
648
- .describe("认证模式:device=设备码授权,web=浏览器回调授权"),
649
- oauthEndpoint: zod_1.z
650
- .string()
651
- .optional()
652
- .describe("高级可选:自定义 device-code 登录 endpoint。配置后 oauthCustom 默认按 true 处理"),
653
- clientId: zod_1.z
654
- .string()
655
- .optional()
656
- .describe("高级可选:自定义 device-code 登录 client_id,不传则使用默认值"),
657
- oauthCustom: zod_1.z
658
- .boolean()
659
- .optional()
660
- .describe("高级可选:自定义 endpoint 返回格式开关。未配置 endpoint 时默认 false;配置 endpoint 后默认 true,且不能设为 false"),
661
- }
662
- : {}),
663
- envId: zod_1.z
664
- .string()
665
- .optional()
666
- .describe("环境ID(CloudBase 环境唯一标识),绑定后工具将操作该环境。action=set_env 时必填"),
667
- ...(supportedAuthActions.includes("logout")
668
- ? {
669
- confirm: zod_1.z
670
- .literal("yes")
671
- .optional()
672
- .describe("action=logout 时确认操作,传 yes"),
673
- }
674
- : {}),
675
- ...(supportedAuthActions.includes("get_temp_credentials")
676
- ? {
677
- reveal: zod_1.z
678
- .boolean()
679
- .optional()
680
- .describe("action=get_temp_credentials 时可选。true=返回明文临时密钥;默认 false 仅返回脱敏结果"),
681
- }
682
- : {}),
683
- },
684
- annotations: {
685
- readOnlyHint: false,
686
- destructiveHint: false,
687
- idempotentHint: false,
688
- openWorldHint: true,
689
- category: "env",
690
- },
691
- }, async (rawArgs) => {
692
- const action = rawArgs.action ?? "status";
693
- const authMode = rawArgs.authMode === "device" || rawArgs.authMode === "web"
694
- ? rawArgs.authMode
695
- : undefined;
696
- const oauthEndpoint = normalizeOptionalToolString(rawArgs.oauthEndpoint);
697
- const clientId = normalizeOptionalToolString(rawArgs.clientId);
698
- const oauthCustom = normalizeOptionalToolBoolean(rawArgs.oauthCustom);
699
- const envId = rawArgs.envId;
700
- const confirm = rawArgs.confirm === "yes" ? "yes" : undefined;
701
- const reveal = normalizeOptionalToolBoolean(rawArgs.reveal) === true;
702
- const resolvedAuthOptions = resolveToolAuthOptions(server, {
703
- authMode,
704
- oauthEndpoint,
705
- clientId,
706
- oauthCustom,
707
- });
708
- const authConfigSummary = (0, auth_js_1.buildAuthConfigSummary)(resolvedAuthOptions);
709
- let deviceAuthInfo;
710
- const onDeviceCode = (info) => {
711
- deviceAuthInfo = info;
712
- (0, auth_js_1.setPendingAuthProgressState)(info, "device");
713
- // emitDeviceAuthNotice(server, info);
714
- };
715
- const authChallenge = () => (0, auth_js_1.buildDeviceAuthChallengePayload)(deviceAuthInfo);
716
- try {
717
- if (!supportedAuthActions.includes(action)) {
718
- return (0, tool_result_js_1.buildJsonToolResult)({
719
- ok: false,
720
- code: "NOT_SUPPORTED",
721
- message: `当前 IDE 不支持 auth(action="${action}")。`,
722
- next_step: (0, tool_result_js_1.buildAuthNextStep)("status", {
723
- suggestedArgs: { action: "status" },
724
- }),
725
- });
726
- }
727
- if (action === "status") {
728
- const loginState = await (0, auth_js_1.peekLoginState)();
729
- const authFlowState = await (0, auth_js_1.getAuthProgressState)();
730
- // 判断是否为 API Key 模式
731
- const isApiKeyMode = !!(process.env.CLOUDBASE_API_KEY && process.env.CLOUDBASE_ENV_ID);
732
- const authStatus = loginState
733
- ? "READY"
734
- : authFlowState.status === "PENDING"
735
- ? "PENDING"
736
- : "REQUIRED";
737
- let envPreparation;
738
- const message = authStatus === "READY"
739
- ? undefined
740
- : authStatus === "PENDING"
741
- ? "设备码授权进行中,请完成浏览器授权后再次调用 auth(action=\"status\")"
742
- : isCodeBuddyIde(server)
743
- ? "当前未登录。CodeBuddy 暂不支持在 tool 内发起认证,请在外部完成认证后再次调用 auth(action=\"status\")。"
744
- : "当前未登录,请先执行 auth(action=\"start_auth\")";
745
- if (authStatus === "READY" && loginState) {
746
- envPreparation = await prepareAuthEnvironment({
747
- server,
748
- cloudBaseOptions,
749
- loginState,
750
- });
751
- }
752
- return (0, tool_result_js_1.buildJsonToolResult)({
753
- ok: true,
754
- code: "STATUS",
755
- auth_status: authStatus,
756
- ...(isApiKeyMode ? { auth_mode: "api_key" } : {}),
757
- auth_config: authConfigSummary,
758
- ...(envPreparation
759
- ? buildAuthEnvSetupPayload(envPreparation)
760
- : {
761
- env_status: "NONE",
762
- current_env_id: null,
763
- ...buildEnvCandidatePayload([]),
764
- }),
765
- auth_challenge: authFlowState.status === "PENDING"
766
- ? (0, auth_js_1.buildDeviceAuthChallengePayload)(authFlowState.authChallenge)
767
- : undefined,
768
- message,
769
- next_step: authStatus === "REQUIRED"
770
- ? buildAuthRequiredNextStep(server)
771
- : authStatus === "PENDING"
772
- ? (0, tool_result_js_1.buildAuthNextStep)("status", {
773
- suggestedArgs: { action: "status" },
774
- })
775
- : envPreparation?.nextStep,
776
- });
777
- }
778
- if (action === "start_auth") {
779
- // API Key 模式:尝试换取临时密钥
780
- if (process.env.CLOUDBASE_API_KEY && process.env.CLOUDBASE_ENV_ID) {
781
- try {
782
- const existingLoginState = await (0, auth_js_1.peekLoginState)();
783
- if (existingLoginState) {
784
- return (0, tool_result_js_1.buildJsonToolResult)({
785
- ok: true,
786
- code: "AUTH_READY",
787
- message: "当前使用 API Key 认证模式,已自动完成登录,无需手动授权。",
788
- auth_mode: "api_key",
789
- envId: process.env.CLOUDBASE_ENV_ID,
790
- });
791
- }
635
+ // 微信 IDE 使用票据认证,不需要登录工具
636
+ if (server.ide !== 'wxide') {
637
+ server.registerTool?.("auth", {
638
+ title: "CloudBase 开发阶段登录与环境",
639
+ description: "CloudBase(腾讯云开发)开发阶段登录与环境绑定。登录后即可访问云资源;环境(env)是云函数、数据库、静态托管等资源的隔离单元,绑定环境后其他 MCP 工具才能操作该环境。支持:查询状态、发起登录、绑定环境(set_env)、退出登录。",
640
+ inputSchema: {
641
+ action: zod_1.z
642
+ .enum(authActionEnum)
643
+ .optional()
644
+ .describe("动作:status=查询状态,start_auth=发起登录,set_env=绑定环境(传envId),logout=退出登录"),
645
+ ...(supportedAuthActions.includes("start_auth")
646
+ ? {
647
+ authMode: zod_1.z
648
+ .enum(["device", "web"])
649
+ .optional()
650
+ .describe("认证模式:device=设备码授权,web=浏览器回调授权"),
651
+ oauthEndpoint: zod_1.z
652
+ .string()
653
+ .optional()
654
+ .describe("高级可选:自定义 device-code 登录 endpoint。配置后 oauthCustom 默认按 true 处理"),
655
+ clientId: zod_1.z
656
+ .string()
657
+ .optional()
658
+ .describe("高级可选:自定义 device-code 登录 client_id,不传则使用默认值"),
659
+ oauthCustom: zod_1.z
660
+ .boolean()
661
+ .optional()
662
+ .describe("高级可选:自定义 endpoint 返回格式开关。未配置 endpoint 时默认 false;配置 endpoint 后默认 true,且不能设为 false"),
792
663
  }
793
- catch (e) {
794
- // peekLoginState 内部异常,记录后 fall through
795
- (0, logger_js_1.debug)("start_auth: peekLoginState threw", { error: e instanceof Error ? e.message : String(e) });
664
+ : {}),
665
+ envId: zod_1.z
666
+ .string()
667
+ .optional()
668
+ .describe("环境ID(CloudBase 环境唯一标识),绑定后工具将操作该环境。action=set_env 时必填"),
669
+ ...(supportedAuthActions.includes("logout")
670
+ ? {
671
+ confirm: zod_1.z
672
+ .literal("yes")
673
+ .optional()
674
+ .describe("action=logout 时确认操作,传 yes"),
675
+ }
676
+ : {}),
677
+ ...(supportedAuthActions.includes("get_temp_credentials")
678
+ ? {
679
+ reveal: zod_1.z
680
+ .boolean()
681
+ .optional()
682
+ .describe("action=get_temp_credentials 时可选。true=返回明文临时密钥;默认 false 仅返回脱敏结果"),
796
683
  }
797
- // API Key 换取失败:返回详细诊断信息
798
- // 尝试获取更详细的错误信息
799
- let diagMessage = "当前配置了 API Key 认证模式,但换取临时密钥失败。";
800
- const endpoint = process.env.CLOUDBASE_API_ENDPOINT || `https://${process.env.CLOUDBASE_ENV_ID}.ap-shanghai.tcb-api.tencentcloudapi.com`;
801
- diagMessage += `\n\n诊断信息:`;
802
- diagMessage += `\n- CLOUDBASE_ENV_ID: ${process.env.CLOUDBASE_ENV_ID}`;
803
- diagMessage += `\n- CLOUDBASE_API_KEY: ${process.env.CLOUDBASE_API_KEY.slice(0, 20)}...(已截断)`;
804
- diagMessage += `\n- Endpoint: ${endpoint}`;
805
- diagMessage += `\n\n可能原因:`;
806
- diagMessage += `\n1. API Key 已过期或被删除`;
807
- diagMessage += `\n2. Endpoint 不可达(网络/DNS 问题)`;
808
- diagMessage += `\n3. CLOUDBASE_ENV_ID 与 API Key 所属环境不匹配`;
809
- diagMessage += `\n\n建议:检查 MCP 配置中的 CLOUDBASE_API_KEY 和 CLOUDBASE_ENV_ID 环境变量是否正确。`;
684
+ : {}),
685
+ },
686
+ annotations: {
687
+ readOnlyHint: false,
688
+ destructiveHint: false,
689
+ idempotentHint: false,
690
+ openWorldHint: true,
691
+ category: "env",
692
+ },
693
+ }, async (rawArgs) => {
694
+ const action = rawArgs.action ?? "status";
695
+ const authMode = rawArgs.authMode === "device" || rawArgs.authMode === "web"
696
+ ? rawArgs.authMode
697
+ : undefined;
698
+ const oauthEndpoint = normalizeOptionalToolString(rawArgs.oauthEndpoint);
699
+ const clientId = normalizeOptionalToolString(rawArgs.clientId);
700
+ const oauthCustom = normalizeOptionalToolBoolean(rawArgs.oauthCustom);
701
+ const envId = rawArgs.envId;
702
+ const confirm = rawArgs.confirm === "yes" ? "yes" : undefined;
703
+ const reveal = normalizeOptionalToolBoolean(rawArgs.reveal) === true;
704
+ const resolvedAuthOptions = resolveToolAuthOptions(server, {
705
+ authMode,
706
+ oauthEndpoint,
707
+ clientId,
708
+ oauthCustom,
709
+ });
710
+ const authConfigSummary = (0, auth_js_1.buildAuthConfigSummary)(resolvedAuthOptions);
711
+ let deviceAuthInfo;
712
+ const onDeviceCode = (info) => {
713
+ deviceAuthInfo = info;
714
+ (0, auth_js_1.setPendingAuthProgressState)(info, "device");
715
+ // emitDeviceAuthNotice(server, info);
716
+ };
717
+ const authChallenge = () => (0, auth_js_1.buildDeviceAuthChallengePayload)(deviceAuthInfo);
718
+ try {
719
+ if (!supportedAuthActions.includes(action)) {
810
720
  return (0, tool_result_js_1.buildJsonToolResult)({
811
721
  ok: false,
812
- code: "API_KEY_AUTH_FAILED",
813
- message: diagMessage,
814
- auth_mode: "api_key",
815
- envId: process.env.CLOUDBASE_ENV_ID,
816
- endpoint,
817
- });
818
- }
819
- const region = server.cloudBaseOptions?.region || process.env.TCB_REGION;
820
- const auth = toolbox_1.AuthSupervisor.getInstance({});
821
- const authFlowState = await (0, auth_js_1.getAuthProgressState)();
822
- if (authFlowState.status === "PENDING" && authFlowState.authChallenge) {
823
- return (0, tool_result_js_1.buildJsonToolResult)({
824
- ok: true,
825
- code: "AUTH_PENDING",
826
- message: "设备码授权进行中,请在浏览器中打开 verification_uri 并输入 user_code 完成授权。",
827
- auth_challenge: (0, auth_js_1.buildDeviceAuthChallengePayload)(authFlowState.authChallenge),
722
+ code: "NOT_SUPPORTED",
723
+ message: `当前 IDE 不支持 auth(action="${action}")。`,
828
724
  next_step: (0, tool_result_js_1.buildAuthNextStep)("status", {
829
725
  suggestedArgs: { action: "status" },
830
726
  }),
831
727
  });
832
728
  }
833
- // 1. 如果已经有登录态,直接返回 AUTH_READY
834
- try {
835
- const existingLoginState = await (0, auth_js_1.peekLoginState)();
836
- if (existingLoginState) {
837
- const envPreparation = await prepareAuthEnvironment({
729
+ if (action === "status") {
730
+ const loginState = await (0, auth_js_1.peekLoginState)();
731
+ const authFlowState = await (0, auth_js_1.getAuthProgressState)();
732
+ // 判断是否为 API Key 模式
733
+ const isApiKeyMode = !!(process.env.CLOUDBASE_API_KEY && process.env.CLOUDBASE_ENV_ID);
734
+ const authStatus = loginState
735
+ ? "READY"
736
+ : authFlowState.status === "PENDING"
737
+ ? "PENDING"
738
+ : "REQUIRED";
739
+ let envPreparation;
740
+ const message = authStatus === "READY"
741
+ ? undefined
742
+ : authStatus === "PENDING"
743
+ ? "设备码授权进行中,请完成浏览器授权后再次调用 auth(action=\"status\")"
744
+ : isCodeBuddyIde(server)
745
+ ? "当前未登录。CodeBuddy 暂不支持在 tool 内发起认证,请在外部完成认证后再次调用 auth(action=\"status\")。"
746
+ : "当前未登录,请先执行 auth(action=\"start_auth\")";
747
+ if (authStatus === "READY" && loginState) {
748
+ envPreparation = await prepareAuthEnvironment({
838
749
  server,
839
750
  cloudBaseOptions,
840
- loginState: existingLoginState,
841
- });
842
- return (0, tool_result_js_1.buildJsonToolResult)({
843
- ok: true,
844
- code: "AUTH_READY",
845
- message: envPreparation.message,
846
- auth_challenge: authChallenge(),
847
- ...buildAuthEnvSetupPayload(envPreparation),
848
- next_step: envPreparation.nextStep,
751
+ loginState,
849
752
  });
850
753
  }
851
- }
852
- catch {
853
- // 忽略 getLoginState 错误,继续尝试发起登录
854
- }
855
- const validationError = (0, auth_js_1.getAuthConfigValidationError)(resolvedAuthOptions);
856
- if (validationError) {
857
754
  return (0, tool_result_js_1.buildJsonToolResult)({
858
- ok: false,
859
- code: "INVALID_ARGS",
860
- message: validationError,
755
+ ok: true,
756
+ code: "STATUS",
757
+ auth_status: authStatus,
758
+ ...(isApiKeyMode ? { auth_mode: "api_key" } : {}),
861
759
  auth_config: authConfigSummary,
862
- next_step: (0, tool_result_js_1.buildAuthNextStep)("start_auth", {
863
- suggestedArgs: { action: "start_auth", authMode: "device" },
864
- }),
760
+ ...(envPreparation
761
+ ? buildAuthEnvSetupPayload(envPreparation)
762
+ : {
763
+ env_status: "NONE",
764
+ current_env_id: null,
765
+ ...buildEnvCandidatePayload([]),
766
+ }),
767
+ auth_challenge: authFlowState.status === "PENDING"
768
+ ? (0, auth_js_1.buildDeviceAuthChallengePayload)(authFlowState.authChallenge)
769
+ : undefined,
770
+ message,
771
+ next_step: authStatus === "REQUIRED"
772
+ ? buildAuthRequiredNextStep(server)
773
+ : authStatus === "PENDING"
774
+ ? (0, tool_result_js_1.buildAuthNextStep)("status", {
775
+ suggestedArgs: { action: "status" },
776
+ })
777
+ : envPreparation?.nextStep,
865
778
  });
866
779
  }
867
- // 2. 设备码模式:监听到 device code 即返回 AUTH_PENDING,后续由 toolbox 异步轮询并更新本地 credential
868
- const effectiveMode = resolvedAuthOptions.authMode;
869
- if (effectiveMode === "device") {
870
- let resolveCode;
871
- let rejectCode;
872
- const codeReady = new Promise((resolve, reject) => {
873
- resolveCode = resolve;
874
- rejectCode = reject;
875
- });
876
- const deviceOnCode = (info) => {
877
- onDeviceCode(info);
878
- if (resolveCode) {
879
- resolveCode();
880
- }
881
- };
882
- try {
883
- // 启动 Device Flow,全流程由 toolbox 负责轮询和写入 credential,这里不等待完成
884
- auth
885
- .loginByWebAuth({
886
- flow: "device",
887
- ...(resolvedAuthOptions.clientId
888
- ? { client_id: resolvedAuthOptions.clientId }
889
- : {}),
890
- ...(resolvedAuthOptions.oauthEndpoint
891
- ? { getOAuthEndpoint: () => resolvedAuthOptions.oauthEndpoint }
892
- : {}),
893
- ...(resolvedAuthOptions.oauthCustom
894
- ? { custom: true }
895
- : {}),
896
- onDeviceCode: deviceOnCode,
897
- })
898
- .then(() => {
899
- (0, auth_js_1.resolveAuthProgressState)();
900
- })
901
- .catch((err) => {
902
- (0, auth_js_1.rejectAuthProgressState)(err);
903
- // 如果在拿到 device code 之前就失败,则唤醒当前调用并返回错误
904
- if (!deviceAuthInfo && rejectCode) {
905
- rejectCode(err);
780
+ if (action === "start_auth") {
781
+ // API Key 模式:尝试换取临时密钥
782
+ if (process.env.CLOUDBASE_API_KEY && process.env.CLOUDBASE_ENV_ID) {
783
+ try {
784
+ const existingLoginState = await (0, auth_js_1.peekLoginState)();
785
+ if (existingLoginState) {
786
+ return (0, tool_result_js_1.buildJsonToolResult)({
787
+ ok: true,
788
+ code: "AUTH_READY",
789
+ message: "当前使用 API Key 认证模式,已自动完成登录,无需手动授权。",
790
+ auth_mode: "api_key",
791
+ envId: process.env.CLOUDBASE_ENV_ID,
792
+ });
906
793
  }
794
+ }
795
+ catch (e) {
796
+ // peekLoginState 内部异常,记录后 fall through
797
+ (0, logger_js_1.debug)("start_auth: peekLoginState threw", { error: e instanceof Error ? e.message : String(e) });
798
+ }
799
+ // API Key 换取失败:返回详细诊断信息
800
+ // 尝试获取更详细的错误信息
801
+ let diagMessage = "当前配置了 API Key 认证模式,但换取临时密钥失败。";
802
+ const endpoint = process.env.CLOUDBASE_API_ENDPOINT || `https://${process.env.CLOUDBASE_ENV_ID}.ap-shanghai.tcb-api.tencentcloudapi.com`;
803
+ diagMessage += `\n\n诊断信息:`;
804
+ diagMessage += `\n- CLOUDBASE_ENV_ID: ${process.env.CLOUDBASE_ENV_ID}`;
805
+ diagMessage += `\n- CLOUDBASE_API_KEY: ${process.env.CLOUDBASE_API_KEY.slice(0, 20)}...(已截断)`;
806
+ diagMessage += `\n- Endpoint: ${endpoint}`;
807
+ diagMessage += `\n\n可能原因:`;
808
+ diagMessage += `\n1. API Key 已过期或被删除`;
809
+ diagMessage += `\n2. Endpoint 不可达(网络/DNS 问题)`;
810
+ diagMessage += `\n3. CLOUDBASE_ENV_ID 与 API Key 所属环境不匹配`;
811
+ diagMessage += `\n\n建议:检查 MCP 配置中的 CLOUDBASE_API_KEY 和 CLOUDBASE_ENV_ID 环境变量是否正确。`;
812
+ return (0, tool_result_js_1.buildJsonToolResult)({
813
+ ok: false,
814
+ code: "API_KEY_AUTH_FAILED",
815
+ message: diagMessage,
816
+ auth_mode: "api_key",
817
+ envId: process.env.CLOUDBASE_ENV_ID,
818
+ endpoint,
907
819
  });
908
820
  }
909
- catch (err) {
910
- if (rejectCode) {
911
- rejectCode(err);
912
- }
821
+ const region = server.cloudBaseOptions?.region || process.env.TCB_REGION;
822
+ const auth = toolbox_1.AuthSupervisor.getInstance({});
823
+ const authFlowState = await (0, auth_js_1.getAuthProgressState)();
824
+ if (authFlowState.status === "PENDING" && authFlowState.authChallenge) {
825
+ return (0, tool_result_js_1.buildJsonToolResult)({
826
+ ok: true,
827
+ code: "AUTH_PENDING",
828
+ message: "设备码授权进行中,请在浏览器中打开 verification_uri 并输入 user_code 完成授权。",
829
+ auth_challenge: (0, auth_js_1.buildDeviceAuthChallengePayload)(authFlowState.authChallenge),
830
+ next_step: (0, tool_result_js_1.buildAuthNextStep)("status", {
831
+ suggestedArgs: { action: "status" },
832
+ }),
833
+ });
913
834
  }
835
+ // 1. 如果已经有登录态,直接返回 AUTH_READY
914
836
  try {
915
- await codeReady;
837
+ const existingLoginState = await (0, auth_js_1.peekLoginState)();
838
+ if (existingLoginState) {
839
+ const envPreparation = await prepareAuthEnvironment({
840
+ server,
841
+ cloudBaseOptions,
842
+ loginState: existingLoginState,
843
+ });
844
+ return (0, tool_result_js_1.buildJsonToolResult)({
845
+ ok: true,
846
+ code: "AUTH_READY",
847
+ message: envPreparation.message,
848
+ auth_challenge: authChallenge(),
849
+ ...buildAuthEnvSetupPayload(envPreparation),
850
+ next_step: envPreparation.nextStep,
851
+ });
852
+ }
853
+ }
854
+ catch {
855
+ // 忽略 getLoginState 错误,继续尝试发起登录
916
856
  }
917
- catch (err) {
918
- const message = err instanceof Error ? err.message : String(err ?? "unknown error");
857
+ const validationError = (0, auth_js_1.getAuthConfigValidationError)(resolvedAuthOptions);
858
+ if (validationError) {
919
859
  return (0, tool_result_js_1.buildJsonToolResult)({
920
860
  ok: false,
921
- code: "AUTH_REQUIRED",
922
- message: `设备码登录初始化失败: ${message}`,
861
+ code: "INVALID_ARGS",
862
+ message: validationError,
863
+ auth_config: authConfigSummary,
923
864
  next_step: (0, tool_result_js_1.buildAuthNextStep)("start_auth", {
924
865
  suggestedArgs: { action: "start_auth", authMode: "device" },
925
866
  }),
926
867
  });
927
868
  }
928
- if (!deviceAuthInfo) {
869
+ // 2. 设备码模式:监听到 device code 即返回 AUTH_PENDING,后续由 toolbox 异步轮询并更新本地 credential
870
+ const effectiveMode = resolvedAuthOptions.authMode;
871
+ if (effectiveMode === "device") {
872
+ let resolveCode;
873
+ let rejectCode;
874
+ const codeReady = new Promise((resolve, reject) => {
875
+ resolveCode = resolve;
876
+ rejectCode = reject;
877
+ });
878
+ const deviceOnCode = (info) => {
879
+ onDeviceCode(info);
880
+ if (resolveCode) {
881
+ resolveCode();
882
+ }
883
+ };
884
+ try {
885
+ // 启动 Device Flow,全流程由 toolbox 负责轮询和写入 credential,这里不等待完成
886
+ auth
887
+ .loginByWebAuth({
888
+ flow: "device",
889
+ ...(resolvedAuthOptions.clientId
890
+ ? { client_id: resolvedAuthOptions.clientId }
891
+ : {}),
892
+ ...(resolvedAuthOptions.oauthEndpoint
893
+ ? { getOAuthEndpoint: () => resolvedAuthOptions.oauthEndpoint }
894
+ : {}),
895
+ ...(resolvedAuthOptions.oauthCustom
896
+ ? { custom: true }
897
+ : {}),
898
+ onDeviceCode: deviceOnCode,
899
+ })
900
+ .then(() => {
901
+ (0, auth_js_1.resolveAuthProgressState)();
902
+ })
903
+ .catch((err) => {
904
+ (0, auth_js_1.rejectAuthProgressState)(err);
905
+ // 如果在拿到 device code 之前就失败,则唤醒当前调用并返回错误
906
+ if (!deviceAuthInfo && rejectCode) {
907
+ rejectCode(err);
908
+ }
909
+ });
910
+ }
911
+ catch (err) {
912
+ if (rejectCode) {
913
+ rejectCode(err);
914
+ }
915
+ }
916
+ try {
917
+ await codeReady;
918
+ }
919
+ catch (err) {
920
+ const message = err instanceof Error ? err.message : String(err ?? "unknown error");
921
+ return (0, tool_result_js_1.buildJsonToolResult)({
922
+ ok: false,
923
+ code: "AUTH_REQUIRED",
924
+ message: `设备码登录初始化失败: ${message}`,
925
+ next_step: (0, tool_result_js_1.buildAuthNextStep)("start_auth", {
926
+ suggestedArgs: { action: "start_auth", authMode: "device" },
927
+ }),
928
+ });
929
+ }
930
+ if (!deviceAuthInfo) {
931
+ return (0, tool_result_js_1.buildJsonToolResult)({
932
+ ok: false,
933
+ code: "AUTH_REQUIRED",
934
+ message: "未获取到设备码信息,请重试设备码登录",
935
+ next_step: (0, tool_result_js_1.buildAuthNextStep)("start_auth", {
936
+ suggestedArgs: { action: "start_auth", authMode: "device" },
937
+ }),
938
+ });
939
+ }
940
+ const envCandidates = await fetchAvailableEnvCandidates(cloudBaseOptions, server);
941
+ return (0, tool_result_js_1.buildJsonToolResult)({
942
+ ok: true,
943
+ code: "AUTH_PENDING",
944
+ message: "已发起设备码登录,请在浏览器中打开 verification_uri 并输入 user_code 完成授权。授权完成后请再次调用 auth(action=\"status\")。",
945
+ auth_challenge: authChallenge(),
946
+ ...buildEnvCandidatePayload(envCandidates),
947
+ next_step: (0, tool_result_js_1.buildAuthNextStep)("status", {
948
+ suggestedArgs: { action: "status" },
949
+ }),
950
+ });
951
+ }
952
+ // 3. 非 Device Flow(显式 web 模式)仍然使用 getLoginState 阻塞等待
953
+ const loginState = await (0, auth_js_1.ensureLogin)({
954
+ region,
955
+ authMode: effectiveMode,
956
+ clientId: resolvedAuthOptions.clientId,
957
+ oauthEndpoint: resolvedAuthOptions.oauthEndpoint,
958
+ oauthCustom: resolvedAuthOptions.oauthCustom,
959
+ });
960
+ if (!loginState) {
929
961
  return (0, tool_result_js_1.buildJsonToolResult)({
930
962
  ok: false,
931
963
  code: "AUTH_REQUIRED",
932
- message: "未获取到设备码信息,请重试设备码登录",
964
+ message: "未获取到登录态,请先完成认证",
933
965
  next_step: (0, tool_result_js_1.buildAuthNextStep)("start_auth", {
934
- suggestedArgs: { action: "start_auth", authMode: "device" },
966
+ suggestedArgs: { action: "start_auth", authMode: effectiveMode },
935
967
  }),
936
968
  });
937
969
  }
938
- const envCandidates = await fetchAvailableEnvCandidates(cloudBaseOptions, server);
970
+ const envPreparation = await prepareAuthEnvironment({
971
+ server,
972
+ cloudBaseOptions,
973
+ loginState,
974
+ });
939
975
  return (0, tool_result_js_1.buildJsonToolResult)({
940
976
  ok: true,
941
- code: "AUTH_PENDING",
942
- message: "已发起设备码登录,请在浏览器中打开 verification_uri 并输入 user_code 完成授权。授权完成后请再次调用 auth(action=\"status\")。",
977
+ code: "AUTH_READY",
978
+ message: envPreparation.message,
943
979
  auth_challenge: authChallenge(),
944
- ...buildEnvCandidatePayload(envCandidates),
945
- next_step: (0, tool_result_js_1.buildAuthNextStep)("status", {
946
- suggestedArgs: { action: "status" },
947
- }),
980
+ ...buildAuthEnvSetupPayload(envPreparation),
981
+ next_step: envPreparation.nextStep,
948
982
  });
949
983
  }
950
- // 3. 非 Device Flow(显式 web 模式)仍然使用 getLoginState 阻塞等待
951
- const loginState = await (0, auth_js_1.ensureLogin)({
952
- region,
953
- authMode: effectiveMode,
954
- clientId: resolvedAuthOptions.clientId,
955
- oauthEndpoint: resolvedAuthOptions.oauthEndpoint,
956
- oauthCustom: resolvedAuthOptions.oauthCustom,
957
- });
958
- if (!loginState) {
959
- return (0, tool_result_js_1.buildJsonToolResult)({
960
- ok: false,
961
- code: "AUTH_REQUIRED",
962
- message: "未获取到登录态,请先完成认证",
963
- next_step: (0, tool_result_js_1.buildAuthNextStep)("start_auth", {
964
- suggestedArgs: { action: "start_auth", authMode: effectiveMode },
965
- }),
966
- });
967
- }
968
- const envPreparation = await prepareAuthEnvironment({
969
- server,
970
- cloudBaseOptions,
971
- loginState,
972
- });
973
- return (0, tool_result_js_1.buildJsonToolResult)({
974
- ok: true,
975
- code: "AUTH_READY",
976
- message: envPreparation.message,
977
- auth_challenge: authChallenge(),
978
- ...buildAuthEnvSetupPayload(envPreparation),
979
- next_step: envPreparation.nextStep,
980
- });
981
- }
982
- if (action === "set_env") {
983
- const loginState = await (0, auth_js_1.peekLoginState)();
984
- if (!loginState) {
985
- return (0, tool_result_js_1.buildJsonToolResult)({
986
- ok: false,
987
- code: "AUTH_REQUIRED",
988
- message: isCodeBuddyIde(server)
989
- ? "当前未登录。CodeBuddy 暂不支持在 tool 内发起认证,请在外部完成认证后再次调用 auth(action=\"status\")。"
990
- : "当前未登录,请先执行 auth(action=\"start_auth\")。",
991
- next_step: buildAuthRequiredNextStep(server),
992
- });
993
- }
994
- const envCandidates = await fetchAvailableEnvCandidates(cloudBaseOptions, server);
995
- if (!envId) {
996
- return (0, tool_result_js_1.buildJsonToolResult)({
997
- ok: false,
998
- code: "INVALID_ARGS",
999
- message: "action=set_env 时必须提供 envId",
1000
- ...buildEnvCandidatePayload(envCandidates),
1001
- next_step: buildSetEnvNextStep(envCandidates),
1002
- });
1003
- }
1004
- const target = envCandidates.find((item) => item.envId === envId);
1005
- if (envCandidates.length > 0 && !target) {
984
+ if (action === "set_env") {
985
+ const loginState = await (0, auth_js_1.peekLoginState)();
986
+ if (!loginState) {
987
+ return (0, tool_result_js_1.buildJsonToolResult)({
988
+ ok: false,
989
+ code: "AUTH_REQUIRED",
990
+ message: isCodeBuddyIde(server)
991
+ ? "当前未登录。CodeBuddy 暂不支持在 tool 内发起认证,请在外部完成认证后再次调用 auth(action=\"status\")。"
992
+ : "当前未登录,请先执行 auth(action=\"start_auth\")。",
993
+ next_step: buildAuthRequiredNextStep(server),
994
+ });
995
+ }
996
+ const envCandidates = await fetchAvailableEnvCandidates(cloudBaseOptions, server);
997
+ if (!envId) {
998
+ return (0, tool_result_js_1.buildJsonToolResult)({
999
+ ok: false,
1000
+ code: "INVALID_ARGS",
1001
+ message: "action=set_env 时必须提供 envId",
1002
+ ...buildEnvCandidatePayload(envCandidates),
1003
+ next_step: buildSetEnvNextStep(envCandidates),
1004
+ });
1005
+ }
1006
+ const target = envCandidates.find((item) => item.envId === envId);
1007
+ if (envCandidates.length > 0 && !target) {
1008
+ return (0, tool_result_js_1.buildJsonToolResult)({
1009
+ ok: false,
1010
+ code: "INVALID_ARGS",
1011
+ message: `未找到环境: ${envId}`,
1012
+ ...buildEnvCandidatePayload(envCandidates),
1013
+ next_step: buildSetEnvNextStep(envCandidates),
1014
+ });
1015
+ }
1016
+ await cloudbase_manager_js_1.envManager.setEnvId(envId);
1006
1017
  return (0, tool_result_js_1.buildJsonToolResult)({
1007
- ok: false,
1008
- code: "INVALID_ARGS",
1009
- message: `未找到环境: ${envId}`,
1010
- ...buildEnvCandidatePayload(envCandidates),
1011
- next_step: buildSetEnvNextStep(envCandidates),
1018
+ ok: true,
1019
+ code: "ENV_READY",
1020
+ message: `环境设置成功,当前环境: ${envId}`,
1021
+ current_env_id: envId,
1012
1022
  });
1013
1023
  }
1014
- await cloudbase_manager_js_1.envManager.setEnvId(envId);
1015
- return (0, tool_result_js_1.buildJsonToolResult)({
1016
- ok: true,
1017
- code: "ENV_READY",
1018
- message: `环境设置成功,当前环境: ${envId}`,
1019
- current_env_id: envId,
1020
- });
1021
- }
1022
- if (action === "logout") {
1023
- // API Key 模式下不允许 logout
1024
- if (process.env.CLOUDBASE_API_KEY && process.env.CLOUDBASE_ENV_ID) {
1024
+ if (action === "logout") {
1025
+ // API Key 模式下不允许 logout
1026
+ if (process.env.CLOUDBASE_API_KEY && process.env.CLOUDBASE_ENV_ID) {
1027
+ return (0, tool_result_js_1.buildJsonToolResult)({
1028
+ ok: false,
1029
+ code: "LOGOUT_NOT_ALLOWED",
1030
+ message: "当前使用 API Key 认证模式,不支持退出登录。如需切换认证方式,请移除 CLOUDBASE_API_KEY 环境变量后重启。",
1031
+ auth_mode: "api_key",
1032
+ });
1033
+ }
1034
+ if (confirm !== "yes") {
1035
+ return (0, tool_result_js_1.buildJsonToolResult)({
1036
+ ok: false,
1037
+ code: "INVALID_ARGS",
1038
+ message: "action=logout 时必须传 confirm=\"yes\"",
1039
+ next_step: (0, tool_result_js_1.buildAuthNextStep)("logout", {
1040
+ suggestedArgs: { action: "logout", confirm: "yes" },
1041
+ }),
1042
+ });
1043
+ }
1044
+ await (0, auth_js_1.logout)();
1045
+ (0, cloudbase_manager_js_1.resetCloudBaseManagerCache)();
1025
1046
  return (0, tool_result_js_1.buildJsonToolResult)({
1026
- ok: false,
1027
- code: "LOGOUT_NOT_ALLOWED",
1028
- message: "当前使用 API Key 认证模式,不支持退出登录。如需切换认证方式,请移除 CLOUDBASE_API_KEY 环境变量后重启。",
1029
- auth_mode: "api_key",
1047
+ ok: true,
1048
+ code: "LOGGED_OUT",
1049
+ message: "✅ 已退出登录",
1030
1050
  });
1031
1051
  }
1032
- if (confirm !== "yes") {
1052
+ if (action === "get_temp_credentials") {
1053
+ const loginState = (await (0, auth_js_1.peekLoginState)());
1054
+ if (!loginState) {
1055
+ return (0, tool_result_js_1.buildJsonToolResult)({
1056
+ ok: false,
1057
+ code: "AUTH_REQUIRED",
1058
+ message: "当前未登录,请先完成管理端认证后再获取临时密钥。",
1059
+ next_step: buildAuthRequiredNextStep(server),
1060
+ });
1061
+ }
1062
+ if (confirm !== "yes") {
1063
+ return (0, tool_result_js_1.buildJsonToolResult)({
1064
+ ok: false,
1065
+ code: "INVALID_ARGS",
1066
+ message: "action=get_temp_credentials 时必须显式传 confirm=\"yes\",以确认你要导出当前管理端临时密钥。",
1067
+ next_step: (0, tool_result_js_1.buildAuthNextStep)("get_temp_credentials", {
1068
+ suggestedArgs: { action: "get_temp_credentials", confirm: "yes" },
1069
+ }),
1070
+ });
1071
+ }
1072
+ if (!isTemporaryCredentialLoginState(loginState)) {
1073
+ return (0, tool_result_js_1.buildJsonToolResult)({
1074
+ ok: false,
1075
+ code: "UNSUPPORTED_CREDENTIAL_TYPE",
1076
+ message: "当前登录态不是可导出的临时密钥。仅支持通过 Web / device 登录得到的临时密钥,永久密钥登录不允许导出。",
1077
+ });
1078
+ }
1079
+ const secretId = normalizeOptionalToolString(loginState.secretId);
1080
+ const secretKey = normalizeOptionalToolString(loginState.secretKey);
1081
+ const token = normalizeOptionalToolString(loginState.token);
1082
+ if (!secretId || !secretKey || !token) {
1083
+ return (0, tool_result_js_1.buildJsonToolResult)({
1084
+ ok: false,
1085
+ code: "INTERNAL_ERROR",
1086
+ message: "当前登录态缺少完整的临时密钥字段,请重新登录后再试。",
1087
+ });
1088
+ }
1033
1089
  return (0, tool_result_js_1.buildJsonToolResult)({
1034
- ok: false,
1035
- code: "INVALID_ARGS",
1036
- message: "action=logout 时必须传 confirm=\"yes\"",
1037
- next_step: (0, tool_result_js_1.buildAuthNextStep)("logout", {
1038
- suggestedArgs: { action: "logout", confirm: "yes" },
1039
- }),
1090
+ ok: true,
1091
+ code: "TEMP_CREDENTIALS_READY",
1092
+ message: reveal
1093
+ ? "当前管理端临时密钥已准备好,请注意避免泄露。"
1094
+ : "当前管理端临时密钥已准备好,默认仅返回脱敏结果。",
1095
+ env_id: normalizeOptionalToolString(loginState.envId) ?? null,
1096
+ credentials: {
1097
+ secretId: reveal ? secretId : maskSensitiveValue(secretId),
1098
+ secretKey: reveal ? secretKey : maskSensitiveValue(secretKey),
1099
+ token: reveal ? token : maskSensitiveValue(token),
1100
+ masked: !reveal,
1101
+ },
1040
1102
  });
1041
1103
  }
1042
- await (0, auth_js_1.logout)();
1043
- (0, cloudbase_manager_js_1.resetCloudBaseManagerCache)();
1044
1104
  return (0, tool_result_js_1.buildJsonToolResult)({
1045
- ok: true,
1046
- code: "LOGGED_OUT",
1047
- message: "✅ 已退出登录",
1105
+ ok: false,
1106
+ code: "NOT_SUPPORTED",
1107
+ message: `不支持的 auth action: ${action}`,
1108
+ next_step: (0, tool_result_js_1.buildAuthNextStep)("status", {
1109
+ suggestedArgs: { action: "status" },
1110
+ }),
1048
1111
  });
1049
1112
  }
1050
- if (action === "get_temp_credentials") {
1051
- const loginState = (await (0, auth_js_1.peekLoginState)());
1052
- if (!loginState) {
1053
- return (0, tool_result_js_1.buildJsonToolResult)({
1054
- ok: false,
1055
- code: "AUTH_REQUIRED",
1056
- message: "当前未登录,请先完成管理端认证后再获取临时密钥。",
1057
- next_step: buildAuthRequiredNextStep(server),
1058
- });
1059
- }
1060
- if (confirm !== "yes") {
1061
- return (0, tool_result_js_1.buildJsonToolResult)({
1062
- ok: false,
1063
- code: "INVALID_ARGS",
1064
- message: "action=get_temp_credentials 时必须显式传 confirm=\"yes\",以确认你要导出当前管理端临时密钥。",
1065
- next_step: (0, tool_result_js_1.buildAuthNextStep)("get_temp_credentials", {
1066
- suggestedArgs: { action: "get_temp_credentials", confirm: "yes" },
1067
- }),
1068
- });
1069
- }
1070
- if (!isTemporaryCredentialLoginState(loginState)) {
1071
- return (0, tool_result_js_1.buildJsonToolResult)({
1072
- ok: false,
1073
- code: "UNSUPPORTED_CREDENTIAL_TYPE",
1074
- message: "当前登录态不是可导出的临时密钥。仅支持通过 Web / device 登录得到的临时密钥,永久密钥登录不允许导出。",
1075
- });
1076
- }
1077
- const secretId = normalizeOptionalToolString(loginState.secretId);
1078
- const secretKey = normalizeOptionalToolString(loginState.secretKey);
1079
- const token = normalizeOptionalToolString(loginState.token);
1080
- if (!secretId || !secretKey || !token) {
1081
- return (0, tool_result_js_1.buildJsonToolResult)({
1082
- ok: false,
1083
- code: "INTERNAL_ERROR",
1084
- message: "当前登录态缺少完整的临时密钥字段,请重新登录后再试。",
1085
- });
1086
- }
1113
+ catch (error) {
1114
+ const message = error instanceof Error ? error.message : String(error);
1087
1115
  return (0, tool_result_js_1.buildJsonToolResult)({
1088
- ok: true,
1089
- code: "TEMP_CREDENTIALS_READY",
1090
- message: reveal
1091
- ? "当前管理端临时密钥已准备好,请注意避免泄露。"
1092
- : "当前管理端临时密钥已准备好,默认仅返回脱敏结果。",
1093
- env_id: normalizeOptionalToolString(loginState.envId) ?? null,
1094
- credentials: {
1095
- secretId: reveal ? secretId : maskSensitiveValue(secretId),
1096
- secretKey: reveal ? secretKey : maskSensitiveValue(secretKey),
1097
- token: reveal ? token : maskSensitiveValue(token),
1098
- masked: !reveal,
1099
- },
1116
+ ok: false,
1117
+ code: "INTERNAL_ERROR",
1118
+ message: `auth 执行失败: ${message}`,
1119
+ auth_challenge: authChallenge(),
1120
+ next_step: (0, tool_result_js_1.buildAuthNextStep)("status", {
1121
+ suggestedArgs: { action: "status" },
1122
+ }),
1100
1123
  });
1101
1124
  }
1102
- return (0, tool_result_js_1.buildJsonToolResult)({
1103
- ok: false,
1104
- code: "NOT_SUPPORTED",
1105
- message: `不支持的 auth action: ${action}`,
1106
- next_step: (0, tool_result_js_1.buildAuthNextStep)("status", {
1107
- suggestedArgs: { action: "status" },
1108
- }),
1109
- });
1110
- }
1111
- catch (error) {
1112
- const message = error instanceof Error ? error.message : String(error);
1113
- return (0, tool_result_js_1.buildJsonToolResult)({
1114
- ok: false,
1115
- code: "INTERNAL_ERROR",
1116
- message: `auth 执行失败: ${message}`,
1117
- auth_challenge: authChallenge(),
1118
- next_step: (0, tool_result_js_1.buildAuthNextStep)("status", {
1119
- suggestedArgs: { action: "status" },
1120
- }),
1121
- });
1122
- }
1123
- });
1124
- // envQuery - 环境查询(合并 listEnvs + getEnvInfo + getEnvAuthDomains)
1125
- server.registerTool?.("envQuery", {
1126
- title: "CloudBase 环境查询",
1127
- 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 等计费字段)。",
1128
- inputSchema: {
1129
- action: zod_1.z
1130
- .enum(["list", "info", "domains"])
1131
- .describe("查询类型:list=环境列表/摘要筛选(按 DescribeEnvs 语义筛选,支持通过 envId 筛选,返回 EnvId、Alias、Status、EnvType、Region、PackageId、PackageName、IsDefault,不支持 expiry),info=指定环境的详细信息(必须传入 envId,返回资源字段和计费信息),domains=安全域名列表"),
1132
- alias: zod_1.z.string().optional().describe("按环境别名筛选。action=list 时可选"),
1133
- aliasExact: zod_1.z.boolean().optional().describe("按环境别名精确筛选。action=list 时可选;与 alias 配合使用"),
1134
- envId: zod_1.z.string().optional().describe("按环境 ID 筛选。action=list 时可选(仅按 DescribeEnvs 语义做筛选,仍返回摘要);action=info 时必填(返回该环境的详细信息,包含资源字段和计费信息)。如果任务已经给出了明确的 EnvId 并要求查询详情,请直接使用 action=info + envId,而不是 action=list"),
1135
- limit: zod_1.z.number().int().positive().optional().describe("返回数量上限。action=list 时可选"),
1136
- offset: zod_1.z.number().int().min(0).optional().describe("分页偏移。action=list 时可选"),
1137
- fields: zod_1.z
1138
- .array(zod_1.z.enum(DEFAULT_ENV_FIELDS))
1139
- .optional()
1140
- .describe("返回字段白名单。仅支持 EnvId、Alias、Status、EnvType、Region、PackageId、PackageName、IsDefault。action=list 时可选"),
1141
- },
1142
- annotations: {
1143
- readOnlyHint: true,
1144
- openWorldHint: true,
1145
- category: "env",
1146
- },
1147
- }, async ({ action, alias, aliasExact, envId, limit, offset, fields, }) => {
1125
+ });
1126
+ } // end: wxide guard for auth tool
1127
+ // queryEnv - 环境查询(合并 listEnvs + getEnvInfo + getEnvAuthDomains)
1128
+ const queryEnvHandler = async ({ action, alias, aliasExact, envId, limit, offset, fields, }) => {
1148
1129
  try {
1149
1130
  let result;
1150
1131
  switch (action) {
@@ -1158,7 +1139,8 @@ function registerEnvTools(server) {
1158
1139
  // 当环境变量设置了 CLOUDBASE_ENV_ID 时(如 API Key 模式),
1159
1140
  // 避免调用 DescribeEnvs(临时密钥可能不支持该接口),
1160
1141
  // 改为通过 DescribeEnvInfo 获取单环境信息
1161
- const envIdFromEnv = process.env.CLOUDBASE_ENV_ID;
1142
+ // 注意:requestFn 模式(如微信 IDE)使用 DescribeEnvs,不走此分支
1143
+ const envIdFromEnv = !cloudBaseOptions?.requestFn && process.env.CLOUDBASE_ENV_ID;
1162
1144
  if (envIdFromEnv) {
1163
1145
  try {
1164
1146
  const envInfo = await cloudbaseList.env.describeEnvInfo({ EnvId: envIdFromEnv });
@@ -1325,61 +1307,91 @@ function registerEnvTools(server) {
1325
1307
  ],
1326
1308
  };
1327
1309
  }
1328
- });
1329
- // envDomainManagement - 环境域名管理(合并 createEnvDomain + deleteEnvDomain)
1330
- server.registerTool?.("envDomainManagement", {
1331
- title: "CloudBase 环境域名管理(安全域名 / CORS 白名单)",
1332
- 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\")。",
1310
+ };
1311
+ // Register primary tool name (queryEnv)
1312
+ const queryEnvToolSchema = {
1313
+ title: "CloudBase 环境查询",
1314
+ 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 等计费字段)。",
1333
1315
  inputSchema: {
1334
1316
  action: zod_1.z
1335
- .enum(["create", "delete"])
1336
- .describe("操作类型:create=添加安全域名,delete=删除安全域名"),
1337
- domains: zod_1.z.array(zod_1.z.string()).describe("安全域名数组(格式:host:port,例如 localhost:5173 或 127.0.0.1:4173)。注意:不是自定义域名,不需要证书。"),
1317
+ .enum(["list", "info", "domains"])
1318
+ .describe("查询类型:list=环境列表/摘要筛选(按 DescribeEnvs 语义筛选,支持通过 envId 筛选,返回 EnvId、Alias、Status、EnvType、Region、PackageId、PackageName、IsDefault,不支持 expiry),info=指定环境的详细信息(必须传入 envId,返回资源字段和计费信息),domains=安全域名列表"),
1319
+ alias: zod_1.z.string().optional().describe("按环境别名筛选。action=list 时可选"),
1320
+ aliasExact: zod_1.z.boolean().optional().describe("按环境别名精确筛选。action=list 时可选;与 alias 配合使用"),
1321
+ envId: zod_1.z.string().optional().describe("按环境 ID 筛选。action=list 时可选(仅按 DescribeEnvs 语义做筛选,仍返回摘要);action=info 时必填(返回该环境的详细信息,包含资源字段和计费信息)。如果任务已经给出了明确的 EnvId 并要求查询详情,请直接使用 action=info + envId,而不是 action=list"),
1322
+ limit: zod_1.z.number().int().positive().optional().describe("返回数量上限。action=list 时可选"),
1323
+ offset: zod_1.z.number().int().min(0).optional().describe("分页偏移。action=list 时可选"),
1324
+ fields: zod_1.z
1325
+ .array(zod_1.z.enum(DEFAULT_ENV_FIELDS))
1326
+ .optional()
1327
+ .describe("返回字段白名单。仅支持 EnvId、Alias、Status、EnvType、Region、PackageId、PackageName、IsDefault。action=list 时可选"),
1338
1328
  },
1339
1329
  annotations: {
1340
- readOnlyHint: false,
1341
- destructiveHint: false, // 注意:delete操作虽然是破坏性的,但这里采用较宽松的标注
1342
- idempotentHint: false,
1330
+ readOnlyHint: true,
1343
1331
  openWorldHint: true,
1344
1332
  category: "env",
1345
1333
  },
1346
- }, async ({ action, domains, }) => {
1347
- try {
1348
- const cloudbase = await getManager();
1349
- let result;
1350
- switch (action) {
1351
- case "create":
1352
- result = await cloudbase.env.createEnvDomain(domains);
1353
- (0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
1354
- break;
1355
- case "delete":
1356
- result = await cloudbase.env.deleteEnvDomain(domains);
1357
- (0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
1358
- break;
1359
- default:
1360
- throw new Error(`不支持的操作类型: ${action}`);
1334
+ };
1335
+ server.registerTool?.("queryEnv", queryEnvToolSchema, queryEnvHandler);
1336
+ // 向后兼容:envQuery 作为 queryEnv 的别名注册
1337
+ server.registerTool?.("envQuery", queryEnvToolSchema, queryEnvHandler);
1338
+ // envDomainManagement - 环境域名管理(合并 createEnvDomain + deleteEnvDomain)
1339
+ // 微信 IDE 场景不需要域名管理
1340
+ if (server.ide !== 'wxide') {
1341
+ server.registerTool?.("envDomainManagement", {
1342
+ title: "CloudBase 环境域名管理(安全域名 / CORS 白名单)",
1343
+ 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\")。",
1344
+ inputSchema: {
1345
+ action: zod_1.z
1346
+ .enum(["create", "delete"])
1347
+ .describe("操作类型:create=添加安全域名,delete=删除安全域名"),
1348
+ domains: zod_1.z.array(zod_1.z.string()).describe("安全域名数组(格式:host:port,例如 localhost:5173 或 127.0.0.1:4173)。注意:不是自定义域名,不需要证书。"),
1349
+ },
1350
+ annotations: {
1351
+ readOnlyHint: false,
1352
+ destructiveHint: false, // 注意:delete操作虽然是破坏性的,但这里采用较宽松的标注
1353
+ idempotentHint: false,
1354
+ openWorldHint: true,
1355
+ category: "env",
1356
+ },
1357
+ }, async ({ action, domains, }) => {
1358
+ try {
1359
+ const cloudbase = await getManager();
1360
+ let result;
1361
+ switch (action) {
1362
+ case "create":
1363
+ result = await cloudbase.env.createEnvDomain(domains);
1364
+ (0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
1365
+ break;
1366
+ case "delete":
1367
+ result = await cloudbase.env.deleteEnvDomain(domains);
1368
+ (0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
1369
+ break;
1370
+ default:
1371
+ throw new Error(`不支持的操作类型: ${action}`);
1372
+ }
1373
+ return (0, tool_result_js_1.buildJsonToolResult)(buildEnvDomainManagementResult({
1374
+ action,
1375
+ domains,
1376
+ result,
1377
+ }));
1361
1378
  }
1362
- return (0, tool_result_js_1.buildJsonToolResult)(buildEnvDomainManagementResult({
1363
- action,
1364
- domains,
1365
- result,
1366
- }));
1367
- }
1368
- catch (error) {
1369
- const toolPayloadResult = (0, tool_result_js_1.toolPayloadErrorToResult)(error);
1370
- if (toolPayloadResult) {
1371
- return toolPayloadResult;
1379
+ catch (error) {
1380
+ const toolPayloadResult = (0, tool_result_js_1.toolPayloadErrorToResult)(error);
1381
+ if (toolPayloadResult) {
1382
+ return toolPayloadResult;
1383
+ }
1384
+ return {
1385
+ content: [
1386
+ {
1387
+ type: "text",
1388
+ text: `域名管理操作失败: ${error instanceof Error ? error.message : String(error)}`,
1389
+ },
1390
+ ],
1391
+ };
1372
1392
  }
1373
- return {
1374
- content: [
1375
- {
1376
- type: "text",
1377
- text: `域名管理操作失败: ${error instanceof Error ? error.message : String(error)}`,
1378
- },
1379
- ],
1380
- };
1381
- }
1382
- });
1393
+ });
1394
+ } // end: wxide guard for envDomainManagement
1383
1395
  }
1384
1396
 
1385
1397
 
@@ -1703,7 +1715,7 @@ ${envIdSection}
1703
1715
  ## 环境信息
1704
1716
  - 操作系统: ${os_1.default.type()} ${os_1.default.release()}
1705
1717
  - Node.js版本: ${process.version}
1706
- - MCP 版本:${process.env.npm_package_version || "2.21.0" || 0}
1718
+ - MCP 版本:${process.env.npm_package_version || "2.21.1-beta.1" || 0}
1707
1719
  - 系统架构: ${os_1.default.arch()}
1708
1720
  - 时间: ${new Date().toISOString()}
1709
1721
  - 请求ID: ${requestId}
@@ -1784,7 +1796,7 @@ function createWrappedHandler(name, handler, server) {
1784
1796
  requestId: (typeof error === 'object' && error && 'requestId' in error) ? error.requestId : '',
1785
1797
  ide: server.ide || process.env.INTEGRATION_IDE || ''
1786
1798
  });
1787
- const mcpVersion = true ? "2.21.0" : 0;
1799
+ const mcpVersion = true ? "2.21.1-beta.1" : 0;
1788
1800
  const requestIdSuffix = requestId ? `\n🆔 RequestId: ${requestId}` : '';
1789
1801
  const enhancedErrorMessage = `${errorMessage}${requestIdSuffix}\n\n📦 CloudBase MCP v${mcpVersion}\n🔗 遇到问题?请复制以下链接到浏览器打开\n即可自动携带错误详情快速创建 GitHub Issue:\n${issueLink}`;
1790
1802
  // 创建新的错误对象,保持原有的错误类型但更新消息
@@ -1990,10 +2002,19 @@ function registerDatabase(server) {
1990
2002
  (0, databaseSQL_js_1.registerSQLDatabaseTools)(server);
1991
2003
  (0, dataModel_js_1.registerDataModelTools)(server);
1992
2004
  }
2005
+ function registerNoSQLDatabase(server) {
2006
+ const region = server.cloudBaseOptions?.region || process.env.TCB_REGION;
2007
+ if (!(0, tencent_cloud_js_1.isInternationalRegion)(region)) {
2008
+ (0, databaseNoSQL_js_1.registerDatabaseTools)(server);
2009
+ }
2010
+ }
1993
2011
  // 可用插件映射
1994
2012
  const AVAILABLE_PLUGINS = {
1995
2013
  env: { name: "env", register: env_js_1.registerEnvTools },
1996
2014
  database: { name: "database", register: registerDatabase },
2015
+ "database-nosql": { name: "database-nosql", register: registerNoSQLDatabase },
2016
+ "database-sql": { name: "database-sql", register: databaseSQL_js_1.registerSQLDatabaseTools },
2017
+ "data-model": { name: "data-model", register: dataModel_js_1.registerDataModelTools },
1997
2018
  functions: { name: "functions", register: functions_js_1.registerFunctionTools },
1998
2019
  hosting: { name: "hosting", register: hosting_js_1.registerHostingTools },
1999
2020
  storage: { name: "storage", register: storage_js_1.registerStorageTools },
@@ -2081,7 +2102,7 @@ function parseEnabledPlugins(pluginsEnabled, pluginsDisabled) {
2081
2102
  * await server.connect(transport);
2082
2103
  */
2083
2104
  async function createCloudBaseMcpServer(options) {
2084
- const { name = "cloudbase-mcp", version = "1.0.0", enableTelemetry = true, cloudBaseOptions, authOptions, cloudMode = false, ide, logger, pluginsEnabled, pluginsDisabled, } = options ?? {};
2105
+ const { name = "cloudbase-mcp", version = "1.0.0", enableTelemetry = true, cloudBaseOptions, authOptions, cloudMode = false, ide, logger, pluginsEnabled, pluginsDisabled, pluginOptions, } = options ?? {};
2085
2106
  // Enable cloud mode if specified
2086
2107
  if (cloudMode) {
2087
2108
  (0, cloud_mode_js_1.enableCloudMode)();
@@ -2096,20 +2117,31 @@ async function createCloudBaseMcpServer(options) {
2096
2117
  ...(ide === "CodeBuddy" ? { logging: {} } : {}),
2097
2118
  },
2098
2119
  });
2120
+ // 初始化 toolDefs,用于外部提取工具列表(如微信 IDE)
2121
+ server.toolDefs = [];
2099
2122
  const originalRegisterTool = server.registerTool.bind(server);
2100
- server.registerTool = ((name, meta, handler) => originalRegisterTool(name, meta, async (args) => {
2101
- try {
2102
- return await handler(args);
2103
- }
2104
- catch (error) {
2105
- if ((0, tool_result_js_1.isToolPayloadError)(error)) {
2106
- // 在结构化错误返回中注入 MCP 版本号
2107
- const payload = { ...error.payload, mcpVersion: version };
2108
- return (0, tool_result_js_1.buildJsonToolResult)(payload);
2123
+ server.registerTool = ((name, meta, handler) => {
2124
+ // 同步记录到 toolDefs
2125
+ server.toolDefs.push({
2126
+ name,
2127
+ description: meta?.description ?? meta?.title ?? '',
2128
+ inputSchema: meta?.inputSchema ?? {},
2129
+ handler,
2130
+ });
2131
+ return originalRegisterTool(name, meta, async (args) => {
2132
+ try {
2133
+ return await handler(args);
2109
2134
  }
2110
- throw error;
2111
- }
2112
- }));
2135
+ catch (error) {
2136
+ if ((0, tool_result_js_1.isToolPayloadError)(error)) {
2137
+ // 在结构化错误返回中注入 MCP 版本号
2138
+ const payload = { ...error.payload, mcpVersion: version };
2139
+ return (0, tool_result_js_1.buildJsonToolResult)(payload);
2140
+ }
2141
+ throw error;
2142
+ }
2143
+ });
2144
+ });
2113
2145
  // Only set logging handler if logging capability is declared
2114
2146
  if (ide === "CodeBuddy") {
2115
2147
  server.server.setRequestHandler(types_js_1.SetLevelRequestSchema, (request, extra) => {
@@ -2124,6 +2156,10 @@ async function createCloudBaseMcpServer(options) {
2124
2156
  if (authOptions) {
2125
2157
  server.authOptions = authOptions;
2126
2158
  }
2159
+ // Store pluginOptions in server instance for plugins to access
2160
+ if (pluginOptions) {
2161
+ server.pluginOptions = pluginOptions;
2162
+ }
2127
2163
  // Store ide in server instance for telemetry
2128
2164
  if (ide) {
2129
2165
  server.ide = ide;
@@ -2231,8 +2267,8 @@ function registerLogTools(server) {
2231
2267
  const cloudBaseOptions = server.cloudBaseOptions;
2232
2268
  const getManager = () => (0, cloudbase_manager_js_1.getCloudBaseManager)({ cloudBaseOptions });
2233
2269
  server.registerTool?.("queryLogs", {
2234
- title: "查询日志服务",
2235
- description: "日志域统一只读入口。支持检查日志服务状态并搜索 CLS 日志。" +
2270
+ title: "查询 CloudBase 日志服务",
2271
+ description: "CloudBase 日志域统一只读入口。支持检查日志服务状态并搜索 CLS 日志。" +
2236
2272
  "\n\n**重要区分**:" +
2237
2273
  "\n- 查询云函数日志:使用 `queryFunctions(action=\"listFunctionLogs\", functionName=\"xxx\")`" +
2238
2274
  "\n- 查询 CLS 日志(跨服务日志聚合):使用本工具 `queryLogs(action=\"searchLogs\")`" +
@@ -3284,7 +3320,7 @@ if (shouldUseConsole()) {
3284
3320
  stderrLevels: ['error', 'warn', 'info', 'debug'], // All logs go to stderr
3285
3321
  }));
3286
3322
  }
3287
- if (!(0, cloud_mode_js_1.isCloudMode)()) {
3323
+ if (!(0, cloud_mode_js_1.isCloudMode)() && process.env.CLOUDBASE_MCP_DISABLE_LOG_FILE !== 'true') {
3288
3324
  // File transport with daily rotation
3289
3325
  transports.push(new DailyRotateFile({
3290
3326
  dirname: logDir,
@@ -3703,8 +3739,9 @@ async function getDatabaseInstanceId(options) {
3703
3739
  async function getCloudBaseManager(options = {}) {
3704
3740
  const { requireEnvId = true, cloudBaseOptions, authStrategy = 'fail_fast', } = options;
3705
3741
  const hasDirectCredentials = !!(cloudBaseOptions?.secretId && cloudBaseOptions?.secretKey);
3706
- // 如果传入了完整凭据,优先使用显式 CloudBase 配置
3707
- if (cloudBaseOptions && hasDirectCredentials) {
3742
+ const hasRequestFn = !!(cloudBaseOptions?.requestFn);
3743
+ // 如果传入了完整凭据或 requestFn,优先使用显式 CloudBase 配置
3744
+ if (cloudBaseOptions && (hasDirectCredentials || hasRequestFn)) {
3708
3745
  let resolvedEnvId = cloudBaseOptions.envId;
3709
3746
  if (requireEnvId && !resolvedEnvId) {
3710
3747
  const envCandidates = await listAvailableEnvCandidates({ cloudBaseOptions });
@@ -4018,6 +4055,13 @@ async function callNoSqlContentApi(options) {
4018
4055
  instanceIdSource: "envId",
4019
4056
  requestId: result?.RequestId,
4020
4057
  });
4058
+ // 检查 API 层返回的业务错误(如集合不存在)并抛出
4059
+ if (result?.Error) {
4060
+ const err = new Error(`${result.Error.Code}: ${result.Error.Message}`);
4061
+ err.code = result.Error.Code;
4062
+ err.requestId = result.RequestId;
4063
+ throw err;
4064
+ }
4021
4065
  return result;
4022
4066
  }
4023
4067
  catch (error) {
@@ -4031,7 +4075,7 @@ async function callNoSqlContentApi(options) {
4031
4075
  throw error;
4032
4076
  }
4033
4077
  }
4034
- async function waitForCollectionReady({ cloudbase, collectionName, logger, timeoutMs = COLLECTION_READY_TIMEOUT_MS, pollIntervalMs = COLLECTION_READY_POLL_INTERVAL_MS, }) {
4078
+ async function waitForCollectionReady({ cloudbase, collectionName, logger, cloudBaseOptions, timeoutMs = COLLECTION_READY_TIMEOUT_MS, pollIntervalMs = COLLECTION_READY_POLL_INTERVAL_MS, }) {
4035
4079
  const startedAt = Date.now();
4036
4080
  const deadline = startedAt + timeoutMs;
4037
4081
  let lastError;
@@ -4045,17 +4089,40 @@ async function waitForCollectionReady({ cloudbase, collectionName, logger, timeo
4045
4089
  });
4046
4090
  while (Date.now() <= deadline) {
4047
4091
  try {
4048
- // 直接用 commonService 调用 DescribeTable 检查集合是否存在,避免 SDK lazyInit → DescribeEnvs
4049
- const envId = await (0, cloudbase_manager_js_1.getEnvId)();
4050
- const result = await cloudbase.commonService("tcb", "2018-06-08").call({
4051
- Action: "DescribeTable",
4092
+ // 用 PutItem 探测集合是否真正就绪(DescribeTable 可能误报),插入一个空占位文档
4093
+ // 如果成功,立即删除该文档;如果仍 ResourceNotFound,继续等待
4094
+ const envId = await (0, cloudbase_manager_js_1.getEnvId)(cloudBaseOptions);
4095
+ const probeDoc = JSON.stringify({ _readyProbe: true, _ts: Date.now() });
4096
+ const probeResult = await cloudbase.commonService("tcb", "2018-06-08").call({
4097
+ Action: "PutItem",
4052
4098
  Param: {
4053
4099
  EnvId: envId,
4054
4100
  TableName: collectionName,
4101
+ MgoDocs: [probeDoc],
4055
4102
  },
4056
4103
  });
4057
- (0, cloudbase_manager_js_1.logCloudBaseResult)(logger, result);
4058
- // DescribeTable 成功返回即表示集合存在
4104
+ (0, cloudbase_manager_js_1.logCloudBaseResult)(logger, probeResult);
4105
+ if (probeResult?.Error) {
4106
+ // 集合还未就绪,继续轮询
4107
+ throw new Error(probeResult.Error.Message);
4108
+ }
4109
+ // 集合就绪,清理探测文档
4110
+ if (Array.isArray(probeResult?.InsertedIds) && probeResult.InsertedIds.length > 0) {
4111
+ try {
4112
+ await cloudbase.commonService("tcb", "2018-06-08").call({
4113
+ Action: "DeleteItem",
4114
+ Param: {
4115
+ EnvId: envId,
4116
+ TableName: collectionName,
4117
+ MgoQuery: JSON.stringify({ _readyProbe: true }),
4118
+ MgoIsMulti: true,
4119
+ },
4120
+ });
4121
+ }
4122
+ catch {
4123
+ // 清理失败不影响主流程
4124
+ }
4125
+ }
4059
4126
  logger?.({
4060
4127
  type: "toolInfo",
4061
4128
  toolName: "writeNoSqlDatabaseStructure",
@@ -4094,8 +4161,8 @@ function registerDatabaseTools(server) {
4094
4161
  const getManager = () => (0, cloudbase_manager_js_1.getCloudBaseManager)({ cloudBaseOptions });
4095
4162
  // readNoSqlDatabaseStructure
4096
4163
  server.registerTool?.("readNoSqlDatabaseStructure", {
4097
- title: "读取 NoSQL 数据库结构",
4098
- description: "读取 NoSQL 数据库集合与索引结构,支持列出集合、查看集合详情、列出索引以及检查索引是否存在。本工具为服务端管理工具,用于管理端查询数据库结构,不用于编写客户端代码。",
4164
+ title: "读取 CloudBase NoSQL 数据库结构",
4165
+ description: "读取 CloudBase NoSQL 数据库集合与索引结构,支持列出集合、查看集合详情、列出索引以及检查索引是否存在。本工具为服务端管理工具,用于管理端查询数据库结构,不用于编写客户端代码。",
4099
4166
  inputSchema: {
4100
4167
  action: zod_1.z.enum([
4101
4168
  "listCollections",
@@ -4282,8 +4349,8 @@ checkIndex: 检查指定索引是否存在`),
4282
4349
  });
4283
4350
  // writeNoSqlDatabaseStructure
4284
4351
  server.registerTool?.("writeNoSqlDatabaseStructure", {
4285
- title: "创建并管理 NoSQL 数据库集合",
4286
- description: "创建、删除和管理 NoSQL 数据库集合(collection)。支持创建新集合、删除现有集合,以及通过 updateCollection 的 updateOptions.CreateIndexes / updateOptions.DropIndexes 添加索引和删除索引。当需要新建集合时,使用 action=createCollection。本工具为服务端管理工具,用于管理端操作集合和索引结构,不用于编写客户端代码。",
4352
+ title: "创建并管理 CloudBase NoSQL 数据库集合",
4353
+ description: "创建、删除和管理 CloudBase NoSQL 数据库集合(collection)。支持创建新集合、删除现有集合,以及通过 updateCollection 的 updateOptions.CreateIndexes / updateOptions.DropIndexes 添加索引和删除索引。当需要新建集合时,使用 action=createCollection。本工具为服务端管理工具,用于管理端操作集合和索引结构,不用于编写客户端代码。",
4287
4354
  inputSchema: {
4288
4355
  action: zod_1.z.enum([
4289
4356
  "createCollection",
@@ -4343,8 +4410,14 @@ deleteCollection: 删除集合`),
4343
4410
  Action: "DescribeTable",
4344
4411
  Param: { EnvId: envId, TableName: collectionName },
4345
4412
  });
4346
- collectionExists = true;
4347
- existsRequestId = descResult?.RequestId ?? "";
4413
+ if (descResult?.Error) {
4414
+ // 集合不存在(ResourceNotFound)或其他错误,继续创建
4415
+ existsRequestId = descResult.RequestId ?? "";
4416
+ }
4417
+ else {
4418
+ collectionExists = true;
4419
+ existsRequestId = descResult?.RequestId ?? "";
4420
+ }
4348
4421
  }
4349
4422
  catch (e) {
4350
4423
  existsRequestId = e?.requestId ?? "";
@@ -4377,6 +4450,7 @@ deleteCollection: 删除集合`),
4377
4450
  cloudbase,
4378
4451
  collectionName,
4379
4452
  logger: server.logger,
4453
+ cloudBaseOptions: server.cloudBaseOptions,
4380
4454
  });
4381
4455
  return {
4382
4456
  content: [
@@ -4459,8 +4533,8 @@ deleteCollection: 删除集合`),
4459
4533
  });
4460
4534
  // readNoSqlDatabaseContent
4461
4535
  server.registerTool?.("readNoSqlDatabaseContent", {
4462
- title: "查询并获取 NoSQL 数据库数据记录",
4463
- description: "查询并获取 NoSQL 数据库数据记录。⚠️ 本工具为服务端管理工具,用于管理端/运维端查询。当任务要求编写客户端应用代码时(例如「用 JS SDK 读取数据」),不应使用本工具,而应在项目代码中编写 @cloudbase/js-sdk 客户端代码(如 db.collection().where().get())。",
4536
+ title: "查询并获取 CloudBase NoSQL 数据库数据记录",
4537
+ description: "查询 CloudBase NoSQL 数据库中的数据记录。支持按条件筛选、分页、排序,适用于管理端数据查询与运维。",
4464
4538
  inputSchema: {
4465
4539
  collectionName: zod_1.z.string().describe("集合名称"),
4466
4540
  instanceId: zod_1.z
@@ -4546,8 +4620,10 @@ deleteCollection: 删除集合`),
4546
4620
  });
4547
4621
  // writeNoSqlDatabaseContent
4548
4622
  server.registerTool?.("writeNoSqlDatabaseContent", {
4549
- title: "修改 NoSQL 数据库数据记录",
4550
- 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)` 读取命中不到。",
4623
+ title: "修改 CloudBase NoSQL 数据库数据记录",
4624
+ description: "修改 CloudBase NoSQL 数据库中的数据记录。支持插入、更新(含 $set/$inc/$push 等操作符)、删除、upsert 等操作,适用于管理端数据写入与运维。" +
4625
+ "⚠️ 服务端写入不含 _openid:若集合依赖客户端 SDK(@cloudbase/js-sdk 或微信小程序 wx.cloud.database())的行级安全规则(如 doc._openid == auth.openid),服务端写入时需手动补充 _openid 字段,否则客户端将无法读取到该数据。" +
4626
+ "⚠️ 部分更新嵌套字段须使用点号路径,如 `$set: {\"shipping.city\": \"guangzhou\"}`,直接传嵌套对象会覆盖整个字段。",
4551
4627
  inputSchema: {
4552
4628
  action: zod_1.z
4553
4629
  .enum(["insert", "update", "delete"])
@@ -6240,99 +6316,6 @@ async function downloadResources() {
6240
6316
  return resourceDownloadPromise;
6241
6317
  }
6242
6318
  async function registerRagTools(server) {
6243
- // 联网搜索
6244
- server.registerTool?.("searchWeb", {
6245
- title: "联网搜索",
6246
- description: "使用联网来进行信息检索,如查询最新的新闻、文章、股价、天气等。支持自然语言查询,也可以直接输入网址获取网页内容",
6247
- inputSchema: {
6248
- query: zod_1.z.string().describe("搜索关键词、问题或网址,支持自然语言"),
6249
- },
6250
- annotations: {
6251
- readOnlyHint: true,
6252
- openWorldHint: true,
6253
- category: "web",
6254
- },
6255
- }, async ({ query }) => {
6256
- try {
6257
- // 使用混元进行联网搜索
6258
- const signInRes = await fetch("https://tcb-advanced-a656fc.api.tcloudbasegateway.com/auth/v1/signin/anonymously", {
6259
- method: "POST",
6260
- headers: {
6261
- "Content-Type": "application/json",
6262
- Accept: "application/json",
6263
- "x-device-id": "cloudbase-ai-toolkit",
6264
- },
6265
- body: safeStringify({}),
6266
- });
6267
- const { access_token } = await signInRes.json();
6268
- // 调用混元API进行联网搜索
6269
- const searchRes = await fetch("https://tcb-advanced-a656fc.api.tcloudbasegateway.com/v1/ai/hunyuan-beta/openapi/v1/chat/completions", {
6270
- method: "POST",
6271
- headers: {
6272
- "Content-Type": "application/json",
6273
- Authorization: `Bearer ${access_token}`,
6274
- },
6275
- body: safeStringify({
6276
- model: "hunyuan",
6277
- messages: [
6278
- {
6279
- role: "user",
6280
- content: `你好,你将扮演一个知识库的角色,联网查询到问题的答案之后回答给我`,
6281
- },
6282
- {
6283
- role: "assistant",
6284
- content: "好的",
6285
- },
6286
- {
6287
- role: "user",
6288
- content: query,
6289
- },
6290
- ],
6291
- enable_enhancement: true,
6292
- search_info: true,
6293
- enable_speed_search: true,
6294
- force_search_enhancement: true,
6295
- }),
6296
- });
6297
- const result = await searchRes.json();
6298
- if (result.error) {
6299
- throw new Error(result.error.message || "联网搜索失败");
6300
- }
6301
- const content = result.choices?.[0]?.message?.content || "";
6302
- const searchResults = result.search_info?.search_results || [];
6303
- return {
6304
- content: [
6305
- {
6306
- type: "text",
6307
- text: safeStringify({
6308
- type: "web_search",
6309
- content: content,
6310
- search_results: searchResults.map((item) => ({
6311
- title: item.title,
6312
- url: item.url,
6313
- snippet: item.snippet,
6314
- })),
6315
- status: "success",
6316
- }),
6317
- },
6318
- ],
6319
- };
6320
- }
6321
- catch (error) {
6322
- return {
6323
- content: [
6324
- {
6325
- type: "text",
6326
- text: safeStringify({
6327
- type: "error",
6328
- message: error instanceof Error ? error.message : "联网搜索失败",
6329
- status: "error",
6330
- }),
6331
- },
6332
- ],
6333
- };
6334
- }
6335
- });
6336
6319
  let openapis = [];
6337
6320
  let skills = [];
6338
6321
  let fallbackSkillsRoot;
@@ -7344,6 +7327,7 @@ async function resolveStoragePublicAccess(params) {
7344
7327
  function registerStorageTools(server) {
7345
7328
  // 获取 cloudBaseOptions,如果没有则为 undefined
7346
7329
  const cloudBaseOptions = server.cloudBaseOptions;
7330
+ const storageOverrides = server.pluginOptions?.storage;
7347
7331
  // 创建闭包函数来获取 CloudBase Manager
7348
7332
  const getManager = () => (0, cloudbase_manager_js_1.getCloudBaseManager)({ cloudBaseOptions });
7349
7333
  // Tool 1: queryStorage - 查询存储信息(只读操作)
@@ -7365,7 +7349,14 @@ function registerStorageTools(server) {
7365
7349
  const storageService = manager.storage;
7366
7350
  switch (input.action) {
7367
7351
  case 'list': {
7368
- const result = await storageService.listDirectoryFiles(input.cloudPath);
7352
+ let files;
7353
+ if (storageOverrides?.listFiles) {
7354
+ files = await storageOverrides.listFiles({ cloudPath: input.cloudPath });
7355
+ }
7356
+ else {
7357
+ const result = await storageService.listDirectoryFiles(input.cloudPath);
7358
+ files = result || [];
7359
+ }
7369
7360
  return {
7370
7361
  content: [
7371
7362
  {
@@ -7375,17 +7366,23 @@ function registerStorageTools(server) {
7375
7366
  data: {
7376
7367
  action: 'list',
7377
7368
  cloudPath: input.cloudPath,
7378
- files: result || [],
7379
- totalCount: result?.length || 0
7369
+ files,
7370
+ totalCount: files.length
7380
7371
  },
7381
- message: `Successfully listed ${result?.length || 0} files in directory '${input.cloudPath}'`
7372
+ message: `Successfully listed ${files.length} files in directory '${input.cloudPath}'`
7382
7373
  }, null, 2)
7383
7374
  }
7384
7375
  ]
7385
7376
  };
7386
7377
  }
7387
7378
  case 'info': {
7388
- const result = await storageService.getFileInfo(input.cloudPath);
7379
+ let fileInfo;
7380
+ if (storageOverrides?.getFileInfo) {
7381
+ fileInfo = await storageOverrides.getFileInfo({ cloudPath: input.cloudPath });
7382
+ }
7383
+ else {
7384
+ fileInfo = await storageService.getFileInfo(input.cloudPath);
7385
+ }
7389
7386
  return {
7390
7387
  content: [
7391
7388
  {
@@ -7395,7 +7392,7 @@ function registerStorageTools(server) {
7395
7392
  data: {
7396
7393
  action: 'info',
7397
7394
  cloudPath: input.cloudPath,
7398
- fileInfo: result
7395
+ fileInfo
7399
7396
  },
7400
7397
  message: `Successfully retrieved file info for '${input.cloudPath}'`
7401
7398
  }, null, 2)
@@ -7439,10 +7436,15 @@ function registerStorageTools(server) {
7439
7436
  const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), STORAGE_READ_TEMP_PREFIX));
7440
7437
  const localPath = path.join(tempDir, getStorageTempFileName(input.cloudPath));
7441
7438
  try {
7442
- await storageService.downloadFile({
7443
- cloudPath: input.cloudPath,
7444
- localPath
7445
- });
7439
+ if (storageOverrides?.downloadFile) {
7440
+ await storageOverrides.downloadFile({ cloudPath: input.cloudPath, localPath });
7441
+ }
7442
+ else {
7443
+ await storageService.downloadFile({
7444
+ cloudPath: input.cloudPath,
7445
+ localPath
7446
+ });
7447
+ }
7446
7448
  const buffer = await fs.readFile(localPath);
7447
7449
  const decoded = decodeInlineTextContent(buffer);
7448
7450
  return {
@@ -7497,22 +7499,32 @@ function registerStorageTools(server) {
7497
7499
  switch (input.action) {
7498
7500
  case 'upload': {
7499
7501
  if (input.isDirectory) {
7500
- await storageService.uploadDirectory({
7501
- localPath: input.localPath,
7502
- cloudPath: input.cloudPath,
7503
- onProgress: (progressData) => {
7504
- console.log("Upload directory progress:", progressData);
7505
- }
7506
- });
7502
+ if (storageOverrides?.uploadDirectory) {
7503
+ await storageOverrides.uploadDirectory({ localPath: input.localPath, cloudPath: input.cloudPath });
7504
+ }
7505
+ else {
7506
+ await storageService.uploadDirectory({
7507
+ localPath: input.localPath,
7508
+ cloudPath: input.cloudPath,
7509
+ onProgress: (progressData) => {
7510
+ console.log("Upload directory progress:", progressData);
7511
+ }
7512
+ });
7513
+ }
7507
7514
  }
7508
7515
  else {
7509
- await storageService.uploadFile({
7510
- localPath: input.localPath,
7511
- cloudPath: input.cloudPath,
7512
- onProgress: (progressData) => {
7513
- console.log("Upload file progress:", progressData);
7514
- }
7515
- });
7516
+ if (storageOverrides?.uploadFile) {
7517
+ await storageOverrides.uploadFile({ localPath: input.localPath, cloudPath: input.cloudPath });
7518
+ }
7519
+ else {
7520
+ await storageService.uploadFile({
7521
+ localPath: input.localPath,
7522
+ cloudPath: input.cloudPath,
7523
+ onProgress: (progressData) => {
7524
+ console.log("Upload file progress:", progressData);
7525
+ }
7526
+ });
7527
+ }
7516
7528
  }
7517
7529
  const fileUrls = await storageService.getTemporaryUrl([{
7518
7530
  cloudPath: input.cloudPath,
@@ -7548,16 +7560,26 @@ function registerStorageTools(server) {
7548
7560
  }
7549
7561
  case 'download': {
7550
7562
  if (input.isDirectory) {
7551
- await storageService.downloadDirectory({
7552
- cloudPath: input.cloudPath,
7553
- localPath: input.localPath
7554
- });
7563
+ if (storageOverrides?.downloadDirectory) {
7564
+ await storageOverrides.downloadDirectory({ cloudPath: input.cloudPath, localPath: input.localPath });
7565
+ }
7566
+ else {
7567
+ await storageService.downloadDirectory({
7568
+ cloudPath: input.cloudPath,
7569
+ localPath: input.localPath
7570
+ });
7571
+ }
7555
7572
  }
7556
7573
  else {
7557
- await storageService.downloadFile({
7558
- cloudPath: input.cloudPath,
7559
- localPath: input.localPath
7560
- });
7574
+ if (storageOverrides?.downloadFile) {
7575
+ await storageOverrides.downloadFile({ cloudPath: input.cloudPath, localPath: input.localPath });
7576
+ }
7577
+ else {
7578
+ await storageService.downloadFile({
7579
+ cloudPath: input.cloudPath,
7580
+ localPath: input.localPath
7581
+ });
7582
+ }
7561
7583
  }
7562
7584
  return {
7563
7585
  content: [
@@ -7593,10 +7615,20 @@ function registerStorageTools(server) {
7593
7615
  };
7594
7616
  }
7595
7617
  if (input.isDirectory) {
7596
- await storageService.deleteDirectory(input.cloudPath);
7618
+ if (storageOverrides?.deleteDirectory) {
7619
+ await storageOverrides.deleteDirectory({ cloudPath: input.cloudPath });
7620
+ }
7621
+ else {
7622
+ await storageService.deleteDirectory(input.cloudPath);
7623
+ }
7597
7624
  }
7598
7625
  else {
7599
- await storageService.deleteFile([input.cloudPath]);
7626
+ if (storageOverrides?.deleteFiles) {
7627
+ await storageOverrides.deleteFiles({ cloudPaths: [input.cloudPath] });
7628
+ }
7629
+ else {
7630
+ await storageService.deleteFile([input.cloudPath]);
7631
+ }
7600
7632
  }
7601
7633
  return {
7602
7634
  content: [
@@ -9275,7 +9307,7 @@ class TelemetryReporter {
9275
9307
  const nodeVersion = process.version; // Node.js版本
9276
9308
  const arch = os_1.default.arch(); // 系统架构
9277
9309
  // 从构建时注入的版本号获取MCP版本信息
9278
- const mcpVersion = process.env.npm_package_version || "2.21.0" || 0;
9310
+ const mcpVersion = process.env.npm_package_version || "2.21.1-beta.1" || 0;
9279
9311
  return {
9280
9312
  userAgent: `${osType} ${osRelease} ${arch} ${nodeVersion} CloudBase-MCP/${mcpVersion}`,
9281
9313
  deviceId: this.deviceId,
@@ -9666,6 +9698,7 @@ exports.MANAGE_FUNCTION_ACTIONS = [
9666
9698
  "attachLayer",
9667
9699
  "detachLayer",
9668
9700
  "updateFunctionLayers",
9701
+ "incrementalDeployFunction", // 增量部署,需通过 pluginOptions.functions 注入实现
9669
9702
  ];
9670
9703
  const VPC_SCHEMA = zod_1.z.object({
9671
9704
  vpcId: zod_1.z.string(),
@@ -9847,6 +9880,7 @@ function wrapFunctionOperationError(operation, functionName, functionRootPath, e
9847
9880
  }
9848
9881
  function registerFunctionTools(server) {
9849
9882
  const cloudBaseOptions = server.cloudBaseOptions;
9883
+ const deployOverrides = server.pluginOptions?.functions;
9850
9884
  const getManager = () => (0, cloudbase_manager_js_1.getCloudBaseManager)({ cloudBaseOptions });
9851
9885
  const buildEnvelope = (data, message, nextActions) => ({
9852
9886
  success: true,
@@ -10211,6 +10245,16 @@ function registerFunctionTools(server) {
10211
10245
  ensureActionAllowedInCloudMode(input);
10212
10246
  switch (input.action) {
10213
10247
  case "createFunction": {
10248
+ if (deployOverrides?.createFunction) {
10249
+ const result = await deployOverrides.createFunction({
10250
+ functionName: String(input.func?.name ?? input.functionName ?? ''),
10251
+ functionRootPath: input.functionRootPath ?? '',
10252
+ runtime: input.func?.runtime,
10253
+ force: input.force,
10254
+ installDependency: input.func?.installDependency,
10255
+ });
10256
+ return buildEnvelope({ action: input.action, result }, '云函数部署成功(override)');
10257
+ }
10214
10258
  if (!input.func?.name || typeof input.func.name !== "string") {
10215
10259
  throw new Error("createFunction 操作时,func.name 参数是必需的");
10216
10260
  }
@@ -10298,6 +10342,15 @@ function registerFunctionTools(server) {
10298
10342
  }, message, nextActions);
10299
10343
  }
10300
10344
  case "updateFunctionCode": {
10345
+ if (deployOverrides?.updateFunctionCode) {
10346
+ const result = await deployOverrides.updateFunctionCode({
10347
+ functionName: input.functionName ?? '',
10348
+ functionRootPath: input.functionRootPath ?? '',
10349
+ force: input.force,
10350
+ installDependency: input.func?.installDependency,
10351
+ });
10352
+ return buildEnvelope({ action: input.action, result }, '云函数代码更新成功(override)');
10353
+ }
10301
10354
  if (!input.functionName) {
10302
10355
  throw new Error("updateFunctionCode 操作时,functionName 参数是必需的");
10303
10356
  }
@@ -10631,6 +10684,19 @@ function registerFunctionTools(server) {
10631
10684
  ]);
10632
10685
  }
10633
10686
  default:
10687
+ // incrementalDeployFunction:无默认实现,必须通过 pluginOptions 注入
10688
+ if (input.action === 'incrementalDeployFunction') {
10689
+ const fn = deployOverrides?.incrementalDeployFunction;
10690
+ if (!fn) {
10691
+ throw new Error('incrementalDeployFunction 需要通过 pluginOptions.functions.incrementalDeployFunction 注入实现(仅在支持的 IDE 环境中可用)');
10692
+ }
10693
+ const result = await fn({
10694
+ functionName: input.functionName ?? '',
10695
+ functionRootPath: input.functionRootPath ?? '',
10696
+ incrementalFile: input.incrementalFile ?? '',
10697
+ });
10698
+ return buildEnvelope({ action: input.action, result }, '云函数增量部署成功');
10699
+ }
10634
10700
  throw new Error(`不支持的操作类型: ${input.action}`);
10635
10701
  }
10636
10702
  };
@@ -10703,7 +10769,7 @@ function registerFunctionTools(server) {
10703
10769
  inputSchema: {
10704
10770
  action: zod_1.z
10705
10771
  .enum(exports.MANAGE_FUNCTION_ACTIONS)
10706
- .describe("写操作类型,例如 createFunction、updateFunctionCode、invokeFunction、deleteFunction、" +
10772
+ .describe("写操作类型,例如 createFunction、updateFunctionCode、incrementalDeployFunction、invokeFunction、deleteFunction、" +
10707
10773
  "createFunctionTrigger(定时任务 / cron / timer)、deleteFunctionTrigger、attachLayer、detachLayer"),
10708
10774
  func: CREATE_FUNCTION_SCHEMA.optional().describe("createFunction 操作的函数配置"),
10709
10775
  functionRootPath: zod_1.z.string().optional().describe("创建或更新函数代码时默认推荐的本地目录方式。" +
@@ -10739,6 +10805,7 @@ function registerFunctionTools(server) {
10739
10805
  .describe("updateFunctionLayers 的目标层列表,顺序即最终顺序"),
10740
10806
  codeSecret: zod_1.z.string().optional().describe("层绑定时的代码保护密钥"),
10741
10807
  confirm: zod_1.z.boolean().optional().describe("危险操作确认开关。deleteFunction、deleteFunctionTrigger、deleteLayerVersion、detachLayer 等删除类操作需要显式传入 confirm=true"),
10808
+ incrementalFile: zod_1.z.string().optional().describe("incrementalDeployFunction 增量部署时的变更文件路径"),
10742
10809
  },
10743
10810
  annotations: {
10744
10811
  readOnlyHint: false,
@@ -11845,7 +11912,7 @@ function registerSetupTools(server) {
11845
11912
  server.registerTool("downloadTemplate", {
11846
11913
  title: "下载项目模板",
11847
11914
  description: `自动下载并部署CloudBase项目模板。
11848
- **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)`,
11915
+ **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)`,
11849
11916
  inputSchema: {
11850
11917
  template: zod_1.z
11851
11918
  .enum(["react", "vue", "miniprogram", "uniapp", "rules"])
@@ -13292,13 +13359,16 @@ async function resolveHostingStaticDomain(cloudbase, logger) {
13292
13359
  return undefined;
13293
13360
  }
13294
13361
  }
13295
- async function assertHostingUploadEnvironmentReady(cloudbase, cloudBaseOptions, logger) {
13362
+ // Returns the first hosting store record from DescribeStaticStore, which is
13363
+ // the authoritative source for Mini Program-sourced environments (those envs
13364
+ // do not populate StaticStorages in DescribeEnvs / getEnvInfo).
13365
+ // Throws when no valid store is found so upload can fail fast with a clear msg.
13366
+ async function getHostingStoreOrThrow(cloudbase, cloudBaseOptions, logger) {
13296
13367
  const envId = await (0, cloudbase_manager_js_1.getEnvId)(cloudBaseOptions);
13297
- const envInfo = await cloudbase.env.getEnvInfo();
13298
- (0, cloudbase_manager_js_1.logCloudBaseResult)(logger, envInfo);
13299
- const staticStorage = envInfo.EnvInfo?.StaticStorages?.[0];
13300
- if (staticStorage?.Bucket) {
13301
- return;
13368
+ const result = await callTcbHostingAction(cloudbase, 'DescribeStaticStore', { EnvId: envId }, logger);
13369
+ const hostingInfo = extractStaticStores(result);
13370
+ if (hostingInfo.length > 0 && hostingInfo[0].Bucket) {
13371
+ return hostingInfo[0];
13302
13372
  }
13303
13373
  throw new Error(`当前环境 ${envId} 未发现静态托管资源配置,无法上传文件。请先确认 MCP 已绑定到已开通静态托管的 CloudBase 环境;如需切换环境,请调用 auth(action="set_env", envId="目标环境ID") 后重试。`);
13304
13374
  }
@@ -13506,8 +13576,9 @@ function registerHostingTools(server) {
13506
13576
  throw new Error('manageHosting(action="upload") 需要提供 localPath + cloudPath,或提供 files 多文件上传列表。');
13507
13577
  }
13508
13578
  let result;
13579
+ let store;
13509
13580
  try {
13510
- await assertHostingUploadEnvironmentReady(cloudbase, cloudBaseOptions, server.logger);
13581
+ store = await getHostingStoreOrThrow(cloudbase, cloudBaseOptions, server.logger);
13511
13582
  result = await cloudbase.hosting.uploadFiles({
13512
13583
  localPath: input.localPath,
13513
13584
  cloudPath: input.cloudPath,
@@ -13519,7 +13590,11 @@ function registerHostingTools(server) {
13519
13590
  throw new Error(buildUploadErrorMessage(error, input.localPath));
13520
13591
  }
13521
13592
  (0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
13522
- const staticDomain = await resolveHostingStaticDomain(cloudbase, server.logger);
13593
+ // Prefer CdnDomain from the DescribeStaticStore result we already
13594
+ // fetched; fall back to getEnvInfo for environments that populate
13595
+ // StaticDomain there but not in DescribeStaticStore.
13596
+ const cdnFromStore = (store.CdnDomain ?? store.StaticDomain);
13597
+ const staticDomain = cdnFromStore || await resolveHostingStaticDomain(cloudbase, server.logger);
13523
13598
  const accessUrl = buildHostingAccessUrl(staticDomain, input.cloudPath, input.localPath);
13524
13599
  try {
13525
13600
  const envId = await (0, cloudbase_manager_js_1.getEnvId)(cloudBaseOptions);
@@ -15921,8 +15996,8 @@ function registerSQLDatabaseTools(server) {
15921
15996
  server,
15922
15997
  };
15923
15998
  server.registerTool?.(QUERY_SQL_DATABASE, {
15924
- title: "Query SQL database state or execute read-only SQL",
15925
- description: "Query SQL database information. Supports read-only SQL execution, MySQL provisioning result lookup, MySQL task status lookup, and current instance context discovery.",
15999
+ title: "查询 CloudBase MySQL 数据库状态或执行只读 SQL",
16000
+ description: "查询 CloudBase MySQL 数据库信息。支持执行只读 SQL、查询 MySQL 开通结果、查询 MySQL 任务状态,以及获取当前实例上下文信息。",
15926
16001
  inputSchema: {
15927
16002
  action: zod_1.z
15928
16003
  .enum(QUERY_ACTIONS)
@@ -15964,8 +16039,8 @@ function registerSQLDatabaseTools(server) {
15964
16039
  }
15965
16040
  });
15966
16041
  server.registerTool?.(MANAGE_SQL_DATABASE, {
15967
- title: "Manage SQL database lifecycle or execute write SQL",
15968
- 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.",
16042
+ title: "管理 CloudBase MySQL 数据库生命周期或执行写入 SQL",
16043
+ description: "管理 CloudBase MySQL 数据库资源。支持开通 MySQL、销毁 MySQL、执行写入 SQL/DDL,以及初始化数据库 Schema。注意:必须先开通 MySQL(action=provisionMySQL,confirm=true)才能执行 runStatement 或 initializeSchema。若 MySQL 尚未开通,工具会返回 MYSQL_NOT_CREATED 并给出开通的 nextAction 提示。",
15969
16044
  inputSchema: {
15970
16045
  action: zod_1.z
15971
16046
  .enum(MANAGE_ACTIONS)