·

Tiếng Việt: Figma MCP With Claude Code Cli And Vs Code

Figma MCP With Claude Code Cli And Vs Code

Nếu bạn đã đọc bài trước về khái niệm Figma MCP, bài này sẽ đi thẳng vào phần mà hầu hết engineer quan tâm nhất: làm sao để cắm Figma MCP (Model Context Protocol — giao thức kết nối AI agent với nguồn dữ liệu/công cụ bên ngoài) vào Claude Code, rồi biến một frame thiết kế thành component React chạy được thật, chứ không phải chỉ xem demo cho vui.

Toàn bộ nội dung dưới đây dựa trên Figma Dev Mode MCP Server — remote MCP server chính thức do Figma vận hành (không phải plugin cộng đồng, không phải server tự host), publish tại https://mcp.figma.com/mcp. Vì là remote server nên bạn không cần cài Figma desktop app chạy nền, không cần mở port local — chỉ cần tài khoản Figma có quyền truy cập file thiết kế và một lần xác thực OAuth (giao thức ủy quyền chuẩn, cho phép Claude Code truy cập tài nguyên Figma thay mặt bạn mà không cần lộ password).

Cài Đặt và Kết Nối Figma MCP vào Claude Code

Cách nhanh nhất để add Figma MCP vào Claude Code là dùng lệnh CLI (command-line interface) built-in:

claude mcp add --transport http figma https://mcp.figma.com/mcp

Phân tích nhanh câu lệnh này: --transport http báo cho Claude Code biết đây là remote MCP server giao tiếp qua HTTP (khác với local MCP server chạy qua stdio — giao tiếp qua standard input/output trên máy bạn), figma là tên định danh bạn tự đặt cho server này (dùng để tham chiếu sau này), còn URL phía sau là endpoint chính thức của Figma.

Sau khi chạy lệnh, Claude Code sẽ tự mở trình duyệt để bắt đầu luồng OAuth. Bạn đăng nhập bằng tài khoản Figma (nên dùng đúng tài khoản có quyền edit/view vào file thiết kế bạn cần), bấm consent (đồng ý cấp quyền), rồi quay lại terminal — Claude Code sẽ báo kết nối thành công. Toàn bộ quá trình chỉ mất khoảng 30 giây, và token xác thực được lưu lại nên bạn không cần lặp lại mỗi lần mở session mới (trừ khi token hết hạn hoặc bạn revoke quyền từ phía Figma).

Nếu team bạn làm việc chung một repo và muốn mọi người dùng chung cấu hình MCP (thay vì mỗi người tự add bằng CLI), cách sạch hơn là commit file .mcp.json vào root của project:

{
  "mcpServers": {
    "figma": {
      "type": "http",
      "url": "https://mcp.figma.com/mcp"
    }
  }
}

Khi Claude Code mở project có file này, nó sẽ tự nhận diện server figma và hỏi bạn có muốn trust config này không (vì lý do bảo mật — tránh trường hợp ai đó chèn MCP server độc hại vào repo rồi bạn vô tình chạy). Đồng nghiệp mới join team chỉ cần approve một lần, không cần nhớ lệnh claude mcp add dài dòng. Lưu ý: file .mcp.json không lưu token OAuth — mỗi máy vẫn phải tự xác thực riêng, đây là điểm nhiều bạn hiểu nhầm.

Để kiểm tra kết nối đã sống chưa, gõ lệnh /mcp ngay trong phiên Claude Code. Lệnh này liệt kê tất cả MCP server đang connect, trạng thái (connected/disconnected/error), và danh sách tool khả dụng. Với Figma MCP, bạn sẽ thấy các tool quen thuộc: get_code, get_variable_defs, get_screenshot, get_code_connect_map, get_metadata, và create_design_system_rules. Nếu /mcp báo lỗi kết nối, 90% nguyên nhân là do OAuth token hết hạn hoặc bạn chưa có quyền truy cập file Figma cụ thể — thử revoke và add lại là xong.

Trong VS Code, nếu bạn dùng Claude Code qua extension hoặc chỉ đơn giản mở terminal tích hợp (integrated terminal) rồi gõ claude, quy trình y hệt như trên — MCP không phải là tính năng đặc thù của terminal đứng riêng, nó gắn với Claude Code process, nên dù bạn chạy trong terminal độc lập hay terminal nhúng trong VS Code, tool Figma vẫn xuất hiện sẵn trong context của agent, không cần cấu hình thêm gì cho phía VS Code.

Mẹo: Đừng add Figma MCP bằng scope global rồi quên mất — nếu bạn làm nhiều project với nhiều tài khoản Figma khác nhau (ví dụ vừa làm cho công ty A vừa freelance cho công ty B), hãy cân nhắc dùng .mcp.json ở scope project thay vì add global, để tránh nhầm lẫn quyền truy cập file thiết kế giữa các job.

Trích Xuất Design Context và Nhận Diện Component từ Frame Figma

Bước quan trọng nhất trước khi generate bất kỳ dòng code nào là cho Claude Code biết chính xác bạn đang nói đến node (phần tử) nào trong file Figma — không thể chỉ nói "làm cái nút login cho tôi" và mong agent tự đoán đúng frame trong một file có 40 page.

Cách chuẩn để tham chiếu một frame cụ thể: mở Figma, chọn frame hoặc layer bạn cần (có thể là cả một screen, hoặc chỉ một component nhỏ như button), right-click hoặc dùng menu Share, chọn "Copy link to selection". Link copy được sẽ có dạng:

https://www.figma.com/design/AbCdEfGhIjKl/My-Design-File?node-id=123-456

Phần node-id=123-456 chính là định danh duy nhất của node bạn vừa chọn — đây là thứ Figma MCP dùng để biết chính xác bạn muốn lấy design context (ngữ cảnh thiết kế: layout, style, cấu trúc layer) của phần tử nào, thay vì đoán mò dựa trên tên frame hay screenshot mờ nhạt.

Dán link này thẳng vào prompt cho Claude Code, ví dụ:

Đây là frame login form: https://www.figma.com/design/AbCdEfGhIjKl/My-Design-File?node-id=123-456
Hãy lấy metadata và variable definitions của node này trước, đừng generate code vội.

Claude Code sẽ tự động gọi tool get_metadata để lấy cấu trúc cây layer (component nào lồng trong component nào, tên layer, kích thước, vị trí), giúp cả bạn và agent hình dung được frame này có bao nhiêu component con trước khi bắt tay generate code. Đây là bước nhiều người bỏ qua vì nóng vội — nhưng với frame phức tạp (nhiều nested component, auto-layout lồng nhau), nếu skip bước này, code sinh ra thường bị sai cấu trúc hoặc gộp nhầm các phần tử không liên quan.

Sau khi có metadata, gọi tiếp get_variable_defs để lấy danh sách token/biến (variable) đang áp dụng lên node đó — màu sắc, spacing, font-size, border-radius. Tool này trả về giá trị thực tế (ví dụ color/brand/primary: #2563EB) kèm tên biến trong hệ thống design token của Figma, chứ không chỉ trả về hex code trần trụi. Đây là dữ liệu cực kỳ quan trọng cho bước map token ở phần 4 của bài này.

Một tool khác đáng chú ý ở giai đoạn nhận diện component là get_code_connect_map. Nếu team design system của bạn đã thiết lập Code Connect (tính năng của Figma cho phép link một component trong Figma tới component thật trong source code, kèm theo prop mapping), tool này sẽ trả về map node nào tương ứng với component nào trong repo, ví dụ node "Button/Primary" map với src/components/Button.tsx. Khi có Code Connect map, Claude Code biết ngay là cần import và tái sử dụng Button component có sẵn thay vì "phát minh lại" một button mới từ đầu.

Nếu team chưa dùng Code Connect (thực tế đa số team nhỏ và vừa chưa setup cái này), bạn vẫn có thể đạt hiệu quả tương tự bằng cách chỉ định rõ thư mục component trong prompt, ví dụ: "Component nào trùng với những gì đã có trong src/components/, hãy tái sử dụng, đừng tạo file mới."

Mẹo: Với frame phức tạp, hãy chia nhỏ prompt thành từng bước — lấy metadata trước, review cấu trúc layer cùng agent (đọc output, xem có component nào bị đặt tên mơ hồ như "Frame 47" không), rồi mới yêu cầu generate code. Làm gộp một phát dễ khiến agent hiểu sai ý đồ layout, nhất là với auto-layout có constraint phức tạp.

Sinh Code React và CSS từ Thiết Kế Figma qua Claude Code

Đây là phần "đã tai" nhất trong workflow — biến node Figma thành component React thật, chạy được trong project.

Tool cốt lõi ở bước này là get_code. Khi Claude Code gọi tool này với node-id bạn cung cấp, Figma MCP server sẽ trả về code (mặc định thường là React kèm CSS, nhưng có thể điều chỉnh sang Tailwind hoặc framework khác tùy cấu hình bạn khai báo trong prompt hoặc trong file rule của project) mô tả cấu trúc và style của node đó. Điều cần hiểu rõ: code trả về từ get_code là bản dịch trực tiếp từ cấu trúc thiết kế sang code, chưa phải là code "sản xuất" tối ưu — nó chưa biết codebase của bạn đặt tên biến kiểu gì, chưa biết bạn dùng CSS Modules hay styled-components, chưa biết component nào đã tồn tại sẵn.

Vì vậy, prompt hiệu quả không bao giờ chỉ là "generate code cho frame này" — nó cần kèm theo ngữ cảnh về codebase. Ví dụ một prompt thực tế mình hay dùng:

Lấy code cho frame này: https://www.figma.com/design/AbCdEfGhIjKl/My-Design-File?node-id=123-456

Yêu cầu:
1. Dự án dùng React + TypeScript, style bằng CSS Modules (không dùng styled-components).
2. Trước khi tạo component mới, kiểm tra trong src/components/ui/ xem đã có Button, Input, Card chưa — nếu có thì import và reuse, không viết lại.
3. Đặt component mới vào src/components/auth/LoginForm.tsx
4. Không hardcode màu/spacing — dùng CSS variable đã định nghĩa trong src/styles/tokens.css

Với prompt như trên, Claude Code sẽ tự phối hợp nhiều tool: gọi get_code_connect_map (hoặc tự đọc thư mục src/components/ui/ qua tool file-system built-in) để biết component nào tái sử dụng được, gọi get_code để lấy cấu trúc thô, rồi "dịch" lại theo convention thực tế của project trước khi ghi file.

Một pattern rất hay gặp: get_code trả về một khối <div> lồng nhau với class Tailwind hoặc inline style dài dằng dặc, nhưng bạn biết rõ phần đó chính là component <Card> đã có sẵn trong hệ thống. Đây là lý do bước "nhận diện component" ở phần 2 quan trọng — nếu bỏ qua, code sinh ra thường bị duplicate logic, mỗi frame lại tạo ra một biến thể button/card riêng, về lâu dài phá vỡ tính nhất quán của design system.

Ví dụ output thực tế (đã được agent "dọn" lại theo convention project) cho một login form đơn giản:

// src/components/auth/LoginForm.tsx
import { Button } from "@/components/ui/Button";
import { Input } from "@/components/ui/Input";
import styles from "./LoginForm.module.css";

export function LoginForm() {
  return (
    <form className={styles.form}>
      <h2 className={styles.title}>Đăng nhập</h2>
      <Input type="email" placeholder="Email" name="email" />
      <Input type="password" placeholder="Mật khẩu" name="password" />
      <Button variant="primary" type="submit">
        Đăng nhập
      </Button>
    </form>
  );
}
/* src/components/auth/LoginForm.module.css */
.form {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
  padding: var(--spacing-lg);
  max-width: 360px;
}

.title {
  font-size: var(--font-size-xl);
  color: var(--color-text-primary);
}

Chú ý là InputButton được import từ component có sẵn, còn CSS thì dùng CSS variable thay vì giá trị cứng — cả hai điều này không tự nhiên mà có, chúng đến từ việc bạn ra prompt rõ ràng và có bước map token (phần tiếp theo).

Một lưu ý thực chiến: get_code phản ánh đúng những gì designer đã vẽ, kể cả khi họ vẽ "sai" theo chuẩn code — ví dụ padding lệch 1px do designer kéo tay không snap đúng grid, hoặc auto-layout có gap không đều. Đừng generate code rồi merge thẳng vào production mà không review — luôn coi output từ MCP là bản nháp chất lượng cao, không phải bản final.

Mẹo: Nếu bạn generate nhiều component trong cùng một session, hãy yêu cầu Claude Code tổng hợp lại danh sách component đã tạo/tái sử dụng ở cuối, kiểu "Recap: đã tạo mới X, Y; đã tái sử dụng Z" — việc này giúp bạn review nhanh xem agent có lỡ tạo trùng component nào không trước khi commit.

Map Design Token của Figma sang CSS Variable trong Codebase

Đây là phần dễ bị làm ẩu nhất, nhưng lại quyết định code sinh ra có "sống" được lâu dài trong codebase hay không. Vấn đề cốt lõi: nếu code React/CSS sinh ra chứa toàn giá trị hardcode kiểu color: #2563EB hay padding: 16px, thì mỗi khi designer đổi theme (ví dụ đổi brand color), bạn phải đi sửa từng file — đúng như cái workflow thủ công mà MCP sinh ra để giải quyết.

Cách làm đúng: không để Claude Code tự bịa giá trị, mà bắt nó đối chiếu hai nguồn dữ liệu — giá trị thực tế lấy từ get_variable_defs (biến Figma đang áp dụng lên node) và file token hiện có trong project (ví dụ tokens.css, theme.ts, hoặc file cấu hình Tailwind).

Prompt mẫu cho bước này:

Trước khi viết CSS cho component này, hãy:
1. Gọi get_variable_defs cho node https://www.figma.com/design/AbCdEfGhIjKl/My-Design-File?node-id=123-456
2. Đọc file src/styles/tokens.css hiện tại của project
3. Với mỗi giá trị lấy được từ Figma, tìm CSS variable tương ứng đã tồn tại trong tokens.css (so khớp theo giá trị, không phải theo tên)
4. Nếu tìm thấy match, dùng var(--ten-bien) trong code. Nếu không tìm thấy token nào khớp, liệt kê ra cho tôi xem, đừng tự tạo token mới hay hardcode giá trị.

Bước 4 ở trên rất quan trọng — nó ép agent phải minh bạch khi gặp trường hợp mơ hồ, thay vì "tự quyết" và tạo ra một token mới không ai biết, hoặc tệ hơn là fallback về hardcode. Trong thực tế, tình huống "không tìm thấy token khớp" xảy ra khá thường xuyên, thường vì hai lý do: designer dùng một màu one-off chưa được đưa vào design system chính thức, hoặc token trong Figma và token trong code đặt tên khác nhau dù giá trị giống hệt (ví dụ Figma gọi là brand/blue-600, code gọi là --color-primary).

Ví dụ file tokens.css thực tế trong một project:

/* src/styles/tokens.css */
:root {
  --color-primary: #2563eb;
  --color-text-primary: #111827;
  --color-text-secondary: #6b7280;
  --spacing-sm: 8px;
  --spacing-md: 16px;
  --spacing-lg: 24px;
  --font-size-base: 14px;
  --font-size-xl: 20px;
}

Và đây là kết quả get_variable_defs trả về cho node button (rút gọn để minh họa):

{
  "fill/brand/primary": "#2563EB",
  "spacing/gap-md": "16px",
  "font/size/xl": "20px"
}

Nhìn vào hai bộ dữ liệu này, agent (hoặc chính bạn khi review) có thể thấy #2563EB từ Figma khớp với --color-primary trong tokens.css, 16px khớp --spacing-md, 20px khớp --font-size-xl — dù tên biến hai bên hoàn toàn khác nhau. Việc đối chiếu theo giá trị (không phải theo tên) là kỹ thuật quan trọng nhất ở bước này, vì tên biến giữa design tool và codebase gần như không bao giờ trùng khớp 100% theo convention.

Với những project lớn có hàng trăm token, bạn có thể yêu cầu Claude Code viết một script nhỏ hỗ trợ đối chiếu tự động thay vì làm tay từng giá trị, ví dụ:

// scripts/match-tokens.js
// Đối chiếu giá trị token từ Figma (input JSON) với CSS variable hiện có
const figmaTokens = require("./figma-variables.json");
const fs = require("fs");

const cssContent = fs.readFileSync("src/styles/tokens.css", "utf-8");
const cssVarRegex = /--([\w-]+):\s*([^;]+);/g;
const cssVars = {};
let match;
while ((match = cssVarRegex.exec(cssContent))) {
  cssVars[match[2].trim().toLowerCase()] = `--${match[1]}`;
}

for (const [figmaName, value] of Object.entries(figmaTokens)) {
  const normalized = value.toLowerCase();
  const cssVar = cssVars[normalized];
  console.log(
    cssVar
      ? `MATCH: ${figmaName} (${value}) -> var(${cssVar})`
      : `NO MATCH: ${figmaName} (${value}) — cần review thủ công`
  );
}

Script này chỉ là điểm khởi đầu (nó so khớp exact string nên sẽ miss các trường hợp format khác nhau như #2563EB vs #2563eb viết hoa/thường, hoặc rgba() vs hex) — nhưng đủ để giảm 80% khối lượng đối chiếu thủ công, phần còn lại để agent hoặc con người xử lý case-by-case.

Một sai lầm phổ biến khác: một số team dùng tool create_design_system_rules (một trong các tool Figma MCP cung cấp) để tự sinh ra một file rule mô tả quy ước design system, rồi để file đó nằm im không update. Token trong Figma thay đổi liên tục theo thời gian — hãy coi việc map token là một quy trình lặp lại mỗi khi có frame mới, không phải việc làm một lần rồi xong.

Mẹo: Lưu lại kết quả đối chiếu token (kể cả những case "no match") vào một file changelog nhỏ trong repo, kiểu docs/design-tokens-sync.md. Về sau khi design system đổi, bạn có sẵn lịch sử để biết token nào từng bị thiếu, tránh lặp lại đúng lỗi cũ mỗi lần sync thiết kế mới.