UNPKG

igniteui-theming

Version:

A set of Sass variables, mixins, and functions for generating palettes, typography, and elevations used by Ignite UI components.

286 lines (285 loc) 11.5 kB
#!/usr/bin/env node import { ACCENT_SHADE_LEVELS, PALETTE_COLOR_GROUPS, SHADE_LEVELS } from "./utils/types.js"; import { RESOURCE_DEFINITIONS, getResourceContent } from "./resources/presets.js"; import "./resources/index.js"; import { TOOL_DESCRIPTIONS } from "./tools/descriptions.js"; import { handleGetColor } from "./tools/handlers/color.js"; import { handleCreateComponentTheme } from "./tools/handlers/component-theme.js"; import { handleGetComponentDesignTokens } from "./tools/handlers/component-tokens.js"; import { handleCreateCustomPalette } from "./tools/handlers/custom-palette.js"; import { handleCreateElevations } from "./tools/handlers/elevations.js"; import { handleSetRoundness, handleSetSize, handleSetSpacing } from "./tools/handlers/layout.js"; import { handleCreatePalette } from "./tools/handlers/palette.js"; import { handleDetectPlatform } from "./tools/handlers/platform.js"; import { handleReadResource } from "./tools/handlers/resource.js"; import { handleCreateTheme } from "./tools/handlers/theme.js"; import { handleCreateTypography } from "./tools/handlers/typography.js"; import { createComponentThemeSchema, createCustomPaletteSchema, createElevationsSchema, createPaletteSchema, createThemeSchema, createTypographySchema, detectPlatformSchema, getColorSchema, getComponentDesignTokensSchema, readResourceSchema, setRoundnessSchema, setSizeSchema, setSpacingInputSchema, setSpacingSchema } from "./tools/schemas.js"; import "./tools/index.js"; import { withPreprocessing } from "./utils/preprocessing.js"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; //#region src/index.ts /** * Ignite UI Theming MCP Server * * A Model Context Protocol server for generating Ignite UI theming code. * Provides tools for creating palettes, typography, elevations, and complete themes. */ /** * Create and configure the MCP server. */ function createServer() { const server = new McpServer({ name: "igniteui-theming", version: "v26.1.0", description: "Generate Sass theming code for Ignite UI components - create palettes, typography, elevations, and complete themes" }); registerTools(server); registerResources(server); return server; } /** * Register all theming tools. */ function registerTools(server) { server.registerTool("detect_platform", { title: "Detect Target Platform", description: TOOL_DESCRIPTIONS.detect_platform, inputSchema: { packageJsonPath: detectPlatformSchema.shape.packageJsonPath } }, async (params) => { return handleDetectPlatform(detectPlatformSchema.parse(params)); }); server.registerTool("create_palette", { title: "Create Color Palette", description: TOOL_DESCRIPTIONS.create_palette, inputSchema: { platform: createPaletteSchema.shape.platform, licensed: createPaletteSchema.shape.licensed, variant: createPaletteSchema.shape.variant, name: createPaletteSchema.shape.name, output: createPaletteSchema.shape.output, primary: createPaletteSchema.shape.primary, secondary: createPaletteSchema.shape.secondary, surface: createPaletteSchema.shape.surface, gray: createPaletteSchema.shape.gray, info: createPaletteSchema.shape.info, success: createPaletteSchema.shape.success, warn: createPaletteSchema.shape.warn, error: createPaletteSchema.shape.error } }, async (params) => { return await handleCreatePalette(createPaletteSchema.parse(params)); }); server.registerTool("create_custom_palette", { title: "Create Custom Handmade Palette", description: TOOL_DESCRIPTIONS.create_custom_palette, inputSchema: { platform: createCustomPaletteSchema.shape.platform, licensed: createCustomPaletteSchema.shape.licensed, variant: createCustomPaletteSchema.shape.variant, designSystem: createCustomPaletteSchema.shape.designSystem, name: createCustomPaletteSchema.shape.name, output: createCustomPaletteSchema.shape.output, primary: createCustomPaletteSchema.shape.primary, secondary: createCustomPaletteSchema.shape.secondary, surface: createCustomPaletteSchema.shape.surface, gray: createCustomPaletteSchema.shape.gray, info: createCustomPaletteSchema.shape.info, success: createCustomPaletteSchema.shape.success, warn: createCustomPaletteSchema.shape.warn, error: createCustomPaletteSchema.shape.error } }, withPreprocessing(createCustomPaletteSchema, handleCreateCustomPalette)); server.registerTool("create_typography", { title: "Create Typography", description: TOOL_DESCRIPTIONS.create_typography, inputSchema: { platform: createTypographySchema.shape.platform, licensed: createTypographySchema.shape.licensed, fontFamily: createTypographySchema.shape.fontFamily, designSystem: createTypographySchema.shape.designSystem, customScale: createTypographySchema.shape.customScale, name: createTypographySchema.shape.name } }, withPreprocessing(createTypographySchema, handleCreateTypography)); server.registerTool("create_elevations", { title: "Create Elevations", description: TOOL_DESCRIPTIONS.create_elevations, inputSchema: { platform: createElevationsSchema.shape.platform, licensed: createElevationsSchema.shape.licensed, designSystem: createElevationsSchema.shape.designSystem, name: createElevationsSchema.shape.name } }, async (params) => { return handleCreateElevations(createElevationsSchema.parse(params)); }); server.registerTool("create_theme", { title: "Create Complete Theme", description: TOOL_DESCRIPTIONS.create_theme, inputSchema: { platform: createThemeSchema.shape.platform, licensed: createThemeSchema.shape.licensed, designSystem: createThemeSchema.shape.designSystem, primaryColor: createThemeSchema.shape.primaryColor, secondaryColor: createThemeSchema.shape.secondaryColor, surfaceColor: createThemeSchema.shape.surfaceColor, variant: createThemeSchema.shape.variant, name: createThemeSchema.shape.name, fontFamily: createThemeSchema.shape.fontFamily, includeTypography: createThemeSchema.shape.includeTypography, includeElevations: createThemeSchema.shape.includeElevations, includeSpacing: createThemeSchema.shape.includeSpacing } }, async (params) => { return await handleCreateTheme(createThemeSchema.parse(params)); }); server.registerTool("set_size", { title: "Set Size Scale", description: TOOL_DESCRIPTIONS.set_size, inputSchema: { platform: setSizeSchema.shape.platform, component: setSizeSchema.shape.component, scope: setSizeSchema.shape.scope, size: setSizeSchema.shape.size, output: setSizeSchema.shape.output } }, async (params) => { return handleSetSize(setSizeSchema.parse(params)); }); server.registerTool("set_spacing", { title: "Set Spacing Scale", description: TOOL_DESCRIPTIONS.set_spacing, inputSchema: { platform: setSpacingInputSchema.shape.platform, component: setSpacingInputSchema.shape.component, scope: setSpacingInputSchema.shape.scope, spacing: setSpacingInputSchema.shape.spacing, inline: setSpacingInputSchema.shape.inline, block: setSpacingInputSchema.shape.block, output: setSpacingInputSchema.shape.output } }, async (params) => { return handleSetSpacing(setSpacingSchema.parse(params)); }); server.registerTool("set_roundness", { title: "Set Roundness Scale", description: TOOL_DESCRIPTIONS.set_roundness, inputSchema: { platform: setRoundnessSchema.shape.platform, component: setRoundnessSchema.shape.component, scope: setRoundnessSchema.shape.scope, radiusFactor: setRoundnessSchema.shape.radiusFactor, output: setRoundnessSchema.shape.output } }, async (params) => { return handleSetRoundness(setRoundnessSchema.parse(params)); }); server.registerTool("get_component_design_tokens", { title: "Get Component Design Tokens", description: TOOL_DESCRIPTIONS.get_component_design_tokens, inputSchema: { component: getComponentDesignTokensSchema.shape.component } }, async (params) => { return await handleGetComponentDesignTokens(getComponentDesignTokensSchema.parse(params)); }); server.registerTool("create_component_theme", { title: "Create Component Theme", description: TOOL_DESCRIPTIONS.create_component_theme, inputSchema: { platform: createComponentThemeSchema.shape.platform, licensed: createComponentThemeSchema.shape.licensed, designSystem: createComponentThemeSchema.shape.designSystem, variant: createComponentThemeSchema.shape.variant, component: createComponentThemeSchema.shape.component, tokens: createComponentThemeSchema.shape.tokens, selector: createComponentThemeSchema.shape.selector, name: createComponentThemeSchema.shape.name, output: createComponentThemeSchema.shape.output } }, withPreprocessing(createComponentThemeSchema, handleCreateComponentTheme)); server.registerTool("get_color", { title: "Get Palette Color", description: TOOL_DESCRIPTIONS.get_color, inputSchema: { color: z.enum(PALETTE_COLOR_GROUPS), variant: z.enum([...SHADE_LEVELS, ...ACCENT_SHADE_LEVELS]).optional(), contrast: z.boolean().optional(), opacity: z.number().min(0).max(1).optional() } }, async (params) => { return handleGetColor(getColorSchema.parse(params)); }); server.registerTool("read_resource", { title: "Read Theming Resource", description: buildReadResourceDescription(), inputSchema: { uri: readResourceSchema.shape.uri } }, async (params) => { return handleReadResource(readResourceSchema.parse(params)); }); } /** * Build the read_resource tool description dynamically from RESOURCE_DEFINITIONS. * Groups resources by URI path prefix and appends the catalog to the static description. */ function buildReadResourceDescription() { const groups = { Platforms: [], Presets: [], Guidance: [], "Layout Docs": [] }; for (const r of RESOURCE_DEFINITIONS) if (r.uri.includes("://platforms")) groups.Platforms.push(r); else if (r.uri.includes("://presets/")) groups.Presets.push(r); else if (r.uri.includes("://guidance/")) groups.Guidance.push(r); else if (r.uri.includes("://docs/")) groups["Layout Docs"].push(r); const lines = [ TOOL_DESCRIPTIONS.read_resource, "", "<available_resources>" ]; for (const [groupName, resources] of Object.entries(groups)) { if (resources.length === 0) continue; lines.push(` ${groupName}:`); for (const r of resources) lines.push(` - "${r.uri}" — ${r.name}`); } lines.push("</available_resources>"); return lines.join("\n"); } /** * Register all theming resources. */ function registerResources(server) { for (const resource of RESOURCE_DEFINITIONS) server.registerResource(resource.name.toLowerCase().replace(/\s+/g, "-"), resource.uri, { title: resource.name, description: resource.description, mimeType: resource.mimeType }, async (uri) => { const content = getResourceContent(uri.href); if (!content) throw new Error(`Resource not found: ${uri.href}`); return { contents: [{ uri: uri.href, mimeType: content.mimeType, text: content.content }] }; }); } /** * Main entry point - start the MCP server with STDIO transport. */ async function main() { const server = createServer(); const transport = new StdioServerTransport(); await server.connect(transport); const shutdown = async () => { await server.close(); process.exit(0); }; process.on("SIGINT", shutdown); process.on("SIGTERM", shutdown); } main().catch((_error) => { process.exit(1); }); //#endregion