SuperAPI AI Directory

cursor-talk-to-figma-mcp

Design & creation

View repository

Updated 10-15 23:41

About this skill

Cursor Talk to Figma MCP

Skill by ara.so — Design Skills collection.

This skill enables AI agents to communicate with Figma through the Model Context Protocol (MCP), allowing programmatic reading and modification of design files. The integration uses a WebSocket server to bridge AI agents (Cursor, Claude Code) with a Figma plugin.

Installation

Prerequisites

Install Bun runtime:

curl -fsSL https://bun.sh/install | bash

Quick Setup

Run the automated setup which installs the MCP server in your Cursor configuration:

bun setup

Manual MCP Configuration

Add to ~/.cursor/mcp.json:

{
  "mcpServers": {
    "TalkToFigma": {
      "command": "bunx",
      "args": ["cursor-talk-to-figma-mcp@latest"]
    }
  }
}

For local development, use direct file path:

{
  "mcpServers": {
    "TalkToFigma": {
      "command": "bun",
      "args": ["/absolute/path/to/src/talk_to_figma_mcp/server.ts"]
    }
  }
}

Start WebSocket Server

bun socket

Figma Plugin Installation

  1. Install from Figma Community
  2. Or develop locally: Plugins > Development > New Plugin > Link existing plugin > Select src/cursor_mcp_plugin/manifest.json

Core Workflow

1. Establish Connection

// First, join a channel to communicate with Figma
await use_mcp_tool("TalkToFigma", "join_channel", {
  channelId: "my-design-session"
});

2. Read Design Information

// Get document overview
const docInfo = await use_mcp_tool("TalkToFigma", "get_document_info", {});

// Get current selection
const selection = await use_mcp_tool("TalkToFigma", "get_selection", {});

// Get detailed node information
const nodeInfo = await use_mcp_tool("TalkToFigma", "get_node_info", {
  nodeId: "123:456"
});

// Read current selection details without parameters
const selectionDetails = await use_mcp_tool("TalkToFigma", "read_my_design", {});

3. Create Elements

// Create a frame
const frame = await use_mcp_tool("TalkToFigma", "create_frame", {
  x: 0,
  y: 0,
  width: 375,
  height: 812,
  name: "iPhone Frame"
});

// Create a rectangle
const rect = await use_mcp_tool("TalkToFigma", "create_rectangle", {
  x: 20,
  y: 20,
  width: 335,
  height: 200,
  name: "Header Background"
});

// Create text
const text = await use_mcp_tool("TalkToFigma", "create_text", {
  x: 40,
  y: 100,
  characters: "Welcome to the App",
  fontSize: 24,
  fontName: { family: "Inter", style: "Bold" },
  name: "Header Title"
});

4. Modify Existing Elements

// Set fill color (RGBA 0-1 range)
await use_mcp_tool("TalkToFigma", "set_fill_color", {
  nodeId: "123:456",
  r: 0.2,
  g: 0.4,
  b: 0.8,
  a: 1.0
});

// Set stroke
await use_mcp_tool("TalkToFigma", "set_stroke_color", {
  nodeId: "123:456",
  r: 0.1,
  g: 0.1,
  b: 0.1,
  a: 1.0,
  strokeWeight: 2
});

// Set corner radius
await use_mcp_tool("TalkToFigma", "set_corner_radius", {
  nodeId: "123:456",
  radius: 12
});

// Move node
await use_mcp_tool("TalkToFigma", "move_node", {
  nodeId: "123:456",
  x: 100,
  y: 200
});

// Resize node
await use_mcp_tool("TalkToFigma", "resize_node", {
  nodeId: "123:456",
  width: 300,
  height: 150
});

Auto Layout Configuration

// Set layout mode
await use_mcp_tool("TalkToFigma", "set_layout_mode", {
  nodeId: "123:456",
  layoutMode: "VERTICAL", // "NONE", "HORIZONTAL", "VERTICAL"
  layoutWrap: "NO_WRAP"   // "NO_WRAP", "WRAP"
});

// Set padding
await use_mcp_tool("TalkToFigma", "set_padding", {
  nodeId: "123:456",
  paddingTop: 24,
  paddingRight: 16,
  paddingBottom: 24,
  paddingLeft: 16
});

// Set alignment
await use_mcp_tool("TalkToFigma", "set_axis_align", {
  nodeId: "123:456",
  primaryAxisAlignItems: "CENTER",      // "MIN", "CENTER", "MAX", "SPACE_BETWEEN"
  counterAxisAlignItems: "CENTER"       // "MIN", "CENTER", "MAX", "BASELINE"
});

// Set sizing behavior
await use_mcp_tool("TalkToFigma", "set_layout_sizing", {
  nodeId: "123:456",
  layoutSizingHorizontal: "HUG",  // "FIXED", "HUG", "FILL"
  layoutSizingVertical: "FIXED"
});

// Set item spacing
await use_mcp_tool("TalkToFigma", "set_item_spacing", {
  nodeId: "123:456",
  itemSpacing: 12
});

Bulk Text Operations

Scan Text Nodes

// Scan all text nodes with chunking for large designs
const textNodes = await use_mcp_tool("TalkToFigma", "scan_text_nodes", {
  chunkSize: 50,        // Process 50 nodes at a time
  startIndex: 0,        // Start from beginning
  parentNodeId: null    // Scan entire document (or specify parent)
});

// Response includes:
// - nodes: Array of text node info
// - hasMore: Boolean indicating more chunks available
// - nextIndex: Index for next chunk
// - total: Total number of text nodes

Update Single Text

await use_mcp_tool("TalkToFigma", "set_text_content", {
  nodeId: "123:456",
  characters: "Updated heading text"
});

Batch Update Multiple Texts

await use_mcp_tool("TalkToFigma", "set_multiple_text_contents", {
  updates: [
    { nodeId: "123:456", characters: "New Title" },
    { nodeId: "123:789", characters: "New Description" },
    { nodeId: "123:101", characters: "Updated Label" }
  ]
});

Annotations

Get Annotations

// Get all annotations in document
const annotations = await use_mcp_tool("TalkToFigma", "get_annotations", {});

// Get annotations for specific node
const nodeAnnotations = await use_mcp_tool("TalkToFigma", "get_annotations", {
  nodeId: "123:456"
});

Create/Update Annotation

await use_mcp_tool("TalkToFigma", "set_annotation", {
  nodeId: "123:456",
  text: "This component needs **accessibility** improvements:\n- Add ARIA labels\n- Improve color contrast",
  category: "DESIGN" // "DESIGN", "ENGINEERING", "CONTENT", "OTHER"
});

Batch Create Annotations

await use_mcp_tool("TalkToFigma", "set_multiple_annotations", {
  annotations: [
    {
      nodeId: "123:456",
      text: "Update to new brand colors",
      category: "DESIGN"
    },
    {
      nodeId: "123:789",
      text: "Implement loading state",
      category: "ENGINEERING"
    }
  ]
});

Components and Instances

Get Components

const components = await use_mcp_tool("TalkToFigma", "get_local_components", {});

Create Component Instance

const instance = await use_mcp_tool("TalkToFigma", "create_component_instance", {
  componentKey: "abc123def456",
  x: 100,
  y: 100
});

Instance Override Management

// Extract overrides from source instance
const overrides = await use_mcp_tool("TalkToFigma", "get_instance_overrides", {
  sourceInstanceId: "123:456"
});

// Apply overrides to target instances
await use_mcp_tool("TalkToFigma", "set_instance_overrides", {
  targetInstanceIds: ["123:789", "123:101"],
  overrides: overrides.overrides
});

Prototyping and Connections

Get Prototype Reactions

// Get all prototype reactions with visual highlights
const reactions = await use_mcp_tool("TalkToFigma", "get_reactions", {});

// Response includes source/destination nodes and interaction details

Create FigJam Connectors

// First, copy a connector in FigJam and set it as default
await use_mcp_tool("TalkToFigma", "set_default_connector", {});

// Create connections based on prototype flow
await use_mcp_tool("TalkToFigma", "create_connections", {
  connections: [
    { from: "123:456", to: "123:789" },
    { from: "123:789", to: "123:101" }
  ]
});

Selection and Focus

// Focus on specific node (selects and scrolls viewport)
await use_mcp_tool("TalkToFigma", "set_focus", {
  nodeId: "123:456"
});

// Select multiple nodes
await use_mcp_tool("TalkToFigma", "set_selections", {
  nodeIds: ["123:456", "123:789", "123:101"]
});

Node Management

Clone Nodes

const clone = await use_mcp_tool("TalkToFigma", "clone_node", {
  nodeId: "123:456",
  offsetX: 20,    // Optional X offset
  offsetY: 20     // Optional Y offset
});

Delete Nodes

// Delete single node
await use_mcp_tool("TalkToFigma", "delete_node", {
  nodeId: "123:456"
});

// Delete multiple nodes efficiently
await use_mcp_tool("TalkToFigma", "delete_multiple_nodes", {
  nodeIds: ["123:456", "123:789", "123:101"]
});

Get Multiple Nodes Info

const nodesInfo = await use_mcp_tool("TalkToFigma", "get_nodes_info", {
  nodeIds: ["123:456", "123:789", "123:101"]
});

Export

// Export node as image
const imageData = await use_mcp_tool("TalkToFigma", "export_node_as_image", {
  nodeId: "123:456",
  format: "PNG",      // "PNG", "JPG", "SVG", "PDF"
  scale: 2            // Optional: 1, 2, 3, 4
});

// Returns base64 encoded image data

Scan Nodes by Type

// Find all nodes of specific types (useful for finding annotation targets)
const frames = await use_mcp_tool("TalkToFigma", "scan_nodes_by_types", {
  types: ["FRAME", "COMPONENT", "INSTANCE"],
  parentNodeId: null  // Optional: limit to specific parent
});

Common Patterns

Pattern: Create a Card Component

// 1. Create container frame
const card = await use_mcp_tool("TalkToFigma", "create_frame", {
  x: 0, y: 0, width: 300, height: 400, name: "Card"
});

// 2. Set auto layout
await use_mcp_tool("TalkToFigma", "set_layout_mode", {
  nodeId: card.id, layoutMode: "VERTICAL"
});

await use_mcp_tool("TalkToFigma", "set_padding", {
  nodeId: card.id,
  paddingTop: 20, paddingRight: 20,
  paddingBottom: 20, paddingLeft: 20
});

await use_mcp_tool("TalkToFigma", "set_item_spacing", {
  nodeId: card.id, itemSpacing: 16
});

// 3. Style the card
await use_mcp_tool("TalkToFigma", "set_fill_color", {
  nodeId: card.id, r: 1, g: 1, b: 1, a: 1
});

await use_mcp_tool("TalkToFigma", "set_corner_radius", {
  nodeId: card.id, radius: 8
});

// 4. Add shadow via stroke as workaround
await use_mcp_tool("TalkToFigma", "set_stroke_color", {
  nodeId: card.id, r: 0.9, g: 0.9, b: 0.9, a: 1, strokeWeight: 1
});

Pattern: Bulk Content Replacement

// 1. Scan all text nodes in chunks
let allTextNodes = [];
let hasMore = true;
let nextIndex = 0;

while (hasMore) {
  const result = await use_mcp_tool("TalkToFigma", "scan_text_nodes", {
    chunkSize: 50,
    startIndex: nextIndex
  });
  
  allTextNodes = allTextNodes.concat(result.nodes);
  hasMore = result.hasMore;
  nextIndex = result.nextIndex;
}

// 2. Filter and prepare updates
const updates = allTextNodes
  .filter(node => node.characters.includes("old-text"))
  .map(node => ({
    nodeId: node.id,
    characters: node.characters.replace("old-text", "new-text")
  }));

// 3. Batch update
await use_mcp_tool("TalkToFigma", "set_multiple_text_contents", {
  updates: updates
});

Pattern: Convert Legacy Annotations

// 1. Scan for text nodes with numbered markers
const textNodes = await use_mcp_tool("TalkToFigma", "scan_text_nodes", {});
const markers = textNodes.nodes.filter(n => /^\d+\./.test(n.characters));

// 2. Find potential annotation targets
const targets = await use_mcp_tool("TalkToFigma", "scan_nodes_by_types", {
  types: ["FRAME", "COMPONENT", "INSTANCE", "RECTANGLE"]
});

// 3. Match markers to targets (by proximity, naming, or path)
const annotations = markers.map(marker => {
  const targetNode = findClosestTarget(marker, targets.nodes);
  return {
    nodeId: targetNode.id,
    text: marker.characters.replace(/^\d+\.\s*/, ""),
    category: "DESIGN"
  };
});

// 4. Create native annotations
await use_mcp_tool("TalkToFigma", "set_multiple_annotations", {
  annotations: annotations
});

// 5. Delete old marker nodes
await use_mcp_tool("TalkToFigma", "delete_multiple_nodes", {
  nodeIds: markers.map(m => m.id)
});

Pattern: Prototype to Connector Visualization

// 1. Get prototype reactions
const reactions = await use_mcp_tool("TalkToFigma", "get_reactions", {});

// 2. Copy and set default connector style in FigJam
await use_mcp_tool("TalkToFigma", "set_default_connector", {});

// 3. Extract connections from reactions
const connections = reactions.reactions.map(r => ({
  from: r.node.id,
  to: r.action.destinationId
}));

// 4. Create connector lines
await use_mcp_tool("TalkToFigma", "create_connections", {
  connections: connections
});

Windows + WSL Configuration

For Windows with WSL, uncomment the hostname in src/socket.ts:

// Uncomment for Windows WSL
hostname: "0.0.0.0",

Install Bun via PowerShell:

irm bun.sh/install.ps1|iex

Troubleshooting

WebSocket Connection Issues

  • Ensure WebSocket server is running: bun socket
  • Verify Figma plugin is active and connected
  • Check that join_channel was called successfully
  • For WSL, ensure hostname is set to 0.0.0.0

MCP Server Not Found

  • Verify ~/.cursor/mcp.json configuration is correct
  • Restart Cursor after configuration changes
  • Check that Bun is installed and in PATH
  • For local development, use absolute paths

Commands Fail Silently

  • Always join a channel first with join_channel
  • Verify node IDs exist using get_document_info or get_selection
  • Check WebSocket server logs for errors
  • Ensure Figma file is open and plugin is running

Text Update Failures

  • Verify node is actually a TEXT node type
  • Check that text layer is not locked
  • For batch updates, process in smaller chunks if needed
  • Missing fonts may cause failures - ensure fonts are available

Color Values

All color values use 0-1 range (not 0-255):

  • Convert: rgbValue / 255
  • Example: RGB(51, 102, 204) = r: 0.2, g: 0.4, b: 0.8

Auto Layout Constraints

  • set_layout_mode must be called before other auto-layout properties
  • Cannot set padding on non-auto-layout frames
  • Item spacing only works in auto-layout frames
  • Some sizing modes require specific layout configurations

Best Practices

  1. Always establish connection first - Call join_channel before any other commands
  2. Get context before modifying - Use get_document_info and get_selection to understand structure
  3. Use batch operations - Prefer set_multiple_text_contents over multiple set_text_content calls
  4. Chunk large operations - Use chunking parameters for designs with many nodes
  5. Verify changes - Use get_node_info after modifications to confirm success
  6. Handle errors gracefully - All commands can throw exceptions, implement proper error handling
  7. Use component instances - Prefer instances over duplicating elements for consistency
  8. Organize with frames - Use frames with auto-layout for structured, responsive designs
  9. Clean up legacy elements - Delete old nodes after migrating to new patterns
  10. Test incrementally - Verify each step when building complex automation workflows