@webspire/mcp 0.5.0 → 0.6.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/README.md CHANGED
@@ -1,15 +1,13 @@
1
1
  # @webspire/mcp
2
2
 
3
- MCP server for [Webspire](https://webspire.de) — AI-native discovery of CSS snippets, UI patterns, and page templates.
3
+ MCP server for [Webspire](https://webspire.de) — AI-native discovery of CSS snippets, UI patterns, and page templates with a 3-layer design token system.
4
4
 
5
- **49 CSS snippets** + **212 UI patterns** + **18 page templates** — all Tailwind v4, dark mode, accessible.
5
+ **49 CSS snippets** + **212 UI patterns** + **18 page templates** — all Tailwind v4, token-based, dark mode, accessible.
6
6
 
7
7
  ## Quick Start
8
8
 
9
9
  ### Claude Code / Claude Desktop
10
10
 
11
- Add to your MCP settings (`~/.claude/settings.json` or Claude Desktop config):
12
-
13
11
  ```json
14
12
  {
15
13
  "mcpServers": {
@@ -21,71 +19,88 @@ Add to your MCP settings (`~/.claude/settings.json` or Claude Desktop config):
21
19
  }
22
20
  ```
23
21
 
24
- ### Custom Registry
25
-
26
- ```json
27
- {
28
- "mcpServers": {
29
- "webspire": {
30
- "command": "npx",
31
- "args": ["-y", "@webspire/mcp", "--registry-url", "https://your-domain.com/registry.json"]
32
- }
33
- }
34
- }
35
- ```
36
-
37
- ## Available Tools
22
+ ## Available Tools (12)
38
23
 
39
24
  | Tool | Description |
40
25
  |------|-------------|
41
26
  | `list_categories` | List all snippet categories with counts |
42
27
  | `search_snippets` | Search snippets by keyword, use case, or CSS technique |
43
28
  | `get_snippet` | Get full CSS source, metadata, and usage example |
44
- | `recommend_snippet` | Describe a UI problem, get best matching snippets with reasoning |
29
+ | `recommend_snippet` | Describe a UI problem, get best matching snippets |
45
30
  | `list_pattern_families` | List all 55 pattern families with counts |
46
31
  | `search_patterns` | Search 212 UI patterns by intent, family, or tier |
47
- | `get_pattern` | Get full pattern HTML/CSS/JS with slots, props, and metadata |
32
+ | `get_pattern` | Get full pattern HTML with component token references |
33
+ | `list_templates` | List all page templates by category |
34
+ | `search_templates` | Search templates by keyword, category, or style |
35
+ | `get_template` | Get full standalone HTML for a page template |
36
+ | `setup_tokens` | Get token CSS files to write into your project (no CDN needed) |
37
+ | `recommend_token_mapping` | Analyze your project tokens and suggest --ws-* mapping |
38
+
39
+ ## 3-Layer Token Architecture
40
+
41
+ Patterns use semantic CSS custom properties via a 3-layer system:
42
+
43
+ ```
44
+ Host Tokens (your project) → WebSpire Alias Tokens → Component Tokens → Markup
45
+ ```
46
+
47
+ ### Setup via MCP
48
+
49
+ ```
50
+ > setup_tokens()
51
+ // Returns webspire-tokens.css + webspire-components.css
52
+ // AI agent writes them into your project
53
+
54
+ > setup_tokens({ components: ["hero", "cta", "pricing"] })
55
+ // Only includes tokens for the families you use
56
+ ```
57
+
58
+ ### Pattern Markup
59
+
60
+ ```html
61
+ <section class="ws-cta bg-[var(--ws-cta-bg)] py-20">
62
+ <h2 class="text-[var(--ws-cta-text)] text-3xl font-bold">Title</h2>
63
+ <a class="bg-[var(--ws-cta-action-bg)] text-[var(--ws-cta-action-text)]
64
+ hover:bg-[var(--ws-cta-action-bg-hover)] rounded-lg px-5 py-3">
65
+ Get started
66
+ </a>
67
+ </section>
68
+ ```
69
+
70
+ ### Customize
71
+
72
+ ```css
73
+ :root {
74
+ --ws-color-primary: #your-brand-color;
75
+ --ws-color-primary-hover: #your-brand-darker;
76
+ }
77
+ ```
48
78
 
49
79
  ## Available Resources
50
80
 
51
81
  | URI | Description |
52
82
  |-----|-------------|
53
- | `webspire://categories` | All snippet categories with counts (JSON) |
54
- | `webspire://category/{name}` | Snippets in a category (JSON) |
55
- | `webspire://snippet/{id}` | Full snippet data including CSS (JSON) |
56
- | `webspire://patterns` | All 212 patterns with brief metadata (JSON) |
57
- | `webspire://pattern/{id}` | Full pattern data including HTML source (JSON) |
83
+ | `webspire://categories` | Snippet categories with counts |
84
+ | `webspire://category/{name}` | Snippets in a category |
85
+ | `webspire://snippet/{id}` | Full snippet data including CSS |
86
+ | `webspire://patterns` | All patterns with brief metadata |
87
+ | `webspire://pattern/{id}` | Full pattern data including HTML |
88
+ | `webspire://templates` | All templates with brief metadata |
89
+ | `webspire://template/{id}` | Full template data including HTML |
58
90
 
59
91
  ## Content
60
92
 
61
93
  ### CSS Snippets (49)
62
94
 
63
- Effects that Tailwind v4 can't do natively:
64
-
65
- - **glass** (5) — Frosted, subtle, bold, colored, dark glassmorphism
66
- - **animations** (7) — Fade, slide, scale, blur, stagger, pulse, infinite scroll
67
- - **easing** (1) — Spring, bounce, snap easing tokens
68
- - **scroll** (8) — Parallax, reveal, progress bar, snap, sticky header
69
- - **decorative** (11) — Aurora, gradient mesh, neon glow, noise, orbs, shimmer
70
- - **interactions** (11) — Hover lift, ripple, flip card, tilt, magnetic, focus ring
71
- - **text** (6) — Fluid size, gradient text, typewriter, truncate, balance
95
+ Effects that Tailwind v4 can't do natively: glass, animations, easing, scroll, decorative, interactions, text.
72
96
 
73
97
  ### UI Patterns (212)
74
98
 
75
- Full Tailwind HTML sections across 55 families:
76
-
77
- accordion, auth, avatar, badge, banner, bento, blog, breadcrumb, callout, cards, checkout, code-preview, comments, comparison, contact, cookie-consent, cta, dashboard, description-list, divider, empty-state, error, faq, features, file-tree, footer, forms, gallery, hero, kbd, link-card, logo-cloud, modal, navbar, newsletter, onboarding, pagination, popup, pricing, product-card, property-table, quote, related-articles, see-also, sidebar, social-proof, stats, steps, tabs, team, testimonials, and more.
99
+ 55 families across Page Sections and Content Elements — all using `--ws-*` component tokens.
78
100
 
79
101
  ### Page Templates (18)
80
102
 
81
- Complete page layouts: company, portfolio, saas-landing, shop — ready to scaffold.
82
-
83
- ## Search Features
84
-
85
- - **Synonym expansion**: "blur" also matches glass/frosted snippets
86
- - **Stemming**: "animations" matches "animated", "animate"
87
- - **Multi-field scoring**: Weighted matches across title, description, use cases, tags, classes, IDs
88
- - **Filters**: Category, tags, dark mode support, responsive support, reduced motion
103
+ Complete standalone pages: SaaS, agency, portfolio, shop, company with Tailwind CDN.
89
104
 
90
105
  ## Programmatic Usage
91
106
 
@@ -95,12 +110,8 @@ import { loadRegistry, searchSnippets } from '@webspire/mcp/registry';
95
110
  const registry = await loadRegistry();
96
111
  const results = searchSnippets(registry, {
97
112
  query: 'glass card hover',
98
- category: 'glass',
99
113
  darkMode: true,
100
- limit: 5,
101
114
  });
102
115
  ```
103
116
 
104
- ## License
105
-
106
- MIT
117
+ Docs: https://webspire.de/tokens
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": "1.2.0",
3
- "generated": "2026-03-21T12:51:58.469Z",
3
+ "generated": "2026-03-21T13:07:14.156Z",
4
4
  "snippets": [
5
5
  {
6
6
  "id": "animations/blur-in",
package/dist/index.js CHANGED
@@ -1,7 +1,12 @@
1
1
  #!/usr/bin/env node
2
+ import { readFileSync } from 'node:fs';
3
+ import { dirname, resolve } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
2
5
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
6
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
7
  import { registerResources, registerTools } from './handlers.js';
8
+ const __dirname = dirname(fileURLToPath(import.meta.url));
9
+ const pkg = JSON.parse(readFileSync(resolve(__dirname, '..', 'package.json'), 'utf-8'));
5
10
  const args = process.argv.slice(2);
6
11
  const urlIdx = args.indexOf('--registry-url');
7
12
  const fileIdx = args.indexOf('--registry-file');
@@ -11,7 +16,7 @@ const registryOptions = {
11
16
  };
12
17
  const server = new McpServer({
13
18
  name: 'webspire',
14
- version: '0.5.0',
19
+ version: pkg.version,
15
20
  });
16
21
  registerTools(server, registryOptions);
17
22
  registerResources(server, registryOptions);
@@ -404,8 +404,14 @@ export function registerToolsWithProvider(server, getRegistry) {
404
404
  });
405
405
  server.tool('search_templates', 'Search Webspire page templates by keyword, category, or style.', {
406
406
  query: z.string().describe('Search query, e.g. "saas landing", "portfolio dark", "shop"'),
407
- category: z.string().optional().describe('Filter by category, e.g. saas-landing, agency, shop'),
408
- style: z.string().optional().describe('Filter by style, e.g. modern, bold, minimal, corporate'),
407
+ category: z
408
+ .string()
409
+ .optional()
410
+ .describe('Filter by category, e.g. saas-landing, agency, shop'),
411
+ style: z
412
+ .string()
413
+ .optional()
414
+ .describe('Filter by style, e.g. modern, bold, minimal, corporate'),
409
415
  }, async ({ query, category, style }) => {
410
416
  const registry = await getRegistry();
411
417
  let templates = registry.templates ?? [];
@@ -416,7 +422,15 @@ export function registerToolsWithProvider(server, getRegistry) {
416
422
  const terms = query.toLowerCase().split(/\s+/).filter(Boolean);
417
423
  const results = templates
418
424
  .map((t) => {
419
- const haystack = [t.title, t.summary, t.description ?? '', t.category, t.style, ...t.tags, ...t.sections]
425
+ const haystack = [
426
+ t.title,
427
+ t.summary,
428
+ t.description ?? '',
429
+ t.category,
430
+ t.style,
431
+ ...t.tags,
432
+ ...t.sections,
433
+ ]
420
434
  .join(' ')
421
435
  .toLowerCase();
422
436
  const score = terms.reduce((acc, term) => acc + (haystack.includes(term) ? 1 : 0), 0);
@@ -469,22 +483,77 @@ export function registerToolsWithProvider(server, getRegistry) {
469
483
  .optional()
470
484
  .describe('CSS framework used in your project'),
471
485
  }, async ({ project_tokens, framework }) => {
472
- const lines = project_tokens.split(/[;\n,]+/).map((s) => s.trim()).filter(Boolean);
486
+ const lines = project_tokens
487
+ .split(/[;\n,]+/)
488
+ .map((s) => s.trim())
489
+ .filter(Boolean);
473
490
  const mappings = [];
474
491
  const TOKEN_HINTS = [
475
- { patterns: [/brand|primary|main|accent-color/i], wsToken: '--ws-color-primary', description: 'Primary/brand color' },
476
- { patterns: [/brand.*hover|primary.*hover|primary.*dark/i], wsToken: '--ws-color-primary-hover', description: 'Primary hover state' },
477
- { patterns: [/brand.*light|primary.*light|primary.*50|brand.*50/i], wsToken: '--ws-color-primary-soft', description: 'Primary soft background' },
478
- { patterns: [/secondary|accent(?!-color)/i], wsToken: '--ws-color-accent', description: 'Secondary/accent color' },
479
- { patterns: [/^bg$|background(?!.*secondary)|surface(?!.*alt)/i], wsToken: '--ws-color-surface', description: 'Page background' },
480
- { patterns: [/bg.*secondary|bg.*subtle|bg.*muted|surface.*alt|bg.*light/i], wsToken: '--ws-color-surface-alt', description: 'Subtle background' },
481
- { patterns: [/^text$|text.*primary|foreground(?!.*muted)/i], wsToken: '--ws-color-text', description: 'Primary text color' },
482
- { patterns: [/text.*secondary|text.*soft|text.*muted|muted.*foreground/i], wsToken: '--ws-color-text-muted', description: 'Muted text color' },
483
- { patterns: [/border(?!.*strong)|divider/i], wsToken: '--ws-color-border', description: 'Default border' },
484
- { patterns: [/success|green|positive/i], wsToken: '--ws-color-success', description: 'Success color' },
485
- { patterns: [/warning|amber|yellow|caution/i], wsToken: '--ws-color-warning', description: 'Warning color' },
486
- { patterns: [/danger|error|red|destructive/i], wsToken: '--ws-color-danger', description: 'Danger/error color' },
487
- { patterns: [/radius|rounded|corner/i], wsToken: '--ws-radius-md', description: 'Border radius' },
492
+ {
493
+ patterns: [/brand|primary|main|accent-color/i],
494
+ wsToken: '--ws-color-primary',
495
+ description: 'Primary/brand color',
496
+ },
497
+ {
498
+ patterns: [/brand.*hover|primary.*hover|primary.*dark/i],
499
+ wsToken: '--ws-color-primary-hover',
500
+ description: 'Primary hover state',
501
+ },
502
+ {
503
+ patterns: [/brand.*light|primary.*light|primary.*50|brand.*50/i],
504
+ wsToken: '--ws-color-primary-soft',
505
+ description: 'Primary soft background',
506
+ },
507
+ {
508
+ patterns: [/secondary|accent(?!-color)/i],
509
+ wsToken: '--ws-color-accent',
510
+ description: 'Secondary/accent color',
511
+ },
512
+ {
513
+ patterns: [/^bg$|background(?!.*secondary)|surface(?!.*alt)/i],
514
+ wsToken: '--ws-color-surface',
515
+ description: 'Page background',
516
+ },
517
+ {
518
+ patterns: [/bg.*secondary|bg.*subtle|bg.*muted|surface.*alt|bg.*light/i],
519
+ wsToken: '--ws-color-surface-alt',
520
+ description: 'Subtle background',
521
+ },
522
+ {
523
+ patterns: [/^text$|text.*primary|foreground(?!.*muted)/i],
524
+ wsToken: '--ws-color-text',
525
+ description: 'Primary text color',
526
+ },
527
+ {
528
+ patterns: [/text.*secondary|text.*soft|text.*muted|muted.*foreground/i],
529
+ wsToken: '--ws-color-text-muted',
530
+ description: 'Muted text color',
531
+ },
532
+ {
533
+ patterns: [/border(?!.*strong)|divider/i],
534
+ wsToken: '--ws-color-border',
535
+ description: 'Default border',
536
+ },
537
+ {
538
+ patterns: [/success|green|positive/i],
539
+ wsToken: '--ws-color-success',
540
+ description: 'Success color',
541
+ },
542
+ {
543
+ patterns: [/warning|amber|yellow|caution/i],
544
+ wsToken: '--ws-color-warning',
545
+ description: 'Warning color',
546
+ },
547
+ {
548
+ patterns: [/danger|error|red|destructive/i],
549
+ wsToken: '--ws-color-danger',
550
+ description: 'Danger/error color',
551
+ },
552
+ {
553
+ patterns: [/radius|rounded|corner/i],
554
+ wsToken: '--ws-radius-md',
555
+ description: 'Border radius',
556
+ },
488
557
  ];
489
558
  for (const line of lines) {
490
559
  const [rawName] = line.split(':').map((s) => s.trim());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webspire/mcp",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "MCP server for Webspire — AI-native discovery of CSS snippets, UI patterns, and page templates",
5
5
  "type": "module",
6
6
  "exports": {