@vizejs/musea-mcp-server 0.33.0 → 0.34.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 → cli.mjs}
RENAMED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { startServer } from "./src-
|
|
3
|
-
|
|
2
|
+
import { n as startServer } from "./src-DqveCZc0.mjs";
|
|
4
3
|
//#region src/cli.ts
|
|
4
|
+
/**
|
|
5
|
+
* Musea MCP Server CLI.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* musea-mcp [project-root] [--tokens-path <path>]
|
|
9
|
+
*
|
|
10
|
+
* Environment:
|
|
11
|
+
* MUSEA_PROJECT_ROOT - Project root directory (default: cwd)
|
|
12
|
+
* MUSEA_TOKENS_PATH - Path to design tokens file/directory
|
|
13
|
+
*/
|
|
5
14
|
let projectRoot = process.env.MUSEA_PROJECT_ROOT || process.cwd();
|
|
6
15
|
let tokensPath = process.env.MUSEA_TOKENS_PATH;
|
|
7
16
|
const args = process.argv.slice(2);
|
|
@@ -13,5 +22,5 @@ startServer(projectRoot, { tokensPath }).catch((error) => {
|
|
|
13
22
|
console.error("[musea-mcp] Failed to start:", error);
|
|
14
23
|
process.exit(1);
|
|
15
24
|
});
|
|
16
|
-
|
|
17
|
-
|
|
25
|
+
//#endregion
|
|
26
|
+
export {};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
2
|
|
|
3
3
|
//#region src/index.d.ts
|
|
4
|
-
|
|
5
4
|
declare function createMuseaServer(config: {
|
|
6
5
|
projectRoot: string;
|
|
7
6
|
include?: string[];
|
|
@@ -10,5 +9,6 @@ declare function createMuseaServer(config: {
|
|
|
10
9
|
}): Server;
|
|
11
10
|
declare function startServer(projectRoot: string, options?: {
|
|
12
11
|
tokensPath?: string;
|
|
13
|
-
}): Promise<void>;
|
|
12
|
+
}): Promise<void>;
|
|
13
|
+
//#endregion
|
|
14
14
|
export { createMuseaServer, createMuseaServer as default, startServer };
|
package/dist/index.mjs
ADDED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
1
2
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
4
|
import { CallToolRequestSchema, ErrorCode, ListResourcesRequestSchema, ListToolsRequestSchema, McpError, ReadResourceRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
4
5
|
import fs from "node:fs";
|
|
5
6
|
import path from "node:path";
|
|
6
|
-
import { createRequire } from "node:module";
|
|
7
|
-
|
|
8
7
|
//#region src/native.ts
|
|
9
8
|
let native = null;
|
|
10
9
|
function loadNative() {
|
|
@@ -17,7 +16,6 @@ function loadNative() {
|
|
|
17
16
|
throw new Error(`Failed to load @vizejs/native. Make sure it's installed: ${String(e)}`);
|
|
18
17
|
}
|
|
19
18
|
}
|
|
20
|
-
|
|
21
19
|
//#endregion
|
|
22
20
|
//#region src/scanner.ts
|
|
23
21
|
async function findArtFiles(root, include, exclude) {
|
|
@@ -49,7 +47,6 @@ function matchGlob(filepath, pattern) {
|
|
|
49
47
|
const regex = pattern.replace(/\*\*/g, "{{DOUBLE_STAR}}").replace(/\*/g, "[^/]*").replace(/{{DOUBLE_STAR}}/g, ".*").replace(/\./g, "\\.");
|
|
50
48
|
return new RegExp(`^${regex}$`).test(filepath);
|
|
51
49
|
}
|
|
52
|
-
|
|
53
50
|
//#endregion
|
|
54
51
|
//#region src/tools/definitions.ts
|
|
55
52
|
/**
|
|
@@ -243,9 +240,13 @@ const toolDefinitions = [
|
|
|
243
240
|
}
|
|
244
241
|
}
|
|
245
242
|
];
|
|
246
|
-
|
|
247
243
|
//#endregion
|
|
248
244
|
//#region src/tools/handler/analysis.ts
|
|
245
|
+
/**
|
|
246
|
+
* MCP tool handlers for component analysis.
|
|
247
|
+
*
|
|
248
|
+
* Handles `analyze_component` and `get_palette` tool calls.
|
|
249
|
+
*/
|
|
249
250
|
async function handleAnalyzeComponent(ctx, binding, args) {
|
|
250
251
|
const vuePath = args?.path;
|
|
251
252
|
if (!vuePath) throw new McpError(ErrorCode.InvalidParams, "path is required");
|
|
@@ -293,9 +294,14 @@ async function handleGetPalette(ctx, binding, args) {
|
|
|
293
294
|
}, null, 2)
|
|
294
295
|
}] };
|
|
295
296
|
}
|
|
296
|
-
|
|
297
297
|
//#endregion
|
|
298
298
|
//#region src/tools/handler/registry.ts
|
|
299
|
+
/**
|
|
300
|
+
* MCP tool handlers for the component registry.
|
|
301
|
+
*
|
|
302
|
+
* Handles `list_components`, `get_component`, `get_variant`, and
|
|
303
|
+
* `search_components` tool calls.
|
|
304
|
+
*/
|
|
299
305
|
async function handleListComponents(ctx, args) {
|
|
300
306
|
const arts = await ctx.scanArtFiles();
|
|
301
307
|
let results = Array.from(arts.values());
|
|
@@ -342,8 +348,7 @@ async function handleGetVariant(ctx, binding, args) {
|
|
|
342
348
|
if (!artPath || !variantName) throw new McpError(ErrorCode.InvalidParams, "path and variant are required");
|
|
343
349
|
const absolutePath = path.resolve(ctx.projectRoot, artPath);
|
|
344
350
|
const source = await fs.promises.readFile(absolutePath, "utf-8");
|
|
345
|
-
const
|
|
346
|
-
const variant = parsed.variants.find((v) => v.name.toLowerCase() === variantName.toLowerCase());
|
|
351
|
+
const variant = binding.parseArt(source, { filename: absolutePath }).variants.find((v) => v.name.toLowerCase() === variantName.toLowerCase());
|
|
347
352
|
if (!variant) throw new McpError(ErrorCode.InvalidParams, `Variant "${variantName}" not found`);
|
|
348
353
|
return { content: [{
|
|
349
354
|
type: "text",
|
|
@@ -372,35 +377,31 @@ async function handleSearchComponents(ctx, args) {
|
|
|
372
377
|
})), null, 2)
|
|
373
378
|
}] };
|
|
374
379
|
}
|
|
375
|
-
|
|
376
380
|
//#endregion
|
|
377
381
|
//#region src/tokens.ts
|
|
378
382
|
async function parseTokensFromPath(tokensPath) {
|
|
379
|
-
|
|
380
|
-
if (stat.isDirectory()) {
|
|
383
|
+
if ((await fs.promises.stat(tokensPath)).isDirectory()) {
|
|
381
384
|
const entries = await fs.promises.readdir(tokensPath, { withFileTypes: true });
|
|
382
385
|
const categories = [];
|
|
383
386
|
for (const entry of entries) if (entry.isFile() && (entry.name.endsWith(".json") || entry.name.endsWith(".tokens.json"))) {
|
|
384
387
|
const filePath = path.join(tokensPath, entry.name);
|
|
385
|
-
const content
|
|
386
|
-
const tokens
|
|
388
|
+
const content = await fs.promises.readFile(filePath, "utf-8");
|
|
389
|
+
const tokens = JSON.parse(content);
|
|
387
390
|
const categoryName = path.basename(entry.name, path.extname(entry.name)).replace(".tokens", "");
|
|
388
391
|
categories.push({
|
|
389
392
|
name: formatCategoryName(categoryName),
|
|
390
|
-
tokens: extractTokenValues(tokens
|
|
391
|
-
subcategories: extractSubcats(tokens
|
|
393
|
+
tokens: extractTokenValues(tokens),
|
|
394
|
+
subcategories: extractSubcats(tokens)
|
|
392
395
|
});
|
|
393
396
|
}
|
|
394
397
|
return categories;
|
|
395
398
|
}
|
|
396
399
|
const content = await fs.promises.readFile(tokensPath, "utf-8");
|
|
397
|
-
|
|
398
|
-
return flattenTokenStructure(tokens);
|
|
400
|
+
return flattenTokenStructure(JSON.parse(content));
|
|
399
401
|
}
|
|
400
402
|
function generateTokensMarkdown(categories) {
|
|
401
403
|
const renderCategory = (category, level = 2) => {
|
|
402
|
-
|
|
403
|
-
let md = `\n${heading} ${category.name}\n\n`;
|
|
404
|
+
let md = `\n${"#".repeat(level)} ${category.name}\n\n`;
|
|
404
405
|
if (Object.keys(category.tokens).length > 0) {
|
|
405
406
|
md += "| Token | Value | Description |\n";
|
|
406
407
|
md += "|-------|-------|-------------|\n";
|
|
@@ -463,9 +464,14 @@ function flattenTokenStructure(tokens) {
|
|
|
463
464
|
function formatCategoryName(name) {
|
|
464
465
|
return name.replace(/[-_]/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").split(" ").map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
|
|
465
466
|
}
|
|
466
|
-
|
|
467
467
|
//#endregion
|
|
468
468
|
//#region src/tools/handler/generation.ts
|
|
469
|
+
/**
|
|
470
|
+
* MCP tool handlers for code generation.
|
|
471
|
+
*
|
|
472
|
+
* Handles `generate_variants`, `generate_csf`, `generate_docs`,
|
|
473
|
+
* `generate_catalog`, and `get_tokens` tool calls.
|
|
474
|
+
*/
|
|
469
475
|
async function handleGenerateVariants(ctx, binding, args) {
|
|
470
476
|
const componentRelPath = args?.componentPath;
|
|
471
477
|
if (!componentRelPath) throw new McpError(ErrorCode.InvalidParams, "componentPath is required");
|
|
@@ -473,8 +479,7 @@ async function handleGenerateVariants(ctx, binding, args) {
|
|
|
473
479
|
if (!binding.generateVariants) throw new McpError(ErrorCode.InternalError, "generateVariants not available in native binding");
|
|
474
480
|
const absolutePath = path.resolve(ctx.projectRoot, componentRelPath);
|
|
475
481
|
const source = await fs.promises.readFile(absolutePath, "utf-8");
|
|
476
|
-
const
|
|
477
|
-
const props = analysis.props.map((p) => ({
|
|
482
|
+
const props = binding.analyzeSfc(source, { filename: absolutePath }).props.map((p) => ({
|
|
478
483
|
name: p.name,
|
|
479
484
|
prop_type: p.type,
|
|
480
485
|
required: p.required,
|
|
@@ -506,10 +511,9 @@ async function handleGenerateCsf(ctx, binding, args) {
|
|
|
506
511
|
if (!artPath) throw new McpError(ErrorCode.InvalidParams, "path is required");
|
|
507
512
|
const absolutePath = path.resolve(ctx.projectRoot, artPath);
|
|
508
513
|
const source = await fs.promises.readFile(absolutePath, "utf-8");
|
|
509
|
-
const csf = binding.artToCsf(source, { filename: absolutePath });
|
|
510
514
|
return { content: [{
|
|
511
515
|
type: "text",
|
|
512
|
-
text:
|
|
516
|
+
text: binding.artToCsf(source, { filename: absolutePath }).code
|
|
513
517
|
}] };
|
|
514
518
|
}
|
|
515
519
|
async function handleGenerateDocs(ctx, binding, args) {
|
|
@@ -573,9 +577,14 @@ async function handleGetTokens(ctx, args) {
|
|
|
573
577
|
text: JSON.stringify({ categories }, null, 2)
|
|
574
578
|
}] };
|
|
575
579
|
}
|
|
576
|
-
|
|
577
580
|
//#endregion
|
|
578
581
|
//#region src/tools/handler/index.ts
|
|
582
|
+
/**
|
|
583
|
+
* MCP tool call handler for Musea.
|
|
584
|
+
*
|
|
585
|
+
* Routes incoming tool calls to the appropriate handler logic based on
|
|
586
|
+
* the tool name, using the native Rust binding and server context.
|
|
587
|
+
*/
|
|
579
588
|
async function handleToolCall(ctx, name, args) {
|
|
580
589
|
const binding = ctx.loadNative();
|
|
581
590
|
switch (name) {
|
|
@@ -593,7 +602,6 @@ async function handleToolCall(ctx, name, args) {
|
|
|
593
602
|
default: throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
594
603
|
}
|
|
595
604
|
}
|
|
596
|
-
|
|
597
605
|
//#endregion
|
|
598
606
|
//#region src/resources.ts
|
|
599
607
|
async function listResources(ctx) {
|
|
@@ -614,8 +622,7 @@ async function listResources(ctx) {
|
|
|
614
622
|
mimeType: "text/markdown"
|
|
615
623
|
});
|
|
616
624
|
}
|
|
617
|
-
|
|
618
|
-
if (resolvedTokensPath) resources.push({
|
|
625
|
+
if (await ctx.resolveTokensPath()) resources.push({
|
|
619
626
|
uri: "musea://tokens",
|
|
620
627
|
name: "Design Tokens",
|
|
621
628
|
description: "Project design tokens (colors, spacing, typography, …)",
|
|
@@ -629,8 +636,7 @@ async function readResource(ctx, uri) {
|
|
|
629
636
|
const absolutePath = path.resolve(ctx.projectRoot, relativePath);
|
|
630
637
|
try {
|
|
631
638
|
const source = await fs.promises.readFile(absolutePath, "utf-8");
|
|
632
|
-
const
|
|
633
|
-
const parsed = binding.parseArt(source, { filename: absolutePath });
|
|
639
|
+
const parsed = ctx.loadNative().parseArt(source, { filename: absolutePath });
|
|
634
640
|
return { contents: [{
|
|
635
641
|
uri,
|
|
636
642
|
mimeType: "application/json",
|
|
@@ -659,11 +665,10 @@ async function readResource(ctx, uri) {
|
|
|
659
665
|
const source = await fs.promises.readFile(absolutePath, "utf-8");
|
|
660
666
|
const binding = ctx.loadNative();
|
|
661
667
|
if (!binding.generateArtDoc) throw new McpError(ErrorCode.InternalError, "generateArtDoc not available in native binding");
|
|
662
|
-
const doc = binding.generateArtDoc(source, { filename: absolutePath });
|
|
663
668
|
return { contents: [{
|
|
664
669
|
uri,
|
|
665
670
|
mimeType: "text/markdown",
|
|
666
|
-
text:
|
|
671
|
+
text: binding.generateArtDoc(source, { filename: absolutePath }).markdown
|
|
667
672
|
}] };
|
|
668
673
|
} catch (e) {
|
|
669
674
|
if (e instanceof McpError) throw e;
|
|
@@ -686,9 +691,17 @@ async function readResource(ctx, uri) {
|
|
|
686
691
|
}
|
|
687
692
|
throw new McpError(ErrorCode.InvalidRequest, `Unknown resource URI: ${uri}`);
|
|
688
693
|
}
|
|
689
|
-
|
|
690
694
|
//#endregion
|
|
691
695
|
//#region src/index.ts
|
|
696
|
+
/**
|
|
697
|
+
* Musea MCP Server — Vue.js design system toolkit.
|
|
698
|
+
*
|
|
699
|
+
* Provides AI assistants with tools to:
|
|
700
|
+
* - Analyze Vue SFC components (props, emits)
|
|
701
|
+
* - Browse and search a component registry
|
|
702
|
+
* - Generate documentation, variants, and Storybook stories
|
|
703
|
+
* - Read and format design tokens
|
|
704
|
+
*/
|
|
692
705
|
function createMuseaServer(config) {
|
|
693
706
|
const server = new Server({
|
|
694
707
|
name: "musea-mcp-server",
|
|
@@ -701,14 +714,14 @@ function createMuseaServer(config) {
|
|
|
701
714
|
const include = config.include ?? ["**/*.art.vue"];
|
|
702
715
|
const exclude = config.exclude ?? ["node_modules/**", "dist/**"];
|
|
703
716
|
const tokensPath = config.tokensPath;
|
|
704
|
-
let artCache = new Map();
|
|
717
|
+
let artCache = /* @__PURE__ */ new Map();
|
|
705
718
|
let lastScanTime = 0;
|
|
706
719
|
async function scanArtFiles() {
|
|
707
720
|
const now = Date.now();
|
|
708
721
|
if (now - lastScanTime < 5e3 && artCache.size > 0) return artCache;
|
|
709
722
|
const binding = loadNative();
|
|
710
723
|
const files = await findArtFiles(projectRoot, include, exclude);
|
|
711
|
-
artCache = new Map();
|
|
724
|
+
artCache = /* @__PURE__ */ new Map();
|
|
712
725
|
for (const file of files) try {
|
|
713
726
|
const source = await fs.promises.readFile(file, "utf-8");
|
|
714
727
|
const parsed = binding.parseArt(source, { filename: file });
|
|
@@ -729,12 +742,11 @@ function createMuseaServer(config) {
|
|
|
729
742
|
}
|
|
730
743
|
async function resolveTokensPath() {
|
|
731
744
|
if (tokensPath) return path.resolve(projectRoot, tokensPath);
|
|
732
|
-
const
|
|
745
|
+
for (const dir of [
|
|
733
746
|
"tokens",
|
|
734
747
|
"design-tokens",
|
|
735
748
|
"style-dictionary"
|
|
736
|
-
]
|
|
737
|
-
for (const dir of candidates) {
|
|
749
|
+
]) {
|
|
738
750
|
const candidate = path.join(projectRoot, dir);
|
|
739
751
|
try {
|
|
740
752
|
const stat = await fs.promises.stat(candidate);
|
|
@@ -764,7 +776,5 @@ async function startServer(projectRoot, options) {
|
|
|
764
776
|
await server.connect(transport);
|
|
765
777
|
console.error("[musea-mcp] Server started");
|
|
766
778
|
}
|
|
767
|
-
var src_default = createMuseaServer;
|
|
768
|
-
|
|
769
779
|
//#endregion
|
|
770
|
-
export {
|
|
780
|
+
export { startServer as n, createMuseaServer as t };
|
package/package.json
CHANGED
|
@@ -1,57 +1,56 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vizejs/musea-mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.0",
|
|
4
4
|
"description": "MCP server for building Vue.js design systems - component analysis, documentation, variant generation, and design tokens",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "./dist/index.js",
|
|
7
|
-
"types": "./dist/index.d.ts",
|
|
8
|
-
"bin": {
|
|
9
|
-
"musea-mcp": "./dist/cli.js"
|
|
10
|
-
},
|
|
11
|
-
"exports": {
|
|
12
|
-
".": {
|
|
13
|
-
"import": "./dist/index.js",
|
|
14
|
-
"types": "./dist/index.d.ts"
|
|
15
|
-
}
|
|
16
|
-
},
|
|
17
|
-
"files": [
|
|
18
|
-
"dist"
|
|
19
|
-
],
|
|
20
5
|
"keywords": [
|
|
6
|
+
"ai",
|
|
7
|
+
"component-analysis",
|
|
8
|
+
"design-system",
|
|
21
9
|
"mcp",
|
|
22
10
|
"model-context-protocol",
|
|
23
|
-
"vue",
|
|
24
|
-
"design-system",
|
|
25
|
-
"component-analysis",
|
|
26
11
|
"musea",
|
|
27
|
-
"
|
|
12
|
+
"vue"
|
|
28
13
|
],
|
|
29
|
-
"author": "ubugeeei",
|
|
30
14
|
"license": "MIT",
|
|
15
|
+
"author": "ubugeeei",
|
|
31
16
|
"repository": {
|
|
32
17
|
"type": "git",
|
|
33
18
|
"url": "https://github.com/ubugeeei/vize.git",
|
|
34
19
|
"directory": "npm/musea-mcp-server"
|
|
35
20
|
},
|
|
21
|
+
"bin": {
|
|
22
|
+
"musea-mcp": "./dist/cli.js"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist"
|
|
26
|
+
],
|
|
27
|
+
"type": "module",
|
|
28
|
+
"main": "./dist/index.js",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"import": "./dist/index.js",
|
|
33
|
+
"types": "./dist/index.d.ts"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
36
39
|
"dependencies": {
|
|
37
40
|
"@modelcontextprotocol/sdk": "^0.5.0",
|
|
38
|
-
"@vizejs/native": "0.
|
|
41
|
+
"@vizejs/native": "0.34.0"
|
|
39
42
|
},
|
|
40
43
|
"devDependencies": {
|
|
41
44
|
"@types/node": "^22.14.0",
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
},
|
|
45
|
-
"publishConfig": {
|
|
46
|
-
"access": "public"
|
|
45
|
+
"typescript": "^5.7.0",
|
|
46
|
+
"vite-plus": "latest"
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
|
49
|
-
"build": "
|
|
50
|
-
"dev": "
|
|
49
|
+
"build": "vp pack",
|
|
50
|
+
"dev": "vp pack --watch",
|
|
51
51
|
"start": "node dist/cli.js",
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"fmt": "
|
|
55
|
-
"fmt:check": "oxfmt src tsdown.config.ts"
|
|
52
|
+
"check": "vp check src vite.config.ts",
|
|
53
|
+
"check:fix": "vp check --fix src vite.config.ts",
|
|
54
|
+
"fmt": "vp fmt --write src vite.config.ts"
|
|
56
55
|
}
|
|
57
56
|
}
|
package/dist/index.js
DELETED
|
File without changes
|