Flutter Skill

repository·main·Indexed 43 days ago

https://github.com/ai-dashboad/flutter-skill

An AI-native E2E testing tool and bridge between AI coding assistants (Claude Code, Cursor, Windsurf) and running Flutter applications. Using the Model Context Protocol (MCP), it provides 25+ tools for UI inspection, gestures, screenshots, and navigation across 10 platforms. It includes a CLI, an IntelliJ/Android Studio plugin, and a Dart package (v0.9.37) to give AI agents 'eyes and hands' inside Flutter apps.

Tokens
127.4K
Snippets
373
Records
554
Agent score
54%

What's inside Flutter Skill

  1. Capabilities of the Flutter Skill CLI

    main

    The Flutter Skill CLI tool acts as an AI Agent Bridge for Flutter apps. Once installed and connected via the Dart VM Service Protocol, it provides the following capabilities:

    • MCP Server: A JSON-RPC interface for AI agents (Claude, Cursor, Windsurf).
    • UI Inspection: Ability to view the widget tree and widget properties.
    • Actions: Perform user interactions such as tapping, scrolling, and entering text.
    • Screenshots: Capture the current state of the app for visual verification.
    • Navigation: Track the application's routes and navigation stack.
  2. Handle multiple Flutter apps in the same directory

    main

    When developing cross-platform apps, you may have multiple Flutter processes running from the same project directory (e.g., one on an iOS simulator and one on an Android emulator). flutter_skill uses Device-Aware Selection to resolve this ambiguity.

    Selection Logic Priority

    1. Exact Directory Match: flutter_skill first filters apps running in your current working directory.
    2. Device Filter: If a device filter is provided (via CLI or API), it narrows the search to matching device IDs.
    3. Unique Match: If only one app remains after filtering, it is auto-selected.
    4. User Selection: If multiple apps match, an interactive UI is presented to choose the correct device/port combination.
    cd /Users/you/my_flutter_app
    
    # Terminal 1
    flutter run -d "iPhone 16 Pro"
    
    # Terminal 2
    flutter run -d "Android Emulator"
    
    # Terminal 3
    flutter_skill inspect  # This will trigger the selection UI
  3. Best practices for port allocation and logging

    main

    When running multiple Flutter instances, follow these conventions to ensure stability and traceability:

    Port Allocation Pattern

    Assign ports sequentially to avoid overlap:

    • Project 1: --vm-service-port=50001
    • Project 2: --vm-service-port=50002
    • Project N: --vm-service-port=5000N

    Logging

    To debug multiple running processes, redirect the output of each flutter run command to a unique log file using tee:

    flutter run --vm-service-port=50001 2>&1 | tee app1.log &
    flutter run --vm-service-port=50002 2>&1 | tee app2.log &
  4. How Smart App Selection works

    main

    When multiple Flutter apps are running simultaneously, flutter_skill uses a smart selection mechanism to identify the correct app to connect to. Instead of relying on port scanning or manual URI input, it uses the current working directory (CWD) to match the running process to your project.

    The selection follows this hierarchy:

    1. Single App: If only one Flutter app is running, it is selected automatically.
    2. Exact Match: If multiple apps are running, it looks for an app whose projectPath exactly matches your current directory.
    3. Prefix Match: If no exact match is found, it checks if your current directory is a subdirectory of a project, or if a project is a subdirectory of your current directory.
    4. Manual Selection: If the match is ambiguous (multiple matches) or no match is found, the tool prompts you to select the correct app from a list.
    // The selection logic follows this priority:
    // 1. Single app -> auto-select
    // 2. Exact CWD match -> auto-select
    // 3. Prefix match (subdirectories) -> auto-select
    // 4. Ambiguous/No match -> userSelect()
  5. Limitations of View Traversal and Jetpack Compose Support

    main

    UI Inspection Limitations

    Despite documentation claims, the current Android SDK ViewTraversal implementation does not support Jetpack Compose.

    • Supported: Traditional Android XML Views and ViewGroup hierarchies.
    • Unsupported: Pure Jetpack Compose UIs. Because Compose renders into a single AndroidComposeView, the SDK cannot traverse individual composables using the standard ViewGroup.children method.

    Consequences: Commands like inspect, find_element, tap, get_text, and enter_text will fail or return empty results when interacting with pure Compose-based screens.

  6. How the Smart Discovery System works

    main

    The Smart Discovery System uses a cascading strategy pipeline to automatically find and connect to running Flutter apps. It attempts strategies in order of speed and efficiency, falling back to more thorough but slower methods if the previous ones fail.

    Discovery Pipeline Order:

    1. Strategy 0: Process-Based (Fastest): Scans ps aux for Flutter processes, extracts the VM Service URI directly, and retrieves the project path via lsof. It then uses smart selection based on the current directory.
    2. Strategy 1: Parallel Port Check: Checks a specific range of ports (50000-50005) simultaneously. It returns the first successful result.
    3. Strategy 2: DTD Discovery: Connects to the DTD service to query for the VM Service URI.
    4. Strategy 3: Port Range Scan (Thorough): Scans the full port range (40000-65535) to find any active VM Service.
  7. Understand the Dart Tooling Daemon (DTD) Protocol

    main

    The Dart Tooling Daemon (DTD) is a next-generation communication protocol introduced in Dart/Flutter 3.x. It is used for tool-to-app communication. While it provides core capabilities like logging and hot reload, it is not a complete replacement for the VM Service, especially for UI-level operations (like tapping or screenshots) which require custom extensions.

    // Example DTD Request (JSON-RPC 2.0)
    {
      "jsonrpc": "2.0",
      "id": 1,
      "method": "streamListen",
      "params": {
        "streamId": "Stdout"
      }
    }
  8. Understand the difference between DTD and VM Service

    main

    When working with Flutter 3.x, it is critical to distinguish between the Dart Tooling Daemon (DTD) and the VM Service, as they use different protocols, ports, and serve different purposes.

    Comparison

    FeatureDTD ServiceVM Service
    ProtocolWebSocketHTTP + WebSocket
    PortDynamic (e.g., 54321)Specifiable (e.g., 50000)
    URI Formatws://127.0.0.1:{port}/{secret}=/wshttp://127.0.0.1:{port}/{secret}=/
    CapabilitiesHot Reload, Log Streaming, File OpsHot Reload, Log Streaming, Debugging, Custom Extensions, UI Operations

    Key Takeaway: You cannot reuse a DTD connection to perform VM Service tasks (like UI operations). However, you can use the DTD as a service discovery mechanism to find the VM Service URI.

  9. Element selection logic

    main

    When sending commands like tap or enter_text, elements are located using the following priority order:

    1. key or testID: Matches the testID prop registered via registerComponent().
    2. text: Matches the text string provided during registration.
    3. accessibilityLabel: Matches the accessibility label provided during registration.
    {
      "method": "tap",
      "params": { "key": "login_button" }
    }
    
    {
      "method": "enter_text",
      "params": { "key": "email_field", "text": "user@example.com" }
    }
    
    {
      "method": "find_element",
      "params": { "text": "Log In" }
    }
    
    {
      "method": "scroll",
      "params": { "key": "main_list", "direction": "down", "distance": 500 }
    }
  10. Use Dart MCP for app monitoring and lifecycle management

    main

    If you do not need UI automation (no tapping, swiping, or screenshots) and only need to monitor the app, you can use Dart MCP which works natively with the Flutter 3.x DTD protocol.

    Supported tasks with Dart MCP:

    • Launching the app
    • Getting app logs
    • Hot reload
    • Monitoring runtime errors

    Limitations: It cannot perform UI interactions like tap or swipe.

    # Example using Dart MCP for monitoring
    mcp__dart__launch_app(device_id="iPhone 16 Pro")
    mcp__dart__connect_dart_tooling_daemon(uri="ws://...")
    mcp__dart__get_app_logs()
    mcp__dart__hot_reload()
  11. How the flutter-skill iOS bridge works

    main

    The SDK acts as a bridge between the flutter-skill server and your native iOS app. The communication flow is as follows:

    1. Discovery: The flutter-skill server performs an HTTP GET request to /.flutter-skill on the app to check health and discover the bridge.
    2. Communication: The server establishes a WebSocket connection via /ws using the JSON-RPC 2.0 protocol.
    3. Execution: The bridge traverses the UIView hierarchy to identify interactive elements (like UIButton or UITextField) and executes requested commands.