@cloudbase/cloudbase-mcp 1.7.6 → 1.7.7

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
@@ -12,8 +12,8 @@
12
12
 
13
13
 
14
14
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
15
- [![npm version](https://badge.fury.io/js/%40cloudbase%2Fcloudbase-mcp.svg)](https://www.npmjs.com/package/@cloudbase/cloudbase-mcp)
16
- [![NPM Downloads](https://img.shields.io/npm/dw/%40cloudbase%2Fcloudbase-mcp)](https://www.npmjs.com/package/@cloudbase/cloudbase-mcp)
15
+ [![npm version](https://badge.fury.io/js/%40cloudbase%2Fcloudbase-mcp.svg)](https://badge.fury.io/js/%40cloudbase%2Fcloudbase-mcp)
16
+ ![NPM Downloads](https://img.shields.io/npm/dw/%40cloudbase%2Fcloudbase-mcp)
17
17
  [![GitHub stars](https://img.shields.io/github/stars/TencentCloudBase/CloudBase-AI-ToolKit?style=social&v=1)](https://github.com/TencentCloudBase/CloudBase-AI-ToolKit/stargazers)
18
18
  [![GitHub forks](https://img.shields.io/github/forks/TencentCloudBase/CloudBase-AI-ToolKit?style=social&v=1)](https://github.com/TencentCloudBase/CloudBase-AI-ToolKit/network/members)
19
19
 
@@ -21,32 +21,42 @@
21
21
  [![GitHub pull requests](https://img.shields.io/github/issues-pr/TencentCloudBase/CloudBase-AI-ToolKit)](https://github.com/TencentCloudBase/CloudBase-AI-ToolKit/pulls)
22
22
  [![GitHub last commit](https://img.shields.io/github/last-commit/TencentCloudBase/CloudBase-AI-ToolKit)](https://github.com/TencentCloudBase/CloudBase-AI-ToolKit/commits)
23
23
  [![GitHub contributors](https://img.shields.io/github/contributors/TencentCloudBase/CloudBase-AI-ToolKit)](https://github.com/TencentCloudBase/CloudBase-AI-ToolKit/graphs/contributors)
24
+
25
+
24
26
  [![CNB 镜像](https://img.shields.io/badge/CNB-CloudBase--AI--ToolKit-blue?logo=data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTIiIGhlaWdodD0iMTIiIHZpZXdCb3g9IjAgMCAxMiAxMiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMTIiIGhlaWdodD0iMTIiIHJ4PSIyIiBmaWxsPSIjM0I4MkY2Ii8+PHBhdGggZD0iTTUgM0g3VjVINSIgc3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSIxLjUiLz48cGF0aCBkPSJNNSA3SDdWOUg1IiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjEuNSIvPjwvc3ZnPg==)](https://cnb.cool/tencent/cloud/cloudbase/CloudBase-AI-ToolKit)
25
27
 
26
28
  当你在**Cursor/ VSCode GitHub Copilot/WinSurf/CodeBuddy/Augment Code**等AI编程工具里写代码时,它能自动帮你生成可直接部署的前后端应用+小程序,并一键发布到腾讯云开发 CloudBase。
27
29
 
30
+ <a href="https://www.producthunt.com/posts/cloudbase-ai-tookit?embed=true&utm_source=badge-featured&utm_medium=badge&utm_source=badge-cloudbase&#0045;ai&#0045;tookit" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=971451&theme=light&t=1748519563832" alt="CloudBase&#0032;AI&#0032;Tookit - Prompt&#0032;to&#0032;Production&#0058;&#0032;Full&#0045;stack&#0044;&#0032;DB&#0032;&#0038;&#0032;functions—zero&#0032;setup&#0046; | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
31
+
32
+ [![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=CloudBase&config=eyJjb21tYW5kIjoibnB4IEBjbG91ZGJhc2UvY2xvdWRiYXNlLW1jcEBsYXRlc3QiLCJlbnYiOnsiQ0xPVURCQVNFX0VOVl9JRCI6IllPVVJfRU5WX0lEIn0sImRpc2FibGVkIjpmYWxzZX0%3D)
33
+
34
+
35
+
36
+ ### 🚀 三大核心能力
28
37
 
29
- **📹 完整视频演示 ⬇️**
38
+ **🤖 AI智能开发**: AI自动生成代码和架构设计 <br>**☁️ 云开发集成**: 一键接入数据库、云函数、静态托管 <br>**⚡ 快速部署**: 几分钟内完成全栈应用上线
39
+ ### 🛠️ 支持平台
30
40
 
31
- <a href="https://www.bilibili.com/video/BV1hpjvzGESg/" target="_blank">
32
- <img style="max-width: 600px; height: auto;" src="https://7463-tcb-advanced-a656fc-1257967285.tcb.qcloud.la/mcp/video-banner.png" alt="视频演示" />
33
- </a>
41
+ **Web应用**: 现代化前端 + 静态托管<br>**微信小程序**: 云开发小程序解决方案<br>**后端服务**: 云数据库 + 无服务器函数+云托管
34
42
 
35
- | 🚀 **核心能力** | 🛠️ **支持平台** |
36
- |---|---|
37
- | 🤖 **AI智能开发**: AI自动生成代码和架构设计<br>☁️ **云开发集成**: 一键接入数据库、云函数、静态托管<br>⚡ **快速部署**: 几分钟内完成全栈应用上线 | **Web应用**: 现代化前端 + 静态托管<br>**微信小程序**: 云开发小程序解决方案<br>**后端服务**: 云数据库 + 无服务器函数+云托管 |
38
43
 
39
44
 
45
+ **完整视频演示**
46
+
47
+ https://github.com/user-attachments/assets/2b402fa6-c5c4-495a-b85b-f5d4a25daa4a
40
48
  </div>
41
49
 
42
50
  ## ✨ 核心特性
43
51
 
44
- - **🤖 AI 原生** - 专为 AI 编程工具设计的规则库,生成代码符合云开发最佳实践
45
- - **🚀 一键部署** - MCP 自动化部署到腾讯云开发 CloudBase 平台,Serverless 架构无需购买服务器
46
- - **📱 全栈应用** - Web + 小程序 + 数据库 + 后端一体化,支持多种应用形式和后端托管
47
- - **🔧 智能修复** - AI 自动查看日志并修复问题,降低运维成本
48
- - **⚡ 极速体验** - 国内 CDN 加速,比海外平台访问速度更快
49
- - **📚 知识检索** - 内置云开发、微信小程序等专业知识库的智能向量检索
52
+ | 特性 | 说明 | 优势 |
53
+ |------|------|------|
54
+ | **🤖 AI 原生** | 专为 AI 编程工具设计的规则库 | 生成代码符合云开发最佳实践 |
55
+ | **🚀 一键部署** | MCP 自动化部署到腾讯云开发 CloudBase 平台 | Serverless 架构,无需购买服务器 |
56
+ | **📱 全栈应用** | Web + 小程序 + 数据库 + 后端一体化 | 支持小程序/web 等多种应用形式,提供后端托管和数据库 |
57
+ | **🔧 智能修复** | AI 自动查看日志并修复问题 | 降低运维成本 |
58
+ | **⚡ 极速体验** | 国内 CDN 加速 | 比海外平台访问速度更快 |
59
+ | **📚 知识检索** | 内置支持云开发、微信小程序等专业知识 |专业知识库的智能向量检索
50
60
 
51
61
 
52
62
  ## 🚀 快速开始
@@ -54,49 +64,12 @@
54
64
 
55
65
  ### 0. 前置条件
56
66
 
57
- <details>
58
- <summary>安装 AI 开发工具</summary>
59
-
67
+ #### 安装 AI 开发工具
60
68
  例如 [Cursor](https://www.cursor.com/) | [WindSurf](https://windsurf.com/editor) | [CodeBuddy](https://copilot.tencent.com/) 等,点击查看 [支持的 AI 开发工具列表](#2-配置你的-ai-ide)
61
69
 
62
- </details>
63
-
64
- <details>
65
- <summary>开通云开发环境</summary>
66
-
70
+ #### 开通云开发环境
67
71
  访问 [腾讯云开发控制台](https://tcb.cloud.tencent.com/dev)开通环境,新用户可以免费开通体验。
68
72
 
69
- </details>
70
-
71
- <details>
72
- <summary>安装 Node.js v18及以上版本</summary>
73
-
74
- 确保您的计算机上安装了 Node.js v18 及以上版本。您可以从 [Node.js 官网](https://nodejs.org/) 下载并安装最新版本。
75
-
76
- </details>
77
-
78
- <details>
79
- <summary>可选:设置 npm 源</summary>
80
-
81
- 为了提高依赖包的下载速度,建议将 npm 源设置为腾讯镜像源。您可以在**终端命令行**中运行以下命令:
82
-
83
- ```bash
84
- npm config set registry https://mirrors.cloud.tencent.com/npm/
85
- ```
86
-
87
- 这样可以加快依赖包的下载速度,特别是在中国大陆地区。
88
- </details>
89
-
90
- <details>
91
- <summary>可选:清理 npx 缓存</summary>
92
- 由于 npx 这个工具本身存在一个缓存的 bug,可能导致 CloudBase AI ToolKit 安装问题,您可以尝试清理 npx 缓存。
93
-
94
- 在**终端命令行**中运行以下命令:
95
- ```
96
- npx -y clear-npx-cache
97
- ```
98
- </details>
99
-
100
73
  ### 1. 快速初始化或增强你的项目
101
74
 
102
75
  我们为你准备了内置云开发最佳实践和 AI IDE 规则的项目模板,推荐如下两种方式:
@@ -105,14 +78,11 @@ npx -y clear-npx-cache
105
78
 
106
79
  选择适合你的模板,一键初始化:
107
80
 
108
- - **微信小程序 + 云开发模板**
109
- [下载代码包](https://static.cloudbase.net/cloudbase-examples/miniprogram-cloudbase-miniprogram-template.zip?v=2025053001) | [开源代码地址](https://github.com/TencentCloudBase/awesome-cloudbase-examples/tree/master/miniprogram/cloudbase-miniprogram-template)
110
-
111
81
  - **React Web 应用 + 云开发模板**
112
82
  [下载代码包](https://static.cloudbase.net/cloudbase-examples/web-cloudbase-react-template.zip?v=2025053001) | [开源代码地址](https://github.com/TencentCloudBase/awesome-cloudbase-examples/tree/master/web/cloudbase-react-template)
113
83
 
114
- - **Vue Web 应用 + 云开发模板**
115
- [下载代码包](https://static.cloudbase.net/cloudbase-examples/web-cloudbase-vue-template.zip?v=2025053001) | [开源代码地址](https://github.com/TencentCloudBase/awesome-cloudbase-examples/tree/master/web/cloudbase-vue-template)
84
+ - **微信小程序 + 云开发模板**
85
+ [下载代码包](https://static.cloudbase.net/cloudbase-examples/miniprogram-cloudbase-miniprogram-template.zip?v=2025053001) | [开源代码地址](https://github.com/TencentCloudBase/awesome-cloudbase-examples/tree/master/miniprogram/cloudbase-miniprogram-template)
116
86
 
117
87
  - **AI 规则通用云开发模板** :不限定语言和框架,内置 CloudBase AI 规则和MCP,适用于任意云开发项目
118
88
 
@@ -125,9 +95,6 @@ npx -y clear-npx-cache
125
95
 
126
96
  ### 2. 配置你的 AI IDE
127
97
 
128
- > [!TIP]
129
- > 温馨提示:如果你使用的是模板项目,所有配置都已经预置完成,请按照指引进行检查和开启工具。如果不是从模板开始,需要按具体的说明手动添加相应配置:
130
-
131
98
  以下工具均支持 CloudBase AI ToolKit,选择合适的工具并按说明配置:
132
99
 
133
100
  | 工具 | 支持平台 |
@@ -143,6 +110,7 @@ npx -y clear-npx-cache
143
110
  | [文心快码](https://comate.baidu.com/) | VS Code、JetBrains插件|
144
111
  | [Augment Code](https://www.augmentcode.com/) | VS Code、JetBrains 插件 |
145
112
 
113
+ 如果你使用的是模板项目,所有配置都已经预置完成,请按照指引进行检查和开启工具。如果不是从模板开始,需要按具体的说明手动添加相应配置:
146
114
 
147
115
  <details>
148
116
  <summary><strong>🔧 Cursor 配置</strong></summary>
@@ -155,7 +123,7 @@ npx -y clear-npx-cache
155
123
 
156
124
  如果使用模板项目,MCP 配置已经预置完成。如果不是从模板开始,可以点击下方按钮安装到 Cursor 中:
157
125
 
158
- [![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=CloudBase&config=eyJjb21tYW5kIjoibnB4IEBjbG91ZGJhc2UvY2xvdWRiYXNlLW1jcEBsYXRlc3QiLCJkaXNhYmxlZCI6ZmFsc2V9)
126
+ [![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=CloudBase&config=eyJjb21tYW5kIjoibnB4IEBjbG91ZGJhc2UvY2xvdWRiYXNlLW1jcEBsYXRlc3QiLCJlbnYiOnsiQ0xPVURCQVNFX0VOVl9JRCI6IllPVVJfRU5WX0lEIn0sImRpc2FibGVkIjpmYWxzZX0%3D)
159
127
 
160
128
  或手动添加配置到 `.cursor/mcp.json`:
161
129
 
@@ -215,12 +183,12 @@ npx -y clear-npx-cache
215
183
 
216
184
  #### 步骤2:配置 MCP
217
185
 
218
- 点开 CodeBuddy 右上角的 MCP 按钮,点击右侧的添加,在 MCP 配置中添加云开发的 MCP
186
+ 如果使用模板项目,MCP 配置已经预置完成。如果不是从模板开始,需要在 MCP 配置中添加:
219
187
 
220
188
  ```json
221
189
  {
222
190
  "mcpServers": {
223
- "cloudbase": {
191
+ "cloudbase-mcp": {
224
192
  "command": "npx",
225
193
  "args": ["-y", "@cloudbase/cloudbase-mcp@latest"]
226
194
  }
@@ -612,7 +580,7 @@ AI 会自动:
612
580
 
613
581
  ## 📋 常见问题 FAQ
614
582
 
615
- 如有迁移、集成等常见疑问,请查阅 [FAQ 常见问题](https://docs.cloudbase.net/ai/cloudbase-ai-toolkit/faq)。
583
+ 如有迁移、集成等常见疑问,请查阅 [FAQ 常见问题](./FAQ.md)。
616
584
 
617
585
  ## 💬 技术交流群
618
586
 
@@ -671,7 +639,6 @@ AI 会自动:
671
639
  | queryDocuments | 查询集合中的文档 |
672
640
  | updateDocuments | 更新集合中的文档 |
673
641
  | deleteDocuments | 删除集合中的文档 |
674
- | manageDataModel | 数据模型查询工具,支持查询和列表数据模型(只读操作)。list操作返回基础信息,get操作返回详细信息含Schema(字段列表、格式、关联关系等),docs操作生成SDK使用文档 |
675
642
  | uploadFiles | 上传文件到静态网站托管 |
676
643
  | listFiles | 获取静态网站托管的文件列表 |
677
644
  | deleteFiles | 删除静态网站托管的文件或文件夹 |
@@ -689,7 +656,7 @@ AI 会自动:
689
656
  | deleteFunctionTrigger | 删除云函数触发器 |
690
657
  | downloadRemoteFile | 下载远程文件到本地临时文件 |
691
658
  | uploadFile | 上传文件到云存储(适合存储业务数据文件) |
692
- | searchKnowledgeBase | 智能检索云开发知识库(支持云开发与云函数以及小程序知识),通过向量搜索快速获取专业文档与答案。|
659
+ | searchKnowledgeBase | 智能检索云开发知识库(支持云开发与云函数),通过向量搜索快速获取专业文档与答案。|
693
660
  | interactiveDialog | 统一的交互式对话工具,支持需求澄清和任务确认 |
694
661
 
695
662
  ## 🏗️ 架构原理
@@ -709,15 +676,6 @@ graph TD
709
676
  J --> K[Web/小程序/API]
710
677
  ```
711
678
 
712
- ## 🔒 数据统计说明
713
-
714
- 为了改进产品体验,CloudBase AI ToolKit 会收集匿名使用统计信息:
715
-
716
- - **收集内容**:工具调用情况、基础环境信息(操作系统、Node.js版本等)
717
- - **隐私保护**:不收集代码内容、文件路径等敏感信息,仅用于产品改进
718
-
719
- 可通过环境变量 `CLOUDBASE_MCP_TELEMETRY_DISABLED` 设置为 `true` 禁用数据统计
720
-
721
679
  ## 🤝 贡献指南
722
680
 
723
681
  欢迎提交 Issue 和 Pull Request!请查看我们的[贡献指南](CONTRIBUTING.md)了解如何参与项目开发。
@@ -87,10 +87,6 @@ class EnvironmentManager {
87
87
  }
88
88
  // 全局实例
89
89
  const envManager = new EnvironmentManager();
90
- // 导出环境ID获取函数
91
- export async function getEnvId() {
92
- return envManager.getEnvId();
93
- }
94
90
  // 导出函数保持兼容性
95
91
  export function resetCloudBaseManagerCache() {
96
92
  envManager.reset();
package/dist/index.js CHANGED
@@ -2,7 +2,6 @@
2
2
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
4
  import { registerEnvTools } from "./tools/env.js";
5
- // import { registerFileTools } from "./tools/file.js";
6
5
  import { registerFunctionTools } from "./tools/functions.js";
7
6
  import { registerDatabaseTools } from "./tools/database.js";
8
7
  import { registerHostingTools } from "./tools/hosting.js";
@@ -11,8 +10,6 @@ import { registerStorageTools } from "./tools/storage.js";
11
10
  import { registerRagTools } from './tools/rag.js';
12
11
  import { registerSetupTools } from "./tools/setup.js";
13
12
  import { registerInteractiveTools } from "./tools/interactive.js";
14
- import { wrapServerWithTelemetry } from "./utils/tool-wrapper.js";
15
- import { telemetryReporter } from "./utils/telemetry.js";
16
13
  // Create server instance
17
14
  const server = new McpServer({
18
15
  name: "cloudbase-mcp",
@@ -22,8 +19,6 @@ const server = new McpServer({
22
19
  tools: {},
23
20
  },
24
21
  });
25
- // 启用数据上报功能(包装工具调用)
26
- wrapServerWithTelemetry(server);
27
22
  // Register environment management tools
28
23
  registerEnvTools(server);
29
24
  // Register RAG tools
@@ -48,14 +43,6 @@ async function main() {
48
43
  const transport = new StdioServerTransport();
49
44
  await server.connect(transport);
50
45
  console.log("TencentCloudBase MCP Server running on stdio");
51
- // 上报启动信息
52
- if (telemetryReporter.isEnabled()) {
53
- telemetryReporter.report('mcp_server_start', {
54
- version: '1.0.0',
55
- nodeVersion: process.version,
56
- platform: process.platform
57
- });
58
- }
59
46
  }
60
47
  main().catch((error) => {
61
48
  console.error("Fatal error in main():", error);
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { getCloudBaseManager, getEnvId } from '../cloudbase-manager.js';
2
+ import { getCloudBaseManager } from '../cloudbase-manager.js';
3
3
  // 获取数据库实例ID
4
4
  async function getDatabaseInstanceId() {
5
5
  const cloudbase = await getCloudBaseManager();
@@ -9,352 +9,6 @@ async function getDatabaseInstanceId() {
9
9
  }
10
10
  return EnvInfo.Databases[0].InstanceId;
11
11
  }
12
- // 生成SDK使用文档的函数
13
- function generateSDKDocs(modelName, modelTitle, userFields, relations) {
14
- // 获取主要字段(前几个非关联字段)
15
- const mainFields = userFields.filter(f => !f.linkage);
16
- const requiredFields = userFields.filter(f => f.required);
17
- const stringFields = userFields.filter(f => f.type === 'string' && !f.linkage);
18
- const numberFields = userFields.filter(f => f.type === 'number');
19
- // 生成字段示例值
20
- const generateFieldValue = (field) => {
21
- if (field.enum && field.enum.length > 0) {
22
- return `"${field.enum[0]}"`;
23
- }
24
- switch (field.type) {
25
- case 'string':
26
- return field.format === 'email' ? '"user@example.com"' :
27
- field.format === 'url' ? '"https://example.com"' :
28
- `"示例${field.title || field.name}"`;
29
- case 'number':
30
- return field.format === 'currency' ? '99.99' : '1';
31
- case 'boolean':
32
- return field.default !== undefined ? field.default : 'true';
33
- case 'array':
34
- return '[]';
35
- case 'object':
36
- return '{}';
37
- default:
38
- return `"${field.title || field.name}值"`;
39
- }
40
- };
41
- // 生成创建数据示例
42
- const createDataExample = mainFields.map(field => ` ${field.name}: ${generateFieldValue(field)}, // ${field.description || field.title || field.name}`).join('\n');
43
- // 生成更新数据示例
44
- const updateDataExample = mainFields.slice(0, 2).map(field => ` ${field.name}: ${generateFieldValue(field)}, // ${field.description || field.title || field.name}`).join('\n');
45
- // 生成查询条件示例
46
- const queryField = stringFields[0] || mainFields[0];
47
- const queryExample = queryField ?
48
- ` ${queryField.name}: {\n $eq: ${generateFieldValue(queryField)}, // 根据${queryField.description || queryField.title || queryField.name}查询\n },` :
49
- ' _id: {\n $eq: "记录ID", // 根据ID查询\n },';
50
- return `# 数据模型 ${modelTitle} (${modelName}) SDK 使用文档
51
-
52
- ## 数据模型字段说明
53
-
54
- ${userFields.map(field => {
55
- let fieldDoc = `- **${field.name}** (${field.type})`;
56
- if (field.required)
57
- fieldDoc += ' *必填*';
58
- if (field.description)
59
- fieldDoc += `: ${field.description}`;
60
- if (field.format)
61
- fieldDoc += ` [格式: ${field.format}]`;
62
- if (field.enum)
63
- fieldDoc += ` [可选值: ${field.enum.join(', ')}]`;
64
- if (field.default !== undefined)
65
- fieldDoc += ` [默认值: ${field.default}]`;
66
- return fieldDoc;
67
- }).join('\n')}
68
-
69
- ${relations.length > 0 ? `
70
- ## 关联关系
71
-
72
- ${relations.map(rel => `- **${rel.field}**: 关联到 ${rel.targetModel} 模型的 ${rel.foreignKey} 字段`).join('\n')}
73
- ` : ''}
74
-
75
- ## 增删改查操作
76
-
77
- ### 创建数据
78
-
79
- #### 创建单条数据 \`create\`
80
-
81
- \`\`\`javascript
82
- const { data } = await models.${modelName}.create({
83
- data: {
84
- ${createDataExample}
85
- },
86
- });
87
-
88
- // 返回创建的记录 id
89
- console.log(data);
90
- // { id: "7d8ff72c665eb6c30243b6313aa8539e"}
91
- \`\`\`
92
-
93
- #### 创建多条数据 \`createMany\`
94
-
95
- \`\`\`javascript
96
- const { data } = await models.${modelName}.createMany({
97
- data: [
98
- {
99
- ${createDataExample}
100
- },
101
- {
102
- ${createDataExample}
103
- },
104
- ],
105
- });
106
-
107
- // 返回创建的记录 idList
108
- console.log(data);
109
- // {
110
- // "idList": [
111
- // "7d8ff72c665ebe5c02442a1a7b29685e",
112
- // "7d8ff72c665ebe5c02442a1b77feba4b"
113
- // ]
114
- // }
115
- \`\`\`
116
-
117
- ### 更新数据
118
-
119
- #### 更新单条数据 \`update\`
120
-
121
- \`\`\`javascript
122
- const { data } = await models.${modelName}.update({
123
- data: {
124
- ${updateDataExample}
125
- },
126
- filter: {
127
- where: {
128
- _id: {
129
- $eq: "记录ID", // 推荐传入_id数据标识进行操作
130
- },
131
- },
132
- },
133
- });
134
-
135
- // 返回更新成功的条数
136
- console.log(data);
137
- // { count: 1}
138
- \`\`\`
139
-
140
- #### 创建或更新数据 \`upsert\`
141
-
142
- \`\`\`javascript
143
- const recordData = {
144
- ${createDataExample}
145
- _id: "指定ID",
146
- };
147
-
148
- const { data } = await models.${modelName}.upsert({
149
- create: recordData,
150
- update: recordData,
151
- filter: {
152
- where: {
153
- _id: {
154
- $eq: recordData._id,
155
- },
156
- },
157
- },
158
- });
159
-
160
- console.log(data);
161
- // 新增时返回: { "count": 0, "id": "指定ID" }
162
- // 更新时返回: { "count": 1, "id": "" }
163
- \`\`\`
164
-
165
- #### 更新多条数据 \`updateMany\`
166
-
167
- \`\`\`javascript
168
- const { data } = await models.${modelName}.updateMany({
169
- data: {
170
- ${updateDataExample}
171
- },
172
- filter: {
173
- where: {
174
- ${queryExample}
175
- },
176
- },
177
- });
178
-
179
- // 返回更新成功的条数
180
- console.log(data);
181
- // { "count": 5 }
182
- \`\`\`
183
-
184
- ### 删除数据
185
-
186
- #### 删除单条 \`delete\`
187
-
188
- \`\`\`javascript
189
- const { data } = await models.${modelName}.delete({
190
- filter: {
191
- where: {
192
- _id: {
193
- $eq: "记录ID", // 推荐传入_id数据标识进行操作
194
- },
195
- },
196
- },
197
- });
198
-
199
- // 返回删除成功的条数
200
- console.log(data);
201
- // { "count": 1 }
202
- \`\`\`
203
-
204
- #### 删除多条 \`deleteMany\`
205
-
206
- \`\`\`javascript
207
- const { data } = await models.${modelName}.deleteMany({
208
- filter: {
209
- where: {
210
- ${queryExample}
211
- },
212
- },
213
- });
214
-
215
- // 返回删除成功的条数
216
- console.log(data);
217
- // { "count": 3 }
218
- \`\`\`
219
-
220
- ### 读取数据
221
-
222
- #### 读取单条数据 \`get\`
223
-
224
- \`\`\`javascript
225
- const { data } = await models.${modelName}.get({
226
- filter: {
227
- where: {
228
- _id: {
229
- $eq: "记录ID", // 推荐传入_id数据标识进行操作
230
- },
231
- },
232
- },
233
- });
234
-
235
- // 返回查询到的数据
236
- console.log(data);
237
- // {
238
- // "_id": "记录ID",
239
- ${userFields.slice(0, 5).map(field => `// "${field.name}": ${generateFieldValue(field)}, // ${field.description || field.title || field.name}`).join('\n')}
240
- // "createdAt": 1717488585078,
241
- // "updatedAt": 1717490751944
242
- // }
243
- \`\`\`
244
-
245
- #### 读取多条数据 \`list\`
246
-
247
- \`\`\`javascript
248
- const { data } = await models.${modelName}.list({
249
- filter: {
250
- where: {
251
- ${queryExample}
252
- },
253
- },
254
- getCount: true, // 开启用来获取总数
255
- });
256
-
257
- // 返回查询到的数据列表 records 和 总数 total
258
- console.log(data);
259
- // {
260
- // "records": [
261
- // {
262
- // "_id": "记录ID1",
263
- ${userFields.slice(0, 3).map(field => `// "${field.name}": ${generateFieldValue(field)}, // ${field.description || field.title || field.name}`).join('\n')}
264
- // "createdAt": 1717488585078,
265
- // "updatedAt": 1717490751944
266
- // },
267
- // // ... 更多记录
268
- // ],
269
- // "total": 10
270
- // }
271
- \`\`\`
272
-
273
- ## 查询条件和排序
274
-
275
- ### 常用查询条件
276
-
277
- \`\`\`javascript
278
- // 等于查询
279
- const { data } = await models.${modelName}.list({
280
- filter: {
281
- where: {
282
- ${queryField ? ` ${queryField.name}: {
283
- $eq: ${generateFieldValue(queryField)}, // ${queryField.description || queryField.title || queryField.name}等于指定值
284
- },` : ' _id: { $eq: "记录ID" },'}
285
- },
286
- },
287
- });
288
-
289
- ${stringFields.length > 0 ? `// 模糊查询
290
- const { data: searchData } = await models.${modelName}.list({
291
- filter: {
292
- where: {
293
- ${stringFields[0].name}: {
294
- $regex: "关键词", // ${stringFields[0].description || stringFields[0].title || stringFields[0].name}包含关键词
295
- },
296
- },
297
- },
298
- });` : ''}
299
-
300
- ${numberFields.length > 0 ? `// 范围查询
301
- const { data: rangeData } = await models.${modelName}.list({
302
- filter: {
303
- where: {
304
- ${numberFields[0].name}: {
305
- $gte: 10, // ${numberFields[0].description || numberFields[0].title || numberFields[0].name}大于等于10
306
- $lte: 100, // ${numberFields[0].description || numberFields[0].title || numberFields[0].name}小于等于100
307
- },
308
- },
309
- },
310
- });` : ''}
311
- \`\`\`
312
-
313
- ### 排序
314
-
315
- \`\`\`javascript
316
- const { data } = await models.${modelName}.list({
317
- filter: {
318
- where: {},
319
- orderBy: [
320
- {
321
- ${mainFields[0] ? `${mainFields[0].name}: "asc", // 按${mainFields[0].description || mainFields[0].title || mainFields[0].name}升序` : '_id: "desc", // 按ID降序'}
322
- },
323
- ],
324
- },
325
- });
326
- \`\`\`
327
-
328
- ${relations.length > 0 ? `
329
- ## 关联查询
330
-
331
- ${relations.map(rel => `
332
- ### 查询关联的 ${rel.targetModel} 数据
333
-
334
- \`\`\`javascript
335
- const { data } = await models.${modelName}.list({
336
- filter: {
337
- where: {},
338
- include: {
339
- ${rel.field}: true, // 包含关联的${rel.targetModel}数据
340
- },
341
- },
342
- });
343
-
344
- // 返回的数据中会包含关联信息
345
- console.log(data.records[0].${rel.field});
346
- \`\`\`
347
- `).join('')}
348
- ` : ''}
349
-
350
- ## 更多操作
351
-
352
- 更多高级查询、分页、聚合等操作,请参考:
353
- - [查询和筛选](https://docs.cloudbase.net/model/select)
354
- - [过滤和排序](https://docs.cloudbase.net/model/filter-and-sort)
355
- ${relations.length > 0 ? '- [关联关系](https://docs.cloudbase.net/model/relation)' : ''}
356
- `;
357
- }
358
12
  export function registerDatabaseTools(server) {
359
13
  // 创建云开发数据库集合
360
14
  server.tool("createCollection", "创建一个新的云开发数据库集合", {
@@ -1005,257 +659,4 @@ export function registerDatabaseTools(server) {
1005
659
  };
1006
660
  }
1007
661
  });
1008
- // 数据模型查询工具
1009
- server.tool("manageDataModel", "数据模型查询工具,支持查询和列表数据模型(只读操作)。list操作返回基础信息(不含Schema),get操作返回详细信息(含简化的Schema,包括字段列表、格式、关联关系等),docs操作生成SDK使用文档", {
1010
- action: z.enum(["get", "list", "docs"]).describe("操作类型:get=查询单个模型(含Schema字段列表、格式、关联关系),list=获取模型列表(不含Schema),docs=生成SDK使用文档"),
1011
- name: z.string().optional().describe("模型名称(get操作时必填)"),
1012
- names: z.array(z.string()).optional().describe("模型名称数组(list操作时可选,用于过滤)")
1013
- }, async ({ action, name, names }) => {
1014
- try {
1015
- const cloudbase = await getCloudBaseManager();
1016
- let currentEnvId = await getEnvId();
1017
- let result;
1018
- switch (action) {
1019
- case 'get':
1020
- if (!name) {
1021
- throw new Error('获取数据模型需要提供模型名称');
1022
- }
1023
- try {
1024
- result = await cloudbase.commonService('lowcode').call({
1025
- Action: 'DescribeBasicDataSource',
1026
- Param: {
1027
- EnvId: currentEnvId,
1028
- Name: name
1029
- }
1030
- });
1031
- // 只保留基础字段,过滤掉冗余信息,并简化Schema
1032
- let simplifiedSchema = null;
1033
- // 解析并简化Schema
1034
- if (result.Data.Schema) {
1035
- try {
1036
- const schema = JSON.parse(result.Data.Schema);
1037
- const properties = schema.properties || {};
1038
- // 提取用户定义的字段(排除系统字段)
1039
- const userFields = Object.keys(properties)
1040
- .filter(key => !properties[key]['x-system']) // 排除系统字段
1041
- .map(key => {
1042
- const field = properties[key];
1043
- const fieldInfo = {
1044
- name: key,
1045
- type: field.type,
1046
- format: field.format,
1047
- title: field.title || key,
1048
- required: schema.required?.includes(key) || false,
1049
- description: field.description || ''
1050
- };
1051
- if (field['x-parent']) {
1052
- fieldInfo.linkage = field['x-parent'];
1053
- }
1054
- return fieldInfo;
1055
- });
1056
- // 提取关联关系
1057
- const relations = userFields
1058
- .filter(field => field.linkage)
1059
- .map(field => ({
1060
- field: field.name,
1061
- type: field.format,
1062
- title: field.title,
1063
- targetModel: field.linkage.parentDataSourceName,
1064
- foreignKey: field.linkage.parentFieldKey,
1065
- displayField: field.linkage.parentFieldTitle
1066
- }));
1067
- simplifiedSchema = {
1068
- userFields,
1069
- relations,
1070
- totalFields: Object.keys(properties).length,
1071
- userFieldsCount: userFields.length
1072
- };
1073
- }
1074
- catch (e) {
1075
- simplifiedSchema = { error: 'Schema解析失败' };
1076
- }
1077
- }
1078
- const simplifiedModel = {
1079
- DbInstanceType: result.Data.DbInstanceType,
1080
- Title: result.Data.Title,
1081
- Description: result.Data.Description,
1082
- Name: result.Data.Name,
1083
- UpdatedAt: result.Data.UpdatedAt,
1084
- Schema: simplifiedSchema
1085
- };
1086
- return {
1087
- content: [{
1088
- type: "text",
1089
- text: JSON.stringify({
1090
- success: true,
1091
- action: 'get',
1092
- data: simplifiedModel,
1093
- message: "获取数据模型成功"
1094
- }, null, 2)
1095
- }]
1096
- };
1097
- }
1098
- catch (error) {
1099
- if (error.original?.Code === 'ResourceNotFound') {
1100
- return {
1101
- content: [{
1102
- type: "text",
1103
- text: JSON.stringify({
1104
- success: false,
1105
- action: 'get',
1106
- error: 'ResourceNotFound',
1107
- message: `数据模型 ${name} 不存在`
1108
- }, null, 2)
1109
- }]
1110
- };
1111
- }
1112
- throw error;
1113
- }
1114
- case 'list':
1115
- // 构建请求参数
1116
- const listParams = {
1117
- EnvId: currentEnvId,
1118
- PageIndex: 1,
1119
- PageSize: 1000,
1120
- QuerySystemModel: true, // 查询系统模型
1121
- QueryConnector: 0 // 0 表示数据模型
1122
- };
1123
- // 只有当 names 参数存在且不为空时才添加过滤条件
1124
- if (names && names.length > 0) {
1125
- listParams.DataSourceNames = names;
1126
- }
1127
- result = await cloudbase.commonService('lowcode').call({
1128
- Action: 'DescribeDataSourceList',
1129
- Param: listParams
1130
- });
1131
- const models = result.Data?.Rows || [];
1132
- // 只保留基础字段,list操作不返回Schema
1133
- const simplifiedModels = models.map((model) => ({
1134
- DbInstanceType: model.DbInstanceType,
1135
- Title: model.Title,
1136
- Description: model.Description,
1137
- Name: model.Name,
1138
- UpdatedAt: model.UpdatedAt
1139
- }));
1140
- return {
1141
- content: [{
1142
- type: "text",
1143
- text: JSON.stringify({
1144
- success: true,
1145
- action: 'list',
1146
- data: simplifiedModels,
1147
- count: simplifiedModels.length,
1148
- message: "获取数据模型列表成功"
1149
- }, null, 2)
1150
- }]
1151
- };
1152
- case 'docs':
1153
- if (!name) {
1154
- throw new Error('生成SDK文档需要提供模型名称');
1155
- }
1156
- try {
1157
- // 先获取模型信息
1158
- result = await cloudbase.commonService('lowcode').call({
1159
- Action: 'DescribeBasicDataSource',
1160
- Param: {
1161
- EnvId: currentEnvId,
1162
- Name: name
1163
- }
1164
- });
1165
- if (!result.Data) {
1166
- throw new Error(`数据模型 ${name} 不存在`);
1167
- }
1168
- // 解析Schema获取字段信息
1169
- let userFields = [];
1170
- let relations = [];
1171
- if (result.Data.Schema) {
1172
- try {
1173
- const schema = JSON.parse(result.Data.Schema);
1174
- console.log(result.Data);
1175
- const properties = schema.properties || {};
1176
- // 提取用户定义的字段
1177
- userFields = Object.keys(properties)
1178
- .filter(key => !properties[key]['x-system'])
1179
- .map(key => {
1180
- const field = properties[key];
1181
- return {
1182
- name: key,
1183
- type: field.type,
1184
- title: field.title || key,
1185
- required: schema.required?.includes(key) || false,
1186
- description: field.description || '',
1187
- format: field.format,
1188
- enum: field.enum,
1189
- default: field.default,
1190
- linkage: field['x-parent']
1191
- };
1192
- });
1193
- // 提取关联关系
1194
- relations = userFields
1195
- .filter(field => field.linkage)
1196
- .map(field => ({
1197
- field: field.name,
1198
- type: field.format,
1199
- title: field.title,
1200
- targetModel: field.linkage.parentDataSourceName,
1201
- foreignKey: field.linkage.parentFieldKey,
1202
- displayField: field.linkage.parentFieldTitle
1203
- }));
1204
- }
1205
- catch (e) {
1206
- // Schema解析失败,使用空数组
1207
- console.error('Schema解析失败', e);
1208
- }
1209
- }
1210
- // 生成SDK使用文档
1211
- const docs = generateSDKDocs(result.Data.Name, result.Data.Title, userFields, relations);
1212
- return {
1213
- content: [{
1214
- type: "text",
1215
- text: JSON.stringify({
1216
- success: true,
1217
- action: 'docs',
1218
- modelName: name,
1219
- modelTitle: result.Data.Title,
1220
- docs,
1221
- message: "SDK使用文档生成成功"
1222
- }, null, 2)
1223
- }]
1224
- };
1225
- }
1226
- catch (error) {
1227
- if (error.original?.Code === 'ResourceNotFound') {
1228
- return {
1229
- content: [{
1230
- type: "text",
1231
- text: JSON.stringify({
1232
- success: false,
1233
- action: 'docs',
1234
- error: 'ResourceNotFound',
1235
- message: `数据模型 ${name} 不存在`
1236
- }, null, 2)
1237
- }]
1238
- };
1239
- }
1240
- throw error;
1241
- }
1242
- default:
1243
- throw new Error(`不支持的操作类型: ${action}`);
1244
- }
1245
- }
1246
- catch (error) {
1247
- return {
1248
- content: [{
1249
- type: "text",
1250
- text: JSON.stringify({
1251
- success: false,
1252
- action,
1253
- error: error.message || error.original?.Message || '未知错误',
1254
- code: error.original?.Code,
1255
- message: "数据模型操作失败"
1256
- }, null, 2)
1257
- }]
1258
- };
1259
- }
1260
- });
1261
662
  }
package/dist/tools/env.js CHANGED
@@ -9,7 +9,7 @@ export function registerEnvTools(server) {
9
9
  forceUpdate: z.boolean().optional().describe("是否强制重新选择环境")
10
10
  }, async ({ forceUpdate = false }) => {
11
11
  try {
12
- const { selectedEnvId, cancelled, error, noEnvs } = await _promptAndSetEnvironmentId(forceUpdate);
12
+ const { selectedEnvId, cancelled, error, noEnvs } = await _promptAndSetEnvironmentId(false);
13
13
  debug("login", { selectedEnvId, cancelled, error, noEnvs });
14
14
  if (error) {
15
15
  return { content: [{ type: "text", text: error }] };
@@ -48,7 +48,7 @@ export function registerEnvTools(server) {
48
48
  await logout();
49
49
  // 清理环境ID配置
50
50
  await clearUserEnvId();
51
- resetCloudBaseManagerCache();
51
+ await resetCloudBaseManagerCache();
52
52
  return {
53
53
  content: [{
54
54
  type: "text",
@@ -8,7 +8,7 @@ export const SUPPORTED_NODEJS_RUNTIMES = [
8
8
  'Nodejs 14.18',
9
9
  'Nodejs 12.16',
10
10
  'Nodejs 10.15',
11
- 'Nodejs 8.9',
11
+ 'Nodejs 8.9(即将下线)',
12
12
  ];
13
13
  export const DEFAULT_NODEJS_RUNTIME = 'Nodejs 18.15';
14
14
  /**
@@ -57,7 +57,7 @@ export function registerFunctionTools(server) {
57
57
  vpcId: z.string(),
58
58
  subnetId: z.string()
59
59
  }).optional().describe("私有网络配置"),
60
- runtime: z.string().optional().describe("运行时环境,建议指定为 'Nodejs 18.15',其他可选值:" + SUPPORTED_NODEJS_RUNTIMES.join(',')),
60
+ runtime: z.string().optional().describe("运行时环境,可选值:" + SUPPORTED_NODEJS_RUNTIMES.join(',') + ",默认 Nodejs 18.15"),
61
61
  installDependency: z.boolean().optional().describe("是否安装依赖,建议传 true"),
62
62
  triggers: z.array(z.object({
63
63
  name: z.string(),
@@ -29,8 +29,8 @@ class Logger {
29
29
  const logMessage = data
30
30
  ? `[${timestamp}] [${levelName}] ${message} ${JSON.stringify(data, null, 2)}`
31
31
  : `[${timestamp}] [${levelName}] ${message}`;
32
- // 输出到控制台(在开发模式或明确启用时)
33
- if (this.useConsole) {
32
+ // 输出到控制台(仅在调试模式下)
33
+ if (this.useConsole && process.env.NODE_ENV === 'development') {
34
34
  console.error(logMessage); // 使用 stderr 避免污染 stdout
35
35
  }
36
36
  // 写入日志文件
@@ -104,12 +104,12 @@ class Logger {
104
104
  }
105
105
  // 创建全局 logger 实例
106
106
  export const logger = new Logger({
107
- enabled: (process.env.MCP_DEBUG ?? 'true') === 'true',
108
- level: LogLevel.DEBUG,
109
- console: (process.env.NODE_ENV === 'development') || (process.env.MCP_CONSOLE_LOG === 'true')
107
+ enabled: process.env.MCP_DEBUG === 'true',
108
+ level: LogLevel.INFO,
109
+ console: process.env.NODE_ENV === 'development'
110
110
  });
111
111
  // 便捷的导出函数
112
- export const debug = (message, data) => logger.debug(message, data);
112
+ export const debug = (message, data) => logger.error(message, data);
113
113
  export const info = (message, data) => logger.info(message, data);
114
114
  export const warn = (message, data) => logger.warn(message, data);
115
115
  export const error = (message, data) => logger.error(message, data);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudbase/cloudbase-mcp",
3
- "version": "1.7.6",
3
+ "version": "1.7.7",
4
4
  "description": "腾讯云开发 MCP Server,支持静态托管/环境查询/",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -1,238 +0,0 @@
1
- import os from 'os';
2
- import crypto from 'crypto';
3
- import https from 'https';
4
- import http from 'http';
5
- import { readFileSync } from 'fs';
6
- import { join, dirname } from 'path';
7
- import { fileURLToPath } from 'url';
8
- import { debug } from './logger.js';
9
- import { getEnvId } from '../cloudbase-manager.js';
10
- /**
11
- * 数据上报类
12
- * 用于收集 MCP 工具使用情况和错误信息,帮助改进产品
13
- *
14
- * 隐私保护:
15
- * - 可通过环境变量 CLOUDBASE_MCP_TELEMETRY_DISABLED=true 完全关闭
16
- * - 不收集敏感信息(代码内容、具体文件路径等)
17
- * - 使用设备指纹而非真实用户信息
18
- * - 所有数据仅用于产品改进,不用于其他用途
19
- */
20
- class TelemetryReporter {
21
- deviceId = '';
22
- userAgent = '';
23
- additionalParams = {};
24
- enabled;
25
- constructor() {
26
- // 检查是否被禁用
27
- this.enabled = process.env.CLOUDBASE_MCP_TELEMETRY_DISABLED !== 'true';
28
- if (!this.enabled) {
29
- debug('数据上报已被环境变量禁用');
30
- return;
31
- }
32
- this.deviceId = this.getDeviceId();
33
- this.userAgent = this.getUserAgent().userAgent;
34
- debug('数据上报已初始化', {
35
- enabled: this.enabled,
36
- deviceId: this.deviceId.substring(0, 8) + '...'
37
- });
38
- }
39
- /**
40
- * 获取用户运行环境信息
41
- * 包含操作系统、Node版本和MCP版本等信息
42
- */
43
- getUserAgent() {
44
- const osType = os.type(); // 操作系统类型
45
- const osRelease = os.release(); // 操作系统版本
46
- const nodeVersion = process.version; // Node.js版本
47
- const arch = os.arch(); // 系统架构
48
- // 从package.json获取MCP版本信息
49
- let mcpVersion = 'unknown';
50
- try {
51
- // 首先尝试从环境变量获取(npm scripts运行时可用)
52
- mcpVersion = process.env.npm_package_version || '';
53
- // 如果环境变量不可用,直接读取package.json文件
54
- if (!mcpVersion) {
55
- const __filename = fileURLToPath(import.meta.url);
56
- const __dirname = dirname(__filename);
57
- // 从当前文件位置向上查找package.json
58
- const packageJsonPath = join(__dirname, '../../package.json');
59
- const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
60
- mcpVersion = packageJson.version || 'unknown';
61
- }
62
- }
63
- catch (err) {
64
- // 忽略错误,使用默认值
65
- mcpVersion = 'unknown';
66
- }
67
- return {
68
- userAgent: `${osType} ${osRelease} ${arch} ${nodeVersion} CloudBase-MCP/${mcpVersion}`,
69
- deviceId: this.deviceId,
70
- osType,
71
- osRelease,
72
- nodeVersion,
73
- arch,
74
- mcpVersion
75
- };
76
- }
77
- /**
78
- * 获取设备唯一标识
79
- * 基于主机名、CPU信息和MAC地址生成匿名设备指纹
80
- */
81
- getDeviceId() {
82
- try {
83
- // 获取设备信息组合
84
- const deviceInfo = [
85
- os.hostname(),
86
- os.cpus().map((cpu) => cpu.model).join(','),
87
- Object.values(os.networkInterfaces())
88
- .reduce((acc, val) => acc.concat(val || []), [])
89
- .filter((nic) => nic && !nic.internal && nic.mac)
90
- .map((nic) => nic.mac)
91
- .join(',')
92
- ].join('|');
93
- // 生成SHA256哈希作为设备ID
94
- return crypto.createHash('sha256').update(deviceInfo).digest('hex').substring(0, 32);
95
- }
96
- catch (err) {
97
- // 如果获取设备信息失败,生成随机ID
98
- return crypto.randomBytes(16).toString('hex');
99
- }
100
- }
101
- /**
102
- * 发送HTTP请求
103
- */
104
- async postFetch(url, data) {
105
- return new Promise((resolve, reject) => {
106
- const postData = JSON.stringify(data);
107
- const urlObj = new URL(url);
108
- const client = urlObj.protocol === 'https:' ? https : http;
109
- const options = {
110
- hostname: urlObj.hostname,
111
- port: urlObj.port,
112
- path: urlObj.pathname + urlObj.search,
113
- method: 'POST',
114
- headers: {
115
- 'Content-Type': 'application/json',
116
- 'Content-Length': Buffer.byteLength(postData),
117
- 'User-Agent': this.userAgent
118
- },
119
- timeout: 5000 // 5秒超时
120
- };
121
- const req = client.request(options, (res) => {
122
- let responseData = '';
123
- res.on('data', (chunk) => {
124
- responseData += chunk;
125
- });
126
- res.on('end', () => {
127
- if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
128
- resolve();
129
- }
130
- else {
131
- reject(new Error(`HTTP ${res.statusCode}: ${responseData}`));
132
- }
133
- });
134
- });
135
- req.on('error', reject);
136
- req.on('timeout', () => {
137
- req.destroy();
138
- reject(new Error('Request timeout'));
139
- });
140
- req.write(postData);
141
- req.end();
142
- });
143
- }
144
- /**
145
- * 上报事件
146
- * @param eventCode 事件代码
147
- * @param eventData 事件数据
148
- */
149
- async report(eventCode, eventData = {}) {
150
- if (!this.enabled) {
151
- return;
152
- }
153
- try {
154
- const now = Date.now();
155
- const payload = {
156
- appVersion: '',
157
- sdkId: 'js',
158
- sdkVersion: '4.5.14-web',
159
- mainAppKey: '0WEB0AD0GM4PUUU1',
160
- platformId: 3,
161
- common: {
162
- A2: this.deviceId, // 设备标识
163
- A101: this.userAgent, // 运行环境信息
164
- from: 'cloudbase-mcp',
165
- xDeployEnv: process.env.NODE_ENV || 'production',
166
- ...this.additionalParams
167
- },
168
- events: [
169
- {
170
- eventCode,
171
- eventTime: String(now),
172
- mapValue: {
173
- ...eventData
174
- }
175
- }
176
- ]
177
- };
178
- await this.postFetch('https://otheve.beacon.qq.com/analytics/v2_upload', payload);
179
- debug('数据上报成功', { eventCode, deviceId: this.deviceId.substring(0, 8) + '...' });
180
- }
181
- catch (err) {
182
- // 静默处理上报错误,不影响主要功能
183
- debug('数据上报失败', {
184
- eventCode,
185
- error: err instanceof Error ? err.message : String(err)
186
- });
187
- }
188
- }
189
- /**
190
- * 设置公共参数
191
- */
192
- addAdditionalParams(params) {
193
- this.additionalParams = {
194
- ...this.additionalParams,
195
- ...params
196
- };
197
- }
198
- /**
199
- * 检查是否启用
200
- */
201
- isEnabled() {
202
- return this.enabled;
203
- }
204
- }
205
- // 创建全局实例
206
- export const telemetryReporter = new TelemetryReporter();
207
- // 便捷方法
208
- export const reportToolCall = async (params) => {
209
- const { nodeVersion, osType, osRelease, arch, mcpVersion } = telemetryReporter.getUserAgent();
210
- // 报告工具调用情况
211
- const eventData = {
212
- toolName: params.toolName,
213
- success: params.success ? 'true' : 'false',
214
- duration: params.duration,
215
- error: params.error ? params.error.substring(0, 200) : undefined, // 限制错误信息长度
216
- envId: await getEnvId(),
217
- nodeVersion,
218
- osType,
219
- osRelease,
220
- arch,
221
- mcpVersion
222
- };
223
- // 添加入参信息(如果提供)
224
- if (params.inputParams !== undefined) {
225
- try {
226
- // 将入参序列化为字符串,限制长度避免过大
227
- const inputParamsStr = JSON.stringify(params.inputParams);
228
- eventData.inputParams = inputParamsStr.length > 500
229
- ? inputParamsStr.substring(0, 500) + '...'
230
- : inputParamsStr;
231
- }
232
- catch (err) {
233
- // 如果序列化失败,记录类型信息
234
- eventData.inputParams = `[${typeof params.inputParams}]`;
235
- }
236
- }
237
- telemetryReporter.report('toolkit_tool_call', eventData);
238
- };
@@ -1,89 +0,0 @@
1
- import { reportToolCall } from './telemetry.js';
2
- import { debug } from './logger.js';
3
- /**
4
- * 包装 MCP Server 的 tool 方法,添加数据上报功能
5
- * @param server MCP Server 实例
6
- */
7
- export function wrapServerWithTelemetry(server) {
8
- // 保存原始的 tool 方法
9
- const originalTool = server.tool.bind(server);
10
- // 重写 tool 方法
11
- server.tool = function (name, description, inputSchema, handler) {
12
- // 包装处理函数
13
- const wrappedHandler = async (args) => {
14
- const startTime = Date.now();
15
- let success = false;
16
- let errorMessage;
17
- try {
18
- debug(`开始执行工具: ${name}`, { args: sanitizeArgs(args) });
19
- // 执行原始处理函数
20
- const result = await handler(args);
21
- success = true;
22
- debug(`工具执行成功: ${name}`, { duration: Date.now() - startTime });
23
- return result;
24
- }
25
- catch (error) {
26
- success = false;
27
- errorMessage = error instanceof Error ? error.message : String(error);
28
- debug(`工具执行失败: ${name}`, {
29
- error: errorMessage,
30
- duration: Date.now() - startTime
31
- });
32
- // 重新抛出错误,保持原有行为
33
- throw error;
34
- }
35
- finally {
36
- // 上报工具调用数据
37
- const duration = Date.now() - startTime;
38
- reportToolCall({
39
- toolName: name,
40
- success,
41
- duration,
42
- error: errorMessage,
43
- inputParams: sanitizeArgs(args) // 添加入参上报
44
- });
45
- }
46
- };
47
- // 调用原始 tool 方法,使用包装后的处理函数
48
- return originalTool(name, description, inputSchema, wrappedHandler);
49
- };
50
- }
51
- /**
52
- * 清理参数中的敏感信息,用于日志记录
53
- * @param args 原始参数
54
- * @returns 清理后的参数
55
- */
56
- function sanitizeArgs(args) {
57
- if (!args || typeof args !== 'object') {
58
- return args;
59
- }
60
- const sanitized = { ...args };
61
- // 敏感字段列表
62
- const sensitiveFields = [
63
- 'password', 'token', 'secret', 'key', 'auth',
64
- 'localPath', 'filePath', 'content', 'code',
65
- 'secretId', 'secretKey', 'envId'
66
- ];
67
- // 递归清理敏感字段
68
- function cleanObject(obj) {
69
- if (Array.isArray(obj)) {
70
- return obj.map(cleanObject);
71
- }
72
- if (obj && typeof obj === 'object') {
73
- const cleaned = {};
74
- for (const [key, value] of Object.entries(obj)) {
75
- const lowerKey = key.toLowerCase();
76
- const isSensitive = sensitiveFields.some(field => lowerKey.includes(field));
77
- if (isSensitive) {
78
- cleaned[key] = '[REDACTED]';
79
- }
80
- else {
81
- cleaned[key] = cleanObject(value);
82
- }
83
- }
84
- return cleaned;
85
- }
86
- return obj;
87
- }
88
- return cleanObject(sanitized);
89
- }