@forgespace/branding-mcp 0.4.0 → 0.5.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/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.5.0] - 2026-02-28
6
+
7
+ ### Added
8
+
9
+ - New MCP tool: `generate_design_system` — complete design system in one call (identity + token export combined)
10
+ - 10 new tests for design system tool (198 total across 16 suites)
11
+
5
12
  ## [0.4.0] - 2026-02-28
6
13
 
7
14
  ### Added
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [![CI](https://github.com/Forge-Space/branding-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/Forge-Space/branding-mcp/actions/workflows/ci.yml)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
7
 
8
- Generate complete design systems — colors, typography, spacing, shadows, borders, motion tokens, gradients, multi-variant logos, favicons, and OG images with multi-format export. 8 MCP tools, zero API dependencies, algorithmic-first generation.
8
+ Generate complete design systems — colors, typography, spacing, shadows, borders, motion tokens, gradients, multi-variant logos, favicons, and OG images with multi-format export. 9 MCP tools, zero API dependencies, algorithmic-first generation.
9
9
 
10
10
  ## Features
11
11
 
@@ -45,16 +45,17 @@ npm run build
45
45
 
46
46
  ### MCP Tools
47
47
 
48
- | Tool | Description |
49
- | ---------------------------- | -------------------------------------------------- |
50
- | `generate_brand_identity` | Complete brand from name, industry, and style |
51
- | `generate_color_palette` | Color palette with harmony and WCAG data |
52
- | `generate_typography_system` | Font pairing + modular type scale |
53
- | `export_design_tokens` | Export brand to JSON/CSS/Tailwind/Figma/React/Sass |
54
- | `create_brand_guidelines` | Generate HTML brand book |
55
- | `validate_brand_consistency` | Check WCAG compliance and completeness |
56
- | `refine_brand_element` | Iterate on specific brand elements |
57
- | `generate_brand_assets` | Generate favicons and OG images from brand |
48
+ | Tool | Description |
49
+ | ---------------------------- | ------------------------------------------------------ |
50
+ | `generate_brand_identity` | Complete brand from name, industry, and style |
51
+ | `generate_color_palette` | Color palette with harmony and WCAG data |
52
+ | `generate_typography_system` | Font pairing + modular type scale |
53
+ | `export_design_tokens` | Export brand to JSON/CSS/Tailwind/Figma/React/Sass |
54
+ | `create_brand_guidelines` | Generate HTML brand book |
55
+ | `validate_brand_consistency` | Check WCAG compliance and completeness |
56
+ | `refine_brand_element` | Iterate on specific brand elements |
57
+ | `generate_brand_assets` | Generate favicons and OG images from brand |
58
+ | `generate_design_system` | Complete design system in one call (identity + export) |
58
59
 
59
60
  ### MCP Resources
60
61
 
package/dist/index.js CHANGED
@@ -11,6 +11,7 @@ import { registerCreateBrandGuidelines } from './tools/create-brand-guidelines.j
11
11
  import { registerValidateBrandConsistency } from './tools/validate-brand-consistency.js';
12
12
  import { registerRefineBrandElement } from './tools/refine-brand-element.js';
13
13
  import { registerGenerateBrandAssets } from './tools/generate-brand-assets.js';
14
+ import { registerGenerateDesignSystem } from './tools/generate-design-system.js';
14
15
  import { registerBrandTemplates } from './resources/brand-templates.js';
15
16
  import { registerBrandKnowledge } from './resources/brand-knowledge.js';
16
17
  async function main() {
@@ -28,6 +29,7 @@ async function main() {
28
29
  registerValidateBrandConsistency(server);
29
30
  registerRefineBrandElement(server);
30
31
  registerGenerateBrandAssets(server);
32
+ registerGenerateDesignSystem(server);
31
33
  registerBrandTemplates(server);
32
34
  registerBrandKnowledge(server);
33
35
  const transport = new StdioServerTransport();
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,OAAO,EAAE,6BAA6B,EAAE,MAAM,oCAAoC,CAAC;AACnF,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,EAAE,gCAAgC,EAAE,MAAM,uCAAuC,CAAC;AACzF,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAC7E,OAAO,EAAE,6BAA6B,EAAE,MAAM,oCAAoC,CAAC;AACnF,OAAO,EAAE,gCAAgC,EAAE,MAAM,uCAAuC,CAAC;AACzF,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAC7E,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAE/E,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAExE,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,OAAO,EAAE,EAAE,8BAA8B,CAAC,CAAC;IAErE,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,0BAA0B;QAChC,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,6BAA6B,CAAC,MAAM,CAAC,CAAC;IACtC,4BAA4B,CAAC,MAAM,CAAC,CAAC;IACrC,gCAAgC,CAAC,MAAM,CAAC,CAAC;IACzC,0BAA0B,CAAC,MAAM,CAAC,CAAC;IACnC,6BAA6B,CAAC,MAAM,CAAC,CAAC;IACtC,gCAAgC,CAAC,MAAM,CAAC,CAAC;IACzC,0BAA0B,CAAC,MAAM,CAAC,CAAC;IACnC,2BAA2B,CAAC,MAAM,CAAC,CAAC;IAEpC,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAE/B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,MAAM,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;AACzD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,qCAAqC,CAAC,CAAC;IAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;IACzB,MAAM,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;IAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;IACxB,MAAM,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;IAC9C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,OAAO,EAAE,6BAA6B,EAAE,MAAM,oCAAoC,CAAC;AACnF,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,EAAE,gCAAgC,EAAE,MAAM,uCAAuC,CAAC;AACzF,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAC7E,OAAO,EAAE,6BAA6B,EAAE,MAAM,oCAAoC,CAAC;AACnF,OAAO,EAAE,gCAAgC,EAAE,MAAM,uCAAuC,CAAC;AACzF,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAC7E,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AAEjF,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAExE,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,OAAO,EAAE,EAAE,8BAA8B,CAAC,CAAC;IAErE,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,0BAA0B;QAChC,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,6BAA6B,CAAC,MAAM,CAAC,CAAC;IACtC,4BAA4B,CAAC,MAAM,CAAC,CAAC;IACrC,gCAAgC,CAAC,MAAM,CAAC,CAAC;IACzC,0BAA0B,CAAC,MAAM,CAAC,CAAC;IACnC,6BAA6B,CAAC,MAAM,CAAC,CAAC;IACtC,gCAAgC,CAAC,MAAM,CAAC,CAAC;IACzC,0BAA0B,CAAC,MAAM,CAAC,CAAC;IACnC,2BAA2B,CAAC,MAAM,CAAC,CAAC;IACpC,4BAA4B,CAAC,MAAM,CAAC,CAAC;IAErC,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAE/B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,MAAM,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;AACzD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,qCAAqC,CAAC,CAAC;IAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;IACzB,MAAM,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;IAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;IACxB,MAAM,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;IAC9C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerGenerateDesignSystem(server: McpServer): void;
3
+ //# sourceMappingURL=generate-design-system.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-design-system.d.ts","sourceRoot":"","sources":["../../src/tools/generate-design-system.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAyGzE,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAuDpE"}
@@ -0,0 +1,104 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { z } from 'zod';
3
+ import { generateColorPalette, generateTypographySystem, generateSpacingScale, generateShadowSystem, generateBorderSystem, generateMotionSystem, generateGradientSystem, generateSvgLogo, defaultLogoConfig, exportDesignTokens, exportCssVariables, exportTailwindPreset, exportFigmaTokens, exportReactTheme, exportSassVariables, } from '../lib/branding-core/index.js';
4
+ import { brandStyleSchema, colorHarmonySchema, colorThemeSchema, exportFormatSchema, fontCategorySchema, hexColorSchema, typeScaleRatioSchema, } from '../lib/branding-core/validators/token-schema.js';
5
+ import { logger } from '../lib/logger.js';
6
+ const STYLE_DEFAULTS = {
7
+ minimal: { heading: 'sans-serif', body: 'sans-serif' },
8
+ bold: { heading: 'display', body: 'sans-serif' },
9
+ elegant: { heading: 'serif', body: 'serif' },
10
+ playful: { heading: 'display', body: 'sans-serif' },
11
+ corporate: { heading: 'sans-serif', body: 'sans-serif' },
12
+ tech: { heading: 'sans-serif', body: 'monospace' },
13
+ organic: { heading: 'serif', body: 'sans-serif' },
14
+ retro: { heading: 'display', body: 'serif' },
15
+ };
16
+ const EXPORTERS = {
17
+ json: exportDesignTokens,
18
+ css: exportCssVariables,
19
+ tailwind: exportTailwindPreset,
20
+ figma: exportFigmaTokens,
21
+ react: exportReactTheme,
22
+ sass: exportSassVariables,
23
+ };
24
+ function buildIdentity(params) {
25
+ const defaults = STYLE_DEFAULTS[params.style];
26
+ const harmony = (params.harmony ?? 'complementary');
27
+ const theme = params.theme;
28
+ const scaleRatio = (params.scaleRatio ?? 'major-third');
29
+ const colors = generateColorPalette(params.baseColor, harmony, theme);
30
+ const typography = generateTypographySystem(params.headingCategory ?? defaults.heading, params.bodyCategory ?? defaults.body, scaleRatio);
31
+ const spacing = generateSpacingScale();
32
+ const shadows = generateShadowSystem(colors.primary.hex, theme);
33
+ const borders = generateBorderSystem(params.style);
34
+ const motion = generateMotionSystem(params.style);
35
+ const gradients = generateGradientSystem(colors, params.style);
36
+ const logoConfig = {
37
+ ...defaultLogoConfig(params.brandName, colors.primary.hex),
38
+ font: typography.headingFont,
39
+ style: params.style,
40
+ };
41
+ const logo = generateSvgLogo(logoConfig);
42
+ return {
43
+ id: `brand_${randomUUID().slice(0, 8)}`,
44
+ name: params.brandName,
45
+ tagline: params.tagline,
46
+ industry: params.industry,
47
+ style: params.style,
48
+ colors,
49
+ typography,
50
+ spacing,
51
+ shadows,
52
+ borders,
53
+ motion,
54
+ gradients,
55
+ logo,
56
+ createdAt: new Date().toISOString(),
57
+ };
58
+ }
59
+ export function registerGenerateDesignSystem(server) {
60
+ server.tool('generate_design_system', 'Generate a complete design system with brand identity and exported tokens in one call. ' +
61
+ 'Combines generate_brand_identity + export_design_tokens for a streamlined workflow.', {
62
+ brandName: z.string().min(1).max(100).describe('Brand name'),
63
+ industry: z.string().min(1).max(100).describe('Industry or sector'),
64
+ style: brandStyleSchema.describe('Visual style direction'),
65
+ tagline: z.string().max(200).optional().describe('Brand tagline'),
66
+ baseColor: hexColorSchema.optional().describe('Base color preference'),
67
+ harmony: colorHarmonySchema.optional().describe('Color harmony type'),
68
+ theme: colorThemeSchema.optional().describe('Light/dark/both'),
69
+ headingCategory: fontCategorySchema.optional().describe('Heading font category'),
70
+ bodyCategory: fontCategorySchema.optional().describe('Body font category'),
71
+ scaleRatio: typeScaleRatioSchema.optional().describe('Typography scale ratio'),
72
+ exportFormats: z
73
+ .array(exportFormatSchema)
74
+ .min(1)
75
+ .max(6)
76
+ .describe('Token export formats to include'),
77
+ }, async (params) => {
78
+ try {
79
+ logger.info({ brandName: params.brandName, formats: params.exportFormats }, 'Generating design system');
80
+ const identity = buildIdentity(params);
81
+ const exports = {};
82
+ for (const format of params.exportFormats) {
83
+ const exporter = EXPORTERS[format];
84
+ const result = exporter(identity);
85
+ exports[format] = typeof result === 'string' ? result : JSON.stringify(result, null, 2);
86
+ }
87
+ const output = {
88
+ identity,
89
+ exports,
90
+ };
91
+ return {
92
+ content: [{ type: 'text', text: JSON.stringify(output, null, 2) }],
93
+ };
94
+ }
95
+ catch (error) {
96
+ const message = error instanceof Error ? error.message : String(error);
97
+ return {
98
+ content: [{ type: 'text', text: `Error generating design system: ${message}` }],
99
+ isError: true,
100
+ };
101
+ }
102
+ });
103
+ }
104
+ //# sourceMappingURL=generate-design-system.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-design-system.js","sourceRoot":"","sources":["../../src/tools/generate-design-system.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forgespace/branding-mcp",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "MCP server for AI-powered brand identity generation — color palettes, typography systems, design tokens, and brand guidelines with multi-format export",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -0,0 +1,176 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { registerGenerateDesignSystem } from '../../tools/generate-design-system.js';
3
+
4
+ function createMockServer(): McpServer & { registeredTools: Map<string, unknown> } {
5
+ const tools = new Map<string, unknown>();
6
+ return {
7
+ registeredTools: tools,
8
+ tool(name: string, _desc: string, _schema: unknown, handler: unknown) {
9
+ tools.set(name, handler);
10
+ },
11
+ } as McpServer & { registeredTools: Map<string, unknown> };
12
+ }
13
+
14
+ describe('generate_design_system tool', () => {
15
+ let server: ReturnType<typeof createMockServer>;
16
+ let handler: (
17
+ params: Record<string, unknown>
18
+ ) => Promise<{ content: Array<{ text: string }>; isError?: boolean }>;
19
+
20
+ beforeAll(() => {
21
+ server = createMockServer();
22
+ registerGenerateDesignSystem(server);
23
+ handler = server.registeredTools.get('generate_design_system') as typeof handler;
24
+ });
25
+
26
+ it('registers the tool', () => {
27
+ expect(server.registeredTools.has('generate_design_system')).toBe(true);
28
+ });
29
+
30
+ it('generates identity with all subsystems', async () => {
31
+ const result = await handler({
32
+ brandName: 'TestBrand',
33
+ industry: 'tech',
34
+ style: 'minimal',
35
+ exportFormats: ['json'],
36
+ });
37
+
38
+ const output = JSON.parse(result.content[0].text);
39
+ const identity = output.identity;
40
+
41
+ expect(identity.name).toBe('TestBrand');
42
+ expect(identity.colors).toBeDefined();
43
+ expect(identity.typography).toBeDefined();
44
+ expect(identity.spacing).toBeDefined();
45
+ expect(identity.shadows).toBeDefined();
46
+ expect(identity.borders).toBeDefined();
47
+ expect(identity.motion).toBeDefined();
48
+ expect(identity.gradients).toBeDefined();
49
+ expect(identity.logo).toBeDefined();
50
+ });
51
+
52
+ it('includes requested export formats', async () => {
53
+ const result = await handler({
54
+ brandName: 'TestBrand',
55
+ industry: 'tech',
56
+ style: 'bold',
57
+ exportFormats: ['css', 'tailwind'],
58
+ });
59
+
60
+ const output = JSON.parse(result.content[0].text);
61
+ expect(output.exports.css).toBeDefined();
62
+ expect(output.exports.tailwind).toBeDefined();
63
+ expect(output.exports.json).toBeUndefined();
64
+ });
65
+
66
+ it('exports valid CSS variables', async () => {
67
+ const result = await handler({
68
+ brandName: 'CSSTest',
69
+ industry: 'design',
70
+ style: 'elegant',
71
+ exportFormats: ['css'],
72
+ });
73
+
74
+ const output = JSON.parse(result.content[0].text);
75
+ expect(output.exports.css).toContain('--');
76
+ expect(output.exports.css).toContain(':root');
77
+ });
78
+
79
+ it('exports valid Tailwind preset', async () => {
80
+ const result = await handler({
81
+ brandName: 'TailwindTest',
82
+ industry: 'tech',
83
+ style: 'tech',
84
+ exportFormats: ['tailwind'],
85
+ });
86
+
87
+ const output = JSON.parse(result.content[0].text);
88
+ expect(output.exports.tailwind).toContain('theme');
89
+ expect(output.exports.tailwind).toContain('extend');
90
+ });
91
+
92
+ it('supports all 6 export formats at once', async () => {
93
+ const result = await handler({
94
+ brandName: 'AllFormats',
95
+ industry: 'retail',
96
+ style: 'playful',
97
+ exportFormats: ['json', 'css', 'tailwind', 'figma', 'react', 'sass'],
98
+ });
99
+
100
+ const output = JSON.parse(result.content[0].text);
101
+ expect(Object.keys(output.exports)).toHaveLength(6);
102
+ });
103
+
104
+ it('applies optional parameters', async () => {
105
+ const result = await handler({
106
+ brandName: 'CustomBrand',
107
+ industry: 'health',
108
+ style: 'organic',
109
+ tagline: 'Live naturally',
110
+ baseColor: '#2D8B4E',
111
+ harmony: 'analogous',
112
+ theme: 'light',
113
+ headingCategory: 'serif',
114
+ bodyCategory: 'sans-serif',
115
+ scaleRatio: 'golden-ratio',
116
+ exportFormats: ['json'],
117
+ });
118
+
119
+ const output = JSON.parse(result.content[0].text);
120
+ expect(output.identity.tagline).toBe('Live naturally');
121
+ expect(output.identity.style).toBe('organic');
122
+ });
123
+
124
+ it('returns error for invalid input gracefully', async () => {
125
+ const result = await handler({
126
+ brandName: 'Test',
127
+ industry: 'tech',
128
+ style: 'minimal',
129
+ exportFormats: ['json'],
130
+ });
131
+
132
+ expect(result.isError).toBeUndefined();
133
+ expect(result.content[0].text).toBeDefined();
134
+ });
135
+
136
+ it('generates unique brand IDs', async () => {
137
+ const params = {
138
+ brandName: 'UniqueTest',
139
+ industry: 'tech',
140
+ style: 'minimal' as const,
141
+ exportFormats: ['json'],
142
+ };
143
+
144
+ const r1 = await handler(params);
145
+ const r2 = await handler(params);
146
+ const id1 = JSON.parse(r1.content[0].text).identity.id;
147
+ const id2 = JSON.parse(r2.content[0].text).identity.id;
148
+ expect(id1).not.toBe(id2);
149
+ });
150
+
151
+ it('all brand styles produce valid output', async () => {
152
+ const styles = [
153
+ 'minimal',
154
+ 'bold',
155
+ 'elegant',
156
+ 'playful',
157
+ 'corporate',
158
+ 'tech',
159
+ 'organic',
160
+ 'retro',
161
+ ];
162
+
163
+ for (const style of styles) {
164
+ const result = await handler({
165
+ brandName: `${style}Brand`,
166
+ industry: 'test',
167
+ style,
168
+ exportFormats: ['json'],
169
+ });
170
+
171
+ expect(result.isError).toBeUndefined();
172
+ const output = JSON.parse(result.content[0].text);
173
+ expect(output.identity.style).toBe(style);
174
+ }
175
+ });
176
+ });
package/src/index.ts CHANGED
@@ -13,6 +13,7 @@ import { registerCreateBrandGuidelines } from './tools/create-brand-guidelines.j
13
13
  import { registerValidateBrandConsistency } from './tools/validate-brand-consistency.js';
14
14
  import { registerRefineBrandElement } from './tools/refine-brand-element.js';
15
15
  import { registerGenerateBrandAssets } from './tools/generate-brand-assets.js';
16
+ import { registerGenerateDesignSystem } from './tools/generate-design-system.js';
16
17
 
17
18
  import { registerBrandTemplates } from './resources/brand-templates.js';
18
19
  import { registerBrandKnowledge } from './resources/brand-knowledge.js';
@@ -34,6 +35,7 @@ async function main(): Promise<void> {
34
35
  registerValidateBrandConsistency(server);
35
36
  registerRefineBrandElement(server);
36
37
  registerGenerateBrandAssets(server);
38
+ registerGenerateDesignSystem(server);
37
39
 
38
40
  registerBrandTemplates(server);
39
41
  registerBrandKnowledge(server);
@@ -0,0 +1,163 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { z } from 'zod';
3
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
4
+ import {
5
+ generateColorPalette,
6
+ generateTypographySystem,
7
+ generateSpacingScale,
8
+ generateShadowSystem,
9
+ generateBorderSystem,
10
+ generateMotionSystem,
11
+ generateGradientSystem,
12
+ generateSvgLogo,
13
+ defaultLogoConfig,
14
+ exportDesignTokens,
15
+ exportCssVariables,
16
+ exportTailwindPreset,
17
+ exportFigmaTokens,
18
+ exportReactTheme,
19
+ exportSassVariables,
20
+ } from '../lib/branding-core/index.js';
21
+ import {
22
+ brandStyleSchema,
23
+ colorHarmonySchema,
24
+ colorThemeSchema,
25
+ exportFormatSchema,
26
+ fontCategorySchema,
27
+ hexColorSchema,
28
+ typeScaleRatioSchema,
29
+ } from '../lib/branding-core/validators/token-schema.js';
30
+ import type { BrandIdentity, BrandStyle, ExportFormat, FontCategory } from '../lib/types.js';
31
+ import { logger } from '../lib/logger.js';
32
+
33
+ const STYLE_DEFAULTS: Record<BrandStyle, { heading: FontCategory; body: FontCategory }> = {
34
+ minimal: { heading: 'sans-serif', body: 'sans-serif' },
35
+ bold: { heading: 'display', body: 'sans-serif' },
36
+ elegant: { heading: 'serif', body: 'serif' },
37
+ playful: { heading: 'display', body: 'sans-serif' },
38
+ corporate: { heading: 'sans-serif', body: 'sans-serif' },
39
+ tech: { heading: 'sans-serif', body: 'monospace' },
40
+ organic: { heading: 'serif', body: 'sans-serif' },
41
+ retro: { heading: 'display', body: 'serif' },
42
+ };
43
+
44
+ const EXPORTERS: Record<ExportFormat, (brand: BrandIdentity) => string | object> = {
45
+ json: exportDesignTokens,
46
+ css: exportCssVariables,
47
+ tailwind: exportTailwindPreset,
48
+ figma: exportFigmaTokens,
49
+ react: exportReactTheme,
50
+ sass: exportSassVariables,
51
+ };
52
+
53
+ function buildIdentity(params: {
54
+ brandName: string;
55
+ industry: string;
56
+ style: BrandStyle;
57
+ tagline?: string;
58
+ baseColor?: string;
59
+ harmony?: string;
60
+ theme?: string;
61
+ headingCategory?: FontCategory;
62
+ bodyCategory?: FontCategory;
63
+ scaleRatio?: string;
64
+ }): BrandIdentity {
65
+ const defaults = STYLE_DEFAULTS[params.style];
66
+ const harmony = (params.harmony ?? 'complementary') as Parameters<typeof generateColorPalette>[1];
67
+ const theme = params.theme as Parameters<typeof generateColorPalette>[2];
68
+ const scaleRatio = (params.scaleRatio ?? 'major-third') as Parameters<
69
+ typeof generateTypographySystem
70
+ >[2];
71
+
72
+ const colors = generateColorPalette(params.baseColor, harmony, theme);
73
+ const typography = generateTypographySystem(
74
+ params.headingCategory ?? defaults.heading,
75
+ params.bodyCategory ?? defaults.body,
76
+ scaleRatio
77
+ );
78
+ const spacing = generateSpacingScale();
79
+ const shadows = generateShadowSystem(colors.primary.hex, theme);
80
+ const borders = generateBorderSystem(params.style);
81
+ const motion = generateMotionSystem(params.style);
82
+ const gradients = generateGradientSystem(colors, params.style);
83
+ const logoConfig = {
84
+ ...defaultLogoConfig(params.brandName, colors.primary.hex),
85
+ font: typography.headingFont,
86
+ style: params.style,
87
+ };
88
+ const logo = generateSvgLogo(logoConfig);
89
+
90
+ return {
91
+ id: `brand_${randomUUID().slice(0, 8)}`,
92
+ name: params.brandName,
93
+ tagline: params.tagline,
94
+ industry: params.industry,
95
+ style: params.style,
96
+ colors,
97
+ typography,
98
+ spacing,
99
+ shadows,
100
+ borders,
101
+ motion,
102
+ gradients,
103
+ logo,
104
+ createdAt: new Date().toISOString(),
105
+ };
106
+ }
107
+
108
+ export function registerGenerateDesignSystem(server: McpServer): void {
109
+ server.tool(
110
+ 'generate_design_system',
111
+ 'Generate a complete design system with brand identity and exported tokens in one call. ' +
112
+ 'Combines generate_brand_identity + export_design_tokens for a streamlined workflow.',
113
+ {
114
+ brandName: z.string().min(1).max(100).describe('Brand name'),
115
+ industry: z.string().min(1).max(100).describe('Industry or sector'),
116
+ style: brandStyleSchema.describe('Visual style direction'),
117
+ tagline: z.string().max(200).optional().describe('Brand tagline'),
118
+ baseColor: hexColorSchema.optional().describe('Base color preference'),
119
+ harmony: colorHarmonySchema.optional().describe('Color harmony type'),
120
+ theme: colorThemeSchema.optional().describe('Light/dark/both'),
121
+ headingCategory: fontCategorySchema.optional().describe('Heading font category'),
122
+ bodyCategory: fontCategorySchema.optional().describe('Body font category'),
123
+ scaleRatio: typeScaleRatioSchema.optional().describe('Typography scale ratio'),
124
+ exportFormats: z
125
+ .array(exportFormatSchema)
126
+ .min(1)
127
+ .max(6)
128
+ .describe('Token export formats to include'),
129
+ },
130
+ async (params) => {
131
+ try {
132
+ logger.info(
133
+ { brandName: params.brandName, formats: params.exportFormats },
134
+ 'Generating design system'
135
+ );
136
+
137
+ const identity = buildIdentity(params);
138
+ const exports: Record<string, string> = {};
139
+
140
+ for (const format of params.exportFormats) {
141
+ const exporter = EXPORTERS[format];
142
+ const result = exporter(identity);
143
+ exports[format] = typeof result === 'string' ? result : JSON.stringify(result, null, 2);
144
+ }
145
+
146
+ const output = {
147
+ identity,
148
+ exports,
149
+ };
150
+
151
+ return {
152
+ content: [{ type: 'text' as const, text: JSON.stringify(output, null, 2) }],
153
+ };
154
+ } catch (error) {
155
+ const message = error instanceof Error ? error.message : String(error);
156
+ return {
157
+ content: [{ type: 'text' as const, text: `Error generating design system: ${message}` }],
158
+ isError: true,
159
+ };
160
+ }
161
+ }
162
+ );
163
+ }