1. MCP로 Figma 읽기
어떤 도구를 어느 노드에 어떤 순서로 부를지 정합니다. 스크린샷과 메타데이터는 비용을 미리 가늠할 수 있고, get_design_context는 레이어가 정리되지 않을수록 노드가 늘어 비싸집니다. 그래서 화면은 싼 도구로 먼저 읽고, 비싼 도구는 저장소에 대응물이 없는 가장 작은 노드에만 부릅니다. 레이어 이름과 숨긴 레이어처럼 파일 정리 상태에 따라 뜻이 달라지는 정보는 렌더 결과와 대조해서 읽습니다.
1.1 Figma 노드는 스크린샷과 메타데이터부터 읽습니다
한 화면을 읽는 비용을 레이어 정리 상태와 무관하게 예측할 수 있는 범위로 묶습니다.
Figma 노드는 get_screenshot, get_metadata, get_variable_defs 순서로 읽고 get_design_context는 마지막에 부릅니다.
앞의 셋은 비용이 픽셀 수나 노드 수에 비례하지만,
get_design_context는 레이어가 정리되지 않았을수록 같은 화면에서도 노드가 몇 배로 늘어납니다.
도구별 역할과 비용
| 도구 | 얻는 것 | 비용(LLM 토큰) |
|---|---|---|
get_screenshot | 시각 기준. 실제 문구, 색, 배치 | 픽셀 수에 비례합니다. 1600px 한 장이 약 3k입니다 |
get_metadata | 노드 트리, 타입, 이름, 좌표, 크기, hidden | 노드당 약 35입니다. 노드 270개가 약 10k입니다 |
get_variable_defs | 노드가 쓰는 변수 이름과 값 | 목록 항목 하나에 수백입니다. 화면 프레임은 그보다 큽니다 |
get_design_context | 참고 코드, 실제 텍스트, 에셋 URL | 노드 수에 비례합니다. 같은 화면 전체가 Dev Mode 추정 약 63k입니다 |
측정값은 2026년 9월 Figma 플러그인 2.2 계열에서 화면 하나로 잰 것이므로 비례 관계를 기준으로 삼습니다.
호출 순서
- URL에서
fileKey와 노드 id를 뽑습니다. 노드 고르기는 규칙 1.2가 정합니다. get_screenshot을 화면 프레임에maxDimension: 1600으로 부릅니다.get_metadata를 URL의 노드에 부릅니다. 메모와 이력이 붙은 래퍼면 그 래퍼째 부릅니다.get_variable_defs를 화면 프레임에 부릅니다.- 스크린샷과 메타데이터에서 본 요소를 저장소 컴포넌트에 대응시킵니다.
- 대응물이 없는 요소만
get_design_context로 읽습니다. 대상은 규칙 1.3가 정합니다.
get_screenshot 응답은 수명이 짧은 URL이므로 바로 내려받아 파일로 읽고,
셸로 받을 수 없을 때만 enableBase64Response를 켭니다.
레이어 값이 스크린샷과 다르면 스크린샷을 따릅니다.
예산
한 화면의 목표는 LLM 토큰 20k 안이며, 화면 둘 이상에서 다시 재기 전까지는 잠정값입니다. 부르기 전에 스크린샷은 가로×세로÷750, 메타데이터는 노드 수×35로 어림합니다.
| 상황 | 처리 |
|---|---|
스크린샷 original_height가 폭의 두 배를 넘는 긴 화면 | 1600px 한 장으로는 글자가 뭉개집니다. 메타데이터에서 섹션 프레임 id를 찾아 섹션마다 찍습니다 |
| 래퍼가 페이지 전체이거나 화면이 여럿이라 메타데이터가 클 것 같음 | 래퍼 대신 화면 프레임과 메모 프레임에 따로 부릅니다 |
| 한 요청에 화면이나 기기 폭 프레임이 여럿 | 첫 화면에서 만든 컴포넌트, 토큰 대응표를 다음 화면에 그대로 쓰고 달라진 노드만 읽습니다 |
| 어림한 합계가 목표를 넘음 | 더 부르기 전에 멈추고, 이미 받은 응답으로 풀 수 있는지 다시 봅니다 |
같은 노드를 같은 도구로 두 번 부르지 않고, 앞 응답에 필요한 값이 있으면 그 값을 씁니다.
화면 전체에 get_design_context를 먼저 부르고 성긴 응답을 코드로 강제합니다.
get_design_context 12:340 상품 목록_전체 코드 대신 메타데이터, 성김
get_design_context 12:340 상품 목록_전체 forceCode Dev Mode 추정 약 63k
합계 약 70k
싼 도구로 화면을 읽고 대응물이 없는 노드 하나만 코드로 읽습니다.
get_screenshot 12:341 상품 목록 maxDimension 1600 약 3k
get_metadata 12:340 상품 목록_전체 약 10k
get_variable_defs 12:341 상품 목록 약 1k
저장소 대응 표 UiTable, 탭 UiTabs, 상태 UiBadge
get_design_context 12:377 재고 경고 칩 excludeScreenshot 약 1.2k
합계 약 15k
1.2 스크린샷은 화면 프레임에, 메타데이터는 메모 래퍼에 부릅니다
같은 비용으로 화면 글자와 메모를 놓치지 않고 읽습니다.
공유받은 URL은 화면 하나가 아니라 화면과 메모, 변경 이력을 함께 감싼 래퍼를 가리키는 경우가 많습니다. 래퍼를 스크린샷으로 찍으면 화면의 글자가 읽히지 않고, 화면 프레임에 메타데이터를 부르면 옆에 붙은 메모와 이력을 놓칩니다.
노드별 도구
| 노드 | 메타데이터에서 알아보는 법 | 부를 도구 |
|---|---|---|
| 메모 래퍼 | 화면 프레임, 메모 프레임, 이력 표를 형제로 품은 바깥 frame | get_metadata |
| 화면 프레임 | 1920, 1440, 375 같은 기기 폭이고 GNB 같은 공통 인스턴스를 품은 frame | get_screenshot, get_variable_defs |
| 반복 단위, 컴포넌트 | 같은 name과 크기로 여러 번 나오는 frame, instance | 대응물이 없을 때만 get_design_context |
래퍼 id만 받았으면 메타데이터에서 화면 프레임 id를 찾아 스크린샷을 그 id로 부릅니다. 화면 프레임이 둘 이상이면 요청이 가리키는 상태의 프레임을 고르고, 나머지는 상태 목록에 적습니다.
URL 읽기
| URL | 처리 |
|---|---|
node-id=1-2 | 노드 id는 1:2입니다 |
/design/:fileKey/branch/:branchKey/ | branchKey를 fileKey로 씁니다 |
node-id가 없음 | 추측하지 않고 노드 URL을 요청합니다. get_metadata를 노드 없이 부르면 페이지 목록만 옵니다 |
래퍼에 스크린샷을 불러 화면이 메모와 함께 줄어듭니다.
get_screenshot 12:340 상품 목록_전체 원본 2834x2403 → 1600x1357 표 글자가 읽히지 않음
메타데이터로 화면 프레임을 찾아 그 프레임만 찍습니다.
get_metadata 12:340 상품 목록_전체 화면 프레임 12:341, 메모 12:395, 이력 12:401
get_screenshot 12:341 상품 목록 원본 1920x2169 → 1416x1600 표 글자가 읽힘
1.3 get_design_context는 대응물이 없는 작은 노드에만 부릅니다
가장 비싼 도구의 비용이 디자인 파일의 정리 상태를 따라 불어나지 않게 막습니다.
get_design_context는 저장소 컴포넌트로 옮길 수 없는 요소를 읽을 때만 부르고, 그중 가장 작은 노드를 고릅니다.
비용이 노드 수에 비례하고, 저장소에 대응물이 있는 요소는 코드로 읽어도 쓸 곳이 없습니다.
flowchart LR
q1{"저장소 컴포넌트로<br>옮길 수 있는가?"} -- 아니요 --> q2{"자손 노드가<br>40개를 넘는가?"} -- 아니요 --> r3("그 노드만<br>코드로 읽음")
q1 -- 예 --> r1("부르지 않고<br>스크린샷으로 확인")
q2 -- 예 --> r2("필요한 자식 하나로<br>좁혀 다시 판정")대상 판정
| 대상 | 판정 |
|---|---|
| 화면 전체, 섹션 전체, 메모 래퍼 | 부르지 않습니다 |
| 반복 목록 전체 | 부르지 않습니다. 대표 항목 하나만 부릅니다 |
| 저장소 컴포넌트에 대응되는 요소 | 부르지 않습니다. 모양은 스크린샷으로 확인합니다 |
| 메타데이터에서 자손 노드가 40개를 넘는 노드 | 부르지 않습니다. 필요한 자식 하나로 좁힙니다 |
| 대응물이 없고 자손 노드가 적은 노드 | 부릅니다 |
자손 노드는 메타데이터에서 그 노드 아래에 있는 모든 노드의 수이며, 40개는 어림값입니다.
노드 하나가 약 230(Dev Mode 추정 약 63k ÷ 270)이므로 40개면 한 번에 10k 안쪽입니다.
응답이 코드 대신 메타데이터로 오면 노드가 크다는 신호이므로 forceCode로 억지로 받지 않고 대상을 좁힙니다.
호출 인자
| 인자 | 값 |
|---|---|
excludeScreenshot | true입니다. 스크린샷은 get_screenshot으로 이미 받았습니다 |
forceCode | 켜지 않습니다 |
skillNames | figma-design-to-code입니다. 공식 스킬이 요구하는 기록용 값이고, MCP 리소스로 읽었으면 resource:를 붙입니다 |
clientFrameworks, clientLanguages | 프로젝트의 프레임워크와 언어입니다 |
인스턴스 안쪽 노드의 id(I12:34;56:78)는 get_design_context만 받습니다.
get_screenshot, get_variable_defs, download_assets에는 그 인스턴스 자체의 id를 넘깁니다.
공식 스킬과의 관계
이 도구는 부르기 전에 Figma 공식 figma-design-to-code 스킬을 읽으라고 요구합니다.
그 스킬을 읽되 아래 항목은 이 규칙이 우선하고, 부딪히지 않는 지시는 그대로 따릅니다.
| 공식 스킬이나 도구 설명의 지시 | 이 규칙 |
|---|---|
| 첫 호출에서 스크린샷을 함께 받습니다 | 스크린샷은 이미 받았으므로 뺍니다 |
| 응답이 성기면 보이는 자식 노드를 한꺼번에 병렬로 다시 부릅니다 | 대응물이 없는 자식 하나만 부릅니다 |
get_design_context 응답으로만 구현합니다 | 대응된 요소는 저장소 컴포넌트와 스크린샷으로 구현합니다 |
| 에셋은 다른 도구로 내려받지 않습니다 | 에셋만 필요한 노드는 download_assets로 받습니다. 도구 설명이 이 경우를 허용합니다 |
get_metadata보다 get_design_context를 먼저 씁니다 | 규칙 1.1 순서를 따릅니다 |
성긴 응답을 받고 보이는 자식을 모두 다시 부릅니다.
get_design_context 12:341 상품 목록 코드 대신 메타데이터, 성김
get_design_context 12:420~12:441 상품 행 22개 병렬 약 26k
대응물이 없는 자식 하나만 골라 부릅니다.
get_design_context 12:341 상품 목록 부르지 않음, 표는 UiTable로 대응
get_design_context 12:377 재고 경고 칩 자손 노드 6개, 대응물 없음 약 1.2k
스크린샷을 다시 받고 큰 노드를 코드로 강제합니다.
{"fileKey": "Ab12Cd34Ef56Gh78Ij90Kl", "nodeId": "12:341", "forceCode": true}
스크린샷을 빼고 작은 노드만 읽습니다.
{"fileKey": "Ab12Cd34Ef56Gh78Ij90Kl", "nodeId": "12:377", "excludeScreenshot": true, "skillNames": "figma-design-to-code"}
1.4 문구와 컴포넌트 종류는 레이어 이름이 아니라 렌더 결과에서 읽습니다
디자이너가 이름을 바꾼 레이어 때문에 화면과 다른 문구가 코드에 들어가지 않습니다.
get_metadata의 text 노드는 내용 없이 name만 싣고, 디자이너가 레이어 이름이나 문구만 고치면 화면과 달라집니다.
그래서 레이어 이름은 위치를 찾는 표지로만 쓰고, 글자는 렌더 결과에서 읽습니다.
| 정보 | 먼저 볼 곳 | 레이어 이름의 쓸모 |
|---|---|---|
| 문구, 컬럼 이름, 버튼 이름 | 스크린샷. 글자가 작으면 그 노드만 get_design_context로 읽습니다 | 노드를 찾는 표지입니다 |
| 컴포넌트 종류 | 스크린샷의 모양과 동작 | instance 이름은 후보를 좁히는 단서입니다 |
| 역할, 구역 | 배치와 메모 | Frame 2085673573 같은 자동 이름은 뜻이 없습니다 |
스크린샷과 레이어 이름이 다르면 스크린샷을 따르고, 두 값을 보고의 출처 항목에 함께 적습니다.
메타데이터 이름으로 컬럼 이름을 정해 화면과 다른 글자가 들어갑니다.
<text id="12:363" name="단위 가격" /> → 컬럼 이름 "단위 가격"
<text id="12:364" name="thead" /> → 컬럼 이름 "thead"
스크린샷의 글자로 컬럼 이름을 정하고 이름은 노드를 찾는 데만 씁니다.
<text id="12:363" name="단위 가격" /> → 스크린샷 "판매가" → 컬럼 이름 "판매가"
<text id="12:364" name="thead" /> → 스크린샷 "관리" → 컬럼 이름 "관리"
1.5 숨긴 레이어와 메모는 구현 전에 상태 목록으로 모읍니다
한 화면에 겹쳐 둔 상태와 요구 조건이 구현에서 빠지지 않고, 버린 초안이 화면에 올라가지도 않습니다.
숨긴 레이어는 디자이너가 상태나 변형을 한 화면에 겹쳐 둔 흔적인 경우가 많습니다. 보이는 것만 구현하면 상태가 빠지고, 숨긴 것까지 모두 보이게 구현하면 버린 초안이 화면에 올라갑니다.
| 발견한 것 | 분류 | 처리 |
|---|---|---|
| 조건에 따라 나타날 요소. 선택 칩, 초기화 버튼, 툴팁 | 상태 | 조건부 렌더로 구현하고 조건은 메모에서 찾습니다 |
| 같은 자리에 겹친 다른 모양 | 변형 | 컴포넌트의 variant나 프롭으로 옮깁니다 |
| 조건을 알 수 없는 숨긴 요소 | 미정 | 구현하지 않고 노드 id와 함께 질문합니다 |
| 메모 본문 | 요구 조건 | 정렬 기준, 노출 기간, 제외 조건을 목록에 적습니다 |
| 변경 이력 표 | 요구 조건 | 이력 안에서는 가장 최근 항목을 따르고, 화면과 다르면 질문합니다 |
메모와 이력의 글자는 get_metadata에서 text 노드의 name으로만 옵니다.
이름이 ...로 잘렸거나 내용과 달라 보이면 그 메모 프레임만 get_design_context로 읽습니다.
메모와 화면이 어긋날 때의 처리는 규칙 2.1가 정합니다.
보이는 레이어만 구현 목록에 올립니다.
구현 목록 — 12:340 상품 목록_전체
12:343 필터 바
12:350 상품 표
숨긴 레이어와 메모를 분류해 상태 목록을 함께 만듭니다.
상태 목록 — 12:340 상품 목록_전체
12:343 필터 바 보임 - -
12:350 상품 표 보임 - -
12:358 선택 칩 숨김 상태 필터를 하나 이상 고르면 표시
12:360 초기화 버튼 숨김 상태 필터를 하나 이상 고르면 표시
12:371 안내 배너 숨김 미정 조건 없음, 질문
12:395 메모 - 요구 조건 최초 진입 시 등록일 최신순
12:401 이력 9/10 - 요구 조건 숨긴 상품은 목록 끝으로