この記事について
| 項目 | 内容 |
|---|---|
| 対象読者 | モバイルアプリのE2Eテストに興味がある人、生成AIを活用したい人 |
| 前提知識 | 以前の記事(Playwright Agents編)を読んでいるとより理解しやすい |
| 検証環境 | macOS 15.7 / Xcode 16.4 / adb 1.0.41 / Node.js 24.x / mobile-mcp 0.0.38 / Kiro CLI 1.22.0 |
✅ この記事を読むと
- mobile-mcpの導入方法とAIエージェントからiOS/Androidを操作する方法がわかる
- AIによるモバイルアプリのテスト計画・テストコード自動生成を試せるようになる
※ 本記事ではKiro CLIを使用していますが、mobile-mcpはMCP対応のあらゆるAIエージェント(Claude Desktop、Cursor、VS Code Copilotなど)で利用可能です。
📱 以前の記事のおさらい
以前の記事では、Playwright AgentsをKiro CLIで動かす方法を紹介しました。
Playwright Agentsは、AIエージェントがブラウザを操作してE2Eテストを実行できるツールです。
- 🌐 Webページを自動探索
- 📝 テスト計画を自動生成
- 🧪 Playwrightのテストコードを生成
- 🩹 失敗したテストを自動修復
「これ、モバイルアプリでもできたら最高じゃない?」
そう思って調べてみたら、ありました。mobile-mcpです!
🤖 mobile-mcpとは
mobile-mcpは、AIエージェントがiOS/Androidのシミュレータ・エミュレータ・実機を操作できるようにするMCPサーバーです。
📺 動作イメージはGitHubのデモ動画を参照してください。
主な機能
| カテゴリ | ツール | 説明 |
|---|---|---|
| デバイス管理 | mobile_list_available_devices |
利用可能なデバイス一覧 |
mobile_get_screen_size |
画面サイズ取得 | |
| アプリ管理 | mobile_launch_app |
アプリ起動 |
mobile_terminate_app |
アプリ終了 | |
| 画面操作 | mobile_take_screenshot |
スクリーンショット |
mobile_list_elements_on_screen |
UI要素一覧取得 | |
mobile_click_on_screen_at_coordinates |
座標タップ | |
mobile_swipe_on_screen |
スワイプ | |
| 入力 | mobile_type_keys |
テキスト入力 |
mobile_press_button |
ボタン押下(HOME, BACKなど) |
iOS/Androidのシミュレータ・エミュレータ・実機すべてに対応しています。
⚙️ セットアップ
前提条件
mobile-mcpを使うには、以下のツールが必要です。
| ツール | 用途 | インストール方法 |
|---|---|---|
| Node.js v22+ | MCPサーバー実行 | nodejs.org |
| Xcode Command Line Tools | iOS自動化 | xcode-select --install |
| Android SDK Platform-Tools | Android自動化 | developer.android.com |
iOS固有の準備
1. mobilecliのインストール
mobile-mcpはiOSシミュレータの操作に内部でmobilecliを使用しています。このパッケージはoptionalDependenciesのため、環境によっては自動インストールされないことがあります。
npm install -g @mobilenext/mobilecli@latest
# インストール確認
npx @mobilenext/mobilecli --version
# mobilecli version 0.0.48 のように表示されればOK
mobilecliがインストールされていないと、タップ操作が「成功」と表示されても実際には画面に反映されません。
2. WebDriverAgent(WDA)の事前起動
mobilecliをインストールしても、初回はWDAが起動していないため、タップ操作が効かないことがあります。
mobile-mcpを使う前に、以下のコマンドでWDAを起動しておいてください。
# デバイスIDを確認
npx @mobilenext/mobilecli devices --platform ios --type simulator
# WDAを起動(ダミーのタップを実行)
npx @mobilenext/mobilecli io tap "0,0" --device <device-id>
このコマンドを実行すると、mobilecliがポート13001でWDAを自動起動します。一度起動すれば、シミュレータを再起動するまで有効です。
3. シミュレータの起動
# シミュレータ一覧
xcrun simctl list devices
# シミュレータ起動
xcrun simctl boot "iPhone 16"
open -a Simulator
手動でWDAを起動したい場合(トラブルシューティング用)
git clone --depth 1 https://github.com/appium/WebDriverAgent.git
cd WebDriverAgent
xcodebuild -project WebDriverAgent.xcodeproj \
-scheme WebDriverAgentRunner \
-destination 'platform=iOS Simulator,name=iPhone 16' test
手動起動したWDA(ポート8100)とmobilecliが起動するWDA(ポート13001)は別物です。mobile-mcpはmobilecli経由でWDAを使用するため、手動起動は通常不要です。
Android固有の準備
# エミュレータ一覧
emulator -list-avds
# エミュレータ起動
emulator -avd Pixel_7_API_34
MCPサーバーの設定
お使いのAIエージェントにmobile-mcpを追加します。
Kiro CLIの場合
~/.kiro/settings/mcp.json:
{
"mcpServers": {
"mobile-mcp": {
"command": "npx",
"args": ["-y", "@mobilenext/mobile-mcp@latest"],
"timeout": 60000
}
}
}
Claude Desktop、Cursor、VS Code Copilotなど他のMCP対応ツールでも同様に設定できます。詳細はmobile-mcp Wikiを参照してください。
🎭 専門エージェントの作成
Playwright Agentsと同じ構成で、モバイルテスト用の専門エージェントを作成しました。
| エージェント | 役割 |
|---|---|
mobile-test-planner |
アプリを探索してテスト計画を作成 |
mobile-test-generator |
XCUITest/Espressoコードを生成 |
mobile-test-healer |
失敗したテストを修復 |
エージェント定義ファイル
~/.kiro/agents/mobile-test-planner.json:
{
"name": "mobile-test-planner",
"description": "モバイルアプリの包括的なテスト計画を作成する専門エージェント",
"prompt": "file://./prompts/mobile-test-planner.md",
"mcpServers": {
"mobile-mcp": {
"command": "npx",
"args": ["-y", "@mobilenext/mobile-mcp@latest"],
"timeout": 120000
}
},
"tools": ["*"],
"allowedTools": ["fs_read", "fs_write", "@mobile-mcp"]
}
プロンプトファイル
~/.kiro/agents/prompts/mobile-test-planner.md:
You are an expert mobile app test planner with extensive experience
in iOS and Android quality assurance.
You will:
1. **Connect and Explore**
- Use `mobile_list_available_devices` to find available devices
- Use `mobile_list_elements_on_screen` to explore the current screen
- Use `mobile_click_on_screen_at_coordinates`, `mobile_swipe_on_screen`
to navigate and discover the interface
2. **Analyze User Flows**
- Map out the primary user journeys
- Identify critical paths through the application
3. **Design Comprehensive Scenarios**
- Happy path scenarios
- Edge cases and boundary conditions
- Error handling and validation
4. **Structure Test Plans**
Each scenario must include:
- Clear, descriptive title
- Target platform (iOS/Android/Both)
- Detailed step-by-step instructions with element identifiers
- Expected outcomes
- Success criteria and failure conditions
5. **Create Documentation**
Save your test plan as a markdown file.
mobile-test-generatorとmobile-test-healerも同様の構成で作成します。
~/.kiro/agents/prompts/mobile-test-generator.md:
You are an expert mobile test automation engineer.
You will:
1. **Read Test Plan**
- Read the provided test plan markdown file
- Understand the test scenarios and expected outcomes
2. **Generate Test Code**
- For iOS: Generate XCUITest code in Swift
- For Android: Generate Espresso code in Kotlin
- Use the element identifiers from the test plan
3. **Best Practices**
- Add proper wait conditions (waitForExistence, etc.)
- Include meaningful assertions
- Handle setup and teardown appropriately
- Add comments explaining each test step
4. **Save the Code**
- Save the generated test file to the specified output path
~/.kiro/agents/prompts/mobile-test-healer.md:
You are an expert mobile test debugger and healer.
You will:
1. **Analyze Failed Test**
- Read the failing test code
- Identify the problematic selectors or assertions
2. **Inspect Current UI**
- Use `mobile_list_available_devices` to connect to the device
- Use `mobile_launch_app` to launch the target app
- Use `mobile_list_elements_on_screen` to get the actual UI hierarchy
- Navigate to the relevant screen if needed
3. **Fix the Test**
- Compare expected selectors with actual UI elements
- Update selectors to match the real UI hierarchy
- Add proper wait conditions if missing
4. **Save the Fixed Code**
- Overwrite the original test file with the corrected code
🚀 実際に動かしてみた(iOS編)
テスト対象
iOSシミュレータの設定アプリ(com.apple.Preferences)で、3つのエージェント(Planner → Generator → Healer)のワークフローを検証しました。
Step 1: テスト計画の作成(Planner)
kiro-cli chat --agent mobile-test-planner --no-interactive \
"iOSシミュレータに接続して、設定アプリの「一般」→「情報」画面への
ナビゲーションをテストするテスト計画を作成してください。
テスト計画は $(pwd)/tests/ios/settings-general-about.md に保存してください。"
📋 実行ログ(クリックで展開)
> iOSシミュレータに接続して、設定アプリを探索します。
Running tool mobile_list_available_devices (from mcp server: mobile-mcp)
- Completed in 0.5s
> iPhone 16シミュレータが利用可能です。設定アプリを起動します。
Running tool mobile_launch_app (from mcp server: mobile-mcp)
{ "device": "92103385-3E8D-4992-AA66-62A5617288CA",
"packageName": "com.apple.Preferences" }
- Completed in 0.5s
Running tool mobile_list_elements_on_screen (from mcp server: mobile-mcp)
{ "device": "92103385-3E8D-4992-AA66-62A5617288CA" }
- Completed in 0.4s
> 設定アプリのメイン画面が表示されました。「一般」セルを探します。
Running tool mobile_click_on_screen_at_coordinates (from mcp server: mobile-mcp)
{ "device": "92103385-3E8D-4992-AA66-62A5617288CA",
"x": 207, "y": 756 }
- Completed in 1.3s
> 「一般」画面に遷移しました。「情報」セルを探します。
Running tool mobile_list_elements_on_screen (from mcp server: mobile-mcp)
- Completed in 0.5s
Running tool mobile_click_on_screen_at_coordinates (from mcp server: mobile-mcp)
{ "x": 207, "y": 378 }
- Completed in 1.4s
> 「情報」画面が表示されました。テスト計画を作成します。
I'll create the following file: tests/ios/settings-general-about.md
Plannerが実際にシミュレータを操作して画面遷移を確認し、テスト計画を作成してくれました!
📋 生成されたテスト計画
# iOS設定アプリ テスト計画: 一般 → 情報 ナビゲーション
## テスト概要
- **対象アプリ**: 設定 (com.apple.Preferences)
- **対象画面**: 一般 → 情報
- **プラットフォーム**: iOS Simulator (iPhone 16)
## テストケース
### TC-001: 一般画面から情報画面への遷移と戻り
**前提条件**: 設定アプリが起動し、メイン画面が表示されている
| ステップ | 操作 | 要素 | 期待結果 |
|:---:|:---|:---|:---|
| 1 | 「一般」セルをタップ | cells["com.apple.settings.general"] @ (207, 756) | 一般画面に遷移 |
| 2 | 「情報」セルをタップ | cells["About"] @ (207, 378) | 情報画面に遷移 |
| 3 | 戻るボタンをタップ | buttons["一般"] | 一般画面に戻る |
| 4 | 戻るボタンをタップ | buttons["設定"] | メイン画面に戻る |
### TC-002: 情報画面のコンテンツ確認
**前提条件**: 情報画面が表示されている
| 確認項目 | 要素 | 期待結果 |
|:---|:---|:---|
| デバイス名 | staticTexts["NAME_CELL_ID"] | デバイス名が表示される |
| iOSバージョン | staticTexts containing "iOS" | バージョン情報が表示される |
ポイント: 実際のUI要素のidentifierと座標が記録されている!
Step 2: テストコードの生成(Generator)
kiro-cli chat --agent mobile-test-generator --no-interactive \
"$(pwd)/tests/ios/settings-general-about.md のテスト計画に基づいて、
XCUITestコードを生成してください。
出力先: $(pwd)/tests/ios/SettingsAboutTests.swift"
📋 生成されたXCUITestコード
import XCTest
final class SettingsAboutTests: XCTestCase {
var app: XCUIApplication!
override func setUpWithError() throws {
continueAfterFailure = false
app = XCUIApplication(bundleIdentifier: "com.apple.Preferences")
app.launch()
}
/// TC-001: 一般画面から情報画面への遷移と戻り
func testNavigateToAboutAndBack() throws {
// Step 1: 「一般」セルをタップ
let generalCell = app.cells["com.apple.settings.general"]
XCTAssertTrue(generalCell.waitForExistence(timeout: 5), "一般セルが見つかりません")
generalCell.tap()
// Step 2: 「情報」セルをタップ
let aboutCell = app.cells["About"]
XCTAssertTrue(aboutCell.waitForExistence(timeout: 5), "情報セルが見つかりません")
aboutCell.tap()
// Step 3: 戻るボタンをタップ(一般画面へ)
let backToGeneral = app.buttons["一般"]
XCTAssertTrue(backToGeneral.waitForExistence(timeout: 5))
backToGeneral.tap()
// Step 4: 戻るボタンをタップ(メイン画面へ)
let backToSettings = app.buttons["設定"]
XCTAssertTrue(backToSettings.waitForExistence(timeout: 5))
backToSettings.tap()
// メイン画面に戻ったことを確認
XCTAssertTrue(generalCell.waitForExistence(timeout: 5))
}
/// TC-002: 情報画面のコンテンツ確認
func testAboutScreenContent() throws {
// 情報画面まで遷移
app.cells["com.apple.settings.general"].tap()
app.cells["About"].tap()
// デバイス名が表示されていることを確認
let deviceName = app.staticTexts["NAME_CELL_ID"]
XCTAssertTrue(deviceName.waitForExistence(timeout: 5), "デバイス名が見つかりません")
}
}
Generatorはテスト計画のidentifierをそのまま使用して、正確なXCUITestコードを生成してくれました!
Step 3: 壊れたテストの修復(Healer)
テストが失敗した場合は、mobile-test-healerエージェントが原因を調査して修正案を提示してくれます。
実際にiOSシミュレータで検証した結果を紹介します!
わざと壊れたテストを作成
Healerの動作を検証するため、手動で間違ったセレクタを使ったテストコードを作成しました。
// BrokenSettingsTests.swift - わざと壊れたテスト
import XCTest
final class BrokenSettingsTests: XCTestCase {
var app: XCUIApplication!
override func setUpWithError() throws {
continueAfterFailure = false
app = XCUIApplication(bundleIdentifier: "com.apple.Preferences")
app.launch()
}
// 壊れたテスト: 間違ったセレクタを使用
func testNavigateToAbout() throws {
// 間違い1: buttonsではなくcellsを使うべき
let generalButton = app.buttons["GeneralSettings"]
XCTAssertTrue(generalButton.exists)
generalButton.tap()
// 間違い2: 存在しないセレクタ
let aboutButton = app.buttons["AboutPhone"]
XCTAssertTrue(aboutButton.exists)
aboutButton.tap()
// 間違い3: waitForExistenceを使っていない
XCTAssertTrue(app.staticTexts["DeviceName"].exists)
}
}
Healerで修復
kiro-cli chat --agent mobile-test-healer --no-interactive \
"$(pwd)/tests/ios/BrokenSettingsTests.swift のテストが失敗しています。
iOSシミュレータに接続して現在のUI状態を確認し、
正しいセレクタに修正してください。
修正後のコードは同じファイルに上書き保存してください。"
📋 実行ログ(クリックで展開)
> まず、失敗しているテストコードを確認し、利用可能なデバイスを調べます。
Reading file: BrokenSettingsTests.swift, all lines
Running tool mobile_list_available_devices (from mcp server: mobile-mcp)
- Completed in 0.481s
> iPhone 16シミュレータが利用可能です。設定アプリを起動してUI要素を確認します。
Running tool mobile_launch_app (from mcp server: mobile-mcp)
Running tool mobile_list_elements_on_screen (from mcp server: mobile-mcp)
> 「一般」セルをタップして画面遷移を確認します。
Running tool mobile_click_on_screen_at_coordinates (from mcp server: mobile-mcp)
Running tool mobile_list_elements_on_screen (from mcp server: mobile-mcp)
> 「情報」画面が表示されました。デバイス名の identifier は NAME_CELL_ID です。
## 調査結果まとめ
| 元のセレクタ | 正しいセレクタ | 要素タイプ |
|-------------|---------------|-----------|
| app.buttons["GeneralSettings"] | app.cells["com.apple.settings.general"] | Cell |
| app.buttons["AboutPhone"] | app.cells["About"] | Cell |
| app.staticTexts["DeviceName"] | app.staticTexts["NAME_CELL_ID"] | StaticText |
修正結果
Healerが実際にシミュレータに接続してUI階層を確認し、自動的にコードを修正してくれました!
| 問題箇所 | 修正前 | 修正後 |
|---|---|---|
| 一般セル | app.buttons["GeneralSettings"] |
app.cells["com.apple.settings.general"] |
| 情報セル | app.buttons["AboutPhone"] |
app.cells["About"] |
| デバイス名 | app.staticTexts["DeviceName"] |
app.staticTexts["NAME_CELL_ID"] |
| 待機処理 | .exists |
.waitForExistence(timeout: 5) |
修正後のコード:
import XCTest
final class BrokenSettingsTests: XCTestCase {
var app: XCUIApplication!
override func setUpWithError() throws {
continueAfterFailure = false
app = XCUIApplication(bundleIdentifier: "com.apple.Preferences")
app.launch()
}
func testNavigateToAbout() throws {
let generalCell = app.cells["com.apple.settings.general"]
XCTAssertTrue(generalCell.waitForExistence(timeout: 5))
generalCell.tap()
let aboutCell = app.cells["About"]
XCTAssertTrue(aboutCell.waitForExistence(timeout: 5))
aboutCell.tap()
XCTAssertTrue(app.staticTexts["NAME_CELL_ID"].waitForExistence(timeout: 5))
}
}
Healerが行った修正のポイント
-
要素タイプの修正:
buttons→cells(設定アプリのメニュー項目はセル) - 正しいidentifierの特定: シミュレータのUI階層から実際のidentifierを取得
- waitForExistenceの追加: 非同期読み込みに対応するためタイムアウト付きの待機を追加
⚠️ 注意点:画面遷移検出の無限ループ
検証中に発見した問題として、AIエージェントが画面遷移を検出できずに無限ループに陥るケースがありました。
Running tool tap (from mcp server: mobile-mcp)
{ "x": 300, "y": 372 }
- Completed in 0.185s
Running tool get_ui_hierarchy (from mcp server: mobile-mcp)
{}
- Completed in 0.247s
Running tool tap (from mcp server: mobile-mcp)
{ "x": 300, "y": 372 } ← 同じ座標を繰り返しタップ
- Completed in 0.163s
...(延々と続く)
原因: get_ui_hierarchyの結果が変化しない(または取得に失敗する)ため、AIが「画面が遷移していない」と判断し、同じ操作を繰り返してしまう。
対策:
- タイムアウト設定: エージェント定義で適切なタイムアウトを設定
- 明確な指示: 「3回試行しても遷移しない場合は次のステップへ進む」などの指示を追加
- 手動介入: 無限ループを検知したらプロセスを停止し、手動でテスト計画を作成
この問題は、mobile-mcpとAIエージェントの連携における課題の一つです。今後のアップデートで改善されることを期待しています。
🤖 Androidでも試してみた
Androidエミュレータでも同じワークフロー(Planner → Generator → Healer)を検証しました。iOS編と同様に動作することを確認できました。
iOS版との主な違い
| 項目 | iOS | Android |
|---|---|---|
| 対象アプリ | 設定アプリ(com.apple.Preferences) | 設定アプリ(com.android.settings) |
| 要素識別子 | identifier(例: com.apple.settings.general) |
resource-id / text(例: android:id/title) |
| 生成コード | XCUITest (Swift) | Espresso (Kotlin) |
| UI階層取得 | 環境によりエラーになることがある | 安定して取得できた |
実行例
# Androidエミュレータを起動
~/Library/Android/sdk/emulator/emulator -avd Medium_Phone_API_36.1 &
# テスト計画を作成
kiro-cli chat --agent mobile-test-planner --no-interactive \
"Androidエミュレータに接続して、設定アプリ(com.android.settings)の
「ネットワークとインターネット」画面へのナビゲーションをテストする
テスト計画を作成してください。
テスト計画は $(pwd)/tests/android/settings-network.md に保存してください。"
📋 実行ログ(クリックで展開)
> まず、利用可能なAndroidエミュレータを確認します。
Running tool mobile_list_available_devices (from mcp server: mobile-mcp)
- Completed in 0.329s
> Androidエミュレータ(emulator-5554)が利用可能です。設定アプリを起動します。
Running tool mobile_launch_app (from mcp server: mobile-mcp)
{ "device": "emulator-5554",
"packageName": "com.android.settings" }
- Completed in 1.147s
Running tool mobile_list_elements_on_screen (from mcp server: mobile-mcp)
{ "device": "emulator-5554" }
- Completed in 2.523s
> 設定アプリのメイン画面が表示されています。
「Network & internet」が座標(221, 586)にあります。これをタップして遷移を確認します。
Running tool mobile_click_on_screen_at_coordinates (from mcp server: mobile-mcp)
{ "device": "emulator-5554", "x": 221, "y": 586 }
- Completed in 0.141s
Running tool mobile_list_elements_on_screen (from mcp server: mobile-mcp)
- Completed in 2.490s
> 「Network & internet」画面に正常に遷移しました。
生成されたEspressoコード
@RunWith(AndroidJUnit4::class)
class SettingsNetworkTests {
@get:Rule
val activityRule = ActivityScenarioRule(SettingsActivity::class.java)
@Test
fun testNavigateToNetworkAndInternet() {
onView(withText("Network & internet")).perform(click())
onView(withText("Internet")).check(matches(isDisplayed()))
onView(withText("SIMs")).check(matches(isDisplayed()))
}
@Test
fun testNavigateUpToMainScreen() {
onView(withText("Network & internet")).perform(click())
onView(withContentDescription("Navigate up")).perform(click())
onView(withText("Network & internet")).check(matches(isDisplayed()))
}
}
Healerによる修復もiOS版と同様に動作し、間違ったセレクタ(withText("NetworkSettings")など)を正しいセレクタ(withText("Network & internet"))に自動修正してくれました。
😵 ハマったポイント
検証中に遭遇した問題と解決策をまとめます。
問題1: mobilecliがインストールされていない
症状: タップ操作が「成功」と表示されるが、実際には画面に反映されない
解決策: mobilecliを明示的にインストール
npm install -g @mobilenext/mobilecli@latest
問題2: WDAが起動していない
症状: 初回実行時にタップが効かない
解決策: 事前にmobilecliでWDAを起動
npx @mobilenext/mobilecli io tap "0,0" --device <device-id>
📝 まとめ
「モバイルアプリでもPlaywright Agentsみたいなことができたら便利だろうな」と思って調べてみたところ、iOS/Androidのシミュレータを操作できるmobile-mcpを発見!
「Playwright用のプロンプトをベースにいけるかな?」と思い、ツール名やコード生成の指示を調整してみたら、案外すんなり動かすことができました。
AIがアプリを探索してテスト計画を作成し、その計画からテストコードを生成。さらにシミュレータで確認しながら壊れたテストを自動修正してくれます。
自分は指示を出しただけなのに、シミュレータが勝手にタップしたりスワイプしたりしているのを見ると、「おお、動いてる!」とちょっと感動しました。
3つのエージェントの連携フロー
- Planner: デバイスに接続 → アプリ起動 → 画面遷移 → UI要素のidentifierと座標を記録
- Generator: テスト計画のidentifierをそのまま使用してテストコードを生成
- Healer: 壊れたテストを読み込み → デバイスで実際のUI階層を確認 → 正しいセレクタに自動修正
注意点
- シミュレータ/エミュレータを事前に起動しておく必要がある
- iOSでは
mobile_list_elements_on_screenがエラーになることがある(環境依存) - 実機の場合は追加の設定が必要(WebDriverAgentなど)
AIによるモバイルテストコード自動生成に興味がある方は、ぜひ試してみてください!🚀