LogoSkills

flutter-inspector-form

Form debugging specialist. Use for validation and error message inspection

항ëĒŠë‚´ėšŠ
ToolsRead, Glob, Grep
Modelhaiku
Skillsflutter-inspector

Flutter Inspector - Form Agent#

A specialized agent for debugging form state and validation at runtime.

Triggers#

Automatically activated when @flutter-inspector-form is invoked or the following keywords are detected:

  • Form, Form, input
  • Validation, Validation
  • Field value, error message

MCP Tools#

form_list#

Lists all forms on the current screen.

{
   " name " :  " form_list " ,
   " description " :  " List forms " ,
   " inputSchema " : {
     " type " :  " object " ,
     " properties " : {}
  }
}

Response example:

{
   " forms " : [
    {
       " key " :  " loginForm " ,
       " fieldCount " : 3,
       " isValid " : false,
       " isDirty " : true,
       " fields " : [ " email " ,  " password " ,  " rememberMe " ]
    },
    {
       " key " :  " profileForm " ,
       " fieldCount " : 5,
       " isValid " : true,
       " isDirty " : false,
       " fields " : [ " name " ,  " phone " ,  " address " ,  " city " ,  " zipCode " ]
    }
  ],
   " count " : 2
}

form_get_state#

Returns the detailed state of a specific form.

{
   " name " :  " form_get_state " ,
   " description " :  " Detailed form state query " ,
   " inputSchema " : {
     " type " :  " object " ,
     " properties " : {
       " formKey " : {
         " type " :  " string " ,
         " description " :  " Form key " 
       }
    },
     " required " : [ " formKey " ]
  }
}

Response example:

{
   " formKey " :  " loginForm " ,
   " state " : {
     " isValid " : false,
     " isDirty " : true,
     " isSubmitting " : false,
     " submitCount " : 2,
     " fields " : {
       " email " : {
         " value " :  " user@example " ,
         " isValid " : false,
         " isTouched " : true,
         " isDirty " : true,
         " error " :  " Invalid email format " 
       },
       " password " : {
         " value " :  " *** " ,
         " isValid " : true,
         " isTouched " : true,
         " isDirty " : true,
         " error " : null
      },
       " rememberMe " : {
         " value " : true,
         " isValid " : true,
         " isTouched " : false,
         " isDirty " : false,
         " error " : null
      }
    }
  }
}

form_get_errors#

Returns all errors for a form.

{
   " name " :  " form_get_errors " ,
   " description " :  " Form error query " ,
   " inputSchema " : {
     " type " :  " object " ,
     " properties " : {
       " formKey " : {
         " type " :  " string " ,
         " description " :  " Form key (omit for all forms) " 
       }
    }
  }
}

Response example:

{
   " errors " : {
     " loginForm " : {
       " email " :  " Invalid email format " ,
       " password " : null
    },
     " profileForm " : {
       " phone " :  " Phone number is required " ,
       " zipCode " :  " Invalid zip code format " 
     }
  },
   " totalErrors " : 3
}

form_validate#

Manually validates a form.

{
   " name " :  " form_validate " ,
   " description " :  " Run form validation " ,
   " inputSchema " : {
     " type " :  " object " ,
     " properties " : {
       " formKey " : {
         " type " :  " string " ,
         " description " :  " Form key " 
       }
    },
     " required " : [ " formKey " ]
  }
}

Response example:

{
   " formKey " :  " loginForm " ,
   " isValid " : false,
   " errors " : {
     " email " :  " Invalid email format " 
   },
   " validatedAt " :  " 2024-01-01T10:00:00Z " 
 }

App Integration Code#

// lib/debug/mcp_form_tools.dart
import 'package:mcp_toolkit/mcp_toolkit.dart';
import 'package:flutter/widgets.dart';

class FormTracker {
  static final instance = FormTracker._();
  FormTracker._();

  final Map<String, GlobalKey<FormState>> _forms = {};
  final Map<String, Map<String, TextEditingController>> _controllers = {};
  final Map<String, Map<String, String?>> _errors = {};

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

  void registerField(String formKey, String fieldName, TextEditingController controller) {
    _controllers[formKey] ??= {};
    _controllers[formKey]![fieldName] = controller;
  }

  void setError(String formKey, String fieldName, String? error) {
    _errors[formKey] ??= {};
    _errors[formKey]![fieldName] = error;
  }

  List<Map<String, dynamic>> listForms() {
    return _forms.entries.map((e) {
      final formState = e.value.currentState;
      return {
        'key': e.key,
        'fieldCount': _controllers[e.key]?.length ?? 0,
        'isValid': formState?.validate() ?? false,
        'fields': _controllers[e.key]?.keys.toList() ?? [],
      };
    }).toList();
  }

  Map<String, dynamic> getFormState(String formKey) {
    final formState = _forms[formKey]?.currentState;
    final controllers = _controllers[formKey] ?? {};
    final errors = _errors[formKey] ?? {};

    return {
      'formKey': formKey,
      'state': {
        'isValid': formState?.validate() ?? false,
        'fields': controllers.map((name, controller) => MapEntry(name, {
          'value': name.contains('password') ? '***' : controller.text,
          'error': errors[name],
        })),
      },
    };
  }

  Map<String, dynamic> getAllErrors() {
    return Map.fromEntries(
      _errors.entries.where((e) => e.value.values.any((v) => v != null)),
    );
  }

  Map<String, dynamic> validateForm(String formKey) {
    final formState = _forms[formKey]?.currentState;
    final isValid = formState?.validate() ?? false;

    return {
      'formKey': formKey,
      'isValid': isValid,
      'errors': _errors[formKey]?.entries
          .where((e) => e.value != null)
          .fold<Map<String, String>>({}, (map, e) => map..[e.key] = e.value!),
    };
  }
}

void registerFormTools() {
  if (!kDebugMode) return;

  addMcpTool(MCPCallEntry.tool(
    handler: (_) => MCPCallResult(
      message: 'Form list',
      parameters: {'forms': FormTracker.instance.listForms()},
    ),
    definition: MCPToolDefinition(
      name: 'form_list',
      description: 'List forms',
      inputSchema: {'type': 'object', 'properties': {}},
    ),
  ));

  addMcpTool(MCPCallEntry.tool(
    handler: (params) {
      final formKey = params['formKey'] as String;
      return MCPCallResult(
        message: 'Form state',
        parameters: FormTracker.instance.getFormState(formKey),
      );
    },
    definition: MCPToolDefinition(
      name: 'form_get_state',
      description: 'Form state query',
      inputSchema: {
        'type': 'object',
        'properties': {'formKey': {'type': 'string'}},
        'required': ['formKey'],
      },
    ),
  ));

  addMcpTool(MCPCallEntry.tool(
    handler: (_) => MCPCallResult(
      message: 'Form errors',
      parameters: {'errors': FormTracker.instance.getAllErrors()},
    ),
    definition: MCPToolDefinition(
      name: 'form_get_errors',
      description: 'Form error query',
      inputSchema: {'type': 'object', 'properties': {}},
    ),
  ));

  addMcpTool(MCPCallEntry.tool(
    handler: (params) {
      final formKey = params['formKey'] as String;
      return MCPCallResult(
        message: 'Validation result',
        parameters: FormTracker.instance.validateForm(formKey),
      );
    },
    definition: MCPToolDefinition(
      name: 'form_validate',
      description: 'Form validation',
      inputSchema: {
        'type': 'object',
        'properties': {'formKey': {'type': 'string'}},
        'required': ['formKey'],
      },
    ),
  ));
}

Usage Examples#

Check form list#

Q: What forms are on the current screen?
A: Run form_list
   - >   loginForm (3 fields), profileForm (5 fields)

Detailed form state check#

Q: Show me the login form state
A: Run form_get_state formKey= " loginForm " 
    - >   email: invalid, password: valid, rememberMe: true

Check errors#

Q: Are there any form errors?
A: Run form_get_errors
   - >   email:  " Invalid email format "

Manual validation#

Q: Validate the profile form
A: Run form_validate formKey= " profileForm " 
    - >   isValid: false, errors: {phone:  " Required field " }

Common Problem Diagnosis#

Form not submitting#

1. Check current state with form_get_state
2. If isValid: false, check errors
3. Query all errors with form_get_errors
4. Review validation logic

Validation not working#

1. Run manual validation with form_validate
2. Check error messages
3. Review validator function logic

Field values not persisting#

1. Check field values with form_get_state
2. Verify TextEditingController connection
3. Review form state restoration logic

Error messages not showing#

1. Confirm errors exist with form_get_errors
2. Check ErrorText widget rendering
3. Check AutovalidateMode settings

Form Widget Integration#

// Form registration example
class LoginForm extends StatefulWidget {
  @override
  _LoginFormState createState() => _LoginFormState();
}

class _LoginFormState extends State<LoginForm> {
  final _formKey = GlobalKey<FormState>();
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();

  @override
  void initState() {
    super.initState();

    if (kDebugMode) {
      FormTracker.instance.registerForm('loginForm', _formKey);
      FormTracker.instance.registerField('loginForm', 'email', _emailController);
      FormTracker.instance.registerField('loginForm', 'password', _passwordController);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        children: [
          TextFormField(
            controller: _emailController,
            validator: (value) {
              final error = _validateEmail(value);
              if (kDebugMode) {
                FormTracker.instance.setError('loginForm', 'email', error);
              }
              return error;
            },
          ),
          // ...
        ],
      ),
    );
  }
}
  • @flutter-inspector: Master inspector
  • @flutter-inspector-bloc: Form state and BLoC connection
  • @flutter-inspector-ui: Form UI layout inspection