Skip to content
Debugging
Skill

/flutter-mcp-toolkit-debug

Diagnose problems in a running Flutter app — read logs, evaluate Dart expressions, interpret error envelopes. Use when something broke.

BOOST
From plugin
mcp-flutter
38922 skills1 agent
Install
$ npx -y skills add Arenukvern/mcp_flutter --skill flutter-mcp-toolkit-debug --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/flutter-mcp-toolkit-debug

Context preview

The summary Claude sees to decide when to auto-load this skill.

Diagnose problems in a running Flutter app — read logs, evaluate Dart expressions, interpret error envelopes. Use when something broke.

SKILL.md

flutter-mcp-toolkit-debug.SKILL.md
name: flutter-mcp-toolkit-debug
description: Diagnose problems in a running Flutter app — read logs, evaluate Dart expressions, interpret error envelopes. Use when something broke.

<!-- @FMT_MODE_PRELUDE -->

When to use

Use this skill when something broke and you need to understand why:

  • A tool call returned an error envelope (`ok: false`).
  • The app behaves unexpectedly and you need runtime log output.
  • You need to inspect live app state without changing it (read `AgentState.instance.value`).
  • A prior `control` action (tap, hot_reload, navigate) completed without error but the result is wrong.

Do NOT use this skill for:

  • Reading what is currently on screen — use `flutter-mcp-toolkit-inspect`.
  • The toolkit itself failing to connect — load `flutter-mcp-toolkit-setup`.

Registry vs bundled tools

  • **Bundled `fmt_*` tools** (screenshot, logs, evaluate, …) run on the MCP server via **`AgentRegistry`** on the host.
  • **App-registered surfaces** appear after `MCPToolkitBinding.addEntries` / `AgentCallEntry` — discover with **`fmt_list_client_tools_and_resources`**, then **`fmt_client_tool`** / **`fmt_client_resource`**.

Triage flow

1. **Error envelope returned?** Read `error.code` first, then `error.descriptor.retryable`. Look the code up in the Error envelope playbook below. 2. **Retryable error?** Run `flutter-mcp-toolkit doctor --json`. If doctor fails, load `flutter-mcp-toolkit-setup`. 3. **Need log output?** Call `get_recent_logs` with `count: 100` and a level filter. Look for stack traces or assertion messages near the timestamp of the failure. 4. **Need live state?** Call `evaluate_dart_expression` with a targeted expression (e.g. `MyBloc.instance.state.toString()`). Do this after logs, not instead of them. 5. **Chaining with inspect?** Order: `semantic_snapshot` → `evaluate_dart_expression` → `get_recent_logs`. Snapshot gives you the current widget tree before expression evaluation mutates nothing; logs give trailing context. 6. **Multiple targets?** If `connection_selection_required`, call `discover_debug_apps`, pick the `targetId`, then pass `connection: {targetId: "..."}` to every subsequent call.

Tool reference

get_recent_logs

Retrieve recent `print()` and `debugPrint()` output from the running app's main isolate.

  • `count` • integer • optional, default: 50 — number of log lines to return.
  • `connection` • object • optional — connection override; required when multiple debug apps are running.
get_recent_logs(count: 100)
get_recent_logs(count: 50, connection: {targetId: "ws://127.0.0.1:8181/<token>/ws"})

Returns: `{"logs": ["[INFO] page loaded", "[ERROR] assertion failed: ..."], "count": 50}`

Read-only; no code executed. Returns only lines buffered since last app start or hot restart. On failure see `getRecentLogsFailed` in the playbook.

evaluate_dart_expression

Evaluate a Dart expression in the running app's main isolate and return its string representation.

  • `expression` • string • **required** — Dart expression (e.g. `"MyClass.instance.counter"`).
  • `connection` • object • optional — connection override.
evaluate_dart_expression(expression: "Navigator.of(context).canPop()")
evaluate_dart_expression(expression: "AgentState.instance.value.toString()")

Returns: `{"result": "42", "kind": "Int", "classRef": "_Smi", "truncated": false}` — `result` is always a string. A long String comes back whole up to 32,768 UTF-16 code units (the unit `length` and `String.length` count in, so non-ASCII text may encode to more bytes); past that `truncated: true` with `length`, `returnedLength` and a hint naming the `.substring(...)` that reads the rest. A List, Map or object comes back as a bare class name (`"_GrowableList"`) with a hint — wrap the expression in `.toString()` or `jsonEncode(...)` to read its value. Executes arbitrary code in the live isolate — avoid side-effecting expressions. Debug mode only. On failure see `evaluateExpressionFailed` in the playbook.

Connect / multi-app flows

When `discover_debug_apps` returns more than one entry (or any call returns `connection_selection_required`):

1. Call `discover_debug_apps()` — read `targets[*].targetId` for each running app. 2. Identify the target by port or hostname. 3. Call `connect_debug_app(connection: {targetId: "ws://127.0.0.1:<port>/<token>/ws"})` to pin the session. 4. Pass the same `connection` object to every subsequent tool call for the session.

Connection override pattern — pass `connection` on any call:

get_recent_logs(count: 50, connection: {targetId: "ws://127.0.0.1:8182/<token>/ws"})
evaluate_dart_expression(expression: "x.toString()", connection: {targetId: "ws://127.0.0.1:8182/<token>/ws"})

If the target changes (app restarted, port shifted), re-run `discover_debug_apps` to get the new `targetId`. Stale URIs return `connect_failed`.

Error envelope playbook

Every failure returns `{code, message, details, descriptor, recovery}`. Always read `error.descriptor` (not the top-level envelope) for `retryable` and `exitCode`. Run `error.recovery.fix_command` directly when provided.

`unexpectedExecutorError` (`unexpected_executor_error`)

**Means:** unhandled exception in the command executor. **Causes:** bug in the server; unexpected nil; unrecoverable VM state. **Recovery:**

1. `flutter-mcp-toolkit doctor --json` 2. If doctor passes, retry once; if it recurs, file a bug with `error.details`.

`connectFailed` (`connect_failed`)

**Means:** connection to the VM Service WebSocket failed. **Causes:** wrong port, stale token, app not running. **Recovery:**

1. `flutter-mcp-toolkit exec --name get_vm --args '{"connection":{"uri":"ws://127.0.0.1:8181/<token>/ws"}}'` 2. Get the exact URI from `app.debugPort.wsUri` in Flutter output.

`vmNotConnected` (`vm_not_connected`)

**Means:** a VM-dependent command was called before a connection was established. **Recovery:**

1. `flutter-mcp-toolkit exec --name status --args '{}'` 2. Then `flut

Read more
Ships withmcp-flutter

Inspect and drive a running Flutter app from your AI assistant. 📖 Docs: docs.page/arenukvern/mcp_flutter 🤝 Contribute: guide · contributors · code of conduct · security flutter-mcp-toolkit is a Dart MCP server + Flutter package for AI agents (Codex, Zed,

Get the whole plugin

Other skills on mcp-flutter.