Snail.MCP.Figma 0.1.0

{
  "inputs": [
    {
      "type": "promptString",
      "id": "SNAIL_MCP_FIGMA_ACCESS_TOKEN",
      "description": "Figma personal access token (figd_…) or OAuth token (figu_…). Needed only for the REST channel: version history, comments, other teams' libraries, files not open in the desktop app. The live-editor channel works without it.",
      "password": true
    },
    {
      "type": "promptString",
      "id": "SNAIL_MCP_FIGMA_DATA_DIRECTORY",
      "description": "Data root: snapshot database, installed editor extension, captures. Default: ~/.snail-mcp-figma."
    },
    {
      "type": "pickString",
      "id": "SNAIL_MCP_FIGMA_SANITIZATION__PROFILE",
      "description": "How aggressively REST responses are trimmed before reaching the model.",
      "default": "Aggressive",
      "options": ["Aggressive", "Balanced", "Raw"]
    },
    {
      "type": "pickString",
      "id": "SNAIL_MCP_FIGMA_BRIDGE__PREFER_PLUGIN_FOR_READS",
      "description": "Read through the live editor when it is connected; false always reads the last saved state via REST.",
      "default": "true",
      "options": ["true", "false"]
    },
    {
      "type": "pickString",
      "id": "SNAIL_MCP_FIGMA_CACHE__ENABLED",
      "description": "Keep LiteDB snapshots of REST reads.",
      "default": "true",
      "options": ["true", "false"]
    },
    {
      "type": "promptString",
      "id": "SNAIL_MCP_FIGMA_IDLE_TIMEOUT_MINUTES",
      "description": "Minutes without a tool call after which the process exits on its own; 0 disables the watchdog.",
      "default": "60"
    }
  ],
  "servers": {
    "Snail.MCP.Figma": {
      "type": "stdio",
      "command": "dnx",
      "args": ["Snail.MCP.Figma@0.1.0", "--yes"],
      "env": {
        "SNAIL_MCP_FIGMA_ACCESS_TOKEN": "${input:SNAIL_MCP_FIGMA_ACCESS_TOKEN}",
        "SNAIL_MCP_FIGMA_DATA_DIRECTORY": "${input:SNAIL_MCP_FIGMA_DATA_DIRECTORY}",
        "SNAIL_MCP_FIGMA_SANITIZATION__PROFILE": "${input:SNAIL_MCP_FIGMA_SANITIZATION__PROFILE}",
        "SNAIL_MCP_FIGMA_BRIDGE__PREFER_PLUGIN_FOR_READS": "${input:SNAIL_MCP_FIGMA_BRIDGE__PREFER_PLUGIN_FOR_READS}",
        "SNAIL_MCP_FIGMA_CACHE__ENABLED": "${input:SNAIL_MCP_FIGMA_CACHE__ENABLED}",
        "SNAIL_MCP_FIGMA_IDLE_TIMEOUT_MINUTES": "${input:SNAIL_MCP_FIGMA_IDLE_TIMEOUT_MINUTES}"
      }
    }
  }
}
                    
This package contains an MCP Server. The server can be used in VS Code by copying the generated JSON to your VS Code workspace's .vscode/mcp.json settings file.
dotnet tool install --global Snail.MCP.Figma --version 0.1.0
                    
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest
                    
if you are setting up this repo
dotnet tool install --local Snail.MCP.Figma --version 0.1.0
                    
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=Snail.MCP.Figma&version=0.1.0
                    
nuke :add-package Snail.MCP.Figma --version 0.1.0
                    

Snail.MCP.Figma

Documentation NuGet Release License: MIT

A local MCP server that gives your AI assistant 139 tools for reading and editing Figma. It runs on your machine, talks to your client over stdio, and reaches Figma two ways: through the Figma Desktop app (a bundled plugin — it sees unsaved edits and spends no API quota) and through the Figma REST API (behind a snapshot cache and a sanitizer that keeps raw Figma JSON out of the model's context).

Point it at a Figma link and ask in plain words: read this screen and implement it in React, export the variables as Tailwind tokens, add a Dark mode, what changed in this file this week, build a FigJam board out of this plan.

  • Read files, pages, components, variables, styles, renders — with the tree already trimmed to what a model can use.
  • Write to the canvas: create, move, restyle, rename and delete nodes, instantiate components, run arbitrary Plugin API code.
  • Design tokens in 11 formats — DTCG, Tokens Studio, CSS variables, SCSS, LESS, Tailwind v3/v4, Style Dictionary, TypeScript, flat and nested JSON.
  • Design ↔ code: component specs for implementation, parity checks, generated Markdown docs, and design system extraction out of an existing codebase.
  • History: version diffs, per-node blame, generated changelogs. Comments, libraries, FigJam, Figma Slides.

Full tool reference with every parameter and JSON schema: orldev.github.io/Snail.MCP.Figma

Requirements

.NET 10 SDK The server is a .NET tool. Download: dotnet.microsoft.com/download
An MCP client Claude Code, Claude Desktop, Cursor, VS Code, Codex — anything that speaks MCP over stdio
Figma Desktop Needed for every write and for quota-free reads. The free plan is enough
A Figma token Optional. Only the REST features need it: version history, comments, other teams' libraries, files that are not open in the desktop app

Works on macOS, Windows and Linux.

Install

Five steps: the server, a token, your client, the Figma plugin, a check. The same walkthrough with per-client paths and fixes for what usually goes wrong lives in the installation guide.

1. Install the server

The recommended way is a global .NET tool — it gives you the snail-mcp-figma command:

dotnet tool install -g Snail.MCP.Figma

If the shell cannot find the command afterwards, add the tools folder to PATH (~/.dotnet/tools on macOS and Linux, %USERPROFILE%\.dotnet\tools on Windows) and open a new terminal.

Two alternatives:

dnx Snail.MCP.Figma --yes          # run without installing (.NET 10 SDK), downloads on first use
git clone https://github.com/orldev/Snail.MCP.Figma.git   # build from source
cd Snail.MCP.Figma && dotnet build -c Release
# the command is then: dotnet <repo>/src/bin/Release/net10.0/Snail.MCP.Figma.dll

Do not launch the server by hand — it speaks JSON-RPC over stdio and has no interactive interface. Your MCP client starts and stops it for you.

2. Get a Figma token (optional, for the REST features)

In Figma: your avatar → Settings → Security → Personal access tokens → Generate new token. The token starts with figd_; OAuth tokens (figu_) work too. Grant the scopes for what you plan to use:

Scope What it unlocks
File content — read Reading files, nodes and renders through REST
File versions — read figma_get_file_versions, version diffs, figma_blame_node
Comments — read/write figma_get_comments, figma_post_comment, figma_delete_comment
Library assets — read Components and styles of other teams' libraries by key
Variables — read/write REST variables; Figma exposes this on Enterprise plans only — through the plugin variables work on any plan

Keep the token in the environment of the MCP client (below), not in a file in your repository. Without a token the server still starts and everything the plugin can do keeps working.

3. Register it with your client

Claude Code

claude mcp add snail-mcp-figma --scope user \
  --env SNAIL_MCP_FIGMA_ACCESS_TOKEN=figd_... \
  -- snail-mcp-figma

Check it with claude mcp list, or /mcp inside a session.

Claude Desktop — edit claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/, Windows: %APPDATA%\Claude\) and restart the app:

{
  "mcpServers": {
    "snail-mcp-figma": {
      "command": "snail-mcp-figma",
      "env": {
        "SNAIL_MCP_FIGMA_ACCESS_TOKEN": "figd_..."
      }
    }
  }
}

Cursor — the same block in ~/.cursor/mcp.json (or .cursor/mcp.json for one project).

VS Code.vscode/mcp.json uses a servers key and an explicit transport:

{
  "servers": {
    "snail-mcp-figma": {
      "type": "stdio",
      "command": "snail-mcp-figma",
      "env": { "SNAIL_MCP_FIGMA_ACCESS_TOKEN": "figd_..." }
    }
  }
}

Codex CLI~/.codex/config.toml:

[mcp_servers.snail-mcp-figma]
command = "snail-mcp-figma"
args = []
env = { SNAIL_MCP_FIGMA_ACCESS_TOKEN = "figd_..." }

If you chose dnx instead of a global install, the command is dnx with "args": ["Snail.MCP.Figma", "--yes"]; for a build from source it is dotnet with "args": ["<repo>/src/bin/Release/net10.0/Snail.MCP.Figma.dll"].

Every other setting is optional — see Configuration.

4. Install the Figma plugin

The plugin is what makes writes possible and reads free. On its first run the server unpacks it into ~/.snail-mcp-figma/plugin (ask the agent for csharp_diagnose to see the exact path under plugin.bundledPath).

  1. Open Figma Desktop (the browser cannot run development plugins).
  2. Plugins → Development → Import plugin from manifest… and pick manifest.json from that folder.
  3. Open the file you want to work in and run Plugins → Development → Snail Bridge.

Keep the plugin window open — closing it ends the session. The plugin finds the server itself on ports 9223–9232, so the order in which you start them does not matter, and several agent sessions can share one plugin. Details: Plugin setup.

5. Check that it works

Ask your assistant to call csharp_diagnose — it reports the configuration, whether the bridge is listening, which files have a live plugin session and whether the token is valid. figma_get_status answers the same question from the Figma side.

Then paste a Figma link and ask for something small: "list the pages of this file".

Updating and removing

dotnet tool update -g Snail.MCP.Figma     # update
dotnet tool uninstall -g Snail.MCP.Figma  # remove

After an update the plugin panel shows a re-import plugin banner when the bundled plugin changed — repeat step 4 to pick up the new bundle. Removing ~/.snail-mcp-figma deletes the snapshot cache, the unpacked plugin and saved screenshots; nothing else is stored outside it.

What you can ask for

Point at a file by pasting its link — every tool takes a fileUrl, and after the first call the session remembers it. Typical requests:

Ask What runs
"Read the Button component from <link> and implement it in React with our tokens" figma_get_component_for_developmentfigma_export_tokens
"Export this file's variables as Tailwind v4" figma_export_tokens
"Add a Dark mode and fill it from tokens.dark.json" figma_add_mode, figma_import_tokens
"Capture the whole design system into one document" figma_get_design_system_kit
"What changed in this file since Monday, as a changelog" figma_get_changes_since_version, figma_generate_changelog
"Who changed this frame and when" figma_blame_node
"Find loose colors on this page that should be tokens" figma_lint_design, figma_get_selection_colors
"Build the login screen from this spec" figma_create_node_from_jsx, figma_set_fills, figma_set_text
"Turn our component library in this repo into Figma variables and a package" figma_ds_analyzefigma_ds_extract_tokensfigma_ds_scaffold
"Lay this retro out as a FigJam board" figjam_create_stickies, figjam_create_connector

Tools

139 tools in 18 families. Each name below links to the reference page with parameters and JSON schemas.

  • Reading (7) — figma_get_file_data, figma_get_component, figma_get_variables, figma_get_file_meta, figma_get_styles, figma_get_component_image, figma_get_file_for_plugin
  • Writing (11) — figma_get_selection, figma_move_node, figma_resize_node, figma_set_fills, figma_set_text, figma_execute, figma_get_selection_colors, figma_sort_styles, figma_commit_undo, figma_create_style, figma_get_status
  • Nodes (15) — figma_clone_node, figma_delete_node, figma_rename_node, figma_set_strokes, figma_set_image_fill, figma_create_child, figma_set_description, figma_set_instance_properties, figma_create_page, figma_create_node_from_svg, figma_place_image, figma_create_node_from_jsx, figma_boolean_operation, figma_group_nodes, figma_ungroup_node
  • Components (9) — figma_search_components, figma_instantiate_component, figma_create_component_set, figma_analyze_component_set, figma_arrange_component_set, figma_add_component_property, figma_edit_component_property, figma_delete_component_property, figma_get_component_details
  • Variables (13) — figma_create_variable_collection, figma_delete_variable_collection, figma_create_variable, figma_update_variable, figma_delete_variable, figma_rename_variable, figma_set_variable_description, figma_add_mode, figma_rename_mode, figma_get_token_values, figma_batch_create_variables, figma_batch_update_variables, figma_setup_design_tokens
  • Design tokens (3) — figma_export_tokens, figma_import_tokens, figma_convert_tokens
  • Design to code (5) — figma_get_component_for_development, figma_get_component_for_development_deep, figma_extract_style_values, figma_check_design_parity, figma_generate_component_doc
  • Design system kit (1) — figma_get_design_system_kit
  • Design system from code (7) — figma_ds_analyze, figma_ds_extract_tokens, figma_ds_scaffold, figma_ds_setup_storybook, figma_ds_extract_component, figma_ds_verify, figma_ds_status
  • Version history (7) — figma_get_file_versions, figma_get_file_at_version, figma_diff_versions, figma_get_changes_since_version, figma_generate_changelog, figma_blame_node, figma_save_version
  • Comments (3) — figma_get_comments, figma_post_comment, figma_delete_comment
  • Libraries (5) — figma_get_library_component_by_key, figma_get_library_variables, figma_import_library_variable, figma_get_library_style_by_key, figma_search_team_components
  • FigJam (10) — figjam_create_sticky, figjam_create_stickies, figjam_create_connector, figjam_create_shape_with_text, figjam_create_section, figjam_create_table, figjam_create_code_block, figjam_auto_arrange, figjam_get_board_contents, figjam_get_connections
  • Slides (16) — figma_list_slides, figma_get_slide_content, figma_get_slide_grid, figma_get_slide_transition, figma_get_focused_slide, figma_create_slide, figma_delete_slide, figma_duplicate_slide, figma_reorder_slides, figma_set_slide_transition, figma_skip_slide, figma_add_text_to_slide, figma_add_shape_to_slide, figma_set_slide_background, figma_set_slides_view_mode, figma_focus_slide
  • Slots (5) — figma_create_slot, figma_get_slots, figma_append_to_slot, figma_reset_slot, figma_add_slot_property
  • Quality and annotations (6) — figma_lint_design, figma_audit_component_accessibility, figma_get_annotations, figma_set_annotations, figma_get_annotation_categories, figma_add_annotation_category
  • Session and console (15) — figma_list_open_files, figma_navigate, figma_execute_across_files, figma_reconnect, figma_reload_plugin, figma_get_console_logs, figma_clear_console, figma_watch_console, figma_export_node, figma_get_active_users, figma_notify, figma_scroll_to_node, figma_set_file_thumbnail, figma_take_screenshot, figma_get_text_styles
  • Diagnostics (1) — csharp_diagnose

Which tools need what:

Works without a token Works without the plugin
Reading files, components, styles, variables, renders yes, with the plugin running yes, through REST
Any write, FigJam, Slides, slots, console, screenshots yes no
Version history, blame, changelogs, comments, other teams' libraries no yes

Configuration

Nothing has to be configured — the defaults work. Every setting is an environment variable (SNAIL_MCP_FIGMA_ + the field, sections separated by __) that goes into the env block of your client:

Variable Default Purpose
SNAIL_MCP_FIGMA_ACCESS_TOKEN Figma token, for the REST channel
SNAIL_MCP_FIGMA_DATA_DIRECTORY ~/.snail-mcp-figma Snapshot cache, unpacked plugin, screenshots
SNAIL_MCP_FIGMA_IDLE_TIMEOUT_MINUTES 60 Minutes without a tool call before the server exits by itself; 0 disables the watchdog
SNAIL_MCP_FIGMA_SANITIZATION__PROFILE Aggressive How hard REST responses are trimmed: Aggressive / Balanced / Raw
SNAIL_MCP_FIGMA_SANITIZATION__DEFAULT_DEPTH 3 Default tree depth of a REST read
SNAIL_MCP_FIGMA_SANITIZATION__DEFAULT_MAX_NODES 500 Node cap of a REST read
SNAIL_MCP_FIGMA_BRIDGE__PREFER_PLUGIN_FOR_READS true Read through the plugin when it is connected
SNAIL_MCP_FIGMA_BRIDGE__PORT_RANGE_START / __PORT_RANGE_END 9223 / 9232 The bridge port range — it is also written into plugin/manifest.json, so it cannot be changed without editing the manifest
SNAIL_MCP_FIGMA_BRIDGE__REQUEST_TIMEOUT_SECONDS 30 Timeout of one plugin command
SNAIL_MCP_FIGMA_CACHE__ENABLED true Keep snapshots of REST reads
SNAIL_MCP_FIGMA_CACHE__FRESHNESS_SECONDS 300 How long a snapshot is served without checking the version
SNAIL_MCP_FIGMA_CACHE__TTL_HOURS / __IMAGE_TTL_HOURS 24 / 24 Lifetime of a node snapshot and of a render link
SNAIL_MCP_FIGMA_SCREENSHOTS__RETAIN_COUNT 30 How many screenshots are kept on disk

A settings file can hold the same fields instead, looked up as $SNAIL_MCP_FIGMA_CONFIG./.snail-mcp-figma.json./snail-mcp-figma.json~/.config/snail-mcp-figma/config.json~/.snail-mcp-figma.json. Environment variables always win. Full sample: Configuration.

Troubleshooting

Symptom What it means
"The plugin is not connected" The plugin is not running in that file. Open it in Figma Desktop, start Snail Bridge, check figma_get_status
ERR_CONNECTION_REFUSED in the plugin console The discovery loop looking for a server that is not running yet. It goes quiet as soon as one connects
Answers marked source: "cache-stale" Figma was unreachable, so the last snapshot was served. Ask again with source: "plugin"
429 with a Retry-After of hours The daily REST quota. The bucket closes locally until it expires; work through the plugin meanwhile
Variables return 403 The REST variables API is Enterprise-only — read them through the plugin (figma_get_token_values)
The tool list is empty in the client The command is not on PATH. Use the absolute path to snail-mcp-figma, or the dotnet <dll> form

More cases: Troubleshooting.

How it works

                 ┌── READ ──→ Live Editor (plugin) ──→ LiteDB snapshot ──→ REST ──→ Sanitizer
Claude ── stdio ─┤
                 └── WRITE ─→ EditorSocketHub (Kestrel, ws://127.0.0.1:9223…9232) ─→ ui.html ─→ code.js ─→ figma.*
                                       └─ DOCUMENT_CHANGE ─→ SnapshotInvalidator
  • Plugin-first reads. While the plugin is connected to a file, reads go through it: no REST requests, no quota, and unsaved edits are visible. The path used is in the source field of every response (plugin / cache / figma-api / cache-stale) and can be forced per call with source.
  • One read costs at most one REST request, and none while the snapshot is fresh. Invalidation is precise: the plugin reports DOCUMENT_CHANGE at the moment of the edit.
  • Quota circuit breaker. A 429 with a long Retry-After closes that endpoint locally until it expires, so a refusal already known costs no network round trip. State: csharp_diagnose → rateLimit.
  • Writes are confirmed by the plugin's answer, never assumed; the node and its ancestors are invalidated after each one.
  • Watchdog. An hour without a tool call and the process exits on its own, so orphaned servers do not pile up.

The internals — the hexagonal layout, the snapshot policy, the sanitizer — are described in Architecture.

Development

git clone https://github.com/orldev/Snail.MCP.Figma.git
cd Snail.MCP.Figma
export SNAIL_MCP_FIGMA_ACCESS_TOKEN=figd_...   # REST tests and manual runs only
dotnet build
dotnet test
  • .NET SDK 10. Folder = layer = namespace Snail.MCP.Figma.<Folder>; the core knows nothing of REST, WebSockets or LiteDB, and the tools see ports only. A new external dependency starts with a port in Application/Ports, then an adapter, then a registration in Extensions.
  • Code, documentation and every string the model reads are in English. The layer boundary, the prompt catalog, the stdio contract and the code style are all guarded by tests.
  • .mcp.json in the repository root registers a local debug build for Claude Code.
  • Docs: dotnet run --project gen -- docs regenerates the tool reference from the catalog, mkdocs serve previews the site (pip install mkdocs-material).
  • Release: a v* tag runs the tests, syncs the version in .mcp/server.json, pushes the package to NuGet and deploys the documentation.

The project grew out of figma-console-mcp (MIT, Southleft); what remains of the donor is the JS plugin in plugin/.

Licences

The server code and the plugin/ bundle are MIT — LICENSE and plugin/LICENSE

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

Version Downloads Last Updated
0.1.0 100 8/24/2026