figma-developer-mcp
by p1t42
README.md
# Figma MCP (personal access token)
Read-only Figma access for any MCP client, driven by your own PAT instead of per-client OAuth.
This folder is the single source of truth — `~/.config/figma-mcp` is a symlink to it.
## Layout
| Path | Purpose |
|---|---|
| `figma-mcp.sh` | stdio launcher (700). Every client points here, so no client config holds a secret |
| `env` | **your token** (600, git-ignored). The only place it exists |
| `env.example` | template. Never put a real token here — it is world-readable and not git-ignored |
| `package.json` / `package-lock.json` | pins the entire dependency tree |
| `node_modules/` | local locked install (git-ignored) |
| `assets/` | default download dir for `download_figma_images`; override with `IMAGE_DIR` in `env` |
| `../.mcp.json` | project-level MCP config at the `swe_projects` root |
Server: `figma-developer-mcp@0.13.2` (Framelink), Figma REST API, stdio transport.
## Token
Figma -> account settings -> **Security** -> *Personal access tokens*. Scopes:
- `file_content:read` — for `/v1/files/:key`, `/v1/files/:key/nodes`, `/v1/images/:key`
- `file_dev_resources:read` — Dev resources
Rotate by editing `env` only — no client config changes. Set an expiration when creating it: a PAT can read
**every file your account can access**, org-wide, with no per-file scoping.
## Hardening applied
- Token passed via env var, never a CLI flag, so it stays out of `ps` output.
- **Locked install** rather than `npx -y`: `package-lock.json` pins all 134 transitive packages, so
dependencies cannot drift between runs. Reinstall with `npm ci`. (Pinning only the top-level version
would still have let sub-dependencies resolve fresh on every launch.)
- **Telemetry off**: the package bundles PostHog with a hardcoded key. The launcher exports
`FRAMELINK_TELEMETRY=off` and `DO_NOT_TRACK=1`.
## Client snippets
Replace `<REPO>` with the absolute path to this folder. These configs are read by different
runtimes and none of them reliably expand `~` or `$HOME`, so the path has to be spelled out.
**Standard `mcpServers` JSON** — Gemini CLI (`~/.gemini/settings.json`), Cursor (`~/.cursor/mcp.json`), VS Code, project `.mcp.json`:
```json
{
"mcpServers": {
"figma": {
"command": "<REPO>/figma-mcp.sh",
"args": []
}
}
}
```
**opencode** (`~/.config/opencode/opencode.jsonc`) — configured:
```jsonc
{
"mcp": {
"figma": {
"type": "local",
"command": ["<REPO>/figma-mcp.sh"],
"enabled": true
}
}
}
```
**Claude Code** — registered at user scope:
```sh
claude mcp add figma -s user -- <REPO>/figma-mcp.sh
```
**Codex CLI** (`~/.codex/config.toml`) — untested, Codex not installed here:
```toml
[mcp_servers.figma]
command = "<REPO>/figma-mcp.sh"
```
## Smoke test
```sh
printf '%s\n%s\n%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"t","version":"0"}}}' \
'{"jsonrpc":"2.0","method":"notifications/initialized"}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
| ./figma-mcp.sh
```
Expect `Figma MCP Server 0.13.2` and two tools: `get_figma_data`, `download_figma_images`.
Note: `grep -r` silently returns nothing under some sandboxes on this machine. Use
`find . -type f -exec grep -l PATTERN {} +` when sweeping for secrets.
## Limits
Read-only: file/node layout, styles, image asset download. Creating Figma files, Code Connect, and design
generation exist only in Figma's official server (`https://mcp.figma.com/mcp`), which is **OAuth-only** —
it does not accept personal access tokens — and only admits clients on Figma's MCP catalog.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues