
Flutter MCP Toolkit
io.github.ArenukvernPublished by GitHub account Arenukvernv7.0.1Updated Oct 24, 2026
Inspect and drive Flutter debug apps/games: semantic snapshots, search, and custom client tools
Overview
A local MCP server that lets an assistant inspect and drive a running Flutter debug app: semantic snapshots, widget interaction, screenshots, hot reload and VM/
- What you can do
- Discover and connect to running Flutter debug apps and manage sessions over the Dart VM service, with explicit target selection when several are found. Capture UI snapshots, screenshots and view details, and inspect widgets at a point or dump semantics, render, layer and focus trees. Interact with the app through a snapshot-and-ref model: tap, long press, enter text, scroll, swipe, drag and reveal off-screen targets. Run hot reload or restart, optionally fused with a fresh capture and error report, and evaluate ad-hoc Dart expressions. Read app errors and recent logs, run diagnostics and runtime validation, and create or diff reproducible snapshots and bundles. Call dynamic client tools and,
- When to use it
- Useful when you are developing a Flutter app or game and want an assistant to look at the running UI, find and tap widgets, read errors and logs, or verify a change after hot reload. It is aimed at local debug builds, not production apps.
- Requirements
- Runs as a local process (container image published on ghcr.io) on a desktop machine, with the Flutter app in debug mode and its Dart VM service reachable, typically on localhost port 8181. The app must include the mcp_toolkit package and initialize the toolkit binding, otherwise inspection is blocked. On macOS, Screen Recording permission is needed for native window capture.
Installation
In SourceWeft
- Open Flutter MCP Toolkit in the dashboard and add it to a workspace.
- Enable the server for the chats that should use its tools.
Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.
Other MCP clients
Follow the launch instructions in the repository.
README
MCP Toolkit Server (Dart)
Migrating from v2.x
Tool names on MCP are prefixed with fmt_, binaries and mcpServers keys were renamed — see Migrating from v2.x to v3.0.
Architecture
This project now uses a shared core execution layer:
flutter-mcp-toolkitis the canonical command surface (connect, inspect, execute, diagnostics).fmtkis the short alias for the same CLI entrypoint.flutter-mcp-toolkit-serveris a thin MCP protocol adapter that maps MCP tool/resource calls to the same core executor.- MCP
tools/listnames use thefmt_capability prefix; CLIexec --nameuses command catalog names or aliases outside the MCPtools/callnamespace. Resource URIs are unchanged.
The shared core module is available as flutter_mcp_core inside this package.
Golden Path
Use this sequence first on macOS:
- Add
mcp_toolkitto the app and callMCPToolkitBinding.instance.bootstrapFlutter(...). - Launch the app in debug mode.
- Run
fmtk validate-runtime(or the canonical long formflutter-mcp-toolkit validate-runtime). - Query dynamic entries in this order:
fmt_list_client_tools_and_resources,fmt_client_tool,fmt_client_resource.
Treat exec as expert mode. validate-runtime is the default first-pass proof command.
CLI v3 Surface (Hard Cut)
The CLI is now agent-first and exposes a canonical interface:
exec --name <command> --args <json>schema [--name <command>]capabilitiesserve(JSON-RPC 2.0 over stdio)snapshot create --name <id> [--args <json>]snapshot diff --from <id> --to <id>bundle create --from-snapshot <id> [--output <dir>]doctor [--json] [--target <path>] [--timeout-ms <n>]permissions status|request|open-settings [--kind visual_capture]
Safe-write flags for write-producing commands:
snapshot create:--check --diff --backup --no-overwritebundle create:--check --diff --backup --no-overwrite
exec targets commands in the shared CommandCatalog (CLI command names may
be bare because they appear only after --name; the CLI is not the MCP
tools/call namespace):
connect, session_start, session_exec, session_end, diagnose, watch, explain_errors, status, discover_debug_apps, get_vm, get_extension_rpcs, hot_reload_flutter, hot_restart_flutter, get_active_ports, get_app_errors, get_screenshots, focus_window, get_view_details, inspect_widget_at_point, capture_ui_snapshot, debug_dump_layer_tree, debug_dump_semantics_tree, debug_dump_render_tree, debug_dump_focus_tree, fmt_list_client_tools_and_resources, fmt_client_tool, fmt_client_resource, dynamicRegistryStats, semantic_snapshot, tap_widget, long_press, enter_text, reveal_search, scroll, swipe, drag, hot_reload_and_capture, evaluate_dart_expression, get_recent_logs.
MCP names. When invoked via MCP
tools/call, exposed tools use thefmt_capability prefix (e.g.fmt_tap_widget,fmt_hot_reload_and_capture). The dynamic-registry host trio is exposed asfmt_list_client_tools_and_resources,fmt_client_tool, andfmt_client_resourcewhere enabled.dynamicRegistryStatsremains available from the CLI catalog for low-level diagnostics and is not part of the default MCP tool surface.
Interaction tools (catalog names: semantic_snapshot → tap_widget / enter_text / reveal_search / scroll / swipe / long_press / drag) follow a Playwright-style ref model: take a snapshot, then pass ref: "s_N" (and optional snapshotId for staleness detection) into the interaction tool. reveal_search is the bounded helper for off-screen semantic targets: it snapshots, matches one narrow selector, scrolls up to maxAttempts, and returns a fresh ref/snapshotId plus trace. hot_reload_and_capture fuses reload + screenshot + fresh snapshot + errors. evaluate_dart_expression runs an ad-hoc Dart expression against the app's root library. See docs/start_here/cli_quick_recipes.mdx and docs/guides/interaction_cookbook.mdx for the full surface and golden paths.
Packaged installs include both flutter-mcp-toolkit and fmtk; examples below use dart run for source-tree development. Prefer fmtk for compact local loops and keep flutter-mcp-toolkit in onboarding, install, PATH, and MCP config docs where the searchable canonical name helps.
CLI runs the same shared command catalog/executor as MCP. Preferred debugging path:
discover_debug_apps -> capture_ui_snapshot -> inspect_widget_at_point.
get_active_ports and dynamicRegistryStats remain available in CLI for low-level diagnostics, but are intentionally not MCP-exposed by default.
CLI Quick Use (v3)
CLI runtime gate for app inspection:
- Require
ext.mcp.toolkit.app_errors,ext.mcp.toolkit.view_details,ext.mcp.toolkit.view_screenshots, andext.mcp.toolkit.inspect_widget_at_pointfromget_extension_rpcs. - If missing, app-level screenshot/layout/error inspection is blocked until
mcp_toolkitis installed, initialized, and the app is hot restarted or rerun. - If screenshots show a black rectangle where a map/camera/web view should be, check
captureHintsonget_view_detailsor screenshot payloads (platformViewsDetectedorweakSignalsDetected). Usemode: desktop_window(or keepauto, which upgrades on macOS host when strong signals are present) instead offlutter_layer. - Host capture runs one automatic focus+capture recovery cycle on retryable failures (
desktopCaptureRetriedin the payload). You can also callfocus_windowthen retryget_screenshotswithdesktop_window. - If first explicit-URI connect times out, retry once and validate with
doctor --json --target <ws_uri> --timeout-ms 10000. - When
--output-diris set,validate-runtimemirrors its JSON envelope to<output-dir>/validate-runtime.jsonand screenshot files are written under<output-dir>/.mcp_screenshots/. validate-runtimetries hostdesktop_windowfirst whenautoselects it. Executor recovery retries focus+capture once (desktopCaptureRetried). Ifdesktop_windowstill fails, validate-runtime retries once withflutter_layer(including when platform views are detected, e.g. the showcaseAppKitView). Checkdata.summary.capturePlatformViewsDetected,captureFocusAttempted, andcaptureFallbackUsed. Web headful capture options: ADR 0007.
Visual Capture Permissions
doctorstays read-only. It now reportsvisual_capture_backend,visual_capture_permission,visual_capture_truth_mode, andapp_permission_bridge.- Interactive CLI capture flows default to
auto_request_onceforexec get_screenshots,exec capture_ui_snapshot, andvalidate-runtime. Raw command schemas still default tocheck_only. - macOS truthful capture is
desktop_window(including iOS Simulator and Chrome / web on a Mac host). Screen Recording permission belongs to the host process runningflutter-mcp-toolkit, not the Flutter app. Usepermissions requestfor the native prompt andpermissions open-settingsafter a denial. get_view_detailsandview_screenshotsincludecaptureHintswhen native platform views are detected (AndroidView,UiKitView,AppKitView,HtmlElementView,PlatformViewLink).TexturesetsweakSignalsDetectedwith a soft warning (noautoupgrade). Hybrid engines without platform views can useMCPToolkitBinding.captureHintsContributorin the app.- Image-only
get_screenshotsMCP responses include routing metadata inmetaand a leading JSON text block whencaptureHints/warningsare present. - Showcase Capture section:
AppKitViewon macOS (make showcase),HtmlElementViewon web (flutter run -d chrome). Usemake showcase-stopbefore a new macOS run. - Web (
chrome/web/web-server):desktop_windowuses macOS ScreenCaptureKit → Chrome CDP (Page.captureScreenshot) →flutter_layer. Global flags:--web-browser-debugging-port,--web-port. Opt-in live test:RUN_WEB_CDP_INTEGRATION=1 dart test test/web_cdp_integration_test.dart. See ADR 0007. - App-owned capture targets such as iOS/Android/Linux must have a reachable VM
target selected before
permissionsordoctorcan verify bridge-backed permission tools/resources. Use--target <ws_uri>or the global--vm-service-uri <ws_uri>when probing those platforms. desktop_windownever silently falls back.automay fall back toflutter_layer, but responses always reportrequestedMode,actualMode,permissionStatus, andfallbackReason.
Troubleshooting:
- If macOS capture is denied, rerun
flutter-mcp-toolkit permissions statusfirst. If status is stilldenied, open System Settings from the CLI and grant Screen Recording to the terminal or client process you are using. - If
doctor --jsonshowsvisual_capture_truth_mode=flutter_layeron macOS, you are not getting native window pixels yet. - If web
desktop_windowfails, useflutter_layeror pass--web-browser-debugging-portfrom Chrome’s--remote-debugging-port. For web targets, pass--flutter-device chromeonvalidate-runtime.validate-runtimestill retriesflutter_layerafter a faileddesktop_windoweven when platform views are detected. - If post-reload capture fails once on macOS desktop-window mode, that is usually a host capture race rather than an app failure.
validate-runtimeretries those failures before returning red, and may also retry withflutter_layerafter a faileddesktop_windowscreenshot.
Failure matrix:
missing_mcp_toolkit_wiring: app did not expose the required toolkit extensions. Fix app bootstrap and hot restart.bad_target_uri_or_unreachable_vm_service: explicit target URI is wrong or the VM service is not reachable.permission_denied: host capture backend lacks permission.host_capture_backend_instability: native capture backend flaked during desktop-window capture, usually around reload.
Migration (v2.x -> v3.0.0)
- Error metadata moved under
error.descriptor; do not parse legacy top-level fields. - Typed arguments are strict. String-encoded booleans/objects/lists/integers now fail validation.
- For write-producing automation, run with
--check --diffbefore actual writes. - Handle
write_blockedexplicitly when using--no-overwrite. - Add
flutter-mcp-toolkit doctor --jsonas preflight before VM-dependent execution.
Machine Envelope
One-shot commands return one JSON envelope with stable fields:
Failures use one strict envelope in error:
code, message, details, descriptor (category, retryable, exitCode, httpLikeStatus), recovery.
The full contract table is documented in docs/ai_agents/troubleshooting.mdx.
Daemon Protocol
serve runs JSON-RPC 2.0 over stdio. Key methods:
- requests:
initialize,capabilities/get,schema/get,command/execute,watch/start,watch/stop,snapshot/create,snapshot/diff,bundle/create,session/start,session/end - notifications:
watch/event,session/changed
Watch notifications are NDJSON JSON-RPC notifications with monotonic seq per watch.
Targeting contracts:
command/execute: optionalparams.args.connectionwatch/start: optionalparams.args.connection(applied once before watch loop starts)snapshot/create: per-step optionalargs.commands[i].args.connection
State + Locking
- State root defaults to
.flutter_mcp/ - state file:
.flutter_mcp/state.json - lock file:
.flutter_mcp/state.lock - snapshots:
.flutter_mcp/snapshots/ - bundles:
.flutter_mcp/bundles/
State operations use a lock with stale-lock TTL recovery to support concurrent agents safely.
Connection Resolution UX
The server keeps startup non-blocking and defers target lock until a VM-dependent call is executed.
Resolution policy for VM-dependent commands/resources:
- Reuse active connection if still healthy.
- Else reuse sticky target if it exists in current discovery results.
- Else auto-attach if exactly one target is discovered.
- Else fail with
connection_selection_requiredwhen multiple targets exist and no explicit target is provided.
Selection-required errors are returned as structured JSON so agents can retry immediately:
CLI one-shot and daemon calls use the same handshake semantics. For ambiguous multi-target sessions, retry with an explicit selector:
All VM-dependent MCP tools now accept optional arguments.connection:
Notes:
targetIdis the preferred selector and must be full VM websocket URI.- Legacy
host:porttarget IDs are rejected; use URI target IDs orconnection.uri. - Safest selector is
connection.uriwith exact Flutter machineapp.debugPort.wsUri. - If
targetIdlookup misses but URI is a full tokenized VM path (/<token>/ws), server attempts direct connect fallback. - CLI
exec --argsand daemoncommand/execute/watch/startaccept the same optional nestedconnectionobject. connect_debug_appaccepts the sameconnectionshape.- Dynamic registry tools (
fmt_list_client_tools_and_resources,fmt_client_tool,fmt_client_resource) accept the same optionalconnection. - Resource reads also support query targeting:
targetId,mode,host,port,uri,forceReconnect. - Flat top-level connection aliases like
host/port/uriin tool arguments are intentionally rejected by strict schemas. - For
connectandsession_start, native selector args (mode,targetId,host,port,uri,force) cannot be mixed with nestedconnection.
Zero-mistake recipe:
- Read machine
app.debugPort.wsUri. - Use
{"connection":{"uri":"<that exact wsUri>"}}. - If using
targetId, copy exactly fromavailableTargets/discover_debug_apps.
Flutter Web Discovery
Discovery order is:
- Flutter machine discovery (
flutter attach --machine) - Port-scan fallback
Both CLI and MCP server accept:
--flutter-project-dir--flutter-device(for examplechrome)--flutter-discovery-timeout-ms--scan-ports(for example8765-8767,9100)--prefer-target-label(for examplestaging)
The port scan recognizes dart/flutter processes. A desktop app hosts its VM
service inside its own native process and an app started with --no-dds has no
Dart process, so neither is found by name. Start such an app on a fixed VM
service port (flutter run -d macos --device-vmservice-port=8765) and pass that
port to the scanner with --scan-ports=8765.
When several debug apps run at once, let each name itself with
MCPToolkitBinding.instance.setAppIdentity(label: 'my_app · staging'):
discovery reports the label on every target, and --prefer-target-label lets
auto-attach pick one without the caller naming an endpoint. The label narrows
the candidates only at the auto-attach step, so an active connection and a
target connected to explicitly still win; a value that matches no running app
is ignored, so discovery keeps behaving as it would without it.
Manual fallback remains available:
- CLI:
--vm-service-uri ws://127.0.0.1:59490/<token>/ws - MCP tool/resource calls:
arguments.connection.uri
Quick Start
📦 Installation from GitHub (Currently Recommended)
For developers who want to contribute to the project or run the latest version directly from source, follow these steps:
-
Clone the repository:
-
Install and build dependencies:
This command installs all necessary dependencies listed in
pubspec.yamland then builds the MCP server. -
Add
mcp_toolkitPackage to Your Flutter App:The
mcp_toolkitpackage provides the necessary service extensions within your Flutter application. You need to add it to your app'spubspec.yaml.Run this command in your Flutter app's directory to add the
mcp_toolkitpackage:or add it to your
pubspec.yamlmanually:Then run
flutter pub getin your Flutter app's directory. -
Initialize in Your App: In your Flutter application's
main.dartfile (or equivalent entry point), initialize the bridge binding: -
Start your Flutter app in debug mode
Adjust
-dfor your device. Prefer the exactapp.debugPort.wsUrifrom machine output inarguments.connection.uriorconnection.targetId. -
🛠️ Add Flutter MCP Toolkit to your AI client
Recommended (skills + MCP config):
Skills only via the open Agent Skills ecosystem:
See docs/ai_agents/overview.mdx for install paths, lockfiles, and skills.sh.
Manual
mcpServersJSON (advanced — use ifinitis not an option):Use registry key
flutter-mcp-toolkitundermcpServers(canonical). The keyflutter-inspectoris legacy but still accepted if your config predates the rename. That string is only amcpServersid — it is not the Claude Code subagent name. The bundled runtime subagent isflutter-mcp-toolkit-runtime(plugin/agents/flutter-mcp-toolkit-runtime.md).Recommended server args:
--resources,--images,--dynamics(defaults are on for resources/images;--dynamicsenables the dynamic registry).Note for Local Development (GitHub Install):
If you installed from GitHub and built locally, point
commandatmcp_server_dart/build/flutter-mcp-toolkit-server. See Installation from GitHub above.Cline Setup
- Add to your
.cline/config.json: - Restart Cline
- The Flutter MCP toolkit tools will be available in your conversations
- Try: "Please get a screenshot of my app" (MCP tools use the
fmt_prefix, e.g.fmt_get_screenshots)
Cursor Setup
Badge
Install the server (edit the path in Cursor after clicking):
Note: fix
commandpath after installation.Manual Setup
-
Open Cursor's settings
-
Go to the Features tab
-
Under "Model Context Protocol", add the server:
-
Restart Cursor
-
Open Agent Panel (cmd + L on macOS)
-
Tool calls use
fmt_*names on the MCP wire (e.g.fmt_capture_ui_snapshot).
Claude Setup
- Add to your Claude configuration file:
- Restart Claude
- The Flutter MCP toolkit tools will be available
- Try: "Please get screenshot of my app"
- Add to your
Development
Command Line Options
Image File Saving Mode
When --save-images is enabled, the server will:
- Save all captured screenshots as PNG files in a
.mcp_screenshotsfolder in the current working directory - Return file URLs (
file://) instead of base64 encoded image data - Automatically clean up screenshots older than 24 hours
- Use timestamped filenames like
screenshot-2025-01-27T10-30-15.123Z.png
This mode is useful when:
- Working with AI tools that prefer file references over base64 data
- Needing to persist screenshots for later analysis
- Reducing memory usage by avoiding large base64 strings in responses
Basic Usage
-
Start your Flutter app in debug mode:
-
Run the MCP server:
Source: mcp_server_dart/README.md at commit b3e278c
Tools
0Version history
4- v7.0.1LatestOct 17, 2026
- v7.0.0Oct 3, 2026
- v6.0.0Oct 3, 2026
- v5.1.0Sep 16, 2026
Score
50% of the applicable checks met
How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.
- Reached in the last 30 days25 pts
Keep the endpoint answering the MCP handshake; SourceWeft probes it every 30 days.
- Auth declared10 pts
Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.
- Tools listed15 pts
Answer tools/list without a credential, or ship a package that starts in a sandbox without one.
- DescriptionRequired15 pts
- Logo10 pts
- Documentation15 pts
- License10 pts