@amedia/brick-mcp 0.0.2 → 0.1.0
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/data/components-metadata.json +28 -28
- package/data/tokens-documentation.json +1 -1
- package/data/tokens.json +4848 -128
- package/dist/data/components/brick-actions.md +59 -0
- package/dist/data/components/brick-alt-teaser.md +264 -0
- package/dist/data/components/brick-avatar.md +299 -0
- package/dist/data/components/brick-button.md +373 -0
- package/dist/data/components/brick-card.md +359 -0
- package/dist/data/components/brick-carousel.md +355 -0
- package/dist/data/components/brick-classnames.md +147 -0
- package/dist/data/components/brick-countdown.md +180 -0
- package/dist/data/components/brick-dialog.md +458 -0
- package/dist/data/components/brick-fonts.md +389 -0
- package/dist/data/components/brick-helloworld.md +228 -0
- package/dist/data/components/brick-icon.md +274 -0
- package/dist/data/components/brick-icons.md +570 -0
- package/dist/data/components/brick-illustrations.md +604 -0
- package/dist/data/components/brick-image.md +361 -0
- package/dist/data/components/brick-input.md +557 -0
- package/dist/data/components/brick-mcp.json +6 -0
- package/dist/data/components/brick-nifs.md +164 -0
- package/dist/data/components/brick-pill.json +6 -0
- package/dist/data/components/brick-player.json +7 -0
- package/dist/data/components/brick-published.json +7 -0
- package/dist/data/components/brick-share.json +7 -0
- package/dist/data/components/brick-stepper.json +7 -0
- package/dist/data/components/brick-tab.json +7 -0
- package/dist/data/components/brick-tabs.json +9 -0
- package/dist/data/components/brick-tag.json +7 -0
- package/dist/data/components/brick-teaser-player.json +9 -0
- package/dist/data/components/brick-teaser-reels.json +9 -0
- package/dist/data/components/brick-teaser.json +9 -0
- package/dist/data/components/brick-template.json +9 -0
- package/dist/data/components/brick-textarea.json +7 -0
- package/dist/data/components/brick-themes.json +6 -0
- package/dist/data/components/brick-toast.json +9 -0
- package/dist/data/components/brick-toggle.json +7 -0
- package/dist/data/components/brick-tokens.json +8 -0
- package/dist/data/components/brick-tooltip.json +7 -0
- package/dist/data/components-metadata.json +228 -0
- package/dist/data/tokens-documentation.json +7 -0
- package/dist/data/tokens.json +4976 -0
- package/dist/http.js +314 -0
- package/dist/http.js.map +7 -0
- package/dist/index.js +26 -37
- package/dist/index.js.map +2 -2
- package/package.json +1 -1
- package/scripts/generate-data.js +15 -47
package/dist/http.js
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
// src/http.ts
|
|
2
|
+
import cors from "@fastify/cors";
|
|
3
|
+
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
4
|
+
import Fastify from "fastify";
|
|
5
|
+
|
|
6
|
+
// src/server.ts
|
|
7
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
|
|
10
|
+
// src/tools/getComponentDocs.ts
|
|
11
|
+
import { readFile as readFile2 } from "node:fs/promises";
|
|
12
|
+
import { join as join3 } from "node:path";
|
|
13
|
+
|
|
14
|
+
// src/utils/dataPath.ts
|
|
15
|
+
import { accessSync } from "node:fs";
|
|
16
|
+
import { dirname, join } from "node:path";
|
|
17
|
+
import { fileURLToPath } from "node:url";
|
|
18
|
+
function getDataPath() {
|
|
19
|
+
const currentFilePath = fileURLToPath(import.meta.url);
|
|
20
|
+
let dir = dirname(currentFilePath);
|
|
21
|
+
const localDataPath = join(dir, "data");
|
|
22
|
+
try {
|
|
23
|
+
accessSync(localDataPath);
|
|
24
|
+
return localDataPath;
|
|
25
|
+
} catch {
|
|
26
|
+
}
|
|
27
|
+
for (let i = 0; i < 5; i++) {
|
|
28
|
+
try {
|
|
29
|
+
const testPath = join(dir, "package.json");
|
|
30
|
+
accessSync(testPath);
|
|
31
|
+
return join(dir, "data");
|
|
32
|
+
} catch {
|
|
33
|
+
const parent = dirname(dir);
|
|
34
|
+
if (parent === dir)
|
|
35
|
+
break;
|
|
36
|
+
dir = parent;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return join(dirname(currentFilePath), "..", "..", "data");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// src/extractors/packageScanner.ts
|
|
43
|
+
import { readFile } from "node:fs/promises";
|
|
44
|
+
import { join as join2 } from "node:path";
|
|
45
|
+
async function scanAllPackages() {
|
|
46
|
+
try {
|
|
47
|
+
const metadataPath = join2(getDataPath(), "components-metadata.json");
|
|
48
|
+
const content = await readFile(metadataPath, "utf-8");
|
|
49
|
+
const metadata = JSON.parse(content);
|
|
50
|
+
return metadata;
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.error("Error loading component metadata:", error);
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async function loadComponentData(componentName) {
|
|
57
|
+
try {
|
|
58
|
+
const componentPath = join2(
|
|
59
|
+
getDataPath(),
|
|
60
|
+
"components",
|
|
61
|
+
`${componentName}.json`
|
|
62
|
+
);
|
|
63
|
+
const content = await readFile(componentPath, "utf-8");
|
|
64
|
+
const component = JSON.parse(content);
|
|
65
|
+
return component;
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error(`Error loading component data for ${componentName}:`, error);
|
|
68
|
+
return void 0;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function filterComponents(components, filter) {
|
|
72
|
+
if (!filter) {
|
|
73
|
+
return components;
|
|
74
|
+
}
|
|
75
|
+
const filterLower = filter.toLowerCase();
|
|
76
|
+
return components.filter((component) => {
|
|
77
|
+
if (component.name.toLowerCase().includes(filterLower)) {
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
if (component.category?.toLowerCase().includes(filterLower)) {
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
if (component.tags?.some((tag) => tag.toLowerCase().includes(filterLower))) {
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// src/tools/getComponentDocs.ts
|
|
91
|
+
async function loadComponentMarkdown(componentName) {
|
|
92
|
+
try {
|
|
93
|
+
const markdownPath = join3(
|
|
94
|
+
getDataPath(),
|
|
95
|
+
"components",
|
|
96
|
+
`${componentName}.md`
|
|
97
|
+
);
|
|
98
|
+
const content = await readFile2(markdownPath, "utf-8");
|
|
99
|
+
return content;
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.error(`Error loading markdown for ${componentName}:`, error);
|
|
102
|
+
return void 0;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async function getComponentDocs(input) {
|
|
106
|
+
const docsPromises = input.components.map(async (componentName) => {
|
|
107
|
+
const md = await loadComponentMarkdown(componentName);
|
|
108
|
+
if (!md) {
|
|
109
|
+
const json = await loadComponentData(componentName);
|
|
110
|
+
return json ? JSON.stringify(json) : void 0;
|
|
111
|
+
}
|
|
112
|
+
return md;
|
|
113
|
+
});
|
|
114
|
+
const docsResults = await Promise.all(docsPromises);
|
|
115
|
+
const docs = docsResults.filter((doc) => doc !== void 0);
|
|
116
|
+
return { docs };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// src/tools/getDesignTokens.ts
|
|
120
|
+
import { readFile as readFile3 } from "node:fs/promises";
|
|
121
|
+
import { join as join4 } from "node:path";
|
|
122
|
+
function getTokensDataPath() {
|
|
123
|
+
return join4(getDataPath(), "tokens.json");
|
|
124
|
+
}
|
|
125
|
+
function getDocumentationDataPath() {
|
|
126
|
+
return join4(getDataPath(), "tokens-documentation.json");
|
|
127
|
+
}
|
|
128
|
+
async function loadAllTokens() {
|
|
129
|
+
try {
|
|
130
|
+
const dataPath = getTokensDataPath();
|
|
131
|
+
const content = await readFile3(dataPath, "utf-8");
|
|
132
|
+
return JSON.parse(content);
|
|
133
|
+
} catch (error) {
|
|
134
|
+
console.error("Error loading tokens data:", error);
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
async function loadDocumentation() {
|
|
139
|
+
try {
|
|
140
|
+
const dataPath = getDocumentationDataPath();
|
|
141
|
+
const content = await readFile3(dataPath, "utf-8");
|
|
142
|
+
return JSON.parse(content);
|
|
143
|
+
} catch (error) {
|
|
144
|
+
console.error("Error loading documentation data:", error);
|
|
145
|
+
return {};
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
async function getDesignTokens(input) {
|
|
149
|
+
const allTokens = await loadAllTokens();
|
|
150
|
+
const documentation = await loadDocumentation();
|
|
151
|
+
let filteredTokens = allTokens;
|
|
152
|
+
if (input.category) {
|
|
153
|
+
filteredTokens = filteredTokens.filter((token) => {
|
|
154
|
+
const path = token.path.toLowerCase();
|
|
155
|
+
switch (input.category) {
|
|
156
|
+
case "colors":
|
|
157
|
+
return path.startsWith("color.");
|
|
158
|
+
case "spacing":
|
|
159
|
+
return path.startsWith("spacing.");
|
|
160
|
+
case "typography":
|
|
161
|
+
return path.startsWith("typography.");
|
|
162
|
+
case "shadows":
|
|
163
|
+
return path.startsWith("box-shadow.");
|
|
164
|
+
case "borders":
|
|
165
|
+
return path.startsWith("border-width.") || path.startsWith("border-radius.") || path.startsWith("border.");
|
|
166
|
+
default:
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
tokens: filteredTokens,
|
|
173
|
+
documentation,
|
|
174
|
+
note: 'The "value" field shows example values from one theme. Actual values vary across different themes (alfa, bravo, charlie, nettavisen, alt). Use the "cssVariable" field for theme-aware styling.'
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// src/tools/listComponents.ts
|
|
179
|
+
async function listComponents(input) {
|
|
180
|
+
const allComponents = await scanAllPackages();
|
|
181
|
+
const components = filterComponents(allComponents, input.filter);
|
|
182
|
+
return {
|
|
183
|
+
components
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// src/server.ts
|
|
188
|
+
function createServer() {
|
|
189
|
+
const server = new McpServer({
|
|
190
|
+
name: "brick-design-system",
|
|
191
|
+
version: "1.0.0"
|
|
192
|
+
});
|
|
193
|
+
server.registerTool(
|
|
194
|
+
"list-components",
|
|
195
|
+
{
|
|
196
|
+
title: "List Brick Components",
|
|
197
|
+
description: "List all available Brick components with metadata. Optionally filter by category, tag, or name.",
|
|
198
|
+
inputSchema: {
|
|
199
|
+
filter: z.string().optional().describe("Optional filter by category, tag, or name")
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
async ({ filter }) => {
|
|
203
|
+
const result = await listComponents({ filter });
|
|
204
|
+
return {
|
|
205
|
+
content: [
|
|
206
|
+
{
|
|
207
|
+
type: "text",
|
|
208
|
+
text: JSON.stringify(result, null, 2)
|
|
209
|
+
}
|
|
210
|
+
]
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
);
|
|
214
|
+
server.registerTool(
|
|
215
|
+
"get-component-docs",
|
|
216
|
+
{
|
|
217
|
+
title: "Get Component Documentation",
|
|
218
|
+
description: "Retrieve detailed documentation for specific Brick component(s) including props, events, examples, and accessibility information.",
|
|
219
|
+
inputSchema: {
|
|
220
|
+
components: z.array(z.string()).describe(
|
|
221
|
+
'Array of component names (e.g., ["brick-button", "brick-modal"])'
|
|
222
|
+
)
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
async ({ components }) => {
|
|
226
|
+
const result = await getComponentDocs({ components });
|
|
227
|
+
return {
|
|
228
|
+
content: [
|
|
229
|
+
{
|
|
230
|
+
type: "text",
|
|
231
|
+
text: JSON.stringify(result, null, 2)
|
|
232
|
+
}
|
|
233
|
+
]
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
);
|
|
237
|
+
server.registerTool(
|
|
238
|
+
"get-design-tokens",
|
|
239
|
+
{
|
|
240
|
+
title: "Get Design Tokens",
|
|
241
|
+
description: "Access design tokens from brick-tokens. Optionally filter by category (colors, spacing, typography, shadows, borders).",
|
|
242
|
+
inputSchema: {
|
|
243
|
+
category: z.enum(["colors", "spacing", "typography", "shadows", "borders"]).optional().describe("Filter tokens by category")
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
async ({ category }) => {
|
|
247
|
+
const result = await getDesignTokens({ category });
|
|
248
|
+
return {
|
|
249
|
+
content: [
|
|
250
|
+
{
|
|
251
|
+
type: "text",
|
|
252
|
+
text: JSON.stringify(result, null, 2)
|
|
253
|
+
}
|
|
254
|
+
]
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
);
|
|
258
|
+
return server;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// src/http.ts
|
|
262
|
+
var PORT = 3e3;
|
|
263
|
+
var HOST = "localhost";
|
|
264
|
+
var fastify = Fastify({
|
|
265
|
+
logger: {
|
|
266
|
+
level: "info"
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
var activeTransports = /* @__PURE__ */ new Map();
|
|
270
|
+
var activeMcpServers = /* @__PURE__ */ new Map();
|
|
271
|
+
await fastify.register(cors, {
|
|
272
|
+
origin: true,
|
|
273
|
+
credentials: true
|
|
274
|
+
});
|
|
275
|
+
fastify.get("/health", async () => {
|
|
276
|
+
return { status: "ok" };
|
|
277
|
+
});
|
|
278
|
+
fastify.get("/sse", async (_request, reply) => {
|
|
279
|
+
reply.hijack();
|
|
280
|
+
const mcpServer = createServer();
|
|
281
|
+
const transport = new SSEServerTransport("/message", reply.raw);
|
|
282
|
+
await mcpServer.connect(transport);
|
|
283
|
+
const sessionId = transport.sessionId;
|
|
284
|
+
activeTransports.set(sessionId, transport);
|
|
285
|
+
activeMcpServers.set(sessionId, mcpServer);
|
|
286
|
+
reply.raw.on("close", async () => {
|
|
287
|
+
activeTransports.delete(sessionId);
|
|
288
|
+
const server = activeMcpServers.get(sessionId);
|
|
289
|
+
if (server) {
|
|
290
|
+
await server.close();
|
|
291
|
+
activeMcpServers.delete(sessionId);
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
fastify.post("/message", async (request, reply) => {
|
|
296
|
+
reply.hijack();
|
|
297
|
+
const { sessionId } = request.query;
|
|
298
|
+
const transport = activeTransports.get(sessionId);
|
|
299
|
+
if (!transport) {
|
|
300
|
+
reply.raw.writeHead(404, { "Content-Type": "application/json" });
|
|
301
|
+
reply.raw.end(JSON.stringify({ error: "Session not found" }));
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
await transport.handlePostMessage(request.raw, reply.raw, request.body);
|
|
305
|
+
});
|
|
306
|
+
try {
|
|
307
|
+
await fastify.listen({ port: PORT, host: HOST });
|
|
308
|
+
console.log(`Brick MCP HTTP server listening on http://${HOST}:${PORT}`);
|
|
309
|
+
console.log(`SSE endpoint: http://${HOST}:${PORT}/sse`);
|
|
310
|
+
} catch (err) {
|
|
311
|
+
fastify.log.error(err);
|
|
312
|
+
process.exit(1);
|
|
313
|
+
}
|
|
314
|
+
//# sourceMappingURL=http.js.map
|
package/dist/http.js.map
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/http.ts", "../src/server.ts", "../src/tools/getComponentDocs.ts", "../src/utils/dataPath.ts", "../src/extractors/packageScanner.ts", "../src/tools/getDesignTokens.ts", "../src/tools/listComponents.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * HTTP server entry point for local development only\n * Uses Fastify and SSE transport for MCP communication\n */\n\nimport cors from '@fastify/cors';\nimport { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';\nimport Fastify from 'fastify';\n\nimport { createServer } from './server.ts';\n\nconst PORT = 3000;\nconst HOST = 'localhost';\n\nconst fastify = Fastify({\n logger: {\n level: 'info',\n },\n});\n\n// Store active transports and servers by sessionId\nconst activeTransports = new Map<string, SSEServerTransport>();\nconst activeMcpServers = new Map<string, ReturnType<typeof createServer>>();\n\n// Enable CORS for local development\nawait fastify.register(cors, {\n origin: true,\n credentials: true,\n});\n\n// Health check endpoint\nfastify.get('/health', async () => {\n return { status: 'ok' };\n});\n\n// SSE endpoint for MCP communication\nfastify.get('/sse', async (_request, reply) => {\n // Prevent Fastify from automatically sending a response\n reply.hijack();\n\n // Create a new MCP server instance for this connection\n const mcpServer = createServer();\n\n // Create SSE transport (this will handle headers internally)\n const transport = new SSEServerTransport('/message', reply.raw);\n\n // Handle the SSE connection (this calls transport.start() which writes headers)\n await mcpServer.connect(transport);\n\n // Store the transport and server by sessionId for POST message handling\n // The sessionId is available after the transport starts via the public getter\n const sessionId = transport.sessionId;\n activeTransports.set(sessionId, transport);\n activeMcpServers.set(sessionId, mcpServer);\n\n // Clean up when the connection closes\n reply.raw.on('close', async () => {\n activeTransports.delete(sessionId);\n const server = activeMcpServers.get(sessionId);\n if (server) {\n await server.close();\n activeMcpServers.delete(sessionId);\n }\n });\n});\n\n// POST endpoint for messages\nfastify.post<{\n Querystring: { sessionId: string };\n}>('/message', async (request, reply) => {\n // Prevent Fastify from automatically sending a response\n reply.hijack();\n\n // Extract sessionId from query parameters (now properly typed)\n const { sessionId } = request.query;\n\n // Find the transport for this session\n const transport = activeTransports.get(sessionId);\n\n if (!transport) {\n reply.raw.writeHead(404, { 'Content-Type': 'application/json' });\n reply.raw.end(JSON.stringify({ error: 'Session not found' }));\n return;\n }\n\n // Let the transport handle the POST message\n await transport.handlePostMessage(request.raw, reply.raw, request.body);\n});\n\n// Start the server\ntry {\n await fastify.listen({ port: PORT, host: HOST });\n console.log(`Brick MCP HTTP server listening on http://${HOST}:${PORT}`);\n console.log(`SSE endpoint: http://${HOST}:${PORT}/sse`);\n} catch (err) {\n fastify.log.error(err);\n process.exit(1);\n}\n", "/**\n * MCP server setup and registration\n */\n\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\n\nimport { getComponentDocs } from './tools/getComponentDocs.ts';\nimport { getDesignTokens } from './tools/getDesignTokens.ts';\nimport { listComponents } from './tools/listComponents.ts';\n\n/**\n * Create and configure the MCP server\n */\nexport function createServer(): McpServer {\n // Create an MCP server\n const server = new McpServer({\n name: 'brick-design-system',\n version: '1.0.0',\n });\n\n // Register list-components tool\n server.registerTool(\n 'list-components',\n {\n title: 'List Brick Components',\n description:\n 'List all available Brick components with metadata. Optionally filter by category, tag, or name.',\n inputSchema: {\n filter: z\n .string()\n .optional()\n .describe('Optional filter by category, tag, or name'),\n },\n },\n async ({ filter }) => {\n const result = await listComponents({ filter });\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n );\n\n // Register get-component-docs tool\n server.registerTool(\n 'get-component-docs',\n {\n title: 'Get Component Documentation',\n description:\n 'Retrieve detailed documentation for specific Brick component(s) including props, events, examples, and accessibility information.',\n inputSchema: {\n components: z\n .array(z.string())\n .describe(\n 'Array of component names (e.g., [\"brick-button\", \"brick-modal\"])'\n ),\n },\n },\n async ({ components }) => {\n const result = await getComponentDocs({ components });\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n );\n\n // Register get-design-tokens tool\n server.registerTool(\n 'get-design-tokens',\n {\n title: 'Get Design Tokens',\n description:\n 'Access design tokens from brick-tokens. Optionally filter by category (colors, spacing, typography, shadows, borders).',\n inputSchema: {\n category: z\n .enum(['colors', 'spacing', 'typography', 'shadows', 'borders'])\n .optional()\n .describe('Filter tokens by category'),\n },\n },\n async ({ category }) => {\n const result = await getDesignTokens({ category });\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n );\n\n return server;\n}\n", "/**\n * Get Component Docs tool implementation\n */\n\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { getDataPath } from '../utils/dataPath.ts';\nimport { loadComponentData } from '../extractors/packageScanner.ts';\n\nexport interface GetComponentDocsInput {\n components: string[]; // e.g., [\"brick-button\", \"brick-modal\"]\n}\n\nexport interface GetComponentDocsOutput {\n docs: string[];\n}\n\n/**\n * Load markdown documentation for a component\n */\nasync function loadComponentMarkdown(\n componentName: string\n): Promise<string | undefined> {\n try {\n const markdownPath = join(\n getDataPath(),\n 'components',\n `${componentName}.md`\n );\n const content = await readFile(markdownPath, 'utf-8');\n return content;\n } catch (error) {\n console.error(`Error loading markdown for ${componentName}:`, error);\n return undefined;\n }\n}\n\n/**\n * Get detailed documentation for specific component(s)\n */\nexport async function getComponentDocs(\n input: GetComponentDocsInput\n): Promise<GetComponentDocsOutput> {\n // Load markdown documentation for each requested component\n const docsPromises = input.components.map(async (componentName) => {\n const md = await loadComponentMarkdown(componentName);\n if (!md) {\n const json = await loadComponentData(componentName);\n return json ? JSON.stringify(json) : undefined;\n }\n return md;\n });\n\n const docsResults = await Promise.all(docsPromises);\n\n // Filter out any components that failed to load\n const docs = docsResults.filter((doc): doc is string => doc !== undefined);\n\n return { docs };\n}\n", "/**\n * Utility for finding the data directory path\n * Works both in development (from src/) and production (from dist/)\n */\n\nimport { accessSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n/**\n * Get the path to the data directory\n * When running from dist/, looks for dist/data\n * When running from src/, looks for package root data\n */\nexport function getDataPath(): string {\n const currentFilePath = fileURLToPath(import.meta.url);\n let dir = dirname(currentFilePath);\n\n // First check if there's a data directory in the same parent as the current file\n // This handles the dist/data case when running from dist/\n const localDataPath = join(dir, 'data');\n try {\n accessSync(localDataPath);\n return localDataPath;\n } catch {\n // Continue to package root search\n }\n\n // Walk up the directory tree to find package root (where package.json exists)\n for (let i = 0; i < 5; i++) {\n try {\n const testPath = join(dir, 'package.json');\n accessSync(testPath);\n return join(dir, 'data');\n } catch {\n // Go up one level\n const parent = dirname(dir);\n if (parent === dir) break; // Reached filesystem root\n dir = parent;\n }\n }\n\n return join(dirname(currentFilePath), '..', '..', 'data');\n}\n", "/**\n * Package scanner for discovering Brick components\n */\n\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { type BrickComponent, type BrickComponentMetadata } from '../types.ts';\nimport { getDataPath } from '../utils/dataPath.ts';\n\n/**\n * Load all component metadata (lightweight, for listing)\n */\nexport async function scanAllPackages(): Promise<BrickComponentMetadata[]> {\n try {\n const metadataPath = join(getDataPath(), 'components-metadata.json');\n const content = await readFile(metadataPath, 'utf-8');\n const metadata: BrickComponentMetadata[] = JSON.parse(content);\n return metadata;\n } catch (error) {\n console.error('Error loading component metadata:', error);\n return [];\n }\n}\n\n/**\n * Load full component data for a specific component\n */\nexport async function loadComponentData(\n componentName: string\n): Promise<BrickComponent | undefined> {\n try {\n const componentPath = join(\n getDataPath(),\n 'components',\n `${componentName}.json`\n );\n const content = await readFile(componentPath, 'utf-8');\n const component: BrickComponent = JSON.parse(content);\n return component;\n } catch (error) {\n console.error(`Error loading component data for ${componentName}:`, error);\n return undefined;\n }\n}\n\n/**\n * Filter components by category or tag\n */\nexport function filterComponents(\n components: BrickComponentMetadata[],\n filter?: string\n): BrickComponentMetadata[] {\n if (!filter) {\n return components;\n }\n\n const filterLower = filter.toLowerCase();\n\n return components.filter((component) => {\n // Match against name\n if (component.name.toLowerCase().includes(filterLower)) {\n return true;\n }\n\n // Match against category\n if (component.category?.toLowerCase().includes(filterLower)) {\n return true;\n }\n\n // Match against tags\n if (\n component.tags?.some((tag) => tag.toLowerCase().includes(filterLower))\n ) {\n return true;\n }\n\n return false;\n });\n}\n", "/**\n * Get Design Tokens tool implementation\n */\n\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { getDataPath } from '../utils/dataPath.ts';\n\nexport interface DesignToken {\n path: string;\n name: string;\n type: string;\n value: string;\n description?: string;\n cssVariable: string;\n}\n\nexport interface GetDesignTokensInput {\n category?: 'colors' | 'spacing' | 'typography' | 'shadows' | 'borders';\n}\n\nexport interface TokensDocumentation {\n anOverview?: string;\n formats?: string;\n naming?: string;\n usage?: string;\n}\n\nexport interface GetDesignTokensOutput {\n tokens: DesignToken[];\n documentation: TokensDocumentation;\n note?: string;\n}\n\n/**\n * Get the path to the bundled tokens data\n */\nfunction getTokensDataPath(): string {\n return join(getDataPath(), 'tokens.json');\n}\n\n/**\n * Get the path to the bundled documentation data\n */\nfunction getDocumentationDataPath(): string {\n return join(getDataPath(), 'tokens-documentation.json');\n}\n\n/**\n * Load all tokens from bundled JSON data\n */\nasync function loadAllTokens(): Promise<DesignToken[]> {\n try {\n const dataPath = getTokensDataPath();\n const content = await readFile(dataPath, 'utf-8');\n return JSON.parse(content);\n } catch (error) {\n console.error('Error loading tokens data:', error);\n return [];\n }\n}\n\n/**\n * Load documentation from bundled JSON data\n */\nasync function loadDocumentation(): Promise<TokensDocumentation> {\n try {\n const dataPath = getDocumentationDataPath();\n const content = await readFile(dataPath, 'utf-8');\n return JSON.parse(content);\n } catch (error) {\n console.error('Error loading documentation data:', error);\n return {};\n }\n}\n\n/**\n * Get design tokens with optional filtering\n */\nexport async function getDesignTokens(\n input: GetDesignTokensInput\n): Promise<GetDesignTokensOutput> {\n const allTokens = await loadAllTokens();\n const documentation = await loadDocumentation();\n\n let filteredTokens = allTokens;\n\n // Filter by category if specified\n if (input.category) {\n filteredTokens = filteredTokens.filter((token) => {\n // Filter based on the path field which contains category information\n const path = token.path.toLowerCase();\n\n switch (input.category) {\n case 'colors':\n return path.startsWith('color.');\n case 'spacing':\n return path.startsWith('spacing.');\n case 'typography':\n return path.startsWith('typography.');\n case 'shadows':\n return path.startsWith('box-shadow.');\n case 'borders':\n return (\n path.startsWith('border-width.') ||\n path.startsWith('border-radius.') ||\n path.startsWith('border.')\n );\n default:\n return false;\n }\n });\n }\n\n return {\n tokens: filteredTokens,\n documentation,\n note: 'The \"value\" field shows example values from one theme. Actual values vary across different themes (alfa, bravo, charlie, nettavisen, alt). Use the \"cssVariable\" field for theme-aware styling.',\n };\n}\n", "/**\n * List Components tool implementation\n */\n\nimport {\n filterComponents,\n scanAllPackages,\n} from '../extractors/packageScanner.ts';\nimport type { BrickComponentMetadata } from '../types.ts';\n\nexport interface ListComponentsInput {\n filter?: string;\n}\n\nexport interface ListComponentsOutput {\n components: BrickComponentMetadata[];\n}\n\n/**\n * List all available Brick components with optional filtering\n */\nexport async function listComponents(\n input: ListComponentsInput\n): Promise<ListComponentsOutput> {\n // Scan all packages in the monorepo (returns lightweight metadata)\n const allComponents = await scanAllPackages();\n\n // Apply filter if provided\n const components = filterComponents(allComponents, input.filter);\n\n return {\n components,\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["readFile", "join", "join", "join", "join", "readFile", "readFile", "join", "join", "readFile"]
|
|
7
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -17,6 +17,12 @@ import { fileURLToPath } from "node:url";
|
|
|
17
17
|
function getDataPath() {
|
|
18
18
|
const currentFilePath = fileURLToPath(import.meta.url);
|
|
19
19
|
let dir = dirname(currentFilePath);
|
|
20
|
+
const localDataPath = join(dir, "data");
|
|
21
|
+
try {
|
|
22
|
+
accessSync(localDataPath);
|
|
23
|
+
return localDataPath;
|
|
24
|
+
} catch {
|
|
25
|
+
}
|
|
20
26
|
for (let i = 0; i < 5; i++) {
|
|
21
27
|
try {
|
|
22
28
|
const testPath = join(dir, "package.json");
|
|
@@ -138,49 +144,33 @@ async function loadDocumentation() {
|
|
|
138
144
|
return {};
|
|
139
145
|
}
|
|
140
146
|
}
|
|
141
|
-
function getAvailableThemes(tokens) {
|
|
142
|
-
const themes = /* @__PURE__ */ new Set();
|
|
143
|
-
for (const token of tokens) {
|
|
144
|
-
if (token.theme) {
|
|
145
|
-
themes.add(token.theme);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
return Array.from(themes).sort();
|
|
149
|
-
}
|
|
150
147
|
async function getDesignTokens(input) {
|
|
151
148
|
const allTokens = await loadAllTokens();
|
|
152
149
|
const documentation = await loadDocumentation();
|
|
153
150
|
let filteredTokens = allTokens;
|
|
154
|
-
if (input.theme) {
|
|
155
|
-
filteredTokens = filteredTokens.filter(
|
|
156
|
-
(token) => token.theme === input.theme
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
151
|
if (input.category) {
|
|
160
152
|
filteredTokens = filteredTokens.filter((token) => {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
153
|
+
const path = token.path.toLowerCase();
|
|
154
|
+
switch (input.category) {
|
|
155
|
+
case "colors":
|
|
156
|
+
return path.startsWith("color.");
|
|
157
|
+
case "spacing":
|
|
158
|
+
return path.startsWith("spacing.");
|
|
159
|
+
case "typography":
|
|
160
|
+
return path.startsWith("typography.");
|
|
161
|
+
case "shadows":
|
|
162
|
+
return path.startsWith("box-shadow.");
|
|
163
|
+
case "borders":
|
|
164
|
+
return path.startsWith("border-width.") || path.startsWith("border-radius.") || path.startsWith("border.");
|
|
165
|
+
default:
|
|
166
|
+
return false;
|
|
175
167
|
}
|
|
176
|
-
return false;
|
|
177
168
|
});
|
|
178
169
|
}
|
|
179
|
-
const themes = getAvailableThemes(allTokens);
|
|
180
170
|
return {
|
|
181
171
|
tokens: filteredTokens,
|
|
182
|
-
|
|
183
|
-
|
|
172
|
+
documentation,
|
|
173
|
+
note: 'The "value" field shows example values from one theme. Actual values vary across different themes (alfa, bravo, charlie, nettavisen, alt). Use the "cssVariable" field for theme-aware styling.'
|
|
184
174
|
};
|
|
185
175
|
}
|
|
186
176
|
|
|
@@ -247,14 +237,13 @@ function createServer() {
|
|
|
247
237
|
"get-design-tokens",
|
|
248
238
|
{
|
|
249
239
|
title: "Get Design Tokens",
|
|
250
|
-
description: "Access design tokens from brick-tokens. Optionally filter by category (colors, spacing, typography, shadows, borders)
|
|
240
|
+
description: "Access design tokens from brick-tokens. Optionally filter by category (colors, spacing, typography, shadows, borders).",
|
|
251
241
|
inputSchema: {
|
|
252
|
-
category: z.enum(["colors", "spacing", "typography", "shadows", "borders"]).optional().describe("Filter tokens by category")
|
|
253
|
-
theme: z.string().optional().describe('Filter tokens by theme (e.g., "bergen", "alfa")')
|
|
242
|
+
category: z.enum(["colors", "spacing", "typography", "shadows", "borders"]).optional().describe("Filter tokens by category")
|
|
254
243
|
}
|
|
255
244
|
},
|
|
256
|
-
async ({ category
|
|
257
|
-
const result = await getDesignTokens({ category
|
|
245
|
+
async ({ category }) => {
|
|
246
|
+
const result = await getDesignTokens({ category });
|
|
258
247
|
return {
|
|
259
248
|
content: [
|
|
260
249
|
{
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts", "../src/server.ts", "../src/tools/getComponentDocs.ts", "../src/utils/dataPath.ts", "../src/extractors/packageScanner.ts", "../src/tools/getDesignTokens.ts", "../src/tools/listComponents.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Main MCP server entry point\n */\n\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\n\nimport { createServer } from './server.ts';\n\n// Create and start the server\nconst server = createServer();\n\n// Start receiving messages on stdin and sending messages on stdout\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\n", "/**\n * MCP server setup and registration\n */\n\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\n\nimport { getComponentDocs } from './tools/getComponentDocs.ts';\nimport { getDesignTokens } from './tools/getDesignTokens.ts';\nimport { listComponents } from './tools/listComponents.ts';\n\n/**\n * Create and configure the MCP server\n */\nexport function createServer(): McpServer {\n // Create an MCP server\n const server = new McpServer({\n name: 'brick-design-system',\n version: '1.0.0',\n });\n\n // Register list-components tool\n server.registerTool(\n 'list-components',\n {\n title: 'List Brick Components',\n description:\n 'List all available Brick components with metadata. Optionally filter by category, tag, or name.',\n inputSchema: {\n filter: z\n .string()\n .optional()\n .describe('Optional filter by category, tag, or name'),\n },\n },\n async ({ filter }) => {\n const result = await listComponents({ filter });\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n );\n\n // Register get-component-docs tool\n server.registerTool(\n 'get-component-docs',\n {\n title: 'Get Component Documentation',\n description:\n 'Retrieve detailed documentation for specific Brick component(s) including props, events, examples, and accessibility information.',\n inputSchema: {\n components: z\n .array(z.string())\n .describe(\n 'Array of component names (e.g., [\"brick-button\", \"brick-modal\"])'\n ),\n },\n },\n async ({ components }) => {\n const result = await getComponentDocs({ components });\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n );\n\n // Register get-design-tokens tool\n server.registerTool(\n 'get-design-tokens',\n {\n title: 'Get Design Tokens',\n description:\n 'Access design tokens from brick-tokens. Optionally filter by category (colors, spacing, typography, shadows, borders) or theme.',\n inputSchema: {\n category: z\n .enum(['colors', 'spacing', 'typography', 'shadows', 'borders'])\n .optional()\n .describe('Filter tokens by category'),\n theme: z\n .string()\n .optional()\n .describe('Filter tokens by theme (e.g., \"bergen\", \"alfa\")'),\n },\n },\n async ({ category, theme }) => {\n const result = await getDesignTokens({ category, theme });\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n );\n\n return server;\n}\n", "/**\n * Get Component Docs tool implementation\n */\n\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { getDataPath } from '../utils/dataPath.ts';\nimport { loadComponentData } from '../extractors/packageScanner.ts';\n\nexport interface GetComponentDocsInput {\n components: string[]; // e.g., [\"brick-button\", \"brick-modal\"]\n}\n\nexport interface GetComponentDocsOutput {\n docs: string[];\n}\n\n/**\n * Load markdown documentation for a component\n */\nasync function loadComponentMarkdown(\n componentName: string\n): Promise<string | undefined> {\n try {\n const markdownPath = join(\n getDataPath(),\n 'components',\n `${componentName}.md`\n );\n const content = await readFile(markdownPath, 'utf-8');\n return content;\n } catch (error) {\n console.error(`Error loading markdown for ${componentName}:`, error);\n return undefined;\n }\n}\n\n/**\n * Get detailed documentation for specific component(s)\n */\nexport async function getComponentDocs(\n input: GetComponentDocsInput\n): Promise<GetComponentDocsOutput> {\n // Load markdown documentation for each requested component\n const docsPromises = input.components.map(async (componentName) => {\n const md = await loadComponentMarkdown(componentName);\n if (!md) {\n const json = await loadComponentData(componentName);\n return json ? JSON.stringify(json) : undefined;\n }\n return md;\n });\n\n const docsResults = await Promise.all(docsPromises);\n\n // Filter out any components that failed to load\n const docs = docsResults.filter((doc): doc is string => doc !== undefined);\n\n return { docs };\n}\n", "/**\n * Utility for finding the data directory path\n * Works both in development (from src/) and production (from dist/)\n */\n\nimport { accessSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n/**\n * Get the path to the data directory at package root\n * Walks up the directory tree to find package.json, then returns the data directory\n */\nexport function getDataPath(): string {\n const currentFilePath = fileURLToPath(import.meta.url);\n let dir = dirname(currentFilePath);\n\n // Walk up the directory tree to find package root (where package.json exists)\n for (let i = 0; i < 5; i++) {\n try {\n const testPath = join(dir, 'package.json');\n accessSync(testPath);\n return join(dir, 'data');\n } catch {\n // Go up one level\n const parent = dirname(dir);\n if (parent === dir) break; // Reached filesystem root\n dir = parent;\n }\n }\n\n return join(dirname(currentFilePath), '..', '..', 'data');\n}\n", "/**\n * Package scanner for discovering Brick components\n */\n\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { type BrickComponent, type BrickComponentMetadata } from '../types.ts';\nimport { getDataPath } from '../utils/dataPath.ts';\n\n/**\n * Load all component metadata (lightweight, for listing)\n */\nexport async function scanAllPackages(): Promise<BrickComponentMetadata[]> {\n try {\n const metadataPath = join(getDataPath(), 'components-metadata.json');\n const content = await readFile(metadataPath, 'utf-8');\n const metadata: BrickComponentMetadata[] = JSON.parse(content);\n return metadata;\n } catch (error) {\n console.error('Error loading component metadata:', error);\n return [];\n }\n}\n\n/**\n * Load full component data for a specific component\n */\nexport async function loadComponentData(\n componentName: string\n): Promise<BrickComponent | undefined> {\n try {\n const componentPath = join(\n getDataPath(),\n 'components',\n `${componentName}.json`\n );\n const content = await readFile(componentPath, 'utf-8');\n const component: BrickComponent = JSON.parse(content);\n return component;\n } catch (error) {\n console.error(`Error loading component data for ${componentName}:`, error);\n return undefined;\n }\n}\n\n/**\n * Filter components by category or tag\n */\nexport function filterComponents(\n components: BrickComponentMetadata[],\n filter?: string\n): BrickComponentMetadata[] {\n if (!filter) {\n return components;\n }\n\n const filterLower = filter.toLowerCase();\n\n return components.filter((component) => {\n // Match against name\n if (component.name.toLowerCase().includes(filterLower)) {\n return true;\n }\n\n // Match against category\n if (component.category?.toLowerCase().includes(filterLower)) {\n return true;\n }\n\n // Match against tags\n if (\n component.tags?.some((tag) => tag.toLowerCase().includes(filterLower))\n ) {\n return true;\n }\n\n return false;\n });\n}\n", "/**\n * Get Design Tokens tool implementation\n */\n\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { getDataPath } from '../utils/dataPath.ts';\n\nexport interface DesignToken {\n name: string;\n value: string;\n type: string;\n description?: string;\n category?: string;\n theme?: string;\n}\n\nexport interface GetDesignTokensInput {\n category?: 'colors' | 'spacing' | 'typography' | 'shadows' | 'borders';\n theme?: string;\n}\n\nexport interface TokensDocumentation {\n anOverview?: string;\n formats?: string;\n naming?: string;\n themes?: string;\n usage?: string;\n}\n\nexport interface GetDesignTokensOutput {\n tokens: DesignToken[];\n themes: string[];\n documentation: TokensDocumentation;\n}\n\n/**\n * Get the path to the bundled tokens data\n */\nfunction getTokensDataPath(): string {\n return join(getDataPath(), 'tokens.json');\n}\n\n/**\n * Get the path to the bundled documentation data\n */\nfunction getDocumentationDataPath(): string {\n return join(getDataPath(), 'tokens-documentation.json');\n}\n\n/**\n * Load all tokens from bundled JSON data\n */\nasync function loadAllTokens(): Promise<DesignToken[]> {\n try {\n const dataPath = getTokensDataPath();\n const content = await readFile(dataPath, 'utf-8');\n return JSON.parse(content);\n } catch (error) {\n console.error('Error loading tokens data:', error);\n return [];\n }\n}\n\n/**\n * Load documentation from bundled JSON data\n */\nasync function loadDocumentation(): Promise<TokensDocumentation> {\n try {\n const dataPath = getDocumentationDataPath();\n const content = await readFile(dataPath, 'utf-8');\n return JSON.parse(content);\n } catch (error) {\n console.error('Error loading documentation data:', error);\n return {};\n }\n}\n\n/**\n * Get unique themes from tokens\n */\nfunction getAvailableThemes(tokens: DesignToken[]): string[] {\n const themes = new Set<string>();\n for (const token of tokens) {\n if (token.theme) {\n themes.add(token.theme);\n }\n }\n return Array.from(themes).sort();\n}\n\n/**\n * Get design tokens with optional filtering\n */\nexport async function getDesignTokens(\n input: GetDesignTokensInput\n): Promise<GetDesignTokensOutput> {\n const allTokens = await loadAllTokens();\n const documentation = await loadDocumentation();\n\n let filteredTokens = allTokens;\n\n // Filter by theme if specified\n if (input.theme) {\n filteredTokens = filteredTokens.filter(\n (token) => token.theme === input.theme\n );\n }\n\n // Filter by category if specified\n if (input.category) {\n filteredTokens = filteredTokens.filter((token) => {\n // Filter based on type or name pattern\n if (input.category === 'colors' && token.type === 'color') {\n return true;\n }\n if (\n input.category === 'spacing' &&\n (token.type === 'spacing' || token.name.includes('spacing'))\n ) {\n return true;\n }\n if (\n input.category === 'typography' &&\n (token.type === 'fontFamily' ||\n token.type === 'fontSize' ||\n token.type === 'fontWeight' ||\n token.name.includes('font'))\n ) {\n return true;\n }\n if (\n input.category === 'shadows' &&\n (token.type === 'boxShadow' || token.name.includes('shadow'))\n ) {\n return true;\n }\n if (\n input.category === 'borders' &&\n (token.type === 'borderRadius' ||\n token.type === 'borderWidth' ||\n token.name.includes('border'))\n ) {\n return true;\n }\n return false;\n });\n }\n\n const themes = getAvailableThemes(allTokens);\n\n return {\n tokens: filteredTokens,\n themes,\n documentation,\n };\n}\n", "/**\n * List Components tool implementation\n */\n\nimport {\n filterComponents,\n scanAllPackages,\n} from '../extractors/packageScanner.ts';\nimport type { BrickComponentMetadata } from '../types.ts';\n\nexport interface ListComponentsInput {\n filter?: string;\n}\n\nexport interface ListComponentsOutput {\n components: BrickComponentMetadata[];\n}\n\n/**\n * List all available Brick components with optional filtering\n */\nexport async function listComponents(\n input: ListComponentsInput\n): Promise<ListComponentsOutput> {\n // Scan all packages in the monorepo (returns lightweight metadata)\n const allComponents = await scanAllPackages();\n\n // Apply filter if provided\n const components = filterComponents(allComponents, input.filter);\n\n return {\n components,\n };\n}\n"],
|
|
5
|
-
"mappings": ";AAIA,SAAS,4BAA4B;;;ACArC,SAAS,iBAAiB;AAC1B,SAAS,SAAS;;;ACDlB,SAAS,YAAAA,iBAAgB;AACzB,SAAS,QAAAC,aAAY;;;ACArB,SAAS,kBAAkB;AAC3B,SAAS,SAAS,YAAY;AAC9B,SAAS,qBAAqB;
|
|
4
|
+
"sourcesContent": ["/**\n * Main MCP server entry point\n */\n\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\n\nimport { createServer } from './server.ts';\n\n// Create and start the server\nconst server = createServer();\n\n// Start receiving messages on stdin and sending messages on stdout\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\n", "/**\n * MCP server setup and registration\n */\n\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\n\nimport { getComponentDocs } from './tools/getComponentDocs.ts';\nimport { getDesignTokens } from './tools/getDesignTokens.ts';\nimport { listComponents } from './tools/listComponents.ts';\n\n/**\n * Create and configure the MCP server\n */\nexport function createServer(): McpServer {\n // Create an MCP server\n const server = new McpServer({\n name: 'brick-design-system',\n version: '1.0.0',\n });\n\n // Register list-components tool\n server.registerTool(\n 'list-components',\n {\n title: 'List Brick Components',\n description:\n 'List all available Brick components with metadata. Optionally filter by category, tag, or name.',\n inputSchema: {\n filter: z\n .string()\n .optional()\n .describe('Optional filter by category, tag, or name'),\n },\n },\n async ({ filter }) => {\n const result = await listComponents({ filter });\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n );\n\n // Register get-component-docs tool\n server.registerTool(\n 'get-component-docs',\n {\n title: 'Get Component Documentation',\n description:\n 'Retrieve detailed documentation for specific Brick component(s) including props, events, examples, and accessibility information.',\n inputSchema: {\n components: z\n .array(z.string())\n .describe(\n 'Array of component names (e.g., [\"brick-button\", \"brick-modal\"])'\n ),\n },\n },\n async ({ components }) => {\n const result = await getComponentDocs({ components });\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n );\n\n // Register get-design-tokens tool\n server.registerTool(\n 'get-design-tokens',\n {\n title: 'Get Design Tokens',\n description:\n 'Access design tokens from brick-tokens. Optionally filter by category (colors, spacing, typography, shadows, borders).',\n inputSchema: {\n category: z\n .enum(['colors', 'spacing', 'typography', 'shadows', 'borders'])\n .optional()\n .describe('Filter tokens by category'),\n },\n },\n async ({ category }) => {\n const result = await getDesignTokens({ category });\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n );\n\n return server;\n}\n", "/**\n * Get Component Docs tool implementation\n */\n\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { getDataPath } from '../utils/dataPath.ts';\nimport { loadComponentData } from '../extractors/packageScanner.ts';\n\nexport interface GetComponentDocsInput {\n components: string[]; // e.g., [\"brick-button\", \"brick-modal\"]\n}\n\nexport interface GetComponentDocsOutput {\n docs: string[];\n}\n\n/**\n * Load markdown documentation for a component\n */\nasync function loadComponentMarkdown(\n componentName: string\n): Promise<string | undefined> {\n try {\n const markdownPath = join(\n getDataPath(),\n 'components',\n `${componentName}.md`\n );\n const content = await readFile(markdownPath, 'utf-8');\n return content;\n } catch (error) {\n console.error(`Error loading markdown for ${componentName}:`, error);\n return undefined;\n }\n}\n\n/**\n * Get detailed documentation for specific component(s)\n */\nexport async function getComponentDocs(\n input: GetComponentDocsInput\n): Promise<GetComponentDocsOutput> {\n // Load markdown documentation for each requested component\n const docsPromises = input.components.map(async (componentName) => {\n const md = await loadComponentMarkdown(componentName);\n if (!md) {\n const json = await loadComponentData(componentName);\n return json ? JSON.stringify(json) : undefined;\n }\n return md;\n });\n\n const docsResults = await Promise.all(docsPromises);\n\n // Filter out any components that failed to load\n const docs = docsResults.filter((doc): doc is string => doc !== undefined);\n\n return { docs };\n}\n", "/**\n * Utility for finding the data directory path\n * Works both in development (from src/) and production (from dist/)\n */\n\nimport { accessSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n/**\n * Get the path to the data directory\n * When running from dist/, looks for dist/data\n * When running from src/, looks for package root data\n */\nexport function getDataPath(): string {\n const currentFilePath = fileURLToPath(import.meta.url);\n let dir = dirname(currentFilePath);\n\n // First check if there's a data directory in the same parent as the current file\n // This handles the dist/data case when running from dist/\n const localDataPath = join(dir, 'data');\n try {\n accessSync(localDataPath);\n return localDataPath;\n } catch {\n // Continue to package root search\n }\n\n // Walk up the directory tree to find package root (where package.json exists)\n for (let i = 0; i < 5; i++) {\n try {\n const testPath = join(dir, 'package.json');\n accessSync(testPath);\n return join(dir, 'data');\n } catch {\n // Go up one level\n const parent = dirname(dir);\n if (parent === dir) break; // Reached filesystem root\n dir = parent;\n }\n }\n\n return join(dirname(currentFilePath), '..', '..', 'data');\n}\n", "/**\n * Package scanner for discovering Brick components\n */\n\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { type BrickComponent, type BrickComponentMetadata } from '../types.ts';\nimport { getDataPath } from '../utils/dataPath.ts';\n\n/**\n * Load all component metadata (lightweight, for listing)\n */\nexport async function scanAllPackages(): Promise<BrickComponentMetadata[]> {\n try {\n const metadataPath = join(getDataPath(), 'components-metadata.json');\n const content = await readFile(metadataPath, 'utf-8');\n const metadata: BrickComponentMetadata[] = JSON.parse(content);\n return metadata;\n } catch (error) {\n console.error('Error loading component metadata:', error);\n return [];\n }\n}\n\n/**\n * Load full component data for a specific component\n */\nexport async function loadComponentData(\n componentName: string\n): Promise<BrickComponent | undefined> {\n try {\n const componentPath = join(\n getDataPath(),\n 'components',\n `${componentName}.json`\n );\n const content = await readFile(componentPath, 'utf-8');\n const component: BrickComponent = JSON.parse(content);\n return component;\n } catch (error) {\n console.error(`Error loading component data for ${componentName}:`, error);\n return undefined;\n }\n}\n\n/**\n * Filter components by category or tag\n */\nexport function filterComponents(\n components: BrickComponentMetadata[],\n filter?: string\n): BrickComponentMetadata[] {\n if (!filter) {\n return components;\n }\n\n const filterLower = filter.toLowerCase();\n\n return components.filter((component) => {\n // Match against name\n if (component.name.toLowerCase().includes(filterLower)) {\n return true;\n }\n\n // Match against category\n if (component.category?.toLowerCase().includes(filterLower)) {\n return true;\n }\n\n // Match against tags\n if (\n component.tags?.some((tag) => tag.toLowerCase().includes(filterLower))\n ) {\n return true;\n }\n\n return false;\n });\n}\n", "/**\n * Get Design Tokens tool implementation\n */\n\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { getDataPath } from '../utils/dataPath.ts';\n\nexport interface DesignToken {\n path: string;\n name: string;\n type: string;\n value: string;\n description?: string;\n cssVariable: string;\n}\n\nexport interface GetDesignTokensInput {\n category?: 'colors' | 'spacing' | 'typography' | 'shadows' | 'borders';\n}\n\nexport interface TokensDocumentation {\n anOverview?: string;\n formats?: string;\n naming?: string;\n usage?: string;\n}\n\nexport interface GetDesignTokensOutput {\n tokens: DesignToken[];\n documentation: TokensDocumentation;\n note?: string;\n}\n\n/**\n * Get the path to the bundled tokens data\n */\nfunction getTokensDataPath(): string {\n return join(getDataPath(), 'tokens.json');\n}\n\n/**\n * Get the path to the bundled documentation data\n */\nfunction getDocumentationDataPath(): string {\n return join(getDataPath(), 'tokens-documentation.json');\n}\n\n/**\n * Load all tokens from bundled JSON data\n */\nasync function loadAllTokens(): Promise<DesignToken[]> {\n try {\n const dataPath = getTokensDataPath();\n const content = await readFile(dataPath, 'utf-8');\n return JSON.parse(content);\n } catch (error) {\n console.error('Error loading tokens data:', error);\n return [];\n }\n}\n\n/**\n * Load documentation from bundled JSON data\n */\nasync function loadDocumentation(): Promise<TokensDocumentation> {\n try {\n const dataPath = getDocumentationDataPath();\n const content = await readFile(dataPath, 'utf-8');\n return JSON.parse(content);\n } catch (error) {\n console.error('Error loading documentation data:', error);\n return {};\n }\n}\n\n/**\n * Get design tokens with optional filtering\n */\nexport async function getDesignTokens(\n input: GetDesignTokensInput\n): Promise<GetDesignTokensOutput> {\n const allTokens = await loadAllTokens();\n const documentation = await loadDocumentation();\n\n let filteredTokens = allTokens;\n\n // Filter by category if specified\n if (input.category) {\n filteredTokens = filteredTokens.filter((token) => {\n // Filter based on the path field which contains category information\n const path = token.path.toLowerCase();\n\n switch (input.category) {\n case 'colors':\n return path.startsWith('color.');\n case 'spacing':\n return path.startsWith('spacing.');\n case 'typography':\n return path.startsWith('typography.');\n case 'shadows':\n return path.startsWith('box-shadow.');\n case 'borders':\n return (\n path.startsWith('border-width.') ||\n path.startsWith('border-radius.') ||\n path.startsWith('border.')\n );\n default:\n return false;\n }\n });\n }\n\n return {\n tokens: filteredTokens,\n documentation,\n note: 'The \"value\" field shows example values from one theme. Actual values vary across different themes (alfa, bravo, charlie, nettavisen, alt). Use the \"cssVariable\" field for theme-aware styling.',\n };\n}\n", "/**\n * List Components tool implementation\n */\n\nimport {\n filterComponents,\n scanAllPackages,\n} from '../extractors/packageScanner.ts';\nimport type { BrickComponentMetadata } from '../types.ts';\n\nexport interface ListComponentsInput {\n filter?: string;\n}\n\nexport interface ListComponentsOutput {\n components: BrickComponentMetadata[];\n}\n\n/**\n * List all available Brick components with optional filtering\n */\nexport async function listComponents(\n input: ListComponentsInput\n): Promise<ListComponentsOutput> {\n // Scan all packages in the monorepo (returns lightweight metadata)\n const allComponents = await scanAllPackages();\n\n // Apply filter if provided\n const components = filterComponents(allComponents, input.filter);\n\n return {\n components,\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["readFile", "join", "join", "join", "join", "readFile", "readFile", "join", "join", "readFile", "server"]
|
|
7
7
|
}
|
package/package.json
CHANGED
package/scripts/generate-data.js
CHANGED
|
@@ -138,32 +138,6 @@ async function generateComponentMetadata() {
|
|
|
138
138
|
console.log(`✅ Generated metadata for ${metadataList.length} components`);
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
/**
|
|
142
|
-
* Recursively extract tokens from nested token object
|
|
143
|
-
*/
|
|
144
|
-
function extractTokens(obj, prefix = '', category, theme, tokens = []) {
|
|
145
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
146
|
-
const tokenName = prefix ? `${prefix}-${key}` : key;
|
|
147
|
-
|
|
148
|
-
if (value && typeof value === 'object') {
|
|
149
|
-
if ('$value' in value && '$type' in value) {
|
|
150
|
-
tokens.push({
|
|
151
|
-
name: tokenName,
|
|
152
|
-
value: String(value.$value),
|
|
153
|
-
type: String(value.$type),
|
|
154
|
-
description: value.$description,
|
|
155
|
-
category,
|
|
156
|
-
theme,
|
|
157
|
-
});
|
|
158
|
-
} else {
|
|
159
|
-
extractTokens(value, tokenName, category, theme, tokens);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
return tokens;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
141
|
/**
|
|
168
142
|
* Generate design tokens documentation
|
|
169
143
|
*/
|
|
@@ -209,35 +183,29 @@ async function generateDesignTokens() {
|
|
|
209
183
|
console.log('Generating design tokens...');
|
|
210
184
|
|
|
211
185
|
const tokensPath = join(BRICK_ROOT, 'packages', 'brick-tokens');
|
|
212
|
-
const
|
|
186
|
+
const tokensViewerPath = join(
|
|
187
|
+
tokensPath,
|
|
188
|
+
'tokens-viewer',
|
|
189
|
+
'tokens-viewer.json'
|
|
190
|
+
);
|
|
213
191
|
|
|
214
192
|
try {
|
|
215
|
-
|
|
216
|
-
const
|
|
217
|
-
|
|
218
|
-
const allTokens = [];
|
|
219
|
-
|
|
220
|
-
for (const file of themeFiles) {
|
|
221
|
-
const themeName = file.replace('.json', '');
|
|
222
|
-
const themePath = join(publicationsPath, file);
|
|
223
|
-
|
|
224
|
-
try {
|
|
225
|
-
const content = await readFile(themePath, 'utf-8');
|
|
226
|
-
const tokenData = JSON.parse(content);
|
|
227
|
-
const tokens = extractTokens(tokenData, '', undefined, themeName);
|
|
228
|
-
allTokens.push(...tokens);
|
|
229
|
-
} catch (error) {
|
|
230
|
-
console.error(`Error reading theme ${themeName}:`, error.message);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
193
|
+
// Read the tokens-viewer.json file
|
|
194
|
+
const content = await readFile(tokensViewerPath, 'utf-8');
|
|
195
|
+
const tokens = JSON.parse(content);
|
|
233
196
|
|
|
197
|
+
// Ensure data directory exists
|
|
234
198
|
await mkdir(DATA_DIR, { recursive: true });
|
|
199
|
+
|
|
200
|
+
// Write tokens.json
|
|
235
201
|
await writeFile(
|
|
236
202
|
join(DATA_DIR, 'tokens.json'),
|
|
237
|
-
JSON.stringify(
|
|
203
|
+
JSON.stringify(tokens, null, 2)
|
|
238
204
|
);
|
|
239
205
|
|
|
240
|
-
console.log(
|
|
206
|
+
console.log(
|
|
207
|
+
`✅ Generated ${tokens.length} design tokens from tokens-viewer.json`
|
|
208
|
+
);
|
|
241
209
|
} catch (error) {
|
|
242
210
|
console.error('Error generating design tokens:', error.message);
|
|
243
211
|
}
|