feat: rn-mcp CLI with Snapshot + Refs pattern#125
Merged
Conversation
agent-browser 스타일의 Snapshot + Refs 패턴을 React Native에 적용한 CLI 도구. AI 에이전트(Claude Code, Codex 등)가 셸에서 직접 앱을 제어할 수 있도록 함. 주요 기능: - snapshot -i: Fiber 트리에서 interactive 요소를 @e1, @e2 refs로 반환 - tap/type/swipe: refs로 요소 조작 (좌표 자동 변환, iOS orientation 자동 처리) - assert: 텍스트/가시성 검증 (exit code 0/1) - init-agent: AGENTS.md/CLAUDE.md에 CLI 가이드 자동 추가 (한영 지원) - query: 셀렉터 직접 사용 가능 구현: - WebSocket extension client로 기존 MCP 서버에 연결 (별도 서버 불필요) - ~/.rn-mcp/session.json에 refs 매핑 저장 (CLI 호출 간 상태 공유) - idb/adb 직접 실행 (기존 유틸 재사용) - bin: rn-mcp → dist/cli.js (기존 react-native-mcp-server와 같은 패키지) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CI에서 기존 YAML E2E 후 CLI smoke test를 실행: - MCP 서버 백그라운드 시작 → 앱 연결 대기 - snapshot -i, tap @ref, assert text, query, init-agent 검증 - iOS/Android 양쪽 워크플로우에 추가 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- eval 코드 빌더: 인라인 중복 → buildQuerySelectorEvalCode 등 기존 export 재사용 - buildEvalCall() 헬퍼: __REACT_NATIVE_MCP__ 가드 패턴 통합 - INTERACTIVE_TYPES: take-snapshot + ref-map 중복 → shared/interactive-types.ts로 추출 - cmdTap: loadSession() 3회 호출 → 1회로 수정 (디스크 읽기 3→1) - cmdScreenshot: Android screencap 이중 실행 + 죽은 dynamic import 제거 - assert text: JSON.stringify false-positive → :text() 셀렉터 기반으로 수정 - cmdQuery: 요소 포맷 중복 → formatElementLine() 헬퍼 추출 - ws-client: WebSocket close 핸들러 추가 (연결 끊김 시 pending reject) - 죽은 코드 제거: evalAssertText, 미사용 existsSync import - 인라인 상수 → 모듈 레벨 (ANDROID_KEYCODES, VALID_DIRECTIONS) - cmdInitAgent: TOCTOU (existsSync→readFileSync) → try/catch로 수정 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- MCP 서버 백그라운드 시작 시 stdin을 /dev/null로 리다이렉트 (stdin EOF로 인한 즉시 종료 방지)
- resolveUdid/resolveSerial에 MCP 내부 deviceId("ios-1") 대신 undefined 전달 (자동 감지)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
MCP 서버는 stdio transport를 사용하므로 stdin EOF 시 즉시 종료됨. sleep infinity를 파이프로 연결하여 stdin을 열어둔 상태로 유지. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
COUNT_REF 추출 시 grep 매칭 실패 → pipefail → 스크립트 종료. || true 추가로 grep 실패를 허용 (빈 결과 시 셀렉터 fallback 사용). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
cd $(mktemp -d) 후 상대 경로가 깨지는 문제. SCRIPT_DIR 기반 절대 경로로 수정. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Android SDK platform-tools/emulator PATH를 명시적으로 추가 - adb start-server를 에뮬레이터 부팅 전에 실행 (adb daemon 연결 실패 방지) - emulator-boot-timeout: 600 명시적 설정 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
libgl1-mesa-dri 삭제 시 libgl1, libglx0, libglx-mesa0이 연쇄 제거되어 에뮬레이터가 그래픽 라이브러리를 찾지 못해 부팅 무한 대기 발생. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
이전 libgl1-mesa-dri 삭제 환경에서 생성된 깨진 AVD 스냅샷 무효화. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
sleep infinity 파이프 방식은 cleanup 시 프로세스 그룹이 남아서 타임아웃. FIFO(named pipe) + fd 3으로 stdin을 열어두고, cleanup 시 fd 닫기 → EOF → 정상 종료. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
FIFO 방식은 macOS CI에서 exec 3>fifo 블로킹 문제 발생. tail -f /dev/null | node 방식으로 단순화: - tail이 stdin을 영구히 열어둠 - node kill → tail broken pipe → 자동 종료 - macOS/Linux 모두 동작 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
tail -f /dev/null이 node kill 후에도 살아남아 5분 타임아웃 발생. 서브셸로 감싸고 pkill -P로 자식 프로세스까지 확실히 종료. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
pkill -P로 자식 kill 후에도 tail -f /dev/null이 남아서 emulator-runner가 script 종료를 못 함 → 1시간 타임아웃. pkill -f "tail -f /dev/null"로 잔여 프로세스까지 확실히 정리. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- en/mcp/cli.md, ko/mcp/cli.md 추가 - _meta.json 사이드바에 "rn-mcp CLI (Snapshot + Refs)" 항목 추가 - 워크플로우, 명령어 레퍼런스, refs 시스템, 예시 포함 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- snapshot --max-depth 기본값(30) 명시 - swipe --dist 단위를 dp로 명시 (JSDoc px→dp 수정 포함) - 전역 옵션에 -h/--help, -v/--version 추가 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
rn-mcp)init-agent명령으로 AGENTS.md/CLAUDE.md에 CLI 가이드 자동 추가 (한영 지원)주요 명령어
아키텍처
~/.rn-mcp/session.json에 refs 매핑 저장 (CLI 호출 간 상태 공유)bin: rn-mcp → dist/cli.js(기존 패키지에 entry point 추가)파일 구조
src/cli.tssrc/cli/ws-client.tssrc/cli/session.ts~/.rn-mcp/session.json세션 관리src/cli/ref-map.tssrc/cli/commands.tssrc/cli/agent-guide.tssrc/shared/interactive-types.tsdocs/cli-spec.mdCI 변경
test.yml: CLI smoke test + init-agent 통합 테스트 추가e2e-ios.yml: YAML E2E 후 CLI smoke test 실행e2e-android.yml: YAML E2E 후 CLI smoke test 실행 + adb PATH 설정 + libgl1-mesa-dri 삭제 제거cli-smoke.sh: 10단계 CLI 통합 테스트 (status, snapshot, tap, assert, query, init-agent)코드 리뷰 반영 (/simplify)
buildQuerySelectorEvalCode등 기존 export 재사용INTERACTIVE_TYPES중복 →shared/interactive-types.ts로 추출assert textfalse-positive 수정 →:text()셀렉터 기반loadSession()3회 호출 → 1회로Test plan
🤖 Generated with Claude Code