@triptease/design-system-mcp 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +35 -41
  3. package/dist/package.json +3 -3
  4. package/dist/src/index.js +40 -14
  5. package/dist/src/index.js.map +1 -1
  6. package/dist/src/manifests/components/entries/barChart.js +3 -3
  7. package/dist/src/manifests/components/entries/barChart.js.map +1 -1
  8. package/dist/src/manifests/components/entries/card.d.ts +7 -2
  9. package/dist/src/manifests/components/entries/card.js +10 -2
  10. package/dist/src/manifests/components/entries/card.js.map +1 -1
  11. package/dist/src/manifests/components/entries/combobox.js +1 -1
  12. package/dist/src/manifests/components/entries/combobox.js.map +1 -1
  13. package/dist/src/manifests/components/entries/datePicker.js +1 -1
  14. package/dist/src/manifests/components/entries/datePicker.js.map +1 -1
  15. package/dist/src/manifests/components/entries/dateRangePicker.js +1 -1
  16. package/dist/src/manifests/components/entries/dateRangePicker.js.map +1 -1
  17. package/dist/src/manifests/components/entries/dialog.js +1 -1
  18. package/dist/src/manifests/components/entries/dialog.js.map +1 -1
  19. package/dist/src/manifests/components/entries/lineChart.js +1 -1
  20. package/dist/src/manifests/components/entries/lineChart.js.map +1 -1
  21. package/dist/src/resources/components/get.d.ts +7 -0
  22. package/dist/src/resources/components/get.js +29 -0
  23. package/dist/src/resources/components/get.js.map +1 -0
  24. package/dist/src/resources/components/index.d.ts +2 -0
  25. package/dist/src/resources/components/index.js +3 -0
  26. package/dist/src/resources/components/index.js.map +1 -0
  27. package/dist/src/resources/components/list.d.ts +7 -0
  28. package/dist/src/resources/components/list.js +19 -0
  29. package/dist/src/resources/components/list.js.map +1 -0
  30. package/dist/src/resources/guides/index.d.ts +2 -0
  31. package/dist/src/resources/guides/index.js +3 -0
  32. package/dist/src/resources/guides/index.js.map +1 -0
  33. package/dist/src/resources/guides/principles.d.ts +60 -0
  34. package/dist/src/resources/guides/principles.js +158 -0
  35. package/dist/src/resources/guides/principles.js.map +1 -0
  36. package/dist/src/resources/guides/setup.d.ts +7 -0
  37. package/dist/src/resources/guides/setup.js +54 -0
  38. package/dist/src/resources/guides/setup.js.map +1 -0
  39. package/dist/src/resources/index.d.ts +3 -0
  40. package/dist/src/resources/index.js +4 -0
  41. package/dist/src/resources/index.js.map +1 -0
  42. package/dist/src/resources/tokens/get.d.ts +7 -0
  43. package/dist/src/resources/tokens/get.js +30 -0
  44. package/dist/src/resources/tokens/get.js.map +1 -0
  45. package/dist/src/resources/tokens/index.d.ts +2 -0
  46. package/dist/src/resources/tokens/index.js +3 -0
  47. package/dist/src/resources/tokens/index.js.map +1 -0
  48. package/dist/src/resources/tokens/list.d.ts +7 -0
  49. package/dist/src/resources/tokens/list.js +21 -0
  50. package/dist/src/resources/tokens/list.js.map +1 -0
  51. package/dist/src/utils/buildCDNUrls.js.map +1 -1
  52. package/package.json +3 -3
  53. package/src/index.ts +94 -14
  54. package/src/manifests/components/entries/barChart.ts +3 -3
  55. package/src/manifests/components/entries/card.ts +10 -2
  56. package/src/manifests/components/entries/combobox.ts +1 -1
  57. package/src/manifests/components/entries/datePicker.ts +1 -1
  58. package/src/manifests/components/entries/dateRangePicker.ts +1 -1
  59. package/src/manifests/components/entries/dialog.ts +1 -1
  60. package/src/manifests/components/entries/lineChart.ts +1 -1
  61. package/src/resources/components/get.test.ts +39 -0
  62. package/src/resources/components/get.ts +35 -0
  63. package/src/resources/components/index.ts +2 -0
  64. package/src/resources/components/list.test.ts +40 -0
  65. package/src/resources/components/list.ts +20 -0
  66. package/src/resources/guides/index.ts +2 -0
  67. package/src/resources/guides/principles.ts +160 -0
  68. package/src/resources/guides/setup.test.ts +72 -0
  69. package/src/resources/guides/setup.ts +66 -0
  70. package/src/resources/index.ts +3 -0
  71. package/src/resources/tokens/get.test.ts +41 -0
  72. package/src/resources/tokens/get.ts +36 -0
  73. package/src/resources/tokens/index.ts +2 -0
  74. package/src/resources/tokens/list.test.ts +42 -0
  75. package/src/resources/tokens/list.ts +31 -0
  76. package/src/utils/buildCDNUrls.ts +1 -1
  77. package/dist/src/tools/searchComponents/handler.d.ts +0 -6
  78. package/dist/src/tools/searchComponents/handler.js +0 -29
  79. package/dist/src/tools/searchComponents/handler.js.map +0 -1
  80. package/dist/src/tools/searchComponents/index.d.ts +0 -12
  81. package/dist/src/tools/searchComponents/index.js +0 -14
  82. package/dist/src/tools/searchComponents/index.js.map +0 -1
  83. package/src/tools/searchComponents/__snapshots__/handler.test.ts.snap +0 -23
  84. package/src/tools/searchComponents/handler.test.ts +0 -14
  85. package/src/tools/searchComponents/handler.ts +0 -36
  86. package/src/tools/searchComponents/index.ts +0 -15
package/src/index.ts CHANGED
@@ -1,14 +1,16 @@
1
1
  #!/usr/bin/env node
2
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
3
3
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
4
  import packageJson from '@/../package.json' with { type: 'json' };
5
5
 
6
- import getComponentDocsTool from '@/tools/getComponentDocs/index.js';
7
- import listComponentsTool from '@/tools/listComponents/index.js';
8
- import getDesignTokensTool from '@/tools/getCSSTokens/index.js';
9
- import searchComponentsTool from '@/tools/searchComponents/index.js';
10
- import getSetupGuideTool from '@/tools/getSetupGuide/index.js';
11
- import listCSSTokens from '@/tools/listCSSTokens/index.js';
6
+ import {
7
+ listComponents,
8
+ getComponentDocs,
9
+ listCSSTokens,
10
+ getCSSTokens,
11
+ getSetupGuide,
12
+ getPrinciplesGuide,
13
+ } from '@/resources/index.js';
12
14
 
13
15
  // Initialize MCP server
14
16
  const server = new McpServer(
@@ -19,18 +21,96 @@ const server = new McpServer(
19
21
  },
20
22
  {
21
23
  capabilities: {
24
+ resources: {},
22
25
  tools: {},
23
26
  },
24
27
  }
25
28
  );
26
29
 
27
- // Register getComponentDocsTool definitions
28
- server.registerTool(getComponentDocsTool.name, getComponentDocsTool.config, getComponentDocsTool.handler);
29
- server.registerTool(listComponentsTool.name, listComponentsTool.config, listComponentsTool.handler);
30
- server.registerTool(getDesignTokensTool.name, getDesignTokensTool.config, getDesignTokensTool.handler);
31
- server.registerTool(searchComponentsTool.name, searchComponentsTool.config, searchComponentsTool.handler);
32
- server.registerTool(getSetupGuideTool.name, getSetupGuideTool.config, getSetupGuideTool.handler);
33
- server.registerTool(listCSSTokens.name, listCSSTokens.config, listCSSTokens.handler);
30
+ // Register resources
31
+ server.registerResource(
32
+ 'list_components',
33
+ 'designsystem://components',
34
+ {
35
+ description: 'List all available design system components',
36
+ mimeType: 'application/json',
37
+ },
38
+ listComponents
39
+ );
40
+
41
+ server.registerResource(
42
+ 'get_component_docs',
43
+ new ResourceTemplate('designsystem://components/{name}', { list: undefined }),
44
+ {
45
+ description: 'Get documentation for a specific component',
46
+ mimeType: 'application/json',
47
+ },
48
+ async (_uri, { name }) => {
49
+ return getComponentDocs(name as string);
50
+ }
51
+ );
52
+
53
+ server.registerResource(
54
+ 'list_css_tokens',
55
+ 'designsystem://tokens',
56
+ {
57
+ description: 'List all CSS token categories with counts',
58
+ mimeType: 'application/json',
59
+ },
60
+ listCSSTokens
61
+ );
62
+
63
+ server.registerResource(
64
+ 'get_css_tokens',
65
+ new ResourceTemplate('designsystem://tokens/{category}', { list: undefined }),
66
+ {
67
+ description: 'Get CSS tokens for a specific category',
68
+ mimeType: 'application/json',
69
+ },
70
+ async (_uri, { category }) => {
71
+ return getCSSTokens(category as string);
72
+ }
73
+ );
74
+
75
+ server.registerResource(
76
+ 'setup_guide_all',
77
+ 'designsystem://guides/setup',
78
+ {
79
+ description: 'Get all setup and installation instructions',
80
+ mimeType: 'application/json',
81
+ },
82
+ async () => getSetupGuide()
83
+ );
84
+
85
+ server.registerResource(
86
+ 'setup_guide_npm',
87
+ 'designsystem://guides/setup/npm',
88
+ {
89
+ description: 'Get NPM setup and installation instructions',
90
+ mimeType: 'application/json',
91
+ },
92
+ async () => getSetupGuide('npm')
93
+ );
94
+
95
+ server.registerResource(
96
+ 'setup_guide_cdn',
97
+ 'designsystem://guides/setup/cdn',
98
+ {
99
+ description: 'Get CDN setup and installation instructions',
100
+ mimeType: 'application/json',
101
+ },
102
+ async () => getSetupGuide('cdn')
103
+ );
104
+
105
+ server.registerResource(
106
+ 'principles_guide',
107
+ 'designsystem://guides/principles',
108
+ {
109
+ description: 'Get design system usage principles and best practices',
110
+ mimeType: 'application/json',
111
+ },
112
+ getPrinciplesGuide
113
+ );
34
114
 
35
115
  // Start the server
36
116
  async function main() {
@@ -37,7 +37,7 @@ export default {
37
37
  name: 'tt-bar-chart',
38
38
  includesTypes: false,
39
39
  optional: false,
40
- moduleFormat: "esm",
40
+ moduleFormat: 'esm',
41
41
  pinnedVersionUrl: buildCDNUrl('tt-bar-chart', latestBarChartVersion),
42
42
  pinnedMajorVersionUrl: buildCDNUrl('tt-bar-chart', buildMajorVersion(latestBarChartVersion)),
43
43
  latestVersionUrl: buildCDNUrl('tt-bar-chart', 'latest'),
@@ -48,7 +48,7 @@ export default {
48
48
  name: 'tt-dataset',
49
49
  includesTypes: false,
50
50
  optional: false,
51
- moduleFormat: "esm",
51
+ moduleFormat: 'esm',
52
52
  pinnedVersionUrl: buildCDNUrl('tt-dataset', latestDatasetVersion),
53
53
  pinnedMajorVersionUrl: buildCDNUrl('tt-dataset', buildMajorVersion(latestDatasetVersion)),
54
54
  latestVersionUrl: buildCDNUrl('tt-dataset', 'latest'),
@@ -59,7 +59,7 @@ export default {
59
59
  name: 'tt-data-point',
60
60
  includesTypes: false,
61
61
  optional: false,
62
- moduleFormat: "esm",
62
+ moduleFormat: 'esm',
63
63
  pinnedVersionUrl: buildCDNUrl('tt-data-point', latestDataPointVersion),
64
64
  pinnedMajorVersionUrl: buildCDNUrl('tt-data-point', buildMajorVersion(latestDataPointVersion)),
65
65
  latestVersionUrl: buildCDNUrl('tt-data-point', 'latest'),
@@ -19,8 +19,8 @@ export default {
19
19
  ],
20
20
  },
21
21
  classes: {
22
- card: 'Standard card with padding',
23
- 'card-dataview': 'Card optimized for displaying metrics/data',
22
+ card: 'Pre-styled container with flex layout, spacing, borders, and elevation',
23
+ 'card-dataview': 'Card variant with grid layout optimized for displaying metrics/data',
24
24
  },
25
25
  examples: [
26
26
  {
@@ -28,6 +28,14 @@ export default {
28
28
  code: `<div class="card">
29
29
  <h3>Card Title</h3>
30
30
  <p>Card content goes here...</p>
31
+ </div>`,
32
+ },
33
+ {
34
+ title: 'Card with custom padding',
35
+ description: 'Customize using --card-padding or --card-vertical-spacing CSS variables',
36
+ code: `<div class="card" style="--card-padding: var(--space-scale-4)">
37
+ <h3>Card with more padding</h3>
38
+ <p>Customized via CSS variable instead of writing custom CSS</p>
31
39
  </div>`,
32
40
  },
33
41
  ],
@@ -30,7 +30,7 @@ export default {
30
30
  name: '@triptease/tt-combobox',
31
31
  includesTypes: false,
32
32
  optional: false,
33
- moduleFormat: "esm",
33
+ moduleFormat: 'esm',
34
34
  latestVersionUrl: buildCDNUrl('tt-combobox', 'latest'),
35
35
  pinnedMajorVersionUrl: buildCDNUrl('tt-combobox', buildMajorVersion(version)),
36
36
  pinnedVersionUrl: buildCDNUrl('tt-combobox', version),
@@ -26,7 +26,7 @@ export default {
26
26
  name: '@triptease/tt-date-picker',
27
27
  includesTypes: false,
28
28
  optional: false,
29
- moduleFormat: "esm",
29
+ moduleFormat: 'esm',
30
30
  latestVersionUrl: buildCDNUrl('tt-date-picker', 'latest'),
31
31
  pinnedMajorVersionUrl: buildCDNUrl('tt-date-picker', buildMajorVersion(version)),
32
32
  pinnedVersionUrl: buildCDNUrl('tt-date-picker', version),
@@ -30,7 +30,7 @@ export default {
30
30
  name: '@triptease/tt-date-range-picker',
31
31
  includesTypes: false,
32
32
  optional: false,
33
- moduleFormat: "esm",
33
+ moduleFormat: 'esm',
34
34
  latestVersionUrl: buildCDNUrl('tt-date-range-picker', 'latest'),
35
35
  pinnedMajorVersionUrl: buildCDNUrl('tt-date-range-picker', buildMajorVersion(version)),
36
36
  pinnedVersionUrl: buildCDNUrl('tt-date-range-picker', version),
@@ -31,7 +31,7 @@ export default {
31
31
  name: 'tt-dialog',
32
32
  includesTypes: false,
33
33
  optional: false,
34
- moduleFormat: "esm",
34
+ moduleFormat: 'esm',
35
35
  pinnedVersionUrl: buildCDNUrl('tt-dialog', version),
36
36
  pinnedMajorVersionUrl: buildCDNUrl('tt-dialog', buildMajorVersion(version)),
37
37
  latestVersionUrl: buildCDNUrl('tt-dialog', 'latest'),
@@ -46,7 +46,7 @@ export default {
46
46
  name: 'tt-dataset',
47
47
  includesTypes: false,
48
48
  optional: false,
49
- moduleFormat: "esm",
49
+ moduleFormat: 'esm',
50
50
  pinnedVersionUrl: buildCDNUrl('tt-dataset', latestDatasetVersion),
51
51
  pinnedMajorVersionUrl: buildCDNUrl('tt-dataset', buildMajorVersion(latestDatasetVersion)),
52
52
  latestVersionUrl: buildCDNUrl('tt-dataset', 'latest'),
@@ -0,0 +1,39 @@
1
+ import { getComponentDocs } from './get.js';
2
+ import { describe, expect, it } from 'vitest';
3
+
4
+ describe('getComponentDocs resource', () => {
5
+ it('should return error for non-existent component', async () => {
6
+ const result = await getComponentDocs('foo');
7
+ const data = JSON.parse(result.contents[0].text);
8
+
9
+ expect(data.error).toBe("Component 'foo' not found");
10
+ expect(data.available).toBeDefined();
11
+ expect(Array.isArray(data.available)).toBe(true);
12
+ });
13
+
14
+ it('should return component manifest for valid component', async () => {
15
+ const result = await getComponentDocs('button');
16
+ const data = JSON.parse(result.contents[0].text);
17
+
18
+ expect(data.name).toBe('Button');
19
+ expect(data.element).toBe('button');
20
+ expect(data.description).toBeDefined();
21
+ expect(data.dataAttributes).toBeDefined();
22
+ });
23
+
24
+ it('should return contents with correct URI and mimeType', async () => {
25
+ const result = await getComponentDocs('button');
26
+
27
+ expect(result.contents).toBeDefined();
28
+ expect(result.contents).toHaveLength(1);
29
+ expect(result.contents[0].uri).toBe('designsystem://components/button');
30
+ expect(result.contents[0].mimeType).toBe('application/json');
31
+ });
32
+
33
+ it('should handle case-insensitive component names', async () => {
34
+ const lowerResult = await getComponentDocs('button');
35
+ const upperResult = await getComponentDocs('BUTTON');
36
+
37
+ expect(JSON.parse(lowerResult.contents[0].text)).toEqual(JSON.parse(upperResult.contents[0].text));
38
+ });
39
+ });
@@ -0,0 +1,35 @@
1
+ import { componentManifest } from '@/manifests/components/index.js';
2
+
3
+ export const getComponentDocs = async (name: string) => {
4
+ const componentName = name.toLowerCase();
5
+ const component = componentManifest[componentName];
6
+
7
+ if (!component) {
8
+ return {
9
+ contents: [
10
+ {
11
+ uri: `designsystem://components/${name}`,
12
+ mimeType: 'application/json',
13
+ text: JSON.stringify(
14
+ {
15
+ error: `Component '${componentName}' not found`,
16
+ available: Object.keys(componentManifest),
17
+ },
18
+ null,
19
+ 2
20
+ ),
21
+ },
22
+ ],
23
+ };
24
+ }
25
+
26
+ return {
27
+ contents: [
28
+ {
29
+ uri: `designsystem://components/${name}`,
30
+ mimeType: 'application/json',
31
+ text: JSON.stringify(component, null, 2),
32
+ },
33
+ ],
34
+ };
35
+ };
@@ -0,0 +1,2 @@
1
+ export { listComponents } from './list.js';
2
+ export { getComponentDocs } from './get.js';
@@ -0,0 +1,40 @@
1
+ import { listComponents } from './list.js';
2
+ import { describe, expect, it } from 'vitest';
3
+
4
+ describe('listComponents resource', () => {
5
+ it('should return contents with correct URI and mimeType', async () => {
6
+ const result = await listComponents();
7
+
8
+ expect(result.contents).toBeDefined();
9
+ expect(result.contents).toHaveLength(1);
10
+ expect(result.contents[0].uri).toBe('designsystem://components');
11
+ expect(result.contents[0].mimeType).toBe('application/json');
12
+ });
13
+
14
+ it('should return all 18 components', async () => {
15
+ const result = await listComponents();
16
+ const data = JSON.parse(result.contents[0].text);
17
+
18
+ expect(data.components).toHaveLength(18);
19
+ });
20
+
21
+ it('should include component key, name, description, and element', async () => {
22
+ const result = await listComponents();
23
+ const data = JSON.parse(result.contents[0].text);
24
+ const firstComponent = data.components[0];
25
+
26
+ expect(firstComponent).toHaveProperty('key');
27
+ expect(firstComponent).toHaveProperty('name');
28
+ expect(firstComponent).toHaveProperty('description');
29
+ expect(firstComponent).toHaveProperty('element');
30
+ });
31
+
32
+ it('should include button component', async () => {
33
+ const result = await listComponents();
34
+ const data = JSON.parse(result.contents[0].text);
35
+ const buttonComponent = data.components.find((c: any) => c.key === 'button');
36
+
37
+ expect(buttonComponent).toBeDefined();
38
+ expect(buttonComponent.name).toBe('Button');
39
+ });
40
+ });
@@ -0,0 +1,20 @@
1
+ import { componentManifest } from '@/manifests/components/index.js';
2
+
3
+ export const listComponents = async () => {
4
+ const components = Object.entries(componentManifest).map(([key, comp]) => ({
5
+ key,
6
+ name: comp.name,
7
+ description: comp.description,
8
+ element: comp.element,
9
+ }));
10
+
11
+ return {
12
+ contents: [
13
+ {
14
+ uri: 'designsystem://components',
15
+ mimeType: 'application/json',
16
+ text: JSON.stringify({ components }, null, 2),
17
+ },
18
+ ],
19
+ };
20
+ };
@@ -0,0 +1,2 @@
1
+ export { getSetupGuide } from './setup.js';
2
+ export { getPrinciplesGuide } from './principles.js';
@@ -0,0 +1,160 @@
1
+ export const designSystemPrinciples = {
2
+ overview: {
3
+ corePrinciple:
4
+ 'Trust the design system. Components and classes are fully styled and production-ready. Use them as-is.',
5
+ philosophy:
6
+ 'The design system handles styling, spacing, colors, and layouts. Your role is to compose components, not recreate their styling.',
7
+ },
8
+ cssClassUsage: {
9
+ defaultApproach: 'Use existing classes without writing additional CSS',
10
+ do: [
11
+ 'Use classes as-is without extra styling (e.g., <div class="card">)',
12
+ 'Check component documentation BEFORE writing any custom CSS',
13
+ 'Compose with multiple classes when needed (e.g., class="card stat-card")',
14
+ 'Override using CSS variables when provided (e.g., style="--card-padding: var(--space-scale-4)")',
15
+ 'Trust that design system classes include ALL necessary styling (layout, spacing, colors, shadows)',
16
+ ],
17
+ dont: [
18
+ "Don't duplicate CSS that classes already provide (border, background, padding, etc.)",
19
+ "Don't create new classes without checking if design system has it",
20
+ "Don't assume classes need additional styling - verify in docs first",
21
+ "Don't override design tokens with hardcoded values (use CSS variables instead)",
22
+ "Don't add wrapper divs just to style - compose classes directly",
23
+ ],
24
+ },
25
+ verificationWorkflow: {
26
+ description: 'Follow this workflow BEFORE writing any custom CSS',
27
+ steps: [
28
+ '1. Check: Does the design system have this component? (Query designsystem://components)',
29
+ '2. Read: What does the component provide? (Check component docs)',
30
+ '3. Use: Apply the class without custom CSS first',
31
+ '4. Test: Does it work as-is? (Usually yes!)',
32
+ '5. Customize: Only if truly needed, use CSS variables or add modifier classes',
33
+ ],
34
+ },
35
+ whenToWriteCustomCSS: {
36
+ description: 'Write custom CSS only in these scenarios',
37
+ scenarios: [
38
+ 'User explicitly requests custom/unique styling',
39
+ 'Design system genuinely lacks the needed component',
40
+ 'Truly unique layout requirements that cannot be solved with existing classes or composition',
41
+ 'Dashboard-specific or app-specific layout patterns (grids, specialized containers)',
42
+ ],
43
+ notValidReasons: [
44
+ 'Not valid: "I need a card with padding" - .card already has padding',
45
+ 'Not valid: "I need a button with a border" - button already has borders',
46
+ 'Not valid: "I need spacing between elements" - use design system spacing tokens',
47
+ ],
48
+ },
49
+ compositionPatterns: {
50
+ description: 'How to combine design system classes effectively',
51
+ patterns: [
52
+ {
53
+ pattern: 'Base + Modifier',
54
+ example: '<div class="card stat-card">',
55
+ explanation: 'Use base design system class (card) + your modifier class (stat-card) for extensions',
56
+ },
57
+ {
58
+ pattern: 'CSS Variable Override',
59
+ example: '<div class="card" style="--card-padding: var(--space-scale-5)">',
60
+ explanation: 'Override CSS variables for customization without duplicating styles',
61
+ },
62
+ {
63
+ pattern: 'Multiple Design System Classes',
64
+ example: '<button class="primary large">',
65
+ explanation: 'Compose multiple utility/variant classes from design system',
66
+ },
67
+ ],
68
+ },
69
+ designTokens: {
70
+ description: 'Use design tokens instead of hardcoded values',
71
+ principle: 'All spacing, colors, typography should use CSS custom properties (--*)',
72
+ examples: [
73
+ {
74
+ wrong: 'padding: 24px',
75
+ right: 'padding: var(--space-scale-3)',
76
+ why: 'Tokens ensure consistency and enable theming',
77
+ },
78
+ {
79
+ wrong: 'color: #DA0707',
80
+ right: 'color: var(--color-alert-400)',
81
+ why: 'Semantic tokens communicate intent and adapt to themes',
82
+ },
83
+ {
84
+ wrong: 'font-size: 16px',
85
+ right: 'font-size: var(--font-size-300)',
86
+ why: 'Typography scale ensures visual hierarchy',
87
+ },
88
+ ],
89
+ },
90
+ commonMistakes: {
91
+ description: 'Common mistakes developers make (and how to avoid them)',
92
+ mistakes: [
93
+ {
94
+ mistake: 'Recreating .card styling',
95
+ problem: 'Duplicating background, border, padding, shadows that .card already provides',
96
+ solution: 'Use <div class="card"> directly. It includes everything.',
97
+ prevention: 'Read component docs BEFORE writing CSS',
98
+ },
99
+ {
100
+ mistake: 'Adding wrapper divs for styling',
101
+ problem: '<div class="my-wrapper"><div class="card">...</div></div>',
102
+ solution: 'Style the card directly: <div class="card my-modifier">',
103
+ prevention: 'Compose classes instead of wrapping',
104
+ },
105
+ {
106
+ mistake: 'Hardcoding spacing values',
107
+ problem: 'margin: 16px; gap: 12px;',
108
+ solution: 'margin: var(--space-scale-2); gap: var(--space-scale-1-5);',
109
+ prevention: 'Query designsystem://tokens/space for available values',
110
+ },
111
+ {
112
+ mistake: 'Assuming classes are incomplete',
113
+ problem: 'Adding display: flex, border: 1px solid, etc. to classes that already have these',
114
+ solution: "Trust the design system. Check docs to see what's included.",
115
+ prevention: 'Default assumption: classes are complete, not partial',
116
+ },
117
+ ],
118
+ },
119
+ resources: {
120
+ description: 'MCP resources for discovering design system capabilities',
121
+ available: [
122
+ {
123
+ resource: 'designsystem://components',
124
+ purpose: 'List all available components',
125
+ },
126
+ {
127
+ resource: 'designsystem://components/{name}',
128
+ purpose: 'Get detailed component documentation',
129
+ },
130
+ {
131
+ resource: 'designsystem://tokens',
132
+ purpose: 'List all token categories',
133
+ },
134
+ {
135
+ resource: 'designsystem://tokens/{category}',
136
+ purpose: 'Get tokens for specific category (color, space, font, etc.)',
137
+ },
138
+ {
139
+ resource: 'designsystem://guides/setup',
140
+ purpose: 'Installation instructions',
141
+ },
142
+ {
143
+ resource: 'designsystem://guides/principles',
144
+ purpose: 'This guide - design system usage principles',
145
+ },
146
+ ],
147
+ },
148
+ };
149
+
150
+ export const getPrinciplesGuide = async () => {
151
+ return {
152
+ contents: [
153
+ {
154
+ uri: 'designsystem://guides/principles',
155
+ mimeType: 'application/json',
156
+ text: JSON.stringify(designSystemPrinciples, null, 2),
157
+ },
158
+ ],
159
+ };
160
+ };
@@ -0,0 +1,72 @@
1
+ import { getSetupGuide } from './setup.js';
2
+ import { describe, expect, it } from 'vitest';
3
+
4
+ describe('getSetupGuide resource', () => {
5
+ it('should return all guides when no type is specified', async () => {
6
+ const result = await getSetupGuide();
7
+ const data = JSON.parse(result.contents[0].text);
8
+
9
+ expect(data.message).toBeDefined();
10
+ expect(data.options).toBeDefined();
11
+ expect(Array.isArray(data.options)).toBe(true);
12
+ expect(data.options).toHaveLength(2);
13
+ expect(data.options.some((opt: any) => opt.type === 'npm')).toBe(true);
14
+ expect(data.options.some((opt: any) => opt.type === 'cdn')).toBe(true);
15
+ });
16
+
17
+ it('should return npm guide with correct structure', async () => {
18
+ const result = await getSetupGuide('npm');
19
+ const data = JSON.parse(result.contents[0].text);
20
+
21
+ expect(data.name).toBe('NPM Stylesheet Setup');
22
+ expect(data.description).toBeDefined();
23
+ expect(Array.isArray(data.steps)).toBe(true);
24
+ expect(data.steps.length).toBeGreaterThan(0);
25
+ expect(data.notes).toBeDefined();
26
+ });
27
+
28
+ it('should return cdn guide with correct structure', async () => {
29
+ const result = await getSetupGuide('cdn');
30
+ const data = JSON.parse(result.contents[0].text);
31
+
32
+ expect(data.name).toBe('CDN Stylesheet Setup');
33
+ expect(data.description).toBeDefined();
34
+ expect(Array.isArray(data.steps)).toBe(true);
35
+ expect(data.steps.length).toBeGreaterThan(0);
36
+ });
37
+
38
+ it('should return error for invalid guide type', async () => {
39
+ const result = await getSetupGuide('invalid');
40
+ const data = JSON.parse(result.contents[0].text);
41
+
42
+ expect(data.error).toBe("Setup guide 'invalid' not found");
43
+ expect(data.available).toBeDefined();
44
+ expect(Array.isArray(data.available)).toBe(true);
45
+ });
46
+
47
+ it('should include code snippets in steps', async () => {
48
+ const result = await getSetupGuide('npm');
49
+ const data = JSON.parse(result.contents[0].text);
50
+ const firstStep = data.steps[0];
51
+
52
+ expect(firstStep).toHaveProperty('title');
53
+ expect(firstStep).toHaveProperty('code');
54
+ expect(firstStep).toHaveProperty('language');
55
+ });
56
+
57
+ it('should return contents with correct URI and mimeType for npm', async () => {
58
+ const result = await getSetupGuide('npm');
59
+
60
+ expect(result.contents).toBeDefined();
61
+ expect(result.contents).toHaveLength(1);
62
+ expect(result.contents[0].uri).toBe('designsystem://guides/setup/npm');
63
+ expect(result.contents[0].mimeType).toBe('application/json');
64
+ });
65
+
66
+ it('should handle case-insensitive guide type', async () => {
67
+ const lowerResult = await getSetupGuide('npm');
68
+ const upperResult = await getSetupGuide('NPM');
69
+
70
+ expect(JSON.parse(lowerResult.contents[0].text)).toEqual(JSON.parse(upperResult.contents[0].text));
71
+ });
72
+ });