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_executeJS 코드 실행 (핵심!)매우 자주
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"
}

파일 데이터 조회, 이미지 다운로드용.


연결 설정 (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개수모드
Primitive44Value
Semantic34Light / Dark
Component30Default

토큰 구조: 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)

TypeSizeState합계
Primary, Outline, Ghost, Outline InverseSM, MD, LGDefault, Hover, Disabled4×3×3 = 36
  • Outline Inverse: 다크 배경용 흰색 테두리 버튼 (나중에 추가)

Phase 3: Input 컴포넌트 (10 variants)

SizeState
MD, LGDefault, Focus, Filled, Error, Disabled

Phase 4: Card 컴포넌트 (6 variants)

StyleSize
Default, OverlaySM, MD, LG

Phase 5: Typography Text Styles (9개)

StyleFontSize
DisplayGmarket Sans TTF Bold28px
Heading/H1Gmarket Sans TTF Bold24px
Heading/H2Gmarket Sans TTF Bold22px
Heading/H3Gmarket Sans TTF Medium20px
Body/LGPretendard Regular16px
Body/MDPretendard Regular14px
Body/MD MediumPretendard Medium14px
CaptionPretendard Regular12px
Caption MediumPretendard Medium12px

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)

ComponentVariants설명
Badge16 (4Color × 2Style × 2Size)Primary/Danger/Warning/Neutral, radius/md
Tab6 (2Style × 3State)Underline/Pill, Active/Default/Disabled
Modal3 (SM/MD/LG)범용 모달
Login Modal1 (Pattern)실제 사이트 기반 로그인 패턴
Select8 (2Size × 4State)Dropdown 컴포넌트
GNB2 (Desktop/Mobile)헤더 네비게이션
Footer1라이트 배경 다단 레이아웃
Guide Box3 (SM/MD/LG)아이콘+제목+설명+화살표
Accordion4 (2Style × 2State)접기/펼치기
Number Spinner4 (2Size × 2State)+/- 숫자 조정
Step Indicator3 (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으로 분류 배치:

  1. Form Controls — Button, Input, Select, Number Spinner
  2. Navigation — GNB, Tab, Step Indicator
  3. Content — Card, Badge, Guide Box, Accordion
  4. Overlay — Modal, Login Modal
  5. 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대 규칙

  1. FILL/HUG는 appendChild 이후에 설정 — 그 전에 설정하면 무시됨
  2. resize(w, 1) 후 자식 추가해도 높이 안 늘어남 — 명시적 layoutSizingVertical = 'HUG' 필수
  3. ComponentSet에도 HUG 별도 적용 — 개별 variant 수정만으로 부족

counterAxisSizingMode 제약

  • 'FIXED' | 'AUTO' 만 허용 ('FILL' 불가)
  • FILL 필요 시 → layoutSizingHorizontal = 'FILL' 사용

텍스트 생성 순서

  1. 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 파일

최종 현황 (2026-03-04)

항목수량
Variables157개 (Primitive 44 + Semantic 34 + Component 79)
Text Styles9개
Button45 variants (5Type × 3Size × 3State)
Input10 variants
Card6 variants
Badge16 variants (4Color × 2Style × 2Size)
Tab6 variants
Modal3 variants
Login Modal1 (Pattern)
Select8 variants
GNB2 variants (Desktop/Mobile)
Footer1 (Light theme)
Guide Box3 variants
Accordion4 variants
Number Spinner4 variants
Step Indicator3 variants
총 컴포넌트15종 112 variants

미구현

  • Carousel (Swiper 기반 — 복잡도 높아 별도 구현 필요)

날짜

  • 시작: 2026-03-04
  • 최종 업데이트: 2026-03-04

serverVersion 0.0.0 버그 (2026-03-19, 해결)

  • Windows에서 서버가 SERVER_HELLOserverVersion: "0.0.0" 전송 → 플러그인 연결 실패
  • 해결: ui.htmlui-full.html로 교체 (bootloader 우회)
  • 상세: Figma-Console-MCP-Windows-트러블슈팅