🤖

MCPデビュー - iOS/フロントエンドエンジニアのためのMCP入門

に公開

MCPデビュー - iOS/フロントエンドエンジニアのためのMCP入門

こんにちは、iOSエンジニアのkeiです。

AIアシスタントがコードを「提案」するだけでなく、ローカル環境で「実行」まで行う世界が、MCP(Model Context Protocol) によって現実のものとなりました。

本ブログでは、AIによるiOS開発の効率化を目指し、MCPサーバーの具体的な作成方法と使い方を、iOS Simulatorの制御を例にご紹介します。

🚀 MCPとは?なぜ今注目されているのか

MCP(Model Context Protocol) は、AIアシスタント(Claude、ChatGPTなど)とローカルツールを連携させるための新しいプロトコルです。Anthropic社が2024年11月に発表したこの技術により、AIが私たちの開発環境と直接やり取りできるようになりました。

なぜMCPが革命的なのか?

従来、AIアシスタントは「コードを提案する」ことはできても、実際に 「実行する」 ことはできませんでした。MCPにより、AIが以下のようなことを直接行えるようになります:

  • iOS Simulatorの操作 - アプリのタップ、スワイプ、テキスト入力
  • データベースへのクエリ実行
  • APIの呼び出し
  • ファイルシステムの操作

理屈はこれくらいにして、早速実践に入りましょう!

✨ 実践の全体像

今回の実践では、以下の3つのコンポーネントが連携して動作します。

  1. Cursor (MCPクライアント): 私たちがAIに指示を出すインターフェースです。
  2. Python MCPサーバー: Cursorからの指示を受け取り、それを解釈して具体的なコマンドを実行します。
  3. iOS Simulator: サーバーが実行したコマンドによって実際に操作される対象です。

このように、自然言語での指示がMCPを通じて具体的な操作に変換されるのが、今回構築するシステムの核心です。

🎯 実践例:iOS Simulator制御MCPサーバー

今回、iOS開発でよく使うSimulatorをAIが直接操作できるMCPサーバーを作成しました。これにより、以下のようなことが可能になります:

💬 「Simulatorを起動して、特定のアプリを起動して、画面の特定なところをタップしてください」
🤖 → AIがSimulatorでアプリを起動し、座標を計算してタップ実行

🛠️ 実装したツール一覧

# デバイス管理
list_devices()      # シミュレーター一覧取得
boot_device()       # デバイス起動
shutdown_device()   # デバイス停止

# アプリ操作
launch_app()        # アプリ起動
take_screenshot()   # スクリーンショット撮影

# UI操作
tap_coordinate()    # 座標タップ
input_text()        # テキスト入力
press_home_button() # ホームボタン押下

🔧 技術実装のポイント

1. MCPプロトコルへの対応

MCPサーバーは、クライアント(この場合はCursor)からの要求に応じて、登録されたツールを実行します。

ツール一覧の提供 (list_tools)

まず、サーバーがどのようなツールを提供しているかをクライアントに知らせる必要があります。@server.list_tools()デコレータを付けたメソッドで、ツールの名前、説明、入力スキーマを定義します。

@app.list_tools()
async def handle_list_tools() -> list[types.Tool]:
    """利用可能なツール一覧を返す"""
    return [
        types.Tool(
            name="launch_app",
            description="指定されたBundle IDのアプリを起動",
            inputSchema={
                "type": "object",
                "properties": {
                    "bundle_id": {"type": "string", "description": "起動するアプリのBundle ID"},
                    "device_id": {"type": "string", "default": "booted", "description": "デバイスID(デフォルト: booted)"}
                },
                "required": ["bundle_id"]
            }
        ),
        # ... 他にも同様にツールを定義 ...
    ]

ポイント:

  • JSONスキーマでパラメータを定義
  • 型安全な実装
  • 明確なエラーハンドリング

2. ツールの実行 (call_tool)

次に、実際にツールを呼び出すための処理を実装します。@server.call_tool()デコレータを付けたメソッドで、ツール名(name)と引数(arguments)を受け取り、対応する処理を呼び分けます。

@self.server.call_tool()
async def call_tool(name: str, arguments: Dict[str, Any]) -> List[types.TextContent]:
    try:
        if name == "launch_app":
            return await self.launch_app(**arguments)
        elif name == "tap_coordinate":
            return await self.tap_coordinate(**arguments)
        elif name == "take_screenshot":
            return await self.take_screenshot(**arguments)
        elif name == "input_text":
            return await self.input_text(**arguments)
        elif name == "list_devices":
            return await self.list_devices()
        elif name == "boot_device":
            return await self.boot_device(**arguments)
        elif name == "shutdown_device":
            return await self.shutdown_device(**arguments)
        elif name == "press_home_button":
            return await self.press_home_button(**arguments)
        else:
            raise ValueError(f"Unknown tool: {name}")
    except Exception as e:
        return [types.TextContent(type="text", text=f"エラー: {str(e)}")]

ポイント:

  • 受信したツール名に応じて、対応するメソッドを呼び出す。
  • try-exceptブロックでエラーを捕捉し、クライアントに分かりやすい形で返す。

3. simctlコマンドによるアプリ起動

async def launch_app(bundle_id: str, device_id: str = "booted") -> list[types.TextContent]:
    """アプリを起動"""
    cmd = f'xcrun simctl launch {device_id} {bundle_id}'
    result = await run_command(cmd)
    return [types.TextContent(type="text", text=f"アプリ {bundle_id} を起動しました\n結果: {result}")]

async def run_command(cmd: str) -> str:
    """シェルコマンドを実行"""
    try:
        process = await asyncio.create_subprocess_shell(
            cmd,
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE
        )
        stdout, stderr = await process.communicate()
        
        if process.returncode != 0:
            error_msg = stderr.decode() if stderr else "Unknown error"
            raise Exception(f"Command failed: {error_msg}")
            
        return stdout.decode() if stdout else "Success"
    except Exception as e:
        raise Exception(f"Command error: {str(e)}")

ポイント:

  • simctl launchコマンドでアプリ起動
  • 非同期処理でコマンド実行
  • エラーハンドリングによる安全な実行

📋 導入手順(5分で完了)

ステップ1: 環境構築

# 仮想環境作成
python -m venv mcp_simulator_env
source mcp_simulator_env/bin/activate

# MCP SDKをインストール
pip install mcp

ステップ2: Cursor設定

プロジェクトルートに .cursor/mcp.json を作成:

{
    "mcpServers": {
        "ios-simulator-controller": {
            "command": "/path/to/your/mcp_simulator_env/bin/python",
            "args": [
                "/path/to/your/mcp_server_simulator.py"
            ]
        }
    }
}

ステップ3: 動作確認

  1. Cursorでプロジェクトを開く
  2. Cmd+Shift+P"MCP Settings" を選択
  3. "ios-simulator-controller" が✅緑色で表示されることを確認

🎮 実際の使用例

UI自動テストシナリオ

💬 あなた: 「Simulatorでサンプルアプリを起動して、
          ユーザー名に'testuser'、パスワードに'password123'を入力し、
          ログインボタンをタップしてください」

🤖 AI: はい!以下の手順で実行します:
      1. アプリを起動します
      2. ユーザー名フィールドをタップしてテキスト入力
      3. パスワードフィールドをタップしてテキスト入力  
      4. ログインボタンをタップ
      5. 結果のスクリーンショットを撮影

      → 実際にSimulatorが動作してテストが実行される

デバッグ支援

💬 あなた: 「アプリがクラッシュしました。
          前の状態のスクリーンショットを撮って、
          ホームボタンを押して再起動してください」

🤖 AI: スクリーンショットを撮影しました: crash_state_1703001234.png
      ホームボタンを押しました
      アプリを再起動しますか?

実際に簡単な指示をしてみた

iOSのシミュレーターを起動して、com.xxx.xxxのアプリを起動してください

🌟 MCPがもたらす開発体験の変化

Before(従来)

1. 手動でSimulatorを操作
2. 毎回同じテスト手順を繰り返し
3. スクリーンショットを手動で撮影
4. 複数デバイスでの確認も手動

After(MCP導入後)

1. 自然言語でテスト指示
2. AIが自動で複雑な操作を実行
3. 結果の記録も自動化
4. 複数デバイスでの一括テストも可能

🎯 今後の展望

1. AI駆動のテスト生成

💬 「このアプリの基本的な動作確認テストを生成して実行してください」
🤖 → UI要素を分析して自動でテストシナリオを作成・実行

2. チーム開発での活用

  • CIパイプラインとの連携
  • テスト結果の自動レポート生成
  • 回帰テストの自動化

3. デバッグプロセスの革新

💬 「このクラッシュログを解析して、再現手順をSimulatorで実行して」
🤖 → AIがクラッシュログを読み解き、再現手順を特定。Simulator上で自動的に操作を実行し、開発者のデバッグ作業を強力に支援する。

📚 まとめ

MCPは単なる「新しいツール」ではなく、AIと開発環境の融合を実現する革新的な技術です。今回作成したiOS Simulator制御MCPサーバーは、この可能性のほんの一部を示しています。

🎉 MCPを始めるメリット

  • 生産性向上 - 繰り返し作業の自動化
  • 品質向上 - 人的ミスの削減
  • 学習効果 - AIとの協働経験

MCPはまだ始まったばかりの技術です。 今から始めることで、AI駆動開発の波に乗り遅れることなく、新しい開発体験を楽しむことができるでしょう。

dely Tech Blog

Discussion