Nếu bạn đã quen dùng Figma MCP (Model Context Protocol) qua Claude Code CLI hay Gemini CLI ở các bài trước, phần lớn khái niệm cốt lõi vẫn giữ nguyên khi chuyển sang Cursor — chỉ khác ở chỗ toàn bộ trải nghiệm giờ diễn ra ngay trong IDE (Integrated Development Environment - môi trường phát triển tích hợp), thay vì bật một terminal riêng. Cursor là một fork của VS Code, giữ nguyên hệ sinh thái extension quen thuộc nhưng thêm vào một lớp Agent Mode (còn gọi là Composer) cho phép AI đọc, sửa, và tạo code trực tiếp trên project đang mở. Khi kết hợp với Figma MCP, bạn có thể dán một link Figma frame vào chat, và agent sẽ tự lấy design, đối chiếu với codebase hiện có, rồi sinh ra component khớp với convention của team — tất cả không rời khỏi cửa sổ editor. Bài này sẽ đi qua bốn nội dung chính: cách setup kết nối, cách thực chiến chuyển frame thành component, cách dùng Code Connect để tránh việc AI "phát minh lại bánh xe", và cuối cùng là những giới hạn thực tế bạn cần biết trước khi tin tưởng tuyệt đối vào code Cursor sinh ra.
Kết Nối Figma MCP Vào Cursor Agent Mode
Cursor hỗ trợ cấu hình MCP server theo hai cấp: project-level (chỉ áp dụng cho repo hiện tại, thường dùng khi team muốn đồng bộ cấu hình qua git) và global (áp dụng cho mọi project bạn mở bằng Cursor trên máy đó).
Với project-level, tạo file .cursor/mcp.json ở thư mục gốc repo:
{
"mcpServers": {
"figma": {
"url": "https://mcp.figma.com/mcp"
}
}
}
Nếu muốn dùng cho mọi project mà không phải cấu hình lại từng repo, đặt cùng nội dung vào ~/.cursor/mcp.json (thư mục home của user). Một lưu ý nhỏ nhưng dễ gây nhầm lẫn: nếu cả hai file cùng tồn tại và cùng khai báo key figma, Cursor sẽ ưu tiên cấu hình ở project-level — điều này hữu ích khi một số repo cần trỏ tới workspace Figma khác với mặc định cá nhân.
Đây là remote MCP server (chạy trên hạ tầng của Figma, không phải chạy local như một số MCP server dạng CLI), nên bạn không cần cài thêm binary hay Node package nào — chỉ cần khai báo URL. Sau khi lưu file, mở Cursor Settings > MCP (truy cập qua Command Palette hoặc icon settings góc dưới bên trái), bạn sẽ thấy server figma xuất hiện trong danh sách với trạng thái ban đầu là chưa xác thực. Nhấn vào để trigger luồng OAuth (giao thức ủy quyền chuẩn, không yêu cầu bạn nhập password Figma trực tiếp vào Cursor) — trình duyệt mặc định sẽ mở ra, yêu cầu bạn đăng nhập tài khoản Figma và cấp quyền cho Cursor truy cập vào các file/project bạn chọn.
Sau khi OAuth hoàn tất, quay lại Cursor Settings > MCP, trạng thái server sẽ chuyển sang "connected" (màu xanh), và danh sách tool bên dưới sẽ được list ra tự động. Đây là bước quan trọng cần kiểm tra kỹ trước khi bắt đầu làm việc thật — nếu danh sách tool trống hoặc báo lỗi, gần như chắc chắn là do session OAuth hết hạn hoặc bạn chưa chọn đúng Figma team/project khi cấp quyền. Các tool bạn nên thấy xuất hiện gồm:
| Tool | Chức năng |
|---|---|
get_code |
Sinh code (React/CSS...) từ một node Figma cụ thể |
get_variable_defs |
Lấy định nghĩa design token (color, spacing, typography...) đang áp dụng cho node |
get_screenshot |
Chụp ảnh render của frame/node để agent đối chiếu trực quan |
get_code_connect_map |
Lấy mapping giữa Figma component và component thật trong codebase (qua Code Connect) |
get_metadata |
Lấy thông tin cấu trúc (layer tree, tên node, kích thước...) mà không sinh code đầy đủ |
create_design_system_rules |
Sinh gợi ý rule file mô tả design system hiện có, dùng làm ngữ cảnh cho các lần generate sau |
Một điểm khác biệt so với dùng MCP qua CLI thuần: trong Cursor, các tool này không chỉ được agent gọi ngầm — bạn còn có thể thấy log từng lời gọi tool ngay trong panel chat, kèm tham số (node-id, file key...) được truyền vào. Điều này giúp debug rất nhanh khi agent sinh sai — bạn biết ngay là nó có gọi đúng get_variable_defs hay không, hay chỉ dựa vào phỏng đoán từ tên layer.
Mẹo: Sau khi connect lần đầu, hãy thử ngay một lệnh đơn giản như "list các design token đang có trong file Figma này" để xác nhận agent thực sự gọi được
get_variable_defstrước khi bắt tay vào task thật. Nhiều bạn bỏ qua bước xác nhận này, rồi mất cả buổi debug vì tưởng agent lỗi logic trong khi thực chất kết nối OAuth đã bị revoke từ phía Figma workspace.
Chuyển Frame Figma Thành UI Component Ngay Trong Cursor
Điểm mạnh lớn nhất khi dùng Figma MCP qua Cursor so với CLI là workflow liền mạch: bạn không cần copy kết quả từ terminal rồi dán lại vào file — agent làm việc trực tiếp trên file trong project, thấy toàn bộ cấu trúc thư mục, và biết nên tạo file mới ở đâu theo convention hiện có.
Cách dùng cơ bản: mở Agent Mode (Composer panel — phím tắt mặc định thường là Cmd/Ctrl + I), sau đó dán trực tiếp link Figma frame vào ô chat. Link Figma dạng đầy đủ trông như thế này, trong đó phần node-id chính là thứ MCP server dùng để xác định chính xác node bạn muốn:
https://www.figma.com/design/AbCdEfGhIjKlMnOp/Design-System?node-id=204-1892
Một ví dụ prompt thực tế bạn có thể gửi cho agent:
Đây là frame checkout summary: https://www.figma.com/design/AbCdEfGhIjKlMnOp/Design-System?node-id=204-1892
Hãy tạo component React (TypeScript) cho frame này, đặt tại src/components/checkout/CheckoutSummary.tsx.
Dùng CSS Modules (theo convention hiện có trong src/components/cart/CartSummary.module.css).
Lấy màu sắc và spacing từ design token thay vì hard-code giá trị số.
Trước khi sinh code cuối, hãy gọi get_screenshot để đối chiếu bố cục.
Khi nhận prompt này, agent tự động nhận diện link chứa node-id, gọi get_code để lấy cấu trúc/code gợi ý ban đầu, gọi get_variable_defs để map các giá trị màu/spacing sang design token thật (thay vì số hex/px rời rạc), và nếu bạn yêu cầu rõ, gọi thêm get_screenshot để so sánh trực quan trước khi chốt code. Kết quả thường trông như sau — chú ý cách token được dùng thay vì giá trị cứng:
// src/components/checkout/CheckoutSummary.tsx
import styles from './CheckoutSummary.module.css';
interface CheckoutSummaryProps {
itemCount: number;
subtotal: string;
shippingFee: string;
total: string;
}
export function CheckoutSummary({
itemCount,
subtotal,
shippingFee,
total,
}: CheckoutSummaryProps) {
return (
<section className={styles.container} aria-label="Checkout summary">
<h2 className={styles.title}>Order Summary ({itemCount} items)</h2>
<div className={styles.row}>
<span>Subtotal</span>
<span>{subtotal}</span>
</div>
<div className={styles.row}>
<span>Shipping</span>
<span>{shippingFee}</span>
</div>
<div className={`${styles.row} ${styles.totalRow}`}>
<span>Total</span>
<span>{total}</span>
</div>
</section>
);
}
/* src/components/checkout/CheckoutSummary.module.css */
.container {
background: var(--color-surface-secondary);
padding: var(--spacing-6);
border-radius: var(--radius-md);
}
.title {
font-size: var(--font-size-lg);
font-weight: var(--font-weight-semibold);
margin-bottom: var(--spacing-4);
}
.row {
display: flex;
justify-content: space-between;
padding: var(--spacing-2) 0;
color: var(--color-text-secondary);
}
.totalRow {
font-weight: var(--font-weight-bold);
color: var(--color-text-primary);
border-top: 1px solid var(--color-border);
margin-top: var(--spacing-2);
}
Vì Cursor thấy toàn bộ context của repo, nó thường tự nhận ra bạn đang dùng CSS Modules hay Tailwind hay styled-components dựa trên các file lân cận — nhưng đừng phó mặc hoàn toàn cho khả năng "tự đoán" này, vì với codebase lớn có nhiều pattern trộn lẫn (do refactor dở dang qua nhiều năm), agent có thể chọn nhầm pattern cũ đã bị deprecated. Luôn chỉ định rõ file convention muốn tham chiếu trong prompt như ví dụ trên.
Mẹo: Khi frame Figma có nhiều state (default, hover, disabled, error...), đừng dán một link duy nhất và hy vọng agent tự suy ra hết các state. Dán lần lượt link của từng variant/state (mỗi state thường có
node-idriêng trong Figma khi dùng component variants), yêu cầu agent gộp chúng thành props (variant,disabled...) của cùng một component — cách này cho kết quả chính xác hơn nhiều so với việc bắt agent tự suy diễn logic state từ một ảnh tĩnh.
Dùng Code Connect Để Khớp Component Figma Với Component Có Sẵn Trong Codebase
Vấn đề lớn nhất khi để AI generate code trực tiếp từ design là nó không biết bạn đã có sẵn component tương ứng trong codebase — kết quả là bạn nhận được một <Button> mới tinh, viết lại từ đầu, trong khi team đã có src/components/Button.tsx với đầy đủ variant, accessibility, và test coverage. Code Connect chính là cơ chế Figma xây ra để giải quyết đúng vấn đề này: nó tạo một mapping tường minh giữa component trong file Figma và component thật trong source code, giúp agent biết "component Figma tên Button này tương ứng với <Button /> ở đâu trong repo, import như thế nào, props nào ánh xạ với gì".
Cách publish mapping này thường qua file .figma.tsx đặt cạnh component gốc, cộng với một file cấu hình figma.config.json ở root repo để CLI của Code Connect biết publish lên đúng file Figma nào:
// figma.config.json
{
"codeConnect": {
"include": ["src/components/**/*.figma.tsx"],
"parser": "react"
}
}
Với component Button, file mapping trông như sau:
// src/components/Button.figma.tsx
import figma from '@figma/code-connect';
import { Button } from './Button';
figma.connect(
Button,
'https://www.figma.com/design/AbCdEfGhIjKlMnOp/Design-System?node-id=88-421',
{
props: {
label: figma.string('Label'),
variant: figma.enum('Variant', {
Primary: 'primary',
Secondary: 'secondary',
Danger: 'danger',
}),
disabled: figma.boolean('Disabled'),
},
example: ({ label, variant, disabled }) => (
<Button variant={variant} disabled={disabled}>
{label}
</Button>
),
}
);
Sau khi team chạy lệnh publish của Code Connect CLI (thường là figma connect publish), mapping này được đẩy lên gắn liền với node Button trên Figma. Từ lúc đó, mỗi khi agent trong Cursor gọi get_code_connect_map cho một frame có chứa instance của component Button, nó nhận về thông tin: component này đã có sẵn tại src/components/Button.tsx, dùng thế nào, props nào map với property nào trên Figma — thay vì generate một bản <button> thô từ HTML/CSS suy đoán.
Trong thực tế dùng với Agent Mode, bạn có thể prompt rõ ràng để đảm bảo agent ưu tiên tra cứu mapping trước khi generate:
Frame này dùng nhiều component có sẵn trong design system: https://www.figma.com/design/.../node-id=204-1892
Trước khi viết code, hãy gọi get_code_connect_map để kiểm tra component nào đã có mapping trong codebase.
Với các component đã map, import và dùng lại nguyên bản (không viết lại từ đầu).
Chỉ tạo component mới cho phần chưa có trong design system.
Lợi ích thực tế không chỉ là tiết kiệm thời gian — nó còn giữ tính nhất quán về accessibility, theme switching (dark mode), và test coverage vốn đã được xây trong component gốc, thứ mà một bản generate mới từ AI gần như chắc chắn sẽ thiếu ở lần đầu.
Mẹo: Đừng để Code Connect mapping "chết" theo thời gian. Khi refactor đổi tên prop hay đổi cấu trúc component gốc, mapping trong file
.figma.tsxphải được cập nhật và publish lại — nếu không, agent sẽ tra cứu ra thông tin cũ, dẫn đến việc import component với props không còn tồn tại. Cách thực dụng nhất là thêm bước publish Code Connect vào cùng CI pipeline với việc build component, để không ai quên.
Hạn Chế Đã Biết và Đánh Đổi Về Độ Chính Xác Thiết Kế Khi Dùng Cursor
Cursor được tối ưu trước hết cho tốc độ và trải nghiệm inline editing — đây là điểm mạnh khi bạn sửa code nhanh, nhưng lại là con dao hai lưỡi khi làm design-to-code. Trong nhiều trường hợp, agent ưu tiên trả lời nhanh dựa trên get_code và get_variable_defs mà bỏ qua hoặc trì hoãn việc gọi get_screenshot — vốn là bước tốn thêm một round-trip và một phần context window để "nhìn" ảnh chụp thực tế của frame. Hệ quả dễ thấy nhất: code sinh ra đúng về mặt cấu trúc (đúng token, đúng tên biến) nhưng lệch pixel-perfect so với thiết kế gốc — sai lệch nhỏ về spacing (padding 12px thay vì 16px do agent làm tròn theo token gần nhất), sai font-weight (chọn 500 thay vì 600 vì hai giá trị token gần giống tên nhau), hoặc bỏ sót một shadow/border tinh tế mà mắt thường nhìn ảnh mới nhận ra.
Một đánh đổi khác nằm ở tầng kiến trúc component: khi bạn không chỉ định rõ, agent tự quyết định cách chia nhỏ component (một file lớn hay tách thành nhiều sub-component, dùng local state hay nhận props từ ngoài...). Cách này nhanh — bạn chỉ cần dán link và nhận code ngay — nhưng rủi ro là kết quả không khớp convention nội bộ của team, đặc biệt ở các đội có quy ước chặt về pattern (ví dụ bắt buộc tách logic ra custom hook, hay quy định rõ khi nào dùng compound component). Ngược lại, nếu bạn viết prompt liệt kê chi tiết convention muốn áp dụng mỗi lần, quá trình chậm hơn đáng kể nhưng độ chính xác và tính nhất quán cao hơn nhiều.
Để giảm thiểu cả hai vấn đề trên, có ba thực hành nên áp dụng thành thói quen:
-
Định nghĩa convention một lần trong rule file thay vì lặp lại mỗi prompt. Cursor hỗ trợ thư mục
.cursor/rules(tương đương vai trò của CLAUDE.md ở Claude Code) để khai báo các quy ước cố định — style file, cách đặt tên, thư viện styling đang dùng, cấu trúc thư mục component. Khi rule file đã có sẵn, agent tự đọc và áp dụng mà không cần bạn gõ lại từng lần, giúp cân bằng giữa tốc độ và độ chính xác. -
Luôn yêu cầu tường minh việc gọi
get_screenshottrước khi chốt code, đặc biệt với các frame có nhiều chi tiết thị giác tinh tế (shadow, gradient, spacing bất đối xứng). Đừng tin tưởng agent tự động làm điều này — như đã nói, nó có xu hướng bỏ qua bước này nếu không được yêu cầu rõ, vì đây là bước tốn thêm thời gian xử lý. -
Review diff kỹ trước khi accept, đặc biệt so sánh trực tiếp giá trị spacing/color trong CSS được sinh ra với
get_variable_defsgốc thay vì chỉ nhìn qua bằng mắt trên preview. Với các dự án có yêu cầu pixel-perfect nghiêm ngặt (landing page marketing, design hero section...), nên coi output của Cursor là bản nháp tốt để tăng tốc, chứ không phải bản final có thể merge thẳng.
| Vấn đề | Nguyên nhân | Cách giảm thiểu |
|---|---|---|
| Sai lệch spacing/font-weight nhỏ | Agent ưu tiên tốc độ, bỏ qua get_screenshot |
Yêu cầu tường minh gọi get_screenshot trước khi chốt |
| Cấu trúc component không khớp convention team | Agent tự quyết định khi thiếu chỉ dẫn | Định nghĩa convention trong .cursor/rules |
| Mapping Code Connect lỗi thời | Component gốc đổi nhưng mapping chưa publish lại | Đưa bước publish Code Connect vào CI |
| Khó phát hiện lỗi tinh tế qua preview mắt thường | Review nhanh, không đối chiếu số liệu | So sánh trực tiếp giá trị CSS với token gốc trước khi accept |
Mẹo: Với những phần UI đòi hỏi độ chính xác cao (design hệ thống, component thư viện dùng chung toàn công ty), hãy tách hẳn quy trình thành hai bước: bước 1 để Cursor sinh bản nháp nhanh cho cấu trúc và logic, bước 2 mở song song ảnh Figma gốc và bản preview code, dùng chính prompt yêu cầu agent "so sánh get_screenshot của node X với ảnh preview hiện tại của component, liệt kê từng điểm khác biệt" — cách hỏi ngược này thường bắt được nhiều lỗi tinh tế hơn là chỉ yêu cầu agent "generate cho đúng" ngay từ đầu.