@vizejs/musea-mcp-server 0.81.0 → 0.82.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.mjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{src-Cp5GZpzj.mjs → src-DCb_Jsfy.mjs} +33 -12
- package/package.json +2 -2
package/dist/cli.mjs
CHANGED
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as startServer, t as createMuseaServer } from "./src-
|
|
1
|
+
import { n as startServer, t as createMuseaServer } from "./src-DCb_Jsfy.mjs";
|
|
2
2
|
export { createMuseaServer, createMuseaServer as default, startServer };
|
|
@@ -495,9 +495,23 @@ function tokenize(query) {
|
|
|
495
495
|
return Array.from(new Set(query.toLowerCase().split(/[\s/,_-]+/).map((term) => term.trim()).filter(Boolean)));
|
|
496
496
|
}
|
|
497
497
|
function toProjectPath(projectRoot, absolutePath) {
|
|
498
|
-
const
|
|
499
|
-
|
|
500
|
-
|
|
498
|
+
const root = path.resolve(projectRoot);
|
|
499
|
+
const resolved = path.resolve(absolutePath);
|
|
500
|
+
const relativePath = path.relative(root, resolved);
|
|
501
|
+
return isProjectPath(root, resolved) ? relativePath || "." : resolved;
|
|
502
|
+
}
|
|
503
|
+
function isProjectPath(projectRoot, candidatePath) {
|
|
504
|
+
const root = path.resolve(projectRoot);
|
|
505
|
+
const candidate = path.resolve(candidatePath);
|
|
506
|
+
const relativePath = path.relative(root, candidate);
|
|
507
|
+
return relativePath === "" || !relativePath.startsWith("..") && !path.isAbsolute(relativePath);
|
|
508
|
+
}
|
|
509
|
+
function resolveProjectPath(projectRoot, inputPath, label = "path") {
|
|
510
|
+
if (inputPath.includes("\0")) throw new McpError(ErrorCode.InvalidParams, `${label} contains an invalid character`);
|
|
511
|
+
const root = path.resolve(projectRoot);
|
|
512
|
+
const resolvedPath = path.isAbsolute(inputPath) ? path.resolve(inputPath) : path.resolve(root, inputPath);
|
|
513
|
+
if (!isProjectPath(root, resolvedPath)) throw new McpError(ErrorCode.InvalidParams, `${label} must stay inside the project root`);
|
|
514
|
+
return resolvedPath;
|
|
501
515
|
}
|
|
502
516
|
function buildResourceUris$1(relativePath, variantNames, hasComponentSource) {
|
|
503
517
|
const encodedPath = encodeURIComponent(relativePath);
|
|
@@ -628,7 +642,7 @@ async function resolveArtReference(ctx, args) {
|
|
|
628
642
|
const queryArg = typeof args?.query === "string" ? args.query : void 0;
|
|
629
643
|
const refArg = typeof args?.ref === "string" ? args.ref : void 0;
|
|
630
644
|
if (pathArg) {
|
|
631
|
-
const resolvedPath =
|
|
645
|
+
const resolvedPath = resolveProjectPath(ctx.projectRoot, pathArg, "path");
|
|
632
646
|
const normalizedResolvedPath = normalizePathLike(resolvedPath);
|
|
633
647
|
const normalizedRelativePath = normalizePathLike(path.relative(ctx.projectRoot, resolvedPath));
|
|
634
648
|
const directMatch = arts.find((info) => {
|
|
@@ -719,6 +733,13 @@ async function getComponentSourceDescriptor(ctx, resolved) {
|
|
|
719
733
|
exists: false,
|
|
720
734
|
error: "This art file does not declare a component source."
|
|
721
735
|
};
|
|
736
|
+
if (!isProjectPath(ctx.projectRoot, componentPath)) return {
|
|
737
|
+
reference: resolved.info.component,
|
|
738
|
+
absolutePath: componentPath,
|
|
739
|
+
path: componentPath,
|
|
740
|
+
exists: false,
|
|
741
|
+
error: "Component source is outside the project root."
|
|
742
|
+
};
|
|
722
743
|
try {
|
|
723
744
|
await fs.promises.access(componentPath, fs.constants.R_OK);
|
|
724
745
|
return {
|
|
@@ -977,7 +998,7 @@ async function handleAnalyzeComponent(ctx, binding, args) {
|
|
|
977
998
|
const directPath = args?.path;
|
|
978
999
|
if (directPath?.endsWith(".vue") && !directPath.endsWith(".art.vue")) {
|
|
979
1000
|
if (!binding.analyzeSfc) throw new McpError(ErrorCode.InternalError, "analyzeSfc not available in native binding");
|
|
980
|
-
const absolutePath =
|
|
1001
|
+
const absolutePath = resolveProjectPath(ctx.projectRoot, directPath, "path");
|
|
981
1002
|
const source = await fs.promises.readFile(absolutePath, "utf-8");
|
|
982
1003
|
const analysis = binding.analyzeSfc(source, { filename: absolutePath });
|
|
983
1004
|
return { content: [{
|
|
@@ -1344,7 +1365,7 @@ async function handleGenerateVariants(ctx, binding, args) {
|
|
|
1344
1365
|
if (!componentRelPath) throw new McpError(ErrorCode.InvalidParams, "componentPath is required");
|
|
1345
1366
|
if (!binding.analyzeSfc) throw new McpError(ErrorCode.InternalError, "analyzeSfc not available in native binding");
|
|
1346
1367
|
if (!binding.generateVariants) throw new McpError(ErrorCode.InternalError, "generateVariants not available in native binding");
|
|
1347
|
-
const absolutePath =
|
|
1368
|
+
const absolutePath = resolveProjectPath(ctx.projectRoot, componentRelPath, "componentPath");
|
|
1348
1369
|
const source = await fs.promises.readFile(absolutePath, "utf-8");
|
|
1349
1370
|
const props = binding.analyzeSfc(source, { filename: absolutePath }).props.map((prop) => ({
|
|
1350
1371
|
name: prop.name,
|
|
@@ -1469,7 +1490,7 @@ async function handleGetTokens(ctx, args) {
|
|
|
1469
1490
|
const inputPath = args?.tokensPath;
|
|
1470
1491
|
const format = args?.format ?? "json";
|
|
1471
1492
|
let resolvedPath;
|
|
1472
|
-
if (inputPath) resolvedPath =
|
|
1493
|
+
if (inputPath) resolvedPath = resolveProjectPath(ctx.projectRoot, inputPath, "tokensPath");
|
|
1473
1494
|
else resolvedPath = await ctx.resolveTokensPath();
|
|
1474
1495
|
if (!resolvedPath) throw new McpError(ErrorCode.InvalidParams, "No tokens path provided and none auto-detected. Looked for: tokens/, design-tokens/, style-dictionary/ directories.");
|
|
1475
1496
|
const categories = await parseTokensFromPath(resolvedPath);
|
|
@@ -1494,7 +1515,7 @@ async function handleSearchTokens(ctx, args) {
|
|
|
1494
1515
|
const inputPath = args?.tokensPath;
|
|
1495
1516
|
const typeFilter = typeof args?.type === "string" ? args.type.toLowerCase() : void 0;
|
|
1496
1517
|
const limit = typeof args?.limit === "number" ? args.limit : 20;
|
|
1497
|
-
const resolvedPath = inputPath ?
|
|
1518
|
+
const resolvedPath = inputPath ? resolveProjectPath(ctx.projectRoot, inputPath, "tokensPath") : await ctx.resolveTokensPath();
|
|
1498
1519
|
if (!resolvedPath) throw new McpError(ErrorCode.InvalidParams, "No tokens path provided and none auto-detected. Looked for: tokens/, design-tokens/, style-dictionary/ directories.");
|
|
1499
1520
|
const flattened = flattenTokenCategories(await parseTokensFromPath(resolvedPath));
|
|
1500
1521
|
const normalizedQuery = query.toLowerCase();
|
|
@@ -1672,7 +1693,7 @@ async function readResource(ctx, uri) {
|
|
|
1672
1693
|
}
|
|
1673
1694
|
if (uri.startsWith("musea://source/")) {
|
|
1674
1695
|
const relativePath = decodeURIComponent(uri.slice(15));
|
|
1675
|
-
const absolutePath =
|
|
1696
|
+
const absolutePath = resolveProjectPath(ctx.projectRoot, relativePath, "source path");
|
|
1676
1697
|
return { contents: [{
|
|
1677
1698
|
uri,
|
|
1678
1699
|
mimeType: "text/plain",
|
|
@@ -1687,7 +1708,7 @@ async function readResource(ctx, uri) {
|
|
|
1687
1708
|
includeDocumentation: false
|
|
1688
1709
|
})).componentSource;
|
|
1689
1710
|
if (!componentSource?.path || componentSource.exists !== true) throw new McpError(ErrorCode.InvalidRequest, componentSource?.error ?? "Component source not available for this art file");
|
|
1690
|
-
const absolutePath =
|
|
1711
|
+
const absolutePath = resolveProjectPath(ctx.projectRoot, componentSource.path, "component source path");
|
|
1691
1712
|
return { contents: [{
|
|
1692
1713
|
uri,
|
|
1693
1714
|
mimeType: "text/plain",
|
|
@@ -1766,7 +1787,7 @@ function createMuseaServer(config) {
|
|
|
1766
1787
|
resources: {},
|
|
1767
1788
|
tools: {}
|
|
1768
1789
|
} });
|
|
1769
|
-
const projectRoot = config.projectRoot;
|
|
1790
|
+
const projectRoot = path.resolve(config.projectRoot);
|
|
1770
1791
|
const include = config.include ?? ["**/*.art.vue"];
|
|
1771
1792
|
const exclude = config.exclude ?? ["node_modules/**", "dist/**"];
|
|
1772
1793
|
const tokensPath = config.tokensPath;
|
|
@@ -1801,7 +1822,7 @@ function createMuseaServer(config) {
|
|
|
1801
1822
|
return artCache;
|
|
1802
1823
|
}
|
|
1803
1824
|
async function resolveTokensPath() {
|
|
1804
|
-
if (tokensPath) return
|
|
1825
|
+
if (tokensPath) return resolveProjectPath(projectRoot, tokensPath, "tokensPath");
|
|
1805
1826
|
for (const dir of [
|
|
1806
1827
|
"tokens",
|
|
1807
1828
|
"design-tokens",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vizejs/musea-mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.82.0",
|
|
4
4
|
"description": "MCP server for building Vue.js design systems - component analysis, documentation, variant generation, and design tokens",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@modelcontextprotocol/sdk": "1.29.0",
|
|
41
|
-
"@vizejs/native": "0.
|
|
41
|
+
"@vizejs/native": "0.82.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@tsdown/css": "0.22.0",
|