1. 들어가며
얼마 전, Figma MCP를 활용해 UI 개발 속도를 크게 높인 회사 사례를 접하면서
“나도 프로젝트에서 한번 써보고 싶다”는 생각을 계속 가지고 있었다.
그러다 마침 프로젝트가 하나 마무리되면서 시간이 생겨, 본격적으로 Figma MCP 기반의 UI 자동화를 실험해보기로 했다.
현재 내가 사용하는 개발 환경은 아래와 같다.
- IDE: Cursor
- AI 모델: Claude Code CLI (Opus 4.5)
여기서 자연스럽게 한 가지 궁금증이 생겼다.
“Cursor와 Figma MCP를 직접 연동하는 경우와,
Cursor IDE 내부에서 Claude Code CLI + Figma MCP 조합을 사용하는 경우는
실제로 어떤 차이가 있을까?”
두 방식 모두 Figma MCP를 사용한다는 점은 같지만,
IDE·모델·맥락 접근 방식이 서로 완전히 다르기 때문에 결과물도 다를 것이라고 예상했다.
그래서 이번 글에서는 이 두 가지 방식의 차이를 직접 비교해본 테스트 결과를 정리해보려 한다.
2. 어떻게 비교했는가
비교 테스트는 최근 내가 실제 프로젝트에서 만들었던 ‘에디터 설정 패널 UI’를 Figma MCP로 다시 구현해보는 방식으로 진행했다.
테스트한 조합은 두 가지다.
- Cursor IDE + Figma MCP
- Cursor IDE 내부에서 Claude Code CLI(Opus 4.5) + Figma MCP
그리고 아래 네 가지를 집중적으로 확인했다:
- 동일한 Figma를 기반으로 했을 때 UI 결과물이 어떻게 다른지
- 💡프로젝트에 이미 존재하는 컴포넌트를 얼마나 잘 재사용하는지
- 상태/로직을 해석하고 구성하는 능력이 얼마나 차이나는지
- 💡각 방식이 사용한 토큰량은 실제로 어느 정도인지
3. 테스트 결과물 비교
본격적인 결과물 비교에 앞서 내가 만들어야 하는 에디터 설정 패널 UI는 아래와 같았다.

3-1. Cursor IDE + Figma MCP 결과물

3-2. Cursor IDE 내부에서 Claude Code CLI(Opus 4.5) + Figma MCP

여기까지만 보면 두 방식 모두 Figma에 정의된 UI를 꽤 정확하게 재현해냈다.
특히 프로젝트 내부에서 사용하는 스타일 토큰도 적절히 반영된 점은 동일하다!!
그렇다면 코드 구조는 어떨까?
4. 코드 구조 비교
겉으로 봤을 때 UI는 거의 동일하지만 실제 코드를 살펴보면 색상 관련 상태를 어떻게 연결했느냐에서 차이가 보였다.
4-1. Cursor + Figma MCP
<ColorPicker value={COLORS.GRAY['800']} css={colorPickerStyle} />
- ColorPicker에 value만 지정하고, onChange와 같은 핸들러는 없다.
- 사용자가 색을 바꿔도 이 컴포넌트 관점에서는 단순히 현재 색상을 보여주는 UI 요소에 그친다.
즉, UI 뼈대와 모양은 잘 구현되어 있지만, 상태와의 연결은 최소한으로만 되어 있는 상태다.
4-2. Cursor + Claude CLI + Figma MCP
const [titleColor, setTitleColor] = useState(COLORS.GRAY['800']);
<ColorPicker value={titleColor} css={colorPickerStyle} onChange={setTitleColor} />
- 색상 상태를 분리해서 관리한다. 즉, "색상 변경 UI를 그렸다"가 아니라 "이 프로젝트에서 실제로 색상을 바꿀 수 있는 설정 요소다" 라는 의도가 코드에 드러나도록 만들어진 느낌이었다.
그래서 같은 Figma를 기반으로 만들어졌음에도,
- Cursor 쪽 코드는 UI 모양과 구조를 잘 살린 뼈대에 더 가까웠고,
- Claude 쪽 코드는 실제로 동작하는 설정 패널로 바로 이어 붙일 수 있는 코드에 더 가깝다고 느껴졌다.
4-3. 동적 커스텀 필드 추가 요청을 했을 경우
여기서 한 가지가 더 궁금해졌다. Figma에는 정의되어 있지 않은 기능을 추가해달라고 했을 때
- 기존 프로젝트 컴포넌트를 재활용하는지
- 재사용성을 고려해 로직을 구성하는지
- 그리고 동적 필드 UI를 어떻게 설계하는지
를 한번 더 비교해보고 싶었다.
그래서 동일한 Figma 패널에 대해 두 방식 모두에게 "커스텀 필드를 동적으로 추가·삭제할 수 있는 영역을 만들어줘. 전체 값은 CustomField[] 배열로 관리하고, 값이 비어있을 때의 문구도 추가해줘." 와 같은 요구를 추가로 던졌다.
두 결과물 모두 CustomField 타입과 customFields 상태와 추가/삭제/변경 핸들러를 만드는 데에는 성공했지만,
디테일한 구현 방식에서 약간의 차이가 있었다.
4-3-1. Cursor + Figma MCP
interface CustomField { id: string; value: string; }
const [customFields, setCustomFields] = useState<CustomField[]>([]);
const handleAddCustomField = () => {
const newField: CustomField = { id: `field_${Date.now()}`, value: '', };
setCustomFields(prev => [...prev, newField]);
};
const handleRemoveCustomField = (id: string) => {
setCustomFields(prev => prev.filter(field => field.id !== id));
};
const handleChangeCustomFieldValue = (id: string, value: string) => {
setCustomFields(prev => prev.map(field => (field.id === id ? { ...field, value } : field)));
};
UI 쪽을 보면, 기존 디자인 시스템 컴포넌트를 적극적으로 활용하는 쪽으로 구현되었다.
<Flex direction="column" gap={8}>
<Flex css={labelContainerStyle} items="center" justify="space-between">
<Tooltip message="동적으로 커스텀 필드를 추가할 수 있습니다." position="bottomLeft" onlyText>
<span css={labelStyle}>커스텀 필드</span>
</Tooltip>
<ButtonSecondary icon={<PlusOutlined />} size="small" onClick={handleAddCustomField}>필드 추가</ButtonSecondary>
</Flex>
{customFields.length > 0 && (
<Flex css={customFieldListStyle} direction="column" gap={8}>
{customFields.map((field, index) => (
<Flex key={field.id} css={customFieldItemStyle} gap={8} items="center">
<span css={customFieldIndexStyle}>{index + 1}</span>
<TextInput value={field.value} placeholder="값을 입력하세요." css={customFieldInputStyle} onChange={e => handleChangeCustomFieldValue(field.id, e.target.value)} />
<ButtonText css={customFieldDeleteBtnStyle} icon={<CloseOutlined />} size="small" onClick={() => handleRemoveCustomField(field.id)} />
</Flex>
))}
</Flex>
)}
{customFields.length === 0 && <div css={emptyCustomFieldStyle}>추가된 필드가 없습니다.</div>}
</Flex>
여기서는 ButtonSecondary, ButtonText, TextInput, Flex 등 기존에 정의되어있던 내부 공통 컴포넌트를 최대한 재사용했다는 점과 인덱스를 동그란 배지(customFieldIndexStyle)로 보여주고 리스트 전체를 박스로 감싸는 등 UI 완성도에 신경을 많이 썼다는 점이 인상깊었다.
4-3-2. Cursor + Claude CLI + Figma MCP
Claude 의 비지니스 로직은 동일했지만 UI는 조금 다른 방향성을 취했다.
<Flex direction="column" gap={8}>
<Flex css={labelContainerStyle} items="center" justify="space-between">
<span css={labelStyle}>커스텀 필드</span>
<button css={addFieldButtonStyle} type="button" onClick={handleAddCustomField}>
<PlusOutlined />
<span>필드 추가</span>
</button>
</Flex>
{customFields.map(field => (
<Flex key={field.id} gap={8} items="center">
<TextInput value={field.value} placeholder="값을 입력하세요." css={customFieldInputStyle} onChange={e => handleCustomFieldChange(field.id, e.target.value)} />
<button css={deleteFieldButtonStyle} type="button" onClick={() => handleRemoveCustomField(field.id)}>
<DeleteOutlined />
</button>
</Flex>
))}
{customFields.length === 0 && <span css={emptyFieldTextStyle}>추가된 필드가 없습니다.</span>}
</Flex>
여기서는 필드 추가/삭제 버튼을 디자인 시스템 컴포넌트가 아닌, 네이티브 button + Emotion 스타일로 풀어냈고 인덱스 표시, 리스트 박스 등은 과감히 생략하고 다소 심플한 구조로 구현했다.
4-3-3. 커스텀 필드에서 느껴진 차이
같은 요구사항을 던졌을 때:
- Cursor + Figma MCP
→ 이미 있는 컴포넌트들을 적극적으로 재사용하면서
→ Figma처럼 보이는 완성형 UI를 만들어주는 쪽에 강점이 있었다고 느꼈다. - Cursor + Claude CLI + Figma MCP
→ id 생성, 버튼 역할 분리, 상태 관리 등
→ 실제 동작하는 폼 로직과 구조 쪽에 조금 더 신경을 쓴 느낌이었다.
둘 다 요구사항은 잘 만족했지만 어디에 중심을 두고 코드를 작성하는지 보여서 테스트 하는 과정이 재미있었다.
5. 토큰 사용량 비교
5-1. Cursor + Figma MCP


5-2. Cursor + Claude CLI + Figma MCP


6. 그래서 어떤 조합으로 사용할 것인가?
어떤 방식이 더 좋다고 단정하기는 어려웠고, 효과적으로 활용하려면 더 연구와 경험이 필요하다고 느꼈다.
일단 UI 초안 단계에서는 토큰 낭비를 줄이기 위해 아토믹 컴포넌트 단위로 빠르게 스케치를 뽑는 용도로 Cursor + Figma MCP를 적극적으로 사용할 것 같다.
그 이후 로직 연결이나 실제 기능 구현 단계에서는 기존 프로젝트 맥락을 잘 따라오는 Cursor + Claude CLI 조합을 활용하는 방식이 가장 현실적인 흐름이라고 생각한다.
'개발회고📚' 카테고리의 다른 글
| 귀찮지만 중요한 반복작업을 AI와 함께 자동화해보자! (w. Cursor AI) (2) | 2025.08.29 |
|---|---|
| 고민 많은 3년차 프론트엔드 개발자의 테스트 코드 도입 과정 (feat. 더이상 미룰 수 없다.) (4) | 2025.08.01 |
| 2022년, 지난 날의 회고 (0) | 2023.02.12 |
| [패스트캠퍼스] Rubber duck debugging : 두 번째 (3) | 2021.08.06 |