
Security News
Happy Birthday, Shai-Hulud
It has been one year since Shai-Hulud made its first appearance on npm.
figma-mcp-rs
Advanced tools
A zero-cost, unlimited Figma/FigJam MCP server in Rust — no API key, no rate limits
Figma/FigJam MCP server in Rust — free, no rate limits. Rust port of vkhanhqui/figma-mcp-go with a rewritten SolidJS plugin and FigJam support.
Open-source MCP server with full read/write access to Figma and FigJam via plugin — no REST API, no rate limits. Turn text into designs and designs into real code. Works with Claude, Cursor, GitHub Copilot, and any MCP-compatible AI tool.
Highlights
get_status, execute_code, eight FigJam tools, the use_figma escape hatch, and four design-system tools: update_style, update_variable, set_variable_mode, bind_variable_to_style)rgb(), hsl(), or oklch(); get_styles and export_tokens emit any of them via colorFormatThe official Figma MCP servers go through the REST API, which is rate limited per plan:
| Figma plan | REST budget |
|---|---|
| Starter | 6 calls/month |
| Professional | 200 calls/day |
| Enterprise | 600 calls/day |
This server never calls the REST API. It talks to a plugin running inside Figma Desktop over a local WebSocket, so every read and write is unlimited and free — and unlike REST, the plugin can write to the open file.
Measured on Apple M4 Pro: ~6 MB RSS idle, ~7 MB with a plugin connected during tool round trips; startup < 10 ms. The Go reference runs ~15–25 MB.
Claude Code CLI
claude mcp add -s project figma-mcp-rs -- npx -y figma-mcp-rs@latest
Or build from source:
make build # cargo build --release + plugin build
claude mcp add -s project figma-mcp-rs -- /path/to/figma-mcp-rs/target/release/figma-mcp-rs
Codex CLI
codex mcp add figma-mcp-rs -- npx -y figma-mcp-rs@latest
Claude Code plugin marketplace (also installs the 15 skills)
/plugin marketplace add <this-repo>
/plugin install figma-mcp-rs@figma-mcp-rs
.mcp.json (Claude and other MCP-compatible tools)
{
"mcpServers": {
"figma-mcp-rs": {
"command": "npx",
"args": ["-y", "figma-mcp-rs"]
}
}
}
.vscode/mcp.json (Cursor / VS Code / GitHub Copilot)
{
"servers": {
"figma-mcp-rs": {
"type": "stdio",
"command": "npx",
"args": ["-y", "figma-mcp-rs"]
}
}
}
Docker
docker build -t figma-mcp-rs .
docker run -i --rm -p 1998:1998 figma-mcp-rs
.mcp.json with Docker:
{
"mcpServers": {
"figma-mcp-rs": {
"command": "docker",
"args": ["run", "-i", "--rm", "-p", "1998:1998", "figma-mcp-rs"]
}
}
}
The image listens on 0.0.0.0:1998 (baked into the default CMD), so the Figma plugin connects to ws://127.0.0.1:1998 as usual through the port mapping — keep the host port at 1998 or update the host in the plugin UI. Run one container per plugin connection; for multiple simultaneous MCP clients on one machine prefer the native binary, whose leader election shares a single plugin connection. The self-installed plugin path inside the container is not host-accessible — import the plugin from this repo's plugin/ directory or the release plugin.zip instead.
Server flags: --ip (default 127.0.0.1), --port (default 1998).
The plugin is bundled inside the server binary — no download or build step.
manifest.json, dist/code.js, and dist/index.html to ~/.figma-mcp-rs/plugin/ (Windows: %USERPROFILE%\.figma-mcp-rs\plugin\) and logs the path.~/.figma-mcp-rs/plugin/manifest.jsonws://127.0.0.1:1998 (host/port configurable in the plugin UI)If a tool fails with plugin not connected, call get_status — it diagnoses the bridge and returns setup instructions.
Multiple server instances are safe: the first to bind the port becomes leader and owns the plugin connection; others become followers that proxy tool calls and take over automatically if the leader dies.
The plugin loads in every editor (editorType: ["figma", "figjam", "slides", "dev"]):
get_document/get_design_context serialize FigJam node types (STICKER, CONNECTOR, MARKER, WIDGET, EMBED, MEDIA…)create_sticky, create_stickies, create_connector, create_shape_with_text, create_table, create_code_block, auto_arrange, get_board_contentsfigma.teamLibrary.*, importVariableByKeyAsync), and anything else unwrapped: use use_figma| Tool | Description |
|---|---|
get_status | Check whether the plugin bridge is connected; returns setup instructions when it is not. Call this first if any tool fails with plugin not connected. |
| Tool | Description |
|---|---|
use_figma | Run Plugin API JavaScript inside the file. The code is the body of async () => { … }: top-level await works and only the return value comes back (console.log is discarded; the value must be JSON-serializable, so return IDs/counts/names, not node objects). Covers what the named tools don't wrap: Slides, component variants and properties, vector networks, styled text ranges, variable scopes, bulk edits in one round-trip. |
execute_code | Run arbitrary Plugin API code in the same sandbox — the code runs as an async function body, with an optional timeoutMs (1–25000 ms, default 5000) for long-running operations. Runs in the user's open file and is undoable with Cmd/Ctrl+Z. Use only for operations the dedicated tools don't cover; prefer the specific tool when one exists. |
| Tool | Description |
|---|---|
create_frame | Create a frame with optional auto-layout, fill, and parent |
create_rectangle | Create a rectangle with optional fill and corner radius |
create_ellipse | Create an ellipse or circle |
create_text | Create a text node (font loaded automatically) |
import_image | Decode base64 image and place it as a rectangle fill |
create_component | Convert an existing FRAME node into a reusable component |
create_section | Create a Figma Section node to organise frames on a page |
| Tool | Description |
|---|---|
set_text | Update text content of an existing TEXT or STICKER node |
set_fills | Set solid fill color (hex) on a node |
set_strokes | Set solid stroke color and weight on a node |
set_opacity | Set opacity of one or more nodes (0 = transparent, 1 = opaque) |
set_corner_radius | Set corner radius — uniform or per-corner |
set_auto_layout | Set auto-layout properties on one or more nodes — direction, padding, gap, alignment, wrap, HUG/FILL sizing, absolute positioning (Figma only) |
set_visible | Show or hide one or more nodes |
lock_nodes / unlock_nodes | Lock/unlock one or more nodes |
rotate_nodes | Set absolute rotation in degrees on one or more nodes |
reorder_nodes | Change z-order: bringToFront, sendToBack, bringForward, sendBackward |
set_blend_mode | Set blend mode (MULTIPLY, SCREEN, OVERLAY, …) |
set_constraints | Set responsive constraints on one or more nodes |
move_nodes | Move nodes to an absolute x/y position |
resize_nodes | Resize nodes by width and/or height |
rename_node | Rename a node |
clone_node | Clone a node, optionally repositioning or reparenting |
reparent_nodes | Move nodes to a different parent frame, group, or section |
group_nodes / ungroup_nodes | Group nodes into a GROUP / dissolve groups |
batch_rename_nodes | Bulk rename via find/replace, regex, or prefix/suffix |
find_replace_text | Find and replace text across TEXT nodes in a subtree or page; supports regex |
delete_nodes | Delete one or more nodes permanently |
| Tool | Description |
|---|---|
set_reactions | Set prototype reactions (triggers + actions); mode replace or append |
remove_reactions | Remove all or specific reactions by index |
| Tool | Description |
|---|---|
set_effects | Apply drop shadow / blur effects directly on a node |
create_paint_style / create_text_style / create_effect_style / create_grid_style | Create named local styles |
update_style | Update any style in place — paint color, text font/size/spacing, effects, grid — plus name and description |
bind_variable_to_style | Bind a variable to a style so the style itself is token-driven |
apply_style_to_node | Apply an existing local style to a node |
delete_style | Delete any style by ID |
| Tool | Description |
|---|---|
create_variable_collection | Create a new local variable collection with an optional initial mode |
add_variable_mode | Add a new mode to an existing collection (e.g. Light/Dark) |
create_variable | Create a variable (COLOR/FLOAT/STRING/BOOLEAN) in a collection |
set_variable_value | Set a variable's value for a mode — a literal or an alias to another variable |
update_variable | Rename a variable or collection; set description, scopes, Dev Mode code syntax; rename a mode |
set_variable_mode | Apply or clear a collection's mode override on a node or the current page |
bind_variable_to_node | Bind a variable to a node property (fills, strokes, size, spacing, …); omit variableId to unbind |
delete_variable | Delete a variable, an entire collection, or a single mode |
| Tool | Description |
|---|---|
add_page | Add a new page (optional name and index) |
delete_page | Delete a page by ID or name |
rename_page | Rename a page by ID or current name |
| Tool | Description |
|---|---|
navigate_to_page | Switch the active page by ID or name |
swap_component | Swap the main component of an INSTANCE node |
detach_instance | Detach component instances to plain frames |
| Tool | Description |
|---|---|
get_document | Full current page tree |
get_metadata | File name, pages, current page |
get_pages | All pages (IDs + names) — lightweight |
get_selection | Currently selected nodes |
get_node / get_nodes_info | One node / multiple nodes by ID |
get_design_context | Depth-limited tree with detail level (minimal/compact/full) |
search_nodes | Find nodes by name substring and/or type |
scan_text_nodes | All text nodes in a subtree |
scan_nodes_by_types | Nodes matching a type list |
get_viewport | Current viewport center, zoom, visible bounds |
get_reactions | Prototype reactions on a node |
get_fonts | Fonts used on the current page, sorted by frequency |
| Tool | Description |
|---|---|
get_styles | Paint, text, effect, and grid styles — with descriptions, publish state, bound variables, and colorFormat |
get_variable_defs | Variable collections, modes, values, aliases, scopes, and code syntax |
get_local_components | All components + component sets |
get_annotations | Dev-mode annotations |
export_tokens | Design tokens (variables + paint styles) as JSON or CSS, with alias var() references and colorFormat |
| Tool | Description |
|---|---|
get_screenshot | Base64 image export of any node |
save_screenshots | Export images to disk (server-side write) |
export_frames_to_pdf | Multiple frames as one multi-page PDF (server-side merge) |
| Tool | Description |
|---|---|
create_sticky | Create a sticky note with text (FigJam only) |
create_stickies | Create multiple sticky notes at once, with optional grid auto-layout (FigJam only) |
create_connector | Create a connector, optionally between two nodes (FigJam only) |
create_shape_with_text | Create a shape with text — rectangles, circles, diamonds, … (FigJam only) |
create_table | Create a table with optional cell text content (FigJam only) |
create_code_block | Create a code block with syntax highlighting (FigJam only) |
auto_arrange | Auto-arrange objects in grid, row, or column layout (FigJam only) |
get_board_contents | All objects and connectors on the current FigJam page, with text content and connection data |
read_design_strategy, design_strategy, text_replacement_strategy, annotation_conversion_strategy, swap_overrides_instances, reaction_to_connector_strategy, style_audit_strategy, bulk_rename_strategy, design_token_generation_strategy, generate_color_palette, generate_type_scale, generate_component_variants
skills/ ships the 12 prompts as Claude Code skills plus bridge-troubleshooting (connection diagnostics), figjam-boards (FigJam stickies, shapes, tables, connectors, auto-arrange), and editor-compatibility (Figma/FigJam/Slides tool matrix). Installed automatically via the plugin marketplace; otherwise copy skills/ into your project's .claude/skills/.
make test # cargo test + plugin bun test
make build # release binary + plugin dist
CI: fmt + clippy + tests (linux amd64/arm64, windows, macos) + plugin typecheck/test/build on every PR.
Releases: conventional commits (feat:, fix:) on main → release-please opens a version-bump PR (Cargo.toml, Cargo.lock, npm/package.json, CHANGELOG); merging it tags vX.Y.Z and the same workflow builds the five binaries + plugin.zip, publishes npm, and pushes the multi-arch image to ghcr.io/jirayusueb/figma-mcp-rs. Re-run a release build for an existing tag with gh workflow run "Release please" -f tag=vX.Y.Z.
Server: Rust (tokio, axum, rmcp). Plugin: TypeScript + SolidJS, built with Vite (UI inlined to dist/index.html, core IIFE dist/code.js).
Toolchain: Bun 1.4.2, TypeScript 7.
The wire protocol (bridge WebSocket frames, follower /rpc) is kept compatible with the Go reference, so this server also works with the original figma-mcp-go plugin.
Fork of the architecture and tool design of figma-mcp-go by vkhanhqui — ported to Rust with a SolidJS plugin and FigJam support.
MIT
FAQs
A zero-cost, unlimited Figma/FigJam MCP server in Rust — no API key, no rate limits
The npm package figma-mcp-rs receives a total of 201 weekly downloads. As such, figma-mcp-rs popularity was classified as not popular.
We found that figma-mcp-rs demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
It has been one year since Shai-Hulud made its first appearance on npm.

Research
/Security News
Operators behind PolinRider used a compromised GitHub account to plant malware in four development versions of a Packagist package with 700,000+ downloads.

Security News
GitHub Actions now supports cache-mode, a least-privilege control on the Actions cache aimed at the cache poisoning technique behind recent compromises.