Skip to content

MCP Server

FlutterProbe ships an MCP (Model Context Protocol) server as a standalone binary called probe-mcp that exposes your entire test suite as tools callable by AI agents. Once connected, Claude Desktop, Cursor, or any MCP-compatible client can manage devices, write and run tests, record interactions, generate reports, and inspect results — all without leaving the AI chat.

As of v0.6.0, the MCP server is a separate binary probe-mcp. The legacy probe mcp-server subcommand still works but prints a deprecation notice on stderr. Update your MCP client configuration to point at probe-mcp directly.

ToolDescription
list_devicesList booted/connected simulators, emulators, and physical devices (id, name, platform, state, OS version)
list_simulatorsList all iOS simulators (booted + shutdown) so the agent can pick one to boot
list_avdsList Android Virtual Device names available to launch
start_deviceBoot an Android emulator (by AVD name) or iOS simulator (by UDID); blocks until online
shutdown_deviceShut down an iOS simulator (udid) or Android emulator (serial)
ToolDescription
get_widget_treeDump the live Flutter widget tree from the running app
take_screenshotCapture the current screen and return it as an image
read_testRead the contents of a .probe file
write_testCreate or overwrite a .probe file — content is validated before writing; syntax errors are returned without creating the file
run_scriptExecute inline ProbeScript without creating a file
run_testsRun .probe test files (supports composite multi-device tests via composite_devices)
list_filesList all .probe files in a directory
lintValidate .probe file syntax without running
recordRecord user interactions and generate a .probe test file (runs for timeout duration, default 30s)

get_widget_tree, take_screenshot, run_script, and run_tests accept an optional device argument (serial or UDID) to pin a specific target.

ToolDescription
get_reportRead the most recently modified JSON test run report
generate_reportGenerate a standalone HTML report from a JSON results file
generate_testAI-generate a .probe test from a natural language prompt
ToolDescription
init_projectInitialize a new FlutterProbe project (creates probe.yaml and tests/ scaffold)

The full workflow this enables: list_devicesstart_device (if needed) → get_widget_treewrite_testrun_testsget_reportgenerate_report — a complete AI-driven test authoring loop, including device bring-up and HTML reporting.

The run_tests tool has named parameters for common options (paths, tag, device, composite_devices) and a flags string for everything else. Key flags an agent should know:

FlagWhat it does
--timeout 60sPer-step timeout (default 30s)
-vVerbose step output — prints → step before each step and ✓/✗ step (Xs) after; slow steps (>5s) emit progress ticks and a warning at 80% of timeout. Recommended when diagnosing failures.
--format jsonStructured JSON results (pipe to get_report)
--format junitJUnit XML for CI systems
--dry-runValidate syntax without a device connection
--parallelDistribute tests across all connected devices
--shard 1/3Run 1/3 of test files (for CI matrix builds)
--host <ip> --token <t>WiFi mode for physical devices
--disable-animationsSet timeDilation=0 for faster tests
-yAuto-approve destructive operations (CI mode)
--videoRecord device screen during the run
--streamEmit one ndjson line per test as it completes (requires --format json)

Tip for agents: pass -v in flags when a test is failing and you need to understand which step is slow or stuck. The progress ticks and timeout warnings appear in run_tests output and tell you exactly where time is being spent before the failure.

write_test supports the full composite test syntax for coordinating multiple devices:

composite test "alice sends bob a message"
devices
A: iPhone 15 Simulator
B: Pixel 9 Emulator
A:
tap "New Message"
type "Hello Bob" in "compose"
tap "Send"
sync "message sent"
B:
wait until "Hello Bob" appears
see "Hello Bob"

Pass device connections to run_tests via composite_devices (space-separated ALIAS=SPEC pairs):

  • WiFi: "A=192.168.1.10:48686/token"
  • iOS simulator: "B=A1B2C3D4-E5F6-..."
  • Android: "C=emulator-5554"

Or configure them in probe.yaml under composite.devices.

Annotation-driven tests (flutter_probe_annotation + flutter_probe_gen)

Section titled “Annotation-driven tests (flutter_probe_annotation + flutter_probe_gen)”

When the user’s Flutter project uses the new annotation packages (flutter_probe_annotation for the DSL and flutter_probe_gen for the build_runner generator), .probe test files appear under tests/generated/ after dart run build_runner build. The MCP run_tests tool runs them like any other .probe file — pass tests/ as the paths argument.

For agents authoring tests in this style:

  • Don’t use write_test to write to tests/generated/ directly — those files are regenerated. Use write_test to author the annotated Dart source instead (the screen class with @ProbeSuite).
  • After the user runs dart run build_runner build, call run_tests as usual. The generated .probe files are picked up automatically.
  • read_test works on either hand-written or generated files.
  • Flutter app running with --dart-define=PROBE_AGENT=true (for live tools like get_widget_tree, take_screenshot, run_tests)
  • An MCP-compatible client (Claude Desktop, Cursor, etc.)
  • For Option 2 below: probe-mcp binary v0.9.0+ installed and in PATH
Section titled “Install — Option 1: one-click Claude Desktop Extension (recommended)”

As of v0.9.4, every release includes a .mcpb Claude Desktop Extension that bundles the probe-mcp binary. Installation is one click — no brew, no JSON config, no PATH setup.

  1. Open the latest GitHub release and download the bundle for your platform:
    • flutter-probe-darwin-arm64.mcpb — Apple Silicon Macs
    • flutter-probe-darwin-amd64.mcpb — Intel Macs
    • flutter-probe-linux-amd64.mcpb — Linux x86_64
    • flutter-probe-win32-amd64.mcpb — Windows x86_64
  2. In Claude Desktop, open Settings → Extensions and click Install Extension.
  3. Pick the downloaded .mcpb file. When prompted, select your Flutter project directory (the folder containing probe.yaml and tests/).
  4. Done — all 18 tools are immediately available in any new Claude conversation.

Auto-updates and lifecycle are handled by Claude Desktop. To update, just install a newer .mcpb over the older one.

Install — Option 2: manual MCP server config

Section titled “Install — Option 2: manual MCP server config”

Use this path for Cursor, Claude Code, or any MCP-compatible client other than Claude Desktop, or if you prefer to keep the binary on $PATH.

Verify the binary is accessible:

Terminal window
which probe-mcp # should print /opt/homebrew/bin/probe-mcp or similar

Edit ~/Library/Application Support/Claude/claude_desktop_config.json:

{
"mcpServers": {
"flutter-probe": {
"command": "probe-mcp"
}
}
}

If probe-mcp is not in your shell PATH (common when Claude Desktop doesn’t inherit your shell environment), use the absolute path:

{
"mcpServers": {
"flutter-probe": {
"command": "/opt/homebrew/bin/probe-mcp"
}
}
}

Find the absolute path with which probe-mcp.

Edit %APPDATA%\Claude\claude_desktop_config.json:

{
"mcpServers": {
"flutter-probe": {
"command": "probe-mcp.exe"
}
}
}

After editing the config, restart Claude Desktop. The flutter-probe tools appear in the tool picker (hammer icon) in any new conversation.

In Cursor, open Settings → MCP (or edit .cursor/mcp.json at the repo root):

{
"mcpServers": {
"flutter-probe": {
"command": "probe-mcp"
}
}
}

Restart Cursor after saving.

The MCP server inherits the working directory from the client. For tools like run_tests, list_files, and get_report to find your test files, the working directory must be your Flutter project root (the folder containing probe.yaml and tests/).

Claude Desktop launches the server with its own working directory, which may not be your project. Set it explicitly:

{
"mcpServers": {
"flutter-probe": {
"command": "probe-mcp",
"cwd": "/Users/you/dev/my-flutter-app"
}
}
}

Test the server manually in your terminal:

Terminal window
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' | probe-mcp

Expected response:

{"jsonrpc":"2.0","id":1,"result":{"capabilities":{"tools":{}},"protocolVersion":"2024-11-05","serverInfo":{"name":"probe-mcp","version":"0.9.8"}}}

List all available tools:

Terminal window
echo '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' | probe-mcp

“Look at the widget tree and write a test that verifies the login flow works.”

  1. get_widget_tree — inspect the running app’s UI
  2. take_screenshot — see what is on screen
  3. write_test — create tests/login.probe (content validated before writing)
  4. run_tests — execute it
  5. get_report — verify all steps passed

“Boot an iOS simulator and run the smoke tests on it.”

  1. list_simulators — discover available UDIDs
  2. start_device with {platform: "ios", udid: "<chosen>"}
  3. list_devices — confirm it came online
  4. run_tests with {tag: "smoke", device: "<udid>"}

“Write a test that verifies push notifications are delivered between two simulators.”

  1. list_simulators — discover two available iOS simulators
  2. start_device for each if needed
  3. get_widget_tree on both devices (using the device argument) to understand the UI
  4. write_test — create a composite test block with device aliases and sync barriers
  5. run_tests with composite_devices: "A=<udid1> B=<udid2>"
  6. get_report — inspect per-device pass/fail results
  7. generate_report — produce a shareable HTML report

“Record my interactions for 30 seconds and turn them into a reusable test.”

  1. record with {timeout: "30s", output: "tests/recorded.probe"} — returns the generated file
  2. lint on the recorded file to check for issues
  3. write_test to clean up and refine the generated steps
  4. run_tests to verify the refined test passes

“The CI run produced JSON results. Generate a report I can share.”

  1. get_report — reads the most recently modified JSON in reports/
  2. generate_report — produces reports/report.html

Change:

{ "command": "probe", "args": ["mcp-server"] }

to:

{ "command": "probe-mcp" }

The tools, protocol, and behavior are identical. The legacy form continues to work but prints a deprecation notice.

  • Restart Claude Desktop after editing the config
  • Verify the JSON is valid (no trailing commas)
  • Check Claude Desktop logs: ~/Library/Logs/Claude/

Claude Desktop may not inherit your shell PATH. Use the absolute binary path:

Terminal window
which probe-mcp # copy this output

Then set "command": "/absolute/path/to/probe-mcp" in the config.

get_widget_tree / take_screenshot return errors

Section titled “get_widget_tree / take_screenshot return errors”

These tools require the Flutter app to be running and connected to the probe agent. Start the app first:

Terminal window
flutter run --dart-define=PROBE_AGENT=true

Then confirm the agent is reachable:

Terminal window
probe test --dry-run

The content you provided failed ProbeScript validation. The file was not created. Check the error message for the line and column of the problem. Common issues:

  • Unterminated strings (" without closing ")
  • Wrong indentation (use 2 spaces, not tabs)
  • Unknown step keywords

Run lint on a corrected version to verify before calling write_test again.

Recording requires a WebSocket-connected device (simulators or emulators). It does not work over HTTP (physical-device WiFi mode). Ensure the device is a simulator or emulator and the app is running.