@cloudbase/cloudbase-mcp 2.3.0 → 2.3.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/README.md CHANGED
@@ -334,7 +334,7 @@ CodeBuddy 已内置 CloudBase MCP,无需配置即可使用。
334
334
 
335
335
  ## 🧩 MCP 工具
336
336
 
337
- **39 个工具**覆盖环境管理、数据库、云函数、静态托管、小程序发布等核心功能。
337
+ 覆盖环境管理、数据库、云函数、静态托管、小程序发布等核心功能。
338
338
 
339
339
  | 分类 | 工具 | 核心功能 |
340
340
  |------|------|----------|
package/dist/cli.cjs CHANGED
@@ -135012,7 +135012,7 @@ class TelemetryReporter {
135012
135012
  const nodeVersion = process.version; // Node.js版本
135013
135013
  const arch = os_1.default.arch(); // 系统架构
135014
135014
  // 从构建时注入的版本号获取MCP版本信息
135015
- const mcpVersion = process.env.npm_package_version || "2.3.0" || 0;
135015
+ const mcpVersion = process.env.npm_package_version || "2.3.1" || 0;
135016
135016
  return {
135017
135017
  userAgent: `${osType} ${osRelease} ${arch} ${nodeVersion} CloudBase-MCP/${mcpVersion}`,
135018
135018
  deviceId: this.deviceId,
@@ -185485,7 +185485,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
185485
185485
  return (mod && mod.__esModule) ? mod : { "default": mod };
185486
185486
  };
185487
185487
  Object.defineProperty(exports, "__esModule", ({ value: true }));
185488
- exports.downloadWebTemplate = downloadWebTemplate;
185489
185488
  exports.getClaudePrompt = getClaudePrompt;
185490
185489
  exports.registerRagTools = registerRagTools;
185491
185490
  const adm_zip_1 = __importDefault(__webpack_require__(30283));
@@ -185503,6 +185502,58 @@ const KnowledgeBaseIdMap = {
185503
185502
  scf: "scfsczskzyws_4bdc",
185504
185503
  miniprogram: "xcxzskws_25d8",
185505
185504
  };
185505
+ // ============ 缓存配置 ============
185506
+ const CACHE_BASE_DIR = path.join(os.homedir(), ".cloudbase-mcp");
185507
+ const CACHE_META_FILE = path.join(CACHE_BASE_DIR, "cache-meta.json");
185508
+ const DEFAULT_CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 默认 24 小时
185509
+ // 支持环境变量 CLOUDBASE_MCP_CACHE_TTL_MS 控制缓存过期时间(毫秒)
185510
+ const parsedCacheTTL = process.env.CLOUDBASE_MCP_CACHE_TTL_MS
185511
+ ? parseInt(process.env.CLOUDBASE_MCP_CACHE_TTL_MS, 10)
185512
+ : NaN;
185513
+ const CACHE_TTL_MS = Number.isNaN(parsedCacheTTL) || parsedCacheTTL < 0
185514
+ ? DEFAULT_CACHE_TTL_MS
185515
+ : parsedCacheTTL;
185516
+ if (!Number.isNaN(parsedCacheTTL) && parsedCacheTTL >= 0) {
185517
+ (0, logger_js_1.debug)("[cache] Using TTL from CLOUDBASE_MCP_CACHE_TTL_MS", {
185518
+ ttlMs: CACHE_TTL_MS,
185519
+ });
185520
+ }
185521
+ else {
185522
+ (0, logger_js_1.debug)("[cache] Using default TTL", { ttlMs: CACHE_TTL_MS });
185523
+ }
185524
+ // 共享的下载 Promise,防止并发重复下载
185525
+ let resourceDownloadPromise = null;
185526
+ // 检查缓存是否可用(未过期)
185527
+ async function canUseCache() {
185528
+ try {
185529
+ const content = await fs.readFile(CACHE_META_FILE, "utf8");
185530
+ const meta = JSON.parse(content);
185531
+ if (!meta.timestamp) {
185532
+ (0, logger_js_1.debug)("[cache] cache-meta missing timestamp, treating as invalid", {
185533
+ ttlMs: CACHE_TTL_MS,
185534
+ });
185535
+ return false;
185536
+ }
185537
+ const ageMs = Date.now() - meta.timestamp;
185538
+ const isValid = ageMs <= CACHE_TTL_MS;
185539
+ (0, logger_js_1.debug)("[cache] evaluated cache meta", {
185540
+ timestamp: meta.timestamp,
185541
+ ageMs,
185542
+ ttlMs: CACHE_TTL_MS,
185543
+ valid: isValid,
185544
+ });
185545
+ return isValid;
185546
+ }
185547
+ catch (error) {
185548
+ (0, logger_js_1.debug)("[cache] failed to read cache meta, treating as miss", { error });
185549
+ return false;
185550
+ }
185551
+ }
185552
+ // 更新缓存时间戳
185553
+ async function updateCache() {
185554
+ await fs.mkdir(CACHE_BASE_DIR, { recursive: true });
185555
+ await fs.writeFile(CACHE_META_FILE, JSON.stringify({ timestamp: Date.now() }, null, 2), "utf8");
185556
+ }
185506
185557
  // 安全 JSON.parse
185507
185558
  function safeParse(str) {
185508
185559
  try {
@@ -185529,31 +185580,141 @@ function safeStringify(obj) {
185529
185580
  return "";
185530
185581
  }
185531
185582
  }
185532
- // Download and extract web template, return extract directory path
185533
- // Always downloads and overwrites existing template
185583
+ // OpenAPI 文档 URL 列表
185584
+ const OPENAPI_SOURCES = [
185585
+ {
185586
+ name: "mysqldb",
185587
+ description: "MySQL RESTful API - 云开发 MySQL 数据库 HTTP API",
185588
+ url: "https://docs.cloudbase.net/openapi/mysqldb.v1.openapi.yaml",
185589
+ },
185590
+ {
185591
+ name: "functions",
185592
+ description: "Cloud Functions API - 云函数 HTTP API",
185593
+ url: "https://docs.cloudbase.net/openapi/functions.v1.openapi.yaml",
185594
+ },
185595
+ {
185596
+ name: "auth",
185597
+ description: "Authentication API - 身份认证 HTTP API",
185598
+ url: "https://docs.cloudbase.net/openapi/auth.v1.openapi.yaml",
185599
+ },
185600
+ {
185601
+ name: "cloudrun",
185602
+ description: "CloudRun API - 云托管服务 HTTP API",
185603
+ url: "https://docs.cloudbase.net/openapi/cloudrun.v1.openapi.yaml",
185604
+ },
185605
+ {
185606
+ name: "storage",
185607
+ description: "Storage API - 云存储 HTTP API",
185608
+ url: "https://docs.cloudbase.net/openapi/storage.v1.openapi.yaml",
185609
+ },
185610
+ ];
185534
185611
  async function downloadWebTemplate() {
185535
- const baseDir = path.join(os.homedir(), ".cloudbase-mcp");
185536
- const zipPath = path.join(baseDir, "web-cloudbase-project.zip");
185537
- const extractDir = path.join(baseDir, "web-template");
185612
+ const zipPath = path.join(CACHE_BASE_DIR, "web-cloudbase-project.zip");
185613
+ const extractDir = path.join(CACHE_BASE_DIR, "web-template");
185538
185614
  const url = "https://static.cloudbase.net/cloudbase-examples/web-cloudbase-project.zip";
185539
- await fs.mkdir(baseDir, { recursive: true });
185540
- // Download zip to specified path (overwrite)
185541
185615
  const response = await fetch(url);
185542
185616
  if (!response.ok) {
185543
185617
  throw new Error(`下载模板失败,状态码: ${response.status}`);
185544
185618
  }
185545
185619
  const buffer = Buffer.from(await response.arrayBuffer());
185546
185620
  await fs.writeFile(zipPath, buffer);
185547
- // Clean and recreate extract directory
185548
185621
  await fs.rm(extractDir, { recursive: true, force: true });
185549
185622
  await fs.mkdir(extractDir, { recursive: true });
185550
185623
  const zip = new adm_zip_1.default(zipPath);
185551
185624
  zip.extractAllTo(extractDir, true);
185625
+ (0, logger_js_1.debug)("[downloadResources] webTemplate 下载完成");
185552
185626
  return extractDir;
185553
185627
  }
185554
- async function prepareKnowledgeBaseWebTemplate() {
185555
- const extractDir = await downloadWebTemplate();
185556
- return collectSkillDescriptions(path.join(extractDir, ".claude", "skills"));
185628
+ async function downloadOpenAPI() {
185629
+ const baseDir = path.join(CACHE_BASE_DIR, "openapi");
185630
+ await fs.mkdir(baseDir, { recursive: true });
185631
+ const results = [];
185632
+ await Promise.all(OPENAPI_SOURCES.map(async (source) => {
185633
+ try {
185634
+ const response = await fetch(source.url);
185635
+ if (!response.ok) {
185636
+ (0, logger_js_1.warn)(`[downloadOpenAPI] Failed to download ${source.name}`, {
185637
+ status: response.status,
185638
+ });
185639
+ return;
185640
+ }
185641
+ const content = await response.text();
185642
+ const filePath = path.join(baseDir, `${source.name}.openapi.yaml`);
185643
+ await fs.writeFile(filePath, content, "utf8");
185644
+ results.push({
185645
+ name: source.name,
185646
+ description: source.description,
185647
+ absolutePath: filePath,
185648
+ });
185649
+ }
185650
+ catch (error) {
185651
+ (0, logger_js_1.warn)(`[downloadOpenAPI] Failed to download ${source.name}`, {
185652
+ error,
185653
+ });
185654
+ }
185655
+ }));
185656
+ (0, logger_js_1.debug)("[downloadOpenAPI] openAPIDocs 下载完成", {
185657
+ successCount: results.length,
185658
+ total: OPENAPI_SOURCES.length,
185659
+ });
185660
+ return results;
185661
+ }
185662
+ // 实际执行下载所有资源的函数(webTemplate 和 openAPI 并发下载)
185663
+ async function _doDownloadResources() {
185664
+ // 并发下载 webTemplate 和 openAPIDocs
185665
+ const [webTemplateDir, openAPIDocs] = await Promise.all([
185666
+ // 下载 web 模板
185667
+ downloadWebTemplate(),
185668
+ // 并发下载所有 OpenAPI 文档
185669
+ downloadOpenAPI(),
185670
+ ]);
185671
+ (0, logger_js_1.debug)("[downloadResources] 所有资源下载完成");
185672
+ return { webTemplateDir, openAPIDocs };
185673
+ }
185674
+ // 下载所有资源(带缓存和共享 Promise 机制)
185675
+ async function downloadResources() {
185676
+ const webTemplateDir = path.join(CACHE_BASE_DIR, "web-template");
185677
+ const openAPIDir = path.join(CACHE_BASE_DIR, "openapi");
185678
+ // 检查缓存是否有效
185679
+ if (await canUseCache()) {
185680
+ try {
185681
+ // 检查两个目录都存在
185682
+ await Promise.all([fs.access(webTemplateDir), fs.access(openAPIDir)]);
185683
+ const files = await fs.readdir(openAPIDir);
185684
+ if (files.length > 0) {
185685
+ (0, logger_js_1.debug)("[downloadResources] 使用缓存");
185686
+ return {
185687
+ webTemplateDir,
185688
+ openAPIDocs: OPENAPI_SOURCES.map((source) => ({
185689
+ name: source.name,
185690
+ description: source.description,
185691
+ absolutePath: path.join(openAPIDir, `${source.name}.openapi.yaml`),
185692
+ })).filter((item) => files.includes(`${item.name}.openapi.yaml`)),
185693
+ };
185694
+ }
185695
+ }
185696
+ catch {
185697
+ // 缓存无效,需要重新下载
185698
+ }
185699
+ }
185700
+ // 如果已有下载任务在进行中,共享该 Promise
185701
+ if (resourceDownloadPromise) {
185702
+ (0, logger_js_1.debug)("[downloadResources] 共享已有下载任务");
185703
+ return resourceDownloadPromise;
185704
+ }
185705
+ // 创建新的下载任务
185706
+ (0, logger_js_1.debug)("[downloadResources] 开始新下载任务");
185707
+ await fs.mkdir(CACHE_BASE_DIR, { recursive: true });
185708
+ resourceDownloadPromise = _doDownloadResources()
185709
+ .then(async (result) => {
185710
+ await updateCache();
185711
+ (0, logger_js_1.debug)("[downloadResources] 缓存已更新");
185712
+ return result;
185713
+ })
185714
+ .finally(() => {
185715
+ resourceDownloadPromise = null;
185716
+ });
185717
+ return resourceDownloadPromise;
185557
185718
  }
185558
185719
  // Get CLAUDE.md prompt content
185559
185720
  // Priority: 1. From downloaded template, 2. Fallback to embedded constant
@@ -185677,23 +185838,15 @@ async function registerRagTools(server) {
185677
185838
  };
185678
185839
  }
185679
185840
  });
185680
- let skills = [];
185681
185841
  let openapis = [];
185682
- // 知识库检索
185683
- try {
185684
- skills = await prepareKnowledgeBaseWebTemplate();
185685
- }
185686
- catch (error) {
185687
- (0, logger_js_1.warn)("[searchKnowledgeBase] Failed to prepare web template", {
185688
- error,
185689
- });
185690
- }
185691
- // OpenAPI 文档准备
185842
+ let skills = [];
185692
185843
  try {
185693
- openapis = await prepareOpenAPIDocs();
185844
+ const { webTemplateDir, openAPIDocs } = await downloadResources();
185845
+ openapis = openAPIDocs;
185846
+ skills = await collectSkillDescriptions(path.join(webTemplateDir, ".claude", "skills"));
185694
185847
  }
185695
185848
  catch (error) {
185696
- (0, logger_js_1.warn)("[searchKnowledgeBase] Failed to prepare OpenAPI docs", {
185849
+ (0, logger_js_1.warn)("[downloadResources] Failed to download resources", {
185697
185850
  error,
185698
185851
  });
185699
185852
  }
@@ -185860,65 +186013,6 @@ function extractDescriptionFromFrontMatter(content) {
185860
186013
  .match(/^(?:decsription|description)\s*:\s*(.*)$/m);
185861
186014
  return match ? match[1].trim() : null;
185862
186015
  }
185863
- // OpenAPI 文档 URL 列表
185864
- const OPENAPI_SOURCES = [
185865
- {
185866
- name: "mysqldb",
185867
- description: "MySQL RESTful API - 云开发 MySQL 数据库 HTTP API",
185868
- url: "https://docs.cloudbase.net/openapi/mysqldb.v1.openapi.yaml",
185869
- },
185870
- {
185871
- name: "functions",
185872
- description: "Cloud Functions API - 云函数 HTTP API",
185873
- url: "https://docs.cloudbase.net/openapi/functions.v1.openapi.yaml",
185874
- },
185875
- {
185876
- name: "auth",
185877
- description: "Authentication API - 身份认证 HTTP API",
185878
- url: "https://docs.cloudbase.net/openapi/auth.v1.openapi.yaml",
185879
- },
185880
- {
185881
- name: "cloudrun",
185882
- description: "CloudRun API - 云托管服务 HTTP API",
185883
- url: "https://docs.cloudbase.net/openapi/cloudrun.v1.openapi.yaml",
185884
- },
185885
- {
185886
- name: "storage",
185887
- description: "Storage API - 云存储 HTTP API",
185888
- url: "https://docs.cloudbase.net/openapi/storage.v1.openapi.yaml",
185889
- },
185890
- ];
185891
- // 下载并准备 OpenAPI 文档
185892
- async function prepareOpenAPIDocs() {
185893
- const baseDir = path.join(os.homedir(), ".cloudbase-mcp", "openapi");
185894
- await fs.mkdir(baseDir, { recursive: true });
185895
- const results = [];
185896
- await Promise.all(OPENAPI_SOURCES.map(async (source) => {
185897
- try {
185898
- const response = await fetch(source.url);
185899
- if (!response.ok) {
185900
- (0, logger_js_1.warn)(`[prepareOpenAPIDocs] Failed to download ${source.name}`, {
185901
- status: response.status,
185902
- });
185903
- return;
185904
- }
185905
- const content = await response.text();
185906
- const filePath = path.join(baseDir, `${source.name}.openapi.yaml`);
185907
- await fs.writeFile(filePath, content, "utf8");
185908
- results.push({
185909
- name: source.name,
185910
- description: source.description,
185911
- absolutePath: filePath,
185912
- });
185913
- }
185914
- catch (error) {
185915
- (0, logger_js_1.warn)(`[prepareOpenAPIDocs] Failed to download ${source.name}`, {
185916
- error,
185917
- });
185918
- }
185919
- }));
185920
- return results;
185921
- }
185922
186016
  async function collectSkillDescriptions(rootDir) {
185923
186017
  const result = [];
185924
186018
  async function walk(dir) {
@@ -200756,7 +200850,7 @@ ${envIdSection}
200756
200850
  ## 环境信息
200757
200851
  - 操作系统: ${os_1.default.type()} ${os_1.default.release()}
200758
200852
  - Node.js版本: ${process.version}
200759
- - MCP 版本:${process.env.npm_package_version || "2.3.0" || 0}
200853
+ - MCP 版本:${process.env.npm_package_version || "2.3.1" || 0}
200760
200854
  - 系统架构: ${os_1.default.arch()}
200761
200855
  - 时间: ${new Date().toISOString()}
200762
200856
  - 请求ID: ${requestId}
@@ -215401,7 +215495,7 @@ function registerSetupTools(server) {
215401
215495
  title: "下载项目模板",
215402
215496
  description: `自动下载并部署CloudBase项目模板。⚠️ **MANDATORY FOR NEW PROJECTS** ⚠️
215403
215497
 
215404
- **CRITICAL**: This tool MUST be called FIRST when starting a new project.\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- 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\n特别说明:\n- rules 模板会自动包含当前 mcp 版本号信息(版本号:${ true ? "2.3.0" : 0}),便于后续维护和版本追踪\n- 下载 rules 模板时,如果项目中已存在 README.md 文件,系统会自动保护该文件不被覆盖(除非设置 overwrite=true)`,
215498
+ **CRITICAL**: This tool MUST be called FIRST when starting a new project.\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- 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\n特别说明:\n- rules 模板会自动包含当前 mcp 版本号信息(版本号:${ true ? "2.3.1" : 0}),便于后续维护和版本追踪\n- 下载 rules 模板时,如果项目中已存在 README.md 文件,系统会自动保护该文件不被覆盖(除非设置 overwrite=true)`,
215405
215499
  inputSchema: {
215406
215500
  template: zod_1.z
215407
215501
  .enum(["react", "vue", "miniprogram", "uniapp", "rules"])
package/dist/index.cjs CHANGED
@@ -134861,7 +134861,7 @@ class TelemetryReporter {
134861
134861
  const nodeVersion = process.version; // Node.js版本
134862
134862
  const arch = os_1.default.arch(); // 系统架构
134863
134863
  // 从构建时注入的版本号获取MCP版本信息
134864
- const mcpVersion = process.env.npm_package_version || "2.3.0" || 0;
134864
+ const mcpVersion = process.env.npm_package_version || "2.3.1" || 0;
134865
134865
  return {
134866
134866
  userAgent: `${osType} ${osRelease} ${arch} ${nodeVersion} CloudBase-MCP/${mcpVersion}`,
134867
134867
  deviceId: this.deviceId,
@@ -185334,7 +185334,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
185334
185334
  return (mod && mod.__esModule) ? mod : { "default": mod };
185335
185335
  };
185336
185336
  Object.defineProperty(exports, "__esModule", ({ value: true }));
185337
- exports.downloadWebTemplate = downloadWebTemplate;
185338
185337
  exports.getClaudePrompt = getClaudePrompt;
185339
185338
  exports.registerRagTools = registerRagTools;
185340
185339
  const adm_zip_1 = __importDefault(__webpack_require__(30283));
@@ -185352,6 +185351,58 @@ const KnowledgeBaseIdMap = {
185352
185351
  scf: "scfsczskzyws_4bdc",
185353
185352
  miniprogram: "xcxzskws_25d8",
185354
185353
  };
185354
+ // ============ 缓存配置 ============
185355
+ const CACHE_BASE_DIR = path.join(os.homedir(), ".cloudbase-mcp");
185356
+ const CACHE_META_FILE = path.join(CACHE_BASE_DIR, "cache-meta.json");
185357
+ const DEFAULT_CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 默认 24 小时
185358
+ // 支持环境变量 CLOUDBASE_MCP_CACHE_TTL_MS 控制缓存过期时间(毫秒)
185359
+ const parsedCacheTTL = process.env.CLOUDBASE_MCP_CACHE_TTL_MS
185360
+ ? parseInt(process.env.CLOUDBASE_MCP_CACHE_TTL_MS, 10)
185361
+ : NaN;
185362
+ const CACHE_TTL_MS = Number.isNaN(parsedCacheTTL) || parsedCacheTTL < 0
185363
+ ? DEFAULT_CACHE_TTL_MS
185364
+ : parsedCacheTTL;
185365
+ if (!Number.isNaN(parsedCacheTTL) && parsedCacheTTL >= 0) {
185366
+ (0, logger_js_1.debug)("[cache] Using TTL from CLOUDBASE_MCP_CACHE_TTL_MS", {
185367
+ ttlMs: CACHE_TTL_MS,
185368
+ });
185369
+ }
185370
+ else {
185371
+ (0, logger_js_1.debug)("[cache] Using default TTL", { ttlMs: CACHE_TTL_MS });
185372
+ }
185373
+ // 共享的下载 Promise,防止并发重复下载
185374
+ let resourceDownloadPromise = null;
185375
+ // 检查缓存是否可用(未过期)
185376
+ async function canUseCache() {
185377
+ try {
185378
+ const content = await fs.readFile(CACHE_META_FILE, "utf8");
185379
+ const meta = JSON.parse(content);
185380
+ if (!meta.timestamp) {
185381
+ (0, logger_js_1.debug)("[cache] cache-meta missing timestamp, treating as invalid", {
185382
+ ttlMs: CACHE_TTL_MS,
185383
+ });
185384
+ return false;
185385
+ }
185386
+ const ageMs = Date.now() - meta.timestamp;
185387
+ const isValid = ageMs <= CACHE_TTL_MS;
185388
+ (0, logger_js_1.debug)("[cache] evaluated cache meta", {
185389
+ timestamp: meta.timestamp,
185390
+ ageMs,
185391
+ ttlMs: CACHE_TTL_MS,
185392
+ valid: isValid,
185393
+ });
185394
+ return isValid;
185395
+ }
185396
+ catch (error) {
185397
+ (0, logger_js_1.debug)("[cache] failed to read cache meta, treating as miss", { error });
185398
+ return false;
185399
+ }
185400
+ }
185401
+ // 更新缓存时间戳
185402
+ async function updateCache() {
185403
+ await fs.mkdir(CACHE_BASE_DIR, { recursive: true });
185404
+ await fs.writeFile(CACHE_META_FILE, JSON.stringify({ timestamp: Date.now() }, null, 2), "utf8");
185405
+ }
185355
185406
  // 安全 JSON.parse
185356
185407
  function safeParse(str) {
185357
185408
  try {
@@ -185378,31 +185429,141 @@ function safeStringify(obj) {
185378
185429
  return "";
185379
185430
  }
185380
185431
  }
185381
- // Download and extract web template, return extract directory path
185382
- // Always downloads and overwrites existing template
185432
+ // OpenAPI 文档 URL 列表
185433
+ const OPENAPI_SOURCES = [
185434
+ {
185435
+ name: "mysqldb",
185436
+ description: "MySQL RESTful API - 云开发 MySQL 数据库 HTTP API",
185437
+ url: "https://docs.cloudbase.net/openapi/mysqldb.v1.openapi.yaml",
185438
+ },
185439
+ {
185440
+ name: "functions",
185441
+ description: "Cloud Functions API - 云函数 HTTP API",
185442
+ url: "https://docs.cloudbase.net/openapi/functions.v1.openapi.yaml",
185443
+ },
185444
+ {
185445
+ name: "auth",
185446
+ description: "Authentication API - 身份认证 HTTP API",
185447
+ url: "https://docs.cloudbase.net/openapi/auth.v1.openapi.yaml",
185448
+ },
185449
+ {
185450
+ name: "cloudrun",
185451
+ description: "CloudRun API - 云托管服务 HTTP API",
185452
+ url: "https://docs.cloudbase.net/openapi/cloudrun.v1.openapi.yaml",
185453
+ },
185454
+ {
185455
+ name: "storage",
185456
+ description: "Storage API - 云存储 HTTP API",
185457
+ url: "https://docs.cloudbase.net/openapi/storage.v1.openapi.yaml",
185458
+ },
185459
+ ];
185383
185460
  async function downloadWebTemplate() {
185384
- const baseDir = path.join(os.homedir(), ".cloudbase-mcp");
185385
- const zipPath = path.join(baseDir, "web-cloudbase-project.zip");
185386
- const extractDir = path.join(baseDir, "web-template");
185461
+ const zipPath = path.join(CACHE_BASE_DIR, "web-cloudbase-project.zip");
185462
+ const extractDir = path.join(CACHE_BASE_DIR, "web-template");
185387
185463
  const url = "https://static.cloudbase.net/cloudbase-examples/web-cloudbase-project.zip";
185388
- await fs.mkdir(baseDir, { recursive: true });
185389
- // Download zip to specified path (overwrite)
185390
185464
  const response = await fetch(url);
185391
185465
  if (!response.ok) {
185392
185466
  throw new Error(`下载模板失败,状态码: ${response.status}`);
185393
185467
  }
185394
185468
  const buffer = Buffer.from(await response.arrayBuffer());
185395
185469
  await fs.writeFile(zipPath, buffer);
185396
- // Clean and recreate extract directory
185397
185470
  await fs.rm(extractDir, { recursive: true, force: true });
185398
185471
  await fs.mkdir(extractDir, { recursive: true });
185399
185472
  const zip = new adm_zip_1.default(zipPath);
185400
185473
  zip.extractAllTo(extractDir, true);
185474
+ (0, logger_js_1.debug)("[downloadResources] webTemplate 下载完成");
185401
185475
  return extractDir;
185402
185476
  }
185403
- async function prepareKnowledgeBaseWebTemplate() {
185404
- const extractDir = await downloadWebTemplate();
185405
- return collectSkillDescriptions(path.join(extractDir, ".claude", "skills"));
185477
+ async function downloadOpenAPI() {
185478
+ const baseDir = path.join(CACHE_BASE_DIR, "openapi");
185479
+ await fs.mkdir(baseDir, { recursive: true });
185480
+ const results = [];
185481
+ await Promise.all(OPENAPI_SOURCES.map(async (source) => {
185482
+ try {
185483
+ const response = await fetch(source.url);
185484
+ if (!response.ok) {
185485
+ (0, logger_js_1.warn)(`[downloadOpenAPI] Failed to download ${source.name}`, {
185486
+ status: response.status,
185487
+ });
185488
+ return;
185489
+ }
185490
+ const content = await response.text();
185491
+ const filePath = path.join(baseDir, `${source.name}.openapi.yaml`);
185492
+ await fs.writeFile(filePath, content, "utf8");
185493
+ results.push({
185494
+ name: source.name,
185495
+ description: source.description,
185496
+ absolutePath: filePath,
185497
+ });
185498
+ }
185499
+ catch (error) {
185500
+ (0, logger_js_1.warn)(`[downloadOpenAPI] Failed to download ${source.name}`, {
185501
+ error,
185502
+ });
185503
+ }
185504
+ }));
185505
+ (0, logger_js_1.debug)("[downloadOpenAPI] openAPIDocs 下载完成", {
185506
+ successCount: results.length,
185507
+ total: OPENAPI_SOURCES.length,
185508
+ });
185509
+ return results;
185510
+ }
185511
+ // 实际执行下载所有资源的函数(webTemplate 和 openAPI 并发下载)
185512
+ async function _doDownloadResources() {
185513
+ // 并发下载 webTemplate 和 openAPIDocs
185514
+ const [webTemplateDir, openAPIDocs] = await Promise.all([
185515
+ // 下载 web 模板
185516
+ downloadWebTemplate(),
185517
+ // 并发下载所有 OpenAPI 文档
185518
+ downloadOpenAPI(),
185519
+ ]);
185520
+ (0, logger_js_1.debug)("[downloadResources] 所有资源下载完成");
185521
+ return { webTemplateDir, openAPIDocs };
185522
+ }
185523
+ // 下载所有资源(带缓存和共享 Promise 机制)
185524
+ async function downloadResources() {
185525
+ const webTemplateDir = path.join(CACHE_BASE_DIR, "web-template");
185526
+ const openAPIDir = path.join(CACHE_BASE_DIR, "openapi");
185527
+ // 检查缓存是否有效
185528
+ if (await canUseCache()) {
185529
+ try {
185530
+ // 检查两个目录都存在
185531
+ await Promise.all([fs.access(webTemplateDir), fs.access(openAPIDir)]);
185532
+ const files = await fs.readdir(openAPIDir);
185533
+ if (files.length > 0) {
185534
+ (0, logger_js_1.debug)("[downloadResources] 使用缓存");
185535
+ return {
185536
+ webTemplateDir,
185537
+ openAPIDocs: OPENAPI_SOURCES.map((source) => ({
185538
+ name: source.name,
185539
+ description: source.description,
185540
+ absolutePath: path.join(openAPIDir, `${source.name}.openapi.yaml`),
185541
+ })).filter((item) => files.includes(`${item.name}.openapi.yaml`)),
185542
+ };
185543
+ }
185544
+ }
185545
+ catch {
185546
+ // 缓存无效,需要重新下载
185547
+ }
185548
+ }
185549
+ // 如果已有下载任务在进行中,共享该 Promise
185550
+ if (resourceDownloadPromise) {
185551
+ (0, logger_js_1.debug)("[downloadResources] 共享已有下载任务");
185552
+ return resourceDownloadPromise;
185553
+ }
185554
+ // 创建新的下载任务
185555
+ (0, logger_js_1.debug)("[downloadResources] 开始新下载任务");
185556
+ await fs.mkdir(CACHE_BASE_DIR, { recursive: true });
185557
+ resourceDownloadPromise = _doDownloadResources()
185558
+ .then(async (result) => {
185559
+ await updateCache();
185560
+ (0, logger_js_1.debug)("[downloadResources] 缓存已更新");
185561
+ return result;
185562
+ })
185563
+ .finally(() => {
185564
+ resourceDownloadPromise = null;
185565
+ });
185566
+ return resourceDownloadPromise;
185406
185567
  }
185407
185568
  // Get CLAUDE.md prompt content
185408
185569
  // Priority: 1. From downloaded template, 2. Fallback to embedded constant
@@ -185526,23 +185687,15 @@ async function registerRagTools(server) {
185526
185687
  };
185527
185688
  }
185528
185689
  });
185529
- let skills = [];
185530
185690
  let openapis = [];
185531
- // 知识库检索
185532
- try {
185533
- skills = await prepareKnowledgeBaseWebTemplate();
185534
- }
185535
- catch (error) {
185536
- (0, logger_js_1.warn)("[searchKnowledgeBase] Failed to prepare web template", {
185537
- error,
185538
- });
185539
- }
185540
- // OpenAPI 文档准备
185691
+ let skills = [];
185541
185692
  try {
185542
- openapis = await prepareOpenAPIDocs();
185693
+ const { webTemplateDir, openAPIDocs } = await downloadResources();
185694
+ openapis = openAPIDocs;
185695
+ skills = await collectSkillDescriptions(path.join(webTemplateDir, ".claude", "skills"));
185543
185696
  }
185544
185697
  catch (error) {
185545
- (0, logger_js_1.warn)("[searchKnowledgeBase] Failed to prepare OpenAPI docs", {
185698
+ (0, logger_js_1.warn)("[downloadResources] Failed to download resources", {
185546
185699
  error,
185547
185700
  });
185548
185701
  }
@@ -185709,65 +185862,6 @@ function extractDescriptionFromFrontMatter(content) {
185709
185862
  .match(/^(?:decsription|description)\s*:\s*(.*)$/m);
185710
185863
  return match ? match[1].trim() : null;
185711
185864
  }
185712
- // OpenAPI 文档 URL 列表
185713
- const OPENAPI_SOURCES = [
185714
- {
185715
- name: "mysqldb",
185716
- description: "MySQL RESTful API - 云开发 MySQL 数据库 HTTP API",
185717
- url: "https://docs.cloudbase.net/openapi/mysqldb.v1.openapi.yaml",
185718
- },
185719
- {
185720
- name: "functions",
185721
- description: "Cloud Functions API - 云函数 HTTP API",
185722
- url: "https://docs.cloudbase.net/openapi/functions.v1.openapi.yaml",
185723
- },
185724
- {
185725
- name: "auth",
185726
- description: "Authentication API - 身份认证 HTTP API",
185727
- url: "https://docs.cloudbase.net/openapi/auth.v1.openapi.yaml",
185728
- },
185729
- {
185730
- name: "cloudrun",
185731
- description: "CloudRun API - 云托管服务 HTTP API",
185732
- url: "https://docs.cloudbase.net/openapi/cloudrun.v1.openapi.yaml",
185733
- },
185734
- {
185735
- name: "storage",
185736
- description: "Storage API - 云存储 HTTP API",
185737
- url: "https://docs.cloudbase.net/openapi/storage.v1.openapi.yaml",
185738
- },
185739
- ];
185740
- // 下载并准备 OpenAPI 文档
185741
- async function prepareOpenAPIDocs() {
185742
- const baseDir = path.join(os.homedir(), ".cloudbase-mcp", "openapi");
185743
- await fs.mkdir(baseDir, { recursive: true });
185744
- const results = [];
185745
- await Promise.all(OPENAPI_SOURCES.map(async (source) => {
185746
- try {
185747
- const response = await fetch(source.url);
185748
- if (!response.ok) {
185749
- (0, logger_js_1.warn)(`[prepareOpenAPIDocs] Failed to download ${source.name}`, {
185750
- status: response.status,
185751
- });
185752
- return;
185753
- }
185754
- const content = await response.text();
185755
- const filePath = path.join(baseDir, `${source.name}.openapi.yaml`);
185756
- await fs.writeFile(filePath, content, "utf8");
185757
- results.push({
185758
- name: source.name,
185759
- description: source.description,
185760
- absolutePath: filePath,
185761
- });
185762
- }
185763
- catch (error) {
185764
- (0, logger_js_1.warn)(`[prepareOpenAPIDocs] Failed to download ${source.name}`, {
185765
- error,
185766
- });
185767
- }
185768
- }));
185769
- return results;
185770
- }
185771
185865
  async function collectSkillDescriptions(rootDir) {
185772
185866
  const result = [];
185773
185867
  async function walk(dir) {
@@ -200605,7 +200699,7 @@ ${envIdSection}
200605
200699
  ## 环境信息
200606
200700
  - 操作系统: ${os_1.default.type()} ${os_1.default.release()}
200607
200701
  - Node.js版本: ${process.version}
200608
- - MCP 版本:${process.env.npm_package_version || "2.3.0" || 0}
200702
+ - MCP 版本:${process.env.npm_package_version || "2.3.1" || 0}
200609
200703
  - 系统架构: ${os_1.default.arch()}
200610
200704
  - 时间: ${new Date().toISOString()}
200611
200705
  - 请求ID: ${requestId}
@@ -215250,7 +215344,7 @@ function registerSetupTools(server) {
215250
215344
  title: "下载项目模板",
215251
215345
  description: `自动下载并部署CloudBase项目模板。⚠️ **MANDATORY FOR NEW PROJECTS** ⚠️
215252
215346
 
215253
- **CRITICAL**: This tool MUST be called FIRST when starting a new project.\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- 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\n特别说明:\n- rules 模板会自动包含当前 mcp 版本号信息(版本号:${ true ? "2.3.0" : 0}),便于后续维护和版本追踪\n- 下载 rules 模板时,如果项目中已存在 README.md 文件,系统会自动保护该文件不被覆盖(除非设置 overwrite=true)`,
215347
+ **CRITICAL**: This tool MUST be called FIRST when starting a new project.\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- 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\n特别说明:\n- rules 模板会自动包含当前 mcp 版本号信息(版本号:${ true ? "2.3.1" : 0}),便于后续维护和版本追踪\n- 下载 rules 模板时,如果项目中已存在 README.md 文件,系统会自动保护该文件不被覆盖(除非设置 overwrite=true)`,
215254
215348
  inputSchema: {
215255
215349
  template: zod_1.z
215256
215350
  .enum(["react", "vue", "miniprogram", "uniapp", "rules"])
package/dist/index.js CHANGED
@@ -2525,7 +2525,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
2525
2525
  return (mod && mod.__esModule) ? mod : { "default": mod };
2526
2526
  };
2527
2527
  Object.defineProperty(exports, "__esModule", ({ value: true }));
2528
- exports.downloadWebTemplate = downloadWebTemplate;
2529
2528
  exports.getClaudePrompt = getClaudePrompt;
2530
2529
  exports.registerRagTools = registerRagTools;
2531
2530
  const adm_zip_1 = __importDefault(__webpack_require__(872));
@@ -2543,6 +2542,58 @@ const KnowledgeBaseIdMap = {
2543
2542
  scf: "scfsczskzyws_4bdc",
2544
2543
  miniprogram: "xcxzskws_25d8",
2545
2544
  };
2545
+ // ============ 缓存配置 ============
2546
+ const CACHE_BASE_DIR = path.join(os.homedir(), ".cloudbase-mcp");
2547
+ const CACHE_META_FILE = path.join(CACHE_BASE_DIR, "cache-meta.json");
2548
+ const DEFAULT_CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 默认 24 小时
2549
+ // 支持环境变量 CLOUDBASE_MCP_CACHE_TTL_MS 控制缓存过期时间(毫秒)
2550
+ const parsedCacheTTL = process.env.CLOUDBASE_MCP_CACHE_TTL_MS
2551
+ ? parseInt(process.env.CLOUDBASE_MCP_CACHE_TTL_MS, 10)
2552
+ : NaN;
2553
+ const CACHE_TTL_MS = Number.isNaN(parsedCacheTTL) || parsedCacheTTL < 0
2554
+ ? DEFAULT_CACHE_TTL_MS
2555
+ : parsedCacheTTL;
2556
+ if (!Number.isNaN(parsedCacheTTL) && parsedCacheTTL >= 0) {
2557
+ (0, logger_js_1.debug)("[cache] Using TTL from CLOUDBASE_MCP_CACHE_TTL_MS", {
2558
+ ttlMs: CACHE_TTL_MS,
2559
+ });
2560
+ }
2561
+ else {
2562
+ (0, logger_js_1.debug)("[cache] Using default TTL", { ttlMs: CACHE_TTL_MS });
2563
+ }
2564
+ // 共享的下载 Promise,防止并发重复下载
2565
+ let resourceDownloadPromise = null;
2566
+ // 检查缓存是否可用(未过期)
2567
+ async function canUseCache() {
2568
+ try {
2569
+ const content = await fs.readFile(CACHE_META_FILE, "utf8");
2570
+ const meta = JSON.parse(content);
2571
+ if (!meta.timestamp) {
2572
+ (0, logger_js_1.debug)("[cache] cache-meta missing timestamp, treating as invalid", {
2573
+ ttlMs: CACHE_TTL_MS,
2574
+ });
2575
+ return false;
2576
+ }
2577
+ const ageMs = Date.now() - meta.timestamp;
2578
+ const isValid = ageMs <= CACHE_TTL_MS;
2579
+ (0, logger_js_1.debug)("[cache] evaluated cache meta", {
2580
+ timestamp: meta.timestamp,
2581
+ ageMs,
2582
+ ttlMs: CACHE_TTL_MS,
2583
+ valid: isValid,
2584
+ });
2585
+ return isValid;
2586
+ }
2587
+ catch (error) {
2588
+ (0, logger_js_1.debug)("[cache] failed to read cache meta, treating as miss", { error });
2589
+ return false;
2590
+ }
2591
+ }
2592
+ // 更新缓存时间戳
2593
+ async function updateCache() {
2594
+ await fs.mkdir(CACHE_BASE_DIR, { recursive: true });
2595
+ await fs.writeFile(CACHE_META_FILE, JSON.stringify({ timestamp: Date.now() }, null, 2), "utf8");
2596
+ }
2546
2597
  // 安全 JSON.parse
2547
2598
  function safeParse(str) {
2548
2599
  try {
@@ -2569,31 +2620,141 @@ function safeStringify(obj) {
2569
2620
  return "";
2570
2621
  }
2571
2622
  }
2572
- // Download and extract web template, return extract directory path
2573
- // Always downloads and overwrites existing template
2623
+ // OpenAPI 文档 URL 列表
2624
+ const OPENAPI_SOURCES = [
2625
+ {
2626
+ name: "mysqldb",
2627
+ description: "MySQL RESTful API - 云开发 MySQL 数据库 HTTP API",
2628
+ url: "https://docs.cloudbase.net/openapi/mysqldb.v1.openapi.yaml",
2629
+ },
2630
+ {
2631
+ name: "functions",
2632
+ description: "Cloud Functions API - 云函数 HTTP API",
2633
+ url: "https://docs.cloudbase.net/openapi/functions.v1.openapi.yaml",
2634
+ },
2635
+ {
2636
+ name: "auth",
2637
+ description: "Authentication API - 身份认证 HTTP API",
2638
+ url: "https://docs.cloudbase.net/openapi/auth.v1.openapi.yaml",
2639
+ },
2640
+ {
2641
+ name: "cloudrun",
2642
+ description: "CloudRun API - 云托管服务 HTTP API",
2643
+ url: "https://docs.cloudbase.net/openapi/cloudrun.v1.openapi.yaml",
2644
+ },
2645
+ {
2646
+ name: "storage",
2647
+ description: "Storage API - 云存储 HTTP API",
2648
+ url: "https://docs.cloudbase.net/openapi/storage.v1.openapi.yaml",
2649
+ },
2650
+ ];
2574
2651
  async function downloadWebTemplate() {
2575
- const baseDir = path.join(os.homedir(), ".cloudbase-mcp");
2576
- const zipPath = path.join(baseDir, "web-cloudbase-project.zip");
2577
- const extractDir = path.join(baseDir, "web-template");
2652
+ const zipPath = path.join(CACHE_BASE_DIR, "web-cloudbase-project.zip");
2653
+ const extractDir = path.join(CACHE_BASE_DIR, "web-template");
2578
2654
  const url = "https://static.cloudbase.net/cloudbase-examples/web-cloudbase-project.zip";
2579
- await fs.mkdir(baseDir, { recursive: true });
2580
- // Download zip to specified path (overwrite)
2581
2655
  const response = await fetch(url);
2582
2656
  if (!response.ok) {
2583
2657
  throw new Error(`下载模板失败,状态码: ${response.status}`);
2584
2658
  }
2585
2659
  const buffer = Buffer.from(await response.arrayBuffer());
2586
2660
  await fs.writeFile(zipPath, buffer);
2587
- // Clean and recreate extract directory
2588
2661
  await fs.rm(extractDir, { recursive: true, force: true });
2589
2662
  await fs.mkdir(extractDir, { recursive: true });
2590
2663
  const zip = new adm_zip_1.default(zipPath);
2591
2664
  zip.extractAllTo(extractDir, true);
2665
+ (0, logger_js_1.debug)("[downloadResources] webTemplate 下载完成");
2592
2666
  return extractDir;
2593
2667
  }
2594
- async function prepareKnowledgeBaseWebTemplate() {
2595
- const extractDir = await downloadWebTemplate();
2596
- return collectSkillDescriptions(path.join(extractDir, ".claude", "skills"));
2668
+ async function downloadOpenAPI() {
2669
+ const baseDir = path.join(CACHE_BASE_DIR, "openapi");
2670
+ await fs.mkdir(baseDir, { recursive: true });
2671
+ const results = [];
2672
+ await Promise.all(OPENAPI_SOURCES.map(async (source) => {
2673
+ try {
2674
+ const response = await fetch(source.url);
2675
+ if (!response.ok) {
2676
+ (0, logger_js_1.warn)(`[downloadOpenAPI] Failed to download ${source.name}`, {
2677
+ status: response.status,
2678
+ });
2679
+ return;
2680
+ }
2681
+ const content = await response.text();
2682
+ const filePath = path.join(baseDir, `${source.name}.openapi.yaml`);
2683
+ await fs.writeFile(filePath, content, "utf8");
2684
+ results.push({
2685
+ name: source.name,
2686
+ description: source.description,
2687
+ absolutePath: filePath,
2688
+ });
2689
+ }
2690
+ catch (error) {
2691
+ (0, logger_js_1.warn)(`[downloadOpenAPI] Failed to download ${source.name}`, {
2692
+ error,
2693
+ });
2694
+ }
2695
+ }));
2696
+ (0, logger_js_1.debug)("[downloadOpenAPI] openAPIDocs 下载完成", {
2697
+ successCount: results.length,
2698
+ total: OPENAPI_SOURCES.length,
2699
+ });
2700
+ return results;
2701
+ }
2702
+ // 实际执行下载所有资源的函数(webTemplate 和 openAPI 并发下载)
2703
+ async function _doDownloadResources() {
2704
+ // 并发下载 webTemplate 和 openAPIDocs
2705
+ const [webTemplateDir, openAPIDocs] = await Promise.all([
2706
+ // 下载 web 模板
2707
+ downloadWebTemplate(),
2708
+ // 并发下载所有 OpenAPI 文档
2709
+ downloadOpenAPI(),
2710
+ ]);
2711
+ (0, logger_js_1.debug)("[downloadResources] 所有资源下载完成");
2712
+ return { webTemplateDir, openAPIDocs };
2713
+ }
2714
+ // 下载所有资源(带缓存和共享 Promise 机制)
2715
+ async function downloadResources() {
2716
+ const webTemplateDir = path.join(CACHE_BASE_DIR, "web-template");
2717
+ const openAPIDir = path.join(CACHE_BASE_DIR, "openapi");
2718
+ // 检查缓存是否有效
2719
+ if (await canUseCache()) {
2720
+ try {
2721
+ // 检查两个目录都存在
2722
+ await Promise.all([fs.access(webTemplateDir), fs.access(openAPIDir)]);
2723
+ const files = await fs.readdir(openAPIDir);
2724
+ if (files.length > 0) {
2725
+ (0, logger_js_1.debug)("[downloadResources] 使用缓存");
2726
+ return {
2727
+ webTemplateDir,
2728
+ openAPIDocs: OPENAPI_SOURCES.map((source) => ({
2729
+ name: source.name,
2730
+ description: source.description,
2731
+ absolutePath: path.join(openAPIDir, `${source.name}.openapi.yaml`),
2732
+ })).filter((item) => files.includes(`${item.name}.openapi.yaml`)),
2733
+ };
2734
+ }
2735
+ }
2736
+ catch {
2737
+ // 缓存无效,需要重新下载
2738
+ }
2739
+ }
2740
+ // 如果已有下载任务在进行中,共享该 Promise
2741
+ if (resourceDownloadPromise) {
2742
+ (0, logger_js_1.debug)("[downloadResources] 共享已有下载任务");
2743
+ return resourceDownloadPromise;
2744
+ }
2745
+ // 创建新的下载任务
2746
+ (0, logger_js_1.debug)("[downloadResources] 开始新下载任务");
2747
+ await fs.mkdir(CACHE_BASE_DIR, { recursive: true });
2748
+ resourceDownloadPromise = _doDownloadResources()
2749
+ .then(async (result) => {
2750
+ await updateCache();
2751
+ (0, logger_js_1.debug)("[downloadResources] 缓存已更新");
2752
+ return result;
2753
+ })
2754
+ .finally(() => {
2755
+ resourceDownloadPromise = null;
2756
+ });
2757
+ return resourceDownloadPromise;
2597
2758
  }
2598
2759
  // Get CLAUDE.md prompt content
2599
2760
  // Priority: 1. From downloaded template, 2. Fallback to embedded constant
@@ -2717,23 +2878,15 @@ async function registerRagTools(server) {
2717
2878
  };
2718
2879
  }
2719
2880
  });
2720
- let skills = [];
2721
2881
  let openapis = [];
2722
- // 知识库检索
2723
- try {
2724
- skills = await prepareKnowledgeBaseWebTemplate();
2725
- }
2726
- catch (error) {
2727
- (0, logger_js_1.warn)("[searchKnowledgeBase] Failed to prepare web template", {
2728
- error,
2729
- });
2730
- }
2731
- // OpenAPI 文档准备
2882
+ let skills = [];
2732
2883
  try {
2733
- openapis = await prepareOpenAPIDocs();
2884
+ const { webTemplateDir, openAPIDocs } = await downloadResources();
2885
+ openapis = openAPIDocs;
2886
+ skills = await collectSkillDescriptions(path.join(webTemplateDir, ".claude", "skills"));
2734
2887
  }
2735
2888
  catch (error) {
2736
- (0, logger_js_1.warn)("[searchKnowledgeBase] Failed to prepare OpenAPI docs", {
2889
+ (0, logger_js_1.warn)("[downloadResources] Failed to download resources", {
2737
2890
  error,
2738
2891
  });
2739
2892
  }
@@ -2900,65 +3053,6 @@ function extractDescriptionFromFrontMatter(content) {
2900
3053
  .match(/^(?:decsription|description)\s*:\s*(.*)$/m);
2901
3054
  return match ? match[1].trim() : null;
2902
3055
  }
2903
- // OpenAPI 文档 URL 列表
2904
- const OPENAPI_SOURCES = [
2905
- {
2906
- name: "mysqldb",
2907
- description: "MySQL RESTful API - 云开发 MySQL 数据库 HTTP API",
2908
- url: "https://docs.cloudbase.net/openapi/mysqldb.v1.openapi.yaml",
2909
- },
2910
- {
2911
- name: "functions",
2912
- description: "Cloud Functions API - 云函数 HTTP API",
2913
- url: "https://docs.cloudbase.net/openapi/functions.v1.openapi.yaml",
2914
- },
2915
- {
2916
- name: "auth",
2917
- description: "Authentication API - 身份认证 HTTP API",
2918
- url: "https://docs.cloudbase.net/openapi/auth.v1.openapi.yaml",
2919
- },
2920
- {
2921
- name: "cloudrun",
2922
- description: "CloudRun API - 云托管服务 HTTP API",
2923
- url: "https://docs.cloudbase.net/openapi/cloudrun.v1.openapi.yaml",
2924
- },
2925
- {
2926
- name: "storage",
2927
- description: "Storage API - 云存储 HTTP API",
2928
- url: "https://docs.cloudbase.net/openapi/storage.v1.openapi.yaml",
2929
- },
2930
- ];
2931
- // 下载并准备 OpenAPI 文档
2932
- async function prepareOpenAPIDocs() {
2933
- const baseDir = path.join(os.homedir(), ".cloudbase-mcp", "openapi");
2934
- await fs.mkdir(baseDir, { recursive: true });
2935
- const results = [];
2936
- await Promise.all(OPENAPI_SOURCES.map(async (source) => {
2937
- try {
2938
- const response = await fetch(source.url);
2939
- if (!response.ok) {
2940
- (0, logger_js_1.warn)(`[prepareOpenAPIDocs] Failed to download ${source.name}`, {
2941
- status: response.status,
2942
- });
2943
- return;
2944
- }
2945
- const content = await response.text();
2946
- const filePath = path.join(baseDir, `${source.name}.openapi.yaml`);
2947
- await fs.writeFile(filePath, content, "utf8");
2948
- results.push({
2949
- name: source.name,
2950
- description: source.description,
2951
- absolutePath: filePath,
2952
- });
2953
- }
2954
- catch (error) {
2955
- (0, logger_js_1.warn)(`[prepareOpenAPIDocs] Failed to download ${source.name}`, {
2956
- error,
2957
- });
2958
- }
2959
- }));
2960
- return results;
2961
- }
2962
3056
  async function collectSkillDescriptions(rootDir) {
2963
3057
  const result = [];
2964
3058
  async function walk(dir) {
@@ -6224,7 +6318,7 @@ ${envIdSection}
6224
6318
  ## 环境信息
6225
6319
  - 操作系统: ${os_1.default.type()} ${os_1.default.release()}
6226
6320
  - Node.js版本: ${process.version}
6227
- - MCP 版本:${process.env.npm_package_version || "2.3.0" || 0}
6321
+ - MCP 版本:${process.env.npm_package_version || "2.3.1" || 0}
6228
6322
  - 系统架构: ${os_1.default.arch()}
6229
6323
  - 时间: ${new Date().toISOString()}
6230
6324
  - 请求ID: ${requestId}
@@ -7471,7 +7565,7 @@ function registerSetupTools(server) {
7471
7565
  title: "下载项目模板",
7472
7566
  description: `自动下载并部署CloudBase项目模板。⚠️ **MANDATORY FOR NEW PROJECTS** ⚠️
7473
7567
 
7474
- **CRITICAL**: This tool MUST be called FIRST when starting a new project.\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- 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\n特别说明:\n- rules 模板会自动包含当前 mcp 版本号信息(版本号:${ true ? "2.3.0" : 0}),便于后续维护和版本追踪\n- 下载 rules 模板时,如果项目中已存在 README.md 文件,系统会自动保护该文件不被覆盖(除非设置 overwrite=true)`,
7568
+ **CRITICAL**: This tool MUST be called FIRST when starting a new project.\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- 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\n特别说明:\n- rules 模板会自动包含当前 mcp 版本号信息(版本号:${ true ? "2.3.1" : 0}),便于后续维护和版本追踪\n- 下载 rules 模板时,如果项目中已存在 README.md 文件,系统会自动保护该文件不被覆盖(除非设置 overwrite=true)`,
7475
7569
  inputSchema: {
7476
7570
  template: zod_1.z
7477
7571
  .enum(["react", "vue", "miniprogram", "uniapp", "rules"])
@@ -8569,7 +8663,7 @@ class TelemetryReporter {
8569
8663
  const nodeVersion = process.version; // Node.js版本
8570
8664
  const arch = os_1.default.arch(); // 系统架构
8571
8665
  // 从构建时注入的版本号获取MCP版本信息
8572
- const mcpVersion = process.env.npm_package_version || "2.3.0" || 0;
8666
+ const mcpVersion = process.env.npm_package_version || "2.3.1" || 0;
8573
8667
  return {
8574
8668
  userAgent: `${osType} ${osRelease} ${arch} ${nodeVersion} CloudBase-MCP/${mcpVersion}`,
8575
8669
  deviceId: this.deviceId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudbase/cloudbase-mcp",
3
- "version": "2.3.0",
3
+ "version": "2.3.1",
4
4
  "description": "腾讯云开发 MCP Server,通过AI提示词和MCP协议+云开发,让开发更智能、更高效,当你在Cursor/ VSCode GitHub Copilot/WinSurf/CodeBuddy/Augment Code/Claude Code等AI编程工具里写代码时,它能自动帮你生成可直接部署的前后端应用+小程序,并一键发布到腾讯云开发 CloudBase。",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",