@cloudbase/cloudbase-mcp 2.35.1 → 2.35.2

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
@@ -4325,7 +4325,7 @@ const types_js_1 = __webpack_require__(9921);
4325
4325
  exports.env = (0, types_js_1.defineModule)({
4326
4326
  // ---- 工具级 meta(description/title 由 server.ts 注册包装层按词典 key 解析)----
4327
4327
  authTitle: "CloudBase 开发阶段登录与环境",
4328
- authDescription: "CloudBase(腾讯云开发)开发阶段登录与环境绑定。登录后即可访问云资源;环境(env)是云函数、数据库、静态托管等资源的隔离单元,绑定环境后其他 MCP 工具才能操作该环境。支持:查询状态、发起登录、API Key登录、绑定环境(set_env)、退出登录。auth(status) 会返回 credential_scope(account=账号级 / single_env=环境级 API Key)与当前 region;环境级 API Key 只能看到绑定的 envId,查不到其他地域环境是权限边界而非环境不存在。可选 site/region/lang 参数:site=站点(domestic/intl),region=地域,lang=输出语言(zh/en)。",
4328
+ authDescription: "CloudBase(腾讯云开发)开发阶段登录与环境绑定。不确定该从哪开始?先调一次 auth(status)(只读、不用参数),确认登录态和当前环境。登录后即可访问云资源;环境(env)是云函数、数据库、静态托管等资源的隔离单元,绑定环境后其他 MCP 工具才能操作该环境。还没有环境时:国内站新用户可以免费开通一个体验环境,开通后再用 set_env 绑定。支持:查询状态、发起登录、API Key登录、绑定环境(set_env)、退出登录。auth(status) 会返回 credential_scope(account=账号级 / single_env=环境级 API Key)与当前 region;环境级 API Key 只能看到绑定的 envId,查不到其他地域环境是权限边界而非环境不存在。可选 site/region/lang 参数:site=站点(domestic/intl),region=地域,lang=输出语言(zh/en)。",
4329
4329
  queryTitle: "CloudBase 环境查询",
4330
4330
  queryDescription: "查询 CloudBase 环境相关信息,支持查询环境列表、指定环境详情、安全域名、资源用量与监控指标。(曾用名:envQuery、listEnvs、getEnvInfo、getEnvAuthDomains)当 action=list 时,会按 DescribeEnvs 语义做列表/筛选,标准返回字段为 EnvId、Alias、Status、EnvType、Region、PackageId、PackageName、IsDefault,并支持通过 fields 白名单裁剪这些字段;aliasExact=true 时会按别名精确筛选,避免把前缀相近的环境误当作候选;即使传入 envId,action=list 也只返回摘要,不会返回完整资源明细或 expiry。账号级登录可传 region(ap-shanghai/ap-guangzhou/ap-singapore)查询对应地域,对齐 CLI `tcb env list -r <region>`;环境级凭证(API Key / 托管授权 token)只能看到绑定的 envId,返回 credential_scope=single_env,此时 region 不参与查询会在 ignored_params 中如实说明(AppliedFilters.region 为 null),不要误判为环境不存在或地域过滤失效。如需查询某个已知 EnvId 对应环境的详细信息(包括资源字段和计费信息),必须使用 action=info 并传入目标环境的 envId 参数。action=info 会在可用时补充 BillingInfo(如 ExpireTime、PayMode、IsAutoRenew 等计费字段)。\n\n📊 action=usage 对齐 tcb env usage/info:透传 Manager SDK describeEnvAccountCircle + describeCreditsUsageDetail,返回计费周期与各模块资源点用量(FLEXDB/SCF/COS 等)。envId 必填;type 可选过滤模块;未传 startDate/endDate 时自动使用当前计费周期。\n\n📈 action=metrics 对齐 TCB DescribeCurveData(manager.monitor.describeCurveData,不是云监控 GetMonitorData):查询环境/网关 QPS、云函数调用与错误、数据库 CPU/内存/磁盘、云托管 CPU/QPS 等时序。envId 与 metricName 必填;startTime/endTime 格式 YYYY-MM-DD HH:mm:ss,须成对传入,不传则默认最近 24 小时;period 仅 300/3600/86400。GatewayTraceEnvQPS 未传 resourceID 时自动填环境级 all|:|all|:|all|:|all;云托管 Tke* 指标必须传服务名 resourceID。禁止用 callCloudApi 猜测监控 Action。\n\n🔍 action=info 还会派生三个用于后端选型的字段:\n- `EnvInfo.RuntimeMode`:'postgresql' 或 'nosql',表示新业务建议默认使用的后端(PG 已开通时为 postgresql,否则为 nosql)。\n- `EnvInfo.RuntimeBackends`:`{postgresql, nosql, mysql}` 三个布尔值,描述当前环境实际并存的后端。\n- `EnvInfo.RuntimeModeHints`:每个后端对应的 API/工具/skill 提示。\n\n🌐 action=info 还会在不改写 `StaticStorages[].StaticDomain`(云 API 名义域名)的前提下,投影网关路由 Enable 状态:`StaticStorages[].staticDomainRouteEnabled` 与 `EnvInfo.staticDomainRouteEnabled`(与 queryHosting websiteConfig 同源)。`false` 表示默认静态域名根路由已禁用(访问会返回 GATEWAY_ROUTE_DISABLED),勿把名义域名当成可达 URL。\n\nAI 在写业务/权限/存储代码前必须先看这三项:PG 模式下新业务推荐 `app.rdb()` + RLS(`managePgDatabase action=execute` 跑 `CREATE POLICY`)+ pgstore;已存在的 NoSQL 集合 / 旧 storage / `managePermissions(resourceType=\"noSqlDatabase\")` 在 PG 环境下仍然有效。真正不适用的是 MySQL:当 `RuntimeBackends.mysql === false` 时,`manageMysqlDatabase` / `queryMysqlDatabase` / `relational-database-mcp-cloudbase` skill 都不该使用。",
4331
4331
  domainTitle: "CloudBase 环境安全域名管理(浏览器 CORS 白名单)【已废弃】",
@@ -4588,7 +4588,7 @@ exports.env = (0, types_js_1.defineModule)({
4588
4588
  }, {
4589
4589
  // ---- Tool-level meta ----
4590
4590
  authTitle: "CloudBase dev-stage login and environment",
4591
- authDescription: "CloudBase (Tencent CloudBase) dev-stage login and environment binding. After login you can access cloud resources; an environment (env) is the isolation unit for cloud functions, databases, static hosting, etc. Other MCP tools operate on the bound environment. Supports: status, start_auth (login), login_by_api_key, set_env (bind env), logout. auth(status) returns credential_scope (account / single_env API Key) and current region; a single-env API Key can only see its bound envId — missing other-region envs is a permission boundary, not a missing environment. Optional site/region/lang params: site=domestic|intl, region=e.g. ap-shanghai|ap-singapore, lang=zh|en output language.",
4591
+ authDescription: "CloudBase (Tencent CloudBase) dev-stage login and environment binding. Unsure where to start? Call auth(status) first (read-only, no arguments) to confirm the login state and the current environment. After login you can access cloud resources; an environment (env) is the isolation unit for cloud functions, databases, static hosting, etc. Other MCP tools operate on the bound environment. No environment yet? On the China site a new user can create a trial environment for free, then bind it with set_env. Supports: status, start_auth (login), login_by_api_key, set_env (bind env), logout. auth(status) returns credential_scope (account / single_env API Key) and current region; a single-env API Key can only see its bound envId — missing other-region envs is a permission boundary, not a missing environment. Optional site/region/lang params: site=domestic|intl, region=e.g. ap-shanghai|ap-singapore, lang=zh|en output language.",
4592
4592
  queryTitle: "Query CloudBase environments",
4593
4593
  queryDescription: "Query CloudBase environment information: environment list, details of a specific environment, security domains, resource usage and monitoring metrics. (Former names: envQuery, listEnvs, getEnvInfo, getEnvAuthDomains) When action=list, listing/filtering follows DescribeEnvs semantics; the standard returned fields are EnvId, Alias, Status, EnvType, Region, PackageId, PackageName, IsDefault, and those fields can be trimmed via the fields whitelist; aliasExact=true filters by exact alias so environments with similar prefixes are not mistaken for candidates; even when envId is passed, action=list still returns only a summary, never full resource details or expiry. Account-level logins may pass region (ap-shanghai/ap-guangzhou/ap-singapore) to query that region, matching CLI `tcb env list -r <region>`; an env-level credential (API Key / hosted authorization token) can only see its bound envId and returns credential_scope=single_env; in that case region plays no part in the query and is reported as such in ignored_params (AppliedFilters.region is null) — do not mistake that for a missing environment or a region filter that failed to apply. To query details of a known EnvId (including resource fields and billing info), you must use action=info and pass the target environment's envId. action=info appends BillingInfo when available (billing fields such as ExpireTime, PayMode, IsAutoRenew).\n\n📊 action=usage matches tcb env usage/info: it passes through Manager SDK describeEnvAccountCircle + describeCreditsUsageDetail and returns the billing cycle and per-module resource-point usage (FLEXDB/SCF/COS, etc.). envId is required; type optionally filters modules; when startDate/endDate are omitted the current billing cycle is used.\n\n📈 action=metrics matches TCB DescribeCurveData (manager.monitor.describeCurveData, not Cloud Monitor GetMonitorData): query time series for env/gateway QPS, cloud function invocations and errors, database CPU/memory/disk, CloudRun CPU/QPS, and more. envId and metricName are required; startTime/endTime use the format YYYY-MM-DD HH:mm:ss and must be passed as a pair, defaulting to the last 24 hours when omitted; period only supports 300/3600/86400. When resourceID is omitted for GatewayTraceEnvQPS, the env-level all|:|all|:|all|:|all is filled in automatically; CloudRun Tke* metrics must pass the service name as resourceID. Do not use callCloudApi to guess monitoring Actions.\n\n🔍 action=info also derives three fields used for backend selection:\n- `EnvInfo.RuntimeMode`: 'postgresql' or 'nosql', the backend recommended by default for new work (postgresql when PG is enabled, otherwise nosql).\n- `EnvInfo.RuntimeBackends`: the three booleans `{postgresql, nosql, mysql}`, describing the backends that actually coexist in the current environment.\n- `EnvInfo.RuntimeModeHints`: the API/tool/skill hints for each backend.\n\n🌐 action=info also projects the gateway route Enable state without rewriting `StaticStorages[].StaticDomain` (the Cloud API nominal domain): `StaticStorages[].staticDomainRouteEnabled` and `EnvInfo.staticDomainRouteEnabled` (same source as queryHosting websiteConfig). `false` means the default static domain root route is disabled (requests return GATEWAY_ROUTE_DISABLED) — do not treat the nominal domain as a reachable URL.\n\nBefore writing business/permission/storage code, AI must check these three items first: in PG mode, new work should prefer `app.rdb()` + RLS (`managePgDatabase action=execute` running `CREATE POLICY`) + pgstore; existing NoSQL collections / legacy storage / `managePermissions(resourceType=\"noSqlDatabase\")` remain valid in a PG environment. What truly does not apply is MySQL: when `RuntimeBackends.mysql === false`, none of `manageMysqlDatabase` / `queryMysqlDatabase` / the `relational-database-mcp-cloudbase` skill should be used.",
4594
4594
  domainTitle: "CloudBase environment security domain management (browser CORS allowlist) [DEPRECATED]",
@@ -6900,9 +6900,10 @@ exports.rag = (0, types_js_1.defineModule)({
6900
6900
 
6901
6901
  ⚠️ 重要:当 CloudBase skills 处于禁用状态或当前 IDE 不支持 skill 文件读取时,必须使用 searchKnowledgeBase(mode=skill, skillName=...) 来获取 CloudBase 技能文档内容,而不是尝试直接读取 skill 文件。直接读取可能返回 400 错误。示例:
6902
6902
  - 需要最小 Web+数据库 Demo 路径时:searchKnowledgeBase(mode=skill, skillName=minimal-web-baas-demo)
6903
- - 需要 auth-tool 指南时:searchKnowledgeBase(mode=skill, skillName=auth-tool)
6904
- - 需要 auth-web 指南时:searchKnowledgeBase(mode=skill, skillName=auth-web)
6903
+ - 需要 auth-tool-cloudbase 指南时:searchKnowledgeBase(mode=skill, skillName=auth-tool-cloudbase)
6904
+ - 需要 auth-web-cloudbase 指南时:searchKnowledgeBase(mode=skill, skillName=auth-web-cloudbase)
6905
6905
  - 需要 cloudbase-agent 指南时:searchKnowledgeBase(mode=skill, skillName=cloudbase-agent)
6906
+ - 需要 MCP 接入方式(本地 / 远程)、用 mcporter 在命令行调用工具、或站点 / 插件开关时:searchKnowledgeBase(mode=skill, skillName=cloudbase-mcp)
6906
6907
 
6907
6908
  返回内容包含该 skill 的 SKILL.md 全文,以及它在远端聚合仓(CNB raw)中的全部 .md 文件地址清单(SKILL.md 与 references/ 等,可直接 HTTP 抓取)。正文中代码栅栏之外的相对链接也会改写为绝对地址;若该 skill 在远端仓中不存在,则只返回内联内容并明确标注,不返回失效链接。
6908
6909
 
@@ -6958,9 +6959,10 @@ exports.rag = (0, types_js_1.defineModule)({
6958
6959
 
6959
6960
  ⚠️ Important: when CloudBase skills are disabled or the current IDE does not support reading skill files, use searchKnowledgeBase(mode=skill, skillName=...) to get CloudBase skill doc content instead of trying to read skill files directly. Direct reads may return 400 errors. Examples:
6960
6961
  - Minimal Web+database demo path: searchKnowledgeBase(mode=skill, skillName=minimal-web-baas-demo)
6961
- - auth-tool guide: searchKnowledgeBase(mode=skill, skillName=auth-tool)
6962
- - auth-web guide: searchKnowledgeBase(mode=skill, skillName=auth-web)
6962
+ - auth-tool-cloudbase guide: searchKnowledgeBase(mode=skill, skillName=auth-tool-cloudbase)
6963
+ - auth-web-cloudbase guide: searchKnowledgeBase(mode=skill, skillName=auth-web-cloudbase)
6963
6964
  - cloudbase-agent guide: searchKnowledgeBase(mode=skill, skillName=cloudbase-agent)
6965
+ - MCP connection modes (local / remote), calling tools from the shell with mcporter, or the site / plugin switches: searchKnowledgeBase(mode=skill, skillName=cloudbase-mcp)
6964
6966
 
6965
6967
  The response contains the full SKILL.md of the skill plus the list of all its .md file URLs in the remote aggregate repo (CNB raw) — SKILL.md and references/ etc., fetchable over HTTP. Relative links outside code fences are rewritten to absolute URLs; when the skill is absent from the remote repo only the inline content is returned and that is stated explicitly, so no dead links are handed out.
6966
6968
 
@@ -7591,6 +7593,84 @@ function createLocalCloudApiRequestFn(endpoint) {
7591
7593
  }
7592
7594
 
7593
7595
 
7596
+ /***/ },
7597
+
7598
+ /***/ 1808
7599
+ (__unused_webpack_module, exports) {
7600
+
7601
+ var __webpack_unused_export__;
7602
+
7603
+ __webpack_unused_export__ = ({ value: true });
7604
+ exports.QQ = __webpack_unused_export__ = void 0;
7605
+ exports.resolveServerInstructions = resolveServerInstructions;
7606
+ /**
7607
+ * MCP `initialize` 结果里的 `instructions`(服务端自述「怎么用我」)。
7608
+ *
7609
+ * 为什么放这里而不是 i18n 词典:词典是给工具 description / 输出文案用的短句,
7610
+ * 这是一整段免协商的自述文本,跟着 server 走、由实例语言选一份。
7611
+ *
7612
+ * 四条约束(改文案前先读):
7613
+ * 1. **≤ MAX_CHARS**(≈500 tokens)。工具定义本身已经吃掉 3 万 tokens(44 个工具),
7614
+ * 这里再堆就是雪上加霜 —— 所以只写「先做一次调用 + 顺序 + 3 条可照抄问法」,
7615
+ * **不列工具清单**(除 `auth` 与「别猜、先查」要用的检索入口外不点名工具)。
7616
+ * 2. **只写使用者照着做什么**,不写内部实现、不写安全须知(那是 rules 的活)。
7617
+ * 3. 提到的 action 名必须与 `auth` 工具 schema 一致(`status` / `start_auth` /
7618
+ * `login_by_api_key` / `set_env` / `logout`),改 auth 时这里要一起改。
7619
+ * 4. **第一句就给一个「零参数、只读、现在就能做」的动作**。读这段文本的模型如果在
7620
+ * 犹豫该不该动,成本最低的出口就是它 —— 这直接对着「连上了但一次都不调用」那条断点。
7621
+ * 5. **不重复**:同一个动作/同一条建议只说一次(`auth(status)` 只在首段出现,
7622
+ * 下面的顺序里不再复述它查登录态)。
7623
+ *
7624
+ * ⚠️ 客户端是否把 instructions 注入上下文**不由协议保证**,也**看不出来**(它不是
7625
+ * capability)⇒ 同样的话在工具 description(首推 `auth`)里要留兜底,不要把它当唯一引导。
7626
+ */
7627
+ __webpack_unused_export__ = 2000;
7628
+ exports.QQ = {
7629
+ zh: [
7630
+ "CloudBase MCP:操作腾讯云开发(CloudBase)环境里的云函数、数据库、静态托管等资源。",
7631
+ "",
7632
+ '第一步先调一次 auth(action="status") —— 只读、不用参数,返回登录态和当前环境;不确定从哪开始就先调它。',
7633
+ "",
7634
+ "接下来按顺序走:",
7635
+ "1. 需要登录时,照 auth(status) 返回的指引完成登录。",
7636
+ '2. auth(action="set_env", envId="环境ID") 绑定环境 —— 没绑定前其他工具都用不了。还没有环境?国内站新用户可以免费开通一个体验环境。',
7637
+ "3. 做一件小事确认链路通,例如「列出这个环境的云函数」。",
7638
+ "",
7639
+ "不要凭记忆猜 API、参数和用法:先读 CloudBase Skill 或调 searchKnowledgeBase 确认;查不到就说查不到。",
7640
+ "",
7641
+ "可以直接照抄的问法:",
7642
+ "- 看下数据库里最新的 10 条记录",
7643
+ "- 把我当前项目部署到静态托管",
7644
+ "- 列出这个环境的云函数和最近的日志",
7645
+ "",
7646
+ "报错时按报错文案里的指引处理,不要反复重试同一个调用。",
7647
+ ].join("\n"),
7648
+ en: [
7649
+ "CloudBase MCP: work with resources in a Tencent CloudBase environment — cloud functions, databases, static hosting, and more.",
7650
+ "",
7651
+ 'Start with one call: auth(action="status") — read-only, no arguments; it returns the login state and current environment. When unsure where to begin, call it first.',
7652
+ "",
7653
+ "Then follow this order:",
7654
+ "1. If login is required, follow what auth(status) returns.",
7655
+ '2. auth(action="set_env", envId="your-env-id") binds an environment — the other tools are unusable until one is bound. No environment yet? On the China site a new user can create a trial environment for free.',
7656
+ '3. Do one small thing to confirm the path works, e.g. "list the cloud functions in this environment".',
7657
+ "",
7658
+ "Do not guess API names, parameters or usage from memory: read the CloudBase Skill or confirm through searchKnowledgeBase first; if it is not documented, say so.",
7659
+ "",
7660
+ "Prompts you can copy as-is:",
7661
+ "- Show me the 10 most recent records in the database",
7662
+ "- Deploy my current project to static hosting",
7663
+ "- List this environment's cloud functions and their recent logs",
7664
+ "",
7665
+ "When a call fails, follow the guidance in the error message instead of retrying the same call repeatedly.",
7666
+ ].join("\n"),
7667
+ };
7668
+ /** 按实例语言取 instructions;未知语言回退 zh(与 i18n 的默认一致) */
7669
+ function resolveServerInstructions(lang) {
7670
+ return exports.QQ[lang] ?? exports.QQ.zh;
7671
+ }
7672
+
7673
+
7594
7674
  /***/ },
7595
7675
 
7596
7676
  /***/ 6324
@@ -7628,6 +7708,7 @@ const msg_push_js_1 = __webpack_require__(7707);
7628
7708
  const feedback_js_1 = __webpack_require__(3951);
7629
7709
  const index_js_1 = __webpack_require__(4908);
7630
7710
  const schema_js_1 = __webpack_require__(6273);
7711
+ const server_instructions_js_1 = __webpack_require__(1808);
7631
7712
  const cloud_mode_js_1 = __webpack_require__(8694);
7632
7713
  const logger_js_1 = __webpack_require__(781);
7633
7714
  const site_map_js_1 = __webpack_require__(4533);
@@ -7794,6 +7875,9 @@ async function createCloudBaseMcpServer(options) {
7794
7875
  (0, cloud_mode_js_1.enableCloudMode)();
7795
7876
  }
7796
7877
  // Create server instance
7878
+ // 实例语言必须在构造前解析:`instructions` 是 initialize 的返回字段,构造时就得定稿,
7879
+ // 不能像工具 description 那样等注册包装层再按 lang 改写。
7880
+ const instanceLang = (0, index_js_1.resolveInstanceLang)(lang);
7797
7881
  const server = new mcp_js_1.McpServer({
7798
7882
  name,
7799
7883
  version,
@@ -7802,11 +7886,13 @@ async function createCloudBaseMcpServer(options) {
7802
7886
  tools: {},
7803
7887
  ...(ide === "CodeBuddy" ? { logging: {} } : {}),
7804
7888
  },
7889
+ // 免协商的「怎么用我」自述:不占 tools/list 的上下文,客户端不支持时自然忽略。
7890
+ instructions: (0, server_instructions_js_1.resolveServerInstructions)(instanceLang),
7805
7891
  });
7806
7892
  // 初始化 toolDefs,用于外部提取工具列表(如微信 IDE)
7807
7893
  server.toolDefs = [];
7808
7894
  // 实例语言解析(须在工具注册前完成:registerTool 包装层按 lang 解析词典 key 形式的 description)
7809
- server.lang = (0, index_js_1.resolveInstanceLang)(lang);
7895
+ server.lang = instanceLang;
7810
7896
  // 同步到 i18n 模块级 instanceLang:否则 t() 无 langOverride 时会退化成
7811
7897
  // TCB_LANG/project.json/zh,导致 options.lang 只影响工具 description、不影响工具输出文案。
7812
7898
  (0, index_js_1.setInstanceLang)(server.lang);
@@ -36024,10 +36110,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36024
36110
  return (mod && mod.__esModule) ? mod : { "default": mod };
36025
36111
  };
36026
36112
  Object.defineProperty(exports, "__esModule", ({ value: true }));
36027
- exports.reportToolkitLifecycle = exports.reportToolCall = exports.telemetryReporter = void 0;
36113
+ exports.reportToolkitLifecycle = exports.reportElicitationResult = exports.reportToolCall = exports.MCP_UI_EXTENSION = exports.telemetryReporter = void 0;
36028
36114
  exports.extractMcpClientInfo = extractMcpClientInfo;
36029
36115
  exports.readMcpClientInfoFromServer = readMcpClientInfoFromServer;
36030
36116
  exports.normalizeClientName = normalizeClientName;
36117
+ exports.extractClientCapabilities = extractClientCapabilities;
36118
+ exports.readClientCapabilitiesFromServer = readClientCapabilitiesFromServer;
36031
36119
  exports.resolveLoginUin = resolveLoginUin;
36032
36120
  const crypto_1 = __importDefault(__webpack_require__(7823));
36033
36121
  const http_1 = __importDefault(__webpack_require__(3782));
@@ -36091,7 +36179,7 @@ class TelemetryReporter {
36091
36179
  const arch = os_1.default.arch(); // 系统架构
36092
36180
  // Build-time injected version; guard for vitest / non-webpack runtimes.
36093
36181
  const mcpVersion = process.env.npm_package_version ||
36094
- ( true ? "2.35.1" : 0);
36182
+ ( true ? "2.35.2" : 0);
36095
36183
  return {
36096
36184
  userAgent: `${osType} ${osRelease} ${arch} ${nodeVersion} CloudBase-MCP/${mcpVersion}`,
36097
36185
  deviceId: this.deviceId,
@@ -36374,6 +36462,88 @@ function appendMcpClientInfoFields(eventData, clientInfo) {
36374
36462
  eventData.mcpClientTitle = clientInfo.title;
36375
36463
  }
36376
36464
  }
36465
+ // ---- MCP 客户端能力(capabilities)----
36466
+ //
36467
+ // 为什么要有:灯塔侧原本只记「客户端是谁」(mcpClientName / ide),**没有任何字段承载
36468
+ // 「它声明了什么能力」** ⇒ 本地 stdio 的支持矩阵完全空白,elicitation / MCP Apps 铺不铺
36469
+ // 只能靠远程日志外推(两条实现未必一致)。远程能从 CLS 事后翻 `initialize` 的
36470
+ // clientInfo,本地是我们自己的进程 —— 声明本来就在手上,不记白不记。
36471
+ /** MCP Apps(SEP-1865)扩展标识:宿主与服务端**双向声明**才谈得上渲染 */
36472
+ exports.MCP_UI_EXTENSION = 'io.modelcontextprotocol/ui';
36473
+ /** 把 `getClientCapabilities()` 的原始值压成可上报的形状 */
36474
+ function extractClientCapabilities(raw) {
36475
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
36476
+ return undefined;
36477
+ }
36478
+ const caps = raw;
36479
+ const elicitation = caps.elicitation && typeof caps.elicitation === 'object' && !Array.isArray(caps.elicitation)
36480
+ ? caps.elicitation
36481
+ : undefined;
36482
+ const extensions = caps.extensions && typeof caps.extensions === 'object' && !Array.isArray(caps.extensions)
36483
+ ? caps.extensions
36484
+ : undefined;
36485
+ const elicitationForm = Boolean(elicitation?.form);
36486
+ const elicitationUrl = Boolean(elicitation?.url);
36487
+ const ui = Boolean(extensions && exports.MCP_UI_EXTENSION in extensions);
36488
+ const roots = Boolean(caps.roots);
36489
+ const sampling = Boolean(caps.sampling);
36490
+ const present = [];
36491
+ // 声明了 elicitation 但两个模式都没识别出来(例如只写了未知子字段):记一个不带模式的名字,
36492
+ // 不要伪造成 form —— 上报宁可少一个维度,也不能多一个假的。
36493
+ if (elicitation && !elicitationForm && !elicitationUrl) {
36494
+ present.push('elicitation');
36495
+ }
36496
+ if (elicitationForm) {
36497
+ present.push('elicitation:form');
36498
+ }
36499
+ if (elicitationUrl) {
36500
+ present.push('elicitation:url');
36501
+ }
36502
+ if (ui) {
36503
+ present.push('ui');
36504
+ }
36505
+ if (roots) {
36506
+ present.push('roots');
36507
+ }
36508
+ if (sampling) {
36509
+ present.push('sampling');
36510
+ }
36511
+ return {
36512
+ elicitationForm,
36513
+ elicitationUrl,
36514
+ ui,
36515
+ roots,
36516
+ sampling,
36517
+ summary: present.length > 0 ? present.join(',') : 'none',
36518
+ };
36519
+ }
36520
+ /**
36521
+ * 从 McpServer 读客户端能力。**每次工具调用都读**(不是只记首次):
36522
+ * SDK 在 initialize 后缓存,读取是纯内存操作;每次都记的好处是同一会话内
36523
+ * 客户端能力变化(重连换客户端)不会只反映在第一条上。
36524
+ *
36525
+ * ⚠️ 与 `readMcpClientInfoFromServer` **同源同风险**:值挂在 server 实例上,而
36526
+ * hosted/cloud 模式若把 McpServer 实例跨请求复用,读到的可能是**上一次** initialize
36527
+ * 的值(与 BFF 的 `Already connected` 同一片区域 —— 实例生命周期没隔离)。
36528
+ * 协议层没有按请求携带 clientInfo 的通道,这里不可能读得更准;要修得连同
36529
+ * `mcpClientName` 一起在 BFF 侧修实例隔离。发现能力分布明显串味时先从那里查。
36530
+ */
36531
+ function readClientCapabilitiesFromServer(server) {
36532
+ try {
36533
+ return extractClientCapabilities(server?.server?.getClientCapabilities?.());
36534
+ }
36535
+ catch {
36536
+ return undefined;
36537
+ }
36538
+ }
36539
+ function appendMcpClientCapabilityFields(eventData, capabilities) {
36540
+ if (!capabilities) {
36541
+ return;
36542
+ }
36543
+ eventData.mcpCaps = capabilities.summary;
36544
+ eventData.mcpCapsElicitation = capabilities.elicitationForm ? 'true' : 'false';
36545
+ eventData.mcpCapsUi = capabilities.ui ? 'true' : 'false';
36546
+ }
36377
36547
  // ---- 账号级归因(login_uin)----
36378
36548
  // 缓存键必须能区分凭证身份:hosted 是单进程多租户(网关按凭证缓存 MCP server 实例,
36379
36549
  // 同进程内并存多个租户),无键的进程级缓存会把 A 账号的 uin 上报到 B 账号的事件上。
@@ -36529,6 +36699,7 @@ const reportToolCall = async (params) => {
36529
36699
  eventData.client = client;
36530
36700
  }
36531
36701
  appendMcpClientInfoFields(eventData, params.mcpClientInfo);
36702
+ appendMcpClientCapabilityFields(eventData, params.mcpClientCapabilities);
36532
36703
  // Debug: 打印最终上报参数
36533
36704
  (0, logger_js_1.debug)('[telemetry] 工具调用上报参数', {
36534
36705
  toolName: params.toolName,
@@ -36542,6 +36713,42 @@ const reportToolCall = async (params) => {
36542
36713
  exports.telemetryReporter.report('toolkit_tool_call', eventData);
36543
36714
  };
36544
36715
  exports.reportToolCall = reportToolCall;
36716
+ const reportElicitationResult = async (params) => {
36717
+ const { nodeVersion, osType, osRelease, arch, mcpVersion } = exports.telemetryReporter.getUserAgent();
36718
+ const { envId } = resolveEnvId(params.cloudBaseOptions);
36719
+ const siteRegion = resolveTelemetrySiteRegion(params.cloudBaseOptions);
36720
+ const loginUin = await resolveLoginUin(params.cloudBaseOptions);
36721
+ const eventData = {
36722
+ phase: params.phase,
36723
+ field: params.field,
36724
+ optionCount: String(params.optionCount),
36725
+ toolName: params.toolName,
36726
+ duration: params.durationMs !== undefined ? String(params.durationMs) : undefined,
36727
+ value: params.value,
36728
+ // 与工具调用同一套截断规则,避免长错误撑爆列
36729
+ error: params.error ? params.error.substring(0, 200) : undefined,
36730
+ envId: envId || 'unknown',
36731
+ region: siteRegion.region,
36732
+ site: siteRegion.site,
36733
+ login_uin: loginUin,
36734
+ nodeVersion,
36735
+ osType,
36736
+ osRelease,
36737
+ arch,
36738
+ mcpVersion,
36739
+ };
36740
+ if (params.ide) {
36741
+ eventData.ide = params.ide;
36742
+ }
36743
+ const client = resolveClientName(params.client);
36744
+ if (client) {
36745
+ eventData.client = client;
36746
+ }
36747
+ appendMcpClientInfoFields(eventData, params.mcpClientInfo);
36748
+ appendMcpClientCapabilityFields(eventData, params.mcpClientCapabilities);
36749
+ exports.telemetryReporter.report('toolkit_elicitation', eventData);
36750
+ };
36751
+ exports.reportElicitationResult = reportElicitationResult;
36545
36752
  // Toolkit 生命周期上报
36546
36753
  const reportToolkitLifecycle = async (params) => {
36547
36754
  const { nodeVersion, osType, osRelease, arch, mcpVersion } = exports.telemetryReporter.getUserAgent();
@@ -36851,7 +37058,7 @@ function createWrappedHandler(name, handler, server) {
36851
37058
  if (isTestEnvironment) {
36852
37059
  throw error instanceof Error ? error : new Error(String(error));
36853
37060
  }
36854
- const mcpVersion = true ? "2.35.1" : 0;
37061
+ const mcpVersion = true ? "2.35.2" : 0;
36855
37062
  const requestIdSuffix = requestId ? `\n🆔 RequestId: ${requestId}` : '';
36856
37063
  const enhancedErrorMessage = `${errorMessage}${requestIdSuffix}\n\n📦 CloudBase MCP v${mcpVersion}\n${contributionHint(server)}`;
36857
37064
  // 创建新的错误对象,保持原有的错误类型但更新消息
@@ -36891,6 +37098,7 @@ function createWrappedHandler(name, handler, server) {
36891
37098
  ide: server.ide || process.env.INTEGRATION_IDE, // 传递集成IDE信息
36892
37099
  client: server.client || process.env.CLOUDBASE_MCP_CLIENT, // 传递 MCP client 来源标识
36893
37100
  mcpClientInfo: (0, telemetry_js_1.readMcpClientInfoFromServer)(server),
37101
+ mcpClientCapabilities: (0, telemetry_js_1.readClientCapabilitiesFromServer)(server),
36894
37102
  }).catch(err => {
36895
37103
  // 静默处理上报错误,不影响主要功能
36896
37104
  (0, logger_js_1.debug)('遥测上报失败', { toolName: name, error: err instanceof Error ? err.message : String(err) });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudbase/cloudbase-mcp",
3
- "version": "2.35.1",
3
+ "version": "2.35.2",
4
4
  "mcpName": "io.github.TencentCloudBase/cloudbase-mcp",
5
5
  "packageManager": "pnpm@10.8.0",
6
6
  "description": "CloudBase MCP Server — operate Tencent CloudBase (database, auth, functions, storage, hosting) from AI coding tools via the Model Context Protocol. Part of CloudBase AI Toolkit.",
package/server.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "name": "io.github.TencentCloudBase/cloudbase-mcp",
4
4
  "title": "CloudBase",
5
5
  "description": "CloudBase MCP: DB, functions, storage, hosting via @cloudbase/cloudbase-mcp",
6
- "version": "2.35.1",
6
+ "version": "2.35.2",
7
7
  "websiteUrl": "https://github.com/TencentCloudBase/CloudBase-AI-Toolkit",
8
8
  "repository": {
9
9
  "url": "https://github.com/TencentCloudBase/CloudBase-AI-Toolkit",
@@ -25,7 +25,7 @@
25
25
  "registryType": "npm",
26
26
  "registryBaseUrl": "https://registry.npmjs.org",
27
27
  "identifier": "@cloudbase/cloudbase-mcp",
28
- "version": "2.35.1",
28
+ "version": "2.35.2",
29
29
  "runtimeHint": "npx",
30
30
  "transport": {
31
31
  "type": "stdio"