Content
# Component Library MCP
An MCP (Model Context Protocol) server that scans React and Vue projects, extracts component metadata (props, slots, events, imports, usage), and exposes it to AI coding agents via structured tools.
**What it solves:** When an AI coding agent writes UI code without context, it produces three recurring problems:
1. **Duplicate components** — creates `<UserCard>` when `<UserProfile>` already exists.
2. **Wrong prop APIs** — passes `label` when the component expects `title`, or misses a required prop.
3. **Inconsistent patterns** — builds a one-off dialog instead of using the project's `<BaseDialog>`.
This MCP gives the agent full visibility into your component library **before** it writes any UI code.
---
## Requirements
- Node.js ≥ 20
- pnpm (other package managers also work — install deps however you like, the server is a plain Node script at runtime)
## Install & build
```bash
git clone <this-repo>
cd component-library-mcp
pnpm install
pnpm build
```
`pnpm build` emits a runnable server at `dist/index.js`.
## Configure in Claude Code
The server scans whatever directory it is launched from (`process.cwd()`). Pick one of the two setups below — no `PROJECT_ROOT` needed.
### Option A — Per-project `.mcp.json` (recommended)
Drop a `.mcp.json` file at the root of every React/Vue project you want to use the MCP with:
```json
{
"mcpServers": {
"component-library": {
"command": "node",
"args": ["/absolute/path/to/component-library-mcp/dist/index.js"]
}
}
}
```
Claude Code auto-loads `.mcp.json` from the open workspace. Each project can have its own `env` overrides (see below) without polluting other projects.
### Option B — Global `~/.claude.json`
If you usually work in one project at a time and always launch Claude Code from that project's directory:
```json
{
"mcpServers": {
"component-library": {
"command": "node",
"args": ["/absolute/path/to/component-library-mcp/dist/index.js"]
}
}
}
```
With no env vars set, the server scans `process.cwd()` — which is the directory Claude Code is opened in. Switch projects by opening a different folder in your editor / re-launching Claude Code from a different directory.
Restart Claude Code after changing either config. The server runs on stdio — there's no port, no daemon.
## Environment variables (optional)
All env vars are optional. Set them under `env: { ... }` in the MCP config only when you need to override defaults.
| Variable | Default | Description |
|---|---|---|
| `PROJECT_ROOT` | `process.cwd()` | Absolute path to scan. Usually you don't need to set this — the server uses the directory it was launched from. Only set it when that isn't what you want. |
| `COMPONENT_DIRS` | `auto` | Comma-separated dirs to scan. `auto` probes `src/components`, `src/ui`, `src/shared`, `components`, `lib/components`, `app/components` and falls back to `src/` or the project root. |
| `FRAMEWORK` | `auto` | `react` \| `vue` \| `auto`. Auto detects from `package.json` deps. |
| `EXCLUDE_PATTERNS` | `node_modules,dist,.next,.nuxt` | Comma-separated dir names or globs. Bare names become `**/<name>/**`. |
| `MAX_DEPTH` | `10` | Max recursion depth for `fast-glob`. |
| `INCLUDE_STORIES` | `true` | Parse `.stories.(ts\|tsx\|js\|jsx)` and attach story examples to components. |
| `LOG_LEVEL` | `silent` | `silent` \| `info` \| `debug`. All logs go to stderr. |
Example `.mcp.json` with overrides:
```json
{
"mcpServers": {
"component-library": {
"command": "node",
"args": ["/absolute/path/to/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"
}
}
}
}
```
## Available tools
All 7 tools accept Zod-validated JSON input and return both `content` (text) and `structuredContent` (same data as structured output).
### 1. `list_components`
Summary of every component in the project. Agents typically call this first.
```jsonc
{ "framework": "react", "min_usage": 1, "include_props": false }
```
Returns an alphabetically sorted array: `{ name, file_path, framework, prop_count, usage_count, has_stories, description?, tags? }`.
### 2. `get_component_details`
Full metadata for one component — props, slots, events, description, story examples.
```jsonc
{ "name": "Button" }
// or
{ "file_path": "src/components/Button.tsx" }
```
Fuzzy fallback: if `name` has no exact match, suggestions within Levenshtein distance ≤ 3 are returned.
### 3. `search_components`
Natural-language + structured search.
```jsonc
{
"query": "dialog modal",
"prop_type": "boolean",
"has_slot": "footer",
"limit": 10
}
```
Returns ranked `{ name, score, reasons[] }` hits. Weights: name 1.0, description 0.5, tags 0.6, prop names 0.35, path 0.2.
### 4. `get_import_graph`
Who imports what.
```jsonc
{ "component_name": "Button", "direction": "both", "depth": 2 }
```
Returns `dependencies[]` (what this component imports) and `dependents[]` (who imports it, with `is_page: true` for pages/routes). Barrel files are followed through but not counted as dependents.
### 5. `check_duplicate` — **highest-value tool**
Call this *before* creating a new component.
```jsonc
{
"proposed_name": "UserCard",
"proposed_props": ["user", "size", "avatarUrl"],
"purpose": "display user profile card"
}
```
Returns `{ has_duplicates, existing_matches[], recommendation }` where recommendation is `use_existing` | `extend_existing` | `create_new`. Score combines name similarity (0.45), prop overlap (0.35), and purpose/description overlap (0.2), with a short-circuit to `use_existing` when proposed props are a full subset of an existing component.
### 6. `get_component_usage_example`
Real usage snippets from the codebase.
```jsonc
{ "component_name": "Button", "limit": 3 }
```
Returns up to `limit` `{ file_path, code_snippet, props_used[] }` examples (5–15 lines around the import line), plus `story_examples[]` from any matching `.stories.(t|j)sx` files.
### 7. `refresh_cache`
Force re-scan. Incremental by default.
```jsonc
{ "full_scan": true }
```
Returns `{ components_found, scan_duration_ms, new_components[], removed_components[], reparsed_files[] }`.
## How it works
- **First tool call** triggers a full scan. Subsequent calls do an `mtime`-based incremental scan — only re-parses files that changed.
- **React parsing** handles function/arrow/FC components, HOC unwrapping (`memo`, `forwardRef`, `observer`, nested), legacy `propTypes`, JSDoc, and cross-file type expansion via the TypeScript compiler API.
- **Vue parsing** handles `<script setup>` typed + runtime `defineProps` / `defineEmits`, Options API, `defineComponent`, named + scoped slots.
- **Import graph** includes page/route directories as consumers (so `usage_count` reflects imports from `src/pages/**`), follows barrel re-exports to source files, and resolves tsconfig `paths` aliases.
- **Performance** — 200-component project scans in ~150ms; 2-file incremental scans in ~30ms.
## Development
```bash
pnpm dev # tsx watch mode
pnpm test # vitest, all tests
pnpm test:perf # perf tests only
pnpm test:watch # vitest watch mode
pnpm build # tsc → dist/
```
## Troubleshooting
**The server returns `{ components: [], total: 0 }` for my project.**
- Make sure Claude Code was launched from (or has opened) the project root — where `package.json` lives. The server scans `process.cwd()` by default.
- If the project root is somewhere else, set `PROJECT_ROOT` in the MCP config's `env` block as a last resort.
- Run with `LOG_LEVEL=info`. stderr will show which dirs the scanner tried and how many files it found.
- If you have a non-standard layout, set `COMPONENT_DIRS` explicitly (e.g., `"lib/ui,packages/core/components"`).
**Framework is wrong.**
- Set `FRAMEWORK=react` or `FRAMEWORK=vue` explicitly. Auto-detection reads `package.json` deps (`react`, `next`, `vue`, `nuxt`).
**Cross-file types show up as `"Props"` instead of `"a" | "b"`.**
- The TS type resolver runs automatically. If it fails, the parser falls back to the alias name. Check `LOG_LEVEL=debug` for resolver errors — usually a missing `tsconfig.json` path alias.
**`usage_count` is 0 for a component that's clearly used.**
- Your importing files must live inside the scanned directories, or inside one of the auto-detected page dirs (`src/pages`, `src/routes`, `src/app`, `pages`, `routes`, `app`). If imports come from a non-standard dir, add it to `COMPONENT_DIRS`.
**JSON-RPC protocol errors from the client.**
- The server writes only JSON-RPC to stdout. If you see garbage there, a dependency is using `console.log` — open an issue. All of our logging goes to stderr via `src/logger.ts`.
## Project layout
```
src/
index.ts # stdio entry point
server.ts # MCP server + tool registration
config.ts # env var parsing
logger.ts # stderr-only logger
lib/
types.ts # ComponentInfo, PropInfo, etc.
schemas.ts # Zod schemas for tool inputs
scanner/
file-scanner.ts # component dir discovery
page-scanner.ts # page/route dir discovery (for graph only)
framework-detector.ts # react vs vue
import-resolver.ts # relative + tsconfig paths
import-extractor.ts # AST → import statements
import-graph.ts # dependencies / dependents / usages
parsers/
react-parser.ts # TSX + HOC unwrap
vue-sfc-parser.ts # <script setup> / Options API / template slots
vue-tsx-parser.ts # Vue TSX (thin wrapper over react parser)
story-parser.ts # .stories.tsx
jsdoc-parser.ts # @tag, @param, description
ts-type-resolver.ts # cross-file type expansion via ts.Program
shared.ts
search/
fuzzy-match.ts # Levenshtein + token overlap
text-search.ts # ranked + structured filters
duplicate-detector.ts # name + prop + purpose scoring
cache/
component-cache.ts # in-memory file_path → entry
incremental-scan.ts # mtime diff + graph rebuild + story join
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/
```
## License
ISC.
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
everything-claude-code
Complete Claude Code configuration collection - agents, skills, hooks,...
markitdown
MarkItDown-MCP is a lightweight server for converting URIs to Markdown.
cc-switch
All-in-One Assistant for Claude Code, Codex & Gemini CLI across platforms.
servers
Model Context Protocol Servers
servers
Model Context Protocol Servers
Time
A Model Context Protocol server for time and timezone conversions.