skillZs
★ LIVE SKILL TAGS ★
>>> LIVE SKILLS INDEX <<<
* OPEN SOURCE *
NO LOGIN, NO TRACKING
※ REAL INSTALL DATA ※
← back to all skills
reason-machines/design-skills146 installs

cursor-talk-to-figma-mcp

MCP server enabling AI agents to read and modify Figma designs programmatically through WebSocket communication

How do I install this agent skill?

npx skills add https://github.com/reason-machines/design-skills --skill cursor-talk-to-figma-mcp
view source ↗

Is this agent skill safe to install?

  • Gen Agent Trust Hubfail

    This skill enables AI agents to interact with Figma designs via the Model Context Protocol (MCP). It involves installing the Bun runtime and an MCP server. While the installation sources for Bun and the Figma connection are well-known, the skill exposes design data to the agent, creating a surface for indirect prompt injection from potentially untrusted design files.

  • Socketpass

    No alerts

  • Snykwarn

    Risk: MEDIUM · 2 issues

What does this agent skill do?

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

Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.

<a href="https://skillzs.dev/skills/reason-machines/design-skills/cursor-talk-to-figma-mcp">View cursor-talk-to-figma-mcp on skillZs</a>