Skip to main content
Any Framework

Offline MCP server for reading local Figma .fig files without the Figma API or a token. Lets an AI agent extract structure, layout, colors, typography, text and embedded images so it can reproduce a design. Parses the Kiwi-based .fig binary directly. Pure managed (no native dependencies). Not affiliated with Figma, Inc.

Published
Jul 30, 2026
2mo ago
Total Downloads
414
414

Install

dotnet add package Zafiro.FigReader.Mcp --version 0.0.4

No framework information available.

README

Zafiro.FigReader.Mcp

An offline MCP server that reads local Figma .fig files so an AI agent can inspect and reproduce a design — structure, layout, colors, typography, text and embedded images — without the Figma API, an account or a token. Think Framelink, but it parses the exported .fig binary directly instead of calling Figma's servers.

Why

The Figma REST API is free but requires a token and an internet round-trip, and Framelink-style tools stream large payloads. Zafiro.FigReader.Mcp works on a .fig you exported yourself (Figma → File → Save local copy…), fully offline, and returns compact, token-efficient JSON.

How it works

A .fig file is a ZIP containing canvas.fig (+ meta.json, thumbnail.png, images/, videos/). canvas.fig is Evan Wallace's Kiwi binary format:

"fig-kiwi" (8 bytes) | uint32 version | chunk0 | chunk1 | ...
chunk = uint32 length + payload
chunk0 = Kiwi binary schema (raw DEFLATE) — self-describing
chunk1.. = Kiwi message (raw DEFLATE or Zstandard) → root type "Message"

The message holds a flat list of nodeChanges (Figma's CRDT model); Zafiro.FigReader.Mcp rebuilds the node tree from each node's parentIndex (parent GUID + fractional position). The Kiwi decoder is a clean-room port of evanw/kiwi; Zstandard is handled by ZstdSharp.Port. No native dependencies.

Build & test

dotnet build -c Release
dotnet test                                   # unit tests (no sample needed)
FIGMA_SAMPLE_FIG=/path/to/file.fig dotnet test # also runs the integration tests

Install

Published as a .NET tool on NuGet (requires the .NET 10 SDK/runtime):

# Install globally...
dotnet tool install -g Zafiro.FigReader.Mcp
# ...then run:
figreadermcp

# ...or run without installing:
dnx Zafiro.FigReader.Mcp

The server speaks MCP over stdio (logs go to stderr, so stdout stays clean for the protocol).

MCP client configuration

VS Code (.vscode/mcp.json)

{
  "servers": {
    "figma": {
      "type": "stdio",
      "command": "dnx",
      "args": ["Zafiro.FigReader.Mcp", "--yes"]
    }
  }
}

Claude Desktop (claude_desktop_config.json)

{
  "mcpServers": {
    "figma": {
      "command": "dnx",
      "args": ["Zafiro.FigReader.Mcp", "--yes"]
    }
  }
}

If you installed the tool globally you can instead use "command": "figreadermcp" with no args.

Build from source

dotnet build -c Release
dotnet src/Zafiro.FigReader.Mcp/bin/Release/net10.0/Zafiro.FigReader.Mcp.dll

(Avoid dotnet run for MCP: its first-run build output can corrupt the stdio protocol.)

Tools

Tool Purpose
load_file(path) Decode a .fig and return a summary (file name, pages, node-type histogram, blob count). Call first; result is cached.
get_metadata(path?) meta.json + high-level counts.
get_node_tree(nodeId?, depth?, path?) Compact hierarchy (id, name, type, bounds, fills, strokes, auto-layout, text). INSTANCE nodes are expanded to the symbol content they render, with overrides applied (effective text, per-node visibility, icon instance-swaps as swappedTo).
get_node(nodeId, raw?, path?) Full detail for one node. For an INSTANCE, resolvedChildren lists the effective labels, icons (swappedTo) and visibility. Set raw=true for the unfiltered Kiwi object.
get_text(nodeId?, path?) All text content + typography under a subtree.
get_styles(path?) Colors actually used (with counts) and distinct text styles.
get_vector(nodeId, geometry?, path?) Decode a node's vector geometry into SVG path(s) (with an F0/F1 fill-rule prefix, ready for an SVG d/Avalonia StreamGeometry). Pass geometry="strokeGeometry" for the stroke outline.
list_images(path?) Embedded image/video blob entries.
export_image(entry, outputDirectory, path?) Extract a blob to disk.
search_nodes(query, type?, limit?, nodeId?, path?) Find nodes by name, text, or instance overrides; optionally scoped to a subtree such as a page.

Node ids use the form sessionID:localID. Tools other than load_file default to the most recently loaded file when path is omitted.

Instances

Figma stores an INSTANCE as a reference to a SYMBOL plus a set of overrides, so instances carry no child nodes of their own. get_node_tree/get_node resolve that for you: they walk the referenced symbol and apply symbolOverrides (text, visibility, …) and componentPropAssignments (text component properties and instance-swaps — e.g. an icon). Nested instances are resolved recursively, so an icon inside a tab inside a tab-menu is surfaced as the actual component it renders.

Example

// get_node_tree on a button symbol
{
  "id": "5:326", "name": "Button/Primary", "type": "SYMBOL",
  "width": 199, "height": 48, "fills": ["#2730E9"],
  "layout": { "mode": "HORIZONTAL", "gap": 16, "padding": [8,40,8,32],
              "primaryAlign": "CENTER", "counterAlign": "CENTER" },
  "children": [
    { "id": "5:322", "name": "Button Text", "type": "TEXT",
      "text": { "characters": "Button Text", "fontFamily": "SF Pro Display",
                "fontStyle": "Semibold", "fontSize": 18, "color": "#FFFFFF" } }
  ]
}

Layout

src/Zafiro.FigReader.Core      Kiwi decoder, .fig container reader, document model, extraction
src/Zafiro.FigReader.Mcp    MCP stdio server + tools
tests/Zafiro.FigReader.Core.Tests

Limitations

  • The Kiwi schema is reverse-engineered; if Figma changes the format, extraction may need updates (the embedded schema keeps basic decoding working across versions).
  • Instance resolution covers text/visibility overrides and text/instance-swap component properties; exotic property kinds (variables, exposed nested props) are surfaced only partially.
  • Large files take a few seconds to decode on first load (then cached in memory).

License

MIT — see LICENSE.

The Kiwi binary decoder is a port of evanw/kiwi (MIT). Third-party licenses and attributions are listed in THIRD-PARTY-NOTICES.md.

"Figma" is a trademark of Figma, Inc. This project is not affiliated with, endorsed by, or sponsored by Figma, Inc.

Changes from Previous Version

No structural changes between v0.0.3 and v0.0.4.

Adoption Assessment

Assess this package against its supported frameworks, license, maintenance signals and dependency graph before making it a project standard.

No target framework metadata is available. Confirm compatibility in a representative project before standardising on this package.

Related Guides & Workflows

Learn how to evaluate, integrate, or audit this package in your .NET project.