内容
# 组件库 MCP
MCP(模型上下文协议)服务器扫描 React 和 Vue 项目,提取组件元数据(属性、插槽、事件、导入、使用情况),并通过结构化工具将其暴露给 AI 编码代理。
**解决的问题:** 当 AI 编码代理在没有上下文的情况下编写 UI 代码时,会出现三个常见问题:
1. **重复组件** — 创建 `<UserCard>` 时,`<UserProfile>` 已经存在。
2. **错误的属性 API** — 传递 `label` 时,组件期望 `title`,或缺少必需的属性。
3. **不一致的模式** — 构建一次性对话框,而不是使用项目的 `<BaseDialog>`。
该 MCP 在 AI 编码代理编写任何 UI 代码之前,为其提供对组件库的完全可见性。
## 要求
- Node.js ≥ 20
- pnpm(其他包管理器也适用 — 安装依赖项时可以使用任意方式,运行时服务器是一个普通的 Node 脚本)
## 安装和构建
```bash
git clone <此仓库>
cd component-library-mcp
pnpm install
pnpm build
```
`pnpm build` 在 `dist/index.js` 处生成一个可运行的服务器。
## 在 Claude Code 中配置
服务器扫描启动目录(`process.cwd()`)。选择以下两种设置之一 — 无需 `PROJECT_ROOT`。
### 选项 A — 每个项目的 `.mcp.json`(推荐)
在要使用 MCP 的每个 React/Vue 项目的根目录中添加一个 `.mcp.json` 文件:
```json
{
"mcpServers": {
"component-library": {
"command": "node",
"args": ["/绝对路径/到/component-library-mcp/dist/index.js"]
}
}
}
```
Claude Code 自动从打开的工作区加载 `.mcp.json`。每个项目都可以有自己的 `env` 重写(见下文),而不会影响其他项目。
### 选项 B — 全局 `~/.claude.json`
如果您通常在一个项目上工作,并始终从该项目的目录启动 Claude Code:
```json
{
"mcpServers": {
"component-library": {
"command": "node",
"args": ["/绝对路径/到/component-library-mcp/dist/index.js"]
}
}
}
```
如果没有设置环境变量,服务器扫描 `process.cwd()` — 即 Claude Code 打开的目录。通过在编辑器中打开不同的文件夹或从不同目录重新启动 Claude Code 来切换项目。
在更改任一配置后重启 Claude Code。服务器在标准输入/输出上运行 — 没有端口,没有守护进程。
## 环境变量(可选)
所有环境变量均为可选。仅在需要覆盖默认值时,在 MCP 配置的 `env: { ... }` 中设置。
| 变量 | 默认值 | 描述 |
| --- | --- | --- |
| `PROJECT_ROOT` | `process.cwd()` | 要扫描的绝对路径。通常不需要设置此变量 — 服务器使用启动目录。仅在不需要时设置。 |
| `COMPONENT_DIRS` | `auto` | 以逗号分隔的目录列表。`auto` 探测 `src/components`、`src/ui`、`src/shared`、`components`、`lib/components`、`app/components`,并回退到 `src/` 或项目根目录。 |
| `FRAMEWORK` | `auto` | `react` \| `vue` \| `auto`。自动从 `package.json` 依赖项检测。 |
| `EXCLUDE_PATTERNS` | `node_modules,dist,.next,.nuxt` | 以逗号分隔的目录名称或通配符。裸名称变为 `**/<name>/**`。 |
| `MAX_DEPTH` | `10` | `fast-glob` 的最大递归深度。 |
| `INCLUDE_STORIES` | `true` | 解析 `.stories.(ts\|tsx\|js\|jsx)` 并将故事示例附加到组件。 |
| `LOG_LEVEL` | `silent` | `silent` \| `info` \| `debug`。所有日志输出到标准错误流。 |
示例 `.mcp.json` 带有重写:
```json
{
"mcpServers": {
"component-library": {
"command": "node",
"args": ["/绝对路径/到/component-library-mcp/dist/index.js"],
"env": {
"COMPONENT_DIRS": "src/components,src/ui",
"FRAMEWORK": "react",
"EXCLUDE_PATTERNS": "node_modules,dist,__tests__,stories",
"INCLUDE_STORIES": "false",
"LOG_LEVEL": "info"
}
}
}
}
```
## 可用工具
所有 7 种工具都接受 Zod 验证的 JSON 输入,并返回 `content`(文本)和 `structuredContent`(与结构化输出相同的数据)。
### 1. `list_components`
项目中每个组件的摘要。通常,代理首先调用此工具。
```jsonc
{ "framework": "react", "min_usage": 1, "include_props": false }
```
返回按字母顺序排序的数组:`{ name, file_path, framework, prop_count, usage_count, has_stories, description?, tags? }`。
### 2. `get_component_details`
一个组件的完整元数据 — 属性、插槽、事件、描述、故事示例。
```jsonc
{ "name": "Button" }
// 或
{ "file_path": "src/components/Button.tsx" }
```
模糊回退:如果 `name` 没有精确匹配,则返回 Levenshtein 距离 ≤ 3 的建议。
### 3. `search_components`
自然语言 + 结构化搜索。
```jsonc
{
"query": "dialog modal",
"prop_type": "boolean",
"has_slot": "footer",
"limit": 10
}
```
返回排名靠前的 `{ name, score, reasons[] }` 结果。权重:名称 1.0,描述 0.5,标签 0.6,属性名称 0.35,路径 0.2。
### 4. `get_import_graph`
谁导入什么。
```jsonc
{ "component_name": "Button", "direction": "both", "depth": 2 }
```
返回 `dependencies[]`(该组件导入的内容)和 `dependents[]`(导入该组件的内容,带有 `is_page: true` 表示页面/路由)。桶文件被跟踪但不计为依赖项。
### 5. `check_duplicate` — **最高价值工具**
在创建新组件之前调用此工具。
```jsonc
{
"proposed_name": "UserCard",
"proposed_props": ["user", "size", "avatarUrl"],
"purpose": "display user profile card"
}
```
返回 `{ has_duplicates, existing_matches[], recommendation }`,其中 recommendation 为 `use_existing` | `extend_existing` | `create_new`。分数结合名称相似度(0.45)、属性重叠(0.35)和目的/描述重叠(0.2),如果建议的属性是现有组件属性的子集,则会短路到 `use_existing`。
### 6. `get_component_usage_example`
代码库中的实际使用代码段。
```jsonc
{ "component_name": "Button", "limit": 3 }
```
返回最多 `limit` 个 `{ file_path, code_snippet, props_used[] }` 示例(5–15 行围绕导入行),以及 `story_examples[]` 来自匹配的 `.stories.(t|j)sx` 文件。
### 7. `refresh_cache`
强制重新扫描。默认情况下增量式。
```jsonc
{ "full_scan": true }
```
返回 `{ components_found, scan_duration_ms, new_components[], removed_components[], reparsed_files[] }`。
## 工作原理
- **首次工具调用** 触发完整扫描。后续调用执行基于 `mtime` 的增量扫描 — 仅重新解析更改的文件。
- **React 解析** 处理函数/箭头/FC 组件、HOC 解包(`memo`、`forwardRef`、`observer`、`nested`)、旧式 `propTypes`、JSDoc 和通过 TypeScript 编译器 API 进行跨文件类型扩展。
- **Vue 解析** 处理 `<script setup>` 类型和运行时 `defineProps` / `defineEmits`、选项 API、`defineComponent`、命名 + 作用域插槽。
- **导入图** 包括页面/路由目录作为使用者(因此 `usage_count` 反映来自 `src/pages/**` 的导入),跟踪桶重新导出到源文件,并解析 tsconfig `paths` 别名。
- **性能** — 200 组件项目在 ~150ms 内扫描;2 文件增量扫描在 ~30ms 内。
## 开发
```bash
pnpm dev # tsx 监视模式
pnpm test # vitest,所有测试
pnpm test:perf # 仅性能测试
pnpm test:watch # vitest 监视模式
pnpm build # tsc → dist/
```
## 故障排除
**服务器返回 `{ components: [], total: 0 }` 我的项目。**
- 确保 Claude Code 从项目根目录启动(或打开),其中包含 `package.json`。
- 如果项目根目录位于其他位置,请在 MCP 配置的 `env` 块中将 `PROJECT_ROOT` 设置为最后的手段。
- 运行 `LOG_LEVEL=info`。标准错误流将显示扫描器尝试的目录及其找到的文件数量。
- 如果您有非标准布局,请显式设置 `COMPONENT_DIRS`(例如 `"lib/ui,packages/core/components"`)。
**框架不正确。**
- 显式设置 `FRAMEWORK=react` 或 `FRAMEWORK=vue`。自动检测读取 `package.json` 依赖项(`react`、`next`、`vue`、`nuxt`)。
**跨文件类型显示为 `"Props"` 而不是 `"a" | "b"`。**
- TypeScript 类型解析器自动运行。如果失败,解析器会回退到别名名称。检查 `LOG_LEVEL=debug` 以获取解析器错误 — 通常是缺少的 `tsconfig.json` 路径别名。
**`usage_count` 为一个明显使用的组件为 0。**
- 导入文件必须位于扫描目录内或自动检测的页面目录(`src/pages`、`src/routes`、`src/app`、`pages`、`routes`、`app`)内。如果导入来自非标准目录,请将其添加到 `COMPONENT_DIRS`。
**来自客户端的 JSON-RPC 协议错误。**
- 服务器仅向标准输出写入 JSON-RPC。如果您在那里看到垃圾,某个依赖项正在使用 `console.log` — 请打开问题。我们的所有日志记录都通过 `src/logger.ts` 输出到标准错误流。
## 项目布局
```
src/
index.ts # 标准输入/输出入口点
server.ts # MCP 服务器 + 工具注册
config.ts # 环境变量解析
logger.ts # 仅标准错误流记录器
lib/
types.ts # ComponentInfo、PropInfo 等
schemas.ts # 工具输入的 Zod 模式
scanner/
file-scanner.ts # 组件目录发现
page-scanner.ts # 页面/路由目录发现(仅用于图表)
framework-detector.ts # react vs vue
import-resolver.ts # 相对 + tsconfig 路径
import-extractor.ts # AST → 导入语句
import-graph.ts # 依赖项 / 依赖者 / 用例
parsers/
react-parser.ts # TSX + HOC 解包
vue-sfc-parser.ts # <script setup> / 选项 API / 模板插槽
vue-tsx-parser.ts # Vue TSX(react 解析器的薄包装)
story-parser.ts # .stories.tsx
jsdoc-parser.ts # @tag, @param, 描述
ts-type-resolver.ts # 通过 ts.Program 进行跨文件类型扩展
shared.ts
search/
fuzzy-match.ts # Levenshtein + 令牌重叠
text-search.ts # 排名 + 结构化过滤器
duplicate-detector.ts # 名称 + 属性 + 目的评分
cache/
component-cache.ts # 内存 file_path → 条目
incremental-scan.ts # mtime 差分 + 图表重建 + 故事连接
tools/
list-components.ts
get-component-details.ts
search-components.ts
get-import-graph.ts
check-duplicate.ts
get-usage-example.ts
refresh-cache.ts
tests/
fixtures/ # react-project, vue-project, mixed, nonstandard
parsers/ scanner/ search/ cache/ tools/ perf/
```
## 许可证
ISC。