Skip to main content
Glama

Claude Talk to Figma MCP

by arinspunk
document-tools.ts10.2 kB
import { z } from "zod"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { sendCommandToFigma, joinChannel } from "../utils/websocket.js"; import { filterFigmaNode } from "../utils/figma-helpers.js"; /** * Register document-related tools to the MCP server * @param server - The MCP server instance */ export function registerDocumentTools(server: McpServer): void { // Document Info Tool server.tool( "get_document_info", "Get detailed information about the current Figma document", {}, async () => { try { const result = await sendCommandToFigma("get_document_info"); return { content: [ { type: "text", text: JSON.stringify(result) } ] }; } catch (error) { return { content: [ { type: "text", text: `Error getting document info: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); // Selection Tool server.tool( "get_selection", "Get information about the current selection in Figma", {}, async () => { try { const result = await sendCommandToFigma("get_selection"); return { content: [ { type: "text", text: JSON.stringify(result) } ] }; } catch (error) { return { content: [ { type: "text", text: `Error getting selection: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); // Node Info Tool server.tool( "get_node_info", "Get detailed information about a specific node in Figma", { nodeId: z.string().describe("The ID of the node to get information about"), }, async ({ nodeId }) => { try { const result = await sendCommandToFigma("get_node_info", { nodeId }); return { content: [ { type: "text", text: JSON.stringify(filterFigmaNode(result)) } ] }; } catch (error) { return { content: [ { type: "text", text: `Error getting node info: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); // Nodes Info Tool server.tool( "get_nodes_info", "Get detailed information about multiple nodes in Figma", { nodeIds: z.array(z.string()).describe("Array of node IDs to get information about") }, async ({ nodeIds }) => { try { const results = await Promise.all( nodeIds.map(async (nodeId) => { const result = await sendCommandToFigma('get_node_info', { nodeId }); return { nodeId, info: result }; }) ); return { content: [ { type: "text", text: JSON.stringify(results.map((result) => filterFigmaNode(result.info))) } ] }; } catch (error) { return { content: [ { type: "text", text: `Error getting nodes info: ${error instanceof Error ? error.message : String(error)}` } ] }; } } ); // Get Styles Tool server.tool( "get_styles", "Get all styles from the current Figma document", {}, async () => { try { const result = await sendCommandToFigma("get_styles"); return { content: [ { type: "text", text: JSON.stringify(result) } ] }; } catch (error) { return { content: [ { type: "text", text: `Error getting styles: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); // Get Local Components Tool server.tool( "get_local_components", "Get all local components from the Figma document", {}, async () => { try { const result = await sendCommandToFigma("get_local_components"); return { content: [ { type: "text", text: JSON.stringify(result) } ] }; } catch (error) { return { content: [ { type: "text", text: `Error getting local components: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); // Get Remote Components Tool server.tool( "get_remote_components", "Get available components from team libraries in Figma", {}, async () => { try { const result = await sendCommandToFigma("get_remote_components"); return { content: [ { type: "text", text: JSON.stringify(result, null, 2) } ] }; } catch (error) { return { content: [ { type: "text", text: `Error getting remote components: ${error instanceof Error ? error.message : String(error)}` } ] }; } } ); // Text Node Scanning Tool server.tool( "scan_text_nodes", "Scan all text nodes in the selected Figma node", { nodeId: z.string().describe("ID of the node to scan"), }, async ({ nodeId }) => { try { // Initial response to indicate we're starting the process const initialStatus = { type: "text" as const, text: "Starting text node scanning. This may take a moment for large designs...", }; // Use the plugin's scan_text_nodes function with chunking flag const result = await sendCommandToFigma("scan_text_nodes", { nodeId, useChunking: true, // Enable chunking on the plugin side chunkSize: 10 // Process 10 nodes at a time }); // If the result indicates chunking was used, format the response accordingly if (result && typeof result === 'object' && 'chunks' in result) { const typedResult = result as { success: boolean, totalNodes: number, processedNodes: number, chunks: number, textNodes: Array<any> }; const summaryText = ` Scan completed: - Found ${typedResult.totalNodes} text nodes - Processed in ${typedResult.chunks} chunks `; return { content: [ initialStatus, { type: "text" as const, text: summaryText }, { type: "text" as const, text: JSON.stringify(typedResult.textNodes, null, 2) } ], }; } // If chunking wasn't used or wasn't reported in the result format, return the result as is return { content: [ initialStatus, { type: "text", text: JSON.stringify(result, null, 2), }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error scanning text nodes: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); // Join Channel Tool server.tool( "join_channel", "Join a specific channel to communicate with Figma", { channel: z.string().describe("The name of the channel to join").default(""), }, async ({ channel }) => { try { if (!channel) { // If no channel provided, ask the user for input return { content: [ { type: "text", text: "Please provide a channel name to join:", }, ], followUp: { tool: "join_channel", description: "Join the specified channel", }, }; } // Use joinChannel instead of sendCommandToFigma to ensure currentChannel is updated await joinChannel(channel); return { content: [ { type: "text", text: `Successfully joined channel: ${channel}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error joining channel: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); // Export Node as Image Tool server.tool( "export_node_as_image", "Export a node as an image from Figma", { nodeId: z.string().describe("The ID of the node to export"), format: z .enum(["PNG", "JPG", "SVG", "PDF"]) .optional() .describe("Export format"), scale: z.number().positive().optional().describe("Export scale"), }, async ({ nodeId, format, scale }) => { try { const result = await sendCommandToFigma("export_node_as_image", { nodeId, format: format || "PNG", scale: scale || 1, }); const typedResult = result as { imageData: string; mimeType: string }; return { content: [ { type: "image", data: typedResult.imageData, mimeType: typedResult.mimeType || "image/png", }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error exporting node as image: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } ); }

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/arinspunk/claude-talk-to-figma-mcp'

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