@empathyds/mcp-server 0.0.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.
- package/README.md +145 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.js +465 -0
- package/package.json +42 -0
package/README.md
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# @empathyds/mcp-server
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server for Empathy DS - enables AI assistants to discover and use Empathy DS Vue components and blocks.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Component Discovery**: List all 60+ Empathy DS components
|
|
8
|
+
- **Detailed Information**: Get props, variants, and usage examples
|
|
9
|
+
- **Category Filtering**: Browse by Forms, Layout, Feedback, Navigation, etc.
|
|
10
|
+
- **Blocks Support**: Pre-built UI patterns (login forms, dashboards)
|
|
11
|
+
- **Search**: Find components by name or description
|
|
12
|
+
- **Remote Registry**: Fetches data from empathyds.com (works anywhere!)
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Quick Start
|
|
17
|
+
|
|
18
|
+
### With Antigravity
|
|
19
|
+
|
|
20
|
+
Add to `~/.gemini/antigravity/mcp_config.json`:
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"mcpServers": {
|
|
25
|
+
"empathy-ds": {
|
|
26
|
+
"command": "npx",
|
|
27
|
+
"args": ["-y", "@empathyds/mcp-server"]
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## How It Works
|
|
36
|
+
|
|
37
|
+
The MCP server fetches component data from `https://empathyds.com/registry.json`:
|
|
38
|
+
- Works for **anyone** using `npx @empathyds/mcp-server`
|
|
39
|
+
- Falls back to local filesystem for development
|
|
40
|
+
- Caches registry data for 5 minutes
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Available Tools (8 Total)
|
|
45
|
+
|
|
46
|
+
| Tool | Description |
|
|
47
|
+
|------|-------------|
|
|
48
|
+
| `getAllComponents` | Lists all 60+ components |
|
|
49
|
+
| `getComponent` | Gets props, examples for a component |
|
|
50
|
+
| `getComponentsByCategory` | Filter by Forms, Layout, Feedback, etc. |
|
|
51
|
+
| `searchComponents` | Search by name or description |
|
|
52
|
+
| `getCategories` | Lists all 7 categories |
|
|
53
|
+
| `getBlocks` | Lists all pre-built UI patterns |
|
|
54
|
+
| `getBlock` | Gets details for a specific block |
|
|
55
|
+
| `getUsageGuide` | Best practices for Empathy DS |
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Publishing to npm
|
|
60
|
+
|
|
61
|
+
### 1. Generate the Registry
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# From monorepo root
|
|
65
|
+
node scripts/generate-registry.js
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
This creates `apps/docs/public/registry.json` which gets deployed to empathyds.com.
|
|
69
|
+
|
|
70
|
+
### 2. Deploy Docs Site
|
|
71
|
+
|
|
72
|
+
Deploy your docs to make `https://empathyds.com/registry.json` accessible.
|
|
73
|
+
|
|
74
|
+
### 3. Publish MCP Server
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
cd packages/mcp-server
|
|
78
|
+
|
|
79
|
+
# Ensure you're logged in
|
|
80
|
+
npm login
|
|
81
|
+
|
|
82
|
+
# Build
|
|
83
|
+
pnpm build
|
|
84
|
+
|
|
85
|
+
# Publish
|
|
86
|
+
npm publish --access public
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 4. Users Can Now Use It
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
npx @empathyds/mcp-server
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Development
|
|
98
|
+
|
|
99
|
+
### Local Testing
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
cd packages/mcp-server
|
|
103
|
+
pnpm install
|
|
104
|
+
pnpm build
|
|
105
|
+
pnpm inspect # Opens MCP Inspector
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Local Antigravity Config
|
|
109
|
+
|
|
110
|
+
For development, use the local path:
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"mcpServers": {
|
|
115
|
+
"empathy-ds": {
|
|
116
|
+
"command": "node",
|
|
117
|
+
"args": ["/path/to/eds-mono/packages/mcp-server/dist/server.js"],
|
|
118
|
+
"disabled": false
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## When You Add New Components
|
|
127
|
+
|
|
128
|
+
| Step | Action |
|
|
129
|
+
|------|--------|
|
|
130
|
+
| 1. Add component | Create in `packages/empathy-ds/src/components/ui/` |
|
|
131
|
+
| 2. Add docs | Create `apps/docs/components/{name}.md` |
|
|
132
|
+
| 3. Categorize | Update `src/lib/categories.ts` |
|
|
133
|
+
| 4. Regenerate | Run `node scripts/generate-registry.js` |
|
|
134
|
+
| 5. Redeploy | Deploy docs to update registry.json |
|
|
135
|
+
| 6. (Optional) | Publish new MCP server version |
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Example AI Queries
|
|
140
|
+
|
|
141
|
+
- "What components does Empathy DS have?"
|
|
142
|
+
- "Show me the button variants"
|
|
143
|
+
- "Get the Card component props"
|
|
144
|
+
- "What form components are available?"
|
|
145
|
+
- "Show me the login form block"
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/server.ts
|
|
4
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import { z as z2 } from "zod";
|
|
7
|
+
|
|
8
|
+
// src/utils/schemas.ts
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
var ComponentMetadataSchema = z.object({
|
|
11
|
+
name: z.string(),
|
|
12
|
+
description: z.string(),
|
|
13
|
+
category: z.string().optional()
|
|
14
|
+
});
|
|
15
|
+
var ComponentPropSchema = z.object({
|
|
16
|
+
name: z.string(),
|
|
17
|
+
type: z.string(),
|
|
18
|
+
default: z.string().optional(),
|
|
19
|
+
description: z.string().optional()
|
|
20
|
+
});
|
|
21
|
+
var ComponentDetailSchema = z.object({
|
|
22
|
+
name: z.string(),
|
|
23
|
+
description: z.string(),
|
|
24
|
+
category: z.string().optional(),
|
|
25
|
+
import: z.string(),
|
|
26
|
+
props: z.array(ComponentPropSchema),
|
|
27
|
+
source: z.string().optional(),
|
|
28
|
+
indexSource: z.string().optional(),
|
|
29
|
+
examples: z.array(z.string()),
|
|
30
|
+
docsUrl: z.string()
|
|
31
|
+
});
|
|
32
|
+
var CategoryComponentsSchema = z.object({
|
|
33
|
+
category: z.string(),
|
|
34
|
+
components: z.array(ComponentMetadataSchema)
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// src/lib/config.ts
|
|
38
|
+
var mcpConfig = {
|
|
39
|
+
projectName: "empathy-ds",
|
|
40
|
+
packageName: "@empathyds/vue",
|
|
41
|
+
baseUrl: "https://empathyds.com",
|
|
42
|
+
registryUrl: "https://empathyds.com/registry.json"
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// src/utils/formatters.ts
|
|
46
|
+
function generateImportStatement(componentName) {
|
|
47
|
+
const pascalName = componentName.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
48
|
+
return `import { ${pascalName} } from '${mcpConfig.packageName}'`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// src/utils/api.ts
|
|
52
|
+
var registryCache = null;
|
|
53
|
+
var registryCacheTime = 0;
|
|
54
|
+
var CACHE_TTL = 5 * 60 * 1e3;
|
|
55
|
+
async function getRegistry() {
|
|
56
|
+
if (registryCache && Date.now() - registryCacheTime < CACHE_TTL) {
|
|
57
|
+
return registryCache;
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
const response = await fetch(mcpConfig.registryUrl);
|
|
61
|
+
if (!response.ok) {
|
|
62
|
+
throw new Error(`Failed to fetch registry: ${response.statusText}`);
|
|
63
|
+
}
|
|
64
|
+
registryCache = await response.json();
|
|
65
|
+
registryCacheTime = Date.now();
|
|
66
|
+
return registryCache;
|
|
67
|
+
} catch (error) {
|
|
68
|
+
console.error("Error fetching remote registry:", error);
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async function listComponents() {
|
|
73
|
+
const registry = await getRegistry();
|
|
74
|
+
if (!registry) return [];
|
|
75
|
+
return registry.components.map((c) => ({
|
|
76
|
+
name: c.name,
|
|
77
|
+
description: c.description,
|
|
78
|
+
category: c.category || void 0
|
|
79
|
+
}));
|
|
80
|
+
}
|
|
81
|
+
async function getComponentDetail(componentName) {
|
|
82
|
+
const registry = await getRegistry();
|
|
83
|
+
if (!registry) return null;
|
|
84
|
+
const component = registry.components.find((c) => c.name === componentName);
|
|
85
|
+
if (!component) return null;
|
|
86
|
+
return {
|
|
87
|
+
name: component.name,
|
|
88
|
+
description: component.description,
|
|
89
|
+
category: component.category || void 0,
|
|
90
|
+
import: generateImportStatement(componentName),
|
|
91
|
+
props: component.props || [],
|
|
92
|
+
examples: component.examples || [],
|
|
93
|
+
docsUrl: component.docsUrl
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
async function searchComponents(query) {
|
|
97
|
+
const allComponents = await listComponents();
|
|
98
|
+
const lowerQuery = query.toLowerCase();
|
|
99
|
+
return allComponents.filter(
|
|
100
|
+
(c) => c.name.toLowerCase().includes(lowerQuery) || c.description.toLowerCase().includes(lowerQuery)
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
async function getComponentsByCategory(category) {
|
|
104
|
+
const allComponents = await listComponents();
|
|
105
|
+
return allComponents.filter((c) => c.category === category);
|
|
106
|
+
}
|
|
107
|
+
async function listBlocks() {
|
|
108
|
+
const registry = await getRegistry();
|
|
109
|
+
if (!registry) return [];
|
|
110
|
+
return registry.blocks.map((b) => ({
|
|
111
|
+
name: b.name,
|
|
112
|
+
description: b.description,
|
|
113
|
+
category: "Blocks"
|
|
114
|
+
}));
|
|
115
|
+
}
|
|
116
|
+
async function getBlockDetail(blockName) {
|
|
117
|
+
const registry = await getRegistry();
|
|
118
|
+
if (!registry) return null;
|
|
119
|
+
const block = registry.blocks.find((b) => b.name === blockName);
|
|
120
|
+
if (!block) return null;
|
|
121
|
+
return {
|
|
122
|
+
name: block.name,
|
|
123
|
+
description: block.description,
|
|
124
|
+
category: "Blocks",
|
|
125
|
+
import: `// Block: ${block.name} - see documentation`,
|
|
126
|
+
props: [],
|
|
127
|
+
examples: block.examples || [],
|
|
128
|
+
docsUrl: block.docsUrl
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// src/server.ts
|
|
133
|
+
var server = new McpServer({
|
|
134
|
+
name: "empathy-ds-mcp",
|
|
135
|
+
version: "0.0.1"
|
|
136
|
+
});
|
|
137
|
+
server.tool(
|
|
138
|
+
"getAllComponents",
|
|
139
|
+
"Lists all 60+ Empathy DS Vue components with their names, descriptions, and categories. Use this to discover available components.",
|
|
140
|
+
{},
|
|
141
|
+
async () => {
|
|
142
|
+
try {
|
|
143
|
+
const components = await listComponents();
|
|
144
|
+
return {
|
|
145
|
+
content: [
|
|
146
|
+
{
|
|
147
|
+
type: "text",
|
|
148
|
+
text: JSON.stringify({
|
|
149
|
+
totalComponents: components.length,
|
|
150
|
+
packageName: mcpConfig.packageName,
|
|
151
|
+
docsUrl: mcpConfig.baseUrl,
|
|
152
|
+
components
|
|
153
|
+
}, null, 2)
|
|
154
|
+
}
|
|
155
|
+
]
|
|
156
|
+
};
|
|
157
|
+
} catch (error) {
|
|
158
|
+
return {
|
|
159
|
+
content: [
|
|
160
|
+
{
|
|
161
|
+
type: "text",
|
|
162
|
+
text: `Error listing components: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
163
|
+
}
|
|
164
|
+
],
|
|
165
|
+
isError: true
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
);
|
|
170
|
+
server.tool(
|
|
171
|
+
"getComponent",
|
|
172
|
+
"Gets detailed information about a specific Empathy DS component including source code, props, variants, and usage examples. Use this when you need implementation details for a component.",
|
|
173
|
+
{
|
|
174
|
+
componentName: z2.string().describe(
|
|
175
|
+
"The kebab-case name of the component (e.g., 'button', 'alert-dialog', 'dropdown-menu')"
|
|
176
|
+
)
|
|
177
|
+
},
|
|
178
|
+
async ({ componentName }) => {
|
|
179
|
+
try {
|
|
180
|
+
const component = await getComponentDetail(componentName);
|
|
181
|
+
if (!component) {
|
|
182
|
+
return {
|
|
183
|
+
content: [
|
|
184
|
+
{
|
|
185
|
+
type: "text",
|
|
186
|
+
text: `Component "${componentName}" not found. Use getAllComponents to see available components.`
|
|
187
|
+
}
|
|
188
|
+
],
|
|
189
|
+
isError: true
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
content: [
|
|
194
|
+
{
|
|
195
|
+
type: "text",
|
|
196
|
+
text: JSON.stringify(component, null, 2)
|
|
197
|
+
}
|
|
198
|
+
]
|
|
199
|
+
};
|
|
200
|
+
} catch (error) {
|
|
201
|
+
return {
|
|
202
|
+
content: [
|
|
203
|
+
{
|
|
204
|
+
type: "text",
|
|
205
|
+
text: `Error fetching component "${componentName}": ${error instanceof Error ? error.message : "Unknown error"}`
|
|
206
|
+
}
|
|
207
|
+
],
|
|
208
|
+
isError: true
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
);
|
|
213
|
+
server.tool(
|
|
214
|
+
"getComponentsByCategory",
|
|
215
|
+
"Gets all Empathy DS components in a specific category. Categories: Forms, Layout, Feedback, Navigation, DataDisplay, Overlays, Actions.",
|
|
216
|
+
{
|
|
217
|
+
category: z2.enum([
|
|
218
|
+
"Forms",
|
|
219
|
+
"Layout",
|
|
220
|
+
"Feedback",
|
|
221
|
+
"Navigation",
|
|
222
|
+
"DataDisplay",
|
|
223
|
+
"Overlays",
|
|
224
|
+
"Actions"
|
|
225
|
+
]).describe("The category to filter by")
|
|
226
|
+
},
|
|
227
|
+
async ({ category }) => {
|
|
228
|
+
try {
|
|
229
|
+
const components = await getComponentsByCategory(category);
|
|
230
|
+
return {
|
|
231
|
+
content: [
|
|
232
|
+
{
|
|
233
|
+
type: "text",
|
|
234
|
+
text: JSON.stringify({
|
|
235
|
+
category,
|
|
236
|
+
totalComponents: components.length,
|
|
237
|
+
components
|
|
238
|
+
}, null, 2)
|
|
239
|
+
}
|
|
240
|
+
]
|
|
241
|
+
};
|
|
242
|
+
} catch (error) {
|
|
243
|
+
return {
|
|
244
|
+
content: [
|
|
245
|
+
{
|
|
246
|
+
type: "text",
|
|
247
|
+
text: `Error fetching category "${category}": ${error instanceof Error ? error.message : "Unknown error"}`
|
|
248
|
+
}
|
|
249
|
+
],
|
|
250
|
+
isError: true
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
);
|
|
255
|
+
server.tool(
|
|
256
|
+
"searchComponents",
|
|
257
|
+
"Searches Empathy DS components by name or description. Use this to find components for a specific use case.",
|
|
258
|
+
{
|
|
259
|
+
query: z2.string().describe(
|
|
260
|
+
"The search query (e.g., 'button', 'form', 'dialog', 'navigation')"
|
|
261
|
+
)
|
|
262
|
+
},
|
|
263
|
+
async ({ query }) => {
|
|
264
|
+
try {
|
|
265
|
+
const results = await searchComponents(query);
|
|
266
|
+
return {
|
|
267
|
+
content: [
|
|
268
|
+
{
|
|
269
|
+
type: "text",
|
|
270
|
+
text: JSON.stringify({
|
|
271
|
+
query,
|
|
272
|
+
totalResults: results.length,
|
|
273
|
+
results,
|
|
274
|
+
tip: "Use getComponent with a component name to get full details including source code and examples."
|
|
275
|
+
}, null, 2)
|
|
276
|
+
}
|
|
277
|
+
]
|
|
278
|
+
};
|
|
279
|
+
} catch (error) {
|
|
280
|
+
return {
|
|
281
|
+
content: [
|
|
282
|
+
{
|
|
283
|
+
type: "text",
|
|
284
|
+
text: `Error searching components: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
285
|
+
}
|
|
286
|
+
],
|
|
287
|
+
isError: true
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
);
|
|
292
|
+
server.tool(
|
|
293
|
+
"getCategories",
|
|
294
|
+
"Lists all component categories in Empathy DS with their component counts. Use this to understand how components are organized.",
|
|
295
|
+
{},
|
|
296
|
+
async () => {
|
|
297
|
+
try {
|
|
298
|
+
const components = await listComponents();
|
|
299
|
+
const categoriesMap = /* @__PURE__ */ new Map();
|
|
300
|
+
components.forEach((c) => {
|
|
301
|
+
if (c.category) {
|
|
302
|
+
categoriesMap.set(c.category, (categoriesMap.get(c.category) || 0) + 1);
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
const categories = Array.from(categoriesMap.entries()).map(([name, count]) => ({
|
|
306
|
+
name,
|
|
307
|
+
componentCount: count
|
|
308
|
+
}));
|
|
309
|
+
return {
|
|
310
|
+
content: [
|
|
311
|
+
{
|
|
312
|
+
type: "text",
|
|
313
|
+
text: JSON.stringify({
|
|
314
|
+
totalCategories: categories.length,
|
|
315
|
+
categories
|
|
316
|
+
}, null, 2)
|
|
317
|
+
}
|
|
318
|
+
]
|
|
319
|
+
};
|
|
320
|
+
} catch (error) {
|
|
321
|
+
return {
|
|
322
|
+
content: [
|
|
323
|
+
{
|
|
324
|
+
type: "text",
|
|
325
|
+
text: `Error fetching categories: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
326
|
+
}
|
|
327
|
+
],
|
|
328
|
+
isError: true
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
);
|
|
333
|
+
server.tool(
|
|
334
|
+
"getBlocks",
|
|
335
|
+
"Lists all Empathy DS blocks (pre-built UI patterns like login forms, dashboards). Use blocks for complex, commonly-used UI patterns.",
|
|
336
|
+
{},
|
|
337
|
+
async () => {
|
|
338
|
+
try {
|
|
339
|
+
const blocks = await listBlocks();
|
|
340
|
+
return {
|
|
341
|
+
content: [
|
|
342
|
+
{
|
|
343
|
+
type: "text",
|
|
344
|
+
text: JSON.stringify({
|
|
345
|
+
totalBlocks: blocks.length,
|
|
346
|
+
docsUrl: `${mcpConfig.baseUrl}/blocks`,
|
|
347
|
+
blocks
|
|
348
|
+
}, null, 2)
|
|
349
|
+
}
|
|
350
|
+
]
|
|
351
|
+
};
|
|
352
|
+
} catch (error) {
|
|
353
|
+
return {
|
|
354
|
+
content: [
|
|
355
|
+
{
|
|
356
|
+
type: "text",
|
|
357
|
+
text: `Error listing blocks: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
358
|
+
}
|
|
359
|
+
],
|
|
360
|
+
isError: true
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
);
|
|
365
|
+
server.tool(
|
|
366
|
+
"getBlock",
|
|
367
|
+
"Gets detailed information about a specific Empathy DS block including code examples. Use this for implementation details of a block pattern.",
|
|
368
|
+
{
|
|
369
|
+
blockName: z2.string().describe(
|
|
370
|
+
"The kebab-case name of the block (e.g., 'login-form')"
|
|
371
|
+
)
|
|
372
|
+
},
|
|
373
|
+
async ({ blockName }) => {
|
|
374
|
+
try {
|
|
375
|
+
const block = await getBlockDetail(blockName);
|
|
376
|
+
if (!block) {
|
|
377
|
+
return {
|
|
378
|
+
content: [
|
|
379
|
+
{
|
|
380
|
+
type: "text",
|
|
381
|
+
text: `Block "${blockName}" not found. Use getBlocks to see available blocks.`
|
|
382
|
+
}
|
|
383
|
+
],
|
|
384
|
+
isError: true
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
return {
|
|
388
|
+
content: [
|
|
389
|
+
{
|
|
390
|
+
type: "text",
|
|
391
|
+
text: JSON.stringify(block, null, 2)
|
|
392
|
+
}
|
|
393
|
+
]
|
|
394
|
+
};
|
|
395
|
+
} catch (error) {
|
|
396
|
+
return {
|
|
397
|
+
content: [
|
|
398
|
+
{
|
|
399
|
+
type: "text",
|
|
400
|
+
text: `Error fetching block "${blockName}": ${error instanceof Error ? error.message : "Unknown error"}`
|
|
401
|
+
}
|
|
402
|
+
],
|
|
403
|
+
isError: true
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
);
|
|
408
|
+
server.tool(
|
|
409
|
+
"getUsageGuide",
|
|
410
|
+
"Returns the Empathy DS usage guide for AI assistants, including import patterns, styling rules, and best practices.",
|
|
411
|
+
{},
|
|
412
|
+
async () => {
|
|
413
|
+
const guide = `# Empathy DS Usage Guide
|
|
414
|
+
|
|
415
|
+
## Import Pattern
|
|
416
|
+
Import components from \`${mcpConfig.packageName}\`:
|
|
417
|
+
\`\`\`ts
|
|
418
|
+
import { Button, Card, Input } from '${mcpConfig.packageName}'
|
|
419
|
+
\`\`\`
|
|
420
|
+
|
|
421
|
+
## Styling
|
|
422
|
+
1. Import the stylesheet in your main entry file:
|
|
423
|
+
\`\`\`ts
|
|
424
|
+
import '${mcpConfig.packageName}/style.css'
|
|
425
|
+
\`\`\`
|
|
426
|
+
|
|
427
|
+
2. Use standard Tailwind utility classes for layout: \`flex\`, \`p-4\`, \`gap-2\`
|
|
428
|
+
|
|
429
|
+
3. Use design tokens for colors - DO NOT hardcode colors:
|
|
430
|
+
- \`bg-primary\`, \`text-primary-foreground\`
|
|
431
|
+
- \`bg-secondary\`, \`text-secondary-foreground\`
|
|
432
|
+
- \`bg-muted\`, \`text-muted-foreground\`
|
|
433
|
+
- \`bg-destructive\`, \`text-destructive-foreground\`
|
|
434
|
+
- \`bg-accent\`, \`text-accent-foreground\`
|
|
435
|
+
|
|
436
|
+
## Component Best Practices
|
|
437
|
+
1. Always prefer Empathy DS components over building from scratch
|
|
438
|
+
2. Use the \`variant\` prop to control visual style
|
|
439
|
+
3. Use the \`size\` prop to control component size
|
|
440
|
+
4. Check component documentation for all available props
|
|
441
|
+
|
|
442
|
+
## Documentation
|
|
443
|
+
Full documentation: ${mcpConfig.baseUrl}
|
|
444
|
+
`;
|
|
445
|
+
return {
|
|
446
|
+
content: [
|
|
447
|
+
{
|
|
448
|
+
type: "text",
|
|
449
|
+
text: guide
|
|
450
|
+
}
|
|
451
|
+
]
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
);
|
|
455
|
+
async function startServer() {
|
|
456
|
+
try {
|
|
457
|
+
const transport = new StdioServerTransport();
|
|
458
|
+
await server.connect(transport);
|
|
459
|
+
console.error("\u2705 Empathy DS MCP server started successfully");
|
|
460
|
+
} catch (error) {
|
|
461
|
+
console.error("\u274C Error starting MCP server:", error);
|
|
462
|
+
process.exit(1);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
startServer();
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@empathyds/mcp-server",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "MCP server for Empathy DS - enables AI assistants to discover and use Empathy DS components",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/server.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"empathy-ds-mcp": "./dist/server.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsup src/server.ts --format esm --dts --out-dir dist --clean",
|
|
15
|
+
"dev": "tsx watch src/server.ts",
|
|
16
|
+
"inspect": "npx -y @modelcontextprotocol/inspector node dist/server.js",
|
|
17
|
+
"start": "node dist/server.js"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@modelcontextprotocol/sdk": "^1.13.1",
|
|
21
|
+
"zod": "^3.25.67"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/node": "^22.14.1",
|
|
25
|
+
"tsup": "^8.5.0",
|
|
26
|
+
"tsx": "^4.20.3",
|
|
27
|
+
"typescript": "^5.8.3"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"mcp",
|
|
31
|
+
"model-context-protocol",
|
|
32
|
+
"empathy-ds",
|
|
33
|
+
"vue",
|
|
34
|
+
"ai",
|
|
35
|
+
"llm"
|
|
36
|
+
],
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "https://bitbucket.org/underlings/eui-mono"
|
|
41
|
+
}
|
|
42
|
+
}
|