LogoSkills

flutter-inspector Templates

Templates for custom inspector tool registration and debugging patterns.

Flutter Inspector Templates#

Templates for custom inspector tool registration and debugging patterns.

Template A: Custom BLoC Inspector Tool#

Register a custom tool for inspecting BLoC state

lib/debug/bloc_inspector_tool.dart#

import 'package:flutter/foundation.dart';
import 'package:mcp_toolkit/mcp_toolkit.dart';

/// Register BLoC state inspection tools
void registerBlocInspectorTools() {
  if (!kDebugMode) return;

  // Query all BLoC list
  addMcpTool(MCPCallEntry.tool(
    handler: (params) {
      final blocs = _getAllRegisteredBlocs();
      return MCPCallResult(
        message: '${blocs.length} BLoCs are registered',
        parameters: {
          'blocs': blocs.map((b) => {
            'name': b.runtimeType.toString(),
            'state': b.state.runtimeType.toString(),
          }).toList(),
        },
      );
    },
    definition: MCPToolDefinition(
      name: 'bloc_get_all',
      description: 'Return all registered BLoC/Cubit instances',
      inputSchema: {'type': 'object', 'properties': {}},
    ),
  ));

  // Query specific BLoC state
  addMcpTool(MCPCallEntry.tool(
    handler: (params) {
      final blocName = params['blocName'] as String?;
      if (blocName == null) {
        return MCPCallResult(
          message: 'blocName parameter is required',
          parameters: {'error': true},
        );
      }

      final bloc = _findBlocByName(blocName);
      if (bloc == null) {
        return MCPCallResult(
          message: 'Cannot find $blocName',
          parameters: {'error': true},
        );
      }

      return MCPCallResult(
        message: '$blocName state query complete',
        parameters: {
          'blocName': blocName,
          'state': _serializeState(bloc.state),
        },
      );
    },
    definition: MCPToolDefinition(
      name: 'bloc_get_state',
      description: 'Return current state of a specific BLoC',
      inputSchema: {
        'type': 'object',
        'properties': {
          'blocName': {
            'type': 'string',
            'description': 'BLoC class name',
          },
        },
        'required': ['blocName'],
      },
    ),
  ));
}

Template B: Navigation Inspector Tool#

GoRouter navigation inspection tool

lib/debug/nav_inspector_tool.dart#

import 'package:flutter/foundation.dart';
import 'package:go_router/go_router.dart';
import 'package:mcp_toolkit/mcp_toolkit.dart';

/// Register navigation inspector tools
void registerNavInspectorTools(GoRouter router) {
  if (!kDebugMode) return;

  // Query current route
  addMcpTool(MCPCallEntry.tool(
    handler: (params) {
      final config = router.routerDelegate.currentConfiguration;
      final location = config.uri.toString();

      return MCPCallResult(
        message: 'Current route: $location',
        parameters: {
          'route': {
            'path': location,
            'pathParameters': config.pathParameters,
            'queryParameters': config.uri.queryParameters,
          },
        },
      );
    },
    definition: MCPToolDefinition(
      name: 'nav_get_current_route',
      description: 'Return currently active route info',
      inputSchema: {'type': 'object', 'properties': {}},
    ),
  ));

  // Deep link test
  addMcpTool(MCPCallEntry.tool(
    handler: (params) {
      final uri = params['uri'] as String?;
      if (uri == null) {
        return MCPCallResult(
          message: 'uri parameter is required',
          parameters: {'error': true},
        );
      }

      try {
        final parsedUri = Uri.parse(uri);
        final match = router.configuration.findMatch(parsedUri);

        return MCPCallResult(
          message: 'Deep link matching successful',
          parameters: {
            'uri': uri,
            'matched': match != null,
            'route': match?.route.path,
            'params': match?.pathParameters,
          },
        );
      } catch (e) {
        return MCPCallResult(
          message: 'Deep link parsing failed: $e',
          parameters: {'error': true},
        );
      }
    },
    definition: MCPToolDefinition(
      name: 'nav_test_deep_link',
      description: 'Test a deep link URI and return matching route',
      inputSchema: {
        'type': 'object',
        'properties': {
          'uri': {
            'type': 'string',
            'description': 'Deep link URI to test',
          },
        },
        'required': ['uri'],
      },
    ),
  ));
}

Template C: Network Inspector Tool#

HTTP request logging tool

lib/debug/network_inspector_tool.dart#

import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:mcp_toolkit/mcp_toolkit.dart';

/// Network log store
class NetworkLogStore {
  static final List<Map<String, dynamic>> _logs = [];
  static const int maxLogs = 100;

  static void addLog(Map<String, dynamic> log) {
    _logs.add(log);
    if (_logs.length > maxLogs) {
      _logs.removeAt(0);
    }
  }

  static List<Map<String, dynamic>> getLogs({
    int? limit,
    String? statusFilter,
  }) {
    var result = _logs.reversed.toList();

    if (statusFilter != null) {
      result = result.where((log) {
        final status = log['status'] as int?;
        if (status == null) return false;
        return status.toString().startsWith(statusFilter[0]);
      }).toList();
    }

    if (limit != null) {
      result = result.take(limit).toList();
    }

    return result;
  }

  static void clear() => _logs.clear();
}

/// Dio interceptor
class NetworkInspectorInterceptor extends Interceptor {
  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    options.extra['startTime'] = DateTime.now();
    handler.next(options);
  }

  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    _logRequest(response.requestOptions, response.statusCode, response.data);
    handler.next(response);
  }

  @override
  void onError(DioException err, ErrorInterceptorHandler handler) {
    _logRequest(err.requestOptions, err.response?.statusCode, err.message);
    handler.next(err);
  }

  void _logRequest(RequestOptions options, int? status, dynamic data) {
    final startTime = options.extra['startTime'] as DateTime?;
    final duration = startTime != null
        ? DateTime.now().difference(startTime).inMilliseconds
        : null;

    NetworkLogStore.addLog({
      'timestamp': DateTime.now().toIso8601String(),
      'method': options.method,
      'url': options.uri.toString(),
      'status': status,
      'duration': duration,
    });
  }
}

/// Register network inspector tools
void registerNetworkInspectorTools() {
  if (!kDebugMode) return;

  addMcpTool(MCPCallEntry.tool(
    handler: (params) {
      final limit = params['limit'] as int? ?? 50;
      final status = params['status'] as String?;

      final logs = NetworkLogStore.getLogs(limit: limit, statusFilter: status);

      return MCPCallResult(
        message: '${logs.length} network logs',
        parameters: {'logs': logs},
      );
    },
    definition: MCPToolDefinition(
      name: 'network_get_logs',
      description: 'HTTP request/response log query',
      inputSchema: {
        'type': 'object',
        'properties': {
          'limit': {'type': 'integer', 'description': 'Maximum count'},
          'status': {'type': 'string', 'description': 'Status filter (2xx, 4xx, 5xx)'},
        },
      },
    ),
  ));

  addMcpTool(MCPCallEntry.tool(
    handler: (params) {
      NetworkLogStore.clear();
      return MCPCallResult(
        message: 'Network logs have been cleared',
        parameters: {'success': true},
      );
    },
    definition: MCPToolDefinition(
      name: 'network_clear_logs',
      description: 'Clear network logs',
      inputSchema: {'type': 'object', 'properties': {}},
    ),
  ));
}

Template D: Image Cache Inspector Tool#

Image cache analysis tool

lib/debug/image_inspector_tool.dart#

import 'package:flutter/foundation.dart';
import 'package:flutter/painting.dart';
import 'package:mcp_toolkit/mcp_toolkit.dart';

/// Register image cache inspector tools
void registerImageInspectorTools() {
  if (!kDebugMode) return;

  addMcpTool(MCPCallEntry.tool(
    handler: (params) {
      final cache = PaintingBinding.instance.imageCache;

      return MCPCallResult(
        message: 'Image cache statistics',
        parameters: {
          'cache': {
            'currentSize': cache.currentSize,
            'currentSizeFormatted': _formatBytes(cache.currentSize),
            'maximumSize': cache.maximumSize,
            'maximumSizeFormatted': _formatBytes(cache.maximumSize),
            'usagePercent': (cache.currentSize / cache.maximumSize * 100).round(),
            'liveImageCount': cache.liveImageCount,
            'pendingImageCount': cache.pendingImageCount,
          },
        },
      );
    },
    definition: MCPToolDefinition(
      name: 'img_get_cache_stats',
      description: 'Return image cache statistics',
      inputSchema: {'type': 'object', 'properties': {}},
    ),
  ));

  addMcpTool(MCPCallEntry.tool(
    handler: (params) {
      final type = params['type'] as String? ?? 'all';
      final cache = PaintingBinding.instance.imageCache;

      switch (type) {
        case 'all':
          cache.clear();
          break;
        case 'live':
          cache.clearLiveImages();
          break;
      }

      return MCPCallResult(
        message: 'Image cache has been cleared (type: $type)',
        parameters: {'success': true},
      );
    },
    definition: MCPToolDefinition(
      name: 'img_clear_cache',
      description: 'Clear image cache',
      inputSchema: {
        'type': 'object',
        'properties': {
          'type': {
            'type': 'string',
            'enum': ['all', 'live'],
            'description': 'Clear type',
          },
        },
      },
    ),
  ));
}

String _formatBytes(int bytes) {
  if (bytes < 1024) return '$bytes B';
  if (bytes < 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(1)} KB';
  return '${(bytes / (1024 * 1024)).toStringAsFixed(1)} MB';
}

Template E: Form Inspector Tool#

Form state inspection tool

lib/debug/form_inspector_tool.dart#

import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:mcp_toolkit/mcp_toolkit.dart';

/// Form registry (app must register forms)
class FormRegistry {
  static final Map<String, GlobalKey<FormState>> _forms = {};

  static void register(String key, GlobalKey<FormState> formKey) {
    _forms[key] = formKey;
  }

  static void unregister(String key) {
    _forms.remove(key);
  }

  static GlobalKey<FormState>? get(String key) => _forms[key];

  static Map<String, GlobalKey<FormState>> get all => _forms;
}

/// Register form inspector tools
void registerFormInspectorTools() {
  if (!kDebugMode) return;

  addMcpTool(MCPCallEntry.tool(
    handler: (params) {
      final forms = FormRegistry.all;

      return MCPCallResult(
        message: '${forms.length} forms are registered',
        parameters: {
          'forms': forms.entries.map((e) {
            final state = e.value.currentState;
            return {
              'key': e.key,
              'isValid': state?.validate() ?? false,
            };
          }).toList(),
        },
      );
    },
    definition: MCPToolDefinition(
      name: 'form_list',
      description: 'Return all registered form list',
      inputSchema: {'type': 'object', 'properties': {}},
    ),
  ));

  addMcpTool(MCPCallEntry.tool(
    handler: (params) {
      final formKey = params['formKey'] as String?;
      if (formKey == null) {
        return MCPCallResult(
          message: 'formKey parameter is required',
          parameters: {'error': true},
        );
      }

      final form = FormRegistry.get(formKey);
      if (form == null) {
        return MCPCallResult(
          message: 'Cannot find form $formKey',
          parameters: {'error': true},
        );
      }

      final isValid = form.currentState?.validate() ?? false;

      return MCPCallResult(
        message: '$formKey validation complete',
        parameters: {
          'formKey': formKey,
          'isValid': isValid,
        },
      );
    },
    definition: MCPToolDefinition(
      name: 'form_validate',
      description: 'Run form validation',
      inputSchema: {
        'type': 'object',
        'properties': {
          'formKey': {
            'type': 'string',
            'description': 'Form key',
          },
        },
        'required': ['formKey'],
      },
    ),
  ));
}

Template F: App Initialization#

Initialize all inspector tools

lib/main.dart#

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:mcp_toolkit/mcp_toolkit.dart';

import 'debug/bloc_inspector_tool.dart';
import 'debug/form_inspector_tool.dart';
import 'debug/image_inspector_tool.dart';
import 'debug/nav_inspector_tool.dart';
import 'debug/network_inspector_tool.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();

  // MCP Toolkit initialization
  MCPToolkitBinding.instance
    ..initialize()
    ..initializeFlutterToolkit();

  // Register inspector tools only in debug mode
  if (kDebugMode) {
    registerBlocInspectorTools();
    registerNavInspectorTools(appRouter);
    registerNetworkInspectorTools();
    registerImageInspectorTools();
    registerFormInspectorTools();

    debugPrint('Flutter Inspector tools registered');
  }

  runApp(const MyApp());
}

Debugging Workflow Patterns#

Pattern 1: Crash Investigation#

1. listClientToolsAndResources - >   Check tools
2. runClientResource uri= " visual://localhost/app/errors/latest " 
 3. runClientTool name= " log_get_errors "   args={ " includeStackTrace " : true}
4. runClientTool name= " bloc_get_all "   - >   Check state
5. Analyze cause and fix
6. hot_reload_flutter - >   Apply changes

Pattern 2: Network Debugging#

1. runClientTool name= " network_get_logs "   args={ " status " :  " 4xx " }
2. runClientTool name= " auth_get_tokens "   - >   Check tokens
3. runClientTool name= " config_get_value "   args={ " key " :  " apiBaseUrl " }
4. Fix the issue
5. runClientTool name= " network_clear_logs " 
 6. Re-test

Pattern 3: UI Performance#

1. runClientResource uri= " visual://localhost/view/screenshots " 
 2. runClientTool name= " ui_find_overflow "   - >   Check overflow
3. runClientTool name= " img_get_cache_stats "   - >   Check image cache
4. runClientTool name= " img_analyze_warnings " 
 5. Apply optimizations
6. hot_reload_flutter

pubspec.yaml Configuration#

dependencies:
  mcp_toolkit: ^0.1.0  # MCP toolkit for debug tools

dev_dependencies:
  # None - mcp_toolkit auto-separates via kDebugMode