Skip to content

Allen-han21/figma-mcp

ย 
ย 

Repository files navigation

Figma MCP Server

Version OCaml MCP Status License

OCaml 5.x ๋„ค์ดํ‹ฐ๋ธŒ MCP ์„œ๋ฒ„ - Figma ๋””์ž์ธ์„ ์ •ํ™•๋„ ์šฐ์„  Fidelity DSL๋กœ ๋ณ€ํ™˜

Note: This is a personal project.

Quickstart

eval $(opam env)
opam pin add grpc-direct https://github.com/jeong-sik/grpc-direct.git -y
opam install . --deps-only
dune build
export FIGMA_TOKEN="YOUR_TOKEN"
./start-figma-mcp-http.sh --port 8940
{
  "mcpServers": {
    "figma": {
      "type": "http",
      "url": "http://127.0.0.1:8940/mcp"
    }
  }
}

ํŠน์ง•

  • MCP 2025-11-25 ์ŠคํŽ™ ์ค€์ˆ˜ - JSON-RPC 2.0 over stdio
  • ์ •ํ™•๋„ ์šฐ์„  - ๋ ˆ์ด์•„์›ƒ/ํŽ˜์ธํŠธ/๋ณด๋”/ํƒ€์ดํฌ๋ฅผ ์ตœ๋Œ€ํ•œ ๊ทธ๋Œ€๋กœ ์ „๋‹ฌ
  • ํƒ€์ž… ์•ˆ์ „ - OCaml Variant/ADT ๊ธฐ๋ฐ˜ ํŒŒ์‹ฑ (HTML ๋ชจ๋“œ)
  • ๋น ๋ฅธ ์‹คํ–‰ - ๋„ค์ดํ‹ฐ๋ธŒ ๋ฐ”์ด๋„ˆ๋ฆฌ (5.5MB)

Capabilities

Capabilities: tools โœ… ยท resources โœ… ยท prompts โœ…
Capability ์ƒํƒœ ์„ค๋ช…
tools โœ… ์ง€์› 51๊ฐœ ๋„๊ตฌ (์•„๋ž˜ ๋ชฉ๋ก ์ฐธ์กฐ)
resources โœ… ์ง€์› figma://docs/* ๊ฐ€์ด๋“œ
prompts โœ… ์ง€์› Fidelity ๋ฆฌ๋ทฐ ํ”„๋กฌํ”„ํŠธ

Resources

figma://docs/fidelity  # Fidelity DSL ํ‚ค ์„ค๋ช…
figma://docs/usage     # ์ •ํ™•๋„ ์šฐ์„  ํ˜ธ์ถœ ํŒจํ„ด

Prompts

# ๋ฆฌ์ŠคํŠธ ์กฐํšŒ
echo '{"jsonrpc":"2.0","id":4,"method":"prompts/list","params":{}}' | ./start-figma-mcp.sh

# ๋‹จ์ผ ํ”„๋กฌํ”„ํŠธ ์กฐํšŒ (text ํฌํ•จ)
echo '{"jsonrpc":"2.0","id":5,"method":"prompts/get","params":{"name":"figma_fidelity_review"}}' | ./start-figma-mcp.sh

Recipes

  • docs/RECIPES.md - end-to-end usage patterns (quickstart, high fidelity, large nodes)
  • docs/SETUP.md - ์„ค์น˜/์‹คํ–‰/์—ฐ๋™ ์š”์•ฝ
  • docs/MCP-TEMPLATE.md - ~/.mcp.json ํ…œํ”Œ๋ฆฟ
  • docs/INSTALL-CHECKLIST.md - ์„ค์น˜ ํ›„ ํ™•์ธ

๋„๊ตฌ ๋ชฉ๋ก (51๊ฐœ)

Phase 1: Core

Tool ์„ค๋ช… ํ…Œ์ŠคํŠธ
figma_codegen Figma JSON โ†’ Fidelity DSL ๋ณ€ํ™˜ โœ…
figma_get_file Figma API์—์„œ ํŒŒ์ผ ๊ฐ€์ ธ์™€ DSL ๋ณ€ํ™˜ โœ…
figma_get_file_meta ํŒŒ์ผ ๋ฉ”ํƒ€(components/componentSets/styles) ๋ฐ˜ํ™˜ โœ…
figma_list_screens ํŒŒ์ผ ๋‚ด ํ™”๋ฉด(Frame/Component) ๋ชฉ๋ก โœ…
figma_get_node ํŠน์ • ๋…ธ๋“œ ID๋งŒ ๊ฐ€์ ธ์™€ DSL ๋ณ€ํ™˜ โœ…
figma_get_node_bundle ์ •ํ™•๋„ ๊ทน๋Œ€ํ™” ๋ฒˆ๋“ค(DSL+๋ Œ๋”+๋ฉ”ํƒ€+๋ณ€์ˆ˜+fills) โœ…
figma_get_node_summary ๊ฒฝ๋Ÿ‰ ๊ตฌ์กฐ ์š”์•ฝ โœ…
figma_select_nodes ํ›„๋ณด ๋…ธ๋“œ ์ ์ˆ˜ํ™”/์„ ๋ณ„ + ๋…ธํŠธ ํ…์ŠคํŠธ ๋ถ„๋ฆฌ โœ…
figma_get_node_chunk ๊นŠ์ด ๋ฒ”์œ„๋ณ„ ๋…ธ๋“œ ์ฒญํฌ ๋กœ๋“œ โœ…
figma_fidelity_loop fidelity ์ ์ˆ˜ ๋ฏธ๋‹ฌ ์‹œ depth/geometry ์ž๋™ ์ƒํ–ฅ โœ…
figma_image_similarity ๋ Œ๋” ์ด๋ฏธ์ง€ SSIM/PSNR ๋น„๊ต โœ…
figma_export_image ๋…ธ๋“œ๋ฅผ PNG/JPG/SVG/PDF URL๋กœ ๋‚ด๋ณด๋‚ด๊ธฐ โœ…
figma_get_image_fills ํŒŒ์ผ ๋‚ด ์ด๋ฏธ์ง€ ์ฑ„์›€(image fills) ์›๋ณธ URL โœ…
figma_get_nodes ์—ฌ๋Ÿฌ ๋…ธ๋“œ ID๋ฅผ ํ•œ๋ฒˆ์— ์กฐํšŒ โœ…
figma_get_file_versions ํŒŒ์ผ ๋ฒ„์ „ ๋ชฉ๋ก ์กฐํšŒ โœ…
figma_get_file_comments ํŒŒ์ผ ์ฝ”๋ฉ˜ํŠธ ๋ชฉ๋ก ์กฐํšŒ โœ…
figma_post_comment ํŒŒ์ผ ์ฝ”๋ฉ˜ํŠธ ์ƒ์„ฑ โœ…
figma_get_file_components ํŒŒ์ผ ์ปดํฌ๋„ŒํŠธ ๋ชฉ๋ก โœ…
figma_get_team_components ํŒ€ ์ปดํฌ๋„ŒํŠธ ๋ชฉ๋ก โœ…
figma_get_file_component_sets ํŒŒ์ผ ์ปดํฌ๋„ŒํŠธ ์…‹ ๋ชฉ๋ก โœ…
figma_get_team_component_sets ํŒ€ ์ปดํฌ๋„ŒํŠธ ์…‹ ๋ชฉ๋ก โœ…
figma_get_file_styles ํŒŒ์ผ ์Šคํƒ€์ผ ๋ชฉ๋ก โœ…
figma_get_team_styles ํŒ€ ์Šคํƒ€์ผ ๋ชฉ๋ก โœ…
figma_get_component ์ปดํฌ๋„ŒํŠธ ์ƒ์„ธ ์กฐํšŒ โœ…
figma_get_component_set ์ปดํฌ๋„ŒํŠธ ์…‹ ์ƒ์„ธ ์กฐํšŒ โœ…
figma_get_style ์Šคํƒ€์ผ ์ƒ์„ธ ์กฐํšŒ โœ…
figma_plugin_connect ํ”Œ๋Ÿฌ๊ทธ์ธ ์ฑ„๋„ ์ƒ์„ฑ/์—ฐ๊ฒฐ โœ…
figma_plugin_use_channel ๊ธฐ๋ณธ ์ฑ„๋„ ์„ค์ • โœ…
figma_plugin_status ํ”Œ๋Ÿฌ๊ทธ์ธ ์ฑ„๋„ ์ƒํƒœ โœ…
figma_plugin_read_selection ํ”Œ๋Ÿฌ๊ทธ์ธ์—์„œ ์„ ํƒ ๋…ธ๋“œ ์ฝ๊ธฐ โœ…
figma_plugin_get_node ํ”Œ๋Ÿฌ๊ทธ์ธ์—์„œ ํŠน์ • ๋…ธ๋“œ ์ฝ๊ธฐ โœ…
figma_plugin_export_node_image ํ”Œ๋Ÿฌ๊ทธ์ธ exportAsync ์ด๋ฏธ์ง€(base64) โœ…
figma_plugin_get_variables ํ”Œ๋Ÿฌ๊ทธ์ธ Variables API ์ถ”์ถœ โœ…
figma_plugin_apply_ops ํ”Œ๋Ÿฌ๊ทธ์ธ์œผ๋กœ create/update/delete โœ…

Phase 1.5: Visual Feedback Loop (95%+ ์ •ํ™•๋„)

Tool ์„ค๋ช… ํ…Œ์ŠคํŠธ
figma_verify_visual HTML ์ƒ์„ฑ + Playwright ๋ Œ๋” + SSIM ๋น„๊ต โ†’ ์ž๋™ ์กฐ์ • โœ…

Evolution Tracking (์ง„ํ™” ์ถ”์ )

figma_verify_visual์€ ์ง„ํ™” ๊ณผ์ •์„ ์ž๋™ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค:

/tmp/figma-evolution/run_1705123456789/
โ”œโ”€โ”€ figma_original.png       # Figma ์›๋ณธ ๋ Œ๋”
โ”œโ”€โ”€ step1_render.png         # 1์ฐจ ์‹œ๋„ ๋ Œ๋”
โ”œโ”€โ”€ step2_render.png         # 2์ฐจ ์‹œ๋„ ๋ Œ๋” (์กฐ์ • ํ›„)
โ”œโ”€โ”€ final_render.png         # ์ตœ์ข… ๋ Œ๋”
โ”œโ”€โ”€ html/
โ”‚   โ”œโ”€โ”€ step1.html           # 1์ฐจ ์‹œ๋„ HTML
โ”‚   โ”œโ”€โ”€ step2.html           # 2์ฐจ ์‹œ๋„ HTML
โ”‚   โ””โ”€โ”€ final.html           # ์ตœ์ข… HTML
โ””โ”€โ”€ evolution.json           # ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ

ํ•ต์‹ฌ ์ธ์‚ฌ์ดํŠธ: Flat HTML > Nested HTML

์ ‘๊ทผ ๋ฐฉ์‹ SSIM ๋ฌธ์ œ์ 
Nested (Figma ๊ณ„์ธต ๋ณต์ œ) 72% padding/gap ๋ˆ„์ ์œผ๋กœ ์œ„์น˜ ํ‹€์–ด์ง
Flat 2-level 99% ์ค‘์•™ ์ •๋ ฌ + typography ์™„์ „ ์žฌํ˜„
<!-- โŒ ์‹คํŒจ: ์ค‘์ฒฉ div -->
<div style="display:flex;flex-direction:column;padding:0px 16px;gap:10px">
  <div style="padding:12px 20px;gap:8px">
    <div style="gap:4px"><span>๋”๋ณด๊ธฐ</span></div>
  </div>
</div>

<!-- โœ… ์„ฑ๊ณต: Flat 2-level -->
<div style="display:flex;align-items:center;justify-content:center;width:343px;height:48px">
  <div style="display:flex;align-items:center;justify-content:center;background:rgb(32,141,249);border-radius:10px">
    <span style="letter-spacing:-0.32px;line-height:24px">๋”๋ณด๊ธฐ</span>
  </div>
</div>

node_id ํ˜•์‹ (์ค‘์š”)

  • Figma URL์—์„œ๋Š” node-id=2089-11127(ํ•˜์ดํ”ˆ)์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ, API๋Š” 2089:11127(์ฝœ๋ก ) ํ˜•์‹๋งŒ ๋ฐ›์Šต๋‹ˆ๋‹ค.
  • MCP ๋„๊ตฌ(figma_get_node, figma_get_node_bundle)์˜ node_id๋Š” ์ฝœ๋ก  ํ˜•์‹์ด ๊ถŒ์žฅ์ž…๋‹ˆ๋‹ค.
  • ๋ณ€ํ™˜ ๊ทœ์น™: 2089-11127 -> 2089:11127
  • MCP ๋„๊ตฌ/gRPC๋Š” ํ•˜์ดํ”ˆ ํ˜•์‹๋„ ์ž๋™ ์ •๊ทœํ™”ํ•ฉ๋‹ˆ๋‹ค.
  • ํŒ: figma_parse_url๋กœ URL์—์„œ node_id๋ฅผ ์ถ”์ถœํ•˜๋ฉด ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ์‹œ:

figma_get_node_bundle
  file_key: "YOUR_FIGMA_FILE_KEY"
  node_id: "2089:11127"
  format: "html"
  depth: 15
  download: true

์ •ํ™•๋„ ์ตœ์šฐ์„  ํ˜ธ์ถœ

  • figma_get_node_bundle ๊ถŒ์žฅ: DSL + ๋ Œ๋” + ๋ฉ”ํƒ€/๋ณ€์ˆ˜/์ด๋ฏธ์ง€ fills๋ฅผ ํ•œ๋ฒˆ์— ์ˆ˜์ง‘
  • ํ”Œ๋Ÿฌ๊ทธ์ธ ์Šค๋ƒ…์ƒท์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ include_plugin=true + plugin_channel_id ์‚ฌ์šฉ (ํ…์ŠคํŠธ ์„ธ๊ทธ๋จผํŠธ/๋ฒ”์œ„ ํฌํ•จ)
  • fidelity ์ ์ˆ˜ ๊ธฐ๋ฐ˜ ์ž๋™ ์žฌ์กฐํšŒ: figma_fidelity_loop + include_variables=true + include_image_fills=true + include_plugin=true
  • ๋ Œ๋” ๊ธฐ์ค€ ์ •๋ฐ€ ๋น„๊ต: figma_image_similarity (SSIM/PSNR)
  • format=raw ์‚ฌ์šฉ ์‹œ ์›๋ณธ JSON ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ (์ถœ๋ ฅ ํผ)
  • figma_get_variables๋Š” format=resolved๋กœ ๊ธฐ๋ณธ ๋ชจ๋“œ ๊ฐ’ ํฌํ•จ

์˜ˆ์‹œ:

figma_fidelity_loop
  file_key: "YOUR_FIGMA_FILE_KEY"
  node_id: "2089:11127"
  target_score: 0.95
  include_variables: true
  include_image_fills: true
  include_plugin: true

๋ Œ๋” ๋น„๊ต๋Š” PNG/JPG๋ฅผ PPM์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ ์œ„ํ•ด sips(macOS) ๋˜๋Š” ImageMagick(magick/convert)์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์ •ํ™•๋„ ์ธก์ • ์Šคํฌ๋ฆฝํŠธ (LLM-free)

Figma MCP ๊ฒฐ๊ณผ๋ฅผ ์ •๋Ÿ‰ํ™”๋œ ๋ฆฌํฌํŠธ๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

./scripts/figma-accuracy-eval.py \
  --file-key "FILE_KEY" \
  --node-id "123:456" \
  --token "$FIGMA_TOKEN" \
  --include-plugin \
  --plugin-channel-id "ch-..." \
  --out "$HOME/me/logs/figma-accuracy-123_456.json"
  • ๊ธฐ๋ณธ MCP URL: http://localhost:8940/mcp (FIGMA_MCP_URL๋กœ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ)
  • ๋น„๊ต ๋…ธ๋“œ๊ฐ€ ์žˆ์œผ๋ฉด --compare-node-id๋กœ SSIM/PSNR๋„ ๊ธฐ๋ก

Phase 2: Navigation & Search

Tool ์„ค๋ช… ํ…Œ์ŠคํŠธ
figma_parse_url URL์—์„œ team/project/file/node ID ์ถ”์ถœ (API ํ˜ธ์ถœ ์—†์Œ) โœ…
figma_get_me ํ˜„์žฌ ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž ์ •๋ณด โœ…
figma_list_projects ํŒ€์˜ ํ”„๋กœ์ ํŠธ ๋ชฉ๋ก โœ…
figma_list_files ํ”„๋กœ์ ํŠธ์˜ ํŒŒ์ผ ๋ชฉ๋ก โœ…
figma_get_variables ๋””์ž์ธ ํ† ํฐ/๋ณ€์ˆ˜ ์กฐํšŒ โŒ Enterprise ๋˜๋Š” file_variables:read ์Šค์ฝ”ํ”„ ํ•„์š”

Phase 3: Analysis & Comparison

Tool ์„ค๋ช… ํ…Œ์ŠคํŠธ
figma_search ํ…์ŠคํŠธ/๋…ธ๋“œ ์ด๋ฆ„ ๊ฒ€์ƒ‰ โœ…
figma_query SQL-like ์กฐ๊ฑด๋ถ€ ํ•„ํ„ฐ๋ง (type, size, color ๋“ฑ) โœ…
figma_tree ๋…ธ๋“œ ํŠธ๋ฆฌ ์‹œ๊ฐํ™” (ASCII/indent/compact) โœ…
figma_stats ๋””์ž์ธ ํ†ต๊ณ„ (์ƒ‰์ƒ, ํฐํŠธ, ํฌ๊ธฐ ๋ถ„ํฌ) โœ…
figma_compare ๋‘ ๋…ธ๋“œ ๋น„๊ต (Web/Mobile ์ผ๊ด€์„ฑ ๊ฒ€์‚ฌ) โœ…
figma_export_tokens CSS/Tailwind/JSON ๋””์ž์ธ ํ† ํฐ ์ถ”์ถœ โœ…

Phase 4: Ops & Cache

Tool ์„ค๋ช… ํ…Œ์ŠคํŠธ
figma_doctor ๋กœ์ปฌ ์˜์กด์„ฑ/์Šคํฌ๋ฆฝํŠธ ๊ฒฝ๋กœ ์ ๊ฒ€ โœ…
figma_read_large_result large_result ํŒŒ์ผ chunk ์ฝ๊ธฐ โœ…
figma_cache_stats L1/L2 ์บ์‹œ ํ†ต๊ณ„ ์กฐํšŒ โœ…
figma_cache_invalidate ์บ์‹œ ๋ฌดํšจํ™” โœ…

ํ…Œ์ŠคํŠธ ํ˜„ํ™ฉ (2026-01-14)

  • ์„ฑ๊ณต: 15/16 ๋„๊ตฌ (Core ๊ธฐ์ค€)
  • ์ œํ•œ: figma_get_variables - Figma Variables API๋Š” Enterprise ํ”Œ๋žœ ๋˜๋Š” file_variables:read OAuth ์Šค์ฝ”ํ”„ ํ•„์š”
  • ์‹ ๊ทœ ๋„๊ตฌ: REST Parity/Plugin Bridge๋Š” ์ƒ˜ํ”Œ ํŒŒ์ผ ๊ธฐ์ค€ ์ถ”๊ฐ€ ๊ฒ€์ฆ ์˜ˆ์ •

์„ค์น˜

# opam ํ™˜๊ฒฝ
eval $(opam env)

# ์™ธ๋ถ€ ์˜์กด์„ฑ pin (opam์— ์—†์Œ)
opam pin add grpc-direct https://github.com/jeong-sik/grpc-direct.git -y

# ์˜์กด์„ฑ ์„ค์น˜
opam install . --deps-only

# ๋นŒ๋“œ
dune build

# ์‹คํ–‰ (๋กœ์ปฌ ๋นŒ๋“œ)
dune exec figma-mcp

ํ† ํฐ ์„ค์ • (Keychain)

start-figma-mcp.sh์™€ start-figma-mcp-http.sh๋Š” Keychain์—์„œ FIGMA_TOKEN์„ ์ฝ์Šต๋‹ˆ๋‹ค.

# 1) ํ™˜๊ฒฝ๋ณ€์ˆ˜๋กœ ์‹คํ–‰ (์ผํšŒ์„ฑ)
export FIGMA_TOKEN="YOUR_TOKEN"

# 2) Keychain ์ €์žฅ (๊ถŒ์žฅ)
security add-generic-password -s "figma-mcp" -a "FIGMA_TOKEN" -w "YOUR_TOKEN"

Claude Code MCP ์„ค์ •

~/.mcp.json ๋˜๋Š” ํ”„๋กœ์ ํŠธ .mcp.json์— ์ถ”๊ฐ€:

{
  "mcpServers": {
    "figma": {
      "command": "/path/to/figma-mcp/start-figma-mcp.sh",
      "args": []
    }
  }
}

Figma Plugin Bridge (๊ณ ์ •๋ฐ€ ์Šค๋ƒ…์ƒท)

REST API๋งŒ์œผ๋กœ ๋ถ€์กฑํ•œ ๋ ˆ์ด์•„์›ƒ/์Šคํƒ€์ผ ์ •๋ณด๋ฅผ ๋ณด๊ฐ•ํ•˜๋ ค๋ฉด ํ”Œ๋Ÿฌ๊ทธ์ธ ๋ธŒ๋ฆฟ์ง€๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜์„ธ์š”.

  1. HTTP ๋ชจ๋“œ ์„œ๋ฒ„ ์‹คํ–‰ (์˜ˆ: 8940)
./start-figma-mcp-http.sh --port 8940
  1. Figma ํ”Œ๋Ÿฌ๊ทธ์ธ ์„ค์น˜
  • Figma โ†’ Plugins โ†’ Development โ†’ Import plugin from manifestโ€ฆ
  • plugin/manifest.json ์„ ํƒ
  • Import ์‹คํŒจ ์‹œ: Figma โ†’ Plugins โ†’ Development โ†’ New Plugin์œผ๋กœ ์ƒ์„ฑ ํ›„, ์ƒ์„ฑ๋œ manifest.json์˜ ์ˆซ์ž ID๋กœ plugin/manifest.json์˜ id ๊ต์ฒด
  • allowedDomains ์— http://localhost:... ๋„ฃ์œผ๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋‚  ์ˆ˜ ์žˆ์œผ๋‹ˆ, ๋กœ์ปฌ์€ devAllowedDomains์—๋งŒ ๋„ฃ๊ณ  allowedDomains๋Š” https ๋„๋ฉ”์ธ๋งŒ ์œ ์ง€
  • Figma๋Š” devAllowedDomains์—์„œ IP(์˜ˆ: 127.0.0.1)๋ฅผ ๊ฑฐ๋ถ€ํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ localhost๋งŒ ์‚ฌ์šฉ
  • plugin/manifest.loopback.json์€ placeholder id์ด๋ฏ€๋กœ import ์‹คํŒจ ์‹œ ์ƒˆ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ๋งŒ๋“ค๊ณ  ์ƒ์„ฑ๋œ id๋กœ ๊ต์ฒดํ•˜์„ธ์š”
  • Dev Mode ํŒจ๋„์—์„œ ์‹คํ–‰ํ•˜๋ ค๋ฉด capabilities: ["inspect", "codegen"] + codegenLanguages๊ฐ€ ํ•„์š”
  1. ํ”Œ๋Ÿฌ๊ทธ์ธ ์‹คํ–‰ ํ›„ ์ฑ„๋„ ์—ฐ๊ฒฐ
  • ํ”Œ๋Ÿฌ๊ทธ์ธ UI์—์„œ Server URL ํ™•์ธ/์ˆ˜์ • โ†’ Connect
  • ํ‘œ์‹œ๋œ Channel ID๋ฅผ ๋ณต์‚ฌ

์—ฐ๊ฒฐ ๋ฌธ์ œ ํ•ด๊ฒฐ:

  • POST /plugin/connect ๋˜๋Š” /plugin/poll์ด net::ERR_CONNECTION_REFUSED๋ฉด ์„œ๋ฒ„๊ฐ€ ๊บผ์ ธ ์žˆ๊ฑฐ๋‚˜ ํฌํŠธ๊ฐ€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. curl http://localhost:8940/health๋กœ ๋จผ์ € ํ™•์ธํ•˜์„ธ์š”.
  • devAllowedDomains ์— 127.0.0.1๋ฅผ ๋„ฃ์œผ๋ฉด Figma๊ฐ€ ๊ฑฐ๋ถ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ plugin/manifest.json์€ localhost๋งŒ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • ๋กœ์ปฌ IP๊ฐ€ ๊ผญ ํ•„์š”ํ•˜๋ฉด plugin/manifest.loopback.json์„ ๋”ฐ๋กœ importํ•˜์„ธ์š”. (Figma๊ฐ€ IP๋ฅผ ๊ฑฐ๋ถ€ํ•˜๋ฉด localhost๋กœ ๋˜๋Œ๋ฆฌ์„ธ์š”.)
  • Channel ID๊ฐ€ ์•ˆ ๋œจ๋ฉด ํ”Œ๋Ÿฌ๊ทธ์ธ ์ฐฝ์„ ๋‹ซ์ง€ ๋ง๊ณ , ์„œ๋ฒ„ ๋กœ๊ทธ//plugin/status๋ฅผ ํ™•์ธํ•˜์„ธ์š”.
  1. MCP ๋„๊ตฌ๋กœ ์ฑ„๋„ ์„ค์ •
figma_plugin_use_channel
  channel_id: "ch-..."
  1. ๋ฒˆ๋“ค์— ํ”Œ๋Ÿฌ๊ทธ์ธ ์Šค๋ƒ…์ƒท ํฌํ•จ
figma_get_node_bundle
  file_key: "..."
  node_id: "123:456"
  include_plugin: true
  plugin_channel_id: "ch-..."
  plugin_depth: 0
  plugin_include_geometry: false
  include_plugin_variables: true
  include_plugin_image: true

URL๋งŒ์œผ๋กœ ํ˜ธ์ถœ (์„ ํƒ ์—†์ด node_id ์‚ฌ์šฉ):

figma_get_node_bundle
  url: "https://www.figma.com/design/...?...node-id=123-456"
  token: "$FIGMA_TOKEN"
  auto_plugin: true
  plugin_channel_id: "ch-..."

์ฃผ์˜: ํ”Œ๋Ÿฌ๊ทธ์ธ ์Šค๋ƒ…์ƒท์€ ํ•ด๋‹น ํŒŒ์ผ์ด Figma์—์„œ ์—ด๋ ค ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

ํ”Œ๋Ÿฌ๊ทธ์ธ ๋„๊ตฌ ์ง์ ‘ ํ˜ธ์ถœ:

figma_plugin_export_node_image
  node_id: "123:456"

figma_plugin_get_variables

ํ”Œ๋Ÿฌ๊ทธ์ธ ์Šค๋ƒ…์ƒท ์˜ต์…˜:

  • plugin_depth: ํฐ ์„น์…˜์€ 0์œผ๋กœ, ํ•„์š”ํ•œ ๊ฒฝ์šฐ 1~2๋กœ ์ ์ง„ ์ฆ๊ฐ€
  • plugin_include_geometry: ์•„์ด์ฝ˜/๋ฒกํ„ฐ๊ฐ€ ํ•„์š”ํ•  ๋•Œ๋งŒ true
  • figma_plugin_get_node๋Š” include_geometry๋กœ ๋ฒกํ„ฐ ํฌํ•จ ์—ฌ๋ถ€ ์ œ์–ด
  • plugin_context_mode: summary + plugin_depth: 0์€ ๋น ๋ฅด์ง€๋งŒ ์ •๋ฐ€๋„๊ฐ€ ๋‚ฎ์Šต๋‹ˆ๋‹ค. ์ตœ์ข… ํŒจ์Šค๋Š” plugin_context_mode: both + plugin_depth: 1 ๊ถŒ์žฅ ์ฃผ์˜: ํ”Œ๋Ÿฌ๊ทธ์ธ ์ด๋ฏธ์ง€ ์‘๋‹ต์€ base64์ด๋ฏ€๋กœ ์ถœ๋ ฅ์ด ์ปค์ง‘๋‹ˆ๋‹ค. (download ์˜ต์…˜์€ REST ์ด๋ฏธ์ง€์—๋งŒ ์ ์šฉ)

HTTP ์—”๋“œํฌ์ธํŠธ:

  • POST /plugin/connect
  • POST /plugin/poll
  • POST /plugin/result
  • GET /plugin/status /plugin/poll์€ wait_ms(๋˜๋Š” timeout_ms)๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. (long-poll, ms ๋‹จ์œ„) ์ตœ๋Œ€ ๋Œ€๊ธฐ ์‹œ๊ฐ„์€ FIGMA_PLUGIN_POLL_MAX_MS๋กœ ์ œํ•œ๋ฉ๋‹ˆ๋‹ค. (๊ธฐ๋ณธ 30000ms)

gRPC Streaming (๋Œ€์šฉ๋Ÿ‰ ์‘๋‹ต) - ๊ถŒ์žฅ

์–ธ์ œ gRPC๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋‚˜?

์ƒํ™ฉ ๊ถŒ์žฅ ํ”„๋กœํ† ์ฝœ ์ด์œ 
7MB+ JSON ์‘๋‹ต gRPC โœ… ์ฒญํฌ ์ŠคํŠธ๋ฆฌ๋ฐ์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์ 
๋Œ€ํ˜• Figma ํŒŒ์ผ (100+ ๋…ธ๋“œ) gRPC โœ… ์ ์ง„์  ๋กœ๋”ฉ์œผ๋กœ ํƒ€์ž„์•„์›ƒ ๋ฐฉ์ง€
์žฌ๊ท€ ํƒ์ƒ‰ (recursive: true) gRPC โœ… ์‹ค์‹œ๊ฐ„ ์ง„ํ–‰ ์ƒํ™ฉ ํ‘œ์‹œ
๋น ๋ฅธ ๋‹จ์ผ ๋…ธ๋“œ ์กฐํšŒ HTTP ์˜ค๋ฒ„ํ—ค๋“œ ๋‚ฎ์Œ
Claude Code stdio ํ†ตํ•ฉ HTTP MCP ํ”„๋กœํ† ์ฝœ ํ˜ธํ™˜

๊ถŒ์žฅ: ๋Œ€์šฉ๋Ÿ‰ ์‘๋‹ต์ด ์˜ˆ์ƒ๋˜๋ฉด HTTP + gRPC ๋™์‹œ ์‹คํ–‰ ๋ชจ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

# โญ ๊ถŒ์žฅ: HTTP + gRPC ๋™์‹œ ์‹คํ–‰ (production)
./figma-mcp --port 8940 --grpc-port 50052

# gRPC ๋‹จ๋… ์‹คํ–‰ (streaming-only ํ™˜๊ฒฝ)
./figma-mcp --grpc-port 50052

# HTTP ๋‹จ๋… ์‹คํ–‰ (์†Œ๊ทœ๋ชจ ์š”์ฒญ)
./figma-mcp --port 8940

์„œ๋น„์Šค/๋ฉ”์„œ๋“œ:

  • figma.v1.FigmaService/GetNodeStream (server streaming)
  • figma.v1.FigmaService/FidelityLoop (server streaming)
  • figma.v1.FigmaService/GetSplitStream (server streaming)
  • figma.v1.FigmaService/GetFileMeta (unary)

ํ…Œ์ŠคํŠธ (reflection ๋น„ํ™œ์„ฑํ™”: proto ์ง€์ • ํ•„์š”):

grpcurl -plaintext -import-path proto -proto figma.proto \
  -d '{"file_key":"...","node_id":"...","token":"..."}' \
  localhost:50052 figma.v1.FigmaService/GetNodeStream

์žฌ๊ท€ ์ŠคํŠธ๋ฆผ(ํ•˜์œ„ ๋…ธ๋“œ ์ „์ฒด ํ™•์žฅ):

grpcurl -plaintext -import-path proto -proto figma.proto \
  -d '{"file_key":"...","node_id":"...","token":"...","recursive":true}' \
  localhost:50052 figma.v1.FigmaService/GetNodeStream

์˜ต์…˜:

  • recursive_max_depth (๊ธฐ๋ณธ 20, env: FIGMA_RECURSIVE_MAX_DEPTH)
  • recursive_max_nodes (๊ธฐ๋ณธ 5000, env: FIGMA_RECURSIVE_MAX_NODES)
  • recursive_depth_per_call (๊ธฐ๋ณธ 1, env: FIGMA_RECURSIVE_DEPTH_PER_CALL)
  • ์žฌ๊ท€ ๋ชจ๋“œ๋Š” ์ค‘๋ณต์„ ํ”ผํ•˜๋ ค๊ณ  ๊ฐ ๋…ธ๋“œ๋ฅผ ๋‹จ์ผ ๋ ˆ๋ฒจ(์ž์‹ ์ œ๊ฑฐ)๋กœ ์ŠคํŠธ๋ฆผํ•ฉ๋‹ˆ๋‹ค.

์š”๊ตฌ์‚ฌํ•ญ ๋ถ„์„ + ๋ถ„ํ• ์ •๋ณต ํ”Œ๋žœ:

grpcurl -plaintext -import-path proto -proto figma.proto \
  -d '{"file_key":"...","node_id":"...","token":"...","recursive":true}' \
  localhost:50052 figma.v1.FigmaService/PlanTasks

PlanTasks ์‘๋‹ต ์ถ”๊ฐ€ ํ•„๋“œ:

  • summary: ์šฐ์„ ์ˆœ์œ„/ํ† ํฐ ์š”์•ฝ
  • requirements_json: ๋…ธ๋“œ ํƒ€์ž…/์˜คํ† ๋ ˆ์ด์•„์›ƒ/์ด๋ฏธ์ง€ fill ๋“ฑ ๋ถ„์„ ๊ฒฐ๊ณผ

ํ”„๋กœํ† ์ฝœ ์ •์˜๋Š” proto/figma.proto๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

Fidelity DSL ํฌ๋งท (์ •ํ™•๋„ ์šฐ์„ )

format: fidelity๋Š” JSON ๊ธฐ๋ฐ˜์˜ ๊ตฌ์กฐํ™” ์ถœ๋ ฅ์ž…๋‹ˆ๋‹ค.

{
  "meta": {"id":"1:2","name":"Card","type":"FRAME"},
  "geometry": {"absoluteBoundingBox":{"x":0,"y":0,"width":320,"height":200}},
  "layout": {"layoutMode":"VERTICAL","paddingTop":16,"itemSpacing":12},
  "paint": {"fills":[...],"strokes":[...],"strokeWeight":1},
  "text": {"characters":null,"style":null},
  "children": [ ... ],
  "layout_missing": ["layoutWrap","layoutAlign"]
}

์ด๋ฏธ์ง€ ๋‹ค์šด๋กœ๋“œ ์˜ต์…˜

figma_export_image, figma_get_node_bundle์—์„œ download: true์™€ save_dir ์ง€์ • ๊ฐ€๋Šฅ. ๊ธฐ๋ณธ ์ €์žฅ ๊ฒฝ๋กœ๋Š” $ME_ROOT/download/figma-assets ์ž…๋‹ˆ๋‹ค. (ME_ROOT ๋ฏธ์„ค์ • ์‹œ $HOME/me/download/figma-assets, ์—†์œผ๋ฉด /tmp/figma-assets)

ํ…Œ์ŠคํŠธ

# initialize
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' | ./start-figma-mcp.sh

# tools/list
echo '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' | ./start-figma-mcp.sh

์˜์กด์„ฑ

  • OCaml 5.x
  • yojson
  • cohttp-lwt-unix
  • lwt
  • uri
  • cmdliner

P0 CSS Fidelity Gap ์ˆ˜์ • (2026-01)

Visual Feedback Loop์—์„œ ๋ฐœ๊ฒฌ๋œ CSS ์ •ํ™•๋„ ๋ฌธ์ œ๋ฅผ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

P0-1, P0-2: Flexbox Alignment

Figma primaryAxisAlignItems/counterAxisAlignItems โ†’ CSS justify-content/align-items ๋งคํ•‘:

Figma justify-content align-items
MIN flex-start (๊ธฐ๋ณธ๊ฐ’) flex-start (๊ธฐ๋ณธ๊ฐ’)
CENTER center center
MAX flex-end flex-end
SPACE_BETWEEN space-between -
BASELINE - baseline

Before: ๋ชจ๋“  ๊ฐ’์ด ๋ฌด์‹œ๋จ โ†’ CENTER/MAX ๋ ˆ์ด์•„์›ƒ ํ‹€์–ด์ง After: ๋™์  ๋งคํ•‘์œผ๋กœ ์ •ํ™•ํ•œ ์ •๋ ฌ

P0-3: Effects (Shadow, Blur)

4๊ฐ€์ง€ Figma ํšจ๊ณผ๋ฅผ CSS๋กœ ๋ณ€ํ™˜:

/* DropShadow โ†’ box-shadow */
box-shadow: 4px 4px 10px 2px rgba(0,0,0,0.25);

/* InnerShadow โ†’ box-shadow inset */
box-shadow: inset 2px 2px 5px 0px rgba(255,255,255,0.5);

/* LayerBlur โ†’ filter:blur */
filter: blur(8px);

/* BackgroundBlur โ†’ backdrop-filter */
backdrop-filter: blur(12px);

์˜ˆ์ œ ์ถœ๋ ฅ:

box-shadow:4px 4px 10px 2px rgba(0,0,0,0.2),inset 2px 2px 5px 0px rgba(255,255,255,0.50);filter:blur(8px);backdrop-filter:blur(12px)

P0-4: Gradient

Figma gradientStops โ†’ CSS linear-gradient:

(* ์ž…๋ ฅ: Figma gradientStops *)
[
  (0.0, {r=1.0; g=0.0; b=0.0; a=1.0});   (* Red *)
  (0.5, {r=0.0; g=1.0; b=0.0; a=1.0});   (* Green *)
  (1.0, {r=0.0; g=0.0; b=1.0; a=1.0});   (* Blue *)
]

(* ์ถœ๋ ฅ: CSS *)
"linear-gradient(to right,#FF0000 0%,#00FF00 50%,#0000FF 100%)"

ํ˜„์žฌ ์ œํ•œ์‚ฌํ•ญ:

  • ๋ฐฉํ–ฅ์€ to right ๊ณ ์ • (๊ฐ๋„ ๊ณ„์‚ฐ์€ P1)
  • Radial/Angular/Diamond๋Š” linear๋กœ fallback

์„ฑ๋Šฅ ๋ฒค์น˜๋งˆํฌ

gradient_to_css (5 stops)     : 4 ยตs/iter
effects_to_css (4 effects)    : 6 ยตs/iter
effects_to_css (all invisible): <1 ยตs/iter

ํ…Œ์ŠคํŠธ

# P0 ์œ ๋‹› ํ…Œ์ŠคํŠธ (10๊ฐœ)
dune exec ./test/test_codegen_p0.exe

# P0 ๋ฒค์น˜๋งˆํฌ
dune exec ./test/bench_p0.exe

Future Work: ๋‹ค์ค‘ ์œ ์‚ฌ๋„ ์ธก์ • ์‹œ์Šคํ…œ

ํ˜„์žฌ figma_compare๋Š” ์‹ค์šฉ์  ํœด๋ฆฌ์Šคํ‹ฑ ๊ธฐ๋ฐ˜์ž…๋‹ˆ๋‹ค. ์•„๋ž˜ ํ•™์ˆ ์  ๊ธฐ๋ฐ˜ ๊ฐœ์„ ์„ ๊ณ„ํš ์ค‘:

๋‹ค์ค‘ ์œ ์‚ฌ๋„ ์ง€ํ‘œ (Multi-Metric Similarity)

์ง€ํ‘œ ๊ณต์‹/์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ถœ์ฒ˜
Color CIEDE2000 (ฮ”E*โ‚€โ‚€) CIE ํ‘œ์ค€, ์ธ๊ฐ„ ์ƒ‰์ง€๊ฐ ๋ชจ๋ธ
Layout IoU (Intersection over Union) ๊ฐ์ฒด ํƒ์ง€ ํ‘œ์ค€ ๋ฉ”ํŠธ๋ฆญ
Structure Tree Edit Distance (TED) Zhang-Shasha ์•Œ๊ณ ๋ฆฌ์ฆ˜
Visual SSIM (Structural Similarity Index) Wang et al. 2004, IEEE TIP
Embedding Cosine Similarity on UI Embedding Rico (Google, UIST 2017)

์ถœ๋ ฅ ์˜ˆ์‹œ (๊ณ„ํš)

๋น„๊ต: "B2C ํ™ˆ (Web)" vs "B2C ํ™ˆ (Mobile)"

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ ์ง€ํ‘œ            โ”‚ ์ ์ˆ˜   โ”‚ ์„ค๋ช…                        โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Color (ฮ”E*โ‚€โ‚€)  โ”‚ 95.2%  โ”‚ ์ƒ‰์ƒ ์ฐจ์ด ฮ”E=2.3 (JND ์ดํ•˜) โ”‚
โ”‚ Layout (IoU)    โ”‚ 87.4%  โ”‚ ์š”์†Œ ์œ„์น˜ ์˜ค๋ฒ„๋žฉ            โ”‚
โ”‚ Structure (TED) โ”‚ 92.0%  โ”‚ ํŠธ๋ฆฌ ํŽธ์ง‘ ๊ฑฐ๋ฆฌ 4            โ”‚
โ”‚ Visual (SSIM)   โ”‚ 89.1%  โ”‚ ๊ตฌ์กฐ์  ์œ ์‚ฌ๋„               โ”‚
โ”‚ Embedding       โ”‚ 94.7%  โ”‚ Rico-style 64dim cosine     โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ **์ข…ํ•ฉ**        โ”‚ 91.7%  โ”‚ ๊ฐ€์ค‘ ํ‰๊ท                    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

์ฐธ๊ณ  ๋…ผ๋ฌธ

๊ตฌํ˜„ ์šฐ์„ ์ˆœ์œ„

  1. โœ… ํ˜„์žฌ: ํœด๋ฆฌ์Šคํ‹ฑ ๊ฐ€์ค‘์น˜ (Critical/Major/Minor)
  2. ๐Ÿ”œ Phase 1: CIEDE2000 ์ƒ‰์ƒ ๊ฑฐ๋ฆฌ ์ ์šฉ
  3. ๐Ÿ”œ Phase 2: IoU ๋ ˆ์ด์•„์›ƒ ์œ ์‚ฌ๋„ ์ถ”๊ฐ€
  4. ๐Ÿ”œ Phase 3: SSIM ์‹œ๊ฐ์  ์œ ์‚ฌ๋„ (๋ Œ๋”๋ง ํ•„์š”)
  5. ๐Ÿ”œ Phase 4: Rico-style Embedding (ML ๋ชจ๋ธ ํ•„์š”)

๋ผ์ด์„ ์Šค

MIT

About

Figma MCP Server - Design to Code with Fidelity DSL

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • OCaml 90.2%
  • JavaScript 6.1%
  • Python 1.6%
  • Shell 1.3%
  • Other 0.8%