@cloudbase/cloudbase-mcp
Version:
腾讯云开发 MCP Server,通过AI提示词和MCP协议+云开发,让开发更智能、更高效,当你在Cursor/ VSCode GitHub Copilot/WinSurf/CodeBuddy/Augment Code/Claude Code等AI编程工具里写代码时,它能自动帮你生成可直接部署的前后端应用+小程序,并一键发布到腾讯云开发 CloudBase。
1,191 lines (1,154 loc) • 571 kB
JavaScript
import * as __WEBPACK_EXTERNAL_MODULE_lockfile__ from "lockfile";
import * as __WEBPACK_EXTERNAL_MODULE_open__ from "open";
import * as __WEBPACK_EXTERNAL_MODULE__cloudbase_toolbox_034e5bd0__ from "@cloudbase/toolbox";
import * as __WEBPACK_EXTERNAL_MODULE__modelcontextprotocol_sdk_types_js_70eb1363__ from "@modelcontextprotocol/sdk/types.js";
import * as __WEBPACK_EXTERNAL_MODULE__modelcontextprotocol_sdk_server_stdio_js_25848778__ from "@modelcontextprotocol/sdk/server/stdio.js";
import * as __WEBPACK_EXTERNAL_MODULE_path__ from "path";
import * as __WEBPACK_EXTERNAL_MODULE_express__ from "express";
import * as __WEBPACK_EXTERNAL_MODULE_adm_zip_aa3527d5__ from "adm-zip";
import * as __WEBPACK_EXTERNAL_MODULE_zod__ from "zod";
import * as __WEBPACK_EXTERNAL_MODULE_winston_daily_rotate_file_69928d76__ from "winston-daily-rotate-file";
import * as __WEBPACK_EXTERNAL_MODULE_http__ from "http";
import * as __WEBPACK_EXTERNAL_MODULE_https__ from "https";
import * as __WEBPACK_EXTERNAL_MODULE_net__ from "net";
import * as __WEBPACK_EXTERNAL_MODULE_fs__ from "fs";
import * as __WEBPACK_EXTERNAL_MODULE__modelcontextprotocol_sdk_server_mcp_js_45c326f0__ from "@modelcontextprotocol/sdk/server/mcp.js";
import * as __WEBPACK_EXTERNAL_MODULE_child_process__ from "child_process";
import * as __WEBPACK_EXTERNAL_MODULE_ws__ from "ws";
import * as __WEBPACK_EXTERNAL_MODULE__cloudbase_manager_node_6a52ea40__ from "@cloudbase/manager-node";
import * as __WEBPACK_EXTERNAL_MODULE_url__ from "url";
import * as __WEBPACK_EXTERNAL_MODULE__cloudbase_cals_lib_cjs_utils_mermaid_datasource_mermaid_json_transform_04ea0f14__ from "@cloudbase/cals/lib/cjs/utils/mermaid-datasource/mermaid-json-transform";
import * as __WEBPACK_EXTERNAL_MODULE_dns__ from "dns";
import * as __WEBPACK_EXTERNAL_MODULE_crypto__ from "crypto";
import * as __WEBPACK_EXTERNAL_MODULE_fs_promises_f8dae9d1__ from "fs/promises";
import * as __WEBPACK_EXTERNAL_MODULE_os__ from "os";
import * as __WEBPACK_EXTERNAL_MODULE_winston__ from "winston";
/******/ var __webpack_modules__ = ({
/***/ 622:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.simplifyEnvList = simplifyEnvList;
exports.registerEnvTools = registerEnvTools;
const zod_1 = __webpack_require__(2971);
const auth_js_1 = __webpack_require__(7291);
const cloudbase_manager_js_1 = __webpack_require__(3431);
const logger_js_1 = __webpack_require__(3039);
const interactive_js_1 = __webpack_require__(3461);
const rag_js_1 = __webpack_require__(4215);
/**
* Simplify environment list data by keeping only essential fields for AI assistant
* This reduces token consumption when returning environment lists via MCP tools
* @param envList - Full environment list from API
* @returns Simplified environment list with only essential fields
*/
function simplifyEnvList(envList) {
if (!Array.isArray(envList)) {
return envList;
}
return envList.map((env) => {
// Only keep essential fields that are useful for AI assistant
const simplified = {};
if (env.EnvId !== undefined)
simplified.EnvId = env.EnvId;
if (env.Alias !== undefined)
simplified.Alias = env.Alias;
if (env.Status !== undefined)
simplified.Status = env.Status;
if (env.EnvType !== undefined)
simplified.EnvType = env.EnvType;
if (env.Region !== undefined)
simplified.Region = env.Region;
if (env.PackageName !== undefined)
simplified.PackageName = env.PackageName;
if (env.IsDefault !== undefined)
simplified.IsDefault = env.IsDefault;
return simplified;
});
}
function registerEnvTools(server) {
// 获取 cloudBaseOptions,如果没有则为 undefined
const cloudBaseOptions = server.cloudBaseOptions;
const getManager = () => (0, cloudbase_manager_js_1.getCloudBaseManager)({ cloudBaseOptions, mcpServer: server });
const hasEnvId = typeof cloudBaseOptions?.envId === 'string' && cloudBaseOptions?.envId.length > 0;
// login - 登录云开发环境
server.registerTool?.("login", {
title: "登录云开发",
description: "登录云开发环境,在生成包含云开发 CloudBase 相关功能前**必须**先调用此工具进行登录。登录云开发环境并选择要使用的环境。",
inputSchema: {
forceUpdate: zod_1.z.boolean().optional().describe("是否强制重新选择环境"),
},
annotations: {
readOnlyHint: false,
destructiveHint: false,
idempotentHint: false,
openWorldHint: true,
category: "env",
},
}, async ({ forceUpdate = false }) => {
let isSwitching = false;
try {
// 使用 while 循环处理用户切换账号的情况
while (true) {
// CRITICAL: Ensure server is passed correctly
(0, logger_js_1.debug)("[env] Calling _promptAndSetEnvironmentId with server:", {
hasServer: !!server,
serverType: typeof server,
hasServerServer: !!server?.server,
hasServerIde: !!server?.ide,
serverIde: server?.ide
});
const { selectedEnvId, cancelled, error, noEnvs, switch: switchAccount, } = await (0, interactive_js_1._promptAndSetEnvironmentId)(forceUpdate, {
server, // Pass ExtendedMcpServer instance
loginFromCloudBaseLoginPage: isSwitching,
// When switching account, ignore environment variables to force Web login
ignoreEnvVars: isSwitching,
});
isSwitching = Boolean(switchAccount);
(0, logger_js_1.debug)("login", {
selectedEnvId,
cancelled,
error,
noEnvs,
switchAccount,
});
if (error) {
return { content: [{ type: "text", text: error }] };
}
if (cancelled) {
return { content: [{ type: "text", text: "用户取消了登录" }] };
}
// 用户选择切换账号,先 logout 再重新登录
if (switchAccount) {
(0, logger_js_1.debug)("User requested switch account, logging out...");
try {
await (0, auth_js_1.logout)();
(0, cloudbase_manager_js_1.resetCloudBaseManagerCache)();
(0, logger_js_1.debug)("Logged out successfully, restarting login flow...");
// Set isSwitching to true so next iteration will ignore env vars
// and force Web authentication to allow account switching
isSwitching = true;
// 继续循环,重新显示登录界面
continue;
}
catch (logoutError) {
(0, logger_js_1.debug)("Logout failed during switch", { error: logoutError });
continue;
}
}
if (selectedEnvId) {
// Get CLAUDE.md prompt content (skip for CodeBuddy IDE)
let promptContent = "";
const currentIde = server.ide || process.env.INTEGRATION_IDE;
if (currentIde !== "CodeBuddy") {
try {
promptContent = await (0, rag_js_1.getClaudePrompt)();
}
catch (promptError) {
(0, logger_js_1.debug)("Failed to get CLAUDE prompt", { error: promptError });
// Continue with login success even if prompt fetch fails
}
}
const successMessage = `✅ 登录成功,当前环境: ${selectedEnvId}`;
const promptMessage = promptContent
? `\n\n⚠️ 重要提示:后续所有云开发相关的开发工作必须严格遵循以下开发规范和最佳实践:\n\n${promptContent}`
: "";
return {
content: [
{
type: "text",
text: successMessage + promptMessage,
},
],
};
}
throw new Error("登录失败");
}
}
catch (error) {
return {
content: [
{
type: "text",
text: `登录失败: ${error instanceof Error ? error.message : String(error)}`,
},
],
};
}
});
// logout - 退出云开发环境
server.registerTool?.("logout", {
title: "退出登录",
description: "退出云开发环境",
inputSchema: {
confirm: zod_1.z.literal("yes").describe("确认操作,默认传 yes"),
},
annotations: {
readOnlyHint: false,
destructiveHint: false,
idempotentHint: true,
openWorldHint: false,
category: "env",
},
}, async () => {
try {
// 登出账户
await (0, auth_js_1.logout)();
// 清理环境ID缓存
(0, cloudbase_manager_js_1.resetCloudBaseManagerCache)();
return {
content: [
{
type: "text",
text: "✅ 已退出登录",
},
],
};
}
catch (error) {
return {
content: [
{
type: "text",
text: `退出失败: ${error instanceof Error ? error.message : String(error)}`,
},
],
};
}
});
// envQuery - 环境查询(合并 listEnvs + getEnvInfo + getEnvAuthDomains + getWebsiteConfig)
server.registerTool?.("envQuery", {
title: "环境查询",
description: "查询云开发环境相关信息,支持查询环境列表、当前环境信息、安全域名和静态网站托管配置。(原工具名:listEnvs/getEnvInfo/getEnvAuthDomains/getWebsiteConfig,为兼容旧AI规则可继续使用这些名称)",
inputSchema: {
action: zod_1.z
.enum(["list", "info", "domains", "hosting"])
.describe("查询类型:list=环境列表,info=当前环境信息,domains=安全域名列表,hosting=静态网站托管配置"),
},
annotations: {
readOnlyHint: true,
openWorldHint: true,
category: "env",
},
}, async ({ action }) => {
try {
let result;
switch (action) {
case "list":
try {
const cloudbaseList = await (0, cloudbase_manager_js_1.getCloudBaseManager)({
cloudBaseOptions,
requireEnvId: true,
mcpServer: server, // Pass server for IDE detection
});
// Use commonService to call DescribeEnvs with filter parameters
// Filter parameters match the reference conditions provided by user
result = await cloudbaseList.commonService("tcb").call({
Action: "DescribeEnvs",
Param: {
EnvTypes: ["weda", "baas"], // Include weda and baas (normal) environments
IsVisible: false, // Filter out invisible environments
Channels: ["dcloud", "iotenable", "tem", "scene_module"], // Filter special channels
},
});
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
// Transform response format to match original listEnvs() format
if (result && result.EnvList) {
result = { EnvList: result.EnvList };
}
else if (result && result.Data && result.Data.EnvList) {
result = { EnvList: result.Data.EnvList };
}
else {
// Fallback to original method if format is unexpected
(0, logger_js_1.debug)("Unexpected response format, falling back to listEnvs()");
result = await cloudbaseList.env.listEnvs();
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
}
// Apply field simplification for MCP tool response to reduce token consumption
if (result && Array.isArray(result.EnvList)) {
result.EnvList = simplifyEnvList(result.EnvList);
}
}
catch (error) {
(0, logger_js_1.debug)("获取环境列表时出错,尝试降级到 listEnvs():", error instanceof Error ? error : new Error(String(error)));
// Fallback to original method on error
try {
const cloudbaseList = await (0, cloudbase_manager_js_1.getCloudBaseManager)({
cloudBaseOptions,
requireEnvId: true,
mcpServer: server, // Pass server for IDE detection
});
result = await cloudbaseList.env.listEnvs();
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
// Apply field simplification for fallback response as well
if (result && Array.isArray(result.EnvList)) {
result.EnvList = simplifyEnvList(result.EnvList);
}
}
catch (fallbackError) {
(0, logger_js_1.debug)("降级到 listEnvs() 也失败:", fallbackError instanceof Error ? fallbackError : new Error(String(fallbackError)));
return {
content: [
{
type: "text",
text: "获取环境列表时出错: " +
(fallbackError instanceof Error
? fallbackError.message
: String(fallbackError)),
},
],
};
}
}
if (hasEnvId && result && Array.isArray(result.EnvList) && result.EnvList.length > 1) {
result.EnvList = result.EnvList.filter((env) => env.EnvId === cloudBaseOptions?.envId);
}
break;
case "info":
const cloudbaseInfo = await getManager();
result = await cloudbaseInfo.env.getEnvInfo();
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
break;
case "domains":
const cloudbaseDomains = await getManager();
result = await cloudbaseDomains.env.getEnvAuthDomains();
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
break;
case "hosting":
const cloudbaseHosting = await getManager();
result = await cloudbaseHosting.hosting.getWebsiteConfig();
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
break;
default:
throw new Error(`不支持的查询类型: ${action}`);
}
let responseText = JSON.stringify(result, null, 2);
// For info action, append CLAUDE.md prompt content (skip for CodeBuddy IDE)
const currentIde = server.ide || process.env.INTEGRATION_IDE;
if (action === "info" && currentIde !== "CodeBuddy") {
try {
const promptContent = await (0, rag_js_1.getClaudePrompt)();
if (promptContent) {
responseText += `\n\n⚠️ 重要提示:后续所有云开发相关的开发工作必须严格遵循以下开发规范和最佳实践:\n\n${promptContent}`;
}
}
catch (promptError) {
(0, logger_js_1.debug)("Failed to get CLAUDE prompt in envQuery", {
error: promptError,
});
// Continue without prompt if fetch fails
}
}
return {
content: [
{
type: "text",
text: responseText,
},
],
};
}
catch (error) {
return {
content: [
{
type: "text",
text: `环境查询失败: ${error instanceof Error ? error.message : String(error)}`,
},
],
};
}
});
// envDomainManagement - 环境域名管理(合并 createEnvDomain + deleteEnvDomain)
server.registerTool?.("envDomainManagement", {
title: "环境域名管理",
description: "管理云开发环境的安全域名,支持添加和删除操作。(原工具名:createEnvDomain/deleteEnvDomain,为兼容旧AI规则可继续使用这些名称)",
inputSchema: {
action: zod_1.z
.enum(["create", "delete"])
.describe("操作类型:create=添加域名,delete=删除域名"),
domains: zod_1.z.array(zod_1.z.string()).describe("安全域名数组"),
},
annotations: {
readOnlyHint: false,
destructiveHint: false, // 注意:delete操作虽然是破坏性的,但这里采用较宽松的标注
idempotentHint: false,
openWorldHint: true,
category: "env",
},
}, async ({ action, domains, }) => {
try {
const cloudbase = await getManager();
let result;
switch (action) {
case "create":
result = await cloudbase.env.createEnvDomain(domains);
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
break;
case "delete":
result = await cloudbase.env.deleteEnvDomain(domains);
(0, cloudbase_manager_js_1.logCloudBaseResult)(server.logger, result);
break;
default:
throw new Error(`不支持的操作类型: ${action}`);
}
return {
content: [
{
type: "text",
text: `${JSON.stringify(result, null, 2)}\n\n请注意安全域名需要10分钟才能生效,用户也应该了解这一点。`,
},
],
};
}
catch (error) {
return {
content: [
{
type: "text",
text: `域名管理操作失败: ${error instanceof Error ? error.message : String(error)}`,
},
],
};
}
});
}
/***/ }),
/***/ 738:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.registerCapiTools = registerCapiTools;
const zod_1 = __webpack_require__(2971);
const cloudbase_manager_js_1 = __webpack_require__(3431);
const CATEGORY = "cloud-api";
const ALLOWED_SERVICES = [
"tcb",
"flexdb",
"scf",
"sts",
"cam",
"lowcode",
"cdn",
"vpc",
];
/**
* Register Common Service based Cloud API tool.
* The tool is intentionally generic; callers must read project rules or
* skills to ensure correct API usage before invoking.
*/
function registerCapiTools(server) {
const cloudBaseOptions = server.cloudBaseOptions;
const logger = server.logger;
const getManager = () => (0, cloudbase_manager_js_1.getCloudBaseManager)({ cloudBaseOptions });
server.registerTool?.("callCloudApi", {
title: "调用云API",
description: "通用的云 API 调用工具,使用前请务必先阅读相关rules或skills,确认所需服务、Action 与 Param 的正确性和安全性",
inputSchema: {
service: zod_1.z
.enum(ALLOWED_SERVICES)
.describe("选择要访问的服务,必须先查看规则/技能确认是否可用。可选:tcb、flexdb、scf、sts、cam、lowcode、cdn、vpc。"),
action: zod_1.z
.string()
.min(1)
.describe("具体 Action 名称,需符合对应服务的 API 定义。"),
params: zod_1.z
.record(zod_1.z.any())
.optional()
.describe("Action 对应的参数对象,键名需与官方 API 定义一致。某些 Action 需要携带 EnvId 等信息,如不清楚请在调用前查看rules/skill。"),
},
annotations: {
readOnlyHint: false,
destructiveHint: true,
idempotentHint: false,
openWorldHint: true,
category: CATEGORY,
},
}, async ({ service, action, params, }) => {
if (!ALLOWED_SERVICES.includes(service)) {
throw new Error(`Service ${service} is not allowed. Allowed services: ${ALLOWED_SERVICES.join(", ")}`);
}
const cloudbase = await getManager();
const result = await cloudbase.commonService(service).call({
Action: action,
Param: params ?? {},
});
(0, cloudbase_manager_js_1.logCloudBaseResult)(logger, result);
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2),
},
],
};
});
}
/***/ }),
/***/ 959:
/***/ ((module) => {
module.exports = __WEBPACK_EXTERNAL_MODULE_lockfile__;
/***/ }),
/***/ 1363:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.wrapServerWithTelemetry = wrapServerWithTelemetry;
const os_1 = __importDefault(__webpack_require__(8116));
const cloudbase_manager_js_1 = __webpack_require__(3431);
const cloud_mode_js_1 = __webpack_require__(9684);
const logger_js_1 = __webpack_require__(3039);
const telemetry_js_1 = __webpack_require__(5880);
/**
* 生成 GitHub Issue 创建链接
* @param toolName 工具名称
* @param errorMessage 错误消息
* @param args 工具参数
* @param cloudBaseOptions CloudBase 配置选项
* @returns GitHub Issue 创建链接
*/
async function generateGitHubIssueLink(toolName, errorMessage, args, cloudBaseOptions, payload) {
const { requestId, ide } = payload || {};
const baseUrl = 'https://github.com/TencentCloudBase/CloudBase-AI-ToolKit/issues/new';
const isTestEnvironment = false || process.env.VITEST === "true";
// 尝试获取环境ID(测试环境跳过,避免交互/阻塞)
let envIdSection = '';
if (!isTestEnvironment) {
try {
// Avoid blocking forever on envId lookup
const envId = await Promise.race([
(0, cloudbase_manager_js_1.getEnvId)(cloudBaseOptions),
new Promise((resolve) => setTimeout(() => resolve(''), 2000)),
]);
if (envId) {
envIdSection = `
## 环境ID
${envId}
`;
}
}
catch (error) {
// 如果获取 envId 失败,不添加环境ID部分
(0, logger_js_1.debug)('无法获取环境ID:', error instanceof Error ? error : new Error(String(error)));
}
}
// 构建标题
const title = `MCP工具错误: ${toolName}`;
// 构建问题描述
const body = `## 错误描述
工具 \`${toolName}\` 执行时发生错误
## 错误信息
\`\`\`
${errorMessage}
\`\`\`
${envIdSection}
## 环境信息
- 操作系统: ${os_1.default.type()} ${os_1.default.release()}
- Node.js版本: ${process.version}
- MCP 版本:${process.env.npm_package_version || "2.7.7" || 0}
- 系统架构: ${os_1.default.arch()}
- 时间: ${new Date().toISOString()}
- 请求ID: ${requestId}
- 集成IDE: ${ide}
## 工具参数
\`\`\`json
${JSON.stringify(sanitizeArgs(args), null, 2)}
\`\`\`
## 复现步骤
1. 使用工具: ${toolName}
2. 传入参数: 上述参数信息
3. 出现错误
## 期望行为
[请描述您期望的正确行为]
## 其他信息
[如有其他相关信息,请在此补充]
`;
// URL 编码
const encodedTitle = encodeURIComponent(title);
const encodedBody = encodeURIComponent(body);
return `${baseUrl}?title=${encodedTitle}&body=${encodedBody}`;
}
/**
* 创建包装后的处理函数,添加数据上报功能
*/
function createWrappedHandler(name, handler, server) {
return async (args) => {
const startTime = Date.now();
let success = false;
let errorMessage;
let requestId;
try {
(0, logger_js_1.debug)(`开始执行工具: ${name}`, { args: sanitizeArgs(args) });
// In test environment, skip logger to avoid potential blocking
const isTestEnvironment = false || process.env.VITEST === "true";
if (!isTestEnvironment) {
server.logger?.({ type: 'beforeToolCall', toolName: name, args: sanitizeArgs(args) });
}
// 执行原始处理函数
const result = await handler(args);
success = true;
const duration = Date.now() - startTime;
(0, logger_js_1.debug)(`工具执行成功: ${name}`, { duration });
if (!isTestEnvironment) {
server.logger?.({ type: 'afterToolCall', toolName: name, args: sanitizeArgs(args), result: result, duration });
}
return result;
}
catch (error) {
success = false;
errorMessage = error instanceof Error ? error.message : String(error);
requestId = (typeof error === 'object' && error && 'requestId' in error) ? error.requestId : '';
(0, logger_js_1.debug)(`工具执行失败: ${name}`, {
error: errorMessage,
duration: Date.now() - startTime
});
const isTestEnvironment = false || process.env.VITEST === "true";
if (!isTestEnvironment) {
server.logger?.({ type: 'errorToolCall', toolName: name, args: sanitizeArgs(args), message: errorMessage, duration: Date.now() - startTime });
}
// In tests, avoid any extra work that may block (envId lookup, issue link generation, etc.)
if (isTestEnvironment) {
throw error instanceof Error ? error : new Error(String(error));
}
// 生成 GitHub Issue 创建链接
const issueLink = await generateGitHubIssueLink(name, errorMessage, args, server.cloudBaseOptions, {
requestId: (typeof error === 'object' && error && 'requestId' in error) ? error.requestId : '',
ide: server.ide || process.env.INTEGRATION_IDE || ''
});
const enhancedErrorMessage = `${errorMessage}\n\n🔗 遇到问题?请复制以下链接到浏览器打开\n即可自动携带错误详情快速创建 GitHub Issue:\n${issueLink}`;
// 创建新的错误对象,保持原有的错误类型但更新消息
const enhancedError = error instanceof Error
? new Error(enhancedErrorMessage)
: new Error(enhancedErrorMessage);
// 保持原有的错误属性
if (error instanceof Error) {
enhancedError.stack = error.stack;
enhancedError.name = error.name;
}
// 重新抛出增强的错误
throw enhancedError;
}
finally {
// 上报工具调用数据(测试环境中跳过,避免阻塞)
const isTestEnvironment = false || process.env.VITEST === "true";
if (!isTestEnvironment) {
const duration = Date.now() - startTime;
// 如果 server.cloudBaseOptions 为空或没有 envId,尝试从缓存获取并更新
let cloudBaseOptions = server.cloudBaseOptions;
if (!cloudBaseOptions?.envId) {
const cachedEnvId = (0, cloudbase_manager_js_1.getCachedEnvId)();
if (cachedEnvId) {
cloudBaseOptions = { ...cloudBaseOptions, envId: cachedEnvId };
}
}
// 异步上报,不阻塞工具返回
(0, telemetry_js_1.reportToolCall)({
toolName: name,
success,
duration,
error: errorMessage,
inputParams: sanitizeArgs(args), // 添加入参上报
cloudBaseOptions: cloudBaseOptions, // 传递 CloudBase 配置(可能已更新)
ide: server.ide || process.env.INTEGRATION_IDE // 传递集成IDE信息
}).catch(err => {
// 静默处理上报错误,不影响主要功能
(0, logger_js_1.debug)('遥测上报失败', { toolName: name, error: err instanceof Error ? err.message : String(err) });
});
}
}
};
}
/**
* 包装 MCP Server 的 registerTool 方法,添加数据上报功能和条件注册
* @param server MCP Server 实例
*/
function wrapServerWithTelemetry(server) {
// 保存原始的 registerTool 方法
const originalRegisterTool = server.registerTool.bind(server);
// Override the registerTool method to add telemetry and conditional registration
server.registerTool = function (toolName, toolConfig, handler) {
// If the tool should not be registered in the current mode, do not register and return undefined
if (!(0, cloud_mode_js_1.shouldRegisterTool)(toolName)) {
(0, logger_js_1.debug)(`Cloud mode: skipping registration of incompatible tool: ${toolName}`);
// Explicitly return undefined to satisfy the expected type
return undefined;
}
// Use the wrapped handler, passing the server instance
const wrappedHandler = createWrappedHandler(toolName, handler, server);
// Call the original registerTool method
return originalRegisterTool(toolName, toolConfig, wrappedHandler);
};
}
/**
* 清理参数中的敏感信息,用于日志记录
* @param args 原始参数
* @returns 清理后的参数
*/
function sanitizeArgs(args) {
if (!args || typeof args !== 'object') {
return args;
}
const sanitized = { ...args };
// 敏感字段列表
const sensitiveFields = [
'password', 'token', 'secret', 'key', 'auth',
'localPath', 'filePath', 'content', 'code',
'secretId', 'secretKey', 'envId'
];
// 递归清理敏感字段
function cleanObject(obj) {
if (Array.isArray(obj)) {
return obj.map(cleanObject);
}
if (obj && typeof obj === 'object') {
const cleaned = {};
for (const [key, value] of Object.entries(obj)) {
const lowerKey = key.toLowerCase();
const isSensitive = sensitiveFields.some(field => lowerKey.includes(field));
if (isSensitive) {
cleaned[key] = '[REDACTED]';
}
else {
cleaned[key] = cleanObject(value);
}
}
return cleaned;
}
return obj;
}
return cleanObject(sanitized);
}
/***/ }),
/***/ 1422:
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.telemetryReporter = exports.reportToolkitLifecycle = exports.reportToolCall = exports.warn = exports.info = exports.error = exports.StdioServerTransport = void 0;
exports.createCloudBaseMcpServer = createCloudBaseMcpServer;
exports.getDefaultServer = getDefaultServer;
const mcp_js_1 = __webpack_require__(4619);
const databaseNoSQL_js_1 = __webpack_require__(3903);
const databaseSQL_js_1 = __webpack_require__(9782);
const download_js_1 = __webpack_require__(9097);
const env_js_1 = __webpack_require__(622);
const functions_js_1 = __webpack_require__(5936);
const hosting_js_1 = __webpack_require__(7279);
const interactive_js_1 = __webpack_require__(3461);
const rag_js_1 = __webpack_require__(4215);
const setup_js_1 = __webpack_require__(6556);
const storage_js_1 = __webpack_require__(4848);
// import { registerMiniprogramTools } from "./tools/miniprogram.js";
const types_js_1 = __webpack_require__(2344);
const capi_js_1 = __webpack_require__(738);
const cloudrun_js_1 = __webpack_require__(5023);
const dataModel_js_1 = __webpack_require__(4052);
const gateway_js_1 = __webpack_require__(4319);
const invite_code_js_1 = __webpack_require__(4760);
const security_rule_js_1 = __webpack_require__(7862);
const cloud_mode_js_1 = __webpack_require__(9684);
const logger_js_1 = __webpack_require__(3039);
const tool_wrapper_js_1 = __webpack_require__(1363);
// 默认插件列表
const DEFAULT_PLUGINS = [
"env",
"database",
"functions",
"hosting",
"storage",
"setup",
"interactive",
"rag",
"cloudrun",
"gateway",
"download",
"security-rule",
"invite-code",
"capi",
];
function registerDatabase(server) {
(0, databaseNoSQL_js_1.registerDatabaseTools)(server);
(0, databaseSQL_js_1.registerSQLDatabaseTools)(server);
(0, dataModel_js_1.registerDataModelTools)(server);
}
// 可用插件映射
const AVAILABLE_PLUGINS = {
env: { name: "env", register: env_js_1.registerEnvTools },
database: { name: "database", register: registerDatabase },
functions: { name: "functions", register: functions_js_1.registerFunctionTools },
hosting: { name: "hosting", register: hosting_js_1.registerHostingTools },
storage: { name: "storage", register: storage_js_1.registerStorageTools },
setup: { name: "setup", register: setup_js_1.registerSetupTools },
interactive: { name: "interactive", register: interactive_js_1.registerInteractiveTools },
rag: { name: "rag", register: rag_js_1.registerRagTools },
download: { name: "download", register: download_js_1.registerDownloadTools },
gateway: { name: "gateway", register: gateway_js_1.registerGatewayTools },
// miniprogram: { name: 'miniprogram', register: registerMiniprogramTools },
"security-rule": {
name: "security-rule",
register: security_rule_js_1.registerSecurityRuleTools,
},
"invite-code": { name: "invite-code", register: invite_code_js_1.registerInviteCodeTools },
cloudrun: { name: "cloudrun", register: cloudrun_js_1.registerCloudRunTools },
capi: { name: "capi", register: capi_js_1.registerCapiTools },
};
/**
* Parse enabled plugins list
* @param pluginsEnabled Optional array of enabled plugin names (takes precedence over env var)
* @param pluginsDisabled Optional array of disabled plugin names (merged with env var)
* @returns Array of enabled plugin names
*/
function parseEnabledPlugins(pluginsEnabled, pluginsDisabled) {
const enabledEnv = process.env.CLOUDBASE_MCP_PLUGINS_ENABLED;
const disabledEnv = process.env.CLOUDBASE_MCP_PLUGINS_DISABLED;
let enabledPlugins;
// Priority: parameter > environment variable > default plugins
if (pluginsEnabled && pluginsEnabled.length > 0) {
enabledPlugins = pluginsEnabled;
}
else if (enabledEnv) {
enabledPlugins = enabledEnv.split(",").map((p) => p.trim());
}
else {
enabledPlugins = [...DEFAULT_PLUGINS];
}
const allDisabledPlugins = new Set();
if (disabledEnv) {
disabledEnv.split(",").map((p) => p.trim()).forEach((p) => allDisabledPlugins.add(p));
}
if (pluginsDisabled && pluginsDisabled.length > 0) {
pluginsDisabled.forEach((p) => allDisabledPlugins.add(p));
}
enabledPlugins = enabledPlugins.filter((p) => !allDisabledPlugins.has(p));
return enabledPlugins;
}
/**
* Create and configure a CloudBase MCP Server instance
* @param options Server configuration options
* @returns Configured McpServer instance
*
* @example
* import { createCloudBaseMcpServer } from "@cloudbase/mcp-server";
* import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
*
* const server = createCloudBaseMcpServer({ cloudBaseOptions: {
* envId, // 环境ID
* secretId, // 腾讯云密钥ID
* secretKey, // 腾讯云密钥
* region, // 地域,默认是 ap-shanghai
* token // 临时密钥,有有效期限制,生成密钥时可控制
* } });
*
* const transport = new StdioServerTransport();
* await server.connect(transport);
*/
async function createCloudBaseMcpServer(options) {
const { name = "cloudbase-mcp", version = "1.0.0", enableTelemetry = true, cloudBaseOptions, cloudMode = false, ide, logger, pluginsEnabled, pluginsDisabled, } = options ?? {};
// Enable cloud mode if specified
if (cloudMode) {
(0, cloud_mode_js_1.enableCloudMode)();
}
// Create server instance
const server = new mcp_js_1.McpServer({
name,
version,
}, {
capabilities: {
tools: {},
...(ide === "CodeBuddy" ? { logging: {} } : {}),
},
});
// Only set logging handler if logging capability is declared
if (ide === "CodeBuddy") {
server.server.setRequestHandler(types_js_1.SetLevelRequestSchema, (request, extra) => {
(0, logger_js_1.info)(`--- Logging level: ${request.params.level}`);
return {};
});
}
// Store cloudBaseOptions in server instance for tools to access
if (cloudBaseOptions) {
server.cloudBaseOptions = cloudBaseOptions;
}
// Store ide in server instance for telemetry
if (ide) {
server.ide = ide;
}
// Store logger in server instance for tools to access
if (logger) {
server.logger = logger;
}
server.setLogger = (logger) => {
server.logger = logger;
};
// Enable telemetry if requested
if (enableTelemetry) {
(0, tool_wrapper_js_1.wrapServerWithTelemetry)(server);
}
// Register plugins based on configuration
const enabledPlugins = parseEnabledPlugins(pluginsEnabled, pluginsDisabled);
for (const pluginName of enabledPlugins) {
const plugin = AVAILABLE_PLUGINS[pluginName];
if (plugin) {
await plugin.register(server);
}
}
return server;
}
/**
* Get the default configured CloudBase MCP Server
*/
function getDefaultServer() {
return createCloudBaseMcpServer();
}
var stdio_js_1 = __webpack_require__(2448);
Object.defineProperty(exports, "StdioServerTransport", ({ enumerable: true, get: function () { return stdio_js_1.StdioServerTransport; } }));
var logger_js_2 = __webpack_require__(3039);
Object.defineProperty(exports, "error", ({ enumerable: true, get: function () { return logger_js_2.error; } }));
Object.defineProperty(exports, "info", ({ enumerable: true, get: function () { return logger_js_2.info; } }));
Object.defineProperty(exports, "warn", ({ enumerable: true, get: function () { return logger_js_2.warn; } }));
var telemetry_js_1 = __webpack_require__(5880);
Object.defineProperty(exports, "reportToolCall", ({ enumerable: true, get: function () { return telemetry_js_1.reportToolCall; } }));
Object.defineProperty(exports, "reportToolkitLifecycle", ({ enumerable: true, get: function () { return telemetry_js_1.reportToolkitLifecycle; } }));
Object.defineProperty(exports, "telemetryReporter", ({ enumerable: true, get: function () { return telemetry_js_1.telemetryReporter; } }));
/***/ }),
/***/ 1622:
/***/ ((module) => {
module.exports = __WEBPACK_EXTERNAL_MODULE_open__;
/***/ }),
/***/ 2090:
/***/ ((module) => {
module.exports = __WEBPACK_EXTERNAL_MODULE__cloudbase_toolbox_034e5bd0__;
/***/ }),
/***/ 2341:
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.InteractiveServer = void 0;
exports.getInteractiveServer = getInteractiveServer;
exports.resetInteractiveServer = resetInteractiveServer;
exports.getInteractiveServerSafe = getInteractiveServerSafe;
const express_1 = __importDefault(__webpack_require__(2674));
const http_1 = __importDefault(__webpack_require__(3782));
const open_1 = __importDefault(__webpack_require__(1622));
const ws_1 = __webpack_require__(6220);
const index_js_1 = __webpack_require__(9529);
const logger_js_1 = __webpack_require__(3039);
// 动态导入 open 模块,兼容 ESM/CJS 环境
async function openUrl(url, options, mcpServer) {
// mcpServer 是 ExtendedMcpServer 实例,它有 server 和 ide 属性
// server 属性是 MCP server 的内部 server 实例,有 sendLoggingMessage 方法
const currentIde = mcpServer?.ide || process.env.INTEGRATION_IDE;
const internalServer = mcpServer?.server; // 内部的 server 实例
(0, logger_js_1.debug)(`[openUrl] Checking IDE: ${currentIde}`);
(0, logger_js_1.debug)(`[openUrl] mcpServer type: ${typeof mcpServer}, has server: ${!!mcpServer?.server}, has ide: ${!!mcpServer?.ide}`);
if (internalServer) {
(0, logger_js_1.debug)(`[openUrl] internalServer type: ${typeof internalServer}, has sendLoggingMessage: ${typeof internalServer.sendLoggingMessage === 'function'}`);
}
// 检查是否为 CodeBuddy IDE (优先使用 mcpServer.ide,回退到环境变量)
if (currentIde === "CodeBuddy" && internalServer && typeof internalServer.sendLoggingMessage === 'function') {
try {
// internalServer 是 MCP server 的内部 server 实例,有 sendLoggingMessage 方法
internalServer.sendLoggingMessage({
level: "notice",
data: {
type: "tcb",
url: url,
},
});
(0, logger_js_1.info)(`CodeBuddy IDE: 已发送网页打开通知 - ${url}`);
return;
}
catch (err) {
(0, logger_js_1.error)(`Failed to send logging message for ${url}: ${err instanceof Error ? err.message : err}`, err instanceof Error ? err : new Error(String(err)));
// 如果发送通知失败,在 CodeBuddy IDE 中不打开网页,直接返回
(0, logger_js_1.warn)(`CodeBuddy IDE: 发送通知失败,不打开网页 - ${url}`);
return;
}
}
// 默认行为:直接打开网页
(0, logger_js_1.debug)(`[openUrl] Opening URL in browser: ${url}`);
try {
return await (0, open_1.default)(url, options);
}
catch (err) {
(0, logger_js_1.error)(`Failed to open ${url} ${options} ${err instanceof Error ? err.message : err} `, err instanceof Error ? err : new Error(String(err)));
(0, logger_js_1.warn)(`Please manually open: ${url}`);
}
}
class InteractiveServer {
app;
server;
wss;
port = 0;
isRunning = false;
currentResolver = null;
sessionData = new Map();
_mcpServer = null; // 保存 MCP server 实例引用
// 公共 getter 和 setter
get mcpServer() {
return this._mcpServer;
}
set mcpServer(server) {
this._mcpServer = server;
}
DEFAULT_PORT = 3721;
FALLBACK_PORTS = [
3722, 3723, 3724, 3725, 3726, 3727, 3728, 3729, 3730, 3731, 3732, 3733,
3734, 3735,
];
constructor(mcpServer) {
this._mcpServer = mcpServer;
this.app = (0, express_1.default)();
this.server = http_1.default.createServer(this.app);
this.wss = new ws_1.WebSocketServer({ server: this.server });
this.setupExpress();
this.setupWebSocket();
process.on("exit", () => this.cleanup());
process.on("SIGINT", () => this.cleanup());
process.on("SIGTERM", () => this.cleanup());
}
cleanup() {
if (this.isRunning) {
(0, logger_js_1.debug)("Cleaning up interactive server resources...");
this.server.close();
this.wss.close();
this.isRunning = false;
}
}
setupExpress() {
this.app.use(express_1.default.json());
this.app.get("/env-setup/:sessionId", (req, res) => {
const { sessionId } = req.params;
const sessionData = this.sessionData.get(sessionId);
if (!sessionData) {
res.status(404).send("会话不存在或已过期");
return;
}
res.send(this.getEnvSetupHTML(sessionData.envs, sessionData.accountInfo, sessionData.errorContext, // Pass error context
sessionId // Pass sessionId for retry functionality
));
});
this.app.get("/clarification/:sessionId", (req, res) => {
const { sessionId } = req.params;
const sessionData = this.sessionData.get(sessionId);
if (!sessionData) {
res.status(404).send("会话不存在或已过期");
return;
}
res.send(this.getClarificationHTML(sessionData.message, sessionData.options));
});
this.app.post("/api/submit", (req, res) => {
const { type, data } = req.body;
(0, logger_js_1.debug)("Received submit request", { type, data });
if (this.currentResolver) {
(0, logger_js_1.info)("Resolving with user data");
this.currentResolver({ type, data });
this.currentResolver = null;
}
else {
(0, logger_js_1.warn)("No resolver waiting for response");
}
res.json({ success: true });
});
this.app.post("/api/cancel", (req, res) => {
(0, logger_js_1.info)("Received cancel request");
if (this.currentResolver) {
(0, logger_js_1.info)("Resolving with cancelled status");
this.currentResolver({
type: "clarification",
data: null,
cancelled: true,
});
this.currentResolver = null;
}
else {
(0, logger_js_1.warn)("No resolver waiting for cancellation");
}
res.json({ success: true });
});
this.app.post("/api/switch", (req, res) => {
(0, logger_js_1.info)("Received switch account request");
if (this.currentResolver) {
(0, logger_js_1.info)("Resolving with switch status");
this.currentResolver({
type: "envId",
data: null,
switch: true,
});
this.currentResolver = null;
}
else {
(0, logger_js_1.warn)("No resolver waiting for switch");
}
res.json({ success: true });
});
this.app.post("/api/retry-init-tcb", (req, res) => {
const { sessionId } = req.body;
(0, logger_js_1.info)("Received retry InitTcb request", { sessionId });
// Mark session for retry
const sessionData = this.sessionData.get(sessionId);
if (sessionData) {
sessionData.retryInitTcb = true;
(0, logger_js_1.debug)("Marked session for InitTcb retry", { sessionId });
}
res.json({ success: true, message: "重试请求已提交,页面将刷新" });
});
// Universal URL opener API - ensures proper handling in different IDEs (e.g., CodeBuddy)
this.app.post("/api/open-url", async (req, res) => {
const { url } = req.body;
if (!url) {
res.status(400).json({ success: false, error: "URL is required" });
return;
}
(0, logger_js_1.info)("Received open URL request", { url });
try {
// Pass mcpServer directly - it's an ExtendedMcpServer instance with server property
await openUrl(url, undefined, this._mcpServer);
res.json({ success: true });
}
catch (err) {
(0, logger_js_1.error)("Failed to open URL", err instanceof Error ? err : new Error(String(err)));
res.status(500).json({
success: false,
error: err instanceof Error ? err.message : String(err)
});
}
});
}
setupWebSocket() {
this.wss.on("connection", (ws) => {
(0, logger_js_1.debug)("WebSocket client connected");
ws.on("message", async (message) => {
try {
const data = JSON.parse(message.toString());
(0, logger_js_1.debug)("WebSocket message received", data);
// Handle session registration
if (data.type === 'registerSession' && data.sessionId) {
(0, logger_js_1.debug)("Registering WebSocket for session:", data.sessionId);
const sessionData = this.sessionData.get(data.sessionId);
if (sessionData) {
sessionData.ws = ws;
(0, logger_js_1.debug)("WebSocket registered successfully for session:", data.sessionId);
}
else {
(0, logger_js_1.debug)("Session not found:", data.sessionId);
}
return;
}
// Handle refresh environment list request
if (data.type === 'refreshEnvList') {
(0, logger_js_1.debug)("Handling refreshEnvList request");
try {
// Find the session ID for this WebSocket connection
let targetSessionId = null;
for (const [sessionId, sessionData] of this.sessionData.entries()) {
if (sessionData.ws === ws) {
targetSessionId = sessionId;
break;
}
}
if (targetSessionId) {
const sessionData = this.sessionData.get(targetSessionId);
if (sessionData && sessionData.manager) {
// Re-fetch environment list using the same API and parameters as ini