3-3. 토큰 최적화와 안정성 2026-03-05 ~ 03-16

토큰 최적화: electron-mcp-server와 같은 교훈

electron-mcp-server의 rc.5에서 토큰 최적화의 중요성을 뼈저리게 느꼈다. 같은 날(3월 5일), react-native-mcp에도 같은 전략을 적용했다.

컴팩트 텍스트 출력 rc.10

모든 트리 구조 응답을 JSON에서 인덴트 텍스트로 변환했다.

take_snapshot 토큰 절감: -90%

// Before (JSON)
{"type":"View","props":{"style":{"flex":1}},"children":[{"type":"Text","props":{"children":"안녕하세요"}}, ...]}

// After (인덴트 텍스트)
View flex:1
  Text "안녕하세요"
  Button [ref=e1] title="로그인"
    Text "로그인"

describe_ui 토큰 절감: -78%

query_selector 토큰 절감: -70%

React Native 특유의 최적화

웹과 다르게 React Native에는 accessibilityLabel, testID, nativeID 같은 RN 전용 props가 있다. 컴팩트 출력에서 이런 props를 우선적으로 표시하고, 스타일 같은 장황한 정보는 생략한다.

안정성: WebSocket 크래시 방어 rc.11

문제 발견

MCP 서버를 강제 종료(Ctrl+C)하면 React Native 앱이 같이 크래시되는 문제가 발견됐다.

원인: MCP 서버가 종료되면 WebSocket 연결이 끊기는데, 런타임에서 이미 닫힌 소켓에 메시지를 보내려고 하면 네이티브 단에서 예외가 발생한다. JS 레벨의 try/catch로는 잡히지 않는 네이티브 크래시였다.

해결: websocket-guard

websocket-guard.ts에서 WebSocket의 send, close 메서드를 래핑했다:

  1. 전송 전에 readyState를 확인
  2. 전송 실패 시 에러를 삼키고 재연결 대기열에 넣기
  3. 런타임의 모든 WebSocket 사용처에서 guard를 통해서만 전송

이 패치 후로 MCP 서버를 아무 때나 종료해도 앱은 살아 있고, 서버를 다시 시작하면 자동 재연결된다.

서버 Instructions: AI 가이드 rc.12 ~ rc.14

MCP 프로토콜에는 instructions라는 필드가 있다. 서버가 자기 자신을 AI에게 소개하는 텍스트이다.

처음에는 간단한 설명만 넣었는데, AI가 도구를 비효율적으로 쓰는 패턴을 발견했다:

  1. 매번 take_screenshot을 먼저 호출 → 이미지 토큰 낭비
  2. 좌표계를 모르고 tap → 엉뚱한 곳 클릭
  3. 간단한 확인에도 무거운 도구 사용

rc.12: 도구 설명 개선

8개 주요 도구의 설명을 다시 썼다. "이 도구는 무엇을 한다"에서 "이 상황에서 이 도구를 써라"로 바꿨다.

rc.13: 도구 우선순위 테이블

AI가 도구를 선택할 때 참고할 수 있는 우선순위 가이드를 instructions에 추가했다:

도구 우선순위:
1. describe_ui (가벼움, 텍스트) → 화면 구조 파악
2. query_selector (가벼움, 텍스트) → 특정 요소 찾기
3. take_snapshot (중간, 텍스트) → 전체 트리 필요 시
4. take_screenshot (무거움, 이미지) → 시각적 확인 필요 시만

rc.14: iOS orientation 가이드

iOS 시뮬레이터의 좌표계 문제 때문에, instructions 맨 앞에 "iOS에서는 먼저 get_orientation을 확인하라"는 안내를 넣었다. AI가 이걸 읽고 먼저 orientation을 확인한 뒤 좌표를 계산하게 된다.

TypeScript Strict Null rc.12

rc.12에서 TypeScript strict null check를 활성화했다. 기존 코드에서 null | undefined 관련 타입 에러가 대거 발견됐다.

대부분은 옵셔널 체이닝(?.)이나 널 병합(??)으로 간단히 수정됐지만, Fiber 탐색 코드에서 fiber.child가 null인 경우를 제대로 처리하지 않은 곳이 몇 군데 있어서 실제 런타임 버그도 잡았다.

모노레포 init 커맨드 02-28

npx -y @ohah/react-native-mcp-server init

이 명령어 하나로 설정이 완료되도록 만들었다:

  1. babel.config.js에 프리셋 추가
  2. MCP 클라이언트 설정 파일 생성 (.cursor/mcp.json 등)
  3. 필요한 네이티브 도구(adb/idb) 확인

단일 레포와 모노레포 모두 지원한다. 모노레포인 경우 package.json의 워크스페이스 설정을 읽어서 적절한 위치에 설정 파일을 생성한다.

6주의 결과

항목수치
총 커밋845
RC 릴리즈14회
MCP 도구48개
런타임 모듈20+
VS Code 확장1개
지원 AI 클라이언트Cursor, Claude Code, Claude Desktop, Windsurf, GitHub Copilot, Antigravity
1줄 요약

토큰을 90% 절감하고, WebSocket 크래시를 방어하고, AI 가이드를 정교하게 다듬어서 실사용 가능한 수준의 React Native MCP 서버를 완성했다.