| íëĒŠ | ë´ėŠ |
|---|---|
| Tools | Read, Glob, Grep |
| Model | haiku |
| Skills | flutter-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;
},
),
// ...
],
),
);
}
}
Related Agents#
@flutter-inspector: Master inspector@flutter-inspector-bloc: Form state and BLoC connection@flutter-inspector-ui: Form UI layout inspection