@forgespace/branding-mcp 0.6.2 → 0.7.1

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 (79) hide show
  1. package/README.md +41 -5
  2. package/dist/index.js +1 -1
  3. package/package.json +27 -9
  4. package/server.json +29 -0
  5. package/.env.example +0 -3
  6. package/.github/PULL_REQUEST_TEMPLATE.md +0 -22
  7. package/.github/workflows/ci.yml +0 -73
  8. package/.github/workflows/release-automation.yml +0 -56
  9. package/.github/workflows/security-scan.yml +0 -37
  10. package/.gitleaks.toml +0 -14
  11. package/.prettierrc.json +0 -10
  12. package/CHANGELOG.md +0 -92
  13. package/CONTRIBUTING.md +0 -203
  14. package/data/README.md +0 -13
  15. package/docs/API.md +0 -110
  16. package/docs/DATA_SOURCES.md +0 -69
  17. package/docs/INTEGRATION.md +0 -58
  18. package/eslint.config.js +0 -52
  19. package/jest.config.js +0 -40
  20. package/src/__tests__/integration/brand-generation.test.ts +0 -84
  21. package/src/__tests__/integration/mcp-server.test.ts +0 -18
  22. package/src/__tests__/unit/ai-interpreter.test.ts +0 -172
  23. package/src/__tests__/unit/border-system.test.ts +0 -77
  24. package/src/__tests__/unit/color-palette.test.ts +0 -161
  25. package/src/__tests__/unit/contrast-checker.test.ts +0 -124
  26. package/src/__tests__/unit/design-system-tool.test.ts +0 -176
  27. package/src/__tests__/unit/design-tokens.test.ts +0 -184
  28. package/src/__tests__/unit/favicon-generator.test.ts +0 -80
  29. package/src/__tests__/unit/gradient-system.test.ts +0 -122
  30. package/src/__tests__/unit/logo-generator.test.ts +0 -146
  31. package/src/__tests__/unit/motion-system.test.ts +0 -91
  32. package/src/__tests__/unit/og-image-generator.test.ts +0 -115
  33. package/src/__tests__/unit/shadow-system.test.ts +0 -63
  34. package/src/__tests__/unit/spacing-scale.test.ts +0 -60
  35. package/src/__tests__/unit/typography-system.test.ts +0 -71
  36. package/src/index.ts +0 -76
  37. package/src/lib/branding-core/ai/brand-interpreter.ts +0 -30
  38. package/src/lib/branding-core/ai/claude-interpreter.ts +0 -76
  39. package/src/lib/branding-core/ai/intent-applier.ts +0 -59
  40. package/src/lib/branding-core/ai/keyword-interpreter.ts +0 -95
  41. package/src/lib/branding-core/ai/prompts.ts +0 -93
  42. package/src/lib/branding-core/ai/types.ts +0 -36
  43. package/src/lib/branding-core/documents/html-generator.ts +0 -32
  44. package/src/lib/branding-core/documents/pdf-generator.ts +0 -21
  45. package/src/lib/branding-core/exporters/css-variables.ts +0 -71
  46. package/src/lib/branding-core/exporters/design-tokens.ts +0 -86
  47. package/src/lib/branding-core/exporters/figma-tokens.ts +0 -87
  48. package/src/lib/branding-core/exporters/react-theme.ts +0 -69
  49. package/src/lib/branding-core/exporters/sass-variables.ts +0 -74
  50. package/src/lib/branding-core/exporters/tailwind-preset.ts +0 -67
  51. package/src/lib/branding-core/generators/border-system.ts +0 -41
  52. package/src/lib/branding-core/generators/color-palette.ts +0 -147
  53. package/src/lib/branding-core/generators/favicon-generator.ts +0 -33
  54. package/src/lib/branding-core/generators/gradient-system.ts +0 -120
  55. package/src/lib/branding-core/generators/logo-generator.ts +0 -152
  56. package/src/lib/branding-core/generators/motion-system.ts +0 -98
  57. package/src/lib/branding-core/generators/og-image-generator.ts +0 -97
  58. package/src/lib/branding-core/generators/shadow-system.ts +0 -66
  59. package/src/lib/branding-core/generators/spacing-scale.ts +0 -29
  60. package/src/lib/branding-core/generators/typography-system.ts +0 -128
  61. package/src/lib/branding-core/index.ts +0 -28
  62. package/src/lib/branding-core/validators/brand-consistency.ts +0 -79
  63. package/src/lib/branding-core/validators/contrast-checker.ts +0 -37
  64. package/src/lib/branding-core/validators/token-schema.ts +0 -50
  65. package/src/lib/config.ts +0 -13
  66. package/src/lib/logger.ts +0 -12
  67. package/src/lib/types.ts +0 -236
  68. package/src/resources/brand-knowledge.ts +0 -60
  69. package/src/resources/brand-templates.ts +0 -385
  70. package/src/tools/create-brand-guidelines.ts +0 -94
  71. package/src/tools/export-design-tokens.ts +0 -52
  72. package/src/tools/generate-brand-assets.ts +0 -48
  73. package/src/tools/generate-brand-identity.ts +0 -115
  74. package/src/tools/generate-color-palette.ts +0 -43
  75. package/src/tools/generate-design-system.ts +0 -163
  76. package/src/tools/generate-typography-system.ts +0 -42
  77. package/src/tools/refine-brand-element.ts +0 -65
  78. package/src/tools/validate-brand-consistency.ts +0 -32
  79. package/tsconfig.json +0 -21
@@ -1,385 +0,0 @@
1
- import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
- import type { BrandIdentity } from '../lib/types.js';
3
-
4
- const TEMPLATES = [
5
- {
6
- id: 'tech-startup',
7
- name: 'Tech Startup',
8
- style: 'tech',
9
- baseColor: '#6B4CE6',
10
- harmony: 'complementary',
11
- headingCategory: 'sans-serif',
12
- bodyCategory: 'sans-serif',
13
- },
14
- {
15
- id: 'luxury-brand',
16
- name: 'Luxury Brand',
17
- style: 'elegant',
18
- baseColor: '#1A1A2E',
19
- harmony: 'analogous',
20
- headingCategory: 'serif',
21
- bodyCategory: 'serif',
22
- },
23
- {
24
- id: 'health-wellness',
25
- name: 'Health & Wellness',
26
- style: 'organic',
27
- baseColor: '#2D6A4F',
28
- harmony: 'analogous',
29
- headingCategory: 'serif',
30
- bodyCategory: 'sans-serif',
31
- },
32
- {
33
- id: 'creative-agency',
34
- name: 'Creative Agency',
35
- style: 'bold',
36
- baseColor: '#FF6B35',
37
- harmony: 'triadic',
38
- headingCategory: 'display',
39
- bodyCategory: 'sans-serif',
40
- },
41
- {
42
- id: 'fintech',
43
- name: 'Fintech',
44
- style: 'corporate',
45
- baseColor: '#0052CC',
46
- harmony: 'complementary',
47
- headingCategory: 'sans-serif',
48
- bodyCategory: 'sans-serif',
49
- },
50
- {
51
- id: 'education',
52
- name: 'Education',
53
- style: 'playful',
54
- baseColor: '#7C3AED',
55
- harmony: 'split-complementary',
56
- headingCategory: 'display',
57
- bodyCategory: 'sans-serif',
58
- },
59
- ];
60
-
61
- const FORGE_SPACE_BRAND: BrandIdentity = {
62
- id: 'brand_forgespace_001',
63
- name: 'Forge Space',
64
- tagline: 'The developer tools ecosystem.',
65
- industry: 'technology',
66
- style: 'tech',
67
- colors: {
68
- primary: {
69
- name: 'Forge Purple',
70
- hex: '#7c3aed',
71
- hsl: { h: 262, s: 83, l: 58 },
72
- usage: 'Primary brand color',
73
- },
74
- secondary: {
75
- name: 'Forge Blue',
76
- hex: '#2563EB',
77
- hsl: { h: 217, s: 83, l: 53 },
78
- usage: 'Secondary brand color',
79
- },
80
- accent: {
81
- name: 'Forge Amber',
82
- hex: '#B45309',
83
- hsl: { h: 33, s: 92, l: 37 },
84
- usage: 'Accent and highlight color',
85
- },
86
- neutral: [
87
- {
88
- name: 'neutral-100',
89
- hex: '#f2f2f3',
90
- hsl: { h: 262, s: 5, l: 95 },
91
- usage: 'Neutral shade 1',
92
- },
93
- {
94
- name: 'neutral-200',
95
- hex: '#e5e4e7',
96
- hsl: { h: 262, s: 5, l: 90 },
97
- usage: 'Neutral shade 2',
98
- },
99
- {
100
- name: 'neutral-300',
101
- hex: '#cbc9cf',
102
- hsl: { h: 262, s: 5, l: 80 },
103
- usage: 'Neutral shade 3',
104
- },
105
- {
106
- name: 'neutral-400',
107
- hex: '#98949e',
108
- hsl: { h: 262, s: 5, l: 60 },
109
- usage: 'Neutral shade 4',
110
- },
111
- {
112
- name: 'neutral-500',
113
- hex: '#65616b',
114
- hsl: { h: 262, s: 5, l: 40 },
115
- usage: 'Neutral shade 5',
116
- },
117
- {
118
- name: 'neutral-600',
119
- hex: '#323036',
120
- hsl: { h: 262, s: 5, l: 20 },
121
- usage: 'Neutral shade 6',
122
- },
123
- {
124
- name: 'neutral-700',
125
- hex: '#19181b',
126
- hsl: { h: 262, s: 5, l: 10 },
127
- usage: 'Neutral shade 7',
128
- },
129
- {
130
- name: 'neutral-800',
131
- hex: '#0d0c0d',
132
- hsl: { h: 262, s: 5, l: 5 },
133
- usage: 'Neutral shade 8',
134
- },
135
- ],
136
- semantic: {
137
- success: {
138
- name: 'success',
139
- hex: '#22c35d',
140
- hsl: { h: 142, s: 70, l: 45 },
141
- usage: 'Success states',
142
- },
143
- warning: {
144
- name: 'warning',
145
- hex: '#f59f0a',
146
- hsl: { h: 38, s: 92, l: 50 },
147
- usage: 'Warning states',
148
- },
149
- error: { name: 'error', hex: '#ef4343', hsl: { h: 0, s: 84, l: 60 }, usage: 'Error states' },
150
- info: {
151
- name: 'info',
152
- hex: '#368fe7',
153
- hsl: { h: 210, s: 79, l: 56 },
154
- usage: 'Informational states',
155
- },
156
- },
157
- contrast: {
158
- 'primary-on-white': { ratio: 5.67, aa: true, aaLarge: true, aaa: false, aaaLarge: true },
159
- 'primary-on-dark': { ratio: 3.07, aa: false, aaLarge: true, aaa: false, aaaLarge: false },
160
- 'secondary-on-white': { ratio: 5.17, aa: true, aaLarge: true, aaa: false, aaaLarge: true },
161
- 'accent-on-white': { ratio: 5.02, aa: true, aaLarge: true, aaa: false, aaaLarge: true },
162
- },
163
- },
164
- typography: {
165
- headingFont: 'Space Grotesk',
166
- bodyFont: 'IBM Plex Sans',
167
- monoFont: 'IBM Plex Mono',
168
- baseSize: 16,
169
- scaleRatio: 1.25,
170
- steps: [
171
- { name: 'xs', size: '10.24px', lineHeight: '1.6', letterSpacing: '0.02em', weight: 400 },
172
- { name: 'sm', size: '12.8px', lineHeight: '1.6', letterSpacing: '0.02em', weight: 400 },
173
- { name: 'base', size: '16px', lineHeight: '1.6', letterSpacing: '0em', weight: 400 },
174
- { name: 'lg', size: '20px', lineHeight: '1.5', letterSpacing: '0em', weight: 400 },
175
- { name: 'xl', size: '25px', lineHeight: '1.3', letterSpacing: '-0.01em', weight: 400 },
176
- { name: '2xl', size: '31.25px', lineHeight: '1.3', letterSpacing: '-0.01em', weight: 600 },
177
- { name: '3xl', size: '39.06px', lineHeight: '1.2', letterSpacing: '-0.01em', weight: 600 },
178
- { name: '4xl', size: '48.83px', lineHeight: '1.2', letterSpacing: '-0.01em', weight: 700 },
179
- { name: '5xl', size: '61.04px', lineHeight: '1.2', letterSpacing: '-0.01em', weight: 700 },
180
- ],
181
- },
182
- spacing: {
183
- unit: 4,
184
- values: {
185
- '0': '0px',
186
- '1': '4px',
187
- '2': '8px',
188
- '3': '12px',
189
- '4': '16px',
190
- '5': '20px',
191
- '6': '24px',
192
- '8': '32px',
193
- '10': '40px',
194
- '12': '48px',
195
- '16': '64px',
196
- '20': '80px',
197
- '24': '96px',
198
- '0.5': '2px',
199
- '1.5': '6px',
200
- '2.5': '10px',
201
- },
202
- },
203
- shadows: {
204
- levels: {
205
- none: {
206
- offsetX: 0,
207
- offsetY: 0,
208
- blur: 0,
209
- spread: 0,
210
- color: 'rgba(47, 36, 66, 0)',
211
- opacity: 0,
212
- cssValue: 'none',
213
- },
214
- sm: {
215
- offsetX: 0,
216
- offsetY: 1,
217
- blur: 2,
218
- spread: 0,
219
- color: 'rgba(47, 36, 66, 0.05)',
220
- opacity: 0.05,
221
- cssValue: '1px 1px 2px 0px rgba(47, 36, 66, 0.05)',
222
- },
223
- md: {
224
- offsetX: 0,
225
- offsetY: 2,
226
- blur: 4,
227
- spread: -1,
228
- color: 'rgba(47, 36, 66, 0.08)',
229
- opacity: 0.08,
230
- cssValue: '2px 2px 4px -1px rgba(47, 36, 66, 0.08)',
231
- },
232
- lg: {
233
- offsetX: 0,
234
- offsetY: 4,
235
- blur: 8,
236
- spread: -2,
237
- color: 'rgba(47, 36, 66, 0.1)',
238
- opacity: 0.1,
239
- cssValue: '4px 4px 8px -2px rgba(47, 36, 66, 0.1)',
240
- },
241
- xl: {
242
- offsetX: 0,
243
- offsetY: 8,
244
- blur: 16,
245
- spread: -4,
246
- color: 'rgba(47, 36, 66, 0.12)',
247
- opacity: 0.12,
248
- cssValue: '8px 8px 16px -4px rgba(47, 36, 66, 0.12)',
249
- },
250
- '2xl': {
251
- offsetX: 0,
252
- offsetY: 16,
253
- blur: 32,
254
- spread: -8,
255
- color: 'rgba(47, 36, 66, 0.15)',
256
- opacity: 0.15,
257
- cssValue: '16px 16px 32px -8px rgba(47, 36, 66, 0.15)',
258
- },
259
- },
260
- },
261
- borders: {
262
- radii: {
263
- none: '0px',
264
- sm: '2px',
265
- md: '4px',
266
- lg: '8px',
267
- xl: '12px',
268
- full: '9999px',
269
- circle: '9999px',
270
- },
271
- widths: {
272
- thin: '1px',
273
- medium: '2px',
274
- thick: '3px',
275
- },
276
- },
277
- motion: {
278
- durations: {
279
- instant: '0ms',
280
- fast: '80ms',
281
- normal: '150ms',
282
- slow: '250ms',
283
- slower: '350ms',
284
- },
285
- easings: {
286
- 'ease-in': 'cubic-bezier(0.55, 0, 1, 1)',
287
- 'ease-out': 'cubic-bezier(0, 0, 0.1, 1)',
288
- 'ease-in-out': 'cubic-bezier(0.55, 0, 0.1, 1)',
289
- spring: 'cubic-bezier(0.2, 1.6, 0.4, 1)',
290
- bounce: 'cubic-bezier(0.2, 1.4, 0.4, 1)',
291
- },
292
- transitions: {
293
- fade: 'opacity 150ms cubic-bezier(0, 0, 0.1, 1)',
294
- slide: 'transform 150ms cubic-bezier(0, 0, 0.1, 1)',
295
- scale: 'transform 80ms cubic-bezier(0, 0, 0.1, 1)',
296
- color:
297
- 'color 250ms cubic-bezier(0, 0, 0.1, 1), background-color 250ms cubic-bezier(0, 0, 0.1, 1)',
298
- all: 'all 150ms cubic-bezier(0, 0, 0.1, 1)',
299
- },
300
- },
301
- gradients: {
302
- presets: {
303
- hero: {
304
- type: 'linear',
305
- angle: 315,
306
- stops: [
307
- { color: '#7c3aed', position: 0 },
308
- { color: '#3B82F6', position: 100 },
309
- ],
310
- cssValue: 'linear-gradient(315deg, #7c3aed 0%, #3B82F6 100%)',
311
- },
312
- button: {
313
- type: 'linear',
314
- angle: 315,
315
- stops: [
316
- { color: '#F59E0B', position: 0 },
317
- { color: '#7c3aed', position: 100 },
318
- ],
319
- cssValue: 'linear-gradient(315deg, #F59E0B 0%, #7c3aed 100%)',
320
- },
321
- card: {
322
- type: 'linear',
323
- angle: 315,
324
- stops: [
325
- { color: '#f2f2f3', position: 0 },
326
- { color: '#cacace', position: 100 },
327
- ],
328
- cssValue: 'linear-gradient(315deg, #f2f2f3 0%, #cacace 100%)',
329
- },
330
- text: {
331
- type: 'linear',
332
- angle: 315,
333
- stops: [
334
- { color: '#7c3aed', position: 0 },
335
- { color: '#F59E0B', position: 100 },
336
- ],
337
- cssValue: 'linear-gradient(315deg, #7c3aed 0%, #F59E0B 100%)',
338
- },
339
- background: {
340
- type: 'linear',
341
- angle: 315,
342
- stops: [
343
- { color: '#f2f2f3', position: 0 },
344
- { color: '#0d0c0d', position: 100 },
345
- ],
346
- cssValue: 'linear-gradient(315deg, #f2f2f3 0%, #0d0c0d 100%)',
347
- },
348
- },
349
- },
350
- logo: {
351
- svg: '<svg xmlns="http://www.w3.org/2000/svg" width="200" height="64" viewBox="0 0 200 64" fill="none">\n <path d="M4 20 L18 14 H56 a3 3 0 0 1 3 3 v6 a3 3 0 0 1-3 3 H18 L4 24 V20Z" fill="#A78BFA"/>\n <rect x="20" y="32" width="30" height="10" rx="3" fill="#8B5CF6"/>\n <rect x="14" y="48" width="40" height="14" rx="4" fill="#6D28D9"/>\n <text x="78" y="30" fill="#8B5CF6" font-size="20" font-family="\'Sora\', sans-serif" font-weight="600" letter-spacing="0.12em">FORGE</text>\n <text x="78" y="52" fill="#8B5CF6" font-size="20" font-family="\'Sora\', sans-serif" font-weight="600" letter-spacing="0.12em">SPACE</text>\n</svg>',
352
- variants: {
353
- wordmark:
354
- '<svg xmlns="http://www.w3.org/2000/svg" width="200" height="64" viewBox="0 0 200 64" fill="none">\n <path d="M4 20 L18 14 H56 a3 3 0 0 1 3 3 v6 a3 3 0 0 1-3 3 H18 L4 24 V20Z" fill="#A78BFA"/>\n <rect x="20" y="32" width="30" height="10" rx="3" fill="#8B5CF6"/>\n <rect x="14" y="48" width="40" height="14" rx="4" fill="#6D28D9"/>\n <text x="78" y="30" fill="#8B5CF6" font-size="20" font-family="\'Sora\', sans-serif" font-weight="600" letter-spacing="0.12em">FORGE</text>\n <text x="78" y="52" fill="#8B5CF6" font-size="20" font-family="\'Sora\', sans-serif" font-weight="600" letter-spacing="0.12em">SPACE</text>\n</svg>',
355
- monogram:
356
- '<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64" fill="none">\n <path d="M4 20 L18 14 H56 a3 3 0 0 1 3 3 v6 a3 3 0 0 1-3 3 H18 L4 24 V20Z" fill="#A78BFA"/>\n <rect x="20" y="32" width="30" height="10" rx="3" fill="#8B5CF6"/>\n <rect x="14" y="48" width="40" height="14" rx="4" fill="#6D28D9"/>\n</svg>',
357
- abstract:
358
- '<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64" fill="none">\n <path d="M4 20 L18 14 H56 a3 3 0 0 1 3 3 v6 a3 3 0 0 1-3 3 H18 L4 24 V20Z" fill="#8B5CF6"/>\n <rect x="20" y="32" width="30" height="10" rx="3" fill="#8B5CF6"/>\n <rect x="14" y="48" width="40" height="14" rx="4" fill="#8B5CF6"/>\n</svg>',
359
- icon: '<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64" fill="none">\n <path d="M4 20 L18 14 H56 a3 3 0 0 1 3 3 v6 a3 3 0 0 1-3 3 H18 L4 24 V20Z" fill="#A78BFA"/>\n <rect x="20" y="32" width="30" height="10" rx="3" fill="#8B5CF6"/>\n <rect x="14" y="48" width="40" height="14" rx="4" fill="#6D28D9"/>\n</svg>',
360
- },
361
- },
362
- createdAt: '2026-03-01T05:55:29.414Z',
363
- };
364
-
365
- export function registerBrandTemplates(server: McpServer): void {
366
- server.resource('brand-templates', 'brand://templates', async () => ({
367
- contents: [
368
- {
369
- uri: 'brand://templates',
370
- text: JSON.stringify(TEMPLATES, null, 2),
371
- mimeType: 'application/json',
372
- },
373
- ],
374
- }));
375
-
376
- server.resource('forge-space-brand', 'brand://templates/forge-space', async () => ({
377
- contents: [
378
- {
379
- uri: 'brand://templates/forge-space',
380
- text: JSON.stringify(FORGE_SPACE_BRAND, null, 2),
381
- mimeType: 'application/json',
382
- },
383
- ],
384
- }));
385
- }
@@ -1,94 +0,0 @@
1
- import { z } from 'zod';
2
- import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
- import { brandDocFormatSchema } from '../lib/branding-core/validators/token-schema.js';
4
- import type { BrandIdentity } from '../lib/types.js';
5
- import { logger } from '../lib/logger.js';
6
-
7
- function generateHtmlGuidelines(brand: BrandIdentity): string {
8
- const { colors, typography } = brand;
9
- return `<!DOCTYPE html>
10
- <html lang="en">
11
- <head>
12
- <meta charset="UTF-8">
13
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
14
- <title>${brand.name} - Brand Guidelines</title>
15
- <style>
16
- body { font-family: '${typography.bodyFont}', sans-serif; max-width: 960px; margin: 0 auto; padding: 2rem; color: #1a1a1a; }
17
- h1, h2, h3 { font-family: '${typography.headingFont}', sans-serif; }
18
- .swatch { display: inline-block; width: 80px; height: 80px; border-radius: 8px; margin: 4px; }
19
- .color-label { font-size: 12px; text-align: center; margin-top: 4px; }
20
- .section { margin: 2rem 0; padding: 1.5rem; border: 1px solid #e0e0e0; border-radius: 8px; }
21
- </style>
22
- </head>
23
- <body>
24
- <h1>${brand.name} Brand Guidelines</h1>
25
- ${brand.tagline ? `<p><em>${brand.tagline}</em></p>` : ''}
26
-
27
- <div class="section">
28
- <h2>Color Palette</h2>
29
- <div>
30
- <div><div class="swatch" style="background:${colors.primary.hex}"></div><div class="color-label">Primary<br>${colors.primary.hex}</div></div>
31
- <div><div class="swatch" style="background:${colors.secondary.hex}"></div><div class="color-label">Secondary<br>${colors.secondary.hex}</div></div>
32
- <div><div class="swatch" style="background:${colors.accent.hex}"></div><div class="color-label">Accent<br>${colors.accent.hex}</div></div>
33
- </div>
34
- <h3>Neutrals</h3>
35
- <div>${colors.neutral.map((n) => `<div style="display:inline-block"><div class="swatch" style="background:${n.hex}"></div><div class="color-label">${n.name}<br>${n.hex}</div></div>`).join('')}</div>
36
- </div>
37
-
38
- <div class="section">
39
- <h2>Typography</h2>
40
- <p><strong>Heading:</strong> ${typography.headingFont}</p>
41
- <p><strong>Body:</strong> ${typography.bodyFont}</p>
42
- <p><strong>Mono:</strong> ${typography.monoFont}</p>
43
- <h3>Type Scale</h3>
44
- ${typography.steps.map((s) => `<p style="font-size:${s.size};line-height:${s.lineHeight};font-weight:${s.weight}">${s.name} — ${s.size}</p>`).join('\n ')}
45
- </div>
46
-
47
- <div class="section">
48
- <h2>Logo</h2>
49
- ${brand.logo?.svg ? brand.logo.svg : '<p>Logo not generated</p>'}
50
- </div>
51
-
52
- <footer><p>Generated by @forgespace/branding-mcp</p></footer>
53
- </body>
54
- </html>`;
55
- }
56
-
57
- export function registerCreateBrandGuidelines(server: McpServer): void {
58
- server.tool(
59
- 'create_brand_guidelines',
60
- 'Generate a brand guidelines document (HTML brand book) from a brand identity. Includes color swatches, typography samples, logo, and usage rules.',
61
- {
62
- brand: z.string().describe('Full BrandIdentity JSON'),
63
- format: brandDocFormatSchema.optional().describe('Output format (html supported)'),
64
- },
65
- async ({ brand, format }) => {
66
- try {
67
- logger.info({ format }, 'Creating brand guidelines');
68
- const brandData: BrandIdentity = JSON.parse(brand);
69
-
70
- if (format === 'pdf') {
71
- return {
72
- content: [
73
- {
74
- type: 'text',
75
- text: 'PDF generation requires pdfkit. Use HTML format or install optional dependencies.',
76
- },
77
- ],
78
- };
79
- }
80
-
81
- const html = generateHtmlGuidelines(brandData);
82
- return {
83
- content: [{ type: 'text', text: html }],
84
- };
85
- } catch (error) {
86
- const message = error instanceof Error ? error.message : String(error);
87
- return {
88
- content: [{ type: 'text', text: `Error creating guidelines: ${message}` }],
89
- isError: true,
90
- };
91
- }
92
- }
93
- );
94
- }
@@ -1,52 +0,0 @@
1
- import { z } from 'zod';
2
- import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
- import {
4
- exportDesignTokens,
5
- exportCssVariables,
6
- exportTailwindPreset,
7
- exportFigmaTokens,
8
- exportReactTheme,
9
- exportSassVariables,
10
- } from '../lib/branding-core/index.js';
11
- import { exportFormatSchema } from '../lib/branding-core/validators/token-schema.js';
12
- import type { BrandIdentity, ExportFormat } from '../lib/types.js';
13
- import { logger } from '../lib/logger.js';
14
-
15
- const EXPORTERS: Record<ExportFormat, (brand: BrandIdentity) => string | object> = {
16
- json: exportDesignTokens,
17
- css: exportCssVariables,
18
- tailwind: exportTailwindPreset,
19
- figma: exportFigmaTokens,
20
- react: exportReactTheme,
21
- sass: exportSassVariables,
22
- };
23
-
24
- export function registerExportDesignTokens(server: McpServer): void {
25
- server.tool(
26
- 'export_design_tokens',
27
- 'Export a brand identity as design tokens in various formats: W3C JSON, CSS custom properties, Tailwind preset, Figma tokens, React theme, or Sass variables.',
28
- {
29
- brand: z.string().describe('Full BrandIdentity JSON (from generate_brand_identity output)'),
30
- format: exportFormatSchema.describe('Export format'),
31
- },
32
- async ({ brand, format }) => {
33
- try {
34
- logger.info({ format }, 'Exporting design tokens');
35
- const brandData: BrandIdentity = JSON.parse(brand);
36
- const exporter = EXPORTERS[format];
37
- const result = exporter(brandData);
38
- const output = typeof result === 'string' ? result : JSON.stringify(result, null, 2);
39
-
40
- return {
41
- content: [{ type: 'text', text: output }],
42
- };
43
- } catch (error) {
44
- const message = error instanceof Error ? error.message : String(error);
45
- return {
46
- content: [{ type: 'text', text: `Error exporting tokens: ${message}` }],
47
- isError: true,
48
- };
49
- }
50
- }
51
- );
52
- }
@@ -1,48 +0,0 @@
1
- import { z } from 'zod';
2
- import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
- import { generateFavicons, generateOgImage } from '../lib/branding-core/index.js';
4
- import type { BrandIdentity } from '../lib/types.js';
5
- import { logger } from '../lib/logger.js';
6
-
7
- const ogTemplateSchema = z.enum(['default', 'article', 'social']);
8
-
9
- export function registerGenerateBrandAssets(server: McpServer): void {
10
- server.tool(
11
- 'generate_brand_assets',
12
- 'Generate brand assets (favicons, OG images) from an existing brand identity JSON.',
13
- {
14
- brand: z
15
- .string()
16
- .min(1)
17
- .describe('JSON string of BrandIdentity from generate_brand_identity'),
18
- ogTemplate: ogTemplateSchema
19
- .optional()
20
- .describe('OG image template: default, article, or social'),
21
- ogTitle: z.string().max(200).optional().describe('Custom OG image title'),
22
- ogSubtitle: z.string().max(200).optional().describe('Custom OG image subtitle'),
23
- },
24
- async ({ brand: brandJson, ogTemplate, ogTitle, ogSubtitle }) => {
25
- try {
26
- const brand: BrandIdentity = JSON.parse(brandJson);
27
- logger.info({ brandName: brand.name }, 'Generating brand assets');
28
-
29
- const iconSvg = brand.logo?.variants?.icon ?? brand.logo?.svg ?? '';
30
- const favicons = iconSvg ? generateFavicons(iconSvg, brand.colors.primary.hex) : null;
31
-
32
- const ogImage = generateOgImage(brand, ogTemplate ?? 'default', ogTitle, ogSubtitle);
33
-
34
- const result = { favicons, ogImage };
35
-
36
- return {
37
- content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
38
- };
39
- } catch (error) {
40
- const message = error instanceof Error ? error.message : String(error);
41
- return {
42
- content: [{ type: 'text', text: `Error generating assets: ${message}` }],
43
- isError: true,
44
- };
45
- }
46
- }
47
- );
48
- }