viewgate-mcp 1.0.17 → 1.0.20
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/index.js +14 -126
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -118,7 +118,8 @@ function createMcpServer(apiKey, personalKey) {
|
|
|
118
118
|
path: { type: "string", description: "The relative path of the endpoint" },
|
|
119
119
|
method: { type: "string", description: "HTTP method (GET, POST, etc.)" },
|
|
120
120
|
description: { type: "string", description: "Human-readable description of what the endpoint does. MUST be in the preferredLanguage." },
|
|
121
|
-
hash: { type: "string", description: "Optional SHA256 hash of the endpoint definition for efficient diffing." }
|
|
121
|
+
hash: { type: "string", description: "Optional SHA256 hash of the endpoint definition for efficient diffing." },
|
|
122
|
+
contract: { type: "string", description: "Optional JSON string or description of the request/response contract (payload)." }
|
|
122
123
|
},
|
|
123
124
|
required: ["path", "method", "description"]
|
|
124
125
|
}
|
|
@@ -142,17 +143,6 @@ function createMcpServer(apiKey, personalKey) {
|
|
|
142
143
|
type: "object",
|
|
143
144
|
properties: {},
|
|
144
145
|
},
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
name: "get_figma_preview",
|
|
148
|
-
description: "Fetches design metadata and image previews from a Figma URL using the project's centralized access token. Use this to understand the UX requirements without needing local Figma configuration. The Figma token must be configured in the ViewGate dashboard under Settings > Integrations.",
|
|
149
|
-
inputSchema: {
|
|
150
|
-
type: "object",
|
|
151
|
-
properties: {
|
|
152
|
-
url: { type: "string", description: "The Figma design or file URL" }
|
|
153
|
-
},
|
|
154
|
-
required: ["url"]
|
|
155
|
-
}
|
|
156
146
|
}
|
|
157
147
|
],
|
|
158
148
|
};
|
|
@@ -227,18 +217,18 @@ function createMcpServer(apiKey, personalKey) {
|
|
|
227
217
|
tag: ann.reference?.tag,
|
|
228
218
|
figmaReference: ann.figmaReference,
|
|
229
219
|
backendEndpoints: ann.backendEndpoints || [ann.backendEndpoint].filter(Boolean),
|
|
230
|
-
_ia_fix_instruction: `### 🎨 DESIGN CONTEXT (Figma)
|
|
231
|
-
${ann.figmaReference ? `A design reference is available: ${
|
|
232
|
-
|
|
233
|
-
### 🔬 SURGICAL FIX PROTOCOL (Language: ${data.preferredLanguage || 'en'})
|
|
234
|
-
1. **PRIMARY**: Search for \`data-vg-id="${ann.reference?.vgId}"\`.
|
|
235
|
-
2. **SECONDARY**: Check \`${file}\` L${line} (Fiber Source).
|
|
236
|
-
3. **TERTIARY**: Match Tag(\`${ann.reference?.tag}\`) + Role(\`${ann.reference?.fingerprint?.role}\`) + Text("${ann.reference?.text?.slice(0, 30)}").
|
|
237
|
-
4. **VALIDATE**: Confirm parent context matches \`${ann.reference?.parentContext?.slice(0, 50).replace(/`/g, "'")}...\`.
|
|
238
|
-
|
|
239
|
-
IMPORTANT: All your analysis and implementation comments MUST BE IN ${data.preferredLanguage === 'es' ? 'SPANISH' : 'ENGLISH'}.
|
|
240
|
-
|
|
241
|
-
Confidence: [vgId: ${ann.reference?.confidence?.vgId || 0}, Fiber: ${ann.reference?.confidence?.fiber || 0}, Fingerprint: ${ann.reference?.confidence?.fingerprint || 0}]
|
|
220
|
+
_ia_fix_instruction: `### 🎨 DESIGN CONTEXT (Figma)
|
|
221
|
+
${ann.figmaReference ? `A design reference is available: ${ann.figmaReference}. Use the Figma link to understand the UX requirements.` : 'No explicit figma design linked.'}
|
|
222
|
+
|
|
223
|
+
### 🔬 SURGICAL FIX PROTOCOL (Language: ${data.preferredLanguage || 'en'})
|
|
224
|
+
1. **PRIMARY**: Search for \`data-vg-id="${ann.reference?.vgId}"\`.
|
|
225
|
+
2. **SECONDARY**: Check \`${file}\` L${line} (Fiber Source).
|
|
226
|
+
3. **TERTIARY**: Match Tag(\`${ann.reference?.tag}\`) + Role(\`${ann.reference?.fingerprint?.role}\`) + Text("${ann.reference?.text?.slice(0, 30)}").
|
|
227
|
+
4. **VALIDATE**: Confirm parent context matches \`${ann.reference?.parentContext?.slice(0, 50).replace(/`/g, "'")}...\`.
|
|
228
|
+
|
|
229
|
+
IMPORTANT: All your analysis and implementation comments MUST BE IN ${data.preferredLanguage === 'es' ? 'SPANISH' : 'ENGLISH'}.
|
|
230
|
+
|
|
231
|
+
Confidence: [vgId: ${ann.reference?.confidence?.vgId || 0}, Fiber: ${ann.reference?.confidence?.fiber || 0}, Fingerprint: ${ann.reference?.confidence?.fingerprint || 0}]
|
|
242
232
|
Instruction: ${ann.message}`
|
|
243
233
|
};
|
|
244
234
|
});
|
|
@@ -405,108 +395,6 @@ Instruction: ${ann.message}`
|
|
|
405
395
|
};
|
|
406
396
|
}
|
|
407
397
|
}
|
|
408
|
-
case "get_figma_preview": {
|
|
409
|
-
try {
|
|
410
|
-
const args = request.params.arguments;
|
|
411
|
-
const url = args.url;
|
|
412
|
-
// 1. Get Figma Token from Backend Config
|
|
413
|
-
const configResponse = await fetch(`${BACKEND_URL}/api/mcp/config`, {
|
|
414
|
-
headers: {
|
|
415
|
-
'x-api-key': apiKey,
|
|
416
|
-
...(personalKey ? { 'x-personal-key': personalKey } : {})
|
|
417
|
-
}
|
|
418
|
-
});
|
|
419
|
-
if (!configResponse.ok) {
|
|
420
|
-
throw new Error(`Failed to fetch project configuration: ${configResponse.status}`);
|
|
421
|
-
}
|
|
422
|
-
const configData = (await configResponse.json());
|
|
423
|
-
const figmaToken = configData?.settings?.figmaToken;
|
|
424
|
-
if (!figmaToken) {
|
|
425
|
-
return {
|
|
426
|
-
content: [{
|
|
427
|
-
type: "text",
|
|
428
|
-
text: "Figma integration is not fully configured. Please add a Figma Access Token in the ViewGate Dashboard (Settings > Integrations)."
|
|
429
|
-
}],
|
|
430
|
-
isError: true
|
|
431
|
-
};
|
|
432
|
-
}
|
|
433
|
-
// 2. Parse Figma URL
|
|
434
|
-
let fileKey = "";
|
|
435
|
-
try {
|
|
436
|
-
if (url.includes("/file/") || url.includes("/design/")) {
|
|
437
|
-
const parts = url.split(/\/(?:file|design)\//)[1].split("/");
|
|
438
|
-
fileKey = parts[0].split(/[?#]/)[0];
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
catch (e) {
|
|
442
|
-
throw new Error("Could not parse Figma File Key from URL.");
|
|
443
|
-
}
|
|
444
|
-
if (!fileKey) {
|
|
445
|
-
throw new Error("Invalid Figma URL format. File key not found.");
|
|
446
|
-
}
|
|
447
|
-
// Extract node-id if present
|
|
448
|
-
let nodeId = "";
|
|
449
|
-
try {
|
|
450
|
-
const urlObj = new URL(url.replace(/#/g, "?")); // Handle hash-based node-id
|
|
451
|
-
nodeId = urlObj.searchParams.get("node-id") || urlObj.searchParams.get("m") || "";
|
|
452
|
-
if (!nodeId && url.includes("node-id=")) {
|
|
453
|
-
nodeId = url.split("node-id=")[1].split("&")[0];
|
|
454
|
-
}
|
|
455
|
-
// Normalización y limpieza
|
|
456
|
-
if (nodeId) {
|
|
457
|
-
nodeId = decodeURIComponent(nodeId).replace(/-/g, ":");
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
catch (e) {
|
|
461
|
-
// Silent fail for nodeId, might just fetch full file
|
|
462
|
-
}
|
|
463
|
-
// 3. Fetch Data from Figma
|
|
464
|
-
// Use /nodes endpoint if nodeId exists, otherwise /files
|
|
465
|
-
const encodedNodeId = nodeId ? encodeURIComponent(nodeId) : "";
|
|
466
|
-
const figmaApiUrl = nodeId
|
|
467
|
-
? `https://api.figma.com/v1/files/${fileKey}/nodes?ids=${encodedNodeId}`
|
|
468
|
-
: `https://api.figma.com/v1/files/${fileKey}`;
|
|
469
|
-
const figmaResponse = await fetch(figmaApiUrl, {
|
|
470
|
-
headers: { 'X-Figma-Token': figmaToken }
|
|
471
|
-
});
|
|
472
|
-
if (!figmaResponse.ok) {
|
|
473
|
-
const errorText = await figmaResponse.text();
|
|
474
|
-
throw new Error(`Figma API returned ${figmaResponse.status}: ${errorText} (URL: ${figmaApiUrl})`);
|
|
475
|
-
}
|
|
476
|
-
const rawData = (await figmaResponse.json());
|
|
477
|
-
// 4. Optionally fetch image preview if a node is specified
|
|
478
|
-
let imageUrl = null;
|
|
479
|
-
if (nodeId) {
|
|
480
|
-
const encodedIds = encodeURIComponent(nodeId);
|
|
481
|
-
const imageResponse = await fetch(`https://api.figma.com/v1/images/${fileKey}?ids=${encodedIds}&scale=2&format=png`, {
|
|
482
|
-
headers: { 'X-Figma-Token': figmaToken }
|
|
483
|
-
});
|
|
484
|
-
if (imageResponse.ok) {
|
|
485
|
-
const imageData = await imageResponse.json();
|
|
486
|
-
imageUrl = imageData.images?.[nodeId];
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
const nodeInfo = nodeId ? rawData.nodes?.[nodeId] : null;
|
|
490
|
-
return {
|
|
491
|
-
content: [{
|
|
492
|
-
type: "text",
|
|
493
|
-
text: JSON.stringify({
|
|
494
|
-
fileName: rawData.name || "Unknown File",
|
|
495
|
-
lastModified: rawData.lastModified,
|
|
496
|
-
previewUrl: imageUrl,
|
|
497
|
-
nodeName: nodeInfo ? (nodeInfo.document?.name || 'Selected Component') : 'Full File',
|
|
498
|
-
note: "Design context successfully retrieved from Figma."
|
|
499
|
-
}, null, 2)
|
|
500
|
-
}]
|
|
501
|
-
};
|
|
502
|
-
}
|
|
503
|
-
catch (error) {
|
|
504
|
-
return {
|
|
505
|
-
content: [{ type: "text", text: `Error fetching Figma preview: ${error.message}` }],
|
|
506
|
-
isError: true
|
|
507
|
-
};
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
398
|
default:
|
|
511
399
|
throw new Error("Unknown tool");
|
|
512
400
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "viewgate-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.20",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"bin": {
|
|
6
6
|
"viewgate-mcp": "./dist/index.js"
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"license": "ISC",
|
|
22
22
|
"description": "",
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
24
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
25
25
|
"cors": "^2.8.6",
|
|
26
26
|
"dotenv": "^17.3.1",
|
|
27
27
|
"express": "^5.2.1",
|