figma-coder-mcp 0.2.0 → 0.2.2
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 +152 -112
- package/dist/bin.js +57 -53
- package/package.json +3 -5
package/README.md
CHANGED
|
@@ -1,112 +1,152 @@
|
|
|
1
|
-
# figma-coder-mcp
|
|
2
|
-
|
|
3
|
-
MCP server
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
figma-coder-mcp
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
figma-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
1
|
+
# figma-coder-mcp
|
|
2
|
+
|
|
3
|
+
> **Figma Coder** is an MCP server and CLI that turns any Figma frame into
|
|
4
|
+
> pixel-faithful, self-contained HTML, right inside your AI coding agent. No
|
|
5
|
+
> screenshots, no rebuilding by hand. Works with any Figma account: no paid
|
|
6
|
+
> plan, completely free.
|
|
7
|
+
|
|
8
|
+
Homepage: **https://figmacoder.sitenow.cloud**
|
|
9
|
+
|
|
10
|
+
`figma-coder-mcp` is one program that is two things at once: an MCP server your
|
|
11
|
+
AI agent talks to, and a command-line tool you can run in a terminal. It runs in
|
|
12
|
+
two modes and picks one automatically: with a Figma token it converts locally on
|
|
13
|
+
your machine; without one it uses the hosted backend. Both modes produce
|
|
14
|
+
identical output.
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm i -g figma-coder-mcp # or run on demand with: npx figma-coder-mcp
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Setup
|
|
21
|
+
|
|
22
|
+
Setup is two steps. Step 1 (required): add the server to your project's
|
|
23
|
+
`.mcp.json`. Step 2: give it access to Figma using either a personal access token
|
|
24
|
+
(local mode) or by signing in with Figma (remote mode).
|
|
25
|
+
|
|
26
|
+
### Local mode — personal access token
|
|
27
|
+
|
|
28
|
+
Create a personal access token (`figd_…`) in your Figma account settings
|
|
29
|
+
(Settings → Security → Personal access tokens:
|
|
30
|
+
https://www.figma.com/settings). Add the server to `.mcp.json` with the token in
|
|
31
|
+
the inline `env`:
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"mcpServers": {
|
|
36
|
+
"figma": {
|
|
37
|
+
"command": "npx",
|
|
38
|
+
"args": ["-y", "figma-coder-mcp"],
|
|
39
|
+
"env": { "FIGMA_PAT": "figd_xxx" }
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Prefer not to keep the token in the project file? Run
|
|
46
|
+
`npx figma-coder-mcp set-token figd_xxx` to store it once in the global settings
|
|
47
|
+
file instead, and leave the `env` out.
|
|
48
|
+
|
|
49
|
+
### Remote mode — sign in with Figma (OAuth)
|
|
50
|
+
|
|
51
|
+
Add the server to `.mcp.json` with no token, then run
|
|
52
|
+
`npx figma-coder-mcp login` once to authorize via the hosted backend. The login
|
|
53
|
+
is stored globally; no token lives in your project.
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"mcpServers": {
|
|
58
|
+
"figma": {
|
|
59
|
+
"command": "npx",
|
|
60
|
+
"args": ["-y", "figma-coder-mcp"]
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`login` opens the authorize page in your browser, captures the token the backend
|
|
67
|
+
hands back over a one-shot loopback server, and stores it in
|
|
68
|
+
`~/.figma-mcp/settings.json`. The access token is refreshed silently when it
|
|
69
|
+
expires; re-run `login` only if the refresh token itself is revoked. Set
|
|
70
|
+
`FIGMA_MCP_NO_BROWSER=1` on headless/SSH hosts to print the URL instead of
|
|
71
|
+
launching a browser.
|
|
72
|
+
|
|
73
|
+
Then ask your agent: **"Convert this Figma frame to HTML."**
|
|
74
|
+
|
|
75
|
+
## Tools
|
|
76
|
+
|
|
77
|
+
Once the server is registered, your agent can call these two tools. There is
|
|
78
|
+
nothing to configure: just ask in plain language and the agent picks the right
|
|
79
|
+
one.
|
|
80
|
+
|
|
81
|
+
| Tool | What it does |
|
|
82
|
+
|------|--------------|
|
|
83
|
+
| `get_figma_data` | Returns the deterministic **Style IR** (the exact CSS for each node) so the agent can reason about the design and generate code itself. Small trees come back inline; large trees are written to a JSON file and summarised. |
|
|
84
|
+
| `convert_figma_to_html` | Produces finished, self-contained **HTML + Tailwind** (assets inlined, optional LLM restructure). The HTML is written to a file, and a compact summary plus path is returned to keep the agent's context small. Args: `mode`, `assets`, `assetScale`, `llm`, `outFile`. |
|
|
85
|
+
|
|
86
|
+
## Configuration
|
|
87
|
+
|
|
88
|
+
A setting can come from three places. When the same setting appears in more than
|
|
89
|
+
one, the higher one wins: **command flags > environment variables > stored
|
|
90
|
+
`settings.json`**.
|
|
91
|
+
|
|
92
|
+
Settings live in two places:
|
|
93
|
+
|
|
94
|
+
- **`.mcp.json`** (project scope): how your agent launches the server, plus an
|
|
95
|
+
optional inline `env` (such as `FIGMA_PAT`). Only applies to this project.
|
|
96
|
+
- **`~/.figma-mcp/settings.json`** (global scope): your stored Figma token or
|
|
97
|
+
OAuth login, written by `set-token` / `login`. Shared by every project. You
|
|
98
|
+
only have this file if you run `set-token` or `login`.
|
|
99
|
+
|
|
100
|
+
The global file mirrors the `env` block of a `.mcp.json` — user-facing values sit
|
|
101
|
+
under `env`, keyed by the same names as the environment variables, so you can
|
|
102
|
+
edit it by hand:
|
|
103
|
+
|
|
104
|
+
```json
|
|
105
|
+
{
|
|
106
|
+
"env": {
|
|
107
|
+
"FIGMA_PAT": "figd_xxx",
|
|
108
|
+
"FIGMA_MCP_API": "https://figmacoder-api.sitenow.cloud",
|
|
109
|
+
"FIGMA_MCP_TOKEN": "<oauth access token>"
|
|
110
|
+
},
|
|
111
|
+
"refreshToken": "<oauth refresh token>",
|
|
112
|
+
"apiTokenExpiresAt": 1735689600000
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Environment variables:
|
|
117
|
+
|
|
118
|
+
| Var | Meaning |
|
|
119
|
+
|-----|---------|
|
|
120
|
+
| `FIGMA_PAT` / `FIGMA_TOKEN` | Figma personal access token (local mode). |
|
|
121
|
+
| `FIGMA_MCP_API` | Backend converter base URL. Defaults to `https://figmacoder-api.sitenow.cloud`. |
|
|
122
|
+
| `FIGMA_MCP_TOKEN` | OAuth/bearer token for the backend. Usually set for you by `login`; an explicit value is used verbatim and never auto-refreshed. |
|
|
123
|
+
| `FIGMA_MCP_MODE` | `auto` (default) · `local` · `remote`. Auto prefers local. |
|
|
124
|
+
| `FIGMA_MCP_OUT_DIR` | Where HTML/JSON outputs are written. Default `<cwd>/figma-output`. |
|
|
125
|
+
| `FIGMA_MCP_NO_BROWSER` | If set, `login` prints the URL instead of opening a browser (headless/SSH). |
|
|
126
|
+
| `OLLAMA_CLOUD_URL` / `OLLAMA_API_KEY` / `OLLAMA_CLOUD_MODELS` | Optional, advanced. Only needed for the `--llm` restructure pass. |
|
|
127
|
+
|
|
128
|
+
## CLI
|
|
129
|
+
|
|
130
|
+
The same program also works on its own, without an agent. Flags for
|
|
131
|
+
convert/data: `--node <id>`, `--mode tailwind|inline`, `--no-assets`, `--llm`,
|
|
132
|
+
`--out <file>`.
|
|
133
|
+
|
|
134
|
+
| Command | What it does |
|
|
135
|
+
|---------|--------------|
|
|
136
|
+
| `figma-coder-mcp` | Start the MCP server over stdio (the default command). |
|
|
137
|
+
| `convert <url\|key>` | One-off convert to a self-contained HTML file. |
|
|
138
|
+
| `data <url\|key>` | Print or save the deterministic Style IR. |
|
|
139
|
+
| `set-token <PAT>` | Store a Figma personal access token globally (local mode). |
|
|
140
|
+
| `login` | Sign in with Figma via OAuth, stored globally (remote mode). |
|
|
141
|
+
| `status` | Show how requests will be served. No secrets printed. |
|
|
142
|
+
| `logout` | Remove the global stored credentials. |
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
figma-coder-mcp convert "https://www.figma.com/design/<key>/Title?node-id=1-23"
|
|
146
|
+
figma-coder-mcp convert <fileKey> --node 1:23 --no-assets --out page.html
|
|
147
|
+
figma-coder-mcp data <fileKey> --node 1:23
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## License
|
|
151
|
+
|
|
152
|
+
MIT
|
package/dist/bin.js
CHANGED
|
@@ -1805,31 +1805,37 @@ var import_core = __toESM(require_dist(), 1);
|
|
|
1805
1805
|
import { promises as fs2 } from "fs";
|
|
1806
1806
|
import * as path2 from "path";
|
|
1807
1807
|
|
|
1808
|
-
// src/
|
|
1808
|
+
// src/settings.ts
|
|
1809
1809
|
import { promises as fs } from "fs";
|
|
1810
1810
|
import * as os from "os";
|
|
1811
1811
|
import * as path from "path";
|
|
1812
1812
|
var DIR = path.join(os.homedir(), ".figma-mcp");
|
|
1813
|
-
var FILE = path.join(DIR, "
|
|
1814
|
-
function
|
|
1813
|
+
var FILE = path.join(DIR, "settings.json");
|
|
1814
|
+
function settingsPath() {
|
|
1815
1815
|
return FILE;
|
|
1816
1816
|
}
|
|
1817
|
-
async function
|
|
1817
|
+
async function loadSettings() {
|
|
1818
1818
|
try {
|
|
1819
1819
|
const raw = await fs.readFile(FILE, "utf8");
|
|
1820
|
-
|
|
1820
|
+
const parsed = JSON.parse(raw);
|
|
1821
|
+
if (!parsed.env || typeof parsed.env !== "object") parsed.env = {};
|
|
1822
|
+
return parsed;
|
|
1821
1823
|
} catch {
|
|
1822
|
-
return {};
|
|
1824
|
+
return { env: {} };
|
|
1823
1825
|
}
|
|
1824
1826
|
}
|
|
1825
|
-
async function
|
|
1826
|
-
const current = await
|
|
1827
|
-
const next = {
|
|
1827
|
+
async function saveSettings(patch) {
|
|
1828
|
+
const current = await loadSettings();
|
|
1829
|
+
const next = {
|
|
1830
|
+
...current,
|
|
1831
|
+
...patch,
|
|
1832
|
+
env: { ...current.env ?? {}, ...patch.env ?? {} }
|
|
1833
|
+
};
|
|
1828
1834
|
await fs.mkdir(DIR, { recursive: true });
|
|
1829
1835
|
await fs.writeFile(FILE, JSON.stringify(next, null, 2), { mode: 384 });
|
|
1830
1836
|
return next;
|
|
1831
1837
|
}
|
|
1832
|
-
async function
|
|
1838
|
+
async function clearSettings() {
|
|
1833
1839
|
try {
|
|
1834
1840
|
await fs.unlink(FILE);
|
|
1835
1841
|
} catch {
|
|
@@ -1839,24 +1845,25 @@ async function clearCredentials() {
|
|
|
1839
1845
|
// src/refresh.ts
|
|
1840
1846
|
var SKEW_MS = 6e4;
|
|
1841
1847
|
async function ensureFreshApiToken(apiUrl, force = false) {
|
|
1842
|
-
const
|
|
1843
|
-
|
|
1848
|
+
const settings = await loadSettings();
|
|
1849
|
+
const apiToken = settings.env?.FIGMA_MCP_TOKEN;
|
|
1850
|
+
if (!apiToken || !settings.refreshToken) return;
|
|
1844
1851
|
if (!force) {
|
|
1845
|
-
if (!
|
|
1846
|
-
if (Date.now() <
|
|
1852
|
+
if (!settings.apiTokenExpiresAt) return;
|
|
1853
|
+
if (Date.now() < settings.apiTokenExpiresAt - SKEW_MS) return;
|
|
1847
1854
|
}
|
|
1848
1855
|
const base = apiUrl.replace(/\/+$/, "");
|
|
1849
1856
|
try {
|
|
1850
1857
|
const res = await fetch(`${base}/auth/figma/cli-refresh`, {
|
|
1851
1858
|
method: "POST",
|
|
1852
1859
|
headers: { "Content-Type": "application/json" },
|
|
1853
|
-
body: JSON.stringify({ refresh_token:
|
|
1860
|
+
body: JSON.stringify({ refresh_token: settings.refreshToken })
|
|
1854
1861
|
});
|
|
1855
1862
|
if (!res.ok) return;
|
|
1856
1863
|
const t = await res.json();
|
|
1857
|
-
await
|
|
1858
|
-
|
|
1859
|
-
refreshToken: t.refresh_token ??
|
|
1864
|
+
await saveSettings({
|
|
1865
|
+
env: { FIGMA_MCP_TOKEN: t.access_token },
|
|
1866
|
+
refreshToken: t.refresh_token ?? settings.refreshToken,
|
|
1860
1867
|
apiTokenExpiresAt: t.expires_in ? Date.now() + t.expires_in * 1e3 : void 0
|
|
1861
1868
|
});
|
|
1862
1869
|
} catch {
|
|
@@ -1864,13 +1871,15 @@ async function ensureFreshApiToken(apiUrl, force = false) {
|
|
|
1864
1871
|
}
|
|
1865
1872
|
|
|
1866
1873
|
// src/config.ts
|
|
1874
|
+
var DEFAULT_API_URL = "https://figmacoder-api.sitenow.cloud";
|
|
1867
1875
|
async function resolveConfig(overrides = {}) {
|
|
1868
|
-
let
|
|
1869
|
-
|
|
1870
|
-
const
|
|
1871
|
-
const
|
|
1876
|
+
let settings = await loadSettings();
|
|
1877
|
+
let env = settings.env ?? {};
|
|
1878
|
+
const mode = overrides.mode ?? process.env.FIGMA_MCP_MODE ?? env.FIGMA_MCP_MODE ?? "auto";
|
|
1879
|
+
const pat = overrides.pat ?? process.env.FIGMA_PAT ?? process.env.FIGMA_TOKEN ?? env.FIGMA_PAT ?? env.FIGMA_TOKEN;
|
|
1880
|
+
const apiUrl = overrides.apiUrl ?? process.env.FIGMA_MCP_API ?? env.FIGMA_MCP_API ?? DEFAULT_API_URL;
|
|
1872
1881
|
const apiTokenOverride = overrides.apiToken ?? process.env.FIGMA_MCP_TOKEN;
|
|
1873
|
-
const outDir = overrides.outDir ?? process.env.FIGMA_MCP_OUT_DIR ?? `${process.cwd()}/figma-output`;
|
|
1882
|
+
const outDir = overrides.outDir ?? process.env.FIGMA_MCP_OUT_DIR ?? env.FIGMA_MCP_OUT_DIR ?? `${process.cwd()}/figma-output`;
|
|
1874
1883
|
let effectiveMode;
|
|
1875
1884
|
if (mode === "local") {
|
|
1876
1885
|
effectiveMode = "local";
|
|
@@ -1881,9 +1890,10 @@ async function resolveConfig(overrides = {}) {
|
|
|
1881
1890
|
}
|
|
1882
1891
|
if (effectiveMode === "remote" && apiUrl && !apiTokenOverride) {
|
|
1883
1892
|
await ensureFreshApiToken(apiUrl);
|
|
1884
|
-
|
|
1893
|
+
settings = await loadSettings();
|
|
1894
|
+
env = settings.env ?? {};
|
|
1885
1895
|
}
|
|
1886
|
-
const apiToken = apiTokenOverride ??
|
|
1896
|
+
const apiToken = apiTokenOverride ?? env.FIGMA_MCP_TOKEN;
|
|
1887
1897
|
return { mode, effectiveMode, pat, apiUrl, apiToken, outDir };
|
|
1888
1898
|
}
|
|
1889
1899
|
function describeConfig(cfg) {
|
|
@@ -1907,7 +1917,7 @@ async function post(cfg, route, body) {
|
|
|
1907
1917
|
let res = await fetch(url, { method: "POST", headers: authHeaders(cfg), body: payload });
|
|
1908
1918
|
if (res.status === 401 && cfg.apiToken) {
|
|
1909
1919
|
await ensureFreshApiToken(cfg.apiUrl, true);
|
|
1910
|
-
const refreshed = (await
|
|
1920
|
+
const refreshed = (await loadSettings()).env?.FIGMA_MCP_TOKEN;
|
|
1911
1921
|
if (refreshed && refreshed !== cfg.apiToken) {
|
|
1912
1922
|
res = await fetch(url, { method: "POST", headers: authHeaders(cfg, refreshed), body: payload });
|
|
1913
1923
|
}
|
|
@@ -2058,12 +2068,12 @@ function buildServer() {
|
|
|
2058
2068
|
"convert_figma_to_html",
|
|
2059
2069
|
{
|
|
2060
2070
|
title: "Convert Figma to HTML + Tailwind",
|
|
2061
|
-
description: "Convert a Figma file/node into finished, self-contained HTML + Tailwind (deterministic Style IR,
|
|
2071
|
+
description: "Convert a Figma file/node into finished, self-contained HTML + Tailwind (deterministic Style IR, optional LLM restructure). Asset inlining is off by default (placeholders shown for images/vectors); pass assets:true to render & inline them. The HTML is written to a file; a compact summary + path is returned to keep context small.",
|
|
2062
2072
|
inputSchema: {
|
|
2063
2073
|
...targetShape,
|
|
2064
2074
|
mode: z.enum(["tailwind", "inline"]).optional().describe("Output mode. Default 'tailwind'."),
|
|
2065
2075
|
document: z.boolean().optional().describe("Emit a full HTML document (default true) vs a fragment."),
|
|
2066
|
-
assets: z.boolean().optional().describe("Export & inline vectors/images as data URIs. Default
|
|
2076
|
+
assets: z.boolean().optional().describe("Export & inline vectors/images as data URIs. Default false (placeholders shown instead)."),
|
|
2067
2077
|
assetScale: z.number().min(1).max(4).optional().describe("Raster export scale (1-4). Default 2."),
|
|
2068
2078
|
llm: z.boolean().optional().describe("Run the LLM restructure pass (needs OLLAMA_* config). Default false."),
|
|
2069
2079
|
outFile: z.string().optional().describe("Override the output file name (within the output dir).")
|
|
@@ -2100,9 +2110,7 @@ var page = (title, body) => `<!doctype html><meta charset="utf-8"><title>figma-c
|
|
|
2100
2110
|
async function login(opts = {}) {
|
|
2101
2111
|
const cfg = await resolveConfig({ apiUrl: opts.apiUrl });
|
|
2102
2112
|
if (!cfg.apiUrl) {
|
|
2103
|
-
throw new Error(
|
|
2104
|
-
"OAuth login needs the backend URL. Set it with `figma-coder-mcp set-api <URL>` or FIGMA_MCP_API."
|
|
2105
|
-
);
|
|
2113
|
+
throw new Error("OAuth login needs the backend URL. Set FIGMA_MCP_API or pass --api <URL>.");
|
|
2106
2114
|
}
|
|
2107
2115
|
const base = cfg.apiUrl.replace(/\/+$/, "");
|
|
2108
2116
|
const tokens = await new Promise((resolve2, reject) => {
|
|
@@ -2155,13 +2163,15 @@ If it doesn't open automatically, visit:
|
|
|
2155
2163
|
openBrowser(authorizeUrl);
|
|
2156
2164
|
});
|
|
2157
2165
|
});
|
|
2158
|
-
await
|
|
2159
|
-
|
|
2160
|
-
|
|
2166
|
+
await saveSettings({
|
|
2167
|
+
env: {
|
|
2168
|
+
FIGMA_MCP_API: base,
|
|
2169
|
+
FIGMA_MCP_TOKEN: tokens.access_token
|
|
2170
|
+
},
|
|
2161
2171
|
refreshToken: tokens.refresh_token,
|
|
2162
2172
|
apiTokenExpiresAt: tokens.expires_in ? Date.now() + tokens.expires_in * 1e3 : void 0
|
|
2163
2173
|
});
|
|
2164
|
-
console.error(`\u2713 Saved Figma OAuth session to ${
|
|
2174
|
+
console.error(`\u2713 Saved Figma OAuth session to ${settingsPath()}`);
|
|
2165
2175
|
console.error("Run the MCP in remote mode (set FIGMA_MCP_MODE=remote) to use it.");
|
|
2166
2176
|
}
|
|
2167
2177
|
|
|
@@ -2192,29 +2202,30 @@ function targetFrom(value, flags) {
|
|
|
2192
2202
|
if (/figma\.com\//.test(value)) return { figmaUrl: value, nodeId };
|
|
2193
2203
|
return { fileKey: value, nodeId };
|
|
2194
2204
|
}
|
|
2195
|
-
var HELP = `figma-coder-mcp
|
|
2205
|
+
var HELP = `figma-coder-mcp: Figma -> HTML/Tailwind for AI agents (MCP server + CLI)
|
|
2196
2206
|
|
|
2197
2207
|
Usage:
|
|
2198
2208
|
figma-coder-mcp [serve] Start the MCP server over stdio (default)
|
|
2199
2209
|
figma-coder-mcp convert <url|key> [..] One-off convert to HTML (writes a file)
|
|
2200
2210
|
figma-coder-mcp data <url|key> [..] One-off: print/save the Style IR
|
|
2201
2211
|
figma-coder-mcp set-token <PAT> Store a Figma personal access token (local mode)
|
|
2202
|
-
figma-coder-mcp set-api <URL> Store the backend converter URL (remote mode)
|
|
2203
2212
|
figma-coder-mcp login [--api <URL>] Log in with Figma via OAuth (remote mode)
|
|
2204
2213
|
figma-coder-mcp status Show how requests will be served (no secrets)
|
|
2205
|
-
figma-coder-mcp logout Remove stored
|
|
2214
|
+
figma-coder-mcp logout Remove stored settings
|
|
2206
2215
|
figma-coder-mcp help Show this help
|
|
2207
2216
|
|
|
2208
2217
|
Common flags (convert/data):
|
|
2209
2218
|
--node <id> Node id ("1-23" or "1:23")
|
|
2210
2219
|
--mode <m> tailwind | inline (convert)
|
|
2211
|
-
--
|
|
2220
|
+
--assets Render & inline assets (convert; off by default, placeholders shown)
|
|
2212
2221
|
--llm Run LLM restructure (convert; needs OLLAMA_* env)
|
|
2213
2222
|
--out <file> Output file name (convert)
|
|
2214
2223
|
|
|
2215
2224
|
Config (env or stored): FIGMA_PAT, FIGMA_MCP_API, FIGMA_MCP_TOKEN, FIGMA_MCP_MODE,
|
|
2216
2225
|
FIGMA_MCP_OUT_DIR, FIGMA_MCP_NO_BROWSER (skip auto-opening the browser on login).
|
|
2217
|
-
Auto mode prefers local (PAT) so it works even if the backend is down
|
|
2226
|
+
Auto mode prefers local (PAT) so it works even if the backend is down; with no PAT
|
|
2227
|
+
it uses the hosted backend by default (override the URL with FIGMA_MCP_API).
|
|
2228
|
+
Stored settings live in ~/.figma-mcp/settings.json under "env" (edit it directly if you like).`;
|
|
2218
2229
|
async function main() {
|
|
2219
2230
|
const [positionals, flags] = parseArgs(process.argv.slice(2));
|
|
2220
2231
|
const cmd = positionals[0] ?? "serve";
|
|
@@ -2227,7 +2238,7 @@ async function main() {
|
|
|
2227
2238
|
const text = await convertFigmaToHtml({
|
|
2228
2239
|
...targetFrom(positionals[1], flags),
|
|
2229
2240
|
mode: flags.mode === "inline" ? "inline" : flags.mode === "tailwind" ? "tailwind" : void 0,
|
|
2230
|
-
assets: flags["no-assets"] ? false : void 0,
|
|
2241
|
+
assets: flags.assets ? true : flags["no-assets"] ? false : void 0,
|
|
2231
2242
|
llm: flags.llm === true,
|
|
2232
2243
|
outFile: typeof flags.out === "string" ? flags.out : void 0
|
|
2233
2244
|
});
|
|
@@ -2242,15 +2253,8 @@ async function main() {
|
|
|
2242
2253
|
case "set-token": {
|
|
2243
2254
|
const pat = positionals[1];
|
|
2244
2255
|
if (!pat) throw new Error("Usage: figma-coder-mcp set-token <PAT>");
|
|
2245
|
-
await
|
|
2246
|
-
console.log(`Stored
|
|
2247
|
-
return;
|
|
2248
|
-
}
|
|
2249
|
-
case "set-api": {
|
|
2250
|
-
const url = positionals[1];
|
|
2251
|
-
if (!url) throw new Error("Usage: figma-coder-mcp set-api <URL>");
|
|
2252
|
-
await saveCredentials({ apiUrl: url });
|
|
2253
|
-
console.log(`Stored backend URL (${url}) in ${credentialsPath()}`);
|
|
2256
|
+
await saveSettings({ env: { FIGMA_PAT: pat } });
|
|
2257
|
+
console.log(`Stored FIGMA_PAT in ${settingsPath()}`);
|
|
2254
2258
|
return;
|
|
2255
2259
|
}
|
|
2256
2260
|
case "login": {
|
|
@@ -2260,12 +2264,12 @@ async function main() {
|
|
|
2260
2264
|
case "status": {
|
|
2261
2265
|
const cfg = await resolveConfig();
|
|
2262
2266
|
console.log(describeConfig(cfg));
|
|
2263
|
-
console.log(`
|
|
2267
|
+
console.log(`settings: ${settingsPath()}`);
|
|
2264
2268
|
return;
|
|
2265
2269
|
}
|
|
2266
2270
|
case "logout":
|
|
2267
|
-
await
|
|
2268
|
-
console.log("Cleared stored
|
|
2271
|
+
await clearSettings();
|
|
2272
|
+
console.log("Cleared stored settings.");
|
|
2269
2273
|
return;
|
|
2270
2274
|
case "help":
|
|
2271
2275
|
case "--help":
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "figma-coder-mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "MCP server + CLI that converts Figma designs into HTML + Tailwind for AI coding agents. Runs locally with a Figma PAT (no backend) or delegates to a figma-to-html-api backend.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "GoldynLabs",
|
|
@@ -29,10 +29,8 @@
|
|
|
29
29
|
"claude",
|
|
30
30
|
"cursor"
|
|
31
31
|
],
|
|
32
|
-
"repository":
|
|
33
|
-
|
|
34
|
-
"url": "git+https://github.com/goldynlabs/figma-coder-mcp.git"
|
|
35
|
-
},
|
|
32
|
+
"repository": "",
|
|
33
|
+
"homepage": "https://figmacoder.sitenow.cloud",
|
|
36
34
|
"scripts": {
|
|
37
35
|
"build": "tsup",
|
|
38
36
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|