flutter_profile_mcp 1.0.5
flutter_profile_mcp: ^1.0.5 copied to clipboard
MCP server for Flutter performance profiling — 27 AI-queryable tools via vm_service. Ask Claude why your app is slow.
flutter_profile_mcp #
An MCP (Model Context Protocol) server that connects to a running Flutter app via
vm_serviceand exposes 27 performance, memory, and debugging tools as AI-queryable actions.
Ask Claude or Gemini "why is my app slow?" and get an actual diagnosis — not generic advice.
What it does #
Flutter DevTools is powerful but hard to use. This MCP server bridges the gap: it speaks directly to the Dart VM, collects the same data DevTools collects, and translates it into plain English that an AI agent can reason about and explain.
You: "Why is my app slow?"
AI: [calls connect_to_app]
Connected. VM 3.11 | isolate: main | debug mode | iOS arm64
[calls capture_frame_timing duration=5]
Frame Analysis — 198 frames (~38.4 fps) via Flutter.Frame events
Budget: 16ms at 60fps
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Janky: 0/198 (0.0%) — GOOD
Worst frame: 4.54ms work (Build: 2.92ms, Raster: 1.61ms)
[calls get_widget_rebuild_counts duration=8]
Widget Rebuild Counts:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Text (product_list.dart:142) 62 rebuilds ← EXCESSIVE
SizedBox (product_list.dart:98) 60 rebuilds ← EXCESSIVE
SlideTransition (home_screen.dart:31) 29 rebuilds ← HIGH
BlocProvider (main.dart:44) 26 rebuilds ← HIGH
Animation widgets rebuilding (possible idle animation leak):
SlideTransition (home_screen.dart:31): 29 rebuilds
→ ensure AnimationController.dispose() called
[calls get_cpu_hotspots duration=5]
CPU Hotspots (5.0s window, 678 samples)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. 1.6% 13.3% RenderObject._paintWithContext
2. 1.1% 1.3% Duration.Duration
Suggestions:
• RenderObject._paintWithContext: 13.3% total — expensive call chain. Check callees.
Requirements #
- Flutter app running in debug or profile mode (
flutter runorflutter run --profile) - Dart SDK ≥ 3.4.0
- Any MCP-compatible client (Claude Desktop, Claude Code, Gemini CLI, etc.)
Installation #
Option A — pub.dev (recommended, no git clone needed) #
dart pub global activate flutter_profile_mcp
This installs the flutter-profile-mcp command globally. Use this path in your MCP config:
which flutter-profile-mcp
# e.g. /Users/you/.pub-cache/bin/flutter-profile-mcp
Option B — compile from source #
git clone https://github.com/cybersleuth0/flutter-profile-mcp
cd flutter-profile-mcp
dart pub get
dart compile exe bin/flutter_devtools_mcp.dart -o flutter_devtools_mcp
Option C — run directly with Dart #
git clone https://github.com/cybersleuth0/flutter-profile-mcp
cd flutter-profile-mcp
dart pub get
Claude Desktop setup #
Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS):
{
"mcpServers": {
"flutter-profile": {
"command": "flutter-profile-mcp"
}
}
}
Note:
flutter-profile-mcpmust be on your PATH. Rundart pub global activate flutter_profile_mcpfirst, then verify withwhich flutter-profile-mcp.
Restart Claude Desktop after editing.
Claude Code / Gemini CLI setup #
Add to your project's .claude/settings.json or ~/.gemini/settings.json:
{
"mcpServers": {
"flutter-profile": {
"command": "flutter-profile-mcp"
}
}
}
Usage #
- Run your Flutter app:
flutter run - Copy the VM service URI from terminal output — looks like
ws://127.0.0.1:PORT/TOKEN=/ws - Tell the AI: "Connect to my Flutter app at
<uri>" - Ask anything:
- "Why is my app slow? Capture 5 seconds while I scroll."
- "Which widgets rebuild too often?"
- "Are there any memory leaks?"
- "Show me recent HTTP requests."
- "What errors appeared in the last 5 seconds?"
Tools (27) #
Connection #
| Tool | Description |
|---|---|
connect_to_app |
Connect to running Flutter app via VM service URI |
get_app_info |
Flutter/Dart version, build mode, isolates, all registered service extensions |
Performance #
| Tool | Description |
|---|---|
capture_frame_timing |
Record frame times via Flutter.Frame stream, detect jank (>16ms), identify UI vs raster bottleneck |
get_cpu_hotspots |
CPU profile — top Dart functions by self-time and call-chain cost, with fix suggestions |
get_widget_rebuild_counts |
Track which widgets rebuild excessively with file:line context — the #1 cause of jank |
analyze_jank_causes |
Composite: frames + CPU → synthesized verdict + prioritized diagnosis |
enable_performance_overlay |
Toggle on-screen GPU/UI thread bars |
debug_frame_events |
Inspect raw timeline event names — use when frame capture returns 0 frames |
Memory #
| Tool | Description |
|---|---|
get_memory_usage |
Heap usage + top allocating classes |
get_memory_timeline |
Record heap + GC events over N seconds — detects growing heap |
force_gc |
Trigger GC, compare before/after — high retained = leak signal |
diff_memory_snapshots |
Snapshot A → interact → snapshot B → show class growers |
find_memory_leaks |
Automated: GC → baseline → observe → GC → measure → leak candidates |
get_class_instances |
Instance count + size for any class by name |
watch_gc_pressure |
GC rate + avg pause → NORMAL / ELEVATED / CRITICAL verdict |
explain_memory_breakdown |
RSS vs Dart heap vs external vs raster in plain English |
disable_http_logging |
Disable HTTP logging to reduce memory overhead during profiling |
Logging #
| Tool | Description |
|---|---|
watch_logs |
Stream stdout/stderr/debugPrint for N seconds with optional filter |
get_error_logs |
Capture N seconds of output, return only error/exception lines |
Network #
| Tool | Description |
|---|---|
get_http_profile |
Recent HTTP requests with method, status, timing, size |
watch_network |
Live-stream new HTTP requests as they happen |
get_http_request_body |
Full request/response headers for a specific request ID |
Navigation & Isolates #
| Tool | Description |
|---|---|
get_navigation_stack |
Current route + full navigation stack — detect route leaks |
list_isolates |
All running isolates with heap usage |
Visual Debugging #
| Tool | Description |
|---|---|
toggle_visual_debug |
debug_paint (widget bounds) + repaint_rainbow (overdraw detection) |
Code Evaluation #
| Tool | Description |
|---|---|
eval_expression |
Evaluate Dart expression in live app context |
Developer Workflow #
| Tool | Description |
|---|---|
hot_reload |
Trigger hot reload — apply source changes without restarting |
get_widget_tree |
Full widget hierarchy as readable indented tree |
Debug vs Profile mode #
| Mode | Command | What works |
|---|---|---|
| Debug | flutter run |
All 27 tools including widget inspector, rebuild counts |
| Profile | flutter run --profile |
Performance tools (accurate numbers, no debug overhead) |
| Release | flutter run --release |
Nothing — VM service not available |
For accurate frame/CPU numbers, use profile mode. For widget tree and rebuild tracking, use debug mode.
How frame timing works #
capture_frame_timing uses the Flutter.Frame extension event stream — the same source as Flutter DevTools' Performance tab. Flutter emits one event per frame containing pre-computed build, raster, and elapsed (wall time including vsync wait) in microseconds.
Jank is measured on build + raster (actual CPU/GPU work), not elapsed. elapsed always includes vsync idle time (~16ms at 60fps) which would make every frame appear janky.
Architecture #
flutter-profile-mcp/
├── bin/
│ └── flutter_devtools_mcp.dart # Entry point — stdio MCP transport
├── lib/
│ ├── server.dart # MCPServer — all 27 tools registered
│ └── analysis/
│ ├── jank_analyzer.dart # Flutter.Frame stream → frame data → jank report
│ ├── cpu_analyzer.dart # CpuSamples → hotspot report (handles dynamic fn field)
│ └── rebuild_collector.dart # RebuiltWidgets events → rebuild counts with file:line
Built with:
dart_mcp— MCP server protocolvm_service— Dart VM service client
Contributing #
Tool ideas, bug reports, and PRs welcome.
To add a new tool:
- Register it in
_registerTools()inlib/server.dart - Add a
_handleXxx()handler method - Use
_service!.callServiceExtension()for Flutter extensions or directVmServicemethods - Return
_ok(text)on success,_err(e)on failure
License #
MIT — see LICENSE