viewgate-mcp 1.0.15 → 1.0.17

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.
Files changed (2) hide show
  1. package/dist/index.js +40 -16
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -228,7 +228,7 @@ function createMcpServer(apiKey, personalKey) {
228
228
  figmaReference: ann.figmaReference,
229
229
  backendEndpoints: ann.backendEndpoints || [ann.backendEndpoint].filter(Boolean),
230
230
  _ia_fix_instruction: `### 🎨 DESIGN CONTEXT (Figma)
231
- ${ann.figmaReference ? `A design reference is available: ${ann.figmaReference}. Use the 'get_figma_preview' tool to fetch design details and image previews before implementing.` : 'No explicit figma design linked.'}
231
+ ${ann.figmaReference ? `A design reference is available: ${Array.isArray(ann.figmaReference) ? (ann.figmaReference[0]?.link || ann.figmaReference[0]) : (ann.figmaReference.link || ann.figmaReference)}. Use the 'get_figma_preview' tool to fetch design details and image previews before implementing.` : 'No explicit figma design linked.'}
232
232
 
233
233
  ### 🔬 SURGICAL FIX PROTOCOL (Language: ${data.preferredLanguage || 'en'})
234
234
  1. **PRIMARY**: Search for \`data-vg-id="${ann.reference?.vgId}"\`.
@@ -431,31 +431,54 @@ Instruction: ${ann.message}`
431
431
  };
432
432
  }
433
433
  // 2. Parse Figma URL
434
- const fileKeyMatch = url.match(/(file|design)\/([a-zA-Z0-9]+)/);
435
- if (!fileKeyMatch) {
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) {
436
445
  throw new Error("Invalid Figma URL format. File key not found.");
437
446
  }
438
- const fileKey = fileKeyMatch[2];
439
447
  // Extract node-id if present
440
- const urlObj = new URL(url.replace(/#/g, '?')); // Handle hash-based node-id
441
- let nodeId = urlObj.searchParams.get('node-id') || urlObj.searchParams.get('m');
442
- if (!nodeId && url.includes('node-id=')) {
443
- nodeId = url.split('node-id=')[1].split('&')[0].replace('%3A', ':');
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
444
462
  }
445
463
  // 3. Fetch Data from Figma
446
- // First get file info
447
- const figmaApiUrl = `https://api.figma.com/v1/files/${fileKey}${nodeId ? `?ids=${nodeId}` : ''}`;
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}`;
448
469
  const figmaResponse = await fetch(figmaApiUrl, {
449
470
  headers: { 'X-Figma-Token': figmaToken }
450
471
  });
451
472
  if (!figmaResponse.ok) {
452
- throw new Error(`Figma API returned ${figmaResponse.status}: ${await figmaResponse.text()}`);
473
+ const errorText = await figmaResponse.text();
474
+ throw new Error(`Figma API returned ${figmaResponse.status}: ${errorText} (URL: ${figmaApiUrl})`);
453
475
  }
454
- const figmaData = (await figmaResponse.json());
476
+ const rawData = (await figmaResponse.json());
455
477
  // 4. Optionally fetch image preview if a node is specified
456
478
  let imageUrl = null;
457
479
  if (nodeId) {
458
- const imageResponse = await fetch(`https://api.figma.com/v1/images/${fileKey}?ids=${nodeId}&scale=2&format=png`, {
480
+ const encodedIds = encodeURIComponent(nodeId);
481
+ const imageResponse = await fetch(`https://api.figma.com/v1/images/${fileKey}?ids=${encodedIds}&scale=2&format=png`, {
459
482
  headers: { 'X-Figma-Token': figmaToken }
460
483
  });
461
484
  if (imageResponse.ok) {
@@ -463,14 +486,15 @@ Instruction: ${ann.message}`
463
486
  imageUrl = imageData.images?.[nodeId];
464
487
  }
465
488
  }
489
+ const nodeInfo = nodeId ? rawData.nodes?.[nodeId] : null;
466
490
  return {
467
491
  content: [{
468
492
  type: "text",
469
493
  text: JSON.stringify({
470
- fileName: figmaData.name,
471
- lastModified: figmaData.lastModified,
494
+ fileName: rawData.name || "Unknown File",
495
+ lastModified: rawData.lastModified,
472
496
  previewUrl: imageUrl,
473
- nodeName: nodeId ? (figmaData.nodes?.[nodeId]?.document?.name || 'Selected Component') : 'Full File',
497
+ nodeName: nodeInfo ? (nodeInfo.document?.name || 'Selected Component') : 'Full File',
474
498
  note: "Design context successfully retrieved from Figma."
475
499
  }, null, 2)
476
500
  }]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "viewgate-mcp",
3
- "version": "1.0.15",
3
+ "version": "1.0.17",
4
4
  "main": "dist/index.js",
5
5
  "bin": {
6
6
  "viewgate-mcp": "./dist/index.js"