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.
- package/README.md +89 -118
- package/dist/index.js +226 -90
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,37 +1,28 @@
|
|
|
1
1
|
# Exploria UI MCP Server
|
|
2
2
|
|
|
3
|
-
|
|
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
|
|
9
|
+
MCP 是 AI 工具世界的「USB 标准」,允许 AI 应用通过统一接口访问自定义数据和功能。
|
|
10
10
|
|
|
11
|
-
### 1.2
|
|
11
|
+
### 1.2 核心特性
|
|
12
12
|
|
|
13
|
-
- **统一接口**:为所有 AI
|
|
14
|
-
-
|
|
15
|
-
- **自动管理**:由 AI
|
|
13
|
+
- **统一接口**:为所有 AI 工具提供统一访问方式
|
|
14
|
+
- **轻量通信**:使用标准输入输出(stdio)通信,无需网络端口
|
|
15
|
+
- **自动管理**:由 AI 客户端自动启动、管理和停止
|
|
16
16
|
- **安全可靠**:通过管道通信,避免网络安全风险
|
|
17
17
|
|
|
18
|
-
### 1.3
|
|
18
|
+
### 1.3 通信流程
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
|
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
|
|
35
|
+
### 2.2 AI IDE 配置
|
|
45
36
|
|
|
46
|
-
|
|
47
|
-
2. 添加以下配置:
|
|
37
|
+
所有 AI IDE 使用统一配置格式:
|
|
48
38
|
|
|
49
39
|
```json
|
|
50
40
|
{
|
|
51
41
|
"mcpServers": {
|
|
52
|
-
"exploria-ui-mcp": {
|
|
53
|
-
"command": "
|
|
54
|
-
"args": ["
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
58
|
+
### 2.3 验证配置
|
|
95
59
|
|
|
96
|
-
|
|
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`
|
|
109
|
-
| `get_component_list`
|
|
110
|
-
| `get_component_details`
|
|
111
|
-
| `search_and_get_details` | 搜索并获取组件详情
|
|
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`
|
|
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`
|
|
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** |
|
|
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
|
-
|
|
137
|
+
在项目根目录执行:
|
|
174
138
|
|
|
175
139
|
```bash
|
|
176
|
-
#
|
|
140
|
+
# 开发模式
|
|
177
141
|
pnpm mcp:dev
|
|
178
142
|
|
|
179
143
|
# 构建 MCP Server
|
|
180
144
|
pnpm mcp:build
|
|
181
145
|
|
|
182
|
-
#
|
|
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/`
|
|
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/`
|
|
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/`
|
|
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`
|
|
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
|
|
238
|
-
-
|
|
183
|
+
- 兼容 Cursor、Trae IDE、Claude Desktop 等
|
|
184
|
+
- 使用 stdio 通信,无需网络端口
|
|
239
185
|
|
|
240
186
|
## 9. 安全特性
|
|
241
187
|
|
|
242
188
|
- 无网络通信,所有数据通过管道传输
|
|
243
189
|
- 由 AI 客户端自动管理,无需手动暴露服务
|
|
244
|
-
-
|
|
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
|
-
##
|
|
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
|
-
|
|
13383
|
-
|
|
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
|
|
13485
|
+
var Im = t.join(process.cwd(), "public"), Lm = new class {
|
|
13487
13486
|
docsRoot;
|
|
13488
|
-
|
|
13489
|
-
|
|
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" ?
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
})
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
13577
|
-
|
|
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 = []
|
|
13581
|
-
|
|
13582
|
-
|
|
13583
|
-
|
|
13584
|
-
|
|
13585
|
-
|
|
13586
|
-
|
|
13587
|
-
|
|
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 =
|
|
13594
|
-
if (this.
|
|
13595
|
-
|
|
13596
|
-
|
|
13597
|
-
|
|
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(
|
|
13600
|
-
e.existsSync(n) && (
|
|
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
|
-
|
|
13697
|
+
let c = {
|
|
13605
13698
|
name: n,
|
|
13606
|
-
category:
|
|
13699
|
+
category: a,
|
|
13607
13700
|
description: `${n} component for Exploria UI`,
|
|
13608
|
-
path:
|
|
13609
|
-
documentContent:
|
|
13610
|
-
props: this.extractProps(
|
|
13611
|
-
events: this.extractEvents(
|
|
13612
|
-
slots: this.extractSlots(
|
|
13613
|
-
usage: this.extractUsage(
|
|
13614
|
-
examples: this.extractExamples(
|
|
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
|
|
13737
|
+
function Rm(e) {
|
|
13640
13738
|
e.resource("component_list", "components://exploria-ui-list", async (e) => {
|
|
13641
|
-
let t =
|
|
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
|
-
|
|
13656
|
-
|
|
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
|
|
13674
|
-
|
|
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
|
|
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 =
|
|
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
|
|
13808
|
+
function Hm(e) {
|
|
13712
13809
|
e.tool("get_component_list", "获取所有 Exploria UI 组件列表", {}, async () => {
|
|
13713
13810
|
try {
|
|
13714
|
-
let e =
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
13803
|
-
|
|
13899
|
+
function Gm(e) {
|
|
13900
|
+
console.log("🔧 正在注册 MCP 工具..."), Wm(e), Hm(e), Vm(e), Um(e), console.log("✅ 所有 MCP 工具注册完成");
|
|
13804
13901
|
}
|
|
13805
|
-
|
|
13806
|
-
|
|
13807
|
-
|
|
13808
|
-
|
|
13809
|
-
|
|
13810
|
-
|
|
13811
|
-
}
|
|
13812
|
-
|
|
13813
|
-
|
|
13814
|
-
|
|
13815
|
-
|
|
13816
|
-
}
|
|
13817
|
-
|
|
13818
|
-
}
|
|
13819
|
-
|
|
13820
|
-
|
|
13821
|
-
|
|
13822
|
-
|
|
13823
|
-
|
|
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
|