The full upstream README, mirrored here for reference. Install config, tool schemas, adoption signals, and an original overview live on the Figme listing page.
.fig files from an AI agentfigme is an MCP server that lets an AI agent read
everything inside a local .fig / .figma file — document structure, geometry, fills,
strokes, effects, auto-layout, text (including mixed-format runs), components and instances,
variables, prototype links and embedded bitmaps.
It is fully offline. No Figma account, no access token, no REST API, no network at runtime.
It parses the file's own bytes, using the Kiwi schema that Figma ships inside every .fig.
It is also token-aware: the reference file used to develop it holds 116,142 nodes, and no tool response ever exceeds ~20 KB. Everything is shallow by default, filterable, and paginated with cursors.
These are deliberate, permanent limits — not missing features:
.fig contains no rendered pixels of your
frames, but it does contain everything needed to draw them again: Figma bakes outlined
strokes, combined booleans, per-glyph outlines and per-instance geometry into the file at save
time. fig_render uses that to produce a real picture offline — see
Rendering for exactly what is exact and what is approximated. It is
not a screenshot of Figma and never will be: read the report before trusting fine detail..fig. The only write paths in the whole
server are fig_image { savePath } and fig_render { savePath }, which write to a path you
name.assetRef so you can see that they exist and where they point.fig_node reports the blob indices and fig_blob hands you the raw bytes, but this server
does not interpret them..fig is a full snapshot, not a delta.zlib.zstdDecompressSync; developed on Node 24).@modelcontextprotocol/sdk and zod. The parser itself uses only
Node built-ins.figme is published on npm, so there is nothing to clone and nothing to build — your MCP
client downloads it on first start with npx.
You need two things:
.fig file on disk. This server reads a local file and never contacts figma.com, so
there is no account, token or sign-in — but there is also nothing to read until you save
one. In Figma: File -> Save local copy....Nearly every MCP client spawns a stdio server from the same two fields:
On Windows, some clients cannot resolve npx on their own. If the server fails to start,
route it through cmd:
Or commit a .mcp.json at the repository root so collaborators get it too:
The Claude Code extensions for VS Code and JetBrains run Claude Code underneath and share its configuration: register the server once with the command above and the extension sees it. They do not read the editor's own MCP settings.
~/.cursor/mcp.json for every project, or .cursor/mcp.json for a single one:
VS Code uses its own key, servers rather than mcpServers, in .vscode/mcp.json:
The same entry works in your user settings.json under "mcp". From a terminal:
Then pick Agent mode in the Chat view.
~/.codeium/windsurf/mcp_config.json:
Spawn npx -y figme-mcp and talk MCP over stdio.
Client UIs and config paths move between releases. The
commandandargspair above is the stable part; if a path here does not match what you see, check that client's own MCP documentation.
Use absolute paths. A file argument may be relative, but it resolves against the server's
working directory — whichever directory your client happened to launch it from. An absolute
path removes the guesswork:
Using figme, run
fig_overviewon /Users/me/Desktop/design.fig
Watch memory. --max-files N (default 4) caps how many parsed files stay cached. A 39 MB
.fig decodes to roughly 900 MB of live objects, so lower it on a small machine and raise it
only with memory to spare:
The usual job: implement this component from our design, starting from a link someone pasted into a ticket.
This server reads a .fig on your disk and never contacts figma.com, so a link by itself is not
enough. Open it in Figma and use File -> Save local copy.... For a Community file, click
Open in Figma first — that duplicates it into your drafts, which is what makes the copy
possible.
Figma writes node ids with a dash in links; the .fig format uses a colon, so
node-id=3017-121 is guid 3017:121. You do not have to convert it yourself — every guid
argument accepts all of these:
| You pass | Server reads |
|---|---|
3017:121 | 3017:121 |
3017-121 | 3017:121 |
3017%3A121 | 3017:121 |
node-id=3017-121 | 3017:121 |
the whole https://www.figma.com/design/...?node-id=3017-121 | 3017:121 |
Anything else is passed through untouched, so a typo still fails loudly rather than being guessed at.
The file key is a cloud identifier with no counterpart in the saved file, so nothing can work
out which local .fig a link refers to. Always give the path yourself.
Using figme, read
/abs/path/UX Case Study Template.figand implement node3017:121as a React component.
A good agent then works roughly in this order:
fig_render — see it. The fastest orientation there is; check the approximated and
unsupported lists before trusting fine detail.fig_node — size, corner radii, auto-layout, constraints, children.fig_style — resolved fills, strokes, effects and typography, already shaped for code.fig_text — the exact copy, including per-run styling.fig_instance — if the node is an INSTANCE, what it came from and what is overridden.
This is what decides reusable component against one-off.fig_variables — token names, so the code references your theme instead of raw hex.fig_render again, and compare it against a screenshot of what you built.That last step is why the renderer exists: you get a pixel oracle, not just a description.
Node ids are intrinsic to the document, so the id in the link should be the id in the saved
file. If it is reported missing anyway you are most likely in the wrong file — compare
fig_overview's document name with the link's slug — or find the layer by name with fig_find,
or browse the page with fig_tree.
A Figma URL is auth-gated and rendered by JavaScript, so fetching it yields nothing useful. Worse, the slug reads like a description, which is enough for a model to invent a plausible component and present it with confidence. The server says as much to every agent at connect time; if yours reaches for the web regardless, tell it not to.
For development, or to run a revision that is not published yet:
Register node /abs/path/to/figme-mcp/dist/mcp/server.js in place of npx -y figme-mcp. This
repository ships a .mcp.json that already does so for Claude Code.
Every tool takes file (path to the .fig). Node references are guid strings of the form
"sessionID:localID", e.g. "2:1339". Responses that were cut set truncated: true and return
an opaque nextCursor you can pass back.
The intended workflow: fig_overview → fig_tree a page → fig_node / fig_style a guid,
with fig_find to jump straight to something by name or copy, and fig_render whenever seeing
the thing is faster than reading it.
fig_overview — orient yourselfDocument name, export date, format version, node counts by type, the page list, and how many components / variables / images the file holds.
fig_tree — explore structureroot (default DOCUMENT), depth (default 2, max 6), types filter, format, cursor.
Returns a flat list in document order; each entry has depth (relative to the root) and
parent, so the hierarchy is reconstructable, plus children (a count) so you can see where
it is worth going deeper.
format: "outline" is roughly 4× denser than JSON and is the best way to browse.
fig_node — inspect one nodedetail is summary, full (default) or raw.
detail: "raw" returns the decoded Figma record verbatim (bytes as hex, int64 as strings). It
is the forward-compatibility escape hatch: anything the mappers do not understand yet is still
reachable there. Limited to one node per call.
fig_find — search names and copyquery (case-insensitive substring, matched against layer names and text content), plus
optional types, scope, limit, cursor. Omit query to list all nodes of some types.
fig_text — copy inventoryAll text in the file or in one scope, in document order, with a compact style block.
includeRuns: true adds the styled runs — the mixed-format spans Figma stores per UTF-16
code unit — each showing only the fields it overrides.
fig_style — resolved style, shaped for codeAuto-layout translated into CSS flexbox terms, paints as hex, typography flattened, plus how the node behaves inside its parent's layout.
For TEXT nodes it also returns typography and resolves shared text/fill styles to the values
they define (styles.text.defines).
fig_components — the component catalogueSYMBOL nodes with their component set, property definitions and defaults, and instance counts — most-used first, so the load-bearing parts of the design system come back first.
fig_instance — how an instance differs from its componentAn instance that sets component properties reports them with the names resolved, e.g.
propAssignments: [ { "defID": "108:1543", "name": "text", "type": "TEXT", "value": "Back" } ].
A path segment is the target's overrideKey when it has one and its guid otherwise, and a
nested path is walked through swapped instances exactly as the renderer expands them.
fig_variables — design tokensEvery collection with its modes, and every variable with a value per mode. Alias chains are followed when the target lives in the same file.
fig_image — embedded bitmapsPass hash (the 40-hex id that fig_node / fig_style report on image paints), or guid to
use the images on a node, or hash: "thumbnail" for the document preview. Images ≤ 2 MB come
back as viewable image content; larger ones return metadata, and savePath writes the exact
bytes to disk.
fig_blob — raw payload bytesindex into the file's blob table (fig_node reports these as vector.networkBlob /
vector.fillBlobs), encoding (base64 | hex), maxBytes (default 65536).
fig_render — a picture of a nodeguid (any node, or a page), format (png | svg, default png), scale (default 2),
maxSize (longest edge, default 1568), background (transparent | page), savePath,
maxNodes (default 20000, counted in layers).
fig_render)Nothing is fetched and no font is needed: Figma stores outlined strokes, combined booleans,
per-glyph outlines and per-instance resolved geometry in the file, so the renderer consumes
what Figma already computed. The SVG it builds is rasterized by
@resvg/resvg-wasm, an optional dependency — with it
uninstalled, everything still works and fig_render returns SVG instead of PNG.
Exact: solid fills, linear and radial gradients, image fills in all four scale modes, strokes including inside/outside alignment, boolean operations, text (glyph outlines, per-run colours, underline and strikethrough, truncation with an ellipsis), component instances with their overrides, their component properties (text, visibility, instance swap) and the sizes the enclosing instance gives them, colour and effect styles resolved to their live definition, frame clipping, layer opacity, the fifteen shared blend modes, drop and inner shadows, layer blur, and all three mask types.
Approximated, and always reported: background blur (drawn flat — a backdrop filter cannot
see behind an isolated subtree), LINEAR_DODGE and LINEAR_BURN (drawn as screen and
multiply), angular and diamond gradients (drawn as their average colour), image crop and
image rotation.
Skipped, and always reported: emoji glyphs, FigJam-style nodes (WIDGET, CONNECTOR,
SHAPE_WITH_TEXT), text without stored outlines (including a text property whose words have
no outlines in the file), and strokes on text.
Fidelity was measured against a Figma export of a 1440×3026 form built from component
instances: 0.18 % of pixels differ, all anti-aliasing. That export came from a design that
is not public, so it is not distributed here — npm run visual runs levels 1-2 until you
supply your own export.
Every response carries unsupported and approximated lists naming the feature and up to five
example guids. An empty pair means the renderer believes it drew the node exactly. Exact values
always remain available from fig_node, fig_style and fig_text.
There is also a CLI for the same thing:
raw node per call.#RRGGBB, and
sizes collapse to "134x40".truncated: true and returns an opaque nextCursor; paging is stable
because it follows document order.The decisive detail is Stage D: the schema ships inside the file. Nothing here hardcodes a field id, so Figma's constant schema additions do not break the reader.
mcp/ and model/ never touch bytes; fig/ knows nothing about Figma semantics.
figma-input/sample.fig and assert measured values (116,142
nodes, 638 schema definitions, 10 pages, specific node geometry, …). They skip with a clear
message if the asset is absent.docs/ and in the
golden tests were replaced with neutral stand-ins, and node guids were renumbered. The
structure and the measured numbers are real; the names are not, so the string assertions
will not match your own .fig until you update them.kiwi-schema package and
deep-compares every field: currently 0 differences across 17,353,242 compared values. It
skips cleanly if kiwi-schema is not installed.tools/fig2json.mjs is the original dependency-free reference CLI that Layer 1 was ported from.
It is kept working as a debugging aid:
Dumping schema.kiwi.txt is the fastest way to look up a field this server does not map yet;
then read it with fig_node detail:"raw".
docs/fig-reading-solution.md — the byte-level reading
procedure, verified end to end.docs/mcp-implementation-plan.md — the plan this server
implements, including the golden values in Appendix A.docs/fig-file-format.md — the measurement log and evidence.MIT.