@vadenai/mcp-server 0.1.0 → 0.2.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.
package/README.md CHANGED
@@ -30,7 +30,7 @@ This MCP Server solves this by providing **design context** that agents can refe
30
30
  | `get_design_tokens` | Returns design tokens (colors, fonts, spacing, radius, etc.) | none |
31
31
  | `get_theme_css` | Returns CSS variables (`:root`, `.dark`, `@theme`) | none |
32
32
  | `get_component_list` | Returns a list of available components | none |
33
- | `get_component_spec` | Returns the spec for a component (props, variants, etc.) | `component`: component name |
33
+ | `get_component_spec` | Returns the spec for a component (props, variants, CVA classes, resolved colors) | `component`: component name |
34
34
  | `search_components` | Searches components by keyword (Japanese supported) | `query`: search query |
35
35
  | `get_wireframes` | Returns wireframe screen list and navigation flows | none |
36
36
  | `get_wireframe_detail` | Returns screen details (components, states, behaviors) | `screen_id`: screen ID |
@@ -105,6 +105,28 @@ Supported: hover, focus-visible, active, disabled
105
105
 
106
106
  ---
107
107
 
108
+ ## Style Config (botanical-organic)
109
+
110
+ **Type**: single
111
+
112
+ **Base Styles**:
113
+ `inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-full text-sm font-medium ...`
114
+
115
+ **variant**:
116
+ - default: `bg-primary text-primary-foreground shadow-sm hover:bg-primary/90 hover:shadow`
117
+ - destructive: `bg-destructive text-destructive-foreground hover:bg-destructive/90`
118
+ - outline: `border border-primary/50 bg-transparent text-primary hover:bg-primary/5`
119
+ - secondary: `bg-secondary text-secondary-foreground hover:bg-secondary/80`
120
+ - ghost: `text-primary hover:bg-accent`
121
+ - link: `text-primary underline-offset-4 hover:underline`
122
+
123
+ **Resolved Colors** (preferred appearance):
124
+ - primary: bg=#7C3AED, fg=#FFFFFF
125
+ - secondary: bg=#F472B6, fg=#1E293B
126
+ - destructive: #EF4444
127
+
128
+ ---
129
+
108
130
  ## Registry Spec (JSON)
109
131
  ```json
110
132
  {
@@ -119,7 +141,7 @@ Supported: hover, focus-visible, active, disabled
119
141
  }
120
142
  ````
121
143
 
122
- Components with registered metadata return both a guide and registry JSON. Components without metadata return registry JSON only.
144
+ Components with registered metadata return both a guide and registry JSON. Components without metadata return registry JSON only. When the project has a generated design system, a **Style Config** section with CVA class definitions and resolved color values is included between the guide and registry spec.
123
145
 
124
146
  **`get_component_list`** — Array of component summaries
125
147
 
@@ -95,10 +95,17 @@ export function generateComponentGuide(info) {
95
95
  }
96
96
  // Important rules (common to all)
97
97
  lines.push("## Important Rules");
98
- lines.push("- Always use design token CSS variables — never hardcode colors or spacing.");
98
+ lines.push("- Always use design token CSS variables — never hardcode colors or spacing. However, Style Config classes override tokens when explicitly specified (see Style Precedence below).");
99
99
  lines.push("- Follow the variant system — do not create ad-hoc style overrides.");
100
100
  if (meta.type === "multipart") {
101
101
  lines.push("- Use the slot-based structure — each slot has specific styling responsibilities.");
102
102
  }
103
+ lines.push("");
104
+ // Style precedence rules
105
+ lines.push("## Style Precedence");
106
+ lines.push("When Style Config and Semantic Tokens conflict, apply this order:");
107
+ lines.push("1. **Style Config classes take highest priority** — they encode component-specific design intent (e.g. `text-white` overrides `text-primary-foreground`).");
108
+ lines.push("2. **Semantic Tokens as fallback** — use tokens only for attributes not specified in the Style Config.");
109
+ lines.push("3. **Resolved Colors are reference values** — they show the actual rendered colors but do not override Style Config classes.");
103
110
  return lines.join("\n");
104
111
  }
package/dist/index.js CHANGED
@@ -17,7 +17,7 @@ import { handleGetConcept, handleGetDesignRationale } from "./tools/concept.js";
17
17
  import { handleGetDesignTokens, handleGetThemeCss, } from "./tools/design-tokens.js";
18
18
  import { handleGetWireframeDetail, handleGetWireframes, } from "./tools/wireframes.js";
19
19
  // --- コマンドライン引数パース ---
20
- const VERSION = "0.1.0";
20
+ const VERSION = "0.2.1";
21
21
  function parseArgs() {
22
22
  const args = process.argv.slice(2);
23
23
  if (args.includes("--help") || args.includes("-h")) {
@@ -92,7 +92,7 @@ const TOOLS = [
92
92
  },
93
93
  {
94
94
  name: "get_component_spec",
95
- description: "指定したコンポーネントの仕様(props・バリアント等)を返します",
95
+ description: "指定したコンポーネントの仕様(props・バリアント等)を返します。プロジェクトにデザインシステムが生成済みの場合、CVAクラス定義・解決済みカラー値も含まれます",
96
96
  inputSchema: {
97
97
  type: "object",
98
98
  properties: {
@@ -93,11 +93,24 @@ export async function handleGetComponentSpec(client, projectId, componentName) {
93
93
  description: spec.description,
94
94
  categories: spec.categories,
95
95
  });
96
+ // スタイル設定を取得(失敗しても既存レスポンスは返す)
97
+ let styleSection = "";
98
+ try {
99
+ const styleData = await client.get(`/api/projects/${encodeURIComponent(projectId)}/design-system/component-styles/${encodeURIComponent(componentName)}`);
100
+ styleSection = formatStyleSection(styleData);
101
+ }
102
+ catch {
103
+ // DS未生成等でスタイルが取得できない場合はスキップ
104
+ }
96
105
  const parts = [];
97
106
  if (guide) {
98
107
  parts.push(guide);
99
108
  parts.push("", "---", "");
100
109
  }
110
+ if (styleSection) {
111
+ parts.push(styleSection);
112
+ parts.push("", "---", "");
113
+ }
101
114
  parts.push("## Registry Spec (JSON)");
102
115
  parts.push("```json");
103
116
  parts.push(JSON.stringify(spec, null, 2));
@@ -227,6 +240,75 @@ export async function handleSearchComponents(client, projectId, query) {
227
240
  const text = `## Search Results for "${query}"\n\n${header}${rows}\n\nUse \`get_component_spec\` with a component name for full details.`;
228
241
  return [{ type: "text", text }];
229
242
  }
243
+ function formatStyleSection(data) {
244
+ const lines = [];
245
+ const styleId = data.styleId;
246
+ const type = data.type;
247
+ const overrideApplied = data.overrideApplied;
248
+ lines.push(`## Style Config${styleId ? ` (${styleId})` : ""}${overrideApplied ? " [override applied]" : ""}`);
249
+ lines.push("");
250
+ lines.push("> **Priority**: Resolve conflicts in this order — (1) **Style Config classes** (highest), (2) **Semantic Tokens** (fallback when class is not specified), (3) **Resolved Colors** (reference-only; never override classes).");
251
+ lines.push("");
252
+ lines.push(`**Type**: ${type}`);
253
+ lines.push("");
254
+ if (type === "single") {
255
+ const baseStyles = data.baseStyles;
256
+ const variants = data.variants;
257
+ lines.push("**Base Styles**:");
258
+ lines.push(`\`${baseStyles}\``);
259
+ lines.push("");
260
+ if (variants) {
261
+ for (const [groupName, groupVariants] of Object.entries(variants)) {
262
+ lines.push(`**${groupName}**:`);
263
+ for (const [name, classes] of Object.entries(groupVariants)) {
264
+ lines.push(`- ${name}: \`${classes}\``);
265
+ }
266
+ lines.push("");
267
+ }
268
+ }
269
+ }
270
+ else if (type === "multipart") {
271
+ const slots = data.slots;
272
+ if (slots) {
273
+ lines.push("**Slots**:");
274
+ for (const [slotName, classes] of Object.entries(slots)) {
275
+ lines.push(`- ${slotName}: \`${classes}\``);
276
+ }
277
+ lines.push("");
278
+ }
279
+ const variants = data.variants;
280
+ if (variants && Object.keys(variants).length > 0) {
281
+ for (const [groupName, groupVariants] of Object.entries(variants)) {
282
+ lines.push(`**${groupName}**:`);
283
+ for (const [name, classes] of Object.entries(groupVariants)) {
284
+ lines.push(`- ${name}: \`${classes}\``);
285
+ }
286
+ lines.push("");
287
+ }
288
+ }
289
+ }
290
+ const resolvedColors = data.resolvedColors;
291
+ if (resolvedColors && Object.keys(resolvedColors).length > 0) {
292
+ lines.push("**Resolved Colors** (preferred appearance):");
293
+ for (const [name, value] of Object.entries(resolvedColors)) {
294
+ if (typeof value === "string") {
295
+ lines.push(`- ${name}: ${value}`);
296
+ }
297
+ else if (value && typeof value === "object") {
298
+ const pair = value;
299
+ if (typeof pair.background === "string" ||
300
+ typeof pair.foreground === "string") {
301
+ lines.push(`- ${name}: bg=${pair.background ?? "-"}, fg=${pair.foreground ?? "-"}`);
302
+ }
303
+ else {
304
+ lines.push(`- ${name}: \`${JSON.stringify(value)}\``);
305
+ }
306
+ }
307
+ }
308
+ lines.push("");
309
+ }
310
+ return lines.join("\n");
311
+ }
230
312
  /** テスト用にキャッシュをクリアする */
231
313
  export function clearRegistryCache() {
232
314
  cache = new WeakMap();
package/package.json CHANGED
@@ -10,7 +10,7 @@
10
10
  ],
11
11
  "homepage": "https://vaden.ai",
12
12
  "license": "MIT",
13
- "version": "0.1.0",
13
+ "version": "0.2.1",
14
14
  "type": "module",
15
15
  "publishConfig": {
16
16
  "access": "public"
@@ -34,6 +34,7 @@
34
34
  "postbuild": "node scripts/postbuild.js",
35
35
  "prepack": "npm run build",
36
36
  "test": "vitest run",
37
+ "test:unit": "vitest run",
37
38
  "typecheck": "tsc --noEmit"
38
39
  },
39
40
  "files": [