@buoy-design/mcp 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Buoy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/bin.js ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ startServer
4
+ } from "./chunk-RDI5XKIN.js";
5
+
6
+ // src/bin.ts
7
+ var args = process.argv.slice(2);
8
+ var command = args[0] || "serve";
9
+ if (command === "serve" || command === void 0) {
10
+ const cwdIndex = args.indexOf("--cwd");
11
+ const cwd = cwdIndex !== -1 && args[cwdIndex + 1] ? args[cwdIndex + 1] : process.cwd();
12
+ startServer(cwd).catch((error) => {
13
+ console.error("Failed to start MCP server:", error);
14
+ process.exit(1);
15
+ });
16
+ } else if (command === "--help" || command === "-h") {
17
+ console.log(`
18
+ Buoy MCP Server
19
+
20
+ Usage:
21
+ buoy-mcp [serve] Start the MCP server
22
+ buoy-mcp serve --cwd <dir> Start with specific working directory
23
+ buoy-mcp --help Show this help message
24
+
25
+ The MCP server provides design system context to AI agents:
26
+ - Resources: tokens, components, patterns, anti-patterns
27
+ - Tools: find_component, validate_code, resolve_token, suggest_fix
28
+
29
+ Claude Code integration:
30
+ Add to .claude/settings.json:
31
+ {
32
+ "mcpServers": {
33
+ "buoy": {
34
+ "command": "npx",
35
+ "args": ["@buoy-design/mcp", "serve"]
36
+ }
37
+ }
38
+ }
39
+ `);
40
+ process.exit(0);
41
+ } else {
42
+ console.error(`Unknown command: ${command}`);
43
+ console.error('Run "buoy-mcp --help" for usage information');
44
+ process.exit(1);
45
+ }
46
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/bin.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * Buoy MCP Server CLI\n *\n * Usage:\n * buoy-mcp serve # Start MCP server (default)\n * buoy-mcp serve --cwd . # Specify working directory\n */\n\nimport { startServer } from './server.js';\n\nconst args = process.argv.slice(2);\nconst command = args[0] || 'serve';\n\nif (command === 'serve' || command === undefined) {\n // Parse --cwd option\n const cwdIndex = args.indexOf('--cwd');\n const cwd = cwdIndex !== -1 && args[cwdIndex + 1]\n ? args[cwdIndex + 1]\n : process.cwd();\n\n startServer(cwd).catch((error) => {\n console.error('Failed to start MCP server:', error);\n process.exit(1);\n });\n} else if (command === '--help' || command === '-h') {\n console.log(`\nBuoy MCP Server\n\nUsage:\n buoy-mcp [serve] Start the MCP server\n buoy-mcp serve --cwd <dir> Start with specific working directory\n buoy-mcp --help Show this help message\n\nThe MCP server provides design system context to AI agents:\n - Resources: tokens, components, patterns, anti-patterns\n - Tools: find_component, validate_code, resolve_token, suggest_fix\n\nClaude Code integration:\n Add to .claude/settings.json:\n {\n \"mcpServers\": {\n \"buoy\": {\n \"command\": \"npx\",\n \"args\": [\"@buoy-design/mcp\", \"serve\"]\n }\n }\n }\n`);\n process.exit(0);\n} else {\n console.error(`Unknown command: ${command}`);\n console.error('Run \"buoy-mcp --help\" for usage information');\n process.exit(1);\n}\n"],"mappings":";;;;;;AAWA,IAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,IAAM,UAAU,KAAK,CAAC,KAAK;AAE3B,IAAI,YAAY,WAAW,YAAY,QAAW;AAEhD,QAAM,WAAW,KAAK,QAAQ,OAAO;AACrC,QAAM,MAAM,aAAa,MAAM,KAAK,WAAW,CAAC,IAC5C,KAAK,WAAW,CAAC,IACjB,QAAQ,IAAI;AAEhB,cAAY,GAAG,EAAE,MAAM,CAAC,UAAU;AAChC,YAAQ,MAAM,+BAA+B,KAAK;AAClD,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AACH,WAAW,YAAY,YAAY,YAAY,MAAM;AACnD,UAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAsBb;AACC,UAAQ,KAAK,CAAC;AAChB,OAAO;AACL,UAAQ,MAAM,oBAAoB,OAAO,EAAE;AAC3C,UAAQ,MAAM,6CAA6C;AAC3D,UAAQ,KAAK,CAAC;AAChB;","names":[]}
@@ -0,0 +1,796 @@
1
+ // src/context-loader.ts
2
+ import { readFileSync, existsSync } from "fs";
3
+ import { join } from "path";
4
+ async function loadDesignSystemContext(cwd) {
5
+ const projectName = getProjectName(cwd);
6
+ const tokens = await loadTokens(cwd);
7
+ const components = await loadComponents(cwd);
8
+ const patterns = detectPatterns(components);
9
+ const antiPatterns = getAntiPatterns();
10
+ return {
11
+ tokens,
12
+ components,
13
+ patterns,
14
+ antiPatterns,
15
+ projectName,
16
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
17
+ };
18
+ }
19
+ function getProjectName(cwd) {
20
+ const pkgPath = join(cwd, "package.json");
21
+ if (existsSync(pkgPath)) {
22
+ try {
23
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
24
+ return pkg.name || "Design System";
25
+ } catch {
26
+ }
27
+ }
28
+ return "Design System";
29
+ }
30
+ async function loadTokens(cwd) {
31
+ const tokens = [];
32
+ const tokenPaths = [
33
+ "design-tokens.json",
34
+ "tokens.json",
35
+ ".buoy/tokens.json",
36
+ "tokens-ai-context.json"
37
+ ];
38
+ for (const tokenPath of tokenPaths) {
39
+ const fullPath = join(cwd, tokenPath);
40
+ if (existsSync(fullPath)) {
41
+ try {
42
+ const content = JSON.parse(readFileSync(fullPath, "utf-8"));
43
+ tokens.push(...parseTokenFile(content));
44
+ break;
45
+ } catch {
46
+ }
47
+ }
48
+ }
49
+ if (tokens.length === 0) {
50
+ tokens.push(...await scanCssTokens(cwd));
51
+ }
52
+ return tokens;
53
+ }
54
+ function parseTokenFile(content) {
55
+ const tokens = [];
56
+ if (!content || typeof content !== "object") return tokens;
57
+ if ("tokens" in content) {
58
+ const tokenObj = content.tokens;
59
+ for (const [category, categoryTokens] of Object.entries(tokenObj)) {
60
+ for (const [name, tokenData] of Object.entries(categoryTokens)) {
61
+ const data = tokenData;
62
+ tokens.push({
63
+ name,
64
+ value: String(data.$value || data.value || ""),
65
+ category,
66
+ intent: data.$intent,
67
+ usage: data.$usage,
68
+ avoid: data.$avoid,
69
+ examples: data.$examples,
70
+ deprecated: data.$deprecated
71
+ });
72
+ }
73
+ }
74
+ return tokens;
75
+ }
76
+ if (typeof content === "object") {
77
+ for (const [key, value] of Object.entries(content)) {
78
+ if (value && typeof value === "object" && "$value" in value) {
79
+ const v = value;
80
+ tokens.push({
81
+ name: key,
82
+ value: String(v.$value),
83
+ category: inferCategory(key, String(v.$value)),
84
+ usage: v.$description
85
+ });
86
+ }
87
+ }
88
+ }
89
+ return tokens;
90
+ }
91
+ function inferCategory(name, value) {
92
+ const lower = name.toLowerCase();
93
+ if (lower.includes("color") || value.startsWith("#") || value.startsWith("rgb")) {
94
+ return "color";
95
+ }
96
+ if (lower.includes("spacing") || lower.includes("space") || lower.includes("gap")) {
97
+ return "spacing";
98
+ }
99
+ if (lower.includes("font") || lower.includes("text") || lower.includes("typography")) {
100
+ return "typography";
101
+ }
102
+ if (lower.includes("radius") || lower.includes("rounded")) {
103
+ return "radius";
104
+ }
105
+ if (lower.includes("shadow")) {
106
+ return "shadow";
107
+ }
108
+ return "color";
109
+ }
110
+ async function scanCssTokens(_cwd) {
111
+ return [];
112
+ }
113
+ async function loadComponents(cwd) {
114
+ const components = [];
115
+ const inventoryPath = join(cwd, ".buoy/components.json");
116
+ if (existsSync(inventoryPath)) {
117
+ try {
118
+ const content = JSON.parse(readFileSync(inventoryPath, "utf-8"));
119
+ if (Array.isArray(content)) {
120
+ return content;
121
+ }
122
+ } catch {
123
+ }
124
+ }
125
+ const skillInventory = join(cwd, ".claude/skills/design-system/components/_inventory.md");
126
+ if (existsSync(skillInventory)) {
127
+ const content = readFileSync(skillInventory, "utf-8");
128
+ components.push(...parseInventoryMarkdown(content));
129
+ }
130
+ return components;
131
+ }
132
+ function parseInventoryMarkdown(content) {
133
+ const components = [];
134
+ const lines = content.split("\n");
135
+ for (const line of lines) {
136
+ const match = line.match(/^\|\s*`?(\w+)`?\s*\|([^|]*)\|([^|]*)\|/);
137
+ if (match && match[1] !== "Component") {
138
+ components.push({
139
+ name: match[1],
140
+ framework: "react",
141
+ // Default assumption
142
+ props: match[3].split(",").map((p) => p.trim()).filter(Boolean),
143
+ description: match[2].trim(),
144
+ path: ""
145
+ });
146
+ }
147
+ }
148
+ return components;
149
+ }
150
+ function detectPatterns(components) {
151
+ const patterns = [];
152
+ const formComponents = components.filter(
153
+ (c) => ["Input", "Select", "Checkbox", "Radio", "Form", "Label"].some(
154
+ (n) => c.name.includes(n)
155
+ )
156
+ );
157
+ if (formComponents.length > 0) {
158
+ patterns.push({
159
+ name: "Forms",
160
+ description: "Form input and validation patterns",
161
+ components: formComponents.map((c) => c.name),
162
+ usage: "Use for user input collection with consistent styling and validation"
163
+ });
164
+ }
165
+ const navComponents = components.filter(
166
+ (c) => ["Nav", "Menu", "Sidebar", "Header", "Footer", "Tab", "Breadcrumb"].some(
167
+ (n) => c.name.includes(n)
168
+ )
169
+ );
170
+ if (navComponents.length > 0) {
171
+ patterns.push({
172
+ name: "Navigation",
173
+ description: "Navigation and menu patterns",
174
+ components: navComponents.map((c) => c.name),
175
+ usage: "Use for site navigation with consistent structure"
176
+ });
177
+ }
178
+ const cardComponents = components.filter(
179
+ (c) => ["Card", "Panel", "Box", "Container"].some((n) => c.name.includes(n))
180
+ );
181
+ if (cardComponents.length > 0) {
182
+ patterns.push({
183
+ name: "Cards",
184
+ description: "Content container patterns",
185
+ components: cardComponents.map((c) => c.name),
186
+ usage: "Use for grouping related content"
187
+ });
188
+ }
189
+ const modalComponents = components.filter(
190
+ (c) => ["Modal", "Dialog", "Drawer", "Sheet", "Popover"].some((n) => c.name.includes(n))
191
+ );
192
+ if (modalComponents.length > 0) {
193
+ patterns.push({
194
+ name: "Modals",
195
+ description: "Overlay and dialog patterns",
196
+ components: modalComponents.map((c) => c.name),
197
+ usage: "Use for focused interactions that require attention"
198
+ });
199
+ }
200
+ return patterns;
201
+ }
202
+ function getAntiPatterns() {
203
+ return [
204
+ {
205
+ name: "Hardcoded Colors",
206
+ description: "Using hex/rgb values directly instead of design tokens",
207
+ avoid: 'style={{ color: "#2563EB" }} or color: #2563EB',
208
+ instead: 'Use color tokens: className="text-primary" or color={tokens.primary}',
209
+ severity: "warning"
210
+ },
211
+ {
212
+ name: "Arbitrary Spacing",
213
+ description: "Using pixel values not in the spacing scale",
214
+ avoid: "padding: 13px or p-[13px]",
215
+ instead: "Use spacing scale: p-4 (16px) or p-3 (12px)",
216
+ severity: "warning"
217
+ },
218
+ {
219
+ name: "Inline onClick Handlers",
220
+ description: "Using div/span with onClick instead of semantic elements",
221
+ avoid: "<div onClick={handleClick}>Click me</div>",
222
+ instead: "Use <Button> or <button> for clickable elements",
223
+ severity: "critical"
224
+ },
225
+ {
226
+ name: "Missing Alt Text",
227
+ description: "Images without alt attributes",
228
+ avoid: '<img src="logo.png" />',
229
+ instead: '<img src="logo.png" alt="Company logo" />',
230
+ severity: "critical"
231
+ },
232
+ {
233
+ name: "Custom Component Creation",
234
+ description: "Creating new components when existing ones would work",
235
+ avoid: "Creating MyButton.tsx when Button component exists",
236
+ instead: "Check component inventory first, extend existing if needed",
237
+ severity: "info"
238
+ },
239
+ {
240
+ name: "Inconsistent Naming",
241
+ description: "Component names that dont follow project conventions",
242
+ avoid: "my-component.tsx or MyComponent.jsx",
243
+ instead: "Follow project naming: ComponentName.tsx",
244
+ severity: "info"
245
+ }
246
+ ];
247
+ }
248
+ function getTokensByCategory(context, category) {
249
+ return context.tokens.filter((t) => t.category === category);
250
+ }
251
+ function findComponent(context, name) {
252
+ return context.components.find(
253
+ (c) => c.name.toLowerCase() === name.toLowerCase()
254
+ );
255
+ }
256
+ function searchComponents(context, useCase) {
257
+ const keywords = useCase.toLowerCase().split(/\s+/);
258
+ return context.components.filter((c) => {
259
+ const searchText = `${c.name} ${c.description || ""} ${c.props.join(" ")}`.toLowerCase();
260
+ return keywords.some((kw) => searchText.includes(kw));
261
+ });
262
+ }
263
+
264
+ // src/server.ts
265
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
266
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
267
+ import {
268
+ CallToolRequestSchema,
269
+ ListResourcesRequestSchema,
270
+ ListToolsRequestSchema,
271
+ ReadResourceRequestSchema
272
+ } from "@modelcontextprotocol/sdk/types.js";
273
+ function createServer(cwd = process.cwd()) {
274
+ const server = new Server(
275
+ {
276
+ name: "buoy-design-system",
277
+ version: "0.1.0"
278
+ },
279
+ {
280
+ capabilities: {
281
+ resources: {},
282
+ tools: {}
283
+ }
284
+ }
285
+ );
286
+ let context = null;
287
+ async function getContext() {
288
+ if (!context) {
289
+ context = await loadDesignSystemContext(cwd);
290
+ }
291
+ return context;
292
+ }
293
+ server.setRequestHandler(ListResourcesRequestSchema, async () => {
294
+ return {
295
+ resources: [
296
+ {
297
+ uri: "tokens://all",
298
+ name: "All Design Tokens",
299
+ description: "Complete list of design tokens with usage guidance",
300
+ mimeType: "application/json"
301
+ },
302
+ {
303
+ uri: "tokens://color",
304
+ name: "Color Tokens",
305
+ description: "Color tokens with semantic meaning",
306
+ mimeType: "application/json"
307
+ },
308
+ {
309
+ uri: "tokens://spacing",
310
+ name: "Spacing Tokens",
311
+ description: "Spacing scale for consistent layouts",
312
+ mimeType: "application/json"
313
+ },
314
+ {
315
+ uri: "tokens://typography",
316
+ name: "Typography Tokens",
317
+ description: "Font sizes, weights, and families",
318
+ mimeType: "application/json"
319
+ },
320
+ {
321
+ uri: "components://inventory",
322
+ name: "Component Inventory",
323
+ description: "All available UI components",
324
+ mimeType: "application/json"
325
+ },
326
+ {
327
+ uri: "patterns://all",
328
+ name: "Pattern Library",
329
+ description: "Common UI patterns and compositions",
330
+ mimeType: "application/json"
331
+ },
332
+ {
333
+ uri: "antipatterns://all",
334
+ name: "Anti-Patterns",
335
+ description: "Things to avoid in this design system",
336
+ mimeType: "application/json"
337
+ }
338
+ ]
339
+ };
340
+ });
341
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
342
+ const ctx = await getContext();
343
+ const uri = request.params.uri;
344
+ if (uri === "tokens://all") {
345
+ return {
346
+ contents: [
347
+ {
348
+ uri,
349
+ mimeType: "application/json",
350
+ text: JSON.stringify(ctx.tokens, null, 2)
351
+ }
352
+ ]
353
+ };
354
+ }
355
+ if (uri.startsWith("tokens://")) {
356
+ const category = uri.replace("tokens://", "");
357
+ const tokens = getTokensByCategory(ctx, category);
358
+ return {
359
+ contents: [
360
+ {
361
+ uri,
362
+ mimeType: "application/json",
363
+ text: JSON.stringify(tokens, null, 2)
364
+ }
365
+ ]
366
+ };
367
+ }
368
+ if (uri === "components://inventory") {
369
+ return {
370
+ contents: [
371
+ {
372
+ uri,
373
+ mimeType: "application/json",
374
+ text: JSON.stringify(ctx.components, null, 2)
375
+ }
376
+ ]
377
+ };
378
+ }
379
+ if (uri.startsWith("components://")) {
380
+ const name = uri.replace("components://", "");
381
+ const component = findComponent(ctx, name);
382
+ return {
383
+ contents: [
384
+ {
385
+ uri,
386
+ mimeType: "application/json",
387
+ text: component ? JSON.stringify(component, null, 2) : JSON.stringify({ error: `Component "${name}" not found` })
388
+ }
389
+ ]
390
+ };
391
+ }
392
+ if (uri === "patterns://all") {
393
+ return {
394
+ contents: [
395
+ {
396
+ uri,
397
+ mimeType: "application/json",
398
+ text: JSON.stringify(ctx.patterns, null, 2)
399
+ }
400
+ ]
401
+ };
402
+ }
403
+ if (uri === "antipatterns://all") {
404
+ return {
405
+ contents: [
406
+ {
407
+ uri,
408
+ mimeType: "application/json",
409
+ text: JSON.stringify(ctx.antiPatterns, null, 2)
410
+ }
411
+ ]
412
+ };
413
+ }
414
+ throw new Error(`Unknown resource: ${uri}`);
415
+ });
416
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
417
+ return {
418
+ tools: [
419
+ {
420
+ name: "find_component",
421
+ description: "Find the best component for a use case. Returns recommended component with alternatives.",
422
+ inputSchema: {
423
+ type: "object",
424
+ properties: {
425
+ useCase: {
426
+ type: "string",
427
+ description: 'Description of what you want to build (e.g., "submit button", "form input")'
428
+ },
429
+ constraints: {
430
+ type: "array",
431
+ items: { type: "string" },
432
+ description: 'Optional constraints (e.g., "accessible", "responsive")'
433
+ }
434
+ },
435
+ required: ["useCase"]
436
+ }
437
+ },
438
+ {
439
+ name: "validate_code",
440
+ description: "Validate code against design system rules. Returns issues and suggestions.",
441
+ inputSchema: {
442
+ type: "object",
443
+ properties: {
444
+ code: {
445
+ type: "string",
446
+ description: "The code to validate"
447
+ },
448
+ filePath: {
449
+ type: "string",
450
+ description: "Optional file path for context"
451
+ }
452
+ },
453
+ required: ["code"]
454
+ }
455
+ },
456
+ {
457
+ name: "resolve_token",
458
+ description: "Find the design token that matches a hardcoded value. Returns exact or closest match.",
459
+ inputSchema: {
460
+ type: "object",
461
+ properties: {
462
+ value: {
463
+ type: "string",
464
+ description: 'The hardcoded value (e.g., "#2563EB", "16px")'
465
+ },
466
+ context: {
467
+ type: "string",
468
+ enum: ["color", "spacing", "typography"],
469
+ description: "Optional hint about value type"
470
+ }
471
+ },
472
+ required: ["value"]
473
+ }
474
+ },
475
+ {
476
+ name: "suggest_fix",
477
+ description: "Get a fix suggestion for a design system violation.",
478
+ inputSchema: {
479
+ type: "object",
480
+ properties: {
481
+ type: {
482
+ type: "string",
483
+ description: 'Type of violation (e.g., "hardcoded-color", "arbitrary-spacing")'
484
+ },
485
+ value: {
486
+ type: "string",
487
+ description: "The problematic value"
488
+ },
489
+ location: {
490
+ type: "string",
491
+ description: "Where the violation occurs (file:line)"
492
+ }
493
+ },
494
+ required: ["type", "value"]
495
+ }
496
+ }
497
+ ]
498
+ };
499
+ });
500
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
501
+ const ctx = await getContext();
502
+ const { name, arguments: args } = request.params;
503
+ switch (name) {
504
+ case "find_component": {
505
+ const { useCase, constraints } = args;
506
+ const result = handleFindComponent(ctx, useCase, constraints);
507
+ return {
508
+ content: [
509
+ {
510
+ type: "text",
511
+ text: JSON.stringify(result, null, 2)
512
+ }
513
+ ]
514
+ };
515
+ }
516
+ case "validate_code": {
517
+ const { code, filePath } = args;
518
+ const result = handleValidateCode(ctx, code, filePath);
519
+ return {
520
+ content: [
521
+ {
522
+ type: "text",
523
+ text: JSON.stringify(result, null, 2)
524
+ }
525
+ ]
526
+ };
527
+ }
528
+ case "resolve_token": {
529
+ const { value, context: tokenContext } = args;
530
+ const result = handleResolveToken(ctx, value, tokenContext);
531
+ return {
532
+ content: [
533
+ {
534
+ type: "text",
535
+ text: JSON.stringify(result, null, 2)
536
+ }
537
+ ]
538
+ };
539
+ }
540
+ case "suggest_fix": {
541
+ const { type, value, location } = args;
542
+ const result = handleSuggestFix(ctx, type, value, location);
543
+ return {
544
+ content: [
545
+ {
546
+ type: "text",
547
+ text: JSON.stringify(result, null, 2)
548
+ }
549
+ ]
550
+ };
551
+ }
552
+ default:
553
+ throw new Error(`Unknown tool: ${name}`);
554
+ }
555
+ });
556
+ return server;
557
+ }
558
+ function handleFindComponent(ctx, useCase, constraints) {
559
+ const matches = searchComponents(ctx, useCase);
560
+ if (matches.length === 0) {
561
+ const availableComponents = ctx.components.slice(0, 5).map((c) => c.name);
562
+ return {
563
+ recommended: null,
564
+ alternatives: [],
565
+ reasoning: `No existing component found for "${useCase}".`,
566
+ guidance: {
567
+ suggestion: "Consider creating a new component or composing existing ones.",
568
+ availableComponents: availableComponents.length > 0 ? `Available components include: ${availableComponents.join(", ")}` : "No components in inventory. Run `buoy scan` to discover components.",
569
+ nextSteps: ctx.components.length === 0 ? ["Run `buoy scan` to discover components", "Run `buoy skill export` to populate component inventory"] : ["Check component naming - try broader search terms", "View full inventory with components://inventory"]
570
+ }
571
+ };
572
+ }
573
+ const scored = matches.map((c) => ({
574
+ component: c,
575
+ score: calculateMatchScore(c, useCase, constraints)
576
+ }));
577
+ scored.sort((a, b) => b.score - a.score);
578
+ const recommended = scored[0].component;
579
+ const alternatives = scored.slice(1, 4).map((s) => s.component);
580
+ return {
581
+ recommended,
582
+ alternatives,
583
+ reasoning: `"${recommended.name}" is the best match for "${useCase}". ${recommended.description || ""}`
584
+ };
585
+ }
586
+ function calculateMatchScore(component, useCase, constraints) {
587
+ let score = 0;
588
+ const searchText = `${component.name} ${component.description || ""} ${component.props.join(" ")}`.toLowerCase();
589
+ const useCaseLower = useCase.toLowerCase();
590
+ if (component.name.toLowerCase().includes(useCaseLower)) {
591
+ score += 10;
592
+ }
593
+ const keywords = useCaseLower.split(/\s+/);
594
+ for (const keyword of keywords) {
595
+ if (searchText.includes(keyword)) {
596
+ score += 2;
597
+ }
598
+ }
599
+ if (constraints) {
600
+ for (const constraint of constraints) {
601
+ if (searchText.includes(constraint.toLowerCase())) {
602
+ score += 3;
603
+ }
604
+ }
605
+ }
606
+ return score;
607
+ }
608
+ function handleValidateCode(ctx, code, _filePath) {
609
+ const issues = [];
610
+ const hexColors = code.match(/#[0-9A-Fa-f]{3,8}\b/g) || [];
611
+ const rgbColors = code.match(/rgb\([^)]+\)/g) || [];
612
+ for (const color of [...hexColors, ...rgbColors]) {
613
+ const isToken = ctx.tokens.some((t) => t.value.toLowerCase() === color.toLowerCase());
614
+ if (!isToken) {
615
+ const match = findClosestToken(ctx, color, "color");
616
+ issues.push({
617
+ type: "hardcoded-color",
618
+ severity: "warning",
619
+ message: `Hardcoded color "${color}" - use design token instead`,
620
+ suggestion: match ? `Use token: ${match.name} (${match.value})` : void 0
621
+ });
622
+ }
623
+ }
624
+ const arbitrarySpacing = code.match(/\b\d+px\b/g) || [];
625
+ const spacingScale = ctx.tokens.filter((t) => t.category === "spacing").map((t) => t.value);
626
+ for (const spacing of arbitrarySpacing) {
627
+ if (!spacingScale.includes(spacing)) {
628
+ const match = findClosestToken(ctx, spacing, "spacing");
629
+ issues.push({
630
+ type: "arbitrary-spacing",
631
+ severity: "warning",
632
+ message: `Arbitrary spacing "${spacing}" - use spacing scale`,
633
+ suggestion: match ? `Use token: ${match.name} (${match.value})` : void 0
634
+ });
635
+ }
636
+ }
637
+ if (/<div[^>]*onClick/i.test(code)) {
638
+ issues.push({
639
+ type: "accessibility",
640
+ severity: "critical",
641
+ message: "Using div with onClick - use button or Button component",
642
+ suggestion: "Replace <div onClick> with <Button onClick>"
643
+ });
644
+ }
645
+ if (/<img[^>]*(?!alt)[^>]*>/i.test(code) && !/<img[^>]*alt=/i.test(code)) {
646
+ issues.push({
647
+ type: "accessibility",
648
+ severity: "critical",
649
+ message: "Image missing alt attribute",
650
+ suggestion: 'Add alt="description" to img element'
651
+ });
652
+ }
653
+ const checksPerformed = [
654
+ "Hardcoded colors",
655
+ "Arbitrary spacing values",
656
+ "Accessibility anti-patterns (div onClick, img alt)"
657
+ ];
658
+ return {
659
+ valid: issues.length === 0,
660
+ issues,
661
+ summary: {
662
+ total: issues.length,
663
+ critical: issues.filter((i) => i.severity === "critical").length,
664
+ warning: issues.filter((i) => i.severity === "warning").length,
665
+ info: issues.filter((i) => i.severity === "info").length
666
+ },
667
+ context: {
668
+ checksPerformed,
669
+ tokensAvailable: ctx.tokens.length,
670
+ componentsKnown: ctx.components.length,
671
+ guidance: issues.length === 0 ? "Code follows design system rules. Run `buoy check` for comprehensive analysis." : "Fix issues above, then re-validate. Run `buoy fix --dry-run` for automated suggestions."
672
+ }
673
+ };
674
+ }
675
+ function handleResolveToken(ctx, value, tokenContext) {
676
+ const candidates = tokenContext ? ctx.tokens.filter((t) => t.category === tokenContext) : ctx.tokens;
677
+ const exactMatch = candidates.find(
678
+ (t) => t.value.toLowerCase() === value.toLowerCase()
679
+ );
680
+ if (exactMatch) {
681
+ return {
682
+ exactMatch,
683
+ closestMatches: [],
684
+ suggestion: `Use token: ${exactMatch.name}`
685
+ };
686
+ }
687
+ const closest = findClosestToken(ctx, value, tokenContext);
688
+ if (closest) {
689
+ return {
690
+ exactMatch: null,
691
+ closestMatches: [{ token: closest, similarity: 0.8 }],
692
+ suggestion: `Closest token: ${closest.name} (${closest.value})`
693
+ };
694
+ }
695
+ const availableCategories = [...new Set(ctx.tokens.map((t) => t.category))];
696
+ return {
697
+ exactMatch: null,
698
+ closestMatches: [],
699
+ suggestion: `No matching token found for "${value}".`,
700
+ guidance: {
701
+ tokenCount: ctx.tokens.length,
702
+ availableCategories: availableCategories.length > 0 ? availableCategories : ["No tokens loaded"],
703
+ nextSteps: ctx.tokens.length === 0 ? [
704
+ "Run `buoy tokens` to extract tokens from hardcoded values",
705
+ "Add a design-tokens.json file",
706
+ "Run `buoy scan` to discover tokens from CSS"
707
+ ] : [
708
+ "Consider adding a new token for this value",
709
+ "Use the closest available value from the scale",
710
+ `View available tokens: tokens://${tokenContext || "all"}`
711
+ ]
712
+ }
713
+ };
714
+ }
715
+ function findClosestToken(ctx, value, category) {
716
+ const candidates = category ? ctx.tokens.filter((t) => t.category === category) : ctx.tokens;
717
+ if (candidates.length === 0) return null;
718
+ if (value.startsWith("#") || value.startsWith("rgb")) {
719
+ return candidates[0];
720
+ }
721
+ const numericValue = parseFloat(value);
722
+ if (!isNaN(numericValue)) {
723
+ let closest = candidates[0];
724
+ let closestDiff = Infinity;
725
+ for (const token of candidates) {
726
+ const tokenValue = parseFloat(token.value);
727
+ if (!isNaN(tokenValue)) {
728
+ const diff = Math.abs(tokenValue - numericValue);
729
+ if (diff < closestDiff) {
730
+ closestDiff = diff;
731
+ closest = token;
732
+ }
733
+ }
734
+ }
735
+ return closest;
736
+ }
737
+ return candidates[0];
738
+ }
739
+ function handleSuggestFix(ctx, type, value, location) {
740
+ let category;
741
+ if (type.includes("color")) category = "color";
742
+ else if (type.includes("spacing")) category = "spacing";
743
+ else if (type.includes("font") || type.includes("typography")) category = "typography";
744
+ const closest = findClosestToken(ctx, value, category);
745
+ if (!closest) {
746
+ return {
747
+ fix: null,
748
+ explanation: `No suitable token found for "${value}"`,
749
+ alternatives: [],
750
+ guidance: {
751
+ tokenCount: ctx.tokens.length,
752
+ categorySearched: category || "all",
753
+ nextSteps: ctx.tokens.length === 0 ? [
754
+ "Run `buoy tokens` to extract tokens from codebase",
755
+ "Add a design-tokens.json file",
756
+ "Manual fix: replace with CSS variable or theme token"
757
+ ] : [
758
+ "Value may be intentionally one-off (consider documenting)",
759
+ "Run `buoy fix --confidence low` to see all suggestions",
760
+ "Create a new token for this value if it will be reused"
761
+ ]
762
+ }
763
+ };
764
+ }
765
+ let replacement = closest.name;
766
+ if (type.includes("color")) {
767
+ replacement = `var(--${closest.name})`;
768
+ } else if (type.includes("class")) {
769
+ replacement = closest.name.replace(/^(color|spacing|font)-/, "");
770
+ }
771
+ return {
772
+ fix: {
773
+ type: "replace",
774
+ original: value,
775
+ replacement,
776
+ confidence: 0.85
777
+ },
778
+ explanation: `Replace hardcoded value with design token "${closest.name}"${location ? ` at ${location}` : ""}`,
779
+ alternatives: ctx.tokens.filter((t) => t.category === category && t.name !== closest.name).slice(0, 3).map((t) => t.name)
780
+ };
781
+ }
782
+ async function startServer(cwd = process.cwd()) {
783
+ const server = createServer(cwd);
784
+ const transport = new StdioServerTransport();
785
+ await server.connect(transport);
786
+ }
787
+
788
+ export {
789
+ loadDesignSystemContext,
790
+ getTokensByCategory,
791
+ findComponent,
792
+ searchComponents,
793
+ createServer,
794
+ startServer
795
+ };
796
+ //# sourceMappingURL=chunk-RDI5XKIN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/context-loader.ts","../src/server.ts"],"sourcesContent":["/**\n * Context loader - gathers design system information from the codebase\n */\n\nimport { readFileSync, existsSync } from 'fs';\nimport { join } from 'path';\nimport type {\n DesignSystemContext,\n TokenWithIntent,\n ComponentSummary,\n Pattern,\n AntiPattern,\n} from './types.js';\n\n/**\n * Load design system context from the project\n */\nexport async function loadDesignSystemContext(\n cwd: string\n): Promise<DesignSystemContext> {\n const projectName = getProjectName(cwd);\n const tokens = await loadTokens(cwd);\n const components = await loadComponents(cwd);\n const patterns = detectPatterns(components);\n const antiPatterns = getAntiPatterns();\n\n return {\n tokens,\n components,\n patterns,\n antiPatterns,\n projectName,\n lastUpdated: new Date().toISOString(),\n };\n}\n\n/**\n * Get project name from package.json\n */\nfunction getProjectName(cwd: string): string {\n const pkgPath = join(cwd, 'package.json');\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n return pkg.name || 'Design System';\n } catch {\n // Ignore parse errors\n }\n }\n return 'Design System';\n}\n\n/**\n * Load tokens from various sources\n */\nasync function loadTokens(cwd: string): Promise<TokenWithIntent[]> {\n const tokens: TokenWithIntent[] = [];\n\n // Try to load from exported tokens file\n const tokenPaths = [\n 'design-tokens.json',\n 'tokens.json',\n '.buoy/tokens.json',\n 'tokens-ai-context.json',\n ];\n\n for (const tokenPath of tokenPaths) {\n const fullPath = join(cwd, tokenPath);\n if (existsSync(fullPath)) {\n try {\n const content = JSON.parse(readFileSync(fullPath, 'utf-8'));\n tokens.push(...parseTokenFile(content));\n break;\n } catch {\n // Continue to next path\n }\n }\n }\n\n // If no token file found, try to scan CSS files\n if (tokens.length === 0) {\n tokens.push(...(await scanCssTokens(cwd)));\n }\n\n return tokens;\n}\n\n/**\n * Parse token file (supports multiple formats)\n */\nfunction parseTokenFile(content: unknown): TokenWithIntent[] {\n const tokens: TokenWithIntent[] = [];\n\n if (!content || typeof content !== 'object') return tokens;\n\n // AI context format\n if ('tokens' in (content as Record<string, unknown>)) {\n const tokenObj = (content as { tokens: Record<string, Record<string, unknown>> }).tokens;\n for (const [category, categoryTokens] of Object.entries(tokenObj)) {\n for (const [name, tokenData] of Object.entries(categoryTokens as Record<string, unknown>)) {\n const data = tokenData as Record<string, unknown>;\n tokens.push({\n name,\n value: String(data.$value || data.value || ''),\n category: category as TokenWithIntent['category'],\n intent: data.$intent as TokenWithIntent['intent'],\n usage: data.$usage as string | undefined,\n avoid: data.$avoid as string | undefined,\n examples: data.$examples as string[] | undefined,\n deprecated: data.$deprecated as boolean | undefined,\n });\n }\n }\n return tokens;\n }\n\n // W3C DTCG format\n if (typeof content === 'object') {\n for (const [key, value] of Object.entries(content as Record<string, unknown>)) {\n if (value && typeof value === 'object' && '$value' in value) {\n const v = value as Record<string, unknown>;\n tokens.push({\n name: key,\n value: String(v.$value),\n category: inferCategory(key, String(v.$value)),\n usage: v.$description as string | undefined,\n });\n }\n }\n }\n\n return tokens;\n}\n\n/**\n * Infer token category from name and value\n */\nfunction inferCategory(name: string, value: string): TokenWithIntent['category'] {\n const lower = name.toLowerCase();\n if (lower.includes('color') || value.startsWith('#') || value.startsWith('rgb')) {\n return 'color';\n }\n if (lower.includes('spacing') || lower.includes('space') || lower.includes('gap')) {\n return 'spacing';\n }\n if (lower.includes('font') || lower.includes('text') || lower.includes('typography')) {\n return 'typography';\n }\n if (lower.includes('radius') || lower.includes('rounded')) {\n return 'radius';\n }\n if (lower.includes('shadow')) {\n return 'shadow';\n }\n return 'color'; // Default\n}\n\n/**\n * Scan CSS files for tokens (fallback)\n */\nasync function scanCssTokens(_cwd: string): Promise<TokenWithIntent[]> {\n // This would scan CSS files for custom properties\n // Simplified for now - real implementation would use the scanners package\n return [];\n}\n\n/**\n * Load components from the codebase\n */\nasync function loadComponents(cwd: string): Promise<ComponentSummary[]> {\n const components: ComponentSummary[] = [];\n\n // Try to load from cached component inventory\n const inventoryPath = join(cwd, '.buoy/components.json');\n if (existsSync(inventoryPath)) {\n try {\n const content = JSON.parse(readFileSync(inventoryPath, 'utf-8'));\n if (Array.isArray(content)) {\n return content as ComponentSummary[];\n }\n } catch {\n // Continue to scanning\n }\n }\n\n // Check for skill-generated inventory\n const skillInventory = join(cwd, '.claude/skills/design-system/components/_inventory.md');\n if (existsSync(skillInventory)) {\n const content = readFileSync(skillInventory, 'utf-8');\n components.push(...parseInventoryMarkdown(content));\n }\n\n return components;\n}\n\n/**\n * Parse component inventory from markdown\n */\nfunction parseInventoryMarkdown(content: string): ComponentSummary[] {\n const components: ComponentSummary[] = [];\n const lines = content.split('\\n');\n\n for (const line of lines) {\n // Parse table rows: | ComponentName | Description | Props |\n const match = line.match(/^\\|\\s*`?(\\w+)`?\\s*\\|([^|]*)\\|([^|]*)\\|/);\n if (match && match[1] !== 'Component') {\n components.push({\n name: match[1],\n framework: 'react', // Default assumption\n props: match[3].split(',').map(p => p.trim()).filter(Boolean),\n description: match[2].trim(),\n path: '',\n });\n }\n }\n\n return components;\n}\n\n/**\n * Detect patterns from component usage\n */\nfunction detectPatterns(components: ComponentSummary[]): Pattern[] {\n const patterns: Pattern[] = [];\n\n // Form pattern\n const formComponents = components.filter(c =>\n ['Input', 'Select', 'Checkbox', 'Radio', 'Form', 'Label'].some(n =>\n c.name.includes(n)\n )\n );\n if (formComponents.length > 0) {\n patterns.push({\n name: 'Forms',\n description: 'Form input and validation patterns',\n components: formComponents.map(c => c.name),\n usage: 'Use for user input collection with consistent styling and validation',\n });\n }\n\n // Navigation pattern\n const navComponents = components.filter(c =>\n ['Nav', 'Menu', 'Sidebar', 'Header', 'Footer', 'Tab', 'Breadcrumb'].some(n =>\n c.name.includes(n)\n )\n );\n if (navComponents.length > 0) {\n patterns.push({\n name: 'Navigation',\n description: 'Navigation and menu patterns',\n components: navComponents.map(c => c.name),\n usage: 'Use for site navigation with consistent structure',\n });\n }\n\n // Card pattern\n const cardComponents = components.filter(c =>\n ['Card', 'Panel', 'Box', 'Container'].some(n => c.name.includes(n))\n );\n if (cardComponents.length > 0) {\n patterns.push({\n name: 'Cards',\n description: 'Content container patterns',\n components: cardComponents.map(c => c.name),\n usage: 'Use for grouping related content',\n });\n }\n\n // Modal pattern\n const modalComponents = components.filter(c =>\n ['Modal', 'Dialog', 'Drawer', 'Sheet', 'Popover'].some(n => c.name.includes(n))\n );\n if (modalComponents.length > 0) {\n patterns.push({\n name: 'Modals',\n description: 'Overlay and dialog patterns',\n components: modalComponents.map(c => c.name),\n usage: 'Use for focused interactions that require attention',\n });\n }\n\n return patterns;\n}\n\n/**\n * Get common anti-patterns to avoid\n */\nfunction getAntiPatterns(): AntiPattern[] {\n return [\n {\n name: 'Hardcoded Colors',\n description: 'Using hex/rgb values directly instead of design tokens',\n avoid: 'style={{ color: \"#2563EB\" }} or color: #2563EB',\n instead: 'Use color tokens: className=\"text-primary\" or color={tokens.primary}',\n severity: 'warning',\n },\n {\n name: 'Arbitrary Spacing',\n description: 'Using pixel values not in the spacing scale',\n avoid: 'padding: 13px or p-[13px]',\n instead: 'Use spacing scale: p-4 (16px) or p-3 (12px)',\n severity: 'warning',\n },\n {\n name: 'Inline onClick Handlers',\n description: 'Using div/span with onClick instead of semantic elements',\n avoid: '<div onClick={handleClick}>Click me</div>',\n instead: 'Use <Button> or <button> for clickable elements',\n severity: 'critical',\n },\n {\n name: 'Missing Alt Text',\n description: 'Images without alt attributes',\n avoid: '<img src=\"logo.png\" />',\n instead: '<img src=\"logo.png\" alt=\"Company logo\" />',\n severity: 'critical',\n },\n {\n name: 'Custom Component Creation',\n description: 'Creating new components when existing ones would work',\n avoid: 'Creating MyButton.tsx when Button component exists',\n instead: 'Check component inventory first, extend existing if needed',\n severity: 'info',\n },\n {\n name: 'Inconsistent Naming',\n description: 'Component names that dont follow project conventions',\n avoid: 'my-component.tsx or MyComponent.jsx',\n instead: 'Follow project naming: ComponentName.tsx',\n severity: 'info',\n },\n ];\n}\n\n/**\n * Get tokens by category\n */\nexport function getTokensByCategory(\n context: DesignSystemContext,\n category: string\n): TokenWithIntent[] {\n return context.tokens.filter(t => t.category === category);\n}\n\n/**\n * Find component by name\n */\nexport function findComponent(\n context: DesignSystemContext,\n name: string\n): ComponentSummary | undefined {\n return context.components.find(\n c => c.name.toLowerCase() === name.toLowerCase()\n );\n}\n\n/**\n * Search components by use case\n */\nexport function searchComponents(\n context: DesignSystemContext,\n useCase: string\n): ComponentSummary[] {\n const keywords = useCase.toLowerCase().split(/\\s+/);\n\n return context.components.filter(c => {\n const searchText = `${c.name} ${c.description || ''} ${c.props.join(' ')}`.toLowerCase();\n return keywords.some(kw => searchText.includes(kw));\n });\n}\n","/**\n * Buoy MCP Server\n *\n * Provides design system context to AI agents via Model Context Protocol.\n *\n * Resources:\n * - tokens://all - All design tokens\n * - tokens://{category} - Tokens by category (color, spacing, typography)\n * - components://inventory - Component catalog\n * - components://{name} - Component details\n * - patterns://all - Pattern library\n * - antipatterns://all - Anti-patterns to avoid\n *\n * Tools:\n * - find_component - Find best component for a use case\n * - validate_code - Check code against design system\n * - resolve_token - Find token for a hardcoded value\n * - suggest_fix - Get fix suggestion for drift\n */\n\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport {\n CallToolRequestSchema,\n ListResourcesRequestSchema,\n ListToolsRequestSchema,\n ReadResourceRequestSchema,\n} from '@modelcontextprotocol/sdk/types.js';\n\nimport {\n loadDesignSystemContext,\n getTokensByCategory,\n findComponent,\n searchComponents,\n} from './context-loader.js';\nimport type {\n DesignSystemContext,\n FindComponentRequest,\n FindComponentResponse,\n ValidateCodeRequest,\n ValidateCodeResponse,\n ResolveTokenRequest,\n ResolveTokenResponse,\n} from './types.js';\n\n/**\n * Create and configure the Buoy MCP server\n */\nexport function createServer(cwd: string = process.cwd()): Server {\n const server = new Server(\n {\n name: 'buoy-design-system',\n version: '0.1.0',\n },\n {\n capabilities: {\n resources: {},\n tools: {},\n },\n }\n );\n\n let context: DesignSystemContext | null = null;\n\n /**\n * Load context on demand\n */\n async function getContext(): Promise<DesignSystemContext> {\n if (!context) {\n context = await loadDesignSystemContext(cwd);\n }\n return context;\n }\n\n /**\n * List available resources\n */\n server.setRequestHandler(ListResourcesRequestSchema, async () => {\n return {\n resources: [\n {\n uri: 'tokens://all',\n name: 'All Design Tokens',\n description: 'Complete list of design tokens with usage guidance',\n mimeType: 'application/json',\n },\n {\n uri: 'tokens://color',\n name: 'Color Tokens',\n description: 'Color tokens with semantic meaning',\n mimeType: 'application/json',\n },\n {\n uri: 'tokens://spacing',\n name: 'Spacing Tokens',\n description: 'Spacing scale for consistent layouts',\n mimeType: 'application/json',\n },\n {\n uri: 'tokens://typography',\n name: 'Typography Tokens',\n description: 'Font sizes, weights, and families',\n mimeType: 'application/json',\n },\n {\n uri: 'components://inventory',\n name: 'Component Inventory',\n description: 'All available UI components',\n mimeType: 'application/json',\n },\n {\n uri: 'patterns://all',\n name: 'Pattern Library',\n description: 'Common UI patterns and compositions',\n mimeType: 'application/json',\n },\n {\n uri: 'antipatterns://all',\n name: 'Anti-Patterns',\n description: 'Things to avoid in this design system',\n mimeType: 'application/json',\n },\n ],\n };\n });\n\n /**\n * Read resource content\n */\n server.setRequestHandler(ReadResourceRequestSchema, async (request) => {\n const ctx = await getContext();\n const uri = request.params.uri;\n\n // Tokens resources\n if (uri === 'tokens://all') {\n return {\n contents: [\n {\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(ctx.tokens, null, 2),\n },\n ],\n };\n }\n\n if (uri.startsWith('tokens://')) {\n const category = uri.replace('tokens://', '');\n const tokens = getTokensByCategory(ctx, category);\n return {\n contents: [\n {\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(tokens, null, 2),\n },\n ],\n };\n }\n\n // Components resources\n if (uri === 'components://inventory') {\n return {\n contents: [\n {\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(ctx.components, null, 2),\n },\n ],\n };\n }\n\n if (uri.startsWith('components://')) {\n const name = uri.replace('components://', '');\n const component = findComponent(ctx, name);\n return {\n contents: [\n {\n uri,\n mimeType: 'application/json',\n text: component\n ? JSON.stringify(component, null, 2)\n : JSON.stringify({ error: `Component \"${name}\" not found` }),\n },\n ],\n };\n }\n\n // Patterns resources\n if (uri === 'patterns://all') {\n return {\n contents: [\n {\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(ctx.patterns, null, 2),\n },\n ],\n };\n }\n\n // Anti-patterns resources\n if (uri === 'antipatterns://all') {\n return {\n contents: [\n {\n uri,\n mimeType: 'application/json',\n text: JSON.stringify(ctx.antiPatterns, null, 2),\n },\n ],\n };\n }\n\n throw new Error(`Unknown resource: ${uri}`);\n });\n\n /**\n * List available tools\n */\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n return {\n tools: [\n {\n name: 'find_component',\n description:\n 'Find the best component for a use case. Returns recommended component with alternatives.',\n inputSchema: {\n type: 'object',\n properties: {\n useCase: {\n type: 'string',\n description: 'Description of what you want to build (e.g., \"submit button\", \"form input\")',\n },\n constraints: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional constraints (e.g., \"accessible\", \"responsive\")',\n },\n },\n required: ['useCase'],\n },\n },\n {\n name: 'validate_code',\n description:\n 'Validate code against design system rules. Returns issues and suggestions.',\n inputSchema: {\n type: 'object',\n properties: {\n code: {\n type: 'string',\n description: 'The code to validate',\n },\n filePath: {\n type: 'string',\n description: 'Optional file path for context',\n },\n },\n required: ['code'],\n },\n },\n {\n name: 'resolve_token',\n description:\n 'Find the design token that matches a hardcoded value. Returns exact or closest match.',\n inputSchema: {\n type: 'object',\n properties: {\n value: {\n type: 'string',\n description: 'The hardcoded value (e.g., \"#2563EB\", \"16px\")',\n },\n context: {\n type: 'string',\n enum: ['color', 'spacing', 'typography'],\n description: 'Optional hint about value type',\n },\n },\n required: ['value'],\n },\n },\n {\n name: 'suggest_fix',\n description:\n 'Get a fix suggestion for a design system violation.',\n inputSchema: {\n type: 'object',\n properties: {\n type: {\n type: 'string',\n description: 'Type of violation (e.g., \"hardcoded-color\", \"arbitrary-spacing\")',\n },\n value: {\n type: 'string',\n description: 'The problematic value',\n },\n location: {\n type: 'string',\n description: 'Where the violation occurs (file:line)',\n },\n },\n required: ['type', 'value'],\n },\n },\n ],\n };\n });\n\n /**\n * Handle tool calls\n */\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const ctx = await getContext();\n const { name, arguments: args } = request.params;\n\n switch (name) {\n case 'find_component': {\n const { useCase, constraints } = args as FindComponentRequest;\n const result = handleFindComponent(ctx, useCase, constraints);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n case 'validate_code': {\n const { code, filePath } = args as ValidateCodeRequest;\n const result = handleValidateCode(ctx, code, filePath);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n case 'resolve_token': {\n const { value, context: tokenContext } = args as ResolveTokenRequest;\n const result = handleResolveToken(ctx, value, tokenContext);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n case 'suggest_fix': {\n const { type, value, location } = args as {\n type: string;\n value: string;\n location?: string;\n };\n const result = handleSuggestFix(ctx, type, value, location);\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(result, null, 2),\n },\n ],\n };\n }\n\n default:\n throw new Error(`Unknown tool: ${name}`);\n }\n });\n\n return server;\n}\n\n/**\n * Find component handler\n */\nfunction handleFindComponent(\n ctx: DesignSystemContext,\n useCase: string,\n constraints?: string[]\n): FindComponentResponse {\n const matches = searchComponents(ctx, useCase);\n\n if (matches.length === 0) {\n // No Dead Ends: Provide guidance when no components found\n const availableComponents = ctx.components.slice(0, 5).map(c => c.name);\n return {\n recommended: null,\n alternatives: [],\n reasoning: `No existing component found for \"${useCase}\".`,\n guidance: {\n suggestion: 'Consider creating a new component or composing existing ones.',\n availableComponents: availableComponents.length > 0\n ? `Available components include: ${availableComponents.join(', ')}`\n : 'No components in inventory. Run `buoy scan` to discover components.',\n nextSteps: ctx.components.length === 0\n ? ['Run `buoy scan` to discover components', 'Run `buoy skill export` to populate component inventory']\n : ['Check component naming - try broader search terms', 'View full inventory with components://inventory'],\n },\n };\n }\n\n // Score matches (simple scoring for now)\n const scored = matches.map(c => ({\n component: c,\n score: calculateMatchScore(c, useCase, constraints),\n }));\n\n scored.sort((a, b) => b.score - a.score);\n\n const recommended = scored[0].component;\n const alternatives = scored.slice(1, 4).map(s => s.component);\n\n return {\n recommended,\n alternatives,\n reasoning: `\"${recommended.name}\" is the best match for \"${useCase}\". ${\n recommended.description || ''\n }`,\n };\n}\n\n/**\n * Calculate match score for a component\n */\nfunction calculateMatchScore(\n component: { name: string; description?: string; props: string[] },\n useCase: string,\n constraints?: string[]\n): number {\n let score = 0;\n const searchText = `${component.name} ${component.description || ''} ${component.props.join(' ')}`.toLowerCase();\n const useCaseLower = useCase.toLowerCase();\n\n // Name match\n if (component.name.toLowerCase().includes(useCaseLower)) {\n score += 10;\n }\n\n // Keyword matches\n const keywords = useCaseLower.split(/\\s+/);\n for (const keyword of keywords) {\n if (searchText.includes(keyword)) {\n score += 2;\n }\n }\n\n // Constraint matches\n if (constraints) {\n for (const constraint of constraints) {\n if (searchText.includes(constraint.toLowerCase())) {\n score += 3;\n }\n }\n }\n\n return score;\n}\n\n/**\n * Validate code handler\n */\nfunction handleValidateCode(\n ctx: DesignSystemContext,\n code: string,\n _filePath?: string\n): ValidateCodeResponse {\n const issues: ValidateCodeResponse['issues'] = [];\n\n // Check for hardcoded colors\n const hexColors = code.match(/#[0-9A-Fa-f]{3,8}\\b/g) || [];\n const rgbColors = code.match(/rgb\\([^)]+\\)/g) || [];\n\n for (const color of [...hexColors, ...rgbColors]) {\n // Check if it's a token value\n const isToken = ctx.tokens.some(t => t.value.toLowerCase() === color.toLowerCase());\n if (!isToken) {\n const match = findClosestToken(ctx, color, 'color');\n issues.push({\n type: 'hardcoded-color',\n severity: 'warning',\n message: `Hardcoded color \"${color}\" - use design token instead`,\n suggestion: match ? `Use token: ${match.name} (${match.value})` : undefined,\n });\n }\n }\n\n // Check for arbitrary spacing\n const arbitrarySpacing = code.match(/\\b\\d+px\\b/g) || [];\n const spacingScale = ctx.tokens\n .filter(t => t.category === 'spacing')\n .map(t => t.value);\n\n for (const spacing of arbitrarySpacing) {\n if (!spacingScale.includes(spacing)) {\n const match = findClosestToken(ctx, spacing, 'spacing');\n issues.push({\n type: 'arbitrary-spacing',\n severity: 'warning',\n message: `Arbitrary spacing \"${spacing}\" - use spacing scale`,\n suggestion: match ? `Use token: ${match.name} (${match.value})` : undefined,\n });\n }\n }\n\n // Check for div onClick (accessibility anti-pattern)\n if (/<div[^>]*onClick/i.test(code)) {\n issues.push({\n type: 'accessibility',\n severity: 'critical',\n message: 'Using div with onClick - use button or Button component',\n suggestion: 'Replace <div onClick> with <Button onClick>',\n });\n }\n\n // Check for img without alt\n if (/<img[^>]*(?!alt)[^>]*>/i.test(code) && !/<img[^>]*alt=/i.test(code)) {\n issues.push({\n type: 'accessibility',\n severity: 'critical',\n message: 'Image missing alt attribute',\n suggestion: 'Add alt=\"description\" to img element',\n });\n }\n\n // No Dead Ends: Provide context about what was checked\n const checksPerformed = [\n 'Hardcoded colors',\n 'Arbitrary spacing values',\n 'Accessibility anti-patterns (div onClick, img alt)',\n ];\n\n return {\n valid: issues.length === 0,\n issues,\n summary: {\n total: issues.length,\n critical: issues.filter(i => i.severity === 'critical').length,\n warning: issues.filter(i => i.severity === 'warning').length,\n info: issues.filter(i => i.severity === 'info').length,\n },\n context: {\n checksPerformed,\n tokensAvailable: ctx.tokens.length,\n componentsKnown: ctx.components.length,\n guidance: issues.length === 0\n ? 'Code follows design system rules. Run `buoy check` for comprehensive analysis.'\n : 'Fix issues above, then re-validate. Run `buoy fix --dry-run` for automated suggestions.',\n },\n };\n}\n\n/**\n * Resolve token handler\n */\nfunction handleResolveToken(\n ctx: DesignSystemContext,\n value: string,\n tokenContext?: 'color' | 'spacing' | 'typography'\n): ResolveTokenResponse {\n // Filter tokens by context if provided\n const candidates = tokenContext\n ? ctx.tokens.filter(t => t.category === tokenContext)\n : ctx.tokens;\n\n // Look for exact match\n const exactMatch = candidates.find(\n t => t.value.toLowerCase() === value.toLowerCase()\n );\n\n if (exactMatch) {\n return {\n exactMatch,\n closestMatches: [],\n suggestion: `Use token: ${exactMatch.name}`,\n };\n }\n\n // Find closest matches\n const closest = findClosestToken(ctx, value, tokenContext);\n\n if (closest) {\n return {\n exactMatch: null,\n closestMatches: [{ token: closest, similarity: 0.8 }],\n suggestion: `Closest token: ${closest.name} (${closest.value})`,\n };\n }\n\n // No Dead Ends: Explain why no match and suggest next steps\n const availableCategories = [...new Set(ctx.tokens.map(t => t.category))];\n return {\n exactMatch: null,\n closestMatches: [],\n suggestion: `No matching token found for \"${value}\".`,\n guidance: {\n tokenCount: ctx.tokens.length,\n availableCategories: availableCategories.length > 0\n ? availableCategories\n : ['No tokens loaded'],\n nextSteps: ctx.tokens.length === 0\n ? [\n 'Run `buoy tokens` to extract tokens from hardcoded values',\n 'Add a design-tokens.json file',\n 'Run `buoy scan` to discover tokens from CSS',\n ]\n : [\n 'Consider adding a new token for this value',\n 'Use the closest available value from the scale',\n `View available tokens: tokens://${tokenContext || 'all'}`,\n ],\n },\n };\n}\n\n/**\n * Find closest matching token\n */\nfunction findClosestToken(\n ctx: DesignSystemContext,\n value: string,\n category?: string\n): DesignSystemContext['tokens'][0] | null {\n const candidates = category\n ? ctx.tokens.filter(t => t.category === category)\n : ctx.tokens;\n\n if (candidates.length === 0) return null;\n\n // For colors, try to find similar hue\n if (value.startsWith('#') || value.startsWith('rgb')) {\n return candidates[0]; // Simplified - return first token\n }\n\n // For spacing, find closest numeric value\n const numericValue = parseFloat(value);\n if (!isNaN(numericValue)) {\n let closest = candidates[0];\n let closestDiff = Infinity;\n\n for (const token of candidates) {\n const tokenValue = parseFloat(token.value);\n if (!isNaN(tokenValue)) {\n const diff = Math.abs(tokenValue - numericValue);\n if (diff < closestDiff) {\n closestDiff = diff;\n closest = token;\n }\n }\n }\n\n return closest;\n }\n\n return candidates[0];\n}\n\n/**\n * Suggest fix handler\n */\nfunction handleSuggestFix(\n ctx: DesignSystemContext,\n type: string,\n value: string,\n location?: string\n) {\n // Determine category from type\n let category: 'color' | 'spacing' | 'typography' | undefined;\n if (type.includes('color')) category = 'color';\n else if (type.includes('spacing')) category = 'spacing';\n else if (type.includes('font') || type.includes('typography')) category = 'typography';\n\n const closest = findClosestToken(ctx, value, category);\n\n if (!closest) {\n // No Dead Ends: Explain why no fix and suggest next steps\n return {\n fix: null,\n explanation: `No suitable token found for \"${value}\"`,\n alternatives: [],\n guidance: {\n tokenCount: ctx.tokens.length,\n categorySearched: category || 'all',\n nextSteps: ctx.tokens.length === 0\n ? [\n 'Run `buoy tokens` to extract tokens from codebase',\n 'Add a design-tokens.json file',\n 'Manual fix: replace with CSS variable or theme token',\n ]\n : [\n 'Value may be intentionally one-off (consider documenting)',\n 'Run `buoy fix --confidence low` to see all suggestions',\n 'Create a new token for this value if it will be reused',\n ],\n },\n };\n }\n\n // Generate fix based on type\n let replacement = closest.name;\n if (type.includes('color')) {\n replacement = `var(--${closest.name})`;\n } else if (type.includes('class')) {\n replacement = closest.name.replace(/^(color|spacing|font)-/, '');\n }\n\n return {\n fix: {\n type: 'replace' as const,\n original: value,\n replacement,\n confidence: 0.85,\n },\n explanation: `Replace hardcoded value with design token \"${closest.name}\"${\n location ? ` at ${location}` : ''\n }`,\n alternatives: ctx.tokens\n .filter(t => t.category === category && t.name !== closest.name)\n .slice(0, 3)\n .map(t => t.name),\n };\n}\n\n/**\n * Start the MCP server\n */\nexport async function startServer(cwd: string = process.cwd()): Promise<void> {\n const server = createServer(cwd);\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n"],"mappings":"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","names":[]}
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ import {
2
+ createServer,
3
+ findComponent,
4
+ getTokensByCategory,
5
+ loadDesignSystemContext,
6
+ searchComponents,
7
+ startServer
8
+ } from "./chunk-RDI5XKIN.js";
9
+ export {
10
+ createServer,
11
+ findComponent,
12
+ getTokensByCategory,
13
+ loadDesignSystemContext,
14
+ searchComponents,
15
+ startServer
16
+ };
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@buoy-design/mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for Buoy design system context",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "bin": {
10
+ "buoy-mcp": "./dist/bin.js"
11
+ },
12
+ "exports": {
13
+ ".": {
14
+ "import": "./dist/index.js",
15
+ "types": "./dist/index.d.ts"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "dependencies": {
22
+ "@modelcontextprotocol/sdk": "^1.0.0",
23
+ "@buoy-design/core": "0.1.3",
24
+ "@buoy-design/scanners": "0.1.5"
25
+ },
26
+ "devDependencies": {
27
+ "tsup": "^8.0.0",
28
+ "typescript": "^5.3.0",
29
+ "vitest": "^1.2.0"
30
+ },
31
+ "keywords": [
32
+ "buoy",
33
+ "design-system",
34
+ "mcp",
35
+ "ai",
36
+ "claude"
37
+ ],
38
+ "scripts": {
39
+ "build": "tsup",
40
+ "dev": "tsup --watch",
41
+ "typecheck": "tsc --noEmit",
42
+ "test": "vitest run",
43
+ "test:watch": "vitest"
44
+ }
45
+ }