Figma MCP vs REST API — 퍼블리싱 워크플로우에서 무엇을 써야 하는가
Figma에서 코드를 뽑아내는 방법이 두 가지가 됐다. Claude Code에서 get_design_context를 호출하는 MCP 방식과, Figma REST API를 직접 호출하는 방식. 둘 다 "Figma 데이터를 가져온다"고 하지만, 실제로 돌려보면 돌아오는 데이터의 성격이 완전히 다르다.
퍼블리싱 파이프라인을 MCP 기반에서 Python + REST API 기반으로 전환하면서 이 차이를 직접 체감했다. 이 글은 그 경험을 정리한 것이다.
MCP가 주는 것
get_design_context를 호출하면 세 가지가 온다.
참조 코드 스니펫. React + Tailwind 기준으로 컴포넌트 코드를 생성해준다. 빠르게 구조를 잡기에는 편하다. Code Connect가 연결돼 있으면 실제 코드베이스의 컴포넌트가 매핑되어 나오기도 한다.
스크린샷. 노드의 시각적 렌더링을 이미지로 반환한다. API로는 알 수 없는 "실제로 어떻게 보이는가"를 확인할 수 있다.
메타데이터. 색상, 간격, 폰트 크기 같은 속성값이 요약된 형태로 온다.
처음 이걸 썼을 때 "이제 Figma 퍼블리싱이 쉬워지겠구나" 싶었다. 코드가 거의 완성된 형태로 나오니까.
MCP의 구조적 한계
그런데 실제 프로덕션 코드를 짜면서 한계가 드러나기 시작했다. 근본 원인은 데이터가 전처리를 거치는 구조에 있다.
MCP 방식:
Figma 원본 → MCP 서버가 전처리 (내부 로직 비공개) → React+Tailwind 힌트 → Claude가 해석 → 최종 코드
REST API 방식:
Figma 원본 → raw JSON (정보 손실 없음) → Python이 직접 처리 → 최종 코드MCP는 중간에 전처리 과정이 끼어 있어서, 원본 데이터가 "요약"되면서 정보가 빠진다. 구체적으로 어떤 게 빠지는지 하나씩 보면:
근사값 문제
MCP가 반환하는 코드는 Tailwind 클래스로 표현된 근사값이다. p-4는 16px인데, 실제 Figma 값이 12px인 경우도 p-3이 아니라 p-4로 나올 수 있다. Tailwind의 4px 그리드로 반올림되기 때문이다.
반면 REST API의 paddingTop, paddingLeft 필드는 픽셀 단위 정확한 값이다.
{
"paddingTop": 12,
"paddingLeft": 20,
"paddingRight": 20,
"paddingBottom": 12
}디자이너가 공들여 잡은 간격이 반올림되는 건 미묘하지만 쌓이면 티가 난다.
노드별 토큰 바인딩 정보 부재
디자인 시스템에서 가장 중요한 건 색상이 어떤 시맨틱 토큰으로 연결돼 있는가다. #3B82F6을 하드코딩하면 안 되고, color.primary.500이나 var(--color-primary)로 써야 한다.
REST API 응답에는 boundVariables 필드가 있다.
{
"fills": [{
"type": "SOLID",
"color": { "r": 0.231, "g": 0.51, "b": 0.965 },
"boundVariables": {
"color": {
"type": "VARIABLE_ALIAS",
"id": "VariableID:123:456"
}
}
}]
}이 VariableID를 token.json의 역색인과 대조하면 "이 색상은 color.primary.blue다"라는 걸 정확히 알 수 있다. MCP에도 get_variable_defs라는 도구가 있어 변수 이름↔값 매핑은 조회 가능하지만, REST API의 boundVariables처럼 **"이 노드의 이 fill이 어떤 변수에 바인딩되어 있는가"**라는 노드별 바인딩 정보는 제공하지 않는다.
숨겨진 상태 미포함
컴포넌트에는 기본 상태(default), 호버(hover), 비활성(disabled) 등 여러 상태가 있다. Figma에서는 이것들이 visible: false 레이어나 componentProperties로 표현된다.
MCP의 get_design_context는 현재 보이는 상태 하나만 반환한다. REST API로 전체 노드 트리를 받으면 모든 상태가 다 있다. 조건부 렌더링을 구현할 때 이 차이가 결정적이다.
{
"name": "state=disabled",
"visible": false,
"children": []
}잘림(truncation) 문제
복잡한 컴포넌트에서 get_design_context의 응답이 잘리는 경우가 있다. 응답 크기 제한 때문이다. 이때 어느 부분이 잘렸는지 명확하지 않아 누락된 스펙이 조용히 무시될 수 있다.
REST API는 depth 파라미터로 조회 깊이를 조절하고, 잘린 노드(children이 비어있는데 실제로는 있는 경우)를 감지해서 추가 요청으로 채울 수 있다.
REST API가 주는 것
정리하면 REST API는 원시 데이터를 준다.
- 모든 레이어 (visible: false 포함)
- 픽셀 단위 정확한 수치
- boundVariables로 토큰 연결 정보
- componentProperties로 모든 UI 상태
- 재귀적으로 깊은 노드까지 순회 가능
figma_analyze.py에서 구현한 핵심 로직도 이 위에 있다. boundVariables로 색상을 토큰으로 역추적하고, visible: false 레이어를 필터링하거나 조건부 렌더링 힌트로 변환하고, 잘린 노드를 감지해서 배치 요청으로 채운다.
def resolve_color(fills, token_index):
"""fills 배열에서 색상을 토큰으로 역추적"""
for fill in fills:
if fill.get('type') != 'SOLID':
continue
bound = fill.get('boundVariables', {}).get('color', {})
if bound.get('type') == 'VARIABLE_ALIAS':
var_id = bound['id']
token_name = token_index['semanticById'].get(var_id) \
or token_index['rawById'].get(var_id)
if token_name:
return token_name # "color.primary.blue"
# 토큰 없으면 hex 반환
r, g, b = fill['color']['r'], fill['color']['g'], fill['color']['b']
return f"#{int(r*255):02x}{int(g*255):02x}{int(b*255):02x}"이런 로직을 MCP 위에서 구현하는 건 불가능하다. MCP가 이 원시 데이터를 주지 않기 때문이다.
그럼 MCP는 언제 쓰는가
MCP가 쓸모없다는 게 아니다. 용도가 다르다.
빠른 시각적 참조. "이 컴포넌트 대략 어떻게 생겼지?" 확인할 때 스크린샷과 함께 오는 MCP 응답은 빠르다.
Code Connect가 잘 구성된 경우. Figma 컴포넌트와 코드베이스 컴포넌트가 정확히 1:1로 매핑돼 있으면, MCP가 <Button variant="primary" /> 같은 실제 코드를 바로 내려준다. 이 경우엔 REST API를 굳이 쓸 필요가 없다.
개략적인 레이아웃 파악. 전체 페이지의 구조를 빠르게 이해할 때 MCP의 구조화된 응답이 편하다.
결국 "정확한 값이 필요한가" 가 분기점이다. 디자인 QA, 토큰 매핑, 조건부 UI 구현처럼 정확도가 중요한 작업은 REST API. 빠른 탐색이나 참조는 MCP.
두 가지를 조합하는 패턴
실제 파이프라인에서는 이렇게 쓴다.
- REST API로 전체 스펙 수집 (
figma_analyze.py): 토큰 매핑, 레이아웃 수치, 자산 목록, 조건부 UI 목록을 완전하게 구성 - MCP로 시각적 확인: 생성된 코드가 실제 시안과 맞는지 스크린샷으로 대조 (
/design-qa)
REST API로 코드를 짜고, MCP로 눈으로 확인한다. 서로의 약점을 보완하는 구조다.
figma_analyze.py (REST API)
→ /tmp/figma-analysis.json ← 정확한 수치, 토큰 정보
→ /tmp/figma-spec-cache.md ← 스펙 요약
claude -p /figma-publish-tailwind (LLM + MCP)
→ 스펙 파일 기반 코드 생성
→ get_design_context로 특정 노드 시각 확인 (필요시)
/design-qa (MCP 스크린샷 비교)
→ 생성된 코드 vs Figma 스크린샷 대조토큰 비용 비교
두 방식의 비용 차이도 크다. 아래는 실제 사용 중 체감한 대략적인 추정치다 (노드 복잡도에 따라 편차가 크다).
MCP 방식 (per 노드, 추정):
get_design_context 호출 → ~1K (tool call)
전처리된 결과 수신 → ~5~15K (코드 힌트 + 메타)
합계: ~6~16K tokens
REST API + Claude 직접 해석 (per 노드, 추정):
curl API 호출 + JSON 수신 → ~30~80K (raw 노드 데이터)
Claude가 JSON 파싱 → ~5K (추론)
합계: ~35~85K tokens
REST API + Python 전처리 (per 노드, 추정):
Python이 API 호출 + 파싱 → 0 tokens (Claude 밖에서 처리)
구조화된 스펙만 Claude에 전달 → ~3~8K tokens
합계: ~3~8K tokensMCP가 토큰 효율적으로 보이지만, Python 전처리 파이프라인을 쓰면 REST API 방식이 오히려 더 적게 소모한다. 정확도와 토큰 효율 모두 잡는 셈이다.
트레이드오프 요약
MCP (get_design_context) | REST API | |
|---|---|---|
| 수치 정확도 | 근사값 (Tailwind 그리드 반올림) | 픽셀 단위 정확 |
| 토큰 역추적 | 변수 정의 조회 가능 (get_variable_defs), 노드별 바인딩은 미제공 | boundVariables로 노드별 바인딩 |
| 숨겨진 레이어 | 미포함 | 전체 포함 |
| 조건부 UI 상태 | 현재 상태만 | 모든 상태 |
| 스크린샷 | 있음 | 없음 |
| Code Connect | 지원 | 별도 구현 |
| 설정 필요 없음 | 바로 사용 | FIGMA_TOKEN 필요 |
| 응답 잘림 가능성 | 있음 | 제어 가능 |
| 토큰 비용 | 응답 크기만큼 소모 | 0 (Python으로 처리) |
권장: 프로덕션 퍼블리싱 파이프라인에서 정확한 스펙 수집은 REST API, 시각적 확인과 코드 생성 보조는 MCP. Code Connect가 잘 구성된 디자인 시스템이라면 MCP 비중을 높여도 된다.