analyze_figma_file
Extract and analyze Figma file structures to identify node hierarchies and relationships. Input a Figma URL and optional depth to retrieve organized data for design insights.
Instructions
Analyze a Figma file structure to understand its nodes and hierarchy
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| depth | No | Optional depth parameter to limit the node tree depth | |
| figmaUrl | Yes | The URL of the Figma file to analyze |
Input Schema (JSON Schema)
{
"properties": {
"depth": {
"description": "Optional depth parameter to limit the node tree depth",
"type": "number"
},
"figmaUrl": {
"description": "The URL of the Figma file to analyze",
"type": "string"
}
},
"required": [
"figmaUrl"
],
"type": "object"
}
Implementation Reference
- src/index.ts:100-161 (handler)The main handler function that orchestrates the analysis: extracts Figma IDs, generates the node tree using FigmaTreeGenerator, formats the result or error as CallToolResult.async function doAnalyzeFigmaFile(figmaUrl: string, depth?: number): Promise<CallToolResult> { try { // Get Figma API Key const figmaApiKey = process.env.FIGMA_API_KEY; if (!figmaApiKey) { throw new Error('FIGMA_API_KEY not configured'); } // Extract file ID and node ID from URL const { fileId, nodeId } = extractFigmaIds(figmaUrl); if (!fileId) { throw new Error('Could not extract file ID from URL'); } if (!nodeId) { throw new Error('No node ID specified in URL'); } // Generate the node tree const treeGenerator = new FigmaTreeGenerator(figmaApiKey); const tree = await treeGenerator.generateNodeTree(fileId, nodeId, depth); // Return the result return { content: [ { type: 'text', text: `Successfully analyzed Figma file: ${figmaUrl}`, }, { type: 'text', text: `File ID: ${fileId}`, }, { type: 'text', text: `Node ID: ${nodeId}`, }, { type: 'text', text: 'Node Tree Structure:', }, { type: 'text', text: JSON.stringify(tree, null, 2), }, ], }; } catch (error) { console.error('Error analyzing Figma file:', error); // Return error as text content instead of throwing return { content: [ { type: 'text', text: `Error analyzing Figma file: ${error instanceof Error ? error.message : 'Unknown error'}` } ] }; } }
- src/index.ts:49-66 (schema)Tool definition including name, description, and input schema for validation.const ANALYZE_FIGMA_FILE: Tool = { name: 'analyze_figma_file', description: 'Analyze a Figma file structure to understand its nodes and hierarchy', inputSchema: { type: 'object', properties: { figmaUrl: { type: 'string', description: 'The URL of the Figma file to analyze', }, depth: { type: 'number', description: 'Optional depth parameter to limit the node tree depth', }, }, required: ['figmaUrl'], }, };
- src/index.ts:69-71 (registration)Registers the tool in the ListToolsRequestSchema handler.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ANALYZE_FIGMA_FILE], }));
- src/index.ts:75-78 (registration)Dispatches tool calls to the handler in CallToolRequestSchema.if (request.params.name === 'analyze_figma_file') { const input = request.params.arguments as { figmaUrl: string; depth?: number }; return doAnalyzeFigmaFile(input.figmaUrl, input.depth); }
- src/figma-api.ts:53-118 (helper)Core helper class for generating and processing the Figma node tree via API, used by the main handler.export class FigmaTreeGenerator { private readonly apiKey: string; private readonly baseUrl = 'https://api.figma.com/v1'; constructor(apiKey: string) { this.apiKey = apiKey; } async generateNodeTree(fileId: string, nodeId: string, depth?: number): Promise<FigmaNode> { try { // Construct URL with optional depth parameter let url = `${this.baseUrl}/files/${fileId}/nodes?ids=${nodeId}`; if (depth !== undefined) { url += `&depth=${depth}`; } // Make request to Figma API const response = await axios.get<FigmaNodesResponse>( url, { headers: { 'X-Figma-Token': this.apiKey } } ); // Check if the node exists in the response if (!response.data.nodes[nodeId]) { throw new Error(`Node ${nodeId} not found in file ${fileId}`); } // Extract the document from the response const nodeData = response.data.nodes[nodeId].document; // Process the node tree return this.processNode(nodeData); } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; throw new Error(`Failed to fetch Figma node tree: ${errorMessage}`); } } private processNode(node: FigmaNode): FigmaNode { // Create a new node object to avoid mutating the original const processedNode: FigmaNode = { id: node.id, name: node.name, type: node.type }; // If this is an INSTANCE node, we stop traversal here // By not adding children property, we indicate this is a terminal node if (node.type === 'INSTANCE') { return processedNode; } // If node has children, process them recursively if (node.children && node.children.length > 0) { processedNode.children = node.children.map(child => this.processNode(child)); } else { processedNode.children = []; } return processedNode; } }
- src/figma-api.ts:21-50 (helper)Utility function to parse Figma file and node IDs from the input URL.export function extractFigmaIds(figmaUrl: string): { fileId: string, nodeId: string | null } { try { const url = new URL(figmaUrl); // Extract the file ID from the URL path const pathParts = url.pathname.split('/'); let fileIdIndex = -1; // Look for file/design/proto in the URL path for (let i = 0; i < pathParts.length; i++) { if (pathParts[i] === 'file' || pathParts[i] === 'design' || pathParts[i] === 'proto') { fileIdIndex = i + 1; break; } } if (fileIdIndex === -1 || fileIdIndex >= pathParts.length) { throw new Error('Invalid Figma URL format: missing file/design/proto segment'); } const fileId = pathParts[fileIdIndex]; // Extract node ID from query parameters if present const nodeId = url.searchParams.get('node-id') || null; return { fileId, nodeId }; } catch (error) { throw new Error('Invalid Figma URL format'); } }