--- name: flutter-mcp-toolkit-inspect description: Read state from a running Flutter app — semantic snapshot, view details, errors, screenshots, VM info. Use when you need to understand what the app is showing. --- ## When to use Use this skill for read-only state inspection of a running Flutter app: what is shown on screen, recent errors, available debug targets, VM metadata, and widget tree details. Do not use for driving interaction — that is the interact skill. Start with `discover_debug_apps` when no connection target is established. Start with `semantic_snapshot` when you need to know which widgets are on screen. ## Recipes ### Fast inspect cycle (prefer `batch`) ```bash flutter-mcp-toolkit batch --steps '[ {"name":"semantic_snapshot"}, {"name":"get_app_errors","args":{"count":5}}, {"name":"get_screenshots","args":{"mode":"flutter_layer","compress":true}} ]' ``` Use `mode: flutter_layer` on `get_screenshots` on macOS to avoid Screen Recording permission failures. `capture_ui_snapshot` uses the separate `screenshotMode` field. ### Snapshot the visible UI 1. Call `semantic_snapshot()`. 2. Read `interactionSurface`: `flutter_widgets` (tap-by-ref works), `hybrid` (sparse semantics), `game_canvas` (use `evaluate_dart_expression` + screenshots). 3. Each interactive node has a stable `ref` (`s_0`, `s_1`, …) and the response includes a `snapshot_id`. 4. Pass refs to interaction tools; pass the `snapshot_id` value as `snapshotId` to detect staleness. ### After a code edit Prefer `hot_reload_and_capture` over separate reload + snapshot + screenshot calls. ### Find an error by message 1. Call `get_app_errors(count: 10)`. 2. Inspect the `errors` array — each entry has message, stack trace, and timestamp. 3. Match on message text to find the source. ### List debug-mode apps 1. Call `discover_debug_apps()`. 2. Read the `targetId` (canonical WebSocket URI) for each active target. 3. Pass the chosen URI as `connection.targetId` on subsequent tool calls. ### Get widget at coordinates 1. Call `inspect_widget_at_point(x: 200, y: 400)`. 2. The response identifies the deepest widget and render node at those global logical pixel coordinates. ### Save a screenshot to a file 1. Call `get_screenshots()`. 2. If `meta.fileUrls` is non-empty, screenshots are on disk at those paths. Otherwise the response contains base64 `ImageContent` blocks — extract and write manually. 3. To force file output, configure an images output directory on the server before calling. ## Tool reference ### discover_debug_apps List all active Flutter debug targets with canonical WebSocket URIs. - `connection` (object, optional) — accepted by schema, ignored by executor; discovery is always local. ``` discover_debug_apps() ``` Returns: `{"targets": [{"targetId": "ws://127.0.0.1:8181//ws", "host": "...", "port": 8181}]}` - `vm_service_unavailable` — no debug-mode Flutter process found. - `tool_not_found` — binary predates v3.0.0; run `make build`. ### get_app_errors Retrieve the most recent application errors from the Dart VM. - `count` (integer, optional, default: 4) — number of errors to return. - `connection` (object, optional) — connection override. ``` get_app_errors(count: 5) ``` Returns: `{"message": "2 errors found", "errors": [{"message": "...", "stack": "..."}]}` - `vm_service_unavailable` — app not reachable. - `connection_selection_required` — multiple targets; supply `connection.targetId`. ### get_screenshots Capture screenshots of all views. - `compress` (boolean, optional, default: true) — compress PNG output. - `mode` (string, optional, default: `auto`) — `auto`, `flutter_layer`, or `desktop_window`. - `permissionPolicy` (string, optional, default: `check_only`) — `check_only`, `auto_request_once`, or `request_always`. - `connection` (object, optional) — connection override. ``` get_screenshots(mode: "flutter_layer", compress: false) ``` Returns: `ImageContent` blocks (base64 PNG) when no output dir configured, or `TextContent` URL refs + `meta.fileUrls` when file output is enabled. - `permission_denied` — retry with `permissionPolicy: "auto_request_once"`. - `vm_service_unavailable` — app not reachable. ### get_view_details Get dimensions, device pixel ratio, and display ID for all views. - `connection` (object, optional) — connection override. ``` get_view_details() ``` Returns: `{"views": [{"id": 0, "width": 1280, "height": 800, "devicePixelRatio": 2.0}]}` - `vm_service_unavailable` — app not running. - `connection_selection_required` — multiple targets; supply `connection.targetId`. ### get_vm Return Dart VM metadata: version, isolates list, pid, and architecture. - `connection` (object, optional) — connection override. ``` get_vm() ``` Returns: `{"type": "VM", "name": "vm", "version": "3.x.x", "isolates": [...]}` - `vm_service_unavailable` — app not reachable. - `connection_selection_required` — multiple targets active. ### get_extension_rpcs List all registered VM service extension RPCs in the running app. - `isolateId` (string, optional) — schema-declared but not read by executor; checks all isolates when omitted. - `isRawResponse` (boolean, optional) — schema-declared but not read by executor. - `connection` (object, optional) — connection override. ``` get_extension_rpcs() ``` Returns: `{"extensionRPCs": ["ext.flutter.inspector.getRootWidget", "ext.mcp.toolkit.semantic_snapshot"]}` - `vm_service_unavailable` — app not running. - `connection_selection_required` — multiple targets. ### semantic_snapshot Return a compact accessibility tree of interactive widgets with stable `ref` strings and a `snapshot_id`. A node is listed when it reads (label, value), acts (button, text field, tap, scroll…) or carries a `Semantics(identifier:)`. - `identifierPrefix` (string, optional) — keep only nodes whose identifier starts with it (`"nav."` for one rail). - `subtreeOf` (string, optional) — keep one node and its descendants; a ref from the latest snapshot or an identifier, the ref tried first. - `fields` (array of strings, optional) — node keys to return; `ref` is always kept. Names: `ref id type identifier label value hint enabled focused checked toggled selected bounds actions children visibleInViewport centerInViewport center`. - `connection` (object, optional) — connection override. The tree is always walked whole, so a ref read off a filtered snapshot is the same ref the full snapshot would give and works with every interaction tool. A filtered reply adds `totalNodeCount` and echoes `filter`; `children` lists kept refs only. ``` semantic_snapshot() semantic_snapshot(identifierPrefix: "nav.", fields: ["identifier", "selected"]) semantic_snapshot(subtreeOf: "panel.tabs") ``` Returns: `{"snapshot_id": 3, "nodeCount": 1, "viewport": {...}, "nodes": [{"ref": "s_0", "label": "Increment", "actions": ["tap"], "bounds": {...}, "visibleInViewport": true, "centerInViewport": true, "center": {...}}]}` — the viewport is stated once in the envelope, not on each node. - `subtree_root_not_found` — `subtreeOf` is neither a ref of the latest snapshot nor an identifier in the tree; no snapshot was taken, refs and `snapshot_id` are unchanged. - `unknown_field` — a name in `fields` is not a node key; `acceptedFields` lists them. Over MCP and the CLI the name is refused at the boundary instead — an invalid `fields` argument naming the accepted keys, without spending a call on the app. - `vm_service_unavailable` — app not running or `MCPToolkitBinding.initialize()` not called. - `connection_selection_required` — multiple targets; supply `connection.targetId`. ### inspect_widget_at_point Identify the deepest widget and render node at a global logical coordinate. - `x` (integer, required) — global logical X coordinate. - `y` (integer, required) — global logical Y coordinate. - `viewId` (integer, optional) — FlutterView ID for multi-view apps. - `connection` (object, optional) — connection override. ``` inspect_widget_at_point(x: 200, y: 400) ``` Returns: `{"widget": {"type": "ElevatedButton", "rect": {"left": 180, "top": 380, "right": 280, "bottom": 420}}}` - `vm_service_unavailable` — app not reachable. - `invalid_argument` — coordinates out of view bounds. ### capture_ui_snapshot Capture screenshots, view details, and app errors in one bundled response. - `errorsCount` (integer, optional, default: 4) — errors to include. - `compress` (boolean, optional, default: true) — compress screenshots. - `includeViewDetails` (boolean, optional, default: true) — include view data. - `includeErrors` (boolean, optional, default: true) — include app errors. - `screenshotMode` (string, optional, default: `auto`) — `auto`, `flutter_layer`, or `desktop_window`. - `permissionPolicy` (string, optional, default: `check_only`) — `check_only`, `auto_request_once`, or `request_always`. - `connection` (object, optional) — connection override. ``` capture_ui_snapshot(errorsCount: 2, includeViewDetails: false) ``` Returns: a `TextContent` JSON block with `screenshots`, `viewDetails`, and `errors` keys. When `screenshots.images` contains inline base64, each payload is lifted into a sibling image block and the JSON reports `screenshots.imagesDeliveredAs: "image_blocks"`; the emptied `images` list is then the normal shape, not a failed capture. Captures delivered through `screenshots.fileUrls` stay in the JSON and produce no image blocks. - `vm_service_unavailable` — app not running. - `permission_denied` — retry with `permissionPolicy: "auto_request_once"`. ### connect_debug_app Explicitly select and connect to a Flutter debug VM target. Use when multiple apps are running or to pin a specific target for the session. - `connection` (object, optional) — pass `connection.targetId` with a WebSocket URI from `discover_debug_apps`. ``` connect_debug_app(connection: {targetId: "ws://127.0.0.1:8181//ws"}) ``` Returns: `{"connected": true, "targetId": "ws://127.0.0.1:8181//ws", "isolates": [...]}` - `target_not_found` — URI doesn't match a running app; re-run `discover_debug_apps` for the exact URI. - `connection_failed` — VM refused connection; verify the app is still running in debug mode.