@vizejs/musea-mcp-server 0.12.0 → 0.14.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/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { startServer } from "./src-DNZL-15O.js";
2
+ import { startServer } from "./src-BY8aIu75.js";
3
3
 
4
4
  //#region src/cli.ts
5
5
  let projectRoot = process.env.MUSEA_PROJECT_ROOT || process.cwd();
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import { createMuseaServer, src_default, startServer } from "./src-DNZL-15O.js";
1
+ import { createMuseaServer, src_default, startServer } from "./src-BY8aIu75.js";
2
2
 
3
3
  export { createMuseaServer, src_default as default, startServer };
@@ -244,6 +244,135 @@ const toolDefinitions = [
244
244
  }
245
245
  ];
246
246
 
247
+ //#endregion
248
+ //#region src/tools/handler/analysis.ts
249
+ async function handleAnalyzeComponent(ctx, binding, args) {
250
+ const vuePath = args?.path;
251
+ if (!vuePath) throw new McpError(ErrorCode.InvalidParams, "path is required");
252
+ if (!binding.analyzeSfc) throw new McpError(ErrorCode.InternalError, "analyzeSfc not available in native binding");
253
+ const absolutePath = path.resolve(ctx.projectRoot, vuePath);
254
+ const source = await fs.promises.readFile(absolutePath, "utf-8");
255
+ const analysis = binding.analyzeSfc(source, { filename: absolutePath });
256
+ return { content: [{
257
+ type: "text",
258
+ text: JSON.stringify({
259
+ props: analysis.props.map((p) => ({
260
+ name: p.name,
261
+ type: p.type,
262
+ required: p.required,
263
+ defaultValue: p.default_value
264
+ })),
265
+ emits: analysis.emits
266
+ }, null, 2)
267
+ }] };
268
+ }
269
+ async function handleGetPalette(ctx, binding, args) {
270
+ const artPath = args?.path;
271
+ if (!artPath) throw new McpError(ErrorCode.InvalidParams, "path is required");
272
+ if (!binding.generateArtPalette) throw new McpError(ErrorCode.InternalError, "generateArtPalette not available in native binding");
273
+ const absolutePath = path.resolve(ctx.projectRoot, artPath);
274
+ const source = await fs.promises.readFile(absolutePath, "utf-8");
275
+ const palette = binding.generateArtPalette(source, { filename: absolutePath });
276
+ return { content: [{
277
+ type: "text",
278
+ text: JSON.stringify({
279
+ title: palette.title,
280
+ controls: palette.controls.map((c) => ({
281
+ name: c.name,
282
+ control: c.control,
283
+ defaultValue: c.default_value,
284
+ description: c.description,
285
+ required: c.required,
286
+ options: c.options,
287
+ range: c.range,
288
+ group: c.group
289
+ })),
290
+ groups: palette.groups,
291
+ json: palette.json,
292
+ typescript: palette.typescript
293
+ }, null, 2)
294
+ }] };
295
+ }
296
+
297
+ //#endregion
298
+ //#region src/tools/handler/registry.ts
299
+ async function handleListComponents(ctx, args) {
300
+ const arts = await ctx.scanArtFiles();
301
+ let results = Array.from(arts.values());
302
+ if (args?.category) results = results.filter((a) => a.category?.toLowerCase() === args.category.toLowerCase());
303
+ if (args?.tag) results = results.filter((a) => a.tags.some((t) => t.toLowerCase() === args.tag.toLowerCase()));
304
+ return { content: [{
305
+ type: "text",
306
+ text: JSON.stringify(results.map((r) => ({
307
+ path: path.relative(ctx.projectRoot, r.path),
308
+ title: r.title,
309
+ description: r.description,
310
+ component: r.component,
311
+ category: r.category,
312
+ tags: r.tags,
313
+ variantCount: r.variantCount
314
+ })), null, 2)
315
+ }] };
316
+ }
317
+ async function handleGetComponent(ctx, binding, args) {
318
+ const artPath = args?.path;
319
+ if (!artPath) throw new McpError(ErrorCode.InvalidParams, "path is required");
320
+ const absolutePath = path.resolve(ctx.projectRoot, artPath);
321
+ const source = await fs.promises.readFile(absolutePath, "utf-8");
322
+ const parsed = binding.parseArt(source, { filename: absolutePath });
323
+ return { content: [{
324
+ type: "text",
325
+ text: JSON.stringify({
326
+ metadata: parsed.metadata,
327
+ variants: parsed.variants.map((v) => ({
328
+ name: v.name,
329
+ template: v.template,
330
+ isDefault: v.is_default,
331
+ skipVrt: v.skip_vrt
332
+ })),
333
+ hasScriptSetup: parsed.has_script_setup,
334
+ hasScript: parsed.has_script,
335
+ styleCount: parsed.style_count
336
+ }, null, 2)
337
+ }] };
338
+ }
339
+ async function handleGetVariant(ctx, binding, args) {
340
+ const artPath = args?.path;
341
+ const variantName = args?.variant;
342
+ if (!artPath || !variantName) throw new McpError(ErrorCode.InvalidParams, "path and variant are required");
343
+ const absolutePath = path.resolve(ctx.projectRoot, artPath);
344
+ const source = await fs.promises.readFile(absolutePath, "utf-8");
345
+ const parsed = binding.parseArt(source, { filename: absolutePath });
346
+ const variant = parsed.variants.find((v) => v.name.toLowerCase() === variantName.toLowerCase());
347
+ if (!variant) throw new McpError(ErrorCode.InvalidParams, `Variant "${variantName}" not found`);
348
+ return { content: [{
349
+ type: "text",
350
+ text: JSON.stringify({
351
+ name: variant.name,
352
+ template: variant.template,
353
+ isDefault: variant.is_default,
354
+ skipVrt: variant.skip_vrt
355
+ }, null, 2)
356
+ }] };
357
+ }
358
+ async function handleSearchComponents(ctx, args) {
359
+ const query = (args?.query)?.toLowerCase();
360
+ if (!query) throw new McpError(ErrorCode.InvalidParams, "query is required");
361
+ const arts = await ctx.scanArtFiles();
362
+ const results = Array.from(arts.values()).filter((a) => a.title.toLowerCase().includes(query) || a.description?.toLowerCase().includes(query) || a.tags.some((t) => t.toLowerCase().includes(query)));
363
+ return { content: [{
364
+ type: "text",
365
+ text: JSON.stringify(results.map((r) => ({
366
+ path: path.relative(ctx.projectRoot, r.path),
367
+ title: r.title,
368
+ description: r.description,
369
+ component: r.component,
370
+ category: r.category,
371
+ tags: r.tags
372
+ })), null, 2)
373
+ }] };
374
+ }
375
+
247
376
  //#endregion
248
377
  //#region src/tokens.ts
249
378
  async function parseTokensFromPath(tokensPath) {
@@ -336,240 +465,131 @@ function formatCategoryName(name) {
336
465
  }
337
466
 
338
467
  //#endregion
339
- //#region src/tools/handler.ts
468
+ //#region src/tools/handler/generation.ts
469
+ async function handleGenerateVariants(ctx, binding, args) {
470
+ const componentRelPath = args?.componentPath;
471
+ if (!componentRelPath) throw new McpError(ErrorCode.InvalidParams, "componentPath is required");
472
+ if (!binding.analyzeSfc) throw new McpError(ErrorCode.InternalError, "analyzeSfc not available in native binding");
473
+ if (!binding.generateVariants) throw new McpError(ErrorCode.InternalError, "generateVariants not available in native binding");
474
+ const absolutePath = path.resolve(ctx.projectRoot, componentRelPath);
475
+ const source = await fs.promises.readFile(absolutePath, "utf-8");
476
+ const analysis = binding.analyzeSfc(source, { filename: absolutePath });
477
+ const props = analysis.props.map((p) => ({
478
+ name: p.name,
479
+ prop_type: p.type,
480
+ required: p.required,
481
+ default_value: p.default_value
482
+ }));
483
+ const relPath = `./${path.basename(absolutePath)}`;
484
+ const result = binding.generateVariants(relPath, props, {
485
+ max_variants: args?.maxVariants,
486
+ include_default: args?.includeDefault,
487
+ include_boolean_toggles: args?.includeBooleanToggles,
488
+ include_enum_variants: args?.includeEnumVariants
489
+ });
490
+ return { content: [{
491
+ type: "text",
492
+ text: JSON.stringify({
493
+ componentName: result.component_name,
494
+ artFileContent: result.art_file_content,
495
+ variants: result.variants.map((v) => ({
496
+ name: v.name,
497
+ isDefault: v.is_default,
498
+ props: v.props,
499
+ description: v.description
500
+ }))
501
+ }, null, 2)
502
+ }] };
503
+ }
504
+ async function handleGenerateCsf(ctx, binding, args) {
505
+ const artPath = args?.path;
506
+ if (!artPath) throw new McpError(ErrorCode.InvalidParams, "path is required");
507
+ const absolutePath = path.resolve(ctx.projectRoot, artPath);
508
+ const source = await fs.promises.readFile(absolutePath, "utf-8");
509
+ const csf = binding.artToCsf(source, { filename: absolutePath });
510
+ return { content: [{
511
+ type: "text",
512
+ text: csf.code
513
+ }] };
514
+ }
515
+ async function handleGenerateDocs(ctx, binding, args) {
516
+ const artPath = args?.path;
517
+ if (!artPath) throw new McpError(ErrorCode.InvalidParams, "path is required");
518
+ if (!binding.generateArtDoc) throw new McpError(ErrorCode.InternalError, "generateArtDoc not available in native binding");
519
+ const absolutePath = path.resolve(ctx.projectRoot, artPath);
520
+ const source = await fs.promises.readFile(absolutePath, "utf-8");
521
+ const doc = binding.generateArtDoc(source, { filename: absolutePath }, {
522
+ include_source: args?.includeSource,
523
+ include_templates: args?.includeTemplates,
524
+ include_metadata: true
525
+ });
526
+ return { content: [{
527
+ type: "text",
528
+ text: JSON.stringify({
529
+ markdown: doc.markdown,
530
+ title: doc.title,
531
+ category: doc.category,
532
+ variantCount: doc.variant_count
533
+ }, null, 2)
534
+ }] };
535
+ }
536
+ async function handleGenerateCatalog(ctx, binding, args) {
537
+ if (!binding.generateArtCatalog) throw new McpError(ErrorCode.InternalError, "generateArtCatalog not available in native binding");
538
+ const arts = await ctx.scanArtFiles();
539
+ const sources = [];
540
+ for (const [filePath] of arts) {
541
+ const source = await fs.promises.readFile(filePath, "utf-8");
542
+ sources.push(source);
543
+ }
544
+ const catalog = binding.generateArtCatalog(sources, {
545
+ include_source: args?.includeSource,
546
+ include_templates: args?.includeTemplates,
547
+ include_metadata: true
548
+ });
549
+ return { content: [{
550
+ type: "text",
551
+ text: JSON.stringify({
552
+ markdown: catalog.markdown,
553
+ componentCount: catalog.component_count,
554
+ categories: catalog.categories,
555
+ tags: catalog.tags
556
+ }, null, 2)
557
+ }] };
558
+ }
559
+ async function handleGetTokens(ctx, args) {
560
+ const inputPath = args?.tokensPath;
561
+ const format = args?.format ?? "json";
562
+ let resolvedPath;
563
+ if (inputPath) resolvedPath = path.resolve(ctx.projectRoot, inputPath);
564
+ else resolvedPath = await ctx.resolveTokensPath();
565
+ if (!resolvedPath) throw new McpError(ErrorCode.InvalidParams, "No tokens path provided and none auto-detected. Looked for: tokens/, design-tokens/, style-dictionary/ directories.");
566
+ const categories = await parseTokensFromPath(resolvedPath);
567
+ if (format === "markdown") return { content: [{
568
+ type: "text",
569
+ text: generateTokensMarkdown(categories)
570
+ }] };
571
+ return { content: [{
572
+ type: "text",
573
+ text: JSON.stringify({ categories }, null, 2)
574
+ }] };
575
+ }
576
+
577
+ //#endregion
578
+ //#region src/tools/handler/index.ts
340
579
  async function handleToolCall(ctx, name, args) {
341
580
  const binding = ctx.loadNative();
342
581
  switch (name) {
343
- case "analyze_component": {
344
- const vuePath = args?.path;
345
- if (!vuePath) throw new McpError(ErrorCode.InvalidParams, "path is required");
346
- if (!binding.analyzeSfc) throw new McpError(ErrorCode.InternalError, "analyzeSfc not available in native binding");
347
- const absolutePath = path.resolve(ctx.projectRoot, vuePath);
348
- const source = await fs.promises.readFile(absolutePath, "utf-8");
349
- const analysis = binding.analyzeSfc(source, { filename: absolutePath });
350
- return { content: [{
351
- type: "text",
352
- text: JSON.stringify({
353
- props: analysis.props.map((p) => ({
354
- name: p.name,
355
- type: p.type,
356
- required: p.required,
357
- defaultValue: p.default_value
358
- })),
359
- emits: analysis.emits
360
- }, null, 2)
361
- }] };
362
- }
363
- case "get_palette": {
364
- const artPath = args?.path;
365
- if (!artPath) throw new McpError(ErrorCode.InvalidParams, "path is required");
366
- if (!binding.generateArtPalette) throw new McpError(ErrorCode.InternalError, "generateArtPalette not available in native binding");
367
- const absolutePath = path.resolve(ctx.projectRoot, artPath);
368
- const source = await fs.promises.readFile(absolutePath, "utf-8");
369
- const palette = binding.generateArtPalette(source, { filename: absolutePath });
370
- return { content: [{
371
- type: "text",
372
- text: JSON.stringify({
373
- title: palette.title,
374
- controls: palette.controls.map((c) => ({
375
- name: c.name,
376
- control: c.control,
377
- defaultValue: c.default_value,
378
- description: c.description,
379
- required: c.required,
380
- options: c.options,
381
- range: c.range,
382
- group: c.group
383
- })),
384
- groups: palette.groups,
385
- json: palette.json,
386
- typescript: palette.typescript
387
- }, null, 2)
388
- }] };
389
- }
390
- case "list_components": {
391
- const arts = await ctx.scanArtFiles();
392
- let results = Array.from(arts.values());
393
- if (args?.category) results = results.filter((a) => a.category?.toLowerCase() === args.category.toLowerCase());
394
- if (args?.tag) results = results.filter((a) => a.tags.some((t) => t.toLowerCase() === args.tag.toLowerCase()));
395
- return { content: [{
396
- type: "text",
397
- text: JSON.stringify(results.map((r) => ({
398
- path: path.relative(ctx.projectRoot, r.path),
399
- title: r.title,
400
- description: r.description,
401
- component: r.component,
402
- category: r.category,
403
- tags: r.tags,
404
- variantCount: r.variantCount
405
- })), null, 2)
406
- }] };
407
- }
408
- case "get_component": {
409
- const artPath = args?.path;
410
- if (!artPath) throw new McpError(ErrorCode.InvalidParams, "path is required");
411
- const absolutePath = path.resolve(ctx.projectRoot, artPath);
412
- const source = await fs.promises.readFile(absolutePath, "utf-8");
413
- const parsed = binding.parseArt(source, { filename: absolutePath });
414
- return { content: [{
415
- type: "text",
416
- text: JSON.stringify({
417
- metadata: parsed.metadata,
418
- variants: parsed.variants.map((v) => ({
419
- name: v.name,
420
- template: v.template,
421
- isDefault: v.is_default,
422
- skipVrt: v.skip_vrt
423
- })),
424
- hasScriptSetup: parsed.has_script_setup,
425
- hasScript: parsed.has_script,
426
- styleCount: parsed.style_count
427
- }, null, 2)
428
- }] };
429
- }
430
- case "get_variant": {
431
- const artPath = args?.path;
432
- const variantName = args?.variant;
433
- if (!artPath || !variantName) throw new McpError(ErrorCode.InvalidParams, "path and variant are required");
434
- const absolutePath = path.resolve(ctx.projectRoot, artPath);
435
- const source = await fs.promises.readFile(absolutePath, "utf-8");
436
- const parsed = binding.parseArt(source, { filename: absolutePath });
437
- const variant = parsed.variants.find((v) => v.name.toLowerCase() === variantName.toLowerCase());
438
- if (!variant) throw new McpError(ErrorCode.InvalidParams, `Variant "${variantName}" not found`);
439
- return { content: [{
440
- type: "text",
441
- text: JSON.stringify({
442
- name: variant.name,
443
- template: variant.template,
444
- isDefault: variant.is_default,
445
- skipVrt: variant.skip_vrt
446
- }, null, 2)
447
- }] };
448
- }
449
- case "search_components": {
450
- const query = (args?.query)?.toLowerCase();
451
- if (!query) throw new McpError(ErrorCode.InvalidParams, "query is required");
452
- const arts = await ctx.scanArtFiles();
453
- const results = Array.from(arts.values()).filter((a) => a.title.toLowerCase().includes(query) || a.description?.toLowerCase().includes(query) || a.tags.some((t) => t.toLowerCase().includes(query)));
454
- return { content: [{
455
- type: "text",
456
- text: JSON.stringify(results.map((r) => ({
457
- path: path.relative(ctx.projectRoot, r.path),
458
- title: r.title,
459
- description: r.description,
460
- component: r.component,
461
- category: r.category,
462
- tags: r.tags
463
- })), null, 2)
464
- }] };
465
- }
466
- case "generate_variants": {
467
- const componentRelPath = args?.componentPath;
468
- if (!componentRelPath) throw new McpError(ErrorCode.InvalidParams, "componentPath is required");
469
- if (!binding.analyzeSfc) throw new McpError(ErrorCode.InternalError, "analyzeSfc not available in native binding");
470
- if (!binding.generateVariants) throw new McpError(ErrorCode.InternalError, "generateVariants not available in native binding");
471
- const absolutePath = path.resolve(ctx.projectRoot, componentRelPath);
472
- const source = await fs.promises.readFile(absolutePath, "utf-8");
473
- const analysis = binding.analyzeSfc(source, { filename: absolutePath });
474
- const props = analysis.props.map((p) => ({
475
- name: p.name,
476
- prop_type: p.type,
477
- required: p.required,
478
- default_value: p.default_value
479
- }));
480
- const relPath = `./${path.basename(absolutePath)}`;
481
- const result = binding.generateVariants(relPath, props, {
482
- max_variants: args?.maxVariants,
483
- include_default: args?.includeDefault,
484
- include_boolean_toggles: args?.includeBooleanToggles,
485
- include_enum_variants: args?.includeEnumVariants
486
- });
487
- return { content: [{
488
- type: "text",
489
- text: JSON.stringify({
490
- componentName: result.component_name,
491
- artFileContent: result.art_file_content,
492
- variants: result.variants.map((v) => ({
493
- name: v.name,
494
- isDefault: v.is_default,
495
- props: v.props,
496
- description: v.description
497
- }))
498
- }, null, 2)
499
- }] };
500
- }
501
- case "generate_csf": {
502
- const artPath = args?.path;
503
- if (!artPath) throw new McpError(ErrorCode.InvalidParams, "path is required");
504
- const absolutePath = path.resolve(ctx.projectRoot, artPath);
505
- const source = await fs.promises.readFile(absolutePath, "utf-8");
506
- const csf = binding.artToCsf(source, { filename: absolutePath });
507
- return { content: [{
508
- type: "text",
509
- text: csf.code
510
- }] };
511
- }
512
- case "generate_docs": {
513
- const artPath = args?.path;
514
- if (!artPath) throw new McpError(ErrorCode.InvalidParams, "path is required");
515
- if (!binding.generateArtDoc) throw new McpError(ErrorCode.InternalError, "generateArtDoc not available in native binding");
516
- const absolutePath = path.resolve(ctx.projectRoot, artPath);
517
- const source = await fs.promises.readFile(absolutePath, "utf-8");
518
- const doc = binding.generateArtDoc(source, { filename: absolutePath }, {
519
- include_source: args?.includeSource,
520
- include_templates: args?.includeTemplates,
521
- include_metadata: true
522
- });
523
- return { content: [{
524
- type: "text",
525
- text: JSON.stringify({
526
- markdown: doc.markdown,
527
- title: doc.title,
528
- category: doc.category,
529
- variantCount: doc.variant_count
530
- }, null, 2)
531
- }] };
532
- }
533
- case "generate_catalog": {
534
- if (!binding.generateArtCatalog) throw new McpError(ErrorCode.InternalError, "generateArtCatalog not available in native binding");
535
- const arts = await ctx.scanArtFiles();
536
- const sources = [];
537
- for (const [filePath] of arts) {
538
- const source = await fs.promises.readFile(filePath, "utf-8");
539
- sources.push(source);
540
- }
541
- const catalog = binding.generateArtCatalog(sources, {
542
- include_source: args?.includeSource,
543
- include_templates: args?.includeTemplates,
544
- include_metadata: true
545
- });
546
- return { content: [{
547
- type: "text",
548
- text: JSON.stringify({
549
- markdown: catalog.markdown,
550
- componentCount: catalog.component_count,
551
- categories: catalog.categories,
552
- tags: catalog.tags
553
- }, null, 2)
554
- }] };
555
- }
556
- case "get_tokens": {
557
- const inputPath = args?.tokensPath;
558
- const format = args?.format ?? "json";
559
- let resolvedPath;
560
- if (inputPath) resolvedPath = path.resolve(ctx.projectRoot, inputPath);
561
- else resolvedPath = await ctx.resolveTokensPath();
562
- if (!resolvedPath) throw new McpError(ErrorCode.InvalidParams, "No tokens path provided and none auto-detected. Looked for: tokens/, design-tokens/, style-dictionary/ directories.");
563
- const categories = await parseTokensFromPath(resolvedPath);
564
- if (format === "markdown") return { content: [{
565
- type: "text",
566
- text: generateTokensMarkdown(categories)
567
- }] };
568
- return { content: [{
569
- type: "text",
570
- text: JSON.stringify({ categories }, null, 2)
571
- }] };
572
- }
582
+ case "analyze_component": return handleAnalyzeComponent(ctx, binding, args);
583
+ case "get_palette": return handleGetPalette(ctx, binding, args);
584
+ case "list_components": return handleListComponents(ctx, args);
585
+ case "get_component": return handleGetComponent(ctx, binding, args);
586
+ case "get_variant": return handleGetVariant(ctx, binding, args);
587
+ case "search_components": return handleSearchComponents(ctx, args);
588
+ case "generate_variants": return handleGenerateVariants(ctx, binding, args);
589
+ case "generate_csf": return handleGenerateCsf(ctx, binding, args);
590
+ case "generate_docs": return handleGenerateDocs(ctx, binding, args);
591
+ case "generate_catalog": return handleGenerateCatalog(ctx, binding, args);
592
+ case "get_tokens": return handleGetTokens(ctx, args);
573
593
  default: throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
574
594
  }
575
595
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vizejs/musea-mcp-server",
3
- "version": "0.12.0",
3
+ "version": "0.14.0",
4
4
  "description": "MCP server for building Vue.js design systems - component analysis, documentation, variant generation, and design tokens",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -35,7 +35,7 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "@modelcontextprotocol/sdk": "^0.5.0",
38
- "@vizejs/native": "0.12.0"
38
+ "@vizejs/native": "0.14.0"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/node": "^22.14.0",