figma-rust-mcp 3.0.4 β 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -31
- package/bin/figma-mcp.js +141 -0
- package/package.json +1 -1
- package/plugin/code.js +25 -5918
- package/plugin/manifest.json +13 -2
- package/plugin/ui.html +134 -1871
- package/scripts/build-plugin.js +2 -2
package/README.md
CHANGED
|
@@ -21,69 +21,94 @@ Enables AI agents (Google Antigravity, Claude Code, Cursor, Windsurf, VS Code, Z
|
|
|
21
21
|
|
|
22
22
|
---
|
|
23
23
|
|
|
24
|
-
## ποΈ Architecture
|
|
24
|
+
## ποΈ Architecture & Zero-Touch Connection
|
|
25
25
|
|
|
26
26
|
```text
|
|
27
27
|
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
28
|
-
β Terminal /
|
|
28
|
+
β Terminal / Background Service β
|
|
29
29
|
β figma-mcp (Pure Rust Engine) β
|
|
30
30
|
β β’ MCP SSE Transport (/sse, /message) & Direct HTTP (/mcp) β
|
|
31
|
+
β β’ Dynamic Runtime Server (/plugin/code.js, /plugin/ui.html) β
|
|
31
32
|
β β’ In-Memory Fast Index (<1ms Lookups & Incremental Diffs) β
|
|
32
33
|
β β’ Design-to-Code Compiler (React/Tailwind, Vue, RN, SwiftUI) β
|
|
33
34
|
β β’ Design Token Transformer (CSS, Tailwind, TypeScript, W3C DTCG) β
|
|
34
35
|
β β’ Sandboxed JS Runtime (Boa ECMAScript Engine) β
|
|
35
36
|
β β’ Binary MessagePack & Progressive Subtree Chunk Receiver β
|
|
36
37
|
βββββββββββββββββ²βββββββββββββββββββββββββββββββββββββββββ²ββββββββββββββββ
|
|
37
|
-
β (ws://127.0.0.1:38451)
|
|
38
|
-
β (
|
|
38
|
+
β (ws://127.0.0.1:38451/ws) β (http://127.0.0.1:38451/sse)
|
|
39
|
+
β (Dynamic Code Streaming & Hot-Reload) β (JSON-RPC 2.0 / SSE)
|
|
39
40
|
βββββββββββ΄ββββββββββ βββββββββββ΄ββββββββββ
|
|
40
41
|
β Figma Desktop β β AI Assistant(s) β
|
|
41
|
-
β (
|
|
42
|
+
β (Thin Loader) β β Google Antigravityβ
|
|
42
43
|
β β β Cursor / Windsurf β
|
|
43
|
-
β β’
|
|
44
|
-
β β’
|
|
44
|
+
β β’ Zero-Touch Sync β β Claude Code / Zed β
|
|
45
|
+
β β’ Live Hot-Reload β βββββββββββββββββββββ
|
|
46
|
+
β β’ SVG/PNG Render β
|
|
45
47
|
βββββββββββββββββββββ
|
|
46
48
|
```
|
|
47
49
|
|
|
50
|
+
### π How the Zero-Touch Connection Works:
|
|
51
|
+
1. **Permanent Thin Loader**: You only import the Figma plugin **once** (`~/.figma-mcp/plugin/manifest.json`).
|
|
52
|
+
2. **Dynamic Runtime Streaming**: Upon launch, the Thin Loader contacts `http://127.0.0.1:38451/plugin/code.js` to fetch and execute the latest runtime in memory.
|
|
53
|
+
3. **Live WebSocket Hot-Reload**: The plugin connects to `ws://127.0.0.1:38451/ws`. When you upgrade `figma-rust-mcp` or restart the daemon, the plugin automatically detects the new server version and hot-reloads seamlessly β **no need to re-import or restart the plugin in Figma**.
|
|
54
|
+
4. **Auto-Reconnect & Offline Buffer**: If Figma is opened before the Rust service starts, the plugin displays a waiting screen and connects automatically the instant the service is up.
|
|
55
|
+
|
|
48
56
|
---
|
|
49
57
|
|
|
50
58
|
## π Quick Start
|
|
51
59
|
|
|
52
|
-
### 1. One-Line Launch with NPX (No Rust toolchain needed)
|
|
53
|
-
|
|
54
|
-
Launch `figma-rust-mcp` on macOS, Linux, or Windows with zero manual setup:
|
|
60
|
+
### 1. One-Line Setup & Launch with NPX (No Rust toolchain needed)
|
|
55
61
|
|
|
56
62
|
```bash
|
|
63
|
+
# Launch interactive MCP server
|
|
57
64
|
npx figma-rust-mcp
|
|
58
65
|
```
|
|
66
|
+
*(Automatically downloads precompiled native binary for macOS Apple Silicon/Intel, Linux, or Windows).*
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
### 2. Install the Figma Plugin (Permanent One-Time Setup)
|
|
71
|
+
|
|
72
|
+
Create the permanent Thin Loader folder in your home directory:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
npx figma-rust-mcp --setup-plugin
|
|
76
|
+
```
|
|
59
77
|
|
|
60
|
-
|
|
78
|
+
1. Open **Figma Desktop**.
|
|
79
|
+
2. Go to **Plugins** β **Development** β **Import plugin from manifest...**
|
|
80
|
+
3. Select `~/.figma-mcp/plugin/manifest.json` (or `plugin/manifest.json` inside this repository).
|
|
81
|
+
4. Run the plugin: **Plugins** β **Development** β **Figma MCP Bridge**.
|
|
82
|
+
5. **Done!** Future updates to `figma-rust-mcp` will stream to Figma automatically.
|
|
61
83
|
|
|
62
84
|
---
|
|
63
85
|
|
|
64
|
-
###
|
|
86
|
+
### 3. Run as Auto-Start Background Service (Recommended)
|
|
65
87
|
|
|
66
|
-
|
|
88
|
+
Run `figma-rust-mcp` seamlessly in the background across all your AI editors without keeping a terminal open:
|
|
67
89
|
|
|
68
90
|
```bash
|
|
69
|
-
# Install and start
|
|
91
|
+
# Install and start background service (macOS LaunchAgent, Linux systemd, Windows Task)
|
|
70
92
|
npx figma-rust-mcp --install-service
|
|
71
93
|
|
|
72
|
-
#
|
|
73
|
-
npx -y figma-rust-mcp@latest --install-service
|
|
74
|
-
|
|
75
|
-
# Check service status
|
|
94
|
+
# Check live background service status & bridge health
|
|
76
95
|
npx figma-rust-mcp --service-status
|
|
77
96
|
|
|
78
|
-
#
|
|
97
|
+
# One-command upgrade to latest version & auto-restart background service
|
|
98
|
+
npx figma-rust-mcp --upgrade
|
|
99
|
+
|
|
100
|
+
# Add convenient 'figma-mcp' alias to your shell profile (~/.zshrc, ~/.bashrc)
|
|
101
|
+
npx figma-rust-mcp --alias
|
|
102
|
+
|
|
103
|
+
# Stop and remove background service
|
|
79
104
|
npx figma-rust-mcp --uninstall-service
|
|
80
105
|
```
|
|
81
106
|
|
|
82
107
|
---
|
|
83
108
|
|
|
84
|
-
###
|
|
109
|
+
### 4. Build from Source (Optional)
|
|
85
110
|
|
|
86
|
-
|
|
111
|
+
If you prefer building directly with the [Rust toolchain](https://rustup.rs/) (`cargo >= 1.80`):
|
|
87
112
|
|
|
88
113
|
```bash
|
|
89
114
|
git clone https://github.com/BuiHung1612/figma-mcp.git
|
|
@@ -94,16 +119,6 @@ cargo build --release
|
|
|
94
119
|
|
|
95
120
|
---
|
|
96
121
|
|
|
97
|
-
### 4. Install the Figma Plugin
|
|
98
|
-
|
|
99
|
-
1. Open **Figma Desktop**.
|
|
100
|
-
2. Go to **Plugins** β **Development** β **Import plugin from manifest...**
|
|
101
|
-
3. Select `plugin/manifest.json` from this repository.
|
|
102
|
-
4. Run the plugin (**Plugins** β **Development** β **Figma MCP Bridge**).
|
|
103
|
-
5. The plugin UI will display a green dot (**Connected**).
|
|
104
|
-
|
|
105
|
-
---
|
|
106
|
-
|
|
107
122
|
### 5. Configure Your MCP Client
|
|
108
123
|
|
|
109
124
|
#### Google Antigravity (SSE Transport - Recommended)
|
package/bin/figma-mcp.js
CHANGED
|
@@ -371,13 +371,151 @@ function isServiceInstalled() {
|
|
|
371
371
|
return false;
|
|
372
372
|
}
|
|
373
373
|
|
|
374
|
+
function setupPlugin(customDir) {
|
|
375
|
+
const pluginDir = customDir || path.join(os.homedir(), '.figma-mcp', 'plugin');
|
|
376
|
+
const sourcePluginDir = path.resolve(__dirname, '../plugin');
|
|
377
|
+
|
|
378
|
+
fs.mkdirSync(pluginDir, { recursive: true });
|
|
379
|
+
|
|
380
|
+
const files = ['manifest.json', 'code.js', 'ui.html', 'icon16.png', 'icon32.png'];
|
|
381
|
+
for (const f of files) {
|
|
382
|
+
const src = path.join(sourcePluginDir, f);
|
|
383
|
+
const dest = path.join(pluginDir, f);
|
|
384
|
+
if (fs.existsSync(src)) {
|
|
385
|
+
fs.copyFileSync(src, dest);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const manifestPath = path.join(pluginDir, 'manifest.json');
|
|
390
|
+
console.log(`\n\x1b[32mβ Figma MCP Dynamic Thin Plugin installed to:\x1b[0m`);
|
|
391
|
+
console.log(` \x1b[36m${manifestPath}\x1b[0m\n`);
|
|
392
|
+
console.log(`\x1b[1mTo connect Figma (Do this ONCE forever):\x1b[0m`);
|
|
393
|
+
console.log(` 1. Open Figma Desktop`);
|
|
394
|
+
console.log(` 2. Go to Plugins β Development β Import plugin from manifest...`);
|
|
395
|
+
console.log(` 3. Select: ${manifestPath}`);
|
|
396
|
+
console.log(` 4. Done! All future updates load dynamically from figma-mcp without file re-imports.\n`);
|
|
397
|
+
return manifestPath;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function isNewer(latest, current) {
|
|
401
|
+
const pLatest = latest.split('.').map(n => parseInt(n, 10) || 0);
|
|
402
|
+
const pCurrent = current.split('.').map(n => parseInt(n, 10) || 0);
|
|
403
|
+
for (let i = 0; i < 3; i++) {
|
|
404
|
+
if ((pLatest[i] || 0) > (pCurrent[i] || 0)) return true;
|
|
405
|
+
if ((pLatest[i] || 0) < (pCurrent[i] || 0)) return false;
|
|
406
|
+
}
|
|
407
|
+
return false;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
function checkForUpdatesAsync() {
|
|
411
|
+
const updateStateFile = path.join(os.homedir(), '.figma-mcp', 'update-check.json');
|
|
412
|
+
try {
|
|
413
|
+
if (fs.existsSync(updateStateFile)) {
|
|
414
|
+
const state = JSON.parse(fs.readFileSync(updateStateFile, 'utf8'));
|
|
415
|
+
const now = Date.now();
|
|
416
|
+
if (state.lastChecked && (now - state.lastChecked < 6 * 3600 * 1000)) {
|
|
417
|
+
if (state.latestVersion && isNewer(state.latestVersion, pkgVersion)) {
|
|
418
|
+
process.stderr.write(`\n\x1b[36mβ‘ Update available: v${pkgVersion} β v${state.latestVersion} (Run: npx figma-rust-mcp --upgrade)\x1b[0m\n\n`);
|
|
419
|
+
}
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
} catch (_) {}
|
|
424
|
+
|
|
425
|
+
const req = https.get('https://registry.npmjs.org/figma-rust-mcp/latest', {
|
|
426
|
+
headers: { 'User-Agent': 'figma-mcp-updater' },
|
|
427
|
+
timeout: 2000
|
|
428
|
+
}, (res) => {
|
|
429
|
+
let data = '';
|
|
430
|
+
res.on('data', chunk => { data += chunk; });
|
|
431
|
+
res.on('end', () => {
|
|
432
|
+
try {
|
|
433
|
+
if (res.statusCode === 200) {
|
|
434
|
+
const json = JSON.parse(data);
|
|
435
|
+
const latest = json.version;
|
|
436
|
+
fs.mkdirSync(path.join(os.homedir(), '.figma-mcp'), { recursive: true });
|
|
437
|
+
fs.writeFileSync(updateStateFile, JSON.stringify({
|
|
438
|
+
lastChecked: Date.now(),
|
|
439
|
+
latestVersion: latest
|
|
440
|
+
}, null, 2));
|
|
441
|
+
if (latest && isNewer(latest, pkgVersion)) {
|
|
442
|
+
process.stderr.write(`\n\x1b[36mβ‘ Update available: v${pkgVersion} β v${latest}\x1b[0m\n\x1b[36m Run: npx figma-rust-mcp --upgrade\x1b[0m\n\n`);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
} catch (_) {}
|
|
446
|
+
});
|
|
447
|
+
});
|
|
448
|
+
req.on('error', () => {});
|
|
449
|
+
req.on('timeout', () => req.destroy());
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
async function upgrade() {
|
|
453
|
+
console.log('\x1b[36m[figma-mcp]\x1b[0m Checking for updates and upgrading figma-rust-mcp...');
|
|
454
|
+
try {
|
|
455
|
+
execSync('npm install -g figma-rust-mcp@latest', { stdio: 'inherit' });
|
|
456
|
+
console.log('\x1b[32mβ Upgraded figma-rust-mcp to latest version.\x1b[0m');
|
|
457
|
+
setupPlugin();
|
|
458
|
+
if (isServiceInstalled()) {
|
|
459
|
+
console.log('\x1b[36mUpdating background service binary...\x1b[0m');
|
|
460
|
+
const binPath = await findOrDownloadBinary();
|
|
461
|
+
await installService(binPath);
|
|
462
|
+
}
|
|
463
|
+
} catch (err) {
|
|
464
|
+
console.log('\x1b[33mTip: Run directly with latest version:\x1b[0m\n npx -y figma-rust-mcp@latest\n');
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function setupAlias() {
|
|
469
|
+
const platform = process.platform;
|
|
470
|
+
if (platform === 'win32') {
|
|
471
|
+
console.log('\x1b[33mOn Windows, install globally for direct command access:\x1b[0m\n npm install -g figma-rust-mcp\n');
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
const shellRc = process.env.SHELL && process.env.SHELL.includes('zsh')
|
|
476
|
+
? path.join(os.homedir(), '.zshrc')
|
|
477
|
+
: path.join(os.homedir(), '.bashrc');
|
|
478
|
+
|
|
479
|
+
const aliasLine = "alias figma-mcp='npx figma-rust-mcp'";
|
|
480
|
+
try {
|
|
481
|
+
let content = fs.existsSync(shellRc) ? fs.readFileSync(shellRc, 'utf8') : '';
|
|
482
|
+
if (!content.includes('alias figma-mcp=')) {
|
|
483
|
+
fs.appendFileSync(shellRc, `\n# Figma MCP alias\n${aliasLine}\n`);
|
|
484
|
+
console.log(`\x1b[32mβ Added alias to ${shellRc}:\x1b[0m`);
|
|
485
|
+
console.log(` ${aliasLine}`);
|
|
486
|
+
console.log(`\nRun \x1b[36msource ${shellRc}\x1b[0m to start using \x1b[1mfigma-mcp\x1b[0m command directly!`);
|
|
487
|
+
} else {
|
|
488
|
+
console.log(`\x1b[32mβ Alias already exists in ${shellRc}\x1b[0m`);
|
|
489
|
+
}
|
|
490
|
+
} catch (err) {
|
|
491
|
+
console.error(`Failed to configure alias: ${err.message}`);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
374
495
|
// βββ MAIN βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
375
496
|
|
|
376
497
|
async function main() {
|
|
377
498
|
const args = process.argv.slice(2);
|
|
378
499
|
|
|
500
|
+
if (args.includes('--upgrade') || args.includes('--update')) {
|
|
501
|
+
await upgrade();
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
if (args.includes('--alias')) {
|
|
506
|
+
setupAlias();
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
if (args.includes('--setup-plugin') || args.includes('--export-plugin') || args.includes('--setup')) {
|
|
511
|
+
const customDir = args.find(a => !a.startsWith('-') && a !== '--setup-plugin' && a !== '--export-plugin' && a !== '--setup');
|
|
512
|
+
setupPlugin(customDir);
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
|
|
379
516
|
if (args.includes('--install-service')) {
|
|
380
517
|
try {
|
|
518
|
+
setupPlugin();
|
|
381
519
|
const binPath = await findOrDownloadBinary();
|
|
382
520
|
await installService(binPath);
|
|
383
521
|
} catch (err) {
|
|
@@ -409,6 +547,9 @@ async function main() {
|
|
|
409
547
|
return;
|
|
410
548
|
}
|
|
411
549
|
|
|
550
|
+
// Non-blocking auto update check
|
|
551
|
+
checkForUpdatesAsync();
|
|
552
|
+
|
|
412
553
|
try {
|
|
413
554
|
const binPath = await findOrDownloadBinary();
|
|
414
555
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "figma-rust-mcp",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.1",
|
|
4
4
|
"description": "Claude Code to Figma β Bidirectional MCP bridge. AI draws UI on Figma canvas, reads designs back. Works with Claude, Cursor, VS Code, Windsurf, Antigravity. No API key needed.",
|
|
5
5
|
"mcpName": "io.github.BuiHung1612/figma-mcp",
|
|
6
6
|
"type": "module",
|