Convert Figma designs to Elementor v4 atomic widgets using Model Context Protocol (MCP) integration with the deployed Figma-Context-MCP server.
- β Converts Figma designs to Elementor v4 widgets in ~5 seconds
- β Extracts design metadata, colors, and layout information
- β Generates production-ready Elementor JSON output
- β
Integrates with deployed MCP server at
https://figma-context-mcp-fre3.onrender.com
npm installnode tests/successful_conversion.mjstest-data/figma_raw_data.yaml- Raw Figma design datatest-data/elementor_success_output.json- Elementor v4 compatible JSON
- MCP Integration: Connects to deployed Figma-Context-MCP server
- Session Management: Proper MCP protocol implementation with SSE support
- Elementor v4 Support: Generates atomic widgets compatible with Elementor v4
- Multiple Transport Modes: Supports both stdio and HTTP modes
- Error Handling: Robust error recovery and debugging capabilities
- TypeScript: Full TypeScript implementation with proper types
Figma Design URL β Figma-Context-MCP β YAML Data β Elementor Widgets β JSON Output
- MCP Client: Communicates with deployed Figma-Context-MCP server
- Session Manager: Handles MCP protocol session lifecycle
- YAML Parser: Extracts design data from Figma YAML response
- Widget Converter: Maps Figma elements to Elementor v4 widgets
- JSON Generator: Creates valid Elementor import format
# Stdio mode (for MCP clients like Cursor)
npx figma-to-elementor-mcp --stdio
# HTTP server mode
npx figma-to-elementor-mcp --http --port 3333fetch_figma_from_deployed_mcp- Fetch Figma data from deployed serverconvert_figma_context_to_elementor- Convert Figma data to Elementor widgetsconvert_figma_url_to_elementor- Complete URL-to-Elementor workflow
import fetch from 'node-fetch';
// Initialize MCP session
const initResponse = await fetch('https://figma-context-mcp-fre3.onrender.com/mcp', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json, text/event-stream', // Critical!
},
body: JSON.stringify({
jsonrpc: '2.0',
method: 'initialize',
params: {
protocolVersion: '2024-11-05',
capabilities: {},
clientInfo: { name: 'figma-to-elementor', version: '1.0.0' },
},
id: 1,
}),
});
const sessionId = initResponse.headers.get('mcp-session-id');
// Fetch Figma data
const figmaResponse = await fetch('https://figma-context-mcp-fre3.onrender.com/mcp', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json, text/event-stream',
'mcp-session-id': sessionId,
},
body: JSON.stringify({
jsonrpc: '2.0',
method: 'tools/call',
params: {
name: 'get_figma_data',
arguments: {
fileKey: 'z8nv6p3cbJCgTp7hbHXGil',
nodeId: '645:176384',
},
},
id: 2,
}),
});# Optional: Set custom port for HTTP mode
PORT=3333
# Optional: Set custom MCP server URL
FIGMA_MCP_URL=https://figma-context-mcp-fre3.onrender.comFor Cursor IDE or other MCP clients:
{
"mcpServers": {
"figma-to-elementor": {
"command": "npx",
"args": ["figma-to-elementor-mcp", "--stdio"]
}
}
}{
"version": "0.4",
"title": "Figma Design Name",
"type": "e-flexbox",
"content": [
{
"id": "root_123456789",
"elType": "widget",
"widgetType": "e-flexbox",
"settings": {
"classes": {
"$$type": "classes",
"value": ["e-root-123456789"]
}
},
"elements": [
{
"id": "heading_123456789",
"elType": "widget",
"widgetType": "e-heading",
"settings": {
"classes": {
"$$type": "classes",
"value": ["e-heading-123456789"]
}
},
"editor_settings": [],
"styles": {
"e-heading-123456789": {
"id": "e-heading-123456789",
"label": "local",
"type": "class",
"variants": [
{
"meta": {
"breakpoint": "desktop",
"state": null
},
"props": {
"typography": {
"$$type": "typography",
"value": {
"size": "32px",
"family": "Roboto"
}
},
"color": {
"$$type": "color",
"value": "#0C0D0E"
}
}
}
]
}
}
}
],
"styles": {
"e-root-123456789": {
"id": "e-root-123456789",
"label": "local",
"type": "class",
"variants": [
{
"meta": {
"breakpoint": "desktop",
"state": null
},
"props": {
"backgroundColor": {
"$$type": "color",
"value": "#FFFFFF"
},
"gap": {
"$$type": "size",
"value": "20px"
}
}
}
]
}
}
}
]
}npm run buildnpm run dev# Test with working solution
node tests/successful_conversion.mjs
# View test data outputs
ls test-data/-
406 Not Acceptable Error
Error: Failed to initialize: 406 Not AcceptableSolution: Ensure Accept header includes both content types:
'Accept': 'application/json, text/event-stream'
-
Session ID Missing
Error: No session ID receivedSolution: Check MCP protocol version in initialization:
protocolVersion: '2024-11-05' -
Parse Errors
Error: Could not parse Figma data from responseSolution: Handle SSE format correctly:
const dataLine = responseText.split('\n').find(line => line.startsWith('data: ')); const jsonData = JSON.parse(dataLine.substring(6));
- Use
debug_response.mjsto inspect server responses - Check
test-data/figma_raw_data.yamlfor raw Figma data - Verify session creation with verbose logging
- URL:
https://figma-context-mcp-fre3.onrender.com - Health Check:
https://figma-context-mcp-fre3.onrender.com/health - Status:
https://figma-context-mcp-fre3.onrender.com/api/status - Debug:
https://figma-context-mcp-fre3.onrender.com/api/debug-figma
https://www.figma.com/design/{fileKey}/{title}?node-id={nodeId}&m=dev
- fileKey: Extract from URL (e.g.,
z8nv6p3cbJCgTp7hbHXGil) - nodeId: Convert from URL format (e.g.,
645-176384β645:176384)
- Session Creation: ~1-2 seconds
- Data Fetch: ~2-3 seconds
- Conversion: <1 second
- Total Time: ~5 seconds
- Fork the repository
- Create a feature branch
- Test with
successful_conversion.mjs - Submit a pull request
MIT License - see LICENSE file for details.
- Figma-Context-MCP - Deployed MCP server for Figma data
- Elementor - WordPress page builder
- Model Context Protocol - MCP specification
package.json- Dependencies and scriptstsconfig.json- TypeScript configurationtsup.config.ts- Build configuration
function convertNodesToWidgets(nodes, metadata) { const widgets = [];
// Add a e-flexbox container for the layout
widgets.push({
id: e-flexbox_${Date.now()},
elType: 'widget',
widgetType: 'e-e-flexbox',
settings: {
gap: 'default',
background_background: 'classic',
background_color: '#FFFFFF',
padding: {
unit: 'px',
top: '20',
right: '20',
bottom: '20',
left: '20',
},
},
elements: [],
});
// Add an e-heading for the design name
widgets[0].elements.push({
id: widget_${Date.now()}_header,
elType: 'widget',
widgetType: 'e-heading',
settings: {
title: metadata.name || 'Figma Design',
header_size: 'h1',
typography_typography: 'custom',
typography_font_size: {
unit: 'px',
size: 32,
},
color: '#0C0D0E',
},
});
// Add widgets for each extracted node
nodes.forEach((node, index) => {
if (node.type === 'COLOR') {
// Use e-e-flexbox for color preview (instead of div-block)
widgets[0].elements.push({
id: widget_${Date.now()}_color_${index},
elType: 'widget',
widgetType: 'e-e-flexbox',
settings: {
background_background: 'classic',
background_color: node.color,
width: {
unit: 'px',
size: 50,
},
height: {
unit: 'px',
size: 50,
},
border_radius: {
unit: 'px',
top: '8',
right: '8',
bottom: '8',
left: '8',
},
},
});
// Add an e-paragraph for the color label
widgets[0].elements.push({
id: `widget_${Date.now()}_color_label_${index}`,
elType: 'widget',
widgetType: 'e-paragraph',
settings: {
text: `Color: ${node.color}`,
typography_typography: 'custom',
typography_font_size: {
unit: 'px',
size: 14,
},
color: '#69727D',
},
});
} else {
// Add an e-paragraph for generic nodes
widgets[0].elements.push({
id: `widget_${Date.now()}_node_${index}`,
elType: 'widget',
widgetType: 'e-paragraph',
settings: {
text: `Node: ${node.name}`,
typography_typography: 'custom',
typography_font_size: {
unit: 'px',
size: 16,
},
color: '#0C0D0E',
},
});
}
});
return widgets; }