@douyinfe/semi-mcp 1.0.2 → 1.0.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 CHANGED
@@ -1,38 +1,40 @@
1
+ [中文](README-zh_CN.md) | [English](README.md)
2
+
1
3
  # Semi MCP Server
2
4
 
3
- 基于 Model Context Protocol (MCP) SDK 实现的 MCP 服务器,提供 Semi Design 组件文档和组件列表查询功能。
5
+ An MCP (Model Context Protocol) server implementation based on the MCP SDK, providing Semi Design component documentation and component list query functionality.
4
6
 
5
- ## 简介
7
+ ## Introduction
6
8
 
7
- Semi MCP Server 是一个 MCP (Model Context Protocol) 服务器,通过 stdio 传输层与支持 MCP 协议的客户端通信。它提供了获取 Semi Design 组件文档、组件列表等功能。
9
+ Semi MCP Server is an MCP (Model Context Protocol) server that communicates with MCP-compatible clients through stdio transport. It provides functionality to fetch Semi Design component documentation, component lists, and more.
8
10
 
9
- ## 安装
11
+ ## Installation
10
12
 
11
- ### 全局安装
13
+ ### Global Installation
12
14
 
13
15
  ```bash
14
16
  npm install -g @douyinfe/semi-mcp
15
17
  ```
16
18
 
17
- ### 本地安装
19
+ ### Local Installation
18
20
 
19
21
  ```bash
20
22
  npm install @douyinfe/semi-mcp
21
23
  ```
22
24
 
23
- ## 使用方法
25
+ ## Usage
24
26
 
25
- ### 作为命令行工具
27
+ ### As a Command Line Tool
26
28
 
27
- 全局安装后,可以直接使用:
29
+ After global installation, you can use it directly:
28
30
 
29
31
  ```bash
30
32
  semi-mcp
31
33
  ```
32
34
 
33
- ### MCP 客户端中配置
35
+ ### Configuration in MCP Clients
34
36
 
35
- 在支持 MCP 的客户端(如 Claude Desktop)中配置:
37
+ Configure in MCP-compatible clients (such as Claude Desktop):
36
38
 
37
39
  ```json
38
40
  {
@@ -45,7 +47,7 @@ semi-mcp
45
47
  }
46
48
  ```
47
49
 
48
- 或者如果已全局安装:
50
+ Or if installed globally:
49
51
 
50
52
  ```json
51
53
  {
@@ -57,28 +59,29 @@ semi-mcp
57
59
  }
58
60
  ```
59
61
 
60
- ## 功能
62
+ ## Features
61
63
 
62
- ### 工具 (Tools)
64
+ ### Tools
63
65
 
64
66
  #### `get_semi_document`
65
67
 
66
- 获取 Semi Design 组件文档或组件列表。
68
+ Get Semi Design component documentation or component list.
67
69
 
68
- **参数:**
69
- - `componentName` (可选): 组件名称,例如 `Button`、`Input` 等。如果不提供,则返回组件列表
70
- - `version` (可选): 版本号,例如 `2.89.2-alpha.3`。如果不提供,默认使用 `latest`
70
+ **Parameters:**
71
+ - `componentName` (optional): Component name, e.g., `Button`, `Input`, etc. If not provided, returns the component list
72
+ - `version` (optional): Version number, e.g., `2.89.2-alpha.3`. If not provided, defaults to `latest`
73
+ - `get_path` (optional): If `true`, saves documents to the system temporary directory and returns the path instead of returning document content in the response. Defaults to `false`
71
74
 
72
- **示例:**
75
+ **Examples:**
73
76
 
74
- 获取组件列表:
77
+ Get component list:
75
78
  ```json
76
79
  {
77
80
  "name": "get_semi_document"
78
81
  }
79
82
  ```
80
83
 
81
- 获取指定组件文档:
84
+ Get specific component documentation:
82
85
  ```json
83
86
  {
84
87
  "name": "get_semi_document",
@@ -89,9 +92,9 @@ semi-mcp
89
92
  }
90
93
  ```
91
94
 
92
- **返回格式:**
95
+ **Response Format:**
93
96
 
94
- 获取组件列表时:
97
+ When getting component list:
95
98
  ```json
96
99
  {
97
100
  "version": "2.89.2-alpha.3",
@@ -100,7 +103,7 @@ semi-mcp
100
103
  }
101
104
  ```
102
105
 
103
- 获取组件文档时:
106
+ When getting component documentation:
104
107
  ```json
105
108
  {
106
109
  "componentName": "button",
@@ -113,91 +116,94 @@ semi-mcp
113
116
  }
114
117
  ```
115
118
 
116
- ### 资源 (Resources)
119
+ **Note:** For large documents (over 888 lines), the tool will automatically save them to a temporary directory and return the file paths instead of content.
120
+
121
+ ### Resources
117
122
 
118
123
  #### `semi://components`
119
124
 
120
- Semi Design 组件列表资源。
125
+ Semi Design component list resource.
121
126
 
122
- ## 开发
127
+ ## Development
123
128
 
124
- ### 环境要求
129
+ ### Requirements
125
130
 
126
131
  - Node.js >= 18.0.0
127
- - npm yarn
132
+ - npm or yarn
128
133
 
129
- ### 安装依赖
134
+ ### Install Dependencies
130
135
 
131
136
  ```bash
132
137
  npm install
133
138
  ```
134
139
 
135
- ### 构建
140
+ ### Build
136
141
 
137
- 构建生产版本:
142
+ Build production version:
138
143
 
139
144
  ```bash
140
145
  npm run build
141
146
  ```
142
147
 
143
- 开发模式(监听文件变化并自动重建):
148
+ Development mode (watch for file changes and auto-rebuild):
144
149
 
145
150
  ```bash
146
151
  npm run dev
147
152
  ```
148
153
 
149
- ### 测试
154
+ ### Test
150
155
 
151
- 运行测试:
156
+ Run tests:
152
157
 
153
158
  ```bash
154
159
  npm test
155
160
  ```
156
161
 
157
- ### 运行
162
+ ### Run
158
163
 
159
- 构建完成后运行服务器:
164
+ Run the server after building:
160
165
 
161
166
  ```bash
162
167
  npm start
163
168
  ```
164
169
 
165
- 或者直接运行构建后的文件:
170
+ Or run the built file directly:
166
171
 
167
172
  ```bash
168
173
  node dist/index.js
169
174
  ```
170
175
 
171
- ## 技术栈
176
+ ## Tech Stack
172
177
 
173
- - **TypeScript**: 类型安全的 JavaScript
174
- - **Rslib**: 快速构建工具
175
- - **@modelcontextprotocol/sdk**: MCP 官方 SDK
178
+ - **TypeScript**: Type-safe JavaScript
179
+ - **Rslib**: Fast build tool
180
+ - **@modelcontextprotocol/sdk**: Official MCP SDK
176
181
 
177
- ## 项目结构
182
+ ## Project Structure
178
183
 
179
184
  ```
180
185
  semi-mcp/
181
186
  ├── src/
182
- │ ├── index.ts # 主入口文件
183
- │ ├── tools/ # 工具定义
187
+ │ ├── index.ts # Main entry file
188
+ │ ├── tools/ # Tool definitions
184
189
  │ │ ├── index.ts
185
190
  │ │ └── get-semi-document.ts
186
- │ └── utils/ # 工具函数
191
+ │ └── utils/ # Utility functions
187
192
  │ ├── fetch-directory-list.ts
188
- └── fetch-file-content.ts
189
- ├── tests/ # 测试文件
193
+ ├── fetch-file-content.ts
194
+ │ └── get-component-list.ts
195
+ ├── tests/ # Test files
190
196
  │ └── get-semi-document.test.ts
191
- ├── dist/ # 构建输出
197
+ ├── dist/ # Build output
192
198
  ├── package.json
193
199
  └── README.md
194
200
  ```
195
201
 
196
- ## 许可证
202
+ ## License
197
203
 
198
204
  MIT
199
205
 
200
- ## 相关链接
206
+ ## Related Links
201
207
 
202
- - [Semi Design 官网](https://semi.design)
203
- - [Model Context Protocol 文档](https://modelcontextprotocol.io)
208
+ - [Semi Design Official Website](https://semi.design)
209
+ - [Model Context Protocol Documentation](https://modelcontextprotocol.io)
package/dist/index.js CHANGED
@@ -16,8 +16,65 @@ function flattenDirectoryStructure(item, result = []) {
16
16
  if (item.files && Array.isArray(item.files)) for (const file of item.files)flattenDirectoryStructure(file, result);
17
17
  return result;
18
18
  }
19
+ async function fetchNpmMirrorDirectoryRecursive(baseUrl, packageName, version, path, maxDepth = 10) {
20
+ if (maxDepth <= 0) return [];
21
+ const url = `${baseUrl}/${packageName}/${version}/files/${path}/?meta`;
22
+ const response = await fetch(url, {
23
+ headers: {
24
+ Accept: 'application/json'
25
+ }
26
+ });
27
+ if (!response.ok) throw new Error(`获取目录列表失败: ${response.status} ${response.statusText}`);
28
+ const contentType = response.headers.get('content-type') || '';
29
+ if (!contentType.includes('application/json')) throw new Error(`API 返回了非 JSON 格式: ${contentType}`);
30
+ const data = await response.json();
31
+ const normalizeType = (item)=>{
32
+ const path = item.path;
33
+ if (path.endsWith('/')) return {
34
+ path,
35
+ type: 'directory'
36
+ };
37
+ if (item.type && item.type.includes('/')) return {
38
+ path,
39
+ type: 'file'
40
+ };
41
+ if ('directory' === item.type) return {
42
+ path,
43
+ type: 'directory'
44
+ };
45
+ return {
46
+ path,
47
+ type: 'file'
48
+ };
49
+ };
50
+ const result = [];
51
+ if (data && 'object' == typeof data && 'files' in data && Array.isArray(data.files)) {
52
+ const promises = [];
53
+ for (const item of data.files){
54
+ const normalized = normalizeType(item);
55
+ result.push(normalized);
56
+ if ('directory' !== normalized.type || item.files && 0 !== item.files.length) {
57
+ if (item.files && Array.isArray(item.files) && item.files.length > 0) {
58
+ const flattened = [];
59
+ flattenDirectoryStructure(item, flattened);
60
+ const subFiles = flattened.filter((f)=>f.path !== normalized.path).map(normalizeType);
61
+ result.push(...subFiles);
62
+ }
63
+ } else {
64
+ const subPath = normalized.path.startsWith('/') ? normalized.path.slice(1) : normalized.path;
65
+ promises.push(fetchNpmMirrorDirectoryRecursive(baseUrl, packageName, version, subPath, maxDepth - 1).then((subFiles)=>subFiles.filter((f)=>f.path !== normalized.path)).catch(()=>[]));
66
+ }
67
+ }
68
+ if (promises.length > 0) {
69
+ const subResults = await Promise.all(promises);
70
+ for (const subFiles of subResults)result.push(...subFiles);
71
+ }
72
+ }
73
+ return result;
74
+ }
19
75
  async function fetchDirectoryListFromSource(baseUrl, packageName, version, path, isNpmMirror = false) {
20
- const url = isNpmMirror ? `${baseUrl}/${packageName}/${version}/files/${path}/?meta` : `${baseUrl}/${packageName}@${version}/${path}/?meta`;
76
+ if (isNpmMirror) return fetchNpmMirrorDirectoryRecursive(baseUrl, packageName, version, path);
77
+ const url = `${baseUrl}/${packageName}@${version}/${path}/?meta`;
21
78
  const response = await fetch(url, {
22
79
  headers: {
23
80
  Accept: 'application/json'
@@ -48,12 +105,8 @@ async function fetchDirectoryListFromSource(baseUrl, packageName, version, path,
48
105
  };
49
106
  if (Array.isArray(data)) return data.map(normalizeType);
50
107
  if (data && 'object' == typeof data && 'files' in data) {
51
- if (Array.isArray(data.files)) {
52
- const flattened = [];
53
- for (const item of data.files)flattenDirectoryStructure(item, flattened);
54
- return flattened.map(normalizeType);
55
- }
56
- return [];
108
+ const filesData = data;
109
+ if (Array.isArray(filesData.files)) return filesData.files.map(normalizeType);
57
110
  }
58
111
  if (data && 'object' == typeof data && 'path' in data) {
59
112
  const singleItem = data;
@@ -71,20 +124,28 @@ async function fetchDirectoryListFromSource(baseUrl, packageName, version, path,
71
124
  async function fetchDirectoryList(packageName, version, path) {
72
125
  const unpkgPromise = fetchDirectoryListFromSource(UNPKG_BASE_URL, packageName, version, path, false);
73
126
  const npmmirrorPromise = fetchDirectoryListFromSource(NPMMIRROR_BASE_URL, packageName, version, path, true);
74
- const unpkgWithFallback = unpkgPromise.catch(()=>new Promise(()=>{}));
75
- const npmmirrorWithFallback = npmmirrorPromise.catch(()=>new Promise(()=>{}));
76
- const raceResult = await Promise.race([
77
- unpkgWithFallback,
78
- npmmirrorWithFallback
79
- ]).catch(()=>null);
80
- if (raceResult) return raceResult;
81
127
  const results = await Promise.allSettled([
82
128
  unpkgPromise,
83
129
  npmmirrorPromise
84
130
  ]);
131
+ const successfulResults = [];
85
132
  const errors = [];
86
- for (const result of results)if ('rejected' === result.status) errors.push(result.reason instanceof Error ? result.reason : new Error(String(result.reason)));
87
- throw new Error(`所有数据源都失败了: ${errors.map((e)=>e.message).join('; ')}`);
133
+ if ('fulfilled' === results[0].status) successfulResults.push({
134
+ source: 'unpkg',
135
+ files: results[0].value
136
+ });
137
+ else errors.push(results[0].reason instanceof Error ? results[0].reason : new Error(String(results[0].reason)));
138
+ if ('fulfilled' === results[1].status) successfulResults.push({
139
+ source: 'npmmirror',
140
+ files: results[1].value
141
+ });
142
+ else errors.push(results[1].reason instanceof Error ? results[1].reason : new Error(String(results[1].reason)));
143
+ if (0 === successfulResults.length) throw new Error(`所有数据源都失败了: ${errors.map((e)=>e.message).join('; ')}`);
144
+ successfulResults.sort((a, b)=>{
145
+ if (b.files.length !== a.files.length) return b.files.length - a.files.length;
146
+ return 'unpkg' === a.source ? -1 : 1;
147
+ });
148
+ return successfulResults[0].files;
88
149
  }
89
150
  const fetch_file_content_UNPKG_BASE_URL = 'https://unpkg.com';
90
151
  const fetch_file_content_NPMMIRROR_BASE_URL = 'https://registry.npmmirror.com';
@@ -14,7 +14,7 @@ export declare function fetchDirectoryListFromSource(baseUrl: string, packageNam
14
14
  }>>;
15
15
  /**
16
16
  * 从 unpkg 或 npmmirror 获取目录列表
17
- * 同时向两个数据源发送请求,使用第一个成功返回的结果
17
+ * 同时向两个数据源发送请求,优先使用返回更多文件的结果
18
18
  */
19
19
  export declare function fetchDirectoryList(packageName: string, version: string, path: string): Promise<Array<{
20
20
  path: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@douyinfe/semi-mcp",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "Semi Design MCP Server - Model Context Protocol server for Semi Design components and documentation",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",