figma-jev-console
This server bridges a running coded app and Figma in both directions — it pushes app routes into Figma as auto-layout frames, then writes your Figma edits back into the exact source lines, live.
Check connection & session state (
jev_status): Jev Bridge plugin, model backend, live sessions, screens and pending reviews.Push an app into Figma (
jev_push_screens): give it a project folder and dev-server URL and it renders each route, rebuilding screens, components and variants as auto-layout frames — with optional route list, viewport (1440x900 or 390x844 mobile), target page, and live-sync toggle.Sync both ways (
jev_sync_now): flush all queued Figma edits into code, then redraw every Figma screen from the code.Handle edits that need a decision (
jev_list_pending,jev_resolve_pending): see unrouted or design-token edits and choose apply / reject / element / token / llm / done.Hand leftovers to an LLM (
jev_changelog,jev_progress): get a ready-made brief for deletes, moves, reorders and expression-driven variants, then report fine-tune steps back to the designer's Figma panel.Inspect and debug the sync (
jev_sync_log,jev_locate,jev_contract): recent edits with file:line and who decided, source location for a layer code like@a3.0.2.1, and the supported CSS ↔ Figma property table with sync directions.Stop watching (
jev_stop_live): end the live session and close the headless browser, leaving Figma layers intact.Run raw Figma Plugin API code (
jev_execute) as an escape hatch inside the Jev Bridge plugin.
Provides a two-way bridge between a running app and Figma, allowing screens to be pushed into Figma as auto-layout frames and Figma design edits to be written back to the app's source code in real time.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@figma-jev-console Push the app's current screen into Figma as auto-layout frames."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Figma JEV Console MCP
A live, two-way bridge between your running app and Figma. Push the screens of a coded app into Figma as auto-layout frames. After that, a change you make in Figma is written into the code about 150 ms later, and a change in the code updates the same Figma frames in place.
Figma JEV Console MCP is a fork of Figma Console MCP by Southleft. It keeps the parts that made that project work well: an MCP server, a Figma Desktop plugin that talks to it over a local WebSocket, a stable plugin install path, and an escape hatch for raw Plugin API code. It adds one thing the original does not do: it treats the app's code and the Figma file as one design, and keeps them in sync while you work.
What is this?
It connects Claude (or any MCP client) to Figma and to your app's source code:
📥 Code → Figma push. Each route of a running app is rendered in headless Chrome and rebuilt in Figma: every container is an auto-layout frame, sizes are hug / fill / fixed as the CSS says, and coded components become Figma components with variants.
✏️ Figma → code, live. Change padding, gap, direction, alignment, sizing, fills, text, type, radius, borders, shadows or opacity in the Design panel, and the edit lands in the right file and line: a Tailwind class, a CSS declaration, an inline style, a JSX string or a component prop at its usage site. Your dev server's hot reload shows it.
🔁 Code → Figma, live. Edit the code (you or Claude) and the Figma screens update in place. Layer ids, comments, prototype links and layers the designer added survive.
🧱 New layers become code. Draw a frame, text, shape, vector or instance inside a pushed screen and it is written into the code; a component made in Figma gets its own file. Deleting, reordering and moving linked layers is written too.
💸 No Claude tokens for small edits. Rules write the edits. A small local model (Kev-0.8B, runs on your Mac) only settles ties, such as two code lines that match a layer equally well.
🤖 Fine-tune with LLM. Anything the rules cannot write is collected in a changelog. One button in the plugin hands it to the Claude session running the server, and the plugin shows Claude's progress.
🎨 Design-system build skill.
figma-system-buildbuilds or tidies screens in Figma with every color, text style, spacing, radius and icon bound to variables.
Related MCP server: Sunnyside Figma MCP
How it differs from Figma Console MCP
Figma Console MCP | Figma JEV Console MCP | |
Main job | Give AI full access to Figma: extraction, creation, tokens, audits, debugging | Keep a running app and its Figma screens in sync, both ways |
Source of truth | The Figma file | The app's code and the Figma screens, kept equal |
Code → Figma | Tokens and components via tools | Whole screens, rendered from the running app, as auto-layout frames |
Figma → code | Token export and sync | Every Design-panel edit written to the exact source line, live |
Figma plugin | Figma Desktop Bridge, ports 9223–9232 | Jev Bridge, ports 9340–9344 |
Stable plugin path |
|
|
Models | None needed | Optional local tie-breaker (Kev-0.8B, MLX); Claude only on request |
Tool count | 120+ | 12, focused on sync |
The two run side by side without conflict: different plugin, ports, server name and skills. Use Figma Console MCP to explore a file, manage variables or audit a design system; use Figma JEV Console MCP when the screens already exist as code and you want to design on top of them.
✅ Works with
Status | |
Vite + React + Tailwind CSS v3/v4 | Tested (end-to-end test suite) |
Plain HTML + CSS | Tested (end-to-end test suite) |
Vite + vanilla JS with CSS files | Used on a real app |
Next.js, Remix, Vue, Svelte, Angular | Not tested yet. The capture works on any page Chrome can render; writing edits back relies on finding the element in the source, which should work for JSX and HTML-like templates but is unproven. Reports welcome. |
CSS-in-JS (styled-components, Emotion), CSS Modules | Not tested. Edits the rules cannot place go to the changelog. |
macOS (Apple Silicon) | Tested, including the local model |
macOS (Intel), Windows, Linux | Server not tested; the local model does not run there (rules only). |
⚡ Quick start
Prerequisites
Figma Desktop (the plugin needs it; the web app cannot reach localhost)
Node.js 20+, Google Chrome and git
Claude Code, or another AI coding assistant with MCP support (Cursor, Windsurf, Claude Desktop)
For the local model: a Mac with Apple Silicon, about 2 GB of disk and 1.5 GB of free memory. Without it, everything still works on rules; ties wait for your review instead.
Install with one prompt
Paste this into Claude Code (or your AI coding assistant). It installs everything and hands you the file to load in Figma.
Install Figma JEV Console MCP for me (https://github.com/anuragfolio/figma-jev-console-mcp).
1. Check that Node.js 20 or newer, git and Google Chrome are installed. If one is missing,
stop and tell me how to install it.
2. Clone the repository into ~/figma-jev-console-mcp (if the folder exists, run git pull
there instead), then run npm install in it.
3. Register the MCP server under the name figma-jev-console so it starts with my AI client.
In Claude Code run:
claude mcp add figma-jev-console -s user -- node ~/figma-jev-console-mcp/bin/figma-jev-console-mcp.js
(use the full path of my home folder). For another client, add the same command to its MCP
config file.
4. If you are Claude Code, copy the folders in ~/figma-jev-console-mcp/skills/ into
~/.claude/skills/.
5. Run: node ~/figma-jev-console-mcp/bin/figma-jev-console-mcp.js --setup
It prints the path of the Figma plugin's manifest.json. Show me that full path, and open
the folder that contains it (macOS: open -R <path>, Windows: explorer /select,<path>).
6. Tell me the last steps: in Figma Desktop choose Plugins → Development → Import plugin
from manifest…, pick that manifest.json, then run Plugins → Development → Jev Bridge.
Restart the AI client so it loads the new MCP server.The plugin's manifest.json lives at ~/.figma-jev-console/plugin/manifest.json. The server
refreshes that copy every time it starts, so the path never changes.
Not on npm yet. Clone and install:
git clone https://github.com/anuragfolio/figma-jev-console-mcp.git ~/figma-jev-console-mcpcd ~/figma-jev-console-mcp && npm installAdd it to Claude Code, either as a Claude Code plugin (MCP server + both skills):
claude plugin marketplace add anuragfolio/figma-jev-console-mcpclaude plugin install figma-jev-console@figma-jev-consoleor as an MCP server only:
claude mcp add figma-jev-console -s user -- node ~/figma-jev-console-mcp/bin/figma-jev-console-mcp.jsCursor / Windsurf / Claude Desktop: add to your MCP config file:
{
"mcpServers": {
"figma-jev-console": {
"command": "node",
"args": ["/Users/you/figma-jev-console-mcp/bin/figma-jev-console-mcp.js"]
}
}
}Write the Figma plugin files and print the manifest path:
node ~/figma-jev-console-mcp/bin/figma-jev-console-mcp.js --setupIn Figma Desktop: Plugins → Development → Import plugin from manifest…, pick that
manifest.json, then run Plugins → Development → Jev Bridge. It finds the server on
ports 9340–9344.
Plugin updates. Figma caches plugin files. After updating (
git pull), close and reopen Jev Bridge to load the newcode.jsandui.html. The panel says so when its version is behind the server's.
Local model (optional, Apple Silicon)
The first time Jev Bridge opens, it offers to install Kev-0.8B (about 1.7 GB) next to the manifest, with a progress bar and log. After that the normal panel appears. The model starts only when an edit needs it and stops after 5 idle minutes.
Try it
Start your app's dev server, then ask Claude:
Push this app to Figma→ The screens appear on the current page. Change a padding or a text in Figma and watch the app update.
🧭 Using it
The plugin panel
Header: the app URL of the selected screen (click to open it), the server port, and an arrow that collapses the panel to just the header.
LIVE: on by default. Edits are written about 150 ms after you stop changing a layer; the second line shows the last one, e.g.
✓ text → "Log in" in index.html:11 · 4 ms. Switch it off to pause; paused edits are written when you switch it back on.Local model: its state (off, starting, running) and how much memory it and the Mac use.
Screens: every pushed screen whose app is running, with its URL. Click one to jump to it in Figma. While a push or fine-tune runs, this area shows its progress.
Fine-tune with LLM: hands the leftovers to Claude (see below).
Live sync
Figma → code: every Design-panel field is read and written (
jev_contractlists the table). Tailwind v3/v4 utilities, CSS rules, inline styles, JSX text and component props at usage sites are all handled.Code → Figma: a code change redraws only what changed. A layer you are editing, or edited in the last 4 seconds, is left alone.
The screen is the truth. Sizes come from layers on the screen (instances in their real parent), never from main components sitting alone in the Components section. Style edits on a main component go to the component's file, so every instance follows.
Restarts are safe. Pushed frames store their app URL, project folder and viewport. When the plugin reconnects to a restarted server, live sync resumes by itself. An edit counts as synced only after the server confirms it, so an edit is never lost to a restart.
Git is your undo. Edits are written straight into your source files. When sync starts, the panel warns if the project is not a git repository, or has uncommitted changes, so you can commit first and undo any edit with git.
Several Claude sessions: each runs its own server. The plugin checks every port and uses the one with a live session, or else the newest.
Fine-tune with LLM
Whatever the rules cannot write goes to a changelog (layer code, Figma node id, file:line
hint, reason; jev_changelog). Fine-tune with LLM compares every linked layer with what
was last synced, adds the changelog, and sends that brief to the Claude Code session running
the server. Only then are Claude tokens spent. Claude reports each step with jev_progress,
and the plugin shows those lines; when it calls jev_progress { done: true }, the changelog
is cleared and Figma is redrawn from the code.
The hand-off uses Claude Code channels (a research preview). With the server added by
claude mcp add, start Claude Code like this:
claude --dangerously-load-development-channels server:figma-jev-consoleWithout it the brief does not reach Claude, and after 60 seconds the panel says so.
JEV_FINE_TUNE=headless uses a separate claude -p run instead.
🧩 Skills
Two skills ship in skills/. The Claude Code plugin installs both; to use them without the
plugin, copy the folders into ~/.claude/skills/.
Skill | Use it for |
| Pushing an app to Figma, live sync, and what to do when an edit did not reach the code |
| Building or tidying screens in Figma by hand, with every color, text style, spacing, radius and icon bound to variables; Phosphor icon set; a lint pass instead of screenshots |
figma-system-build runs its Plugin API scripts through jev_execute (or figma_execute from
Figma Console MCP). Pushed screens copy raw values from CSS; binding them to variables with
this skill is design work on top, and the sync compares values, so it writes nothing to the
code unless a value changes.
🛠️ Tools
Tool | Purpose |
| Plugin connection, model backend, live session |
| Push routes to Figma and start live sync |
| Write queued edits, then refresh screens from code |
| Edits that need a decision |
| What the rules could not write, with a ready prompt |
| Claude reports fine-tune steps to the plugin |
| Applied edits with file:line and who decided |
| Layer code → file:line |
| What the edit check has learned for this project, and where it is stored |
| The CSS ↔ Figma property table |
| Stop watching and close the browser |
| Run raw Figma Plugin API code (escape hatch) |
⚙️ How it works
Step | Done by |
Render each route in headless Chrome, read layout and computed CSS | code ( |
Copy padding, gap, colors, type, radius, borders, shadows into Figma | code (fixed table in |
Direction (HORIZONTAL / VERTICAL / WRAP), hug / fill / fixed, components | rules from CSS and measured layout |
Find the source line or CSS rule for an edited layer | rules; the local model only on a tie |
Write the edit (Tailwind class, CSS declaration, inline style, text) | code ( |
Check the edit in the running app; roll back and try the next place if it missed | code ( |
Anything left over | the changelog, then Claude on request |
Every edit is checked. After a Figma edit is written, the screen is reloaded in the headless browser and the element is measured again:
Did it land? The element must now show the Figma value (within 0.5 px for lengths, 1/255 per colour channel, exact for text, direction, wrap and alignment).
Nothing else changed? No other element's own style may change (padding, colours, type, radius, borders, gap, direction). Elements drawn from the same template that change the same way are fine, and so are position and size changes caused by the edit.
If the check fails, the file is put back exactly as it was (byte for byte) and the next place is tried: another source line, the next class list, a CSS rule, an inline style. At most 4 tries. If none works, the code stays as it started and the changelog gets an item listing every try and why it failed, ready for Fine-tune with LLM.
The first write happens at once, so the app updates as fast as before. The panel's LIVE line then shows "Verifying…", followed by ✓ verified, "Corrected: ", or a note that the edit is in the changelog. Creates, deletes, reorders and moves are not checked yet.
Learned preferences. Each try is recorded: for this component (or page) and property, which kind of write passed or failed. Next time, the kind that works for that component is tried first (score = passes − 2 × fails). It is a lookup table, not machine learning, and the local model is not asked anything new. Two copies are kept, and either one rebuilds the other:
~/.figma-jev-console/prefs/<figma-file>/<project>--<hash>.json<project>/.figma-jev-console/prefs.json(added to.git/info/exclude, never to your.gitignore; the git safety notice does not count it)
jev_prefs shows what was learned and where both copies are; { reset: true } clears them.
Layer names are short codes such as @a3.0.2.1: screen a3, then the element's index
among its parent's element children at each DOM level (base 36). :t is the text inside a
boxed element. The code is also stored in plugin data, so moving a layer does not change what
it points to. Screen frames keep their route name.
Updates are in place. Layers are matched to elements by a content fingerprint (tag, classes, text, component), then by code, then by position. Each update is one undo step.
New layers: a frame becomes a flex div, a text layer a text element, an instance of a
pushed component <Button variant="primary">…</Button> with its import, a component made in
Figma a new file in src/components/, and a frame wrapped around linked layers (Shift+A) a new
wrapper around the existing code.
Deletes, reorders, moves, vectors: a deleted layer's element (or data-list item) is
removed; reordered layers move their code blocks; a layer dragged into another linked frame
moves its code; vectors become inline <svg>; a variant swap driven by an expression maps to
its condition.
🧠 Local model
Ties go to Kev-0.8B (weights), a Jev-compatible decision model running on the Mac with MLX, installed from the plugin's setup screen.
Starts on demand (about 8 seconds the first time), stops after 5 idle minutes.
Will not start when less than 12% of memory is free, and is stopped if memory stays that low while the Mac starts swapping.
Memory use is logged every 10 seconds to
~/.figma-jev-console/sync.logwhile it runs.Any server that speaks the same
/v1/systemoneformat can replace it (JEV_LOCAL_URL), including TypeSafe's cloud Jev (TYPESAFE_API_KEY, optional).
🔧 Configuration
Set in .env next to package.json, in ~/.figma-jev-console/.env, or in your MCP client's
env. Keep keys out of version control.
Variable | Default | Meaning |
|
| WebSocket ports for Jev Bridge |
|
|
|
|
| Local Jev-compatible server |
| none | Optional cloud Jev key |
|
| Minimum confidence to write a tie-broken edit without review |
|
| Minutes before the idle local model stops |
|
| Memory floor for starting or keeping the local model |
|
| Chrome channel for headless capture |
| channel |
|
|
| Where the plugin files are kept |
|
| Where the local model is installed |
| on |
|
|
| Where the log and learned preferences are kept (tests use a temp folder) |
🧪 Tests
npm testRuns every end-to-end scenario: the real MCP server on a test port (JEV_PORTS=9390, so a
Jev Bridge open in Figma is not touched), a fake plugin, a push, Figma-style edits, and the
resulting source files. One scenario:
FIXTURE=fixture-react SCENARIO=scenario-react.mjs node test/e2e.mjstest/live-harness.mjs runs a fixture against real Figma.
🩺 Troubleshooting
The panel says "Looking for server…" or "Server offline". The MCP server is not running.
It starts with your MCP client: restart Claude Code (or your client) and check that
figma-jev-console is listed (claude mcp list). Ports 9340–9344 must be free for at least one
server; lsof -i :9340 shows what holds a port.
The plugin connected to the wrong server. Every Claude session starts its own server. The plugin prefers the one with a live session, else the newest, and re-checks every 15 seconds. If it still picks an old one, close the other Claude sessions or reopen the plugin.
"Jev Bridge is out of date". Figma is running a cached copy of the plugin. Close the
plugin and open it again (Plugins → Development → Jev Bridge). If the notice stays, re-import
~/.figma-jev-console/plugin/manifest.json.
"Could not start Chrome". Install Google Chrome, or point JEV_CHROME_CHANNEL at another
Chromium channel you have (chrome-beta, msedge).
A Figma edit did not reach the code. Ask Claude "why didn't my edit sync?": the skill
reads jev_list_pending. Common reasons are a design token (it asks whether to change the
token or just this element) or a value built from variables in the code. Anything left over
goes to Fine-tune with LLM.
Screens are missing from the panel's list. Only screens whose app answers at their URL are listed. Start the app's dev server; screens pushed by early versions store no URL and stay hidden until you push them again.
Fine-tune with LLM says "No reply from Claude". Claude Code must be started with
channels on: claude --dangerously-load-development-channels server:figma-jev-console. Or set
JEV_FINE_TUNE=headless to use a separate claude -p run.
The local model does not start. It needs Apple Silicon and at least 12% free memory.
The panel shows the reason; the log is ~/.figma-jev-console/sync.log. Start again
retries without downloading anything.
An edit was "corrected" or ended in the changelog. Every edit is checked in the running
app. "Corrected" means the first place it was written did not show the change, so it was put
back and written somewhere else. A changelog item means no place worked, so the code was left
unchanged; the item lists each try. The log (~/.figma-jev-console/sync.log) has one
verify line per try with the value expected and the value found. JEV_VERIFY=0 turns the
check off.
The app shows an edit that Figma no longer matches. Checking reloads the page in a headless browser, not in yours. If your browser tab does not hot-reload, refresh it.
Undo an edit. Figma's undo changes the layer back, and the sync writes that like any
other edit. For the code itself, use git (git diff, git checkout -- <file>).
Known limits
One viewport per session; hover and focus states, animations and icon fonts are not pushed.
::before/::aftertext (such as a placeholder) is drawn but not written back.Showing a hidden data item again, and moves or reorders across files, go to the changelog.
Block layouts with uneven margins use the median spacing as the auto-layout gap, so a few pixels can shift.
Instances cannot change structure; a component rendered with different children becomes separate variants.
The local model needs Apple Silicon.
Credits and license
MIT, see LICENSE. A fork of Figma Console MCP
by Southleft and its contributors (MIT). Tie-breaking model: Kev
by Jared Palmer. Icons in figma-system-build: Phosphor.
Available Tools
12 toolsjev_changelogB
Figma changes that need an LLM to finish in code (deletes, moves, reorders, expression-driven variants, anything the rules and Jev could not write), with layer codes, Figma node ids, code hints and a ready prompt.
Inputs: no named parameters.
jev_contractA
The CSS ↔ Figma property table the sync supports, and which direction each property syncs.
Inputs: no named parameters.
jev_executeA
Escape hatch: run Figma plugin API code inside the Jev Bridge plugin (async function body with figma in scope; return a JSON-serializable value).
Inputs: code (required).
jev_list_pendingA
Figma edits that were not written to code automatically (Jev was unsure where they go, or a design token is involved), with the reason for each.
Inputs: no named parameters.
jev_locateA
Find the source file and line for a Figma layer code such as @a3.0.2.1.
Inputs: code (required).
jev_progressA
During a Fine-tune (sent to you through the figma-jev-console channel): report a step to the designer's Figma panel. Call with done: true when every item is fixed; Figma is then redrawn from the code and the changelog is cleared.
Inputs: text (required), done.
jev_push_screensA
Push the app's screens into Figma as auto-layout frames and components, then keep them in live two-way sync. The app's dev server must be running. Call this when the user says 'push to Figma'.
Inputs: baseUrl (required), projectDir (required), live, routes, +2 more.
jev_resolve_pendingA
Decide a pending item: 'apply' writes the best guess, 'reject' drops it, 'element' / 'token' choose the scope for a design-token color, 'llm' hands it to the LLM, 'done' marks it finished after you changed the code yourself (Figma is then redrawn).
Inputs: id (required), action (required).
jev_statusA
Connection status: Jev Bridge plugin in Figma, Jev backend, and the live session (screens, pending reviews).
Inputs: no named parameters.
jev_stop_liveA
Stop the live session: stop watching files and close the headless browser. Figma layers stay.
Inputs: no named parameters.
jev_sync_logB
Recent Figma → code edits: what changed, which file and line, and whether Jev or a rule decided the location.
Inputs: limit.
jev_sync_nowA
One-click sync: write all queued Figma edits into the code, then refresh every screen in Figma from the code.
Inputs: no named parameters.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 12 tools
While each tool has a specific name, several overlap in function and timing: jev_sync_now, jev_push_screens, and jev_resolve_pending all trigger writes to code or Figma, and jev_status, jev_sync_log, jev_progress, jev_changelog, and jev_list_pending all report state, making it hard to select the right one. Descriptions are detailed but the boundaries are blurred.
All tool names start with 'jev_' followed by a simple verb (status, sync_now, list_pending, changelog, push_screens, resolve_pending, sync_log, locate, progress, contract, stop_live, execute), following a consistent, predictable pattern. All are lowercase with underscores, no mixing of conventions.
With 12 tools, the set is well-scoped for the Figma-Jev integration console. Each tool addresses a distinct aspect of the workflow (status, sync, pending, changelog, push, resolve, log, locate, progress, contract, stop, execute), and the count is within the ideal 3-15 range, with no redundancy.
The set covers core lifecycle operations: status, sync, pending resolution, push, stop, and a progress reporting mechanism. However, there is a notable gap: no explicit tool to start or manage a live session (only stop_live exists), and the fine-tune workflow relies on an external channel rather than a dedicated tool. The escape hatch jev_execute partially mitigates gaps, but the surface feels incomplete for the stated purpose.
Maintenance
Related MCP Connectors
Turn any live website into brand colors, fonts, design tokens, SVGs, Lottie and paste-ready code.
Visual website builder synced with real code. Build, publish and maintain websites from any agent.
Compare Figma designs against live websites and get visual + content QA reports, from inside Claude.
Connect AI coding agents to Anima Playground, Figma, and your design system.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables bidirectional synchronization between IDEs and Figma for Design System management, allowing developers to generate React components and synchronize design tokens, icons, and components across platforms.1MIT
- AlicenseNot gradedqualityDmaintenanceConnects Figma designs to AI agents, enabling extraction of production-ready code, assets, and design tokens through natural language descriptions. Supports React, Vue, CSS, and Tailwind with real-time design system analysis.155,133 npm40MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to read Figma design files and automatically map responsive relationships between mobile and desktop screens to generate accurate frontend code. Eliminates manual copy-pasting by providing direct access to design tokens, dimensions, and screen layouts within AI-powered IDEs.ISC
- AlicenseNot gradedqualityDmaintenanceConnects Figma designs to React components using your actual component library, enabling AI tools to generate production-ready code with proper imports.1MIT