Kiro에게 그림 그리는 법 가르치기: Gemini의 Interactions API와 MCP를 기반으로 구축된 상태 유지 이미지 편집 기술
요약
Google의 Gemini Interactions API와 MCP를 활용하여 Kiro 에이전트가 상태를 유지하며 이미지를 편집할 수 있는 기술을 소개합니다. 기존의 상태 비저장(stateless) 방식과 달리, interaction_id를 통해 시각적 컨텍스트를 유지하며 연속적인 이미지 수정이 가능합니다.
핵심 포인트
- Gemini Interactions API를 통한 시각적 컨텍스트 유지
- MCP 서버와 Kiro 스킬을 결합한 에이전트 구현
- interaction_id 체이닝을 통한 연속적인 이미지 편집 가능
- 프롬프트 재입력 없이 자연스러운 이미지 수정 워크플로우
요약 (TL;DR): nb2lite-skill-kiro는 Google의 gemini-3.1-flash-lite-image 모델 (NB2Lite)을 아주 작은 FastMCP 서버로 래핑(wrap)하여 Kiro 스킬로 패키징합니다. Kiro에 "사이버펑크 주방 이미지를 생성해줘"라고 입력하면, 그냥... 해냅니다. 그다음 "네온 라멘 간판을 추가해줘"라고 말하면, 전체 장면을 다시 프롬프트로 입력할 필요 없이 동일한 이미지를 편집합니다. 아, 그리고 이 글의 커버 이미지요? 이 글의 주제가 되는 바로 그 도구로 생성했습니다. 끝까지 제대로 된 도그푸딩(dogfooding)이죠. 자세한 내용은 마지막에 설명하겠습니다.
배경: 왜 또 다른 이미지 도구가 필요한가?
대부분의 이미지 생성 워크플로우는 상태 비저장(stateless) 방식입니다. 프롬프트를 보내면 픽셀을 돌려받고, 모델은 즉시 모든 것을 잊어버립니다. 결과를 수정하고 싶나요? 그러면 전체 장면을 다시 묘사해야 하며, 캐릭터, 조명, 구도가 이 과정을 거치며 유지되기를 기도해야 합니다. (해설: 유지되지 않습니다.)
Google의 NB2Lite — gemini-3.1-flash-lite-image의 친근한 별명 — 는 다른 접근 방식을 취합니다. 이는 2초 미만의 생성 속도, 25개 이상의 언어에서 안정적인 텍스트 렌더링, 그리고 핵심 기능인 상태 유지 Interactions API (stateful Interactions API) 지원을 갖춘 고효율 이미지 모델입니다. 이 API를 통해 모델이 서버 측에서 시각적 컨텍스트를 유지하는 동안 여러 턴에 걸쳐 이미지를 반복적으로 수정할 수 있습니다.
이 저장소(repo)는 해당 기능을 Kiro에 결합하여, 여러분의 코딩 에이전트가 세션의 자연스러운 일부로서 이미지를 생성하고 반복적으로 개선할 수 있도록 합니다. 이 저장소는 한 저장소 내에 두 가지 형태로 제공됩니다:
- 정확히 4개의 도구를 노출하는 Model Context Protocol (MCP) 서버 (
nb2lite-agent,server.py에 있는 단일 파일 FastMCP 앱). - Kiro에게 해당 도구들을 언제 그리고 어떻게 잘 사용할지 가르치는 Kiro 스킬 (
nb2lite-image).
Interactions API: 기억력이 있는 이미지
Interactions API는 Gemini의 상태 유지(stateful) 엔드포인트입니다. 핵심 루프는 다음과 같습니다:
- 프롬프트와
store=True를 포함하여client.interactions.create(...)를 호출합니다. - 응답에는 Google 서버에 저장되어 해당 턴의 시각적 컨텍스트(visual context)를 제어할 수 있는 핸들인 **
interaction_id**가 포함됩니다. - 다음 호출 시
previous_interaction_id를 전달하면, 모델은 캐릭터, 스타일, 조명 및 픽셀 연속성(pixel continuity)을 유지하면서 _기존 캔버스(existing canvas)_를 편집합니다.
따라서 다음과 같은 방식(상태 비저장(stateless) 방식의 고충) 대신:
"새벽녘 숲속의 수채화풍 여우, 안개, 부드러운 빛, 빨간 목도리를 착용함, 왼쪽에 자작나무 세 그루, 그리고 이제는 또한 랜턴을 들고 있음"
...이렇게 작성하면 됩니다:
"발에 랜턴을 추가해줘."
그게 전부입니다. 저장된 컨텍스트가 나머지를 처리합니다.
서버가 대신 처리해 주는 몇 가지 실무적인 세부 사항은 다음과 같습니다:
- 매 턴마다 새로운 interaction ID가 반환됩니다. 가장 최신 ID를 체이닝(chain)하십시오. 오래된 ID로 편집하면 세션이 이전 상태에서 조용히 분기(fork)됩니다 (이를 수동으로 구현할 경우 발생할 수 있는 미묘하고 매우 짜증 나는 버그입니다).
- 종횡비(Aspect ratio)는 생성 시점에 결정되며 (
1:1,16:9,9:16,4:3,3:4) 상태 유지 편집 시 _상속_됩니다. 세션 중간에 종횡비를 변경하면 픽셀 연속성이 저하되므로, 편집 도구는 의도적으로 변경을 허용하지 않습니다. - 사고 수준(Thinking levels):
low(기본값, 빠른 초안) 또는high(복잡한 렌더링, 정확한 텍스트 레이아웃, 캐릭터 구도). 일반적인 API 명세에는minimal과medium도 나열되어 있지만, 실제 API에서는 이 모델에 대해 해당 값들을 사용하면 HTTP 400 오류를 반환하며 거부합니다. 서버가 여러분이 이를 직접 겪으며 깨닫지 않도록 미리 막아주는 셈입니다.
MCP란 무엇인가, 1분 요약
**Model Context Protocol (MCP)**는 AI 어시스턴트를 도구 및 데이터와 연결하기 위한 개방형 표준입니다. MCP 이전에는 모델에 특정 서비스에 대한 액세스 권한을 주려면 각 어시스턴트마다 맞춤형 통합(bespoke integration) 코드를 작성해야 했습니다. 즉, N개의 어시스턴트 × M개의 서비스만큼 모든 사람이 동일한 배관 작업을 새로 만들어야 했습니다. MCP는 이를 하나로 통합합니다. 도구 제작자가 타입이 지정된 도구(typed tools)를 노출하는 하나의 MCP 서버를 작성하면, MCP를 지원하는 모든 클라이언트(Kiro, Claude Code, Claude Desktop 및 계속 늘어나고 있는 다른 클라이언트들)가 클라이언트별 연결 코드(glue code) 없이도 해당 도구들을 발견하고 호출할 수 있습니다.
MCP 서버는 일반적으로 stdio를 통해 JSON-RPC를 사용하는 작은 로컬 프로세스입니다. 클라이언트가 이를 실행하고 "어떤 도구들을 가지고 있나요?"라고 물으면, 그 이후부터 모델은 해당 도구들을 함수처럼 호출할 수 있습니다.
nb2lite-agent 서버는 정확히 네 가지 도구를 노출합니다:
| 도구 (Tool) | 기능 |
|---|---|
generate_image | 텍스트 → 1k 이미지 생성. 로컬에 저장하며, 경로와 상호작용 ID (interaction ID)를 반환함. |
| ... |
이미지는 gen_<timestamp>_<uuid8>.jpg (또는 edit_/edit_local_ 접두사가 붙은 형태)로 디스크에 저장됩니다. UUID 접미사는 동시에 진행되는 생성 작업들이 서로를 덮어쓰지 않도록 방지합니다. 오류는 프로토콜 오류 대신 🔴 ... 텍스트 문자열로 반환되므로, 에이전트가 이를 읽고 대응할 수 있습니다.
그렇다면 Kiro의 '스킬 (skill)'이란 무엇인가?
MCP가 '손' (Kiro가 물리적으로 호출할 수 있는 도구들)이라면, **스킬 (skill)**은 '근육 기억 (muscle memory)'입니다. 즉, 마크다운 파일(SKILL.md)과 묶음 리소스(bundled resources)로 구성되며, 이는 Kiro의 컨텍스트(context)에 로드되어 어떤 도구를 어떤 순서로, 어떤 제약 조건 하에 사용할지 등의 워크플로우(workflow)를 가르칩니다.
Kiro 스킬은 프로젝트 내부의 .kiro/skills/<skill-name>/ 경로에 존재합니다. Kiro가 스킬의 설명과 일치하는 트리거 문구(trigger phrase)를 감지하면, 자동으로 스킬을 활성화하고 그 안에 인코딩된 가이드를 사용하기 시작합니다.
nb2lite-image의 경우, 스킬에는 다음과 같은 사항들이 인코딩되어 있습니다:
- 설정 문제를 진단할 때는 가장 먼저
get_help를 호출할 것 — API 키가 누락되면 다른 어떤 것도 작동하지 않습니다. - 편집 프롬프트(edit prompts)를 **점진적 (incremental)**으로 유지할 것: 장면이 아니라 변경 사항을 설명하세요.
- 항상 최신 (latest) 상호작용 ID (interaction ID)를 체이닝(chain)할 것.
- 생성 작업은 비용이 발생함 — 관련 편집 작업들을 배치(batch)로 처리하고, 초안 작업 시에는
thinking_level: low를 권장함.
또한 이 스킬은 MCP 서버 자체(mcp/server.py), 요구 사항(requirements), 설치 스크립트, 그리고 Interactions API 개발자 가이드의 벤더드 복사본(vendored copy)을 함께 묶어 제공하므로 자급자족(self-contained)이 가능합니다. 즉, 스킬을 설치하면 서버를 구축하는 데 필요한 모든 것을 갖추게 됩니다.
설치하기: "그냥 바로 작동했으면 좋겠어" 버전
세 가지가 필요합니다: Python 3.10+, Kiro, 그리고 Gemini API key (Google AI Studio에서 무료로 발급 가능)입니다. 아래 경로 중 _하나_를 선택하세요.
경로 A: 클론 및 부트스트랩 (이 리포지토리 사용)
# 1. 코드 가져오기
git clone https://github.com/xbill9/nb2lite-skill-kiro.git
cd nb2lite-skill-kiro
...
정말로 이게 전부입니다. 무언가 잘못된 것 같다면 init.sh를 다시 실행해도 안전합니다.
경로 B: 본인의 프로젝트에 설치하기
리포지토리를 클론한 상태에서 다음을 실행합니다:
make init TARGET=/path/to/your/project ARGS='--output-dir ./images'
이 명령은 스킬을 <project>/.kiro/skills/nb2lite-image/로 복사하고, 해당 프로젝트의 .mcp.json에 nb2lite-agent 항목을 작성합니다. 이미 설정해 두었다면 ~/gemini.key를 재사용합니다. 대상 프로젝트에서 Kiro를 재시작하고 서버를 승인하면 완료됩니다.
경로 C: 수동 등록
직접 연결하는 것을 선호한다면 다음과 같이 하세요:
# 의존성 설치
pip install -r requirements.txt
...
{
"mcpServers": {
"nb2lite-agent": {
...
그 다음 스킬 파일들을 .kiro/skills/nb2lite-image/로 복사하고 Kiro를 재시작하세요.
경로 D: Docker (호스트에는 Docker 외에 아무것도 설치하지 않음)
서버는 xbill9/nb2lite-agent로 배포되어 있습니다. 프로젝트의 .mcp.json에 다음을 추가하세요:
{
"mcpServers": {
"nb2lite-agent": {
...
-v "$PWD:$PWD" -w "$PWD" 마운트가 중요합니다. 서버가 이미지를 디스크에 저장하고 edit_local_image를 위해 로컬 파일을 읽기 때문에, 컨테이너는 호스트와 _동일한 절대 경로_에서 프로젝트를 볼 수 있어야 합니다.
문제 해결 가이드 전체
- MCP 서버가 나타나지 않음 → 프로젝트 디렉토리에서 Kiro를 재시작하세요.
- 도구가
🔴 GEMINI_API_KEY is not set을 반환함 →source set_env.sh를 실행하거나 (또는 키를 export하고) 재시작하세요. - 그 외의 문제 → Kiro에게
get_help를 호출하도록 요청하세요. 현재 활성화된 설정을 보고합니다.
예시: 실제 세션 적용
설치가 완료되면 일반적인 영어로 대화할 수 있습니다. 실제 흐름은 다음과 같습니다:
사용자: _"해질녘 눈 덮인 숲속의 아늑한 오두막을 16:9 비율로 생성해줘."
Kiro 호출:
generate_image(
prompt="A cozy log cabin in a snowy forest at dusk, warm light in the windows",
aspect_ratio="16:9",
...
사용자: "좋아. 굴뚝에서 연기가 피어오르게 해줘."
edit_image(
previous_interaction_id="v1_ChdpRU5...",
edit_prompt="add gentle smoke curling from the chimney",
...
사용자: "이제 밤으로 바꾸고, 하늘에 오로라를 넣어줘."
동일한 도구, 최신 ID를 사용하며 오두막, 나무, 굴뚝 연기는 그대로 유지된 채 하늘만 바뀝니다. 다시 프롬프트를 작성할 필요도, 연속성(continuity)이 깨질까 봐 도박을 할 필요도 없습니다.
모델에서 생성되지 않은 이미지의 경우:
사용자: "./whiteboard-sketch.png 파일을 가져와서 깔끔한 3D 제품 목업(mockup)으로 렌더링해줘."
edit_local_image(
image_path="./whiteboard-sketch.png",
edit_prompt="render this hand-drawn sketch as a high-fidelity 3D product mockup",
...
이 또한 상호작용 ID(interaction ID)를 반환하므로, 후속 수정 작업은 edit_image로 전환되어 그 시점부터 상태 유지(stateful) 방식으로 진행됩니다.
Dogfooding: 커버 이미지에 대하여 🐕🍖
이 용어가 생소하시다면: **"자신의 개 사료를 먹는다(eating your own dog food)"**는 것은 제품을 단순히 데모용으로 보여주는 것이 아니라, 실제 업무에 자신의 제품을 직접 사용하는 것을 의미합니다. 이는 "이건 작동할 거야"와 "나는 매일 이것으로 작업해"의 차이입니다. 도구가 사용자들에게 충분히 훌륭하다면, 개발자 자신에게도 충분히 훌륭해야 합니다. 만약 그렇지 않다면, 개발자가 가장 먼저 불편함을 느끼고 이를 수정하게 될 것입니다.
이 저장소(repo)는 모든 계층에서 자체적으로 Dogfooding을 수행합니다:
- 스킬(skill)이 자체 저장소 내에서 활성화되어 있습니다 — 클론(clone)된 환경에서 Kiro를 열면
nb2lite-image스킬과nb2lite-agent서버가 이미 연결되어 있어, 모든 개발 세션이 통합 테스트(integration test) 역할을 겸합니다. - 통합 테스트(
make test)는 실제 API를 대상으로 최종 사용자가 사용하는 것과 동일한 네 가지 MCP 도구를 구동합니다. - 그리고 이제, 이 기사의 커버 이미지는 이 저장소 내의 Kiro 세션에서, 기사가 설명하는 바로 그 스킬을 통해 생성되었습니다. 단 한 번의 도구 호출, 단 한 번의 시도로 리터칭 없이 완성되었습니다:
generate_image(
prompt="'nb2lite-image'라는 이름의 개발자 도구를 위한 세련된 다크 테마 테크 커버 이미지. 장면은 미래지향적인 AI 워크스페이스를 보여줍니다: 빛나는 "
...
(해당 출력물은 영수증을 포함하여 cover-image.jpg로 리포지토리에 커밋되었습니다.)
주목할 만한 점:
- 텍스트가 정확하게 렌더링되었습니다. 상단의 "nb2lite-image"와 하단의 전체 태그라인이 선명하고 오타 없이 출력되었습니다. 이것이 바로 텍스트가 많은 레이아웃에서
thinking_level: "high"를 설정했을 때 얻을 수 있는 결과입니다. - Kiro가 말 그대로 그림 속에 있습니다. 중앙 무대의 빛나는 "K" 로고는 단순한 장식이 아닙니다. 이는 생성을 조율하는 실제 에이전트(Agent)를 나타냅니다. 이 스킬은 자신의 아키텍처(Architecture)를 설명하는 이미지를 생성해낸 것입니다.
- 듀얼 모니터 구성이 전체 이야기를 전달합니다. 왼쪽에는 코드 에디터(Code editor), 오른쪽에는 AI가 생성한 예술 작품, 그리고 그 둘을 연결하는 Kiro — 이것이 바로 이 기사에서 설명하는 워크플로우(Workflow)를 한 프레임에 시각화한 모습입니다.
- 만약 강조 색상을 바꾸고 싶다면, 저는 다시 생성하지 않을 것입니다. 대신 해당 상호작용 ID(Interaction ID)를 사용하여
edit_image를 호출하고 "파란색 강조 색상을 보라색으로 바꿔줘"라고 말할 것입니다. 그것이 바로 핵심입니다.
도그푸딩(Dogfooding, 자사 제품 직접 사용)은 가장 저렴한 신뢰 구축 방법입니다. 엄선된 갤러리도, "결과는 다를 수 있음"이라는 작은 글씨의 면책 조항도 없습니다. 도구의 실제 출력물은 말 그대로 당신이 이 기사를 열었을 때 처음 본 것입니다. 만약 스킬이 글자를 틀렸거나 레이아웃을 망가뜨렸다면, 당신은 지금 바로 그 증거를 보고 있었을 것입니다. 대신, 이 기사는 헤더에 자체적인 증거를 포함한 채 배포됩니다.
링크
링크
- Repo: github.com/xbill9/nb2lite-skill-kiro (Apache-2.0)
- Docker image: hub.docker.com/r/xbill9/nb2lite-agent
- Interactions API reference: ai.google.dev/api/interactions-api
- Model Context Protocol: modelcontextprotocol.io
이것은 Anthropic이나 Google과 제휴하거나 보증하는 것이 아닌, 서드파티 커뮤니티 프로젝트입니다. 사용자의 Gemini API 키를 가져오십시오. 그리고 생성(generations)은 비용이 발생한다는 점을 기억하고, 초안은 low로 작성하고 중요한 순간에만 high를 저장하십시오.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기