Figma MCP로 디자인 시스템 제어하기
목표
Claude Code에서 Figma Console MCP를 사용하여 디자인 시스템(Variables, Components, Text Styles)을 직접 생성/수정
사용한 MCP 서버
1. figma-console (핵심 - 읽기/쓰기)
Figma Desktop Bridge 플러그인을 통해 figma API에 직접 접근. 컴포넌트 생성, 수정, 삭제 모두 가능.
"figma-console": {
"command": "npx",
"args": ["-y", "figma-console-mcp"],
"env": {}
}주요 도구:
| 도구 | 용도 | 사용 빈도 |
|---|---|---|
figma_get_status | 연결 상태 확인 | 세션 시작 시 |
figma_execute | JS 코드 실행 (핵심!) | 매우 자주 |
figma_capture_screenshot | 노드 스크린샷 캡처 | 검증 시 |
figma_get_selection | 현재 선택된 노드 조회 | 필요 시 |
figma_search_components | 컴포넌트 검색 | 세션 시작 시 |
2. figma-official (읽기 전용, Dev Mode)
REST API 기반. 파일 구조 조회용. 컴포넌트 생성 불가.
"figma-official": {
"url": "http://127.0.0.1:3845/mcp"
}3. framelink-figma (읽기 전용)
파일 데이터 조회, 이미지 다운로드용.
연결 설정 (Desktop Bridge)
필수 조건
- Figma Desktop 앱 실행 중
- Desktop Bridge 플러그인 임포트 완료
플러그인 임포트 경로
Plugins → Development → Import plugin from manifest
manifest 위치:
C:\Users\USER\AppData\Local\npm-cache\_npx\{hash}\node_modules\figma-console-mcp\figma-desktop-bridge\manifest.json
포트 충돌 해결
- 기본 포트: 9223
- 여러 MCP 인스턴스 실행 시 포트 충돌 → fallback 포트 사용 (9224, 9225, 9226…)
- 해결법: 플러그인 재임포트하면 multi-port scanning 지원
작업 히스토리 (2026-03-04)
Phase 1: Variables 생성 (108개)
| Collection | 개수 | 모드 |
|---|---|---|
| Primitive | 44 | Value |
| Semantic | 34 | Light / Dark |
| Component | 30 | Default |
토큰 구조: Primitive → Semantic → Component (3-tier alias)
// figma_execute 예시: Variable 생성
const collection = figma.variables.createVariableCollection('Primitive');
const modeId = collection.modes[0].modeId;
const v = figma.variables.createVariable('color/blue/500', collection, 'COLOR');
v.setValueForMode(modeId, { r: 0.02, g: 0.28, b: 0.87, a: 1 });Phase 2: Button 컴포넌트 (36 variants)
| Type | Size | State | 합계 |
|---|---|---|---|
| Primary, Outline, Ghost, Outline Inverse | SM, MD, LG | Default, Hover, Disabled | 4×3×3 = 36 |
- Outline Inverse: 다크 배경용 흰색 테두리 버튼 (나중에 추가)
Phase 3: Input 컴포넌트 (10 variants)
| Size | State |
|---|---|
| MD, LG | Default, Focus, Filled, Error, Disabled |
Phase 4: Card 컴포넌트 (6 variants)
| Style | Size |
|---|---|
| Default, Overlay | SM, MD, LG |
Phase 5: Typography Text Styles (9개)
| Style | Font | Size |
|---|---|---|
| Display | Gmarket Sans TTF Bold | 28px |
| Heading/H1 | Gmarket Sans TTF Bold | 24px |
| Heading/H2 | Gmarket Sans TTF Bold | 22px |
| Heading/H3 | Gmarket Sans TTF Medium | 20px |
| Body/LG | Pretendard Regular | 16px |
| Body/MD | Pretendard Regular | 14px |
| Body/MD Medium | Pretendard Medium | 14px |
| Caption | Pretendard Regular | 12px |
| Caption Medium | Pretendard Medium | 12px |
Phase 6: Component Tokens 추가 (49개, 총 157개)
Badge, Tab, Modal, Select, Accordion, GNB, Guide Box용 컴포넌트 토큰 일괄 추가.
- Component Collection: 30개 → 79개
- 총 Variables: 108개 → 157개
Phase 7: 나머지 컴포넌트 10종 (MCP figma_execute)
| Component | Variants | 설명 |
|---|---|---|
| Badge | 16 (4Color × 2Style × 2Size) | Primary/Danger/Warning/Neutral, radius/md |
| Tab | 6 (2Style × 3State) | Underline/Pill, Active/Default/Disabled |
| Modal | 3 (SM/MD/LG) | 범용 모달 |
| Login Modal | 1 (Pattern) | 실제 사이트 기반 로그인 패턴 |
| Select | 8 (2Size × 4State) | Dropdown 컴포넌트 |
| GNB | 2 (Desktop/Mobile) | 헤더 네비게이션 |
| Footer | 1 | 라이트 배경 다단 레이아웃 |
| Guide Box | 3 (SM/MD/LG) | 아이콘+제목+설명+화살표 |
| Accordion | 4 (2Style × 2State) | 접기/펼치기 |
| Number Spinner | 4 (2Size × 2State) | +/- 숫자 조정 |
| Step Indicator | 3 (3State) | 단계 표시 |
Phase 8: 디자인 비교 수정
실제 rideus.net과 비교하여 수정:
- Footer: 다크 → 라이트 배경 (color/bg/secondary)
- Badge: radius/full(40px) → radius/md(8px), 4색상 추가, 16 variants로 재생성
- Button: CTA(오렌지) 타입 추가 → 5타입 45 variants
- Login Modal: 실제 사이트 로그인 모달 기반 패턴 컴포넌트 생성
Phase 9: 컴포넌트 정리
5개 Section으로 분류 배치:
- Form Controls — Button, Input, Select, Number Spinner
- Navigation — GNB, Tab, Step Indicator
- Content — Card, Badge, Guide Box, Accordion
- Overlay — Modal, Login Modal
- Layout & Interactive — Footer
figma_execute 핵심 패턴
Async API 필수 (중요!)
// ❌ 동기 API (에러 발생)
const vars = figma.variables.getLocalVariables();
// ✅ 비동기 API 사용
const vars = await figma.variables.getLocalVariablesAsync();
const collections = await figma.variables.getLocalVariableCollectionsAsync();
const textStyles = await figma.getLocalTextStylesAsync();Variable 바인딩 Fill
function bindFill(node, variable) {
const paint = figma.variables.setBoundVariableForPaint(
{ type: 'SOLID', color: { r: 0, g: 0, b: 0 }, opacity: 1 },
'color', variable
);
node.fills = [paint];
}Variable 바인딩 (숫자: padding, radius 등)
node.setBoundVariable('paddingLeft', spacingVariable);
node.setBoundVariable('topLeftRadius', radiusVariable);기존 Variable 참조
const allVars = await figma.variables.getLocalVariablesAsync();
const blueVar = allVars.find(v => v.name === 'color/blue/500');Component Set에 Variant 추가
const buttonSet = figma.currentPage.findOne(
n => n.name === 'Button' && n.type === 'COMPONENT_SET'
);
const newComp = figma.createComponent();
newComp.name = 'Type=New, Size=MD, State=Default';
// ... 스타일링 후
buttonSet.appendChild(newComp);Text Style 생성
await figma.loadFontAsync({ family: 'Pretendard', style: 'Regular' });
const style = figma.createTextStyle();
style.name = 'Body/MD';
style.fontName = { family: 'Pretendard', style: 'Regular' };
style.fontSize = 14;
style.lineHeight = { value: 150, unit: 'PERCENT' };Figma Plugin API 주의사항
폰트
- 텍스트 생성 전 반드시
figma.loadFontAsync()호출 - Gmarket Sans의 Figma 등록명:
Gmarket Sans TTF(TTF 포함!) fontName먼저 설정 → 그 다음characters설정
Layout
counterAxisSizingMode:'FIXED'|'AUTO'만 가능 ('FILL'불가)- FILL 설정:
node.layoutSizingHorizontal = 'FILL'— 반드시 appendChild 후 설정 - HUG 설정:
node.layoutSizingVertical = 'HUG'— 반드시 appendChild 후 설정
Component Set Wrap
// 너비 고정해야 wrap 동작
set.primaryAxisSizingMode = 'FIXED';
set.resize(800, set.height);
set.layoutWrap = 'WRAP';삽질 기록
포트 충돌 (해결)
- MCP 서버 여러 개 실행 시 포트 9223 점유 → fallback 9226 사용
- Desktop Bridge 플러그인이 9223만 스캔 → 연결 실패
- 해결: 플러그인 재임포트로 multi-port scanning 활성화
동기 API 오류 (해결)
figma.variables.getLocalVariables()→ “Cannot call with documentAccess: dynamic-page” 오류- 해결:
getLocalVariablesAsync()사용
Outline Inverse 안 보임 (정상)
- 흰색 텍스트+테두리 → Component Set 배경(연보라)에서 거의 안 보임
- 실제 다크 배경에 인스턴스 배치하면 정상 표시
1px 높이 컴포넌트 (해결 — 가장 빈번한 문제)
resize(width, 1)+counterAxisSizingMode = 'AUTO'로 생성 시 자식 추가해도 높이 1px 유지- GNB(2), Footer(1), Accordion(4), Guide Box(3) 등 10개 컴포넌트에서 발생
- 해결: 자식을 모두 추가한 뒤
node.layoutSizingVertical = 'HUG'명시 설정 - 주의: ComponentSet 래퍼에도 별도로 HUG 설정 필요 (개별 variant 수정만으로는 부족)
내부 프레임 높이 고정 (해결)
- Modal 내부 footer/button 프레임이
layoutSizingVertical = 'FIXED'(100px)로 설정되어 버튼이 타원형으로 렌더링 - 해결: 내부 프레임들을 재귀적으로
layoutSizingVertical = 'HUG'설정
텍스트 겹침 (해결)
- Guide Box SM (240px)에서 텍스트 그룹이 FILL이 아니고 설명 텍스트가 줄바꿈 안 됨 → 텍스트 오버랩
- 해결: 아이콘/화살표는 FIXED, 텍스트 그룹은 FILL, 설명 텍스트에
textAutoResize = 'HEIGHT'적용
실제 사이트와 디자인 불일치 (해결)
- 분석 문서만 보고 만들면 실제와 차이 발생
- Footer 배경색, Badge 반경/색상, Button CTA 타입 누락 등
- 교훈: 구현 후 반드시 원본 사이트와 시각 비교 → 차이점 수정 사이클 필수
실전 교훈 요약 (Quick Reference)
Auto Layout 사이징 3대 규칙
- FILL/HUG는 appendChild 이후에 설정 — 그 전에 설정하면 무시됨
- resize(w, 1) 후 자식 추가해도 높이 안 늘어남 — 명시적
layoutSizingVertical = 'HUG'필수 - ComponentSet에도 HUG 별도 적용 — 개별 variant 수정만으로 부족
counterAxisSizingMode 제약
'FIXED'|'AUTO'만 허용 ('FILL'불가)- FILL 필요 시 →
layoutSizingHorizontal = 'FILL'사용
텍스트 생성 순서
loadFontAsync()→ 2.fontName설정 → 3.characters설정 (순서 위반 시 에러)
- 줄바꿈 필요:
resize(fixedWidth, h)→textAutoResize = 'HEIGHT' - GmarketSans Figma 등록명:
Gmarket Sans TTF
Variable 참조 딕셔너리 패턴
const allVars = await figma.variables.getLocalVariablesAsync();
const v = {};
allVars.forEach(vr => { v[vr.name] = vr; });
// → v['color/blue/500'], v['spacing/4'] 등으로 접근MCP 연결 체크리스트
- Figma Desktop 앱 실행 중?
- Desktop Bridge 플러그인 실행 중?
-
figma_get_status로 연결 확인? - 포트 충돌 시 → 플러그인 재임포트
- 이전 세션 nodeId는 무효 →
figma_search_components로 재검색
프로젝트 파일 구조
디자인시스템/
├── css/
│ ├── tokens.css # CSS Custom Properties (Primitive + Semantic)
│ └── components.css # Button, Input, Card 컴포넌트 CSS
├── figma-plugin/
│ ├── manifest.json # Figma 플러그인 매니페스트
│ ├── code.js # Variables + Button 생성 스크립트
│ ├── code-input-card.js # Input + Card 생성 스크립트
│ └── code-card.js # Card 단독 생성 스크립트
├── preview.html # 디자인 시스템 프리뷰 (Light/Dark 토글)
└── docs/ # PDCA 문서
Figma 파일
- URL: https://www.figma.com/design/lYp3hnoDQiWcslaDSRwJx4/Design-system-test
- Page: Page 1
최종 현황 (2026-03-04)
| 항목 | 수량 |
|---|---|
| Variables | 157개 (Primitive 44 + Semantic 34 + Component 79) |
| Text Styles | 9개 |
| Button | 45 variants (5Type × 3Size × 3State) |
| Input | 10 variants |
| Card | 6 variants |
| Badge | 16 variants (4Color × 2Style × 2Size) |
| Tab | 6 variants |
| Modal | 3 variants |
| Login Modal | 1 (Pattern) |
| Select | 8 variants |
| GNB | 2 variants (Desktop/Mobile) |
| Footer | 1 (Light theme) |
| Guide Box | 3 variants |
| Accordion | 4 variants |
| Number Spinner | 4 variants |
| Step Indicator | 3 variants |
| 총 컴포넌트 | 15종 112 variants |
미구현
- Carousel (Swiper 기반 — 복잡도 높아 별도 구현 필요)
날짜
- 시작: 2026-03-04
- 최종 업데이트: 2026-03-04
serverVersion 0.0.0 버그 (2026-03-19, 해결)
- Windows에서 서버가
SERVER_HELLO에serverVersion: "0.0.0"전송 → 플러그인 연결 실패 - 해결:
ui.html을ui-full.html로 교체 (bootloader 우회) - 상세: Figma-Console-MCP-Windows-트러블슈팅
