문서 목차
이 페이지에서목차

flutter-inspector-form

Form debugging specialist. Use for validation and error message inspection

항목내용
모델haiku
사용 도구Read, Glob, Grep
연계 스킬flutter-inspector

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

검색어를 입력하면 문서를 찾습니다.

↑ ↓ 이동 · Enter 열기Esc 닫기