Figma Local MCP Bridge
README.md
# Figma Local MCP Bridge
A VS Code extension for managing the local Figma MCP bridge server: server lifecycle, the Figma dev plugin, MCP tool integration for Copilot, and one-click setup for other AI agents — all without leaving the editor.
This is a from-scratch port of the Figma Local MCP GUI Flutter desktop app, rebuilt around native VS Code UI (activity-bar tree view, status bar, output channels, commands) instead of a standalone window.
## Features
- **Bridge lifecycle** — start/stop/restart the local bridge with a health gate (status flips to Running only after `/health` returns 200), orphan-kill, multi-window adopt-external, session/uptime in the status bar.
- **MCP for Copilot** — registers an `McpServerDefinitionProvider` so agent mode gets the Figma MCP tools natively (VS Code ≥ 1.101).
- **Plugin build** — builds the Figma development plugin (`manifest.json`, `code.js`, `ui.html`, with the bridge port injected) into an extension-owned folder, ready to import into Figma; rebuilds update it in place and a sidecar `.installed.json` tracks staleness.
- **Connect AI agent…** — one command adds the Figma MCP server to other agents. Pick any of them (installed ones are detected and preselected):
| Agent | Config written |
|---|---|
| Claude Code | `claude mcp add-json --scope user` if the CLI is on PATH, else `~/.claude.json` |
| Gemini CLI | `~/.gemini/settings.json` |
| OpenAI Codex CLI | `~/.codex/config.toml` (or `$CODEX_HOME`) |
| opencode | `~/.config/opencode/opencode.json` (`%APPDATA%\opencode` on Windows) |
| Kilo Code / Cline / Roo Code | the extension's `settings/*mcp_settings.json` in VS Code global storage |
| Cursor | `~/.cursor/mcp.json` |
| Windsurf | `~/.codeium/windsurf/mcp_config.json` |
| Claude Desktop | `claude_desktop_config.json` |
| Anything else | "Other agent…" copies a generic `mcpServers` JSON snippet |
Existing entries and settings are preserved (atomic merge, one-time `.bak`, chmod 600). **Preview AI Agent Config…** shows the entry without writing it. When the bridge token is changed or regenerated, connected agents are rewritten automatically (or run **Update Connected AI Agents**). Agents talk to the bridge that this extension runs, so keep VS Code open while you use them.
- **Runtime** — seeds from a VSIX-bundled `runtime-seed/` built from `superdoccimo/figma-mcp-free`; stage-and-swap, rollback, force-reinstall; optional on-device **Build from source** with verification (MCP `initialize` + `/health` 401/200) before swap.
- **System check** — Node runtime (VS Code's built-in one counts), port availability/health, Figma desktop process, plugin installed.
## Requirements
- VS Code **1.101+** (native MCP support)
- Figma desktop (to import and run the development plugin)
- **No Node.js install needed.** The bridge, the Copilot MCP server and the AI agent configs all run on VS Code's own binary via `ELECTRON_RUN_AS_NODE`. Only **Build from source** needs a real Node.js ≥ 18, and it offers to download a managed copy if none is found.
## Extension Settings
| Setting | Default | Description |
|---|---|---|
| `figmaMcpBridge.port` | `3845` | Bridge listen port (must match plugin `devAllowedDomains`) |
| `figmaMcpBridge.host` | `127.0.0.1` | Bind address: `127.0.0.1`, `localhost`, or `::1` |
| `figmaMcpBridge.autoStart` | `false` | Start the bridge on activation |
| `figmaMcpBridge.mcpServerPath` | `""` | Custom `mcp-server.cjs` path |
| `figmaMcpBridge.nodePath` | `""` | Real Node.js for source builds / server fallback |
| `figmaMcpBridge.opencodeNodePath` | `""` | Node written into AI agent configs (optional; defaults to system Node, else VS Code's binary) |
| `figmaMcpBridge.figmaPluginId` | `""` | Override plugin manifest `id` |
| `figmaMcpBridge.autoCheckUpdates` | `true` | Check upstream SHA on activation |
| `figmaMcpBridge.maxDepth` | `5` | Max node-tree depth the Figma inspect tools may return (1–64; upstream caps at 5) |
Secrets (pairing password, Figma token) live in VS Code Secret Storage — never in settings or argv.
### Max inspect depth
Upstream hard-codes a ceiling of 5 for `inspect_selection` / `inspect_current_selection`, and publishes it to MCP clients as a JSON-Schema `maximum`, so clients reject anything deeper before the server is even asked. `figmaMcpBridge.maxDepth` lifts that ceiling by rebuilding the bundled runtime with a small, anchored patch that makes the limit read `FIGMA_MCP_MAX_DEPTH` (`tool/runtimePatches.mjs`). The value is then passed to the MCP server through the environment — no rebuild happens when you change the setting, and the change applies on the next MCP server start.
It only raises the **ceiling**: your agent still picks a depth per call. Raising it does not make every call more expensive, but it makes expensive responses possible. Response size grows roughly as `maxChildren × depth`, `maxChildren` is independently capped at 100, `inspect_selection` sends the depth to the Figma REST API too (so deeper means slower and larger network responses), and oversized responses can be truncated or rejected outright. The settings UI asks for confirmation above the default, and the Runtime section of the dashboard tree shows the effective value.
The ceiling is 64 because that is how deeply the bridge already captures a selection (`bridge-cli serve --max-depth`, default 64). Raising `maxDepth` past it could not reveal anything more, so the two are deliberately kept aligned.
If an upstream update changes the code these patches anchor on, the patch is **skipped** rather than half-applied and the build still succeeds — the dashboard surfaces skipped patches so the setting silently doing nothing is visible.
## Commands
Open the **Figma MCP** activity-bar icon for the dashboard tree (Bridge / MCP / Plugin / Runtime / System). Title-bar and context-menu actions cover start/stop/restart, test connection, build plugin, build from source, rollback, and system check. Palette-visible commands use the `Figma MCP:` prefix.
## Loading the plugin into Figma
Figma desktop does not pick up plugins from a folder — development plugins are imported once by manifest path:
1. Run **Build Figma Plugin** (Plugin section of the tree, or the Command Palette). It prints the path of the built `manifest.json`; use **Copy manifest path** to put it on the clipboard.
2. In Figma desktop: **Plugins → Development → Import plugin from manifest…** and select that file (in the Linux/macOS file dialog, press `Ctrl+L` / `Cmd+Shift+G` and paste the path).
3. Run it from **Plugins → Development**. Keep the pre-filled bridge URL (`http://localhost:<port>`) and paste the pairing token (**Copy token** in the Bridge section of the tree).
4. Later rebuilds (port change, runtime update) overwrite the same folder and keep the manifest `id`, so Figma picks up the new files without re-importing.
The manifest lists only `http://localhost:<port>` in `devAllowedDomains`: Figma rejects IP literals such as `127.0.0.1` there (the plugin then shows "Manifest issue" and won't run). The plugin iframe's CSP is built from that list, so inside Figma the bridge must be addressed as `localhost`, not `127.0.0.1`.
## Security notes
- The bridge token is passed only via `FIGMA_PLUGIN_BRIDGE_TOKEN` (never argv).
- AI agent config files are written with mode `600` on POSIX and contain the bridge token in plaintext by design — don't commit or share them.
- Runtime `runtime.json` files are SHA-256 verified hard-fail before stage-and-swap.
## Development
```bash
npm install
npm run watch # esbuild --watch; or press F5 → Extension Development Host
npm run lint
npm run check-types
npm test # unit (vitest) + integration (@vscode/test-cli)
npm run sync-runtime # rebuild runtime-seed/ from superdoccimo/figma-mcp-free
npx @vscode/vsce package
```
### Runtime seed
`runtime-seed/` is a committed build artifact (bridge + MCP + plugin + `runtime.json`). Refresh it with:
```bash
npm run sync-runtime
# or pin a ref:
node tool/build-runtime.mjs --ref <sha>
```
The script downloads upstream source, builds with pnpm, bundles with esbuild (CJS), hard-fails on missing plugin files, writes per-file SHA-256s, and smoke-verifies (MCP `initialize` + `/health` 401/200).
## License
MIT — see the `LICENSE` file.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues