AI가 폰을 조종하는 속도를 10배 올렸다
"Rabby에서 5달러 브릿지 해봐."
AI가 폰을 잡더니 Bridge 화면을 열고, 금액을 넣고, 견적이 뜰 때까지 기다린 뒤 확인을 누르고, 생체인증을 취소하고, 비밀번호를 치고, 최종 확인까지 눌렀다. MCP 호출 2번으로 끝났다.
일주일 전만 해도 같은 작업에 호출이 20번 넘게 필요했다. React Native 앱에선 시작조차 못했다.
뭐가 바뀌었나
가장 큰 변화는 도구 6개를 mobile_do 하나로 합친 것이다. 화면 읽기, 탭, 타이핑, 스와이프, 스크린샷을 전부 하나의 도구로 처리한다. 액션 없이 호출하면 지금 화면에 뭐가 있는지 알려주고, 액션을 넘기면 실행한 뒤 바뀐 화면을 돌려준다.
mobile_do(actions: ["tap TEXT:Bridge", "wait 2000", "type 5", "tap BUTTON:Confirm"])> tapped TEXT:Bridge
> typed "5"
> tapped BUTTON:Confirm
---
TEXT:Authentication required
BUTTON:Cancel액션 4개를 한 번에 실행하고, 마지막 화면 상태가 바로 돌아온다.
좌표도 버렸다. 이전에는 tap 541 2316처럼 픽셀 좌표를 넘겨야 했는데, 키보드가 올라오거나 모달이 뜨면 좌표가 수백 픽셀씩 밀려서 엉뚱한 곳을 누르는 일이 잦았다. 지금은 tap BUTTON:Confirm처럼 요소의 이름으로 탭한다. 탭할 때마다 화면을 새로 읽어서 현재 위치를 찾기 때문에, 레이아웃이 바뀌어도 항상 올바른 곳을 누른다.
같은 이름이 화면에 여러 개 있으면 @N으로 구분한다. 비밀번호 바텀시트에 Confirm 버튼이 2개일 때, 바깥쪽은 BUTTON:Confirm@1, 비밀번호 확인용은 BUTTON:Confirm@2가 된다. 이 번호는 화면 구조가 같은 한 항상 일관된다.
React Native 앱이 된다
D'CENT 지갑은 React Native로 만들어졌다. 기존 방식(uiautomator dump)은 이 앱에서 영원히 멈췄다. 캐러셀 같은 애니메이션이 100ms마다 화면 변경 이벤트를 발생시키는데, "화면이 안정됐는지" 확인하는 로직이 이 이벤트 때문에 영원히 통과되지 않는다.
우리는 이 안정 체크를 건너뛰는 7KB짜리 프로그램(DEX)을 만들어서 디바이스에서 직접 실행하게 했다. 기존 방식을 먼저 시도하고, 실패하면 이 프로그램으로 자동 전환된다. 패키지에 포함돼 있어서 첫 실행 때 알아서 설치되고, 사용자가 설정할 건 아무것도 없다.
실제로 해본 것
Rabby Bridge — MCP 2콜로 $5 브릿지:
1콜로 홈에서 Bridge까지 이동, 금액 입력, 견적 대기, 확인까지 처리했다(액션 6개). 2콜로 생체인증을 취소하고, 비밀번호를 입력하고, 최종 확인을 눌렀다(액션 6개). Polygon에서 Base로 $5 브릿지 완료.
D'CENT Swap — MCP 1콜, 액션 13개:
Swap 화면 진입 → 토큰 선택 → 금액 입력 → 견적 대기 → Swap 탭 → 가격 충격 경고 통과 → 약관 동의 → 확인 → 6자리 PIN 입력. 1 USDC가 10.29 POL로 교환됐다. 일주일 전에는 이 앱을 열지도 못했다.
DFS 탐색 — MCP 1콜로 화면 4개 순회 + 스크린샷 4장:
["tap TEXT:Security", "wait 1000", "screenshot /path/021.png",
"press BACK", "wait 500",
"tap TEXT:Notifications", "wait 1000", "screenshot /path/022.png",
"press BACK"]화면을 하나씩 방문하면서 스크린샷을 찍고 뒤로 돌아오는 걸 한 번의 호출로 처리한다. 앱 전체를 탐색해서 스크린샷 카탈로그를 만드는 작업이 이전보다 몇 배 빨라졌다.
| 시나리오 | 이전 | 이후 |
|---|---|---|
| 버튼 하나 탭 | 4콜 | 1콜 |
| 화면 4개 DFS | 24콜 이상 | 1콜 |
| Rabby Bridge E2E | ~20콜 | 2콜 |
| D'CENT Swap E2E | 불가능 | 1콜 |
전이 테이블
앱을 한 번 탐색하고 나면 화면 + 행동 → 다음 화면 맵이 생긴다. 우리는 이걸 TRANSITIONS.md라고 부른다. 이 맵이 있으면 전체 플로우를 미리 계획해서 한 번에 실행할 수 있다. 중간에 화면을 확인할 필요가 없어진다.
Bridge → tap BUTTON:Confirm → 생체인증 프롬프트
생체인증 → tap BUTTON:Cancel → 비밀번호 시트
비밀번호 → type {password} + tap BUTTON:Confirm@2 → 완료탐색 단계에서 mobile_do가 매 액션마다 바뀐 화면을 돌려주기 때문에, 전이 맵은 탐색하면서 자연스럽게 만들어진다.
한계
텍스트 매칭은 실시간으로 바뀌는 요소(매초 변하는 가격 등)에 약하다. 탭할 때마다 화면을 새로 읽기 때문에 단일 탭의 속도 자체는 이전 좌표 방식과 비슷하다. 다만 안정성은 비교할 수 없이 높다. 접근성 트리를 읽는 방식이라 라벨 없는 아이콘이나 색상으로만 표현되는 상태(회색 비활성화 등)는 인식하지 못한다.
코드
- mobile-mcp 포크 — 패치된 MCP 서버
- llm-mobile-testing — 탐색 방법론. 이 README를 LLM에 주면 알아서 탐색을 시작한다.