exploria-ui-mcp-server 2.1.1 → 2.1.3

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.
Files changed (3) hide show
  1. package/README.md +89 -118
  2. package/dist/index.js +226 -90
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,37 +1,28 @@
1
1
  # Exploria UI MCP Server
2
2
 
3
- Exploria UI MCP Server 是一个基于 MCP(Model Context Protocol)协议的服务,允许 AI 客户端(如 Cursor、Trae IDE)访问和查询 Exploria UI 组件库的文档和信息。
3
+ 基于 MCP(Model Context Protocol)协议的服务,允许 AI 客户端(如 Cursor、Trae IDE)访问和查询 Exploria UI 组件库的文档和信息。
4
4
 
5
5
  ## 1. MCP 协议简介
6
6
 
7
7
  ### 1.1 什么是 MCP?
8
8
 
9
- MCP(Model Context Protocol)是 AI 工具世界的「USB 标准」,它允许 AI 应用(如 Cursor、Trae IDE)通过统一的接口访问自定义数据和功能。
9
+ MCP AI 工具世界的「USB 标准」,允许 AI 应用通过统一接口访问自定义数据和功能。
10
10
 
11
- ### 1.2 核心设计理念
11
+ ### 1.2 核心特性
12
12
 
13
- - **统一接口**:为所有 AI 工具提供统一的访问方式,避免为每个 AI 工具单独开发适配层
14
- - **轻量通信**:默认使用标准输入输出(stdio)进行通信,无需网络端口
15
- - **自动管理**:由 AI 客户端自动启动、管理和停止,无需手动干预
13
+ - **统一接口**:为所有 AI 工具提供统一访问方式
14
+ - **轻量通信**:使用标准输入输出(stdio)通信,无需网络端口
15
+ - **自动管理**:由 AI 客户端自动启动、管理和停止
16
16
  - **安全可靠**:通过管道通信,避免网络安全风险
17
17
 
18
- ### 1.3 通信原理
18
+ ### 1.3 通信流程
19
19
 
20
- MCP Server 与 AI IDE 的通信流程:
21
-
22
- 1. AI IDE(如 Cursor/Trae)启动时读取配置文件
23
- 2. 根据配置中的 `mcpServers` 自动启动 MCP Server 作为子进程
24
- 3. 通过标准输入输出(stdio)与 MCP Server 通信
20
+ 1. AI IDE 启动时读取配置文件
21
+ 2. 根据 `mcpServers` 配置自动启动 MCP Server 子进程
22
+ 3. 通过 stdio 与 MCP Server 通信
25
23
  4. 发送初始化指令,获取可用工具列表
26
- 5. 在需要时调用相应工具,获取结果
27
- 6. IDE 关闭时,自动终止 MCP Server 进程
28
-
29
- **关键特点**:
30
-
31
- - Cursor/Trae 是 MCP Server 的父进程
32
- - 通信方式:标准输入输出(stdio),不是网络通信
33
- - 无端口、无 TCP、无 HTTP
34
- - 所有消息通过 JSON 格式管道传输
24
+ 5. 按需调用工具,获取结果
25
+ 6. IDE 关闭时自动终止 MCP Server 进程
35
26
 
36
27
  ## 2. 快速开始
37
28
 
@@ -41,59 +32,32 @@ MCP Server 与 AI IDE 的通信流程:
41
32
  pnpm install
42
33
  ```
43
34
 
44
- ### 2.2 Cursor 配置
35
+ ### 2.2 AI IDE 配置
45
36
 
46
- 1. 打开 Cursor 配置文件:`%APPDATA%\Cursor\cursor_config.json`
47
- 2. 添加以下配置:
37
+ 所有 AI IDE 使用统一配置格式:
48
38
 
49
39
  ```json
50
40
  {
51
41
  "mcpServers": {
52
- "exploria-ui-mcp": {
53
- "command": "pnpm",
54
- "args": ["serve"],
55
- "cwd": "C:\\Users\\YYWD4\\Desktop\\exploria-ui-document\\mcp-server"
42
+ "exploria-ui-mcp-server": {
43
+ "command": "npx",
44
+ "args": ["exploria-ui-mcp-server"]
56
45
  }
57
46
  }
58
47
  }
59
48
  ```
60
49
 
61
- **注意**:请将 `cwd` 路径替换为您实际的项目路径。
62
-
63
- 3. 重启 Cursor,它会自动启动并连接到 MCP Server
64
-
65
- ### 2.3 Trae IDE 配置
66
-
67
- 1. 打开 Trae IDE MCP 配置文件:`.trae/mcp.json`(位于项目根目录)
68
- 2. 添加以下配置:
69
-
70
- ```json
71
- {
72
- "servers": [
73
- {
74
- "id": "exploria-ui-mcp",
75
- "name": "Exploria UI MCP Server",
76
- "command": "pnpm",
77
- "args": ["mcp:dev"],
78
- "cwd": ".",
79
- "env": {},
80
- "enabled": true
81
- }
82
- ]
83
- }
84
- ```
85
-
86
- **注意**:
87
-
88
- - `cwd` 路径为项目根目录
89
- - 使用根项目的 `mcp:dev` 脚本启动服务
90
- - 确保 `enabled` 字段设置为 `true` 以启用该服务器
50
+ #### 具体 IDE 配置
91
51
 
92
- 3. 重启 Trae IDE 或重新加载配置,它会自动启动并连接到 MCP Server
52
+ | IDE | 配置文件位置 | 操作步骤 |
53
+ |-----|-------------|----------|
54
+ | Cursor | `%APPDATA%\Cursor\cursor_config.json` | 1. 打开配置文件<br>2. 添加上述配置<br>3. 重启 Cursor |
55
+ | Trae IDE | `.trae/mcp.json`(项目根目录) | 1. 打开配置文件<br>2. 添加上述配置<br>3. 重启 Trae IDE |
56
+ | 其他支持 MCP 的 IDE | 参考官方文档 | 1. 找到 MCP 配置文件<br>2. 添加上述配置<br>3. 重启 IDE |
93
57
 
94
- ### 2.4 验证配置
58
+ ### 2.3 验证配置
95
59
 
96
- 配置完成后,在 AI IDE 中输入类似以下的查询,验证 MCP Server 是否正常工作:
60
+ AI IDE 中输入查询验证服务是否正常:
97
61
 
98
62
  ```
99
63
  帮我查一下 button 组件的文档
@@ -103,38 +67,38 @@ pnpm install
103
67
 
104
68
  ### 3.1 工具(Tools)
105
69
 
106
- | 工具名称 | 描述 | 参数 | 返回值 |
107
- | ------------------------ | ------------------------- | --------------------------------- | -------------------------------------- |
108
- | `search_documents` | 搜索 Exploria UI 组件文档 | `query: string` | 匹配的组件列表 |
109
- | `get_component_list` | 获取所有组件列表 | 无 | 所有组件的基本信息 |
110
- | `get_component_details` | 获取指定组件的详细信息 | `componentName: string` | 组件的详细信息,包括属性、事件、插槽等 |
111
- | `search_and_get_details` | 搜索并获取组件详情 | `query: string`, `limit?: number` | 匹配的组件列表,包含详细信息 |
70
+ | 工具名称 | 描述 | 参数 | 返回值 |
71
+ |---------|------|------|--------|
72
+ | `search_documents` | 搜索组件文档 | `query: string` | 匹配的组件列表 |
73
+ | `get_component_list` | 获取所有组件列表 | 无 | 所有组件基本信息 |
74
+ | `get_component_details` | 获取组件详情 | `componentName: string` | 组件详细信息(属性、事件、插槽等) |
75
+ | `search_and_get_details` | 搜索并获取组件详情 | `query: string`, `limit?: number` | 匹配的组件列表(含详情) |
112
76
 
113
77
  ### 3.2 资源(Resources)
114
78
 
115
- | 资源 URI | 描述 | 返回值 |
116
- | ------------------------------- | -------------- | -------------------------------- |
117
- | `status://exploria-ui-server` | 服务器状态信息 | 服务器运行状态、版本、运行时间等 |
118
- | `docs://exploria-ui-api` | API 文档 | 完整的 API 文档 |
119
- | `components://exploria-ui-list` | 组件列表资源 | 所有组件的基本信息 |
79
+ | 资源 URI | 描述 | 返回值 |
80
+ |---------|------|--------|
81
+ | `status://exploria-ui-server` | 服务器状态 | 运行状态、版本、运行时间等 |
82
+ | `docs://exploria-ui-api` | API 文档 | 完整 API 文档 |
83
+ | `components://exploria-ui-list` | 组件列表 | 所有组件基本信息 |
120
84
 
121
85
  ### 3.3 提示(Prompts)
122
86
 
123
- | 提示名称 | 描述 | 参数 | 返回值 |
124
- | ------------------------- | ---------------- | -------------------------------------------- | ---------------- |
125
- | `component_documentation` | 生成组件文档模板 | `componentName: string` | 组件文档模板 |
126
- | `usage_example` | 生成组件使用示例 | `componentName: string`, `scenario?: string` | 组件使用示例代码 |
87
+ | 提示名称 | 描述 | 参数 | 返回值 |
88
+ |---------|------|------|--------|
89
+ | `component_documentation` | 生成组件文档模板 | `componentName: string` | 组件文档模板 |
90
+ | `usage_example` | 生成组件使用示例 | `componentName: string`, `scenario?: string` | 组件使用示例代码 |
127
91
 
128
92
  ## 4. 项目架构
129
93
 
130
94
  ### 4.1 核心模块
131
95
 
132
- | 模块 | 功能 |
133
- | ------------- | -------------------------------------- |
134
- | **Tools** | 可执行功能,如搜索文档、获取组件详情 |
135
- | **Resources** | 提供只读数据,如服务器状态、API 文档 |
136
- | **Prompts** | 预定义模板,用于生成组件文档和使用示例 |
137
- | **Utils** | 工具类,如文档解析器 |
96
+ | 模块 | 功能 |
97
+ |------|------|
98
+ | **Tools** | 可执行功能(搜索文档、获取组件详情等) |
99
+ | **Resources** | 提供只读数据(服务器状态、API 文档等) |
100
+ | **Prompts** | 预定义模板(生成文档、使用示例等) |
101
+ | **Utils** | 工具类(文档解析器等) |
138
102
 
139
103
  ### 4.2 项目结构
140
104
 
@@ -157,7 +121,7 @@ src/
157
121
  │ ├── componentDocumentation.ts # 生成组件文档模板
158
122
  │ └── usageExample.ts # 生成组件使用示例
159
123
  └── utils/ # 工具类
160
- └── documentParser.ts # 文档解析器,处理组件文档
124
+ └── documentParser.ts # 文档解析器
161
125
  ```
162
126
 
163
127
  ## 5. 开发与调试
@@ -170,79 +134,86 @@ pnpm build
170
134
 
171
135
  ### 5.2 本地运行(仅开发阶段)
172
136
 
173
- **注意**:在生产环境中,MCP Server 由 AI IDE 自动启动和管理,无需手动运行。以下命令仅用于开发和调试阶段。
137
+ 在项目根目录执行:
174
138
 
175
139
  ```bash
176
- # 从根项目启动 MCP Server 开发模式
140
+ # 开发模式
177
141
  pnpm mcp:dev
178
142
 
179
143
  # 构建 MCP Server
180
144
  pnpm mcp:build
181
145
 
182
- # 运行构建后的 MCP Server
146
+ # 运行构建后的服务
183
147
  pnpm mcp:start
184
148
  ```
185
149
 
186
- **注意**:这些命令需要在项目根目录下执行,而不是 mcp-server 子目录。
187
-
188
- ### 5.3 使用 MCP Dev 工具
189
-
190
- 安装 MCP Dev 工具进行调试:
191
-
192
- ```bash
193
- npm install -g @modelcontextprotocol/dev
194
- ```
195
-
196
- 然后在项目目录中运行:
197
-
198
- ```bash
199
- mcp dev src/index.ts
200
- ```
201
-
202
- 这会模拟 AI IDE 启动和调用流程,便于调试。
203
-
204
150
  ## 6. 扩展指南
205
151
 
206
152
  ### 6.1 添加新工具
207
153
 
208
- 1. 在 `src/tools/` 目录下创建新的工具文件,如 `newTool.ts`
154
+ 1. 在 `src/tools/` 目录下创建新工具文件(如 `newTool.ts`)
209
155
  2. 实现工具函数并注册到 MCP Server
210
156
  3. 在 `src/tools/index.ts` 中导入并注册新工具
211
157
 
212
158
  ### 6.2 添加新资源
213
159
 
214
- 1. 在 `src/resources/` 目录下创建新的资源文件,如 `newResource.ts`
160
+ 1. 在 `src/resources/` 目录下创建新资源文件
215
161
  2. 实现资源函数并注册到 MCP Server
216
162
  3. 在 `src/resources/index.ts` 中导入并注册新资源
217
163
 
218
164
  ### 6.3 添加新提示
219
165
 
220
- 1. 在 `src/prompts/` 目录下创建新的提示文件,如 `newPrompt.ts`
166
+ 1. 在 `src/prompts/` 目录下创建新提示文件
221
167
  2. 实现提示函数并注册到 MCP Server
222
168
  3. 在 `src/prompts/index.ts` 中导入并注册新提示
223
169
 
224
170
  ## 7. 技术栈
225
171
 
226
- | 技术 | 用途 |
227
- | --------------------------- | ---------------------------- |
228
- | `@modelcontextprotocol/sdk` | 官方 MCP TypeScript SDK |
229
- | `zod` | 用于工具参数的运行时类型校验 |
230
- | `tsx` | 直接运行 TypeScript 代码 |
231
- | `typescript` | 类型安全 |
232
- | `pnpm` | 包管理 |
172
+ | 技术 | 用途 |
173
+ |-----|------|
174
+ | `@modelcontextprotocol/sdk` | 官方 MCP TypeScript SDK |
175
+ | `zod` | 工具参数运行时类型校验 |
176
+ | `tsx` | 直接运行 TypeScript 代码 |
177
+ | `typescript` | 类型安全 |
178
+ | `pnpm` | 包管理 |
233
179
 
234
180
  ## 8. 协议兼容性
235
181
 
236
182
  - 支持 MCP 协议 v1.0+
237
- - 兼容 Cursor、Trae IDE、Claude Desktop 等支持 MCP 的 AI 客户端
238
- - 使用标准输入输出(stdio)通信,无需网络端口
183
+ - 兼容 Cursor、Trae IDE、Claude Desktop
184
+ - 使用 stdio 通信,无需网络端口
239
185
 
240
186
  ## 9. 安全特性
241
187
 
242
188
  - 无网络通信,所有数据通过管道传输
243
189
  - 由 AI 客户端自动管理,无需手动暴露服务
244
- - 支持工具级别的权限控制(通过 MCP SDK 实现)
190
+ - 支持工具级别的权限控制
191
+
192
+ ## 10. 知识库
193
+
194
+ ### 10.1 知识库位置
195
+
196
+ 位于 `mcp-server/public` 文件夹下,包含所有组件、指令、工具函数的详细文档和使用示例。
197
+
198
+ ### 10.2 知识库结构
199
+
200
+ ```
201
+ public/
202
+ ├── components/ # 组件文档(按类别分类)
203
+ │ ├── advanced/ # 高级组件
204
+ │ ├── ai/ # AI 相关组件
205
+ │ ├── basic/ # 基础组件
206
+ │ ├── data/ # 数据展示组件
207
+ │ ├── feedback/ # 反馈组件
208
+ │ ├── form/ # 表单组件
209
+ │ ├── geometry/ # 几何相关组件
210
+ │ ├── layout/ # 布局组件
211
+ │ └── navigation/ # 导航组件
212
+ ├── directives/ # 指令文档
213
+ ├── other/ # 其他功能文档
214
+ └── utils/ # 工具函数文档
215
+ ```
245
216
 
246
- ## 10. 许可证
217
+ ## 11. 许可证
247
218
 
248
219
  MIT
package/dist/index.js CHANGED
@@ -13375,13 +13375,12 @@ function Nm(e) {
13375
13375
  //#endregion
13376
13376
  //#region src/prompts/index.ts
13377
13377
  function Pm(e) {
13378
- Mm(e), Nm(e);
13378
+ console.log("💡 正在注册 MCP 提示..."), Mm(e), Nm(e), console.log("✅ 所有 MCP 提示注册完成");
13379
13379
  }
13380
13380
  //#endregion
13381
13381
  //#region src/resources/apiDocs.ts
13382
- var Fm = import.meta.url.slice(7), Im = t.dirname(Fm);
13383
- function Lm(n) {
13384
- let r = t.join(Im, "../../package.json"), i = JSON.parse(e.readFileSync(r, "utf-8"));
13382
+ function Fm(n) {
13383
+ let r = t.join(process.cwd(), "package.json"), i = JSON.parse(e.readFileSync(r, "utf-8"));
13385
13384
  n.resource("api_docs", "docs://exploria-ui-api", async (e) => ({ contents: [{
13386
13385
  uri: e.href,
13387
13386
  text: `# Exploria UI MCP Server API Documentation
@@ -13483,12 +13482,16 @@ function Lm(n) {
13483
13482
  }
13484
13483
  //#endregion
13485
13484
  //#region src/utils/documentParser.ts
13486
- var Rm = import.meta.url.slice(7), zm = t.dirname(Rm), Bm = t.join(zm, "../../public"), Vm = new class {
13485
+ var Im = t.join(process.cwd(), "public"), Lm = new class {
13487
13486
  docsRoot;
13488
- constructor(t = Bm) {
13489
- this.docsRoot = t, e.existsSync(this.docsRoot) || console.warn(`文档根目录不存在: ${this.docsRoot}`);
13487
+ componentListCache = null;
13488
+ componentDetailsCache = /* @__PURE__ */ new Map();
13489
+ constructor(t = Im) {
13490
+ this.docsRoot = t, e.existsSync(this.docsRoot) ? console.log(`📁 文档根目录已设置: ${this.docsRoot}`) : console.warn(`⚠️ 文档根目录不存在: ${this.docsRoot}`);
13490
13491
  }
13491
13492
  getComponentList() {
13493
+ if (this.componentListCache) return console.log(`✅ 从缓存中获取组件列表,共 ${this.componentListCache.length} 个组件`), this.componentListCache;
13494
+ console.log("🔍 正在扫描文档目录...");
13492
13495
  let e = [];
13493
13496
  return this.traverseDocs((t, n, r) => {
13494
13497
  e.push({
@@ -13497,37 +13500,74 @@ var Rm = import.meta.url.slice(7), zm = t.dirname(Rm), Bm = t.join(zm, "../../pu
13497
13500
  description: `${n} component for Exploria UI`,
13498
13501
  path: r
13499
13502
  });
13500
- }), e;
13503
+ }), this.componentListCache = e, console.log(`✅ 扫描完成,共找到 ${e.length} 个组件`), e;
13501
13504
  }
13502
13505
  traverseDocs(n) {
13503
13506
  try {
13504
13507
  if (!e.existsSync(this.docsRoot)) return;
13505
13508
  e.readdirSync(this.docsRoot).forEach((r) => {
13506
13509
  let i = t.join(this.docsRoot, r);
13507
- e.statSync(i).isDirectory() && (r === "components" ? e.readdirSync(i).forEach((r) => {
13508
- let a = t.join(i, r);
13509
- e.statSync(a).isDirectory() && e.readdirSync(a).forEach((i) => {
13510
- let o = t.join(a, i);
13511
- e.statSync(o).isDirectory() && n(r, i, o);
13512
- });
13513
- }) : e.readdirSync(i).forEach((a) => {
13514
- let o = t.join(i, a);
13515
- e.statSync(o).isDirectory() && n(r, a, o);
13516
- }));
13510
+ e.statSync(i).isDirectory() && (r === "components" ? this.traverseComponentsDir(i, n) : this.traverseOtherDir(r, i, n));
13517
13511
  });
13518
13512
  } catch (e) {
13519
- console.error("遍历文档目录时出错:", e);
13513
+ console.error("🔴 遍历文档目录时出错:", e instanceof Error ? e.message : String(e));
13520
13514
  }
13521
13515
  }
13516
+ traverseComponentsDir(n, r) {
13517
+ e.readdirSync(n).forEach((i) => {
13518
+ let a = t.join(n, i);
13519
+ e.statSync(a).isDirectory() && e.readdirSync(a).forEach((n) => {
13520
+ let o = t.join(a, n);
13521
+ e.statSync(o).isDirectory() && r(i, n, o);
13522
+ });
13523
+ });
13524
+ }
13525
+ traverseOtherDir(n, r, i) {
13526
+ e.readdirSync(r).forEach((a) => {
13527
+ let o = t.join(r, a);
13528
+ e.statSync(o).isDirectory() && i(n, a, o);
13529
+ });
13530
+ }
13522
13531
  extractMarkdownFromVue(e) {
13523
13532
  let t = e.match(/<!--[\s\S]*?-->/);
13524
13533
  if (t) return t[0].replace(/<!--|-->/g, "").trim();
13525
13534
  let n = e.match(/<template>[\s\S]*?<\/template>/);
13526
- return n ? n[0].replace(/<template>|<\/template>/g, "").trim() : "";
13535
+ if (n) return n[0].replace(/<template>|<\/template>/g, "").trim();
13536
+ let r = e.match(/<script[\s\S]*?<\/script>/);
13537
+ if (r) {
13538
+ let e = r[0].match(/\/\*\*[\s\S]*?\*\//);
13539
+ if (e) return e[0].replace(/\/\*\*|\*\//g, "").replace(/^\s*\*\s?/gm, "").trim();
13540
+ }
13541
+ return "";
13527
13542
  }
13528
13543
  extractProps(e) {
13529
13544
  let t = [];
13530
- return e.toLowerCase().includes("props") && t.push({
13545
+ if (!e.toLowerCase().includes("props")) return t;
13546
+ try {
13547
+ let n = e.match(/(?:###|##)\s*Props[\s\S]*?(?=(?:###|##)\s|$)/i);
13548
+ if (n) {
13549
+ let e = n[0].match(/\|\s*Name\s*\|\s*Type\s*\|\s*Default\s*\|\s*Description\s*\|(?:\s*\|\s*Options\s*\|)?[\s\S]*?(?=\n\n|$)/);
13550
+ if (e) {
13551
+ let n = e[0].split("\n").filter((e) => e.trim().startsWith("|"));
13552
+ for (let e = 2; e < n.length; e++) {
13553
+ let r = n[e].split("|").map((e) => e.trim()).filter((e) => e !== "");
13554
+ r.length >= 4 && t.push({
13555
+ name: r[0],
13556
+ type: r[1],
13557
+ default: this.parseDefaultValue(r[2]),
13558
+ description: r[3],
13559
+ options: r[4] ? r[4].split(",").map((e) => e.trim()) : void 0
13560
+ });
13561
+ }
13562
+ } else this.addDefaultProps(t);
13563
+ } else this.addDefaultProps(t);
13564
+ } catch (e) {
13565
+ console.error("🔴 提取属性时出错:", e instanceof Error ? e.message : String(e)), this.addDefaultProps(t);
13566
+ }
13567
+ return t;
13568
+ }
13569
+ addDefaultProps(e) {
13570
+ e.push({
13531
13571
  name: "type",
13532
13572
  type: "string",
13533
13573
  default: "default",
@@ -13554,11 +13594,36 @@ var Rm = import.meta.url.slice(7), zm = t.dirname(Rm), Bm = t.join(zm, "../../pu
13554
13594
  type: "boolean",
13555
13595
  default: !1,
13556
13596
  description: "是否禁用"
13557
- }), t;
13597
+ });
13598
+ }
13599
+ parseDefaultValue(e) {
13600
+ let t = e.trim();
13601
+ if (t === "true") return !0;
13602
+ if (t === "false") return !1;
13603
+ if (t === "null") return null;
13604
+ if (t === "undefined") return;
13605
+ if (t === "[]") return [];
13606
+ if (t === "{}") return {};
13607
+ let n = Number(t);
13608
+ return !isNaN(n) && t !== "" ? n : t.startsWith("\"") && t.endsWith("\"") || t.startsWith("'") && t.endsWith("'") ? t.slice(1, -1) : t;
13558
13609
  }
13559
13610
  extractEvents(e) {
13560
13611
  let t = [];
13561
- return e.toLowerCase().includes("events") && t.push({
13612
+ if (!e.toLowerCase().includes("events")) return t;
13613
+ try {
13614
+ let n = e.match(/(?:###|##)\s*Events[\s\S]*?(?=(?:###|##)\s|$)/i);
13615
+ if (n) {
13616
+ let e = n[0], r = /-\s*`(\w+)`\s*:\s*(.*?)(?=\n-|$)/g, i;
13617
+ for (; (i = r.exec(e)) !== null;) t.push({
13618
+ name: i[1],
13619
+ description: i[2].trim(),
13620
+ parameters: []
13621
+ });
13622
+ }
13623
+ } catch (e) {
13624
+ console.error("🔴 提取事件时出错:", e instanceof Error ? e.message : String(e));
13625
+ }
13626
+ return t.length === 0 && t.push({
13562
13627
  name: "click",
13563
13628
  description: "点击事件",
13564
13629
  parameters: []
@@ -13566,55 +13631,85 @@ var Rm = import.meta.url.slice(7), zm = t.dirname(Rm), Bm = t.join(zm, "../../pu
13566
13631
  }
13567
13632
  extractSlots(e) {
13568
13633
  let t = [];
13569
- return e.toLowerCase().includes("slots") && t.push({
13634
+ if (!e.toLowerCase().includes("slots")) return t;
13635
+ try {
13636
+ let n = e.match(/(?:###|##)\s*Slots[\s\S]*?(?=(?:###|##)\s|$)/i);
13637
+ if (n) {
13638
+ let e = n[0], r = /-\s*`(\w+)`\s*:\s*(.*?)(?=\n-|$)/g, i;
13639
+ for (; (i = r.exec(e)) !== null;) t.push({
13640
+ name: i[1],
13641
+ description: i[2].trim(),
13642
+ default: i[1] === "default"
13643
+ });
13644
+ }
13645
+ } catch (e) {
13646
+ console.error("🔴 提取插槽时出错:", e instanceof Error ? e.message : String(e));
13647
+ }
13648
+ return t.length === 0 && t.push({
13570
13649
  name: "default",
13571
13650
  description: "默认插槽",
13572
13651
  default: !0
13573
13652
  }), t;
13574
13653
  }
13575
13654
  extractUsage(e) {
13576
- let t = e.match(/```[\s\S]*?```/);
13577
- return t ? t[0].replace(/```/g, "").trim() : `<${this.capitalizeFirstLetter(e.split(" ")[0] || "Component")} />`;
13655
+ try {
13656
+ let t = e.match(/```(vue|html|jsx)?[\s\S]*?```/);
13657
+ if (t) return t[0].replace(/```(vue|html|jsx)?|```/g, "").trim();
13658
+ } catch (e) {
13659
+ console.error("🔴 提取使用示例时出错:", e instanceof Error ? e.message : String(e));
13660
+ }
13661
+ return `<${this.capitalizeFirstLetter(e.split(" ")[0] || "Component")} />`;
13578
13662
  }
13579
13663
  extractExamples(e) {
13580
- let t = [], n = e.match(/```[\s\S]*?```/g) || [];
13581
- return n.length > 0 && t.push({
13582
- title: "Basic Usage",
13583
- code: n[0].replace(/```/g, "").trim()
13584
- }), n.length > 1 && t.push({
13585
- title: "Advanced Usage",
13586
- code: n[1].replace(/```/g, "").trim()
13587
- }), t;
13664
+ let t = [];
13665
+ try {
13666
+ let n = e.match(/```(vue|html|jsx)?[\s\S]*?```/g) || [];
13667
+ n.length > 0 && t.push({
13668
+ title: "Basic Usage",
13669
+ code: n[0].replace(/```(vue|html|jsx)?|```/g, "").trim()
13670
+ }), n.length > 1 && t.push({
13671
+ title: "Advanced Usage",
13672
+ code: n[1].replace(/```(vue|html|jsx)?|```/g, "").trim()
13673
+ });
13674
+ } catch (e) {
13675
+ console.error("🔴 提取示例代码时出错:", e instanceof Error ? e.message : String(e));
13676
+ }
13677
+ return t;
13588
13678
  }
13589
13679
  capitalizeFirstLetter(e) {
13590
13680
  return e.charAt(0).toUpperCase() + e.slice(1);
13591
13681
  }
13592
13682
  getComponentDetails(n) {
13593
- let r = "", i = "";
13594
- if (this.traverseDocs((e, t, a) => {
13595
- t.toLowerCase() === n.toLowerCase() && (r = a, i = e);
13596
- }), !r) return null;
13597
- let a = "", o = "";
13683
+ let r = n.toLowerCase();
13684
+ if (this.componentDetailsCache.has(r)) return console.log(`✅ 从缓存中获取组件 ${n} 的详情`), this.componentDetailsCache.get(r);
13685
+ console.log(`🔍 正在查找组件 ${n}...`);
13686
+ let i = "", a = "";
13687
+ if (this.traverseDocs((e, t, r) => {
13688
+ t.toLowerCase() === n.toLowerCase() && (i = r, a = e);
13689
+ }), !i) return console.warn(`❌ 未找到组件 ${n}`), null;
13690
+ let o = "", s = "";
13598
13691
  try {
13599
- let n = t.join(r, "Document.vue");
13600
- e.existsSync(n) && (o = e.readFileSync(n, "utf-8"), a = this.extractMarkdownFromVue(o));
13692
+ let n = t.join(i, "Document.vue");
13693
+ e.existsSync(n) && (console.log(`📄 正在读取组件文档: ${n}`), s = e.readFileSync(n, "utf-8"), o = this.extractMarkdownFromVue(s));
13601
13694
  } catch (e) {
13602
- console.error("读取组件文档时出错:", e);
13695
+ console.error("🔴 读取组件文档时出错:", e instanceof Error ? e.message : String(e));
13603
13696
  }
13604
- return {
13697
+ let c = {
13605
13698
  name: n,
13606
- category: i,
13699
+ category: a,
13607
13700
  description: `${n} component for Exploria UI`,
13608
- path: r,
13609
- documentContent: a,
13610
- props: this.extractProps(a),
13611
- events: this.extractEvents(a),
13612
- slots: this.extractSlots(a),
13613
- usage: this.extractUsage(a),
13614
- examples: this.extractExamples(a)
13701
+ path: i,
13702
+ documentContent: o,
13703
+ props: this.extractProps(o),
13704
+ events: this.extractEvents(o),
13705
+ slots: this.extractSlots(o),
13706
+ usage: this.extractUsage(o),
13707
+ examples: this.extractExamples(o)
13615
13708
  };
13709
+ return this.componentDetailsCache.set(r, c), console.log(`✅ 成功获取组件 ${n} 的详情`), c;
13616
13710
  }
13617
13711
  searchDocuments(e) {
13712
+ console.log(`🔍 正在搜索文档: ${e}`);
13618
13713
  let t = [], n = e.toLowerCase();
13619
13714
  return this.traverseDocs((e, r, i) => {
13620
13715
  let a = r.toLowerCase(), o = e.toLowerCase(), s = "low";
@@ -13631,14 +13726,17 @@ var Rm = import.meta.url.slice(7), zm = t.dirname(Rm), Bm = t.join(zm, "../../pu
13631
13726
  low: 1
13632
13727
  };
13633
13728
  return n[t.relevance] - n[e.relevance];
13634
- }), t;
13729
+ }), console.log(`✅ 搜索完成,共找到 ${t.length} 个匹配结果`), t;
13730
+ }
13731
+ clearCache() {
13732
+ this.componentListCache = null, this.componentDetailsCache.clear(), console.log("🗑️ 已清空文档解析器缓存");
13635
13733
  }
13636
13734
  }();
13637
13735
  //#endregion
13638
13736
  //#region src/resources/componentList.ts
13639
- function Hm(e) {
13737
+ function Rm(e) {
13640
13738
  e.resource("component_list", "components://exploria-ui-list", async (e) => {
13641
- let t = Vm.getComponentList();
13739
+ let t = Lm.getComponentList();
13642
13740
  return { contents: [{
13643
13741
  uri: e.href,
13644
13742
  text: JSON.stringify({
@@ -13652,9 +13750,8 @@ function Hm(e) {
13652
13750
  }
13653
13751
  //#endregion
13654
13752
  //#region src/resources/serverStatus.ts
13655
- var Um = import.meta.url.slice(7), Wm = t.dirname(Um);
13656
- function Gm(n) {
13657
- let r = t.join(Wm, "../../package.json"), i = JSON.parse(e.readFileSync(r, "utf-8"));
13753
+ function zm(n) {
13754
+ let r = t.join(process.cwd(), "package.json"), i = JSON.parse(e.readFileSync(r, "utf-8"));
13658
13755
  n.resource("server_status", "status://exploria-ui-server", async (e) => ({ contents: [{
13659
13756
  uri: e.href,
13660
13757
  text: JSON.stringify({
@@ -13670,15 +13767,15 @@ function Gm(n) {
13670
13767
  }
13671
13768
  //#endregion
13672
13769
  //#region src/resources/index.ts
13673
- function Km(e) {
13674
- Gm(e), Lm(e), Hm(e);
13770
+ function Bm(e) {
13771
+ console.log("📚 正在注册 MCP 资源..."), zm(e), Fm(e), Rm(e), console.log("✅ 所有 MCP 资源注册完成");
13675
13772
  }
13676
13773
  //#endregion
13677
13774
  //#region src/tools/getComponentDetails.ts
13678
- function qm(e) {
13775
+ function Vm(e) {
13679
13776
  e.tool("get_component_details", "获取指定 Exploria UI 组件的详细信息", { componentName: r.string().describe("组件名称,例如:button、input、dialog") }, async ({ componentName: e }) => {
13680
13777
  try {
13681
- let t = Vm.getComponentDetails(e);
13778
+ let t = Lm.getComponentDetails(e);
13682
13779
  return t ? { content: [{
13683
13780
  type: "text",
13684
13781
  text: JSON.stringify({
@@ -13708,10 +13805,10 @@ function qm(e) {
13708
13805
  }
13709
13806
  //#endregion
13710
13807
  //#region src/tools/getComponentList.ts
13711
- function Jm(e) {
13808
+ function Hm(e) {
13712
13809
  e.tool("get_component_list", "获取所有 Exploria UI 组件列表", {}, async () => {
13713
13810
  try {
13714
- let e = Vm.getComponentList();
13811
+ let e = Lm.getComponentList();
13715
13812
  return { content: [{
13716
13813
  type: "text",
13717
13814
  text: JSON.stringify({
@@ -13733,13 +13830,13 @@ function Jm(e) {
13733
13830
  }
13734
13831
  //#endregion
13735
13832
  //#region src/tools/searchAndGetDetails.ts
13736
- function Ym(e) {
13833
+ function Um(e) {
13737
13834
  e.tool("search_and_get_details", "搜索 Exploria UI 组件并获取详细信息", {
13738
13835
  query: r.string().describe("搜索关键词,例如:button、input、dialog"),
13739
13836
  limit: r.number().optional().describe("返回结果数量限制,默认为 3")
13740
13837
  }, async ({ query: e, limit: t = 3 }) => {
13741
13838
  try {
13742
- let n = Vm.searchDocuments(e);
13839
+ let n = Lm.searchDocuments(e);
13743
13840
  if (n.length === 0) return { content: [{
13744
13841
  type: "text",
13745
13842
  text: JSON.stringify({
@@ -13748,7 +13845,7 @@ function Ym(e) {
13748
13845
  }, null, 2)
13749
13846
  }] };
13750
13847
  let r = await Promise.all(n.slice(0, t).map(async (e) => {
13751
- let t = Vm.getComponentDetails(e.name);
13848
+ let t = Lm.getComponentDetails(e.name);
13752
13849
  return {
13753
13850
  ...e,
13754
13851
  details: t
@@ -13775,10 +13872,10 @@ function Ym(e) {
13775
13872
  }
13776
13873
  //#endregion
13777
13874
  //#region src/tools/searchDocuments.ts
13778
- function Xm(e) {
13875
+ function Wm(e) {
13779
13876
  e.tool("search_documents", "搜索 Exploria UI 组件文档", { query: r.string().describe("搜索关键词,例如:button、input、dialog") }, async ({ query: e }) => {
13780
13877
  try {
13781
- let t = Vm.searchDocuments(e);
13878
+ let t = Lm.searchDocuments(e);
13782
13879
  return { content: [{
13783
13880
  type: "text",
13784
13881
  text: JSON.stringify({
@@ -13799,27 +13896,66 @@ function Xm(e) {
13799
13896
  }
13800
13897
  //#endregion
13801
13898
  //#region src/tools/index.ts
13802
- function Zm(e) {
13803
- Xm(e), Jm(e), qm(e), Ym(e);
13899
+ function Gm(e) {
13900
+ console.log("🔧 正在注册 MCP 工具..."), Wm(e), Hm(e), Vm(e), Um(e), console.log("✅ 所有 MCP 工具注册完成");
13804
13901
  }
13805
- //#endregion
13806
- //#region src/index.ts
13807
- var Qm = import.meta.url.slice(7), $m = t.dirname(Qm), eh = t.join($m, "../package.json"), th = JSON.parse(e.readFileSync(eh, "utf-8")), nh = new _m({
13808
- name: th.name,
13809
- version: th.version,
13810
- description: th.description
13811
- });
13812
- Zm(nh), Km(nh), Pm(nh), process.stdin.on("error", (e) => {
13813
- console.error("标准输入错误:", e), process.exit(1);
13814
- }), process.stdout.on("error", (e) => {
13815
- console.error("标准输出错误:", e), process.exit(1);
13816
- }), process.on("SIGINT", async () => {
13817
- await nh.close(), console.log("MCP Server 已关闭"), process.exit(0);
13818
- });
13819
- var rh = new jm();
13820
- nh.connect(rh).then(() => {
13821
- console.log("Exploria UI MCP Server 已启动,等待连接..."), console.log(`Server name: ${th.name}`), console.log(`Server version: ${th.version}`);
13822
- }).catch((e) => {
13823
- console.error("启动 MCP Server 失败:", e), process.exit(1);
13824
- });
13902
+ new class {
13903
+ server = null;
13904
+ packageJson;
13905
+ transport = null;
13906
+ constructor() {
13907
+ this.loadPackageJson(), this.setupEventHandlers();
13908
+ }
13909
+ loadPackageJson() {
13910
+ try {
13911
+ let n = t.join(process.cwd(), "package.json"), r = e.readFileSync(n, "utf-8");
13912
+ this.packageJson = JSON.parse(r);
13913
+ } catch (e) {
13914
+ console.error("🔴 加载 package.json 失败:", e), process.exit(1);
13915
+ }
13916
+ }
13917
+ setupEventHandlers() {
13918
+ process.stdin.on("error", (e) => {
13919
+ console.error("🔴 标准输入错误:", e.message), this.shutdown(1);
13920
+ }), process.stdout.on("error", (e) => {
13921
+ console.error("🔴 标准输出错误:", e.message), this.shutdown(1);
13922
+ }), process.on("SIGINT", () => {
13923
+ console.log("\n🟠 收到 SIGINT 信号,正在关闭服务器..."), this.shutdown(0);
13924
+ }), process.on("SIGTERM", () => {
13925
+ console.log("\n🟠 收到 SIGTERM 信号,正在关闭服务器..."), this.shutdown(0);
13926
+ }), process.on("uncaughtException", (e) => {
13927
+ console.error("🔴 未捕获异常:", e.message), console.error("🔴 异常堆栈:", e.stack), this.shutdown(1);
13928
+ }), process.on("unhandledRejection", (e) => {
13929
+ console.error("🔴 未处理的 Promise 拒绝:", e), this.shutdown(1);
13930
+ });
13931
+ }
13932
+ initializeServer() {
13933
+ try {
13934
+ this.server = new _m({
13935
+ name: this.packageJson.name,
13936
+ version: this.packageJson.version,
13937
+ description: this.packageJson.description
13938
+ }), Gm(this.server), Bm(this.server), Pm(this.server), console.log("🟢 成功注册所有工具、资源和提示");
13939
+ } catch (e) {
13940
+ console.error("🔴 初始化 MCP Server 失败:", e), process.exit(1);
13941
+ }
13942
+ }
13943
+ async start() {
13944
+ try {
13945
+ if (this.initializeServer(), this.transport = new jm(), !this.server || !this.transport) throw Error("服务器或传输层未初始化");
13946
+ await this.server.connect(this.transport), console.log("\n✅ Exploria UI MCP Server 已成功启动"), console.log(`📦 服务器名称: ${this.packageJson.name}`), console.log(`📌 服务器版本: ${this.packageJson.version}`), console.log("🔗 等待 AI IDE 连接...\n");
13947
+ } catch (e) {
13948
+ console.error("🔴 启动 MCP Server 失败:", e), this.shutdown(1);
13949
+ }
13950
+ }
13951
+ async shutdown(e) {
13952
+ try {
13953
+ this.server && (await this.server.close(), console.log("✅ MCP Server 已成功关闭"));
13954
+ } catch (e) {
13955
+ console.error("🔴 关闭服务器时发生错误:", e);
13956
+ } finally {
13957
+ process.exit(e);
13958
+ }
13959
+ }
13960
+ }().start();
13825
13961
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "exploria-ui-mcp-server",
3
- "version": "2.1.1",
3
+ "version": "2.1.3",
4
4
  "description": "MCP Server for Exploria UI Component Library",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",