OPEN SOURCE DEEP DIVE
Framelink MCP for Figma: design files compressed into usable context, not screenshots
Also known as Figma-Context-MCP, npm package figma-developer-mcp, TypeScript, MIT, and a third-party implementation rather than the Dev Mode MCP server Figma ships itself. It exposes only two tools: get_figma_data (read-only) and download_figma_images (removable with –skip-image-downloads, and confined to writing inside –image-dir). The narrow surface is deliberate; the engineering sits in the fetch → simplify → serialize pipeline behind it. Simplify uses composable extractors (layout, text, visuals, component, plus the allExtractors, layoutAndText, contentOnly, visualsOnly and layoutOnly bundles) to compress the raw Figma response into semantic layout and styling in a single tree walk, with maxDepth and nodeFilter, and outputs tree (default, cheapest in tokens), yaml or json. The part worth copying is that compression effectiveness is a metric computed on every call: rawSizeKb against simplifiedSizeKb, rawNodeCount against simplifiedNodeCount, component/instance/text/image node counts, namedStyleCount (the source comment states a high count is a design-system maturity signal), hasVariables (whether Figma Variables are used at all), and separate fetch/simplify/serialize timings; the same hooks drive MCP progress notifications and heartbeats so a large file taking tens of seconds does not look hung. Judgement shows in the details: node IDs accept both the plain and the deeply nested instance shape, the depth parameter description says do not use it unless the user explicitly asks, the proxy default deliberately avoids installing EnvHttpProxyAgent when no proxy variables exist so a stale variable cannot route traffic through an intermediary returning 403, and stdio mode warns at startup when –image-dir is unset. Credentials come from FIGMA_API_KEY or FIGMA_OAUTH_TOKEN; telemetry can be disabled with –no-telemetry or DO_NOT_TRACK=1 and secrets are redacted from reports. 15.9k stars. It generates no frontend code - the output is design facts, and translating them into React, Vue or SwiftUI is your coding agent job. We have not run it against a Figma file of our own and did no screenshot-versus-structured-data accuracy comparison, so it is graded as pending reproduction.
What it is
Framelink MCP for Figma (repo GLips/Figma-Context-MCP, npm package figma-developer-mcp) is a TypeScript MCP server under the MIT licence with a single job: hand Figma design data to a coding agent so it can implement the design in any framework in one shot. The README's core claim is blunt - with structured Figma data available, an agent one-shots designs far more accurately than with alternatives such as pasting screenshots.
It exposes only two tools: get_figma_data (read-only, annotated readOnlyHint) and download_figma_images (annotated openWorldHint, and removable entirely via --skip-image-downloads). That narrow surface is deliberate. The engineering effort here is not in having more tools but in the pipeline behind these two: compressing the raw Figma API response into context a model can actually use.
The core mechanism: one tree walk, composable extractors
get_figma_data runs fetch → simplify → serialize, and the same code serves both the MCP tool and the CLI's fetch subcommand. All the value is in simplify:
| Layer | Implementation | Purpose |
|---|---|---|
| Strategy | layoutExtractor / textExtractor / visualsExtractor / componentExtractor, plus the bundles allExtractors, layoutAndText, contentOnly, visualsOnly, layoutOnly | Decides what this call needs; copy audits take text only, design systems take visuals only |
| Traversal | A single tree walk (node-walker) with maxDepth and nodeFilter | The tree is walked once no matter how many extractors are attached; depth and node type can be clipped |
| Extraction | Pure functions turning one node's raw fields into a simplified shape, finished by collapseSvgContainers | Collapses Figma's verbose representation into semantic layout and style |
Output comes in three formats - tree (default), yaml, json - set by --format or the OUTPUT_FORMAT variable, with --json kept as a back-compat alias for --format=json. An invalid value fails loudly at startup instead of being coerced silently. Tree is the default rather than JSON because it carries the same information in fewer tokens.
What it measures about itself
The part worth copying is that "did the compression work" is a metric computed on every call (GetFigmaDataMetrics) rather than a slogan:
- Compression ratio:
rawSizeKbagainstsimplifiedSizeKb,rawNodeCountagainstsimplifiedNodeCount. The first pair describes how complex the tree the user asked about is; the second describes the payload actually sent to the model. - Structural profile:
componentCount,instanceCount,textNodeCount,imageNodeCount(derived by looking upglobalVars.stylesentries whose fills include IMAGE or PATTERN),componentPropertyCount,maxDepth. - Design-system maturity:
namedStyleCountcounts reusable styles the user created in Figma's Styles panel, and the source comment says outright that a high count is a design-system maturity signal;hasVariablesreports whether any node carriesboundVariables, i.e. whether Figma Variables are in use at all. - Timing breakdown:
fetchMs,simplifyMsandserializeMsare recorded separately, so a slow call names its own bottleneck.
Those same hooks solve an agent UX problem. The pipeline emits MCP progress notifications at each phase boundary (0/3 fetch, 1/3 simplify, 2/3 serialize) plus heartbeats reading "Waiting for Figma API response" and "Simplifying design data (N nodes processed)", so a large file taking tens of seconds does not look like a hung client.
Judgement calls buried in the engineering
- Node IDs have two shapes. The plain
1234:5678, and the deeply nested instance formI5666:180910;1:10515;1:10336- the semicolon-joined chain is an instance override path and still one node ID, not several. The parameter schema's regex accepts both, and the handler converts-into the:the Figma API expects. - The
depthparameter's description says "do NOT use unless explicitly requested by the user". That is tool-description-as-behaviour-constraint, stopping the model from quietly fetching a shallow slice and then writing code from incomplete information. - The proxy default is a safety decision. An explicit proxy URL installs
ProxyAgent; without one,EnvHttpProxyAgentis installed only if proxy variables actually exist; otherwise Node's default is used. The source comment explains the intent - never installingEnvHttpProxyAgentwhen no proxy vars are present keeps a stale shell variable or a VPN client's leftover from silently routing api.figma.com traffic through an intermediary that returns 403.--proxy=noneopts out explicitly. - It warns about where images land. In stdio mode with no
--image-dir, startup writes a warning to stderr, because MCP clients spawn the server with a cwd that is rarely your project root, so images would otherwise be saved into the client's install directory. The download tool will only write inside--image-dir. - Credentials and telemetry. Either
FIGMA_API_KEY(personal access token) orFIGMA_OAUTH_TOKEN. stdio has no per-request credential channel, so credentials must resolve at startup and the server fails fast if they do not - deliberately before side effects such as installing the proxy dispatcher or initialising telemetry. Telemetry is on by default and can be disabled with--no-telemetry,FRAMELINK_TELEMETRY=offorDO_NOT_TRACK=1, and error reports redact the API key and OAuth token.
Boundaries: not official Figma, and it writes no code
Three things need separating. Figma itself ships a Dev Mode MCP server inside the desktop app, using Figma's own account model and selection semantics. Framelink is a third-party open-source implementation that needs nothing but a personal access token against the Figma REST API; the upside is that any MCP-capable client can use it and you can change the extraction strategy yourself, the downside is that you do not get the official depth of integration with selection and code connect. And Figma Make is Figma's own product for going from a prompt straight to a running interface - a different path entirely: one generates for you, this one hands the design facts to your agent so it can generate.
This project also writes no frontend code. Its output is a structured description of the design; turning that description into React, Vue or SwiftUI is your coding agent's job. "Better at one-shotting designs" is the README's qualitative claim - it ships no benchmark numbers, and we ran no comparison.
Where it sits on agientry
On the design shelf we already list v0 and lovable, the "prompt to deployable interface" products, and ui-ux-pro-max-skill, which makes an agent better at producing interfaces on its own. Framelink covers the segment in between: how an existing design file enters agent context without loss. In companies that segment is often the expensive one - the design system is already settled in Figma, and rewriting the frontend around it is the waste. The contrast with img2threejs is equally clean: that one turns an image into 3D scene code, this one turns a vector design file into UI facts, and both are solving how a visual input becomes an executable structured input.
Facts on this page come from the project README (read in full) and the repository source: src/mcp/index.ts (tool registration and annotations), src/mcp/tools/get-figma-data-tool.ts (parameter schema and progress hooks), src/services/get-figma-data.ts (the three-phase pipeline), src/services/get-figma-data-metrics.ts (metric definitions), src/extractors/README.md (extractor architecture), src/bin.ts, src/config.ts and src/server.ts (transport, credentials, proxy, telemetry); stars, licence and language come from the GitHub API. We have not run it against a Figma file of our own, have not measured its compression ratio, and have not run a screenshot-versus-structured-data accuracy comparison, so this entry is recorded as pending reproduction.