Skip to content

Commit 7c1d36f

Browse files
Extract remaining tools (#27)
* Create read tool file method * extract the theme generator * Finish tool class extractions # Conflicts: # src/index.ts # src/tools/replace-hard-coded-values-tool.ts * Extract md files * specifiy import type * update type * removed unused parameter * removed useless variable stuff
1 parent a8fdcbb commit 7c1d36f

24 files changed

+1302
-1372
lines changed

src/_internal/resource-path.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,11 @@ const readPromptFile = async (filename: string): Promise<string> => {
1616
return readFileSync(filePath, 'utf-8')
1717
}
1818

19-
export { readResourceFile, readPromptFile }
19+
const readToolFile = async (filename: string): Promise<string> => {
20+
const currentDir = dirname(fileURLToPath(import.meta.url))
21+
const filePath = join(currentDir, '..', 'tools', filename)
22+
23+
return readFileSync(filePath, 'utf-8')
24+
}
25+
26+
export { readResourceFile, readPromptFile, readToolFile }

src/index.ts

Lines changed: 13 additions & 196 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,6 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
1212
import type { ListPromptsRequestSchema, GetPromptRequestSchema } from "@modelcontextprotocol/sdk/types"
1313
import { z } from 'zod';
1414
import { designTokens } from './optics-data.js';
15-
import { generateTheme } from './tools/theme-generator.js';
16-
import { validateTokenUsage, formatValidationReport } from './tools/validate.js';
17-
18-
import { checkTokenContrast, formatContrastResult } from './tools/accessibility.js';
19-
import { suggestTokenMigration, formatMigrationSuggestions } from './tools/migration.js';
20-
import { generateComponentScaffold, formatScaffoldOutput } from './tools/scaffold.js';
21-
import { generateStickerSheet, formatStickerSheet } from './tools/sticker-sheet.js';
2215

2316
// Resources
2417
import * as systemOverview from './resources/system-overview.js';
@@ -43,7 +36,13 @@ import ListComponentsTool from './tools/list-components-tool.js'
4336
import GetComponentInfoTool from './tools/get-component-info-tool.js';
4437
import GetComponentTokensTool from './tools/get-component-tokens-tool.js';
4538
import SearchDocumentationTool from './tools/search-documentation-tool.js';
39+
import GenerateThemeTool from './tools/generate-theme-tool.js';
40+
import ValidateTokenUsageTool from './tools/validate-token-usage-tool.js';
4641
import ReplaceHardCodedValuesTool from './tools/replace-hard-coded-values-tool.js';
42+
import CheckContrastTool from './tools/check-contrast-tool.js';
43+
import SuggestTokenMigrationTool from './tools/suggest-token-migration-tool.js';
44+
import GenerateComponentScaffoldTool from './tools/generate-component-scaffold-tool.js';
45+
import GenerateStickerSheetTool from './tools/generate-sticker-sheet-tool.js';
4746

4847
/**
4948
* Create and configure the MCP server
@@ -189,7 +188,13 @@ const tools = [
189188
new GetComponentInfoTool(),
190189
new GetComponentTokensTool(),
191190
new SearchDocumentationTool(),
192-
new ReplaceHardCodedValuesTool()
191+
new GenerateThemeTool(),
192+
new ValidateTokenUsageTool(),
193+
new ReplaceHardCodedValuesTool(),
194+
new CheckContrastTool(),
195+
new SuggestTokenMigrationTool(),
196+
new GenerateComponentScaffoldTool(),
197+
new GenerateStickerSheetTool()
193198
]
194199

195200
tools.forEach((tool) => {
@@ -215,194 +220,6 @@ tools.forEach((tool) => {
215220
)
216221
})
217222

218-
/**
219-
* Tool: Generate Theme
220-
*/
221-
server.registerTool(
222-
'generate_theme',
223-
{
224-
title: 'Generate Theme',
225-
description: 'Generate a custom Optics theme with CSS variable overrides',
226-
inputSchema: {
227-
brandName: z.string().describe('Name of the brand/theme (e.g., "Acme Corp")'),
228-
primary: z.string().describe('Primary brand color (hex, e.g., "#0066CC")'),
229-
secondary: z.string().optional().describe('Secondary color (hex, optional)'),
230-
},
231-
},
232-
async ({ brandName, primary, secondary }) => {
233-
const brandColors = {
234-
primary,
235-
secondary,
236-
};
237-
238-
const theme = generateTheme(brandName, brandColors);
239-
240-
return {
241-
content: [
242-
{
243-
type: 'text',
244-
text: `# ${brandName} Theme Generated\n\n## CSS Variables\n\n\`\`\`css\n${theme.cssVariables}\n\`\`\`\n\n## Figma Variables\n\nSave this as \`figma-variables.json\`:\n\n\`\`\`json\n${theme.figmaVariables}\n\`\`\`\n\n## Summary\n\n- **Total tokens**: ${theme.tokens.length}\n- **Colors**: ${theme.tokens.filter(t => t.category === 'color').length}\n- **Typography**: ${theme.tokens.filter(t => t.category === 'typography').length}\n- **Spacing**: ${theme.tokens.filter(t => t.category === 'spacing').length}\n\n${theme.documentation}`,
245-
},
246-
],
247-
};
248-
}
249-
);
250-
251-
/**
252-
* Tool: Validate Token Usage
253-
*/
254-
server.registerTool(
255-
'validate_token_usage',
256-
{
257-
title: 'Validate Token Usage',
258-
description: 'Validate code for hard-coded values that should use design tokens',
259-
inputSchema: {
260-
code: z.string().describe('CSS or component code to validate'),
261-
},
262-
},
263-
async ({ code }) => {
264-
const report = validateTokenUsage(code, designTokens);
265-
const formatted = formatValidationReport(report);
266-
267-
return {
268-
content: [
269-
{
270-
type: 'text',
271-
text: formatted,
272-
},
273-
],
274-
};
275-
}
276-
);
277-
278-
279-
280-
/**
281-
* Tool: Check Contrast
282-
*/
283-
server.registerTool(
284-
'check_contrast',
285-
{
286-
title: 'Check Contrast',
287-
description: 'Check WCAG contrast ratio between two color tokens',
288-
inputSchema: {
289-
foregroundToken: z.string().describe('Foreground color token name'),
290-
backgroundToken: z.string().describe('Background color token name'),
291-
},
292-
},
293-
async ({ foregroundToken, backgroundToken }) => {
294-
const result = checkTokenContrast(foregroundToken, backgroundToken, designTokens);
295-
const formatted = formatContrastResult(result);
296-
297-
return {
298-
content: [
299-
{
300-
type: 'text',
301-
text: formatted,
302-
},
303-
],
304-
};
305-
}
306-
);
307-
308-
/**
309-
* Tool: Suggest Token Migration
310-
*/
311-
server.registerTool(
312-
'suggest_token_migration',
313-
{
314-
title: 'Suggest Token Migration',
315-
description: 'Suggest design tokens for a hard-coded value',
316-
inputSchema: {
317-
value: z.string().describe('Hard-coded value to find tokens for (e.g., "#0066CC", "16px")'),
318-
category: z.string().optional().describe('Optional category filter (color, spacing, typography)'),
319-
},
320-
},
321-
async ({ value, category }) => {
322-
const suggestion = suggestTokenMigration(value, designTokens, category);
323-
const formatted = formatMigrationSuggestions(suggestion);
324-
325-
return {
326-
content: [
327-
{
328-
type: 'text',
329-
text: formatted,
330-
},
331-
],
332-
};
333-
}
334-
);
335-
336-
/**
337-
* Tool: Generate Component Scaffold
338-
*/
339-
server.registerTool(
340-
'generate_component_scaffold',
341-
{
342-
title: 'Generate Component Scaffold',
343-
description: 'Generate a React component scaffold with proper token usage',
344-
inputSchema: {
345-
componentName: z.string().describe('Name of the component (e.g., "Alert", "Card")'),
346-
description: z.string().describe('Brief description of the component'),
347-
tokens: z.array(z.string()).describe('List of token names the component should use'),
348-
},
349-
},
350-
async ({ componentName, description, tokens }) => {
351-
const scaffold = generateComponentScaffold(
352-
componentName,
353-
description,
354-
tokens,
355-
designTokens
356-
);
357-
const formatted = formatScaffoldOutput(scaffold);
358-
359-
return {
360-
content: [
361-
{
362-
type: 'text',
363-
text: formatted,
364-
},
365-
],
366-
};
367-
}
368-
);
369-
370-
/**
371-
* Tool: Generate Sticker Sheet
372-
*/
373-
server.registerTool(
374-
'generate_sticker_sheet',
375-
{
376-
title: 'Generate Sticker Sheet',
377-
description: 'Generate a visual style guide with color swatches and component examples',
378-
inputSchema: {
379-
framework: z.enum(['react', 'vue', 'svelte', 'html']).optional().describe('Target framework (default: react)'),
380-
includeColors: z.boolean().optional().describe('Include color swatches (default: true)'),
381-
includeTypography: z.boolean().optional().describe('Include typography specimens (default: true)'),
382-
includeComponents: z.boolean().optional().describe('Include component examples (default: true)'),
383-
},
384-
},
385-
async ({ framework, includeColors, includeTypography, includeComponents }) => {
386-
const options = {
387-
framework: framework ?? 'react',
388-
includeColors: includeColors ?? true,
389-
includeTypography: includeTypography ?? true,
390-
includeComponents: includeComponents ?? true,
391-
};
392-
const sheet = generateStickerSheet(designTokens, components, options);
393-
const formatted = formatStickerSheet(sheet);
394-
395-
return {
396-
content: [
397-
{
398-
type: 'text',
399-
text: formatted,
400-
},
401-
],
402-
};
403-
}
404-
);
405-
406223
/**
407224
* Start the server
408225
*/

src/tools/accessibility.ts

Lines changed: 0 additions & 148 deletions
This file was deleted.

0 commit comments

Comments
 (0)