Skip to main content
Glama

convert-figma-to-code

Converts a Figma node URL to a code block by fetching the node and its rendered image from the Figma API.

Instructions

Fetches a Figma node and its rendered image from the Figma API and converts it to a code block. Requires FIGMA_ACCESS_TOKEN environment variable to be set.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
figmaNodeUrlYesThe URL of the Figma node (e.g., https://www.figma.com/design/fileKey/fileName?node-id=123-456)

Implementation Reference

  • src/index.ts:675-1049 (registration)
    The 'convert-figma-to-code' tool is registered using server.tool() on line 675. This is where the tool name, description, Zod schema (figmaNodeUrl), and handler are all defined together.
        server.tool(
          'convert-figma-to-code',
          'Fetches a Figma node and its rendered image from the Figma API and converts it to a code block. Requires FIGMA_ACCESS_TOKEN environment variable to be set.',
          {
            figmaNodeUrl: z.string().describe('The URL of the Figma node (e.g., https://www.figma.com/design/fileKey/fileName?node-id=123-456)'),
          },
          async ({ figmaNodeUrl }): Promise<CallToolResult> => {
            try {
              // Get Figma access token from environment variables
              const figmaAccessToken = process.env.FIGMA_ACCESS_TOKEN;
              
              if (!figmaAccessToken) {
                return {
                  content: [
                    {
                      type: 'text',
                      text: `Error: FIGMA_ACCESS_TOKEN environment variable is not set.
    
    To use this tool, you need to:
    1. Generate a Personal Access Token from Figma:
       - Go to Figma > Settings > Account > Personal access tokens
       - Generate a new token
    2. Set the FIGMA_ACCESS_TOKEN environment variable with your token
    
    Example for your MCP config:
    {
      "env": {
        "FIGMA_ACCESS_TOKEN": "your-personal-access-token"
      }
    }`,
                    },
                  ],
                };
              }
    
              // Parse Figma URL to extract fileKey and nodeId
              // URL formats:
              // https://www.figma.com/file/{fileKey}/{fileName}?node-id={nodeId}
              // https://www.figma.com/design/{fileKey}/{fileName}?node-id={nodeId}
              const urlPattern = /figma\.com\/(file|design)\/([a-zA-Z0-9]+)(?:\/[^?]*)?(?:\?.*node-id=([^&]+))?/;
              const match = figmaNodeUrl.match(urlPattern);
    
              if (!match) {
                return {
                  content: [
                    {
                      type: 'text',
                      text: `Error: Invalid Figma URL format.
    
    Expected formats:
    - https://www.figma.com/file/{fileKey}/{fileName}?node-id={nodeId}
    - https://www.figma.com/design/{fileKey}/{fileName}?node-id={nodeId}
    
    Provided URL: ${figmaNodeUrl}`,
                    },
                  ],
                };
              }
    
              const fileKey = match[2];
              const nodeId = match[3] ? decodeURIComponent(match[3]) : null;
    
              if (!nodeId) {
                return {
                  content: [
                    {
                      type: 'text',
                      text: `Error: No node-id found in the Figma URL.
    
    Please make sure your URL includes a node-id parameter.
    Example: https://www.figma.com/design/${fileKey}/FileName?node-id=123-456
    
    Provided URL: ${figmaNodeUrl}`,
                    },
                  ],
                };
              }
    
              // API headers
              const headers = {
                'X-Figma-Token': figmaAccessToken,
              };
    
              // Fetch node data
              const nodeApiUrl = `https://api.figma.com/v1/files/${fileKey}/nodes?ids=${encodeURIComponent(nodeId)}`;
              const nodeResponse = await fetch(nodeApiUrl, { headers });
    
              if (!nodeResponse.ok) {
                const errorText = await nodeResponse.text();
                return {
                  content: [
                    {
                      type: 'text',
                      text: `Error fetching Figma node data:
    Status: ${nodeResponse.status} ${nodeResponse.statusText}
    Response: ${errorText}
    
    API URL: ${nodeApiUrl}`,
                    },
                  ],
                };
              }
    
              const nodeData = await nodeResponse.json();
    
              // Fetch node image
              const imageApiUrl = `https://api.figma.com/v1/images/${fileKey}?ids=${encodeURIComponent(nodeId)}&scale=2`;
              const imageResponse = await fetch(imageApiUrl, { headers });
    
              if (!imageResponse.ok) {
                const errorText = await imageResponse.text();
                return {
                  content: [
                    {
                      type: 'text',
                      text: `Error fetching Figma node image:
    Status: ${imageResponse.status} ${imageResponse.statusText}
    Response: ${errorText}
    
    API URL: ${imageApiUrl}
    Node data was retrieved successfully.`,
                    },
                  ],
                };
              }
    
              const imageData = await imageResponse.json();
    
              // Extract the image URL from the response
              const imageUrl = imageData.images?.[nodeId] || imageData.images?.[Object.keys(imageData.images)[0]] || null;
    
              // Helper function to simplify Figma node data - extracts only essential info for code conversion
              const simplifyNode = (node: any): any => {
                if (!node) return null;
                
                const simplified: any = {
                  type: node.type,
                  name: node.name,
                };
    
                // Add dimensions if available
                if (node.absoluteBoundingBox) {
                  simplified.size = {
                    width: Math.round(node.absoluteBoundingBox.width),
                    height: Math.round(node.absoluteBoundingBox.height),
                  };
                }
    
                // Add layout info for frames
                if (node.layoutMode) {
                  simplified.layout = {
                    mode: node.layoutMode, // HORIZONTAL, VERTICAL, NONE
                    padding: node.paddingLeft || node.paddingTop ? {
                      top: node.paddingTop,
                      right: node.paddingRight,
                      bottom: node.paddingBottom,
                      left: node.paddingLeft,
                    } : undefined,
                    gap: node.itemSpacing,
                    align: node.primaryAxisAlignItems,
                    justify: node.counterAxisAlignItems,
                  };
                }
    
                // Add corner radius
                if (node.cornerRadius) {
                  simplified.borderRadius = node.cornerRadius;
                } else if (node.rectangleCornerRadii) {
                  simplified.borderRadius = node.rectangleCornerRadii;
                }
    
                // Add fills (background colors)
                if (node.fills && node.fills.length > 0) {
                  simplified.fills = node.fills
                    .filter((fill: any) => fill.visible !== false)
                    .map((fill: any) => ({
                      type: fill.type,
                      color: fill.color ? {
                        r: Math.round(fill.color.r * 255),
                        g: Math.round(fill.color.g * 255),
                        b: Math.round(fill.color.b * 255),
                        a: fill.color.a !== undefined ? Math.round(fill.color.a * 100) / 100 : 1,
                      } : undefined,
                      opacity: fill.opacity,
                    }));
                }
    
                // Add strokes (borders)
                if (node.strokes && node.strokes.length > 0) {
                  simplified.strokes = node.strokes
                    .filter((stroke: any) => stroke.visible !== false)
                    .map((stroke: any) => ({
                      type: stroke.type,
                      color: stroke.color ? {
                        r: Math.round(stroke.color.r * 255),
                        g: Math.round(stroke.color.g * 255),
                        b: Math.round(stroke.color.b * 255),
                      } : undefined,
                    }));
                  if (node.strokeWeight) {
                    simplified.strokeWeight = node.strokeWeight;
                  }
                }
    
                // Add effects (shadows, blur)
                if (node.effects && node.effects.length > 0) {
                  simplified.effects = node.effects
                    .filter((effect: any) => effect.visible !== false)
                    .map((effect: any) => ({
                      type: effect.type,
                      radius: effect.radius,
                      offset: effect.offset,
                      color: effect.color ? {
                        r: Math.round(effect.color.r * 255),
                        g: Math.round(effect.color.g * 255),
                        b: Math.round(effect.color.b * 255),
                        a: Math.round(effect.color.a * 100) / 100,
                      } : undefined,
                    }));
                }
    
                // Add text-specific properties
                if (node.type === 'TEXT') {
                  simplified.text = node.characters;
                  if (node.style) {
                    simplified.textStyle = {
                      fontFamily: node.style.fontFamily,
                      fontWeight: node.style.fontWeight,
                      fontSize: node.style.fontSize,
                      lineHeight: node.style.lineHeightPx,
                      letterSpacing: node.style.letterSpacing,
                      textAlign: node.style.textAlignHorizontal,
                    };
                  }
                }
    
                // Recursively process children
                if (node.children && node.children.length > 0) {
                  simplified.children = node.children.map(simplifyNode).filter(Boolean);
                }
    
                return simplified;
              };
    
              // Simplify the node data
              const simplifiedNodeData = nodeData.nodes ? 
                Object.keys(nodeData.nodes).reduce((acc: any, key: string) => {
                  const node = nodeData.nodes[key];
                  acc[key] = {
                    document: simplifyNode(node.document),
                    components: node.components ? Object.keys(node.components).length + ' components' : undefined,
                    styles: node.styles ? Object.keys(node.styles).length + ' styles' : undefined,
                  };
                  return acc;
                }, {}) 
                : simplifyNode(nodeData);
    
              // Return combined result with AI instructions
              return {
                content: [
                  {
                    type: 'text',
                    text: `# Figma to Code Conversion Task
    
    ## Instructions for AI
    
    You have received a Figma design that needs to be converted to code. Follow these steps:
    
    ### Step 1: Analyze the Design
    Look at the rendered image below and the node structure data to understand:
    - The layout and component hierarchy
    - Colors, typography, and spacing used
    - Interactive elements (buttons, inputs, links, etc.)
    - Component patterns that match Flowbite components
    
    ### Step 2: Use Flowbite MCP Resources
    Before writing code, fetch the relevant Flowbite component documentation using the MCP resources. 
    
    ### Step 3: Write the Code
    Generate clean, semantic HTML with Tailwind CSS classes following these guidelines:
    
    1. **Use Flowbite Components**: Match the Figma design to Flowbite components whenever possible
    2. **Flowbite variables** - Use Flowbite variable utility classes when possible (e.g. text-brand, rounded-base, etc.)
    3. **Tailwind CSS Classes**: Use Tailwind utility classes for styling
    4. **Responsive Design**: Include responsive breakpoints (sm:, md:, lg:, xl:)
    5. **Semantic HTML**: Use proper HTML5 semantic elements
    6. **Accessibility**: Include ARIA attributes and proper alt texts
    7. **Match Colors**: Use Flowbite variables and secondly Tailwind color classes that best match the Figma design colors
    8. **Match Spacing**: Use Tailwind spacing utilities (p-*, m-*, gap-*) to match the design
    
    ### Step 4: Output Format - IMPORTANT
    
    **⚠️ ONLY output the component code block - DO NOT include:**
    - \`<!DOCTYPE html>\`
    - \`<html>\`, \`</html>\` tags
    - \`<head>\`, \`</head>\` tags
    - \`<body>\`, \`</body>\` tags
    - \`<link>\` tags (CSS imports)
    - \`<script>\` tags (JS imports)
    - Any meta tags or document structure
    - ':dark' variant classes unless explicitly requested
    
    **✅ DO output:**
    - Only the component HTML markup itself
    - The actual UI component code that would go inside a \`<body>\` tag
    - Clean, well-formatted code block with proper indentation
    - Just the reusable component/section code
    - When possible use the "brand" variables from Flowbite instead of hardcoded colors from Tailwind CSS
    
    **Example of what to output:**
    \`\`\`html
    <div class="bg-neutral-primary-soft block max-w-sm p-6 border border-default rounded-base shadow-xs">
        <h5 class="mb-3 text-2xl font-semibold tracking-tight text-heading leading-8">Noteworthy technology acquisitions 2021</h5>
        <p class="text-body mb-6">Here are the biggest technology acquisitions of 2025 so far, in reverse chronological order.</p>
        <a href="#" class="inline-flex items-center text-white bg-brand box-border border border-transparent hover:bg-brand-strong focus:ring-4 focus:ring-brand-medium shadow-xs font-medium leading-5 rounded-base text-sm px-4 py-2.5 focus:outline-none">
            Read more
            <svg class="w-4 h-4 ms-1.5 rtl:rotate-180 -me-0.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 12H5m14 0-4 4m4-4-4-4"/></svg>
        </a>
    </div>
    \`\`\`
    
    ---
    
    ## Figma Design Data
    
    ### File Information
    - **File Key**: ${fileKey}
    - **Node ID**: ${nodeId}
    - **Source URL**: ${figmaNodeUrl}
    
    ### Rendered Design Image
    ${imageUrl ? `
    
    <img src="${imageUrl}">
    
    **Direct Image URL**: ${imageUrl}` : '⚠️ No image URL available - analyze the node data structure below'}
    
    ### Node Structure Data (Simplified)
    The following JSON contains the essential Figma node structure for code conversion:
    
    \`\`\`json
    ${JSON.stringify(simplifiedNodeData, null, 2)}
    \`\`\`
    
    ---
    
    ## Now Convert This Design
    
    Based on the image and node data above:
    1. Identify the UI components visible in the design
    2. Fetch the relevant Flowbite component documentation from the MCP resources
    3. Generate ONLY the component HTML/Tailwind CSS code (no document wrapper, no \`<html>\`, \`<head>\`, \`<body>\`, \`<link>\`, or \`<script>\` tags)
    4. Ensure the code is production-ready with proper responsiveness and accessibility`,
                  },
                ],
              };
    
            } catch (error) {
              console.error(`Error fetching Figma node: ${error}`);
              return {
                content: [
                  {
                    type: 'text',
                    text: `Error fetching Figma node: ${error instanceof Error ? error.message : String(error)}
    
    Please check:
    1. Your FIGMA_ACCESS_TOKEN is valid
    2. The Figma URL is correct
    3. You have access to the Figma file`,
                  },
                ],
              };
            }
          }
        );
  • The handler function starting at line 681 executes the tool logic: parses the Figma URL, fetches node data and image from Figma API, simplifies the node structure, and returns a comprehensive prompt instructing an AI to convert the design to HTML/Tailwind CSS code using Flowbite components.
          async ({ figmaNodeUrl }): Promise<CallToolResult> => {
            try {
              // Get Figma access token from environment variables
              const figmaAccessToken = process.env.FIGMA_ACCESS_TOKEN;
              
              if (!figmaAccessToken) {
                return {
                  content: [
                    {
                      type: 'text',
                      text: `Error: FIGMA_ACCESS_TOKEN environment variable is not set.
    
    To use this tool, you need to:
    1. Generate a Personal Access Token from Figma:
       - Go to Figma > Settings > Account > Personal access tokens
       - Generate a new token
    2. Set the FIGMA_ACCESS_TOKEN environment variable with your token
    
    Example for your MCP config:
    {
      "env": {
        "FIGMA_ACCESS_TOKEN": "your-personal-access-token"
      }
    }`,
                    },
                  ],
                };
              }
    
              // Parse Figma URL to extract fileKey and nodeId
              // URL formats:
              // https://www.figma.com/file/{fileKey}/{fileName}?node-id={nodeId}
              // https://www.figma.com/design/{fileKey}/{fileName}?node-id={nodeId}
              const urlPattern = /figma\.com\/(file|design)\/([a-zA-Z0-9]+)(?:\/[^?]*)?(?:\?.*node-id=([^&]+))?/;
              const match = figmaNodeUrl.match(urlPattern);
    
              if (!match) {
                return {
                  content: [
                    {
                      type: 'text',
                      text: `Error: Invalid Figma URL format.
    
    Expected formats:
    - https://www.figma.com/file/{fileKey}/{fileName}?node-id={nodeId}
    - https://www.figma.com/design/{fileKey}/{fileName}?node-id={nodeId}
    
    Provided URL: ${figmaNodeUrl}`,
                    },
                  ],
                };
              }
    
              const fileKey = match[2];
              const nodeId = match[3] ? decodeURIComponent(match[3]) : null;
    
              if (!nodeId) {
                return {
                  content: [
                    {
                      type: 'text',
                      text: `Error: No node-id found in the Figma URL.
    
    Please make sure your URL includes a node-id parameter.
    Example: https://www.figma.com/design/${fileKey}/FileName?node-id=123-456
    
    Provided URL: ${figmaNodeUrl}`,
                    },
                  ],
                };
              }
    
              // API headers
              const headers = {
                'X-Figma-Token': figmaAccessToken,
              };
    
              // Fetch node data
              const nodeApiUrl = `https://api.figma.com/v1/files/${fileKey}/nodes?ids=${encodeURIComponent(nodeId)}`;
              const nodeResponse = await fetch(nodeApiUrl, { headers });
    
              if (!nodeResponse.ok) {
                const errorText = await nodeResponse.text();
                return {
                  content: [
                    {
                      type: 'text',
                      text: `Error fetching Figma node data:
    Status: ${nodeResponse.status} ${nodeResponse.statusText}
    Response: ${errorText}
    
    API URL: ${nodeApiUrl}`,
                    },
                  ],
                };
              }
    
              const nodeData = await nodeResponse.json();
    
              // Fetch node image
              const imageApiUrl = `https://api.figma.com/v1/images/${fileKey}?ids=${encodeURIComponent(nodeId)}&scale=2`;
              const imageResponse = await fetch(imageApiUrl, { headers });
    
              if (!imageResponse.ok) {
                const errorText = await imageResponse.text();
                return {
                  content: [
                    {
                      type: 'text',
                      text: `Error fetching Figma node image:
    Status: ${imageResponse.status} ${imageResponse.statusText}
    Response: ${errorText}
    
    API URL: ${imageApiUrl}
    Node data was retrieved successfully.`,
                    },
                  ],
                };
              }
    
              const imageData = await imageResponse.json();
    
              // Extract the image URL from the response
              const imageUrl = imageData.images?.[nodeId] || imageData.images?.[Object.keys(imageData.images)[0]] || null;
    
              // Helper function to simplify Figma node data - extracts only essential info for code conversion
              const simplifyNode = (node: any): any => {
                if (!node) return null;
                
                const simplified: any = {
                  type: node.type,
                  name: node.name,
                };
    
                // Add dimensions if available
                if (node.absoluteBoundingBox) {
                  simplified.size = {
                    width: Math.round(node.absoluteBoundingBox.width),
                    height: Math.round(node.absoluteBoundingBox.height),
                  };
                }
    
                // Add layout info for frames
                if (node.layoutMode) {
                  simplified.layout = {
                    mode: node.layoutMode, // HORIZONTAL, VERTICAL, NONE
                    padding: node.paddingLeft || node.paddingTop ? {
                      top: node.paddingTop,
                      right: node.paddingRight,
                      bottom: node.paddingBottom,
                      left: node.paddingLeft,
                    } : undefined,
                    gap: node.itemSpacing,
                    align: node.primaryAxisAlignItems,
                    justify: node.counterAxisAlignItems,
                  };
                }
    
                // Add corner radius
                if (node.cornerRadius) {
                  simplified.borderRadius = node.cornerRadius;
                } else if (node.rectangleCornerRadii) {
                  simplified.borderRadius = node.rectangleCornerRadii;
                }
    
                // Add fills (background colors)
                if (node.fills && node.fills.length > 0) {
                  simplified.fills = node.fills
                    .filter((fill: any) => fill.visible !== false)
                    .map((fill: any) => ({
                      type: fill.type,
                      color: fill.color ? {
                        r: Math.round(fill.color.r * 255),
                        g: Math.round(fill.color.g * 255),
                        b: Math.round(fill.color.b * 255),
                        a: fill.color.a !== undefined ? Math.round(fill.color.a * 100) / 100 : 1,
                      } : undefined,
                      opacity: fill.opacity,
                    }));
                }
    
                // Add strokes (borders)
                if (node.strokes && node.strokes.length > 0) {
                  simplified.strokes = node.strokes
                    .filter((stroke: any) => stroke.visible !== false)
                    .map((stroke: any) => ({
                      type: stroke.type,
                      color: stroke.color ? {
                        r: Math.round(stroke.color.r * 255),
                        g: Math.round(stroke.color.g * 255),
                        b: Math.round(stroke.color.b * 255),
                      } : undefined,
                    }));
                  if (node.strokeWeight) {
                    simplified.strokeWeight = node.strokeWeight;
                  }
                }
    
                // Add effects (shadows, blur)
                if (node.effects && node.effects.length > 0) {
                  simplified.effects = node.effects
                    .filter((effect: any) => effect.visible !== false)
                    .map((effect: any) => ({
                      type: effect.type,
                      radius: effect.radius,
                      offset: effect.offset,
                      color: effect.color ? {
                        r: Math.round(effect.color.r * 255),
                        g: Math.round(effect.color.g * 255),
                        b: Math.round(effect.color.b * 255),
                        a: Math.round(effect.color.a * 100) / 100,
                      } : undefined,
                    }));
                }
    
                // Add text-specific properties
                if (node.type === 'TEXT') {
                  simplified.text = node.characters;
                  if (node.style) {
                    simplified.textStyle = {
                      fontFamily: node.style.fontFamily,
                      fontWeight: node.style.fontWeight,
                      fontSize: node.style.fontSize,
                      lineHeight: node.style.lineHeightPx,
                      letterSpacing: node.style.letterSpacing,
                      textAlign: node.style.textAlignHorizontal,
                    };
                  }
                }
    
                // Recursively process children
                if (node.children && node.children.length > 0) {
                  simplified.children = node.children.map(simplifyNode).filter(Boolean);
                }
    
                return simplified;
              };
    
              // Simplify the node data
              const simplifiedNodeData = nodeData.nodes ? 
                Object.keys(nodeData.nodes).reduce((acc: any, key: string) => {
                  const node = nodeData.nodes[key];
                  acc[key] = {
                    document: simplifyNode(node.document),
                    components: node.components ? Object.keys(node.components).length + ' components' : undefined,
                    styles: node.styles ? Object.keys(node.styles).length + ' styles' : undefined,
                  };
                  return acc;
                }, {}) 
                : simplifyNode(nodeData);
    
              // Return combined result with AI instructions
              return {
                content: [
                  {
                    type: 'text',
                    text: `# Figma to Code Conversion Task
    
    ## Instructions for AI
    
    You have received a Figma design that needs to be converted to code. Follow these steps:
    
    ### Step 1: Analyze the Design
    Look at the rendered image below and the node structure data to understand:
    - The layout and component hierarchy
    - Colors, typography, and spacing used
    - Interactive elements (buttons, inputs, links, etc.)
    - Component patterns that match Flowbite components
    
    ### Step 2: Use Flowbite MCP Resources
    Before writing code, fetch the relevant Flowbite component documentation using the MCP resources. 
    
    ### Step 3: Write the Code
    Generate clean, semantic HTML with Tailwind CSS classes following these guidelines:
    
    1. **Use Flowbite Components**: Match the Figma design to Flowbite components whenever possible
    2. **Flowbite variables** - Use Flowbite variable utility classes when possible (e.g. text-brand, rounded-base, etc.)
    3. **Tailwind CSS Classes**: Use Tailwind utility classes for styling
    4. **Responsive Design**: Include responsive breakpoints (sm:, md:, lg:, xl:)
    5. **Semantic HTML**: Use proper HTML5 semantic elements
    6. **Accessibility**: Include ARIA attributes and proper alt texts
    7. **Match Colors**: Use Flowbite variables and secondly Tailwind color classes that best match the Figma design colors
    8. **Match Spacing**: Use Tailwind spacing utilities (p-*, m-*, gap-*) to match the design
    
    ### Step 4: Output Format - IMPORTANT
    
    **⚠️ ONLY output the component code block - DO NOT include:**
    - \`<!DOCTYPE html>\`
    - \`<html>\`, \`</html>\` tags
    - \`<head>\`, \`</head>\` tags
    - \`<body>\`, \`</body>\` tags
    - \`<link>\` tags (CSS imports)
    - \`<script>\` tags (JS imports)
    - Any meta tags or document structure
    - ':dark' variant classes unless explicitly requested
    
    **✅ DO output:**
    - Only the component HTML markup itself
    - The actual UI component code that would go inside a \`<body>\` tag
    - Clean, well-formatted code block with proper indentation
    - Just the reusable component/section code
    - When possible use the "brand" variables from Flowbite instead of hardcoded colors from Tailwind CSS
    
    **Example of what to output:**
    \`\`\`html
    <div class="bg-neutral-primary-soft block max-w-sm p-6 border border-default rounded-base shadow-xs">
        <h5 class="mb-3 text-2xl font-semibold tracking-tight text-heading leading-8">Noteworthy technology acquisitions 2021</h5>
        <p class="text-body mb-6">Here are the biggest technology acquisitions of 2025 so far, in reverse chronological order.</p>
        <a href="#" class="inline-flex items-center text-white bg-brand box-border border border-transparent hover:bg-brand-strong focus:ring-4 focus:ring-brand-medium shadow-xs font-medium leading-5 rounded-base text-sm px-4 py-2.5 focus:outline-none">
            Read more
            <svg class="w-4 h-4 ms-1.5 rtl:rotate-180 -me-0.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 12H5m14 0-4 4m4-4-4-4"/></svg>
        </a>
    </div>
    \`\`\`
    
    ---
    
    ## Figma Design Data
    
    ### File Information
    - **File Key**: ${fileKey}
    - **Node ID**: ${nodeId}
    - **Source URL**: ${figmaNodeUrl}
    
    ### Rendered Design Image
    ${imageUrl ? `
    
    <img src="${imageUrl}">
    
    **Direct Image URL**: ${imageUrl}` : '⚠️ No image URL available - analyze the node data structure below'}
    
    ### Node Structure Data (Simplified)
    The following JSON contains the essential Figma node structure for code conversion:
    
    \`\`\`json
    ${JSON.stringify(simplifiedNodeData, null, 2)}
    \`\`\`
    
    ---
    
    ## Now Convert This Design
    
    Based on the image and node data above:
    1. Identify the UI components visible in the design
    2. Fetch the relevant Flowbite component documentation from the MCP resources
    3. Generate ONLY the component HTML/Tailwind CSS code (no document wrapper, no \`<html>\`, \`<head>\`, \`<body>\`, \`<link>\`, or \`<script>\` tags)
    4. Ensure the code is production-ready with proper responsiveness and accessibility`,
                  },
                ],
              };
    
            } catch (error) {
              console.error(`Error fetching Figma node: ${error}`);
              return {
                content: [
                  {
                    type: 'text',
                    text: `Error fetching Figma node: ${error instanceof Error ? error.message : String(error)}
    
    Please check:
    1. Your FIGMA_ACCESS_TOKEN is valid
    2. The Figma URL is correct
    3. You have access to the Figma file`,
                  },
                ],
              };
            }
          }
  • The input schema defines a single required parameter 'figmaNodeUrl' (a string describing the Figma node URL). It uses Zod for validation.
    {
      figmaNodeUrl: z.string().describe('The URL of the Figma node (e.g., https://www.figma.com/design/fileKey/fileName?node-id=123-456)'),
    },
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It discloses the authentication requirement (FIGMA_ACCESS_TOKEN) and implies a read-only operation by stating 'fetches' and 'converts'. It does not mention rate limits or mutability, but the behavioral transparency is adequate for the tool's simplicity.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences long, with the first sentence stating purpose and the second stating a prerequisite. No unnecessary words. Efficiently conveys essential information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the basic purpose and prerequisite, but lacks details about the output format (e.g., what type of code block). Since there is no output schema, the description should provide more completeness about the return value. It is somewhat incomplete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents the single parameter fully. The description adds no additional meaning beyond what the schema provides, earning a baseline score of 3.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'fetches' and 'converts', and the resource 'Figma node and its rendered image'. It distinguishes the tool from the sibling 'generate-theme' by its specific action. Purpose is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description mentions the prerequisite FIGMA_ACCESS_TOKEN, providing essential context. However, it does not specify when to use this tool over alternatives or when not to use it. No explicit usage guidelines beyond the token requirement.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/themesberg/flowbite-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server