Skip to main content
Glama

figma_to_code

Extract Figma node IDs and convert designs into HTML, React with CSS Modules, or React with Tailwind CSS using MCP server f2c-mcp-server to automate design-to-code workflows.

Instructions

Convert Figma designs into code. This tool extracts specified Figma nodes and transforms them into HTML, React with CSS Modules, or React with Tailwind CSS, facilitating automated design-to-code conversion.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
fileKeyYesThe unique identifier for a Figma file. Can be found in the Figma file URL, such as: https://www.figma.com/file/XXXXXXXXXXXX/, where XXXXXXXXXXXX is the fileKey.
formatNoThe output code format: 'html' for pure HTML and CSS code, 'react-cssmodules' for React components with CSS modules, 'react-tailwind' for React components using Tailwind CSS.html
idsYesList of Figma node IDs to convert, separated by commas. These can be obtained in Figma by selecting elements, right-clicking and choosing 'Copy/Paste as' → 'Copy ID'.
personalTokenNoYour Figma personal access token

Implementation Reference

  • Registers the 'figma_to_code' MCP tool with server, providing description, input schema using Zod, and the execution handler.
    export const registerF2cServer = (server: McpServer) => { // Register Figma to HTML conversion tool server.tool( 'figma_to_code', 'Transform Figma designs into production-ready code. This tool converts selected Figma nodes into HTML,enabling seamless design-to-code workflow.', { fileKey: z .string() .describe( 'The Figma file identifier found in the file URL (e.g., https://www.figma.com/file/XXXXXXXXXXXX/). Extract the XXXXXXXXXXXX portion as the fileKey.', ), ids: z .string() .describe( 'Comma-separated list of Figma node IDs for conversion. To obtain node IDs, select elements in Figma, right-click and select "Copy/Paste as" → "Copy ID".', ), format: z .enum(['html', 'react-cssmodules', 'react-tailwind']) .default('html') .describe( 'Specify the output format: "html" generates semantic HTML/CSS, "react-cssmodules" creates React components with scoped CSS modules, "react-tailwind" produces React components with utility-first Tailwind classes.', ), personalToken: z .string() .optional() .describe( 'Figma personal access token for API authentication.The parameters are not required when the tool is called.', ), localPath: z .string() .optional() .describe( 'Absolute path for image asset storage. Directory will be created if non-existent. Path must follow OS-specific format without special character escaping. When set, all static resources will be saved to the images directory under this path.', ), imgFormat: z .enum(['png', 'jpg', 'svg']) .default('png') .describe( 'Export format for image assets: "png" for lossless quality, "jpg" for compressed files, or "svg" for vector graphics.', ), scaleSize: z .number() .min(1) .max(4) .default(2) .describe( 'Image export scale factor (1-4). Higher values yield better quality at the cost of larger file sizes.', ), }, async (o): Promise<CallToolResult> => { downloader.setup({...o, format: 'html'}) try { // const cb: NodeToCodeFile[] = (await api.nodeToCode({...o, format: 'react-tailwind'})) || [] const cb: NodeToCodeFile[] = (await api.nodeToCode(o)) || [] await downloader.checkLocalAndDownload(cb) if (!cb) { return { content: [ { type: 'text', text: 'Failed to generate any code. Please check if the provided Figma node IDs are correct or if the nodes can be converted to code.', }, ], } } const files = Array.isArray(cb) ? cb : [cb] // Handle case when returned file array is empty if (files.length === 0) { return { content: [ { type: 'text', text: 'Conversion succeeded but no files were generated. Please check if the selected Figma nodes contain convertible content.', }, ], } } // Create file summary const summary = files.map((file, index) => `${index + 1}. ${file.path}`).join('\n') // If local path is specified, return save location information instead of detailed content if (o.localPath) { return { content: [ { type: 'text', text: `# Files Saved Locally ## Save Location ${o.localPath} ## Generated Files ${summary}. Convert the Tailwind to vanilla CSS if not already used in the codebase. Do not install any dependencies.`, }, ], } } // Create detailed file content (only when local path is not specified) const fileDetails = files .map((file, index) => { const fileExtension = file.path.split('.').pop() || '' return `## File ${index + 1}: ${file.path}\n\`\`\`${fileExtension}\n${file.content}\n\`\`\`` }) .join('\n\n') return { content: [ { type: 'text', text: `# Generated Files Summary\n${summary}\n\n# File Details\n${fileDetails}. Convert the Tailwind to vanilla CSS if not already used in the codebase. Do not install any dependencies.`, }, ], } } catch (error: any) { logger.error('Tool execution error:', error) return { content: [{type: 'text', text: `Error: ${error.message}`}], } } }, ) }
  • The tool execution handler. Sets up downloader, calls the F2C API via api.nodeToCode, downloads assets if localPath provided, formats response with file contents or paths.
    async (o): Promise<CallToolResult> => { downloader.setup({...o, format: 'html'}) try { // const cb: NodeToCodeFile[] = (await api.nodeToCode({...o, format: 'react-tailwind'})) || [] const cb: NodeToCodeFile[] = (await api.nodeToCode(o)) || [] await downloader.checkLocalAndDownload(cb) if (!cb) { return { content: [ { type: 'text', text: 'Failed to generate any code. Please check if the provided Figma node IDs are correct or if the nodes can be converted to code.', }, ], } } const files = Array.isArray(cb) ? cb : [cb] // Handle case when returned file array is empty if (files.length === 0) { return { content: [ { type: 'text', text: 'Conversion succeeded but no files were generated. Please check if the selected Figma nodes contain convertible content.', }, ], } } // Create file summary const summary = files.map((file, index) => `${index + 1}. ${file.path}`).join('\n') // If local path is specified, return save location information instead of detailed content if (o.localPath) { return { content: [ { type: 'text', text: `# Files Saved Locally ## Save Location ${o.localPath} ## Generated Files ${summary}. Convert the Tailwind to vanilla CSS if not already used in the codebase. Do not install any dependencies.`, }, ], } } // Create detailed file content (only when local path is not specified) const fileDetails = files .map((file, index) => { const fileExtension = file.path.split('.').pop() || '' return `## File ${index + 1}: ${file.path}\n\`\`\`${fileExtension}\n${file.content}\n\`\`\`` }) .join('\n\n') return { content: [ { type: 'text', text: `# Generated Files Summary\n${summary}\n\n# File Details\n${fileDetails}. Convert the Tailwind to vanilla CSS if not already used in the codebase. Do not install any dependencies.`, }, ], } } catch (error: any) { logger.error('Tool execution error:', error) return { content: [{type: 'text', text: `Error: ${error.message}`}], } } },
  • Zod schema for tool inputs defining parameters like fileKey, node ids, output format, token, local save path, image options.
    { fileKey: z .string() .describe( 'The Figma file identifier found in the file URL (e.g., https://www.figma.com/file/XXXXXXXXXXXX/). Extract the XXXXXXXXXXXX portion as the fileKey.', ), ids: z .string() .describe( 'Comma-separated list of Figma node IDs for conversion. To obtain node IDs, select elements in Figma, right-click and select "Copy/Paste as" → "Copy ID".', ), format: z .enum(['html', 'react-cssmodules', 'react-tailwind']) .default('html') .describe( 'Specify the output format: "html" generates semantic HTML/CSS, "react-cssmodules" creates React components with scoped CSS modules, "react-tailwind" produces React components with utility-first Tailwind classes.', ), personalToken: z .string() .optional() .describe( 'Figma personal access token for API authentication.The parameters are not required when the tool is called.', ), localPath: z .string() .optional() .describe( 'Absolute path for image asset storage. Directory will be created if non-existent. Path must follow OS-specific format without special character escaping. When set, all static resources will be saved to the images directory under this path.', ), imgFormat: z .enum(['png', 'jpg', 'svg']) .default('png') .describe( 'Export format for image assets: "png" for lossless quality, "jpg" for compressed files, or "svg" for vector graphics.', ), scaleSize: z .number() .min(1) .max(4) .default(2) .describe( 'Image export scale factor (1-4). Higher values yield better quality at the cost of larger file sizes.', ), },
  • Core helper function that builds query parameters and calls external F2C API (https://f2c-figma-api.yy.com/api/nodes) to convert Figma nodes to code files.
    async nodeToCode(o: NodeToCodeWithF2COptions): Promise<NodeToCodeFile[]> { const op = { fileKey: o.fileKey, nodeIds: o.ids, personal_token: o.personalToken || config.personalToken, option: { cssFramework: 'inlinecss', imgFormat: o.imgFormat || 'png', scaleSize: o.scaleSize || 2, }, format: 'files', // format: 'allFiles', } if (o.format === 'react-cssmodules') { op.option.cssFramework = 'cssmodules' } else if (o.format === 'react-tailwind') { op.option.cssFramework = 'tailwindcss' } const url = this.opToUrl(`${this.f2cHost}/nodes`, op) return this.fetch(url, 'json', o.ideInfo || 'other') }
  • Downloader helper that replaces remote Figma image URLs in generated code with local files and saves the code files to localPath if provided.
    public async checkLocalAndDownload(files: NodeToCodeFile[]) { if (!this.op.localPath) return await Promise.all( files.map(async f => { f.content = await this.downLoadImageAndReplaceContent(f.content) }), ) for (const file of files) { try { const savedPath = await this.saveContentToFile(file.content, file.path) logger.debug(`Successfully saved: ${savedPath}`) } catch (error) { logger.error(`Failed to save file ${file.path}:`, error) } } }

Other Tools

Related 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/f2c-ai/f2c-mcp'

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