@epilot/volt-ui-mcp 0.1.0 → 0.1.1

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 (4) hide show
  1. package/README.md +169 -7
  2. package/index.js +106 -38
  3. package/package.json +1 -1
  4. package/registry.json +14688 -30
package/README.md CHANGED
@@ -1,24 +1,186 @@
1
1
  # Volt UI MCP Server
2
2
 
3
- Runs a local MCP server that exposes Volt UI components, props, and examples.
3
+ An MCP (Model Context Protocol) server that exposes Volt UI components, props, documentation, and design tokens to AI assistants.
4
4
 
5
- ## Usage
5
+ ## Features
6
+
7
+ - **Component Discovery**: List and search all Volt UI components
8
+ - **Props & Documentation**: Get detailed component props, descriptions, and usage examples
9
+ - **Design Tokens**: Access CSS variables, semantic colors, and theming information
10
+ - **Theme Support**: Light and dark theme token values
11
+
12
+ ## Available Tools
13
+
14
+ | Tool | Description |
15
+ |------|-------------|
16
+ | `list_components` | List all available Volt UI components |
17
+ | `get_component` | Get detailed information about a specific component |
18
+ | `search_components` | Search components by name, description, or props |
19
+ | `list_tokens` | List design tokens with optional filtering |
20
+ | `get_token` | Get details for a specific design token |
21
+ | `search_tokens` | Search tokens by name or value |
22
+
23
+ ## Setup Instructions
24
+
25
+ ### Claude Desktop
26
+
27
+ Add the following to your Claude Desktop configuration file:
28
+
29
+ **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
30
+ **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
31
+
32
+ ```json
33
+ {
34
+ "mcpServers": {
35
+ "volt-ui": {
36
+ "command": "npx",
37
+ "args": ["-y", "@epilot/volt-ui-mcp"]
38
+ }
39
+ }
40
+ }
41
+ ```
42
+
43
+ ### Claude Code (VS Code Extension)
44
+
45
+ Add to your VS Code settings or project's `.vscode/mcp.json`:
46
+
47
+ ```json
48
+ {
49
+ "mcpServers": {
50
+ "volt-ui": {
51
+ "command": "npx",
52
+ "args": ["-y", "@epilot/volt-ui-mcp"]
53
+ }
54
+ }
55
+ }
56
+ ```
57
+
58
+ Or add to `~/.claude/settings.json` for global access:
59
+
60
+ ```json
61
+ {
62
+ "mcpServers": {
63
+ "volt-ui": {
64
+ "command": "npx",
65
+ "args": ["-y", "@epilot/volt-ui-mcp"]
66
+ }
67
+ }
68
+ }
69
+ ```
70
+
71
+ ### Cursor
72
+
73
+ Add to your Cursor MCP configuration (`.cursor/mcp.json` in your project or global settings):
6
74
 
7
75
  ```json
8
76
  {
9
77
  "mcpServers": {
10
- "volt-ui-mcp": {
78
+ "volt-ui": {
11
79
  "command": "npx",
12
- "args": ["-y", "volt-ui-mcp"]
80
+ "args": ["-y", "@epilot/volt-ui-mcp"]
13
81
  }
14
82
  }
15
83
  }
16
84
  ```
17
85
 
18
- ## Build the registry
86
+ ### Windsurf
19
87
 
20
- Run this from the repo root before publishing:
88
+ Add to your Windsurf MCP configuration:
21
89
 
22
- ```sh
90
+ ```json
91
+ {
92
+ "mcpServers": {
93
+ "volt-ui": {
94
+ "command": "npx",
95
+ "args": ["-y", "@epilot/volt-ui-mcp"]
96
+ }
97
+ }
98
+ }
99
+ ```
100
+
101
+ ### GitHub Copilot (VS Code)
102
+
103
+ Add to your VS Code `settings.json`:
104
+
105
+ ```json
106
+ {
107
+ "github.copilot.chat.mcpServers": {
108
+ "volt-ui": {
109
+ "command": "npx",
110
+ "args": ["-y", "@epilot/volt-ui-mcp"]
111
+ }
112
+ }
113
+ }
114
+ ```
115
+
116
+ ### Local Development (Testing)
117
+
118
+ For testing during development, point to the local path:
119
+
120
+ ```json
121
+ {
122
+ "mcpServers": {
123
+ "volt-ui": {
124
+ "command": "node",
125
+ "args": ["/path/to/volt-ui/tools/volt-ui-mcp/index.js"]
126
+ }
127
+ }
128
+ }
129
+ ```
130
+
131
+ ## Usage Examples
132
+
133
+ Once configured, you can ask your AI assistant questions like:
134
+
135
+ - "What props does the Button component accept?"
136
+ - "Show me how to use the Dialog component"
137
+ - "What are the available color tokens in Volt UI?"
138
+ - "How do I set up dark mode?"
139
+ - "Search for components with loading states"
140
+
141
+ ## For Maintainers
142
+
143
+ ### Building the Registry
144
+
145
+ The registry is automatically built during `npm publish` via the `prepack` script. To manually rebuild:
146
+
147
+ ```bash
148
+ # From the volt-ui repo root
23
149
  bun run build:mcp
24
150
  ```
151
+
152
+ This parses:
153
+ - Component exports from `src/index.ts`
154
+ - Documentation from `docs/content/docs/components/*.mdx`
155
+ - Design tokens from `src/styles/*.css`
156
+
157
+ ### Publishing
158
+
159
+ ```bash
160
+ cd tools/volt-ui-mcp
161
+ npm publish
162
+ ```
163
+
164
+ The `prepack` script automatically runs `build:mcp` to ensure the registry is up-to-date.
165
+
166
+ ### Versioning
167
+
168
+ Update the version in `package.json` before publishing:
169
+
170
+ ```bash
171
+ cd tools/volt-ui-mcp
172
+ npm version patch # or minor, major
173
+ npm publish
174
+ ```
175
+
176
+ ## Resources
177
+
178
+ The server also exposes MCP resources:
179
+
180
+ | URI | Description |
181
+ |-----|-------------|
182
+ | `volt-ui://components` | List of all components |
183
+ | `volt-ui://tokens` | List of all design tokens |
184
+ | `volt-ui://components/{name}` | Specific component details |
185
+ | `volt-ui://tokens/{name}` | Specific token details |
186
+
package/index.js CHANGED
@@ -37,9 +37,9 @@ server.setRequestHandler(ListResourcesRequestSchema, async () => {
37
37
  mimeType: "application/json",
38
38
  },
39
39
  {
40
- uri: "volt-ui://blocks",
41
- name: "Volt UI Blocks",
42
- description: "List of all available Volt UI blocks/examples.",
40
+ uri: "volt-ui://tokens",
41
+ name: "Volt UI Tokens",
42
+ description: "List of Volt UI design tokens.",
43
43
  mimeType: "application/json",
44
44
  },
45
45
  ]
@@ -51,15 +51,18 @@ server.setRequestHandler(ListResourcesRequestSchema, async () => {
51
51
  mimeType: "application/json",
52
52
  }))
53
53
 
54
- const blockResources = registry.blocks.map((block) => ({
55
- uri: `volt-ui://blocks/${encodeURIComponent(block.name)}`,
56
- name: block.title,
57
- description: block.name,
54
+ const tokenNames = Array.from(
55
+ new Set((registry.tokens || []).map((token) => token.name))
56
+ ).sort((a, b) => a.localeCompare(b))
57
+ const tokenResources = tokenNames.map((name) => ({
58
+ uri: `volt-ui://tokens/${encodeURIComponent(name)}`,
59
+ name,
60
+ description: "Design token",
58
61
  mimeType: "application/json",
59
62
  }))
60
63
 
61
64
  return {
62
- resources: [...baseResources, ...componentResources, ...blockResources],
65
+ resources: [...baseResources, ...componentResources, ...tokenResources],
63
66
  }
64
67
  })
65
68
 
@@ -126,29 +129,57 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
126
129
  },
127
130
  },
128
131
  {
129
- name: "list_blocks",
130
- description: "List available Volt UI blocks/examples.",
132
+ name: "list_tokens",
133
+ description: "List Volt UI design tokens.",
131
134
  inputSchema: {
132
135
  type: "object",
133
- properties: {},
136
+ properties: {
137
+ query: {
138
+ type: "string",
139
+ description: "Optional text filter for token name or value.",
140
+ },
141
+ theme: {
142
+ type: "string",
143
+ description: "Optional theme filter (light, dark, global).",
144
+ },
145
+ group: {
146
+ type: "string",
147
+ description: "Optional group filter (palette, semantic, utility).",
148
+ },
149
+ },
134
150
  additionalProperties: false,
135
151
  },
136
152
  },
137
153
  {
138
- name: "get_block",
139
- description: "Get a specific Volt UI block/example.",
154
+ name: "get_token",
155
+ description: "Get details for a specific Volt UI token.",
140
156
  inputSchema: {
141
157
  type: "object",
142
158
  properties: {
143
159
  name: {
144
160
  type: "string",
145
- description: "Block name (e.g. card-example).",
161
+ description: "Token name (e.g. --volt-blue-9).",
146
162
  },
147
163
  },
148
164
  required: ["name"],
149
165
  additionalProperties: false,
150
166
  },
151
167
  },
168
+ {
169
+ name: "search_tokens",
170
+ description: "Search tokens by name or value.",
171
+ inputSchema: {
172
+ type: "object",
173
+ properties: {
174
+ query: {
175
+ type: "string",
176
+ description: "Search term.",
177
+ },
178
+ },
179
+ required: ["query"],
180
+ additionalProperties: false,
181
+ },
182
+ },
152
183
  ],
153
184
  }
154
185
  })
@@ -169,12 +200,19 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
169
200
  const query = typeof args?.query === "string" ? args.query : ""
170
201
  return toolResult(searchComponents(query))
171
202
  }
172
- case "list_blocks": {
173
- return toolResult(listBlocks())
203
+ case "list_tokens": {
204
+ const query = typeof args?.query === "string" ? args.query : ""
205
+ const theme = typeof args?.theme === "string" ? args.theme : ""
206
+ const group = typeof args?.group === "string" ? args.group : ""
207
+ return toolResult(listTokens({ query, theme, group }))
208
+ }
209
+ case "get_token": {
210
+ const tokenName = typeof args?.name === "string" ? args.name : ""
211
+ return toolResult(getToken(tokenName))
174
212
  }
175
- case "get_block": {
176
- const blockName = typeof args?.name === "string" ? args.name : ""
177
- return toolResult(getBlock(blockName))
213
+ case "search_tokens": {
214
+ const query = typeof args?.query === "string" ? args.query : ""
215
+ return toolResult(searchTokens(query))
178
216
  }
179
217
  default:
180
218
  return toolResult({ error: `Unknown tool: ${name}` })
@@ -192,7 +230,7 @@ function loadRegistry(filePath) {
192
230
  return {
193
231
  schemaVersion: 1,
194
232
  components: [],
195
- blocks: [],
233
+ tokens: [],
196
234
  error: String(error),
197
235
  }
198
236
  }
@@ -202,16 +240,16 @@ function resolveResource(uri) {
202
240
  if (uri === "volt-ui://components") {
203
241
  return listComponents("")
204
242
  }
205
- if (uri === "volt-ui://blocks") {
206
- return listBlocks()
243
+ if (uri === "volt-ui://tokens") {
244
+ return listTokens({})
207
245
  }
208
246
  if (uri.startsWith("volt-ui://components/")) {
209
247
  const name = decodeURIComponent(uri.replace("volt-ui://components/", ""))
210
248
  return getComponent(name)
211
249
  }
212
- if (uri.startsWith("volt-ui://blocks/")) {
213
- const name = decodeURIComponent(uri.replace("volt-ui://blocks/", ""))
214
- return getBlock(name)
250
+ if (uri.startsWith("volt-ui://tokens/")) {
251
+ const name = decodeURIComponent(uri.replace("volt-ui://tokens/", ""))
252
+ return getToken(name)
215
253
  }
216
254
  return { error: `Unknown resource: ${uri}` }
217
255
  }
@@ -277,25 +315,55 @@ function searchComponents(query) {
277
315
  }
278
316
  }
279
317
 
280
- function listBlocks() {
318
+ function listTokens({ query = "", theme = "", group = "" }) {
319
+ const q = query.trim().toLowerCase()
320
+ const t = theme.trim().toLowerCase()
321
+ const g = group.trim().toLowerCase()
322
+ const tokens = (registry.tokens || []).filter((token) => {
323
+ if (t && token.theme.toLowerCase() !== t) {
324
+ return false
325
+ }
326
+ if (g && token.group.toLowerCase() !== g) {
327
+ return false
328
+ }
329
+ if (!q) {
330
+ return true
331
+ }
332
+ return (
333
+ token.name.toLowerCase().includes(q) ||
334
+ token.value.toLowerCase().includes(q)
335
+ )
336
+ })
337
+
281
338
  return {
282
- count: registry.blocks.length,
283
- blocks: registry.blocks.map((block) => ({
284
- name: block.name,
285
- title: block.title,
286
- sourcePath: block.sourcePath,
287
- })),
339
+ count: tokens.length,
340
+ tokens,
288
341
  }
289
342
  }
290
343
 
291
- function getBlock(name) {
292
- const block = registry.blocks.find(
293
- (entry) => entry.name.toLowerCase() === name.toLowerCase()
344
+ function getToken(name) {
345
+ const target = name.trim().toLowerCase()
346
+ if (!target) {
347
+ return { error: "Token name is required." }
348
+ }
349
+ const tokens = (registry.tokens || []).filter(
350
+ (token) => token.name.toLowerCase() === target
294
351
  )
295
- if (!block) {
296
- return { error: `Block not found: ${name}` }
352
+ if (tokens.length === 0) {
353
+ return { error: `Token not found: ${name}` }
354
+ }
355
+ return {
356
+ name,
357
+ tokens,
358
+ }
359
+ }
360
+
361
+ function searchTokens(query) {
362
+ const q = query.trim().toLowerCase()
363
+ if (!q) {
364
+ return { count: 0, tokens: [] }
297
365
  }
298
- return block
366
+ return listTokens({ query: q })
299
367
  }
300
368
 
301
369
  function findComponent(name) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@epilot/volt-ui-mcp",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {