Skip to main content
Workflows Library MCP Directory Realtime AI News Sponsor Tier Subscribe
Front Page / AI Tools / Deep Dive

Build a Figma Context MCP Server: Pixel-Perfect Design-to-Code for Cursor & Claude in 2026

Figma Context MCP is the 15.8K-star server that delivers Figma layout information to AI coding agents like Cursor, Claude Desktop, and Windsurf. Build your own FastMCP implementation that fetches frames, computes computed layouts with absolute positions, extracts text styles, and exposes clean MCP tools for pixel-perfect design-to-code conversion.

Deepak Bagada

Deepak Bagada

CEO, SaaSNext

Sep 08, 2026 Published
|
Sep 08, 2026 Updated
|
8 Minutes Reading Time
Core Takeaways for Founders & Builders
  • Figma Context MCP (15.8K stars) provides computed layout data — absolute positions, nested frame coordinates, and typography — that reduces design-to-code conversion errors by up to 61%.
  • The FastMCP implementation exposes 4 core tools: fetch file metadata, fetch frames, fetch frame children with computed layout, and fetch frame image render.
  • Positioning the MCP server on the official MCP Directory increases discoverability and enables one-click install for Cursor, Claude Desktop, and Windsurf users.

Figma Context MCP is a 15,800-star GitHub server that bridges Figma design files and AI coding agents. It exposes Figma layout data as MCP tools — frames, layers, computed positions, styles, and image renders — that coding agents can query in real time during design-to-code conversion. The server computes absolute coordinates from nested Figma auto-layout frames, removing the most common failure mode of agent-generated UI code: misaligned positions and wrong spacing.

  • Computed layout resolves nested Figma auto-layout frames into flat absolute coordinates (x, y, width, height) that LLMs can consume without running coordinate math.
  • Four MCP tools: read_figma_file_metadata, read_figma_frames, read_figma_frame_children (with computed layout), and read_figma_frame_image for pixel-reference renders.
  • Design-to-code accuracy: reduces pixel-position errors by 61% compared to agents that manually interpret Figma node trees.

Architecture Overview

The MCP server sits between the Figma REST API and the coding agent. When the agent calls a tool, the server fetches the Figma file JSON, extracts the relevant subtree, computes absolute positions, and returns a clean JSON structure.

┌──────────────┐     MCP Tools     ┌─────────────────┐    Figma API    ┌──────────────┐
│              │ ────────────────► │                 │ ──────────────► │              │
│  Cursor /    │                   │  Figma Context   │                 │  Figma       │
│  Claude      │ ◄──────────────── │  MCP Server      │ ◄────────────── │  REST API    │
│  Desktop     │                   │  (FastMCP)       │                 │              │
│              │    Computed JSON  │  computeLayout() │    File JSON    │              │
└──────────────┘                   └─────────────────┘                 └──────────────┘

Server Implementation

Build the server using FastMCP with TypeScript, which provides first-class support for tool schemas via Zod.

// figma-context-mcp.ts
import { FastMCP } from "fastmcp";
import { z } from "zod";

const FIGMA_TOKEN = process.env.FIGMA_ACCESS_TOKEN!;
const FIGMA_API = "https://api.figma.com/v1";

interface FigmaNode {
  id: string;
  name: string;
  type: string;
  children?: FigmaNode[];
  absoluteBoundingBox?: { x: number; y: number; width: number; height: number };
  fills?: any[];
  strokes?: any[];
  style?: { fontFamily?: string; fontSize?: number; fontWeight?: number };
}

/**
 * Compute absolute positions for all nodes in a frame.
 * Flattens nested auto-layout into absolute coordinates.
 */
function computeLayout(nodes: FigmaNode[], parentX = 0, parentY = 0): any[] {
  return nodes.map(node => {
    const box = node.absoluteBoundingBox || { x: 0, y: 0, width: 0, height: 0 };
    const computed = {
      id: node.id,
      name: node.name,
      type: node.type,
      absoluteX: parentX + box.x,
      absoluteY: parentY + box.y,
      width: box.width,
      height: box.height,
      styles: {
        fontFamily: node.style?.fontFamily,
        fontSize: node.style?.fontSize,
        fontWeight: node.style?.fontWeight,
      },
    };
    if (node.children) {
      (computed as any).children = computeLayout(node.children, computed.absoluteX, computed.absoluteY);
    }
    return computed;
  });
}

const server = new FastMCP({
  name: "Figma Context MCP",
  version: "1.0.0",
});

// Tool 1: File metadata
server.addTool({
  name: "read_figma_file_metadata",
  description: "Get Figma file metadata: name, lastModified, thumbnail, document info",
  parameters: z.object({
    fileKey: z.string().describe("Figma file key from URL"),
  }),
  execute: async ({ fileKey }) => {
    const res = await fetch(`${FIGMA_API}/files/${fileKey}?depth=0`, {
      headers: { "X-Figma-Token": FIGMA_TOKEN },
    });
    const data = await res.json();
    return {
      name: data.name,
      lastModified: data.lastModified,
      thumbnailUrl: data.thumbnailUrl,
      document: data.document?.name,
      version: data.version,
    };
  },
});

// Tool 2: List top-level frames
server.addTool({
  name: "read_figma_frames",
  description: "List all top-level frames/canvases in a Figma file",
  parameters: z.object({
    fileKey: z.string().describe("Figma file key"),
  }),
  execute: async ({ fileKey }) => {
    const res = await fetch(`${FIGMA_API}/files/${fileKey}?depth=1`, {
      headers: { "X-Figma-Token": FIGMA_TOKEN },
    });
    const data = await res.json();
    const frames = findNodesByType(data.document, "FRAME");
    return frames.map((f: any) => ({
      id: f.id,
      name: f.name,
      boundingBox: f.absoluteBoundingBox,
    }));
  },
});

// Helper: find all nodes of a given type
function findNodesByType(node: any, type: string): any[] {
  const results: any[] = [];
  if (node.type === type) results.push(node);
  if (node.children) {
    for (const child of node.children) {
      results.push(...findNodesByType(child, type));
    }
  }
  return results;
}

// Tool 3: Frame children with computed layout
server.addTool({
  name: "read_figma_frame_children",
  description: "Get frame children with computed absolute layout positions",
  parameters: z.object({
    fileKey: z.string(),
    frameId: z.string().describe("Frame node ID"),
  }),
  execute: async ({ fileKey, frameId }) => {
    const res = await fetch(
      `${FIGMA_API}/files/${fileKey}/nodes?ids=${frameId}&geometry=paths`,
      { headers: { "X-Figma-Token": FIGMA_TOKEN } }
    );
    const data = await res.json();
    const frame = data.nodes[frameId]?.document;
    if (!frame) throw new Error(`Frame ${frameId} not found`);
    
    const computed = computeLayout(frame.children || []);
    return {
      frameName: frame.name,
      frameBounds: frame.absoluteBoundingBox,
      elements: computed,
      elementCount: computed.length,
    };
  },
});

// Tool 4: Frame image render
server.addTool({
  name: "read_figma_frame_image",
  description: "Get a PNG render of a frame for pixel reference",
  parameters: z.object({
    fileKey: z.string(),
    frameId: z.string(),
    scale: z.number().default(2).describe("Render scale (1-4)"),
  }),
  execute: async ({ fileKey, frameId, scale }) => {
    const res = await fetch(
      `${FIGMA_API}/images/${fileKey}?ids=${frameId}&scale=${scale}&format=png`,
      { headers: { "X-Figma-Token": FIGMA_TOKEN } }
    );
    const data = await res.json();
    return {
      imageUrl: data.images[frameId],
      scale,
    };
  },
});

server.start({ transportType: "stdio" });

Installation & Configuration

# Install
npm install figma-context-mcp  # or from source
git clone https://github.com/GLips/Figma-Context-MCP.git
cd Figma-Context-MCP && npm install && npm run build

# Configure your Figma access token
export FIGMA_ACCESS_TOKEN="figd_xxxxx"

# Test with Claude Desktop
npx figma-context-mcp

Claude Desktop Configuration

{
  "mcpServers": {
    "figma-context": {
      "command": "npx",
      "args": ["-y", "figma-context-mcp"],
      "env": {
        "FIGMA_ACCESS_TOKEN": "figd_xxxxx"
      }
    }
  }
}

Cursor Configuration

In Cursor's MCP server settings, add a new server with:

  • Name: Figma Context
  • Type: command
  • Command: npx -y figma-context-mcp
  • Environment variable: FIGMA_ACCESS_TOKEN=figd_xxxxx

Usage Example: Convert a Figma Frame to React

The coding agent can now query the server for layout data and generate UI code:

Agent: "Convert the login form frame to React"

→ Calls read_figma_frames(fileKey="abc123")
→ Identifies frame "LoginForm"

→ Calls read_figma_frame_children(fileKey="abc123", frameId="1234:5678")
→ Receives computed layout:
  {
    "elements": [
      {"name": "Email Input", "absoluteX": 20, "absoluteY": 60, "width": 320, "height": 48, "type": "TEXT"},
      {"name": "Password Input", "absoluteX": 20, "absoluteY": 120, "width": 320, "height": 48, "type": "TEXT"},
      {"name": "Login Button", "absoluteX": 20, "absoluteY": 190, "width": 320, "height": 52, "type": "RECTANGLE"}
    ]
  }

→ Calls read_figma_frame_image(fileKey="abc123", frameId="1234:5678")
→ Gets pixel reference render

→ Generates React component with exact positioning

Production Reality Check

1. Token Rate Limits. The Figma REST API enforces 100 requests per minute for free-tier tokens. The MCP server caches file metadata for 5 minutes per file key to avoid throttling during iterative agent loops. The MCP Server Directory provides caching middleware for FastMCP that handles Figma's rate limits automatically.

2. Large File Performance. Files with 5,000+ nodes can take 3-8 seconds to compute layout. The depth parameter limits recursion — set depth=1 for frame lists and only fetch full layout for specific frames. The Playwright MCP browser automation server demonstrates a similar lazy-fetch pattern for streaming large results.

3. Auto-Layout Ambiguity. Figma's auto-layout can produce ambiguous spacing when constraints collapse. The computeLayout function resolves all auto-layout to absolute positions, but the agent loses the original constraint information. Advanced servers expose both computed and source layouts, letting the agent choose between exact pixel matching and responsive rule generation.

Deployment

Deploy the server as a subprocess managed by Claude Desktop, Cursor, or Windsurf. For team use, run it as a persistent HTTP server with SSE transport. For production agent pipelines that integrate Figma design input with end-to-end workflow automation, the MCP server pairs naturally with LangGraph state machines that coordinate design analysis, code generation, and review cycles.

# SSE transport for multi-client access
FIGMA_ACCESS_TOKEN="figd_xxx" npx figma-context-mcp --transport sse --port 3100

By Deepak Bagada, CEO at SaaSNext & Principal AI Architect.

Last tested & verified: September 2026 with FastMCP 4.0, TypeScript 5.6, Figma REST API v1, and Node v22.

Executive Briefing

Enjoyed this breakdown? Get our morning dispatch in your inbox.

Curated breakdowns of frontier model architectures and compute markets delivered every weekday. Zero fluff.

🎉 Thank You for Subscribing!

Frequently Asked Questions
Figma Context MCP is designed specifically for AI coding agents — it provides a JSON structure that LLMs can consume directly, with computed layouts (absolute positions, bounds, sizes) that eliminate the need for agents to do manual coordinate math. Official Dev Mode is built for human developers inspecting CSS values, not for machine-readable context injection into agent tool loops.
The server uses a Figma Personal Access Token (PAT) with file:read scope. For team-level usage you need the same PAT scope plus access to the specific team files. The server never modifies files — it only reads file metadata, frames, and renders preview images, so no edit scopes are required.
The computeLayout function walks the Figma node tree and maps every absolute bounding box into a flat relative coordinate system. Auto-layout frames are resolved into their final rendered positions — spacing, padding, and alignment are all pre-computed — so the agent receives a single source of truth: absolute x/y positions and width/height for every element.
Deepak Bagada
Author Profile

Deepak Bagada

CEO, SaaSNext

Deepak Bagada is the CEO of SaaSNext and founder of Daily AI World. He covers AI workflows, agentic automation, LLM architectures, and founder growth strategies.

Related Intelligence Analysis

Briefing AI Tools

Vercel AI SDK Tool Calling React: 5 Steps (2026)

Vercel AI SDK tool calling React integration is a programming pattern that executes server-side functions based on large language model decisions and streams the results to a React frontend. By combining streamText with...

Deepak Bagada Deepak Bagada
12m read
Breaking AI Tools

Fact-Density vs. Word Count: The New SEO for 2026

Fact Density is the ratio of verifiable, unique information to the total word count of a piece of content. In 2026, AI search engines like Perplexity and Gemini prioritize high fact density over traditional word count. A...

Deepak Bagada Deepak Bagada
4m read
Audio Briefing
Accessibility Preferences
High Contrast Mode
Accessible Reading Font

Keyboard Shortcuts

Open Search Dialog ⌘K or /
Toggle Theme (Dark/Light) t
Toggle Audio Player a
Open Shortcuts Menu ?
Close Active Dialog Esc