Skip to main content
This guide covers setting up Talk to Figma MCP for local development, allowing you to modify the source code, test changes, and contribute to the project.

Prerequisites

Before you begin, ensure you have:
  • Bun runtime installed
  • Git installed
  • A code editor (VS Code, Cursor, or similar)
  • Node.js knowledge (TypeScript)
  • Figma account with editor access

Initial Setup

1

Clone the repository

git clone https://github.com/grab/cursor-talk-to-figma-mcp.git
cd talk-to-figma-mcp
2

Install dependencies

bun install
This installs all required packages:
  • @modelcontextprotocol/sdk - MCP protocol implementation
  • ws - WebSocket client
  • uuid - Unique ID generation
  • zod - Schema validation
  • TypeScript and build tools
3

Review project structure

talk-to-figma-mcp/
├── src/
│   ├── talk_to_figma_mcp/
│   │   ├── server.ts          # Main MCP server
│   │   └── package.json        # Server package config
│   ├── cursor_mcp_plugin/
│   │   ├── code.js             # Figma plugin main thread
│   │   ├── ui.html             # Plugin UI
│   │   └── manifest.json       # Plugin metadata
│   └── socket.ts               # WebSocket relay server
├── scripts/
│   └── setup.sh                # Automated setup script
├── package.json                # Root package config
└── tsup.config.ts              # Build configuration

Development Configuration

For local development, you need to point the MCP configuration to your local source files instead of the published package.

Cursor Configuration

Create or edit .cursor/mcp.json in your project root:
{
  "mcpServers": {
    "TalkToFigma": {
      "command": "bun",
      "args": ["/absolute/path/to/talk-to-figma-mcp/src/talk_to_figma_mcp/server.ts"]
    }
  }
}
Use the absolute path to your local server.ts file, not a relative path.

Claude Code Configuration

Create or edit .mcp.json in your project root:
{
  "mcpServers": {
    "TalkToFigma": {
      "command": "bun",
      "args": ["/absolute/path/to/talk-to-figma-mcp/src/talk_to_figma_mcp/server.ts"]
    }
  }
}

Finding your absolute path

cd /path/to/talk-to-figma-mcp
pwd
# Copy the output and append /src/talk_to_figma_mcp/server.ts
Example absolute paths:
  • macOS/Linux: /home/username/projects/talk-to-figma-mcp/src/talk_to_figma_mcp/server.ts
  • Windows: C:/Users/username/projects/talk-to-figma-mcp/src/talk_to_figma_mcp/server.ts

Development Workflow

Running the WebSocket Server

The WebSocket relay server requires no build step:
bun socket
For development with auto-reload, use:
bun --watch src/socket.ts

Building the MCP Server

The MCP server is written in TypeScript and needs to be built:
bun run build
Watch mode automatically rebuilds when you save changes to TypeScript files.

Running the MCP Server

After building:
bun run start
For testing, you can run the server directly:
bun src/talk_to_figma_mcp/server.ts

Figma Plugin Development

The Figma plugin requires no build step - it uses vanilla JavaScript:
1

Link the plugin

In Figma Desktop:
  1. Go to Plugins → Development → New Plugin
  2. Choose “Link existing plugin”
  3. Select src/cursor_mcp_plugin/manifest.json
2

Make changes

Edit code.js or ui.html in src/cursor_mcp_plugin/
3

Reload

Close and reopen the plugin in Figma to see your changes.
The plugin files are loaded directly by Figma - no transpilation or bundling needed.

Development Commands

All available commands from package.json:
{
  "scripts": {
    "start": "bun run dist/server.js",
    "socket": "bun run src/socket.ts",
    "setup": "./scripts/setup.sh",
    "build": "tsup",
    "build:watch": "tsup --watch",
    "dev": "bun run build:watch",
    "pub:release": "bun run build && npm publish"
  }
}

Testing Your Changes

1

Start the WebSocket server

bun socket
2

Build and run the MCP server (in watch mode)

bun run dev
In a separate terminal:
bun run start
3

Run the Figma plugin

In Figma: Plugins → Development → Cursor MCP Plugin
4

Test via Cursor or Claude Code

Use your AI agent to send commands and verify the behavior.

Architecture Deep Dive

MCP Server (src/talk_to_figma_mcp/server.ts)

The MCP server:
  • Implements the Model Context Protocol
  • Exposes 50+ tools for Figma manipulation
  • Manages WebSocket communication
  • Handles request/response correlation with UUIDs
  • Implements 30-second timeouts with progress resets
  • Validates all parameters with Zod schemas
Key patterns:
// Request tracking
const pendingRequests = new Map<string, {
  resolve: (value: any) => void;
  reject: (error: any) => void;
  timeoutId: NodeJS.Timeout;
  lastActivity: number;
}>();

// Logging (stderr only, stdout is for MCP protocol)
console.error('[MCP] Starting server...');

// Color conversion (Figma uses 0-1, display uses hex)
function rgbToHex(r: number, g: number, b: number): string {
  const toHex = (n: number) => Math.round(n * 255).toString(16).padStart(2, '0');
  return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
}

WebSocket Relay (src/socket.ts)

The WebSocket relay:
  • Lightweight Bun WebSocket server
  • Channel-based message routing
  • Runs on port 3055 (configurable via PORT env)
  • Handles connection management
  • CORS-enabled for browser plugin
Key features:
// Channel isolation
const channels = new Map<string, Set<ServerWebSocket<any>>>();

// Configurable binding
const server = Bun.serve({
  port: 3055,
  hostname: "0.0.0.0", // For Windows WSL
  // ...
});

Figma Plugin (src/cursor_mcp_plugin/)

The plugin:
  • Vanilla JavaScript (no build process)
  • Command dispatcher for 30+ operations
  • Chunking for large operations (prevents UI freezing)
  • WebSocket client for MCP communication
  • Progress reporting for long-running tasks
Key components:
// Command dispatcher
const commandHandlers = {
  get_document_info: async () => { /* ... */ },
  create_rectangle: async (params) => { /* ... */ },
  // 30+ more handlers
};

// Chunking pattern
for (let i = 0; i < nodes.length; i += chunkSize) {
  const chunk = nodes.slice(i, i + chunkSize);
  // Process chunk
  sendProgress(i, total);
}

Common Development Tasks

Adding a new MCP tool

1

Define the tool schema

In server.ts, add a new tool definition:
server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [
    // ... existing tools
    {
      name: "my_new_tool",
      description: "Description of what it does",
      inputSchema: {
        type: "object",
        properties: {
          param1: {
            type: "string",
            description: "First parameter"
          }
        },
        required: ["param1"]
      }
    }
  ]
}));
2

Implement the tool handler

Add the handler in the CallToolRequestSchema handler:
case "my_new_tool": {
  const params = request.params.arguments;
  // Send command to plugin
  const result = await sendCommandToPlugin({
    command: "my_new_tool",
    params: params
  });
  return { content: [{ type: "text", text: JSON.stringify(result) }] };
}
3

Add plugin handler

In code.js, add the command handler:
async function handleMyNewTool(params) {
  // Implement Figma API operations
  const node = figma.getNodeById(params.nodeId);
  // ...
  return { success: true, result: data };
}
4

Test the new tool

Rebuild, restart, and test via your AI agent.

Modifying WebSocket communication

The WebSocket protocol uses this message format:
{
  type: "join" | "message",
  channel: string,
  message?: {
    command: string,
    params: any
  },
  id?: string
}
Modifications should maintain backward compatibility with this structure.

Debugging

// All logs must go to stderr
console.error('[DEBUG] Variable value:', value);

// Never log to stdout (breaks MCP protocol)
// console.log('...') // DON'T DO THIS

Build Configuration

The project uses tsup for building. Configuration in tsup.config.ts:
import { defineConfig } from 'tsup'

export default defineConfig({
  entry: ['src/talk_to_figma_mcp/server.ts'],
  format: ['esm'],
  dts: false,
  shims: true,
  outDir: 'dist',
  clean: true,
})
This:
  • Compiles TypeScript to JavaScript
  • Outputs to dist/ directory
  • Uses ES modules format
  • Cleans output directory on each build

Contributing Guidelines

When contributing:
  1. Code Style: Follow existing patterns
  2. Logging: Use stderr for MCP server logs
  3. Error Handling: All errors should return structured responses
  4. Validation: Use Zod for parameter validation
  5. Documentation: Update relevant docs for new features
  6. Testing: Test with both Cursor and Claude Code
  7. Chunking: Use chunking for operations on 100+ nodes

Publishing Changes

For maintainers:
1

Update version

Edit package.json and bump the version number.
2

Build and publish

bun run pub:release
This builds the project and publishes to npm.
3

Update Figma plugin

If plugin changes are made, update the plugin on Figma Community separately.

Next Steps

Architecture

Understand the system architecture

API Reference

Explore all available MCP tools

Troubleshooting Development Issues

Build errors

  • Ensure all dependencies are installed: bun install
  • Clear the build cache: rm -rf dist && bun run build
  • Check TypeScript version compatibility

MCP server not reloading

  • You must restart your AI agent after making MCP server changes
  • Verify the absolute path in your MCP configuration is correct
  • Check stderr logs for error messages

Plugin changes not appearing

  • Close and reopen the plugin in Figma
  • For major changes, try unlinking and relinking the plugin
  • Check the Figma plugin console for JavaScript errors

WebSocket connection issues

  • Ensure the WebSocket server is running
  • Check port 3055 isn’t in use by another process
  • On Windows, verify hostname: "0.0.0.0" is set

Build docs developers (and LLMs) love