Start
Five minutes from a plain Flutter app to an agent that taps through it. This page covers apps built from Material widgets; a custom design system adds one step, in Configure.
How it fits together
Marionette has two halves. A package in your app opens it to the agent through the Dart VM service, the same channel Flutter DevTools uses. A bridge, the MCP server or the CLI, turns the agent’s tool calls into actions in the app.
Claude Code, Cursor, Codex, …
marionette_mcp, or the marionette CLI
marionette_flutter and its binding
The app always needs the package. For the bridge, pick either one: both see and drive the app, and both write the same session reports.
Add the package
Add marionette_flutter to the app, then initialize MarionetteBinding in main(), in debug builds only. For standard Material widgets the defaults are enough.
flutter pub add marionette_flutter
void main() {
if (kDebugMode) {
MarionetteBinding.ensureInitialized();
} else {
WidgetsFlutterBinding.ensureInitialized();
}
runApp(const MyApp());
}
Give your agent the tools
Pick the bridge you prefer. Both see and drive the app, and both write the same session reports.
MCP server
Your agent calls Marionette’s tools. Install the server once, then register it with your agent.
dart pub global activate marionette_mcp
claude mcp add --transport stdio marionette -- marionette_mcp
codex mcp add marionette -- marionette_mcp
{
"mcpServers": {
"marionette": { "command": "marionette_mcp", "args": [] }
}
}
gemini mcp add marionette marionette_mcp
copilot mcp add marionette -- marionette_mcp
{
"servers": {
"marionette": { "command": "marionette_mcp", "args": [] }
}
}
{
"mcpServers": {
"marionette": { "command": "marionette_mcp", "args": [] }
}
}
Prefer a dev dependency to a global tool? Run dart pub add dev:marionette_mcp, and register
dart run marionette_mcp as the server command.
CLI
Your agent runs marionette commands in its shell. Install the CLI once; the Agent Skills below teach the agent its commands.
dart pub global activate marionette_cli
Add the Agent Skills
marionette_flutter ships three Agent Skills: one prepares an app for Marionette, one drives it with either bridge and writes the report, and one turns a verified run into Patrol tests. This documentation then does not have to be in its context. Dart’s package skills tooling installs them into the folder your agent reads.
$ flutter pub add marionette_flutter # if it is not a dependency yet
$ dart run skills@ get
Without the Dart toolchain, npx skills add leancodepl/marionette_mcp reads them straight from GitHub. Run the install again after upgrading the package.
Run the app
Start the app in debug mode. Among the first lines, flutter run prints the VM service URI. The agent needs the
ws://…/ws part.
$ flutter run
…
A Dart VM Service on sdk gphone64 x86 64 is available at: http://127.0.0.1:9101/V3N5aBc=/
The Flutter DevTools debugger and profiler on sdk gphone64 x86 64 is available at:
http://127.0.0.1:9101/V3N5aBc=/devtools/?uri=ws://127.0.0.1:9101/V3N5aBc=/ws
Paste that URI into the prompt yourself, or ask the agent to run the app: it starts flutter run, reads the URI from the output, and connects.
The first prompt
Give the agent a task:
Connect to ws://127.0.0.1:9101/V3N5aBc=/ws. Open the login screen, sign in
with test@example.com, and check the logs that the sign-in request fired.
Run the app with flutter run and connect to it. Open the login screen, sign
in with test@example.com, and check the logs that the sign-in request fired.
The agent calls connect, then get_interactive_elements to see the screen, then
tap and enter_text with the keys or the text it found, then get_logs
for the proof. That is the whole loop: look, act, look again.
For a real task, name the screen, the precondition and the goal. Drive has prompts for common jobs.
Try the example app first
The repository has an example app that is already set up: a custom design system with its configuration, log collection, session reports, device config and a custom navigation extension. It is the lowest risk first run.
$ git clone https://github.com/leancodepl/marionette_mcp
$ cd marionette_mcp/example
$ flutter run
Connect to <the ws:// URI from flutter run>. Open the Custom Widgets screen
and list what you see. Which of the design-system widgets can you tap?
Is it working?
-
connectanswers with a success message. A version mismatch meansmarionette_mcpandmarionette_flutterdiffer: upgrade both. -
get_interactive_elementslists your buttons and fields. If your own widgets are missing, the configuration in Configure is the fix, not a bug. -
tapchanges the screen, and a secondget_interactive_elementsshows the new one. -
get_logsreturns lines. If it explains how to enable a log collector instead, wire one up in Configure.
FAQ
Does it work in release builds?
No, by design. Marionette reaches the app through the Dart VM service, which exists only in debug and profile builds. Gate the binding on
kDebugMode, or on !kReleaseMode to include profile builds, and nothing of it reaches the release binary.
Which agents does it work with?
Any agent with MCP support, such as Claude Code, Codex, Cursor, Gemini CLI, Copilot or Antigravity, through the MCP server. Any agent that runs shell commands, through the
marionette CLI. Most agents can use either.
Do I have to change my widgets?
Not for Flutter's own widgets. A custom design system needs isInteractiveElement, and usually
extractText, in the configuration. A ValueKey or a Semantics(identifier:)
gives the agent a stable target.
Does it replace integration tests or Patrol?
No. Its gestures simulate a user on a best-effort basis, which is right for an agent checking its own work. For a suite that must pass or fail the same way on every CI run, use Patrol.
How does the agent find my app?
You give it the ws:// VM service URI that flutter run prints, for example ws://127.0.0.1:9101/ws. Pasting it into the prompt is the most reliable way.
connect fails with a version mismatch.
connect fails with a version mismatch.
marionette_mcp checks that the app runs the same version of marionette_flutter. Upgrade both packages together.
Is it free?
Yes. Marionette is open source under the Apache 2.0 license and maintained by LeanCode.