Flutter语义树AI调试服务

通过嵌入MCP协议服务器,使AI助手能够访问Flutter应用的语义树和错误上下文,实现本地化AI辅助调试。

  • by moinsen-dev
  • Dart
  • 本地部署
  • 更新于
在 GitHub 查看 moinsen-dev/mcp_flutter_semantics

使用说明

Flutter 语义 MCP 服务器

使AI编码助手能够“查看”并理解您正在运行的Flutter应用程序,通过 模型上下文协议(MCP)在使用AI进行调试时,省去手动截图和用户界面描述的步骤。

这是什么?

这个包在您的Flutter应用中嵌入了一个MCP服务器,使像Claude Code这样的AI助手能够:

  • 查看你的用户界面查询完整的Flutter语义树以了解屏幕上的内容
  • 调试错误访问包含完整上下文(堆栈跟踪、小部件路径、用户操作)的全面错误追踪功能
  • 提问“为什么这个按钮被禁用了?”,“发生了什么错误?”,“当前可见的是什么?”

所有数据均保存在本地——无需网络传输,在发布版本中自动禁用。

特点/特性

  • 语义树访问AI可以查询完整的Flutter UI层次结构
  • 全面错误追踪自动捕获,包括堆栈跟踪、小部件上下文、语义快照和用户操作历史
  • MCP协议集成人工智能工具通信的标准协议
  • 隐私优先在发布版本中自动禁用,注重隐私的数据收集
  • 轻松设置只需≤5行代码即可上手
  • 平台支持macOS 和 iOS(模拟器和实体设备)

快速入门(< 10分钟)

先决条件

  • Flutter ≥3.24.0(可翻译为:“Flutter版本需大于或等于3.24.0”)
  • Dart 版本 ≥3.0.0
  • macOS 13或更高版本,或iOS 15或更高版本(MVP平台)
  • Claude Code 或其他与MCP兼容的AI助手

安装

将该包添加到您的Flutter项目中:

flutter pub add mcp_flutter_semantics

初始化服务器

将以下几行添加到你的 main.dart:

import 'package:flutter/material.dart';
import 'package:mcp_flutter_semantics/mcp_flutter_semantics.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Start MCP server (auto-disabled in release builds)
  await McpSemanticsServer.instance.start();

  runApp(MyApp());
}

完成了!MCP 服务器现在正在您的 Flutter 应用中运行。

配置Claude代码

遵循 设置指南 将 Claude Code 连接到您的应用程序。

测试连接

运行你的Flutter应用,然后询问Claude Code:

  • “屏幕上当前显示的是什么?”
  • “为什么这个按钮被禁用了?”
  • “发生了什么错误?”
  • “向我展示最后一次用户交互”

使您的应用具备AI控制能力

为了使AI助手能够与您的应用进行交互,请将您的小部件(widgets)用支持MCP(机器可读元数据平台或类似功能的术语,具体根据上下文确定)的小部件进行包装。该包提供了常见Flutter小部件的即插即用替代品,这些替代品向AI暴露了丰富的元数据。

MCP 小部件包装器

McpButton - 交互式按钮

将任何类似按钮的小部件包装起来,使其可进行AI点击:

McpButton(
  id: 'submit-button',              // Unique ID for AI to reference
  label: 'Submit Form',             // Human-readable label
  hint: 'Tap to submit the form',   // Help text for AI
  onPressed: _handleSubmit,         // Your callback
  enabled: _formIsValid,            // Dynamic enabled state
  metadata: {                       // Custom metadata for AI
    'formValid': _formIsValid,
    'disabledReasons': _getDisabledReasons(),
  },
  child: const Text('Submit'),      // Your original button
)

人工智能可以:

  • 查询按钮状态: widgets://tree 显示是否已启用/禁用
  • 读取元数据:查看按钮为何被禁用
  • 触发点击: trigger_action("submit-button", "tap")

McpTextField - 文本输入框

使文本字段可由AI填充:

McpTextField(
  id: 'email-field',
  label: 'Email Address',
  hint: 'Enter your email',
  controller: _emailController,
  enabled: true,
  metadata: {
    'required': true,
    'isValid': _emailController.text.contains('@'),
    'validationMessage': _getEmailError(),
  },
  decoration: const InputDecoration(
    labelText: 'Email',
    hintText: 'you@example.com',
  ),
  validator: (value) => value?.contains('@') == true
      ? null
      : 'Invalid email',
  onChanged: (_) => setState(() {}),
)

人工智能可以:

  • 填写字段: trigger_action("email-field", "set_text", "john@example.com")
  • 清除字段: trigger_action("email-field", "clear")
  • 读取值:检查元数据以获取当前值和验证状态

McpDropdown - 选择下拉菜单

McpDropdown<String>(
  id: 'country-dropdown',
  label: 'Country',
  hint: 'Select your country',
  value: _selectedCountry,
  items: const [
    DropdownMenuItem(value: 'US', child: Text('United States')),
    DropdownMenuItem(value: 'UK', child: Text('United Kingdom')),
    DropdownMenuItem(value: 'CA', child: Text('Canada')),
  ],
  onChanged: (value) => setState(() => _selectedCountry = value),
  metadata: {
    'required': false,
    'options': ['US', 'UK', 'CA'],  // AI sees available options
  },
)

人工智能可以:

  • 选择选项: trigger_action("country-dropdown", "select", "UK")
  • 查看选项:元数据包含所有可用值

McpCheckbox - 复选框

McpCheckbox(
  id: 'terms-checkbox',
  label: 'I accept terms and conditions',
  value: _acceptedTerms,
  enabled: true,
  metadata: {'required': true},
  title: const Text('I accept the terms and conditions'),
  onChanged: (value) => setState(() => _acceptedTerms = value ?? false),
)

人工智能可以:

  • 检查: trigger_action("terms-checkbox", "check")
  • 取消选中: trigger_action("terms-checkbox", "uncheck")
  • 切换: trigger_action("terms-checkbox", "toggle")

McpSlider - 值滑块

McpSlider(
  id: 'satisfaction-slider',
  label: 'Satisfaction Level',
  hint: 'Rate from 0 to 10',
  value: _satisfaction,
  min: 0,
  max: 10,
  divisions: 10,
  onChanged: (value) => setState(() => _satisfaction = value),
  metadata: {
    'unit': 'rating',
    'currentValue': _satisfaction,
  },
)

人工智能可以:

  • 设置值: trigger_action("satisfaction-slider", "set_value", "8.0")
  • 增加: trigger_action("satisfaction-slider", "increase")
  • 减少: trigger_action("satisfaction-slider", "decrease")

导航追踪

注册路由以帮助AI导航您的应用程序:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Register routes with rich metadata
  McpNavigationMap.instance.registerRoute(
    path: '/profile',
    name: 'User Profile',
    description: 'View and edit user profile information',
    metadata: {
      'purpose': 'Manage user account details',
      'commonActions': ['Edit name', 'Change avatar', 'Update email'],
      'prerequisites': 'User must be logged in',
    },
  );

  await McpSemanticsServer.instance.start();
  runApp(MyApp());
}

在你的 MaterialApp 中添加导航观察者:

MaterialApp(
  navigatorObservers: [
    McpNavigationObserver(sanitizeParams: true),
    McpRoutingObserver(logger: debugPrint),
  ],
  // ... rest of your app
)

人工智能可以:

  • 查询网站地图: navigation://sitemap 显示所有路线
  • 导航: navigate_to("/profile")
  • 返回: go_back()

带修复提示的表单验证

帮助AI理解和自动修复表单验证问题:

McpButton(
  id: 'submit-button',
  label: 'Submit',
  onPressed: _isValid ? _handleSubmit : null,
  enabled: _isValid,
  metadata: {
    'disabledReasons': _getDisabledReasons(),  // ["Name is empty", "Email invalid"]

    // Healing hints tell AI how to fix issues
    'healingHints': {
      'canAutoHeal': true,
      'autoHealableFields': ['name-field', 'email-field'],
      'suggestedAction': 'Fill name and email fields',
    },

    // Field status shows current validation state
    'fieldStatus': {
      'name': {
        'id': 'name-field',
        'valid': false,
        'accessible': true,
        'validationMessage': 'Name is required',
      },
      'email': {
        'id': 'email-field',
        'valid': false,
        'accessible': true,
        'validationMessage': 'Must contain @',
      },
    },

    'completionPercentage': 0,  // Progress tracking
  },
  child: const Text('Submit'),
)

人工智能可以:

  • 查看“查看原因”按钮为何被禁用
  • 知道哪些字段需要修正
  • 智能自动填充表单
  • 追踪轨道完成进度

最佳实践

1. 使用独特、描述性的ID

✅ GOOD: id: 'user-profile-save-button'
❌ BAD:  id: 'button1'

2. 提供丰富的元数据

McpTextField(
  id: 'age-field',
  label: 'Age',
  metadata: {
    'required': true,
    'minValue': 18,
    'maxValue': 120,
    'validationMessage': _ageError,
    'isEmpty': _ageController.text.isEmpty,
    'isValid': _isAgeValid(),
  },
  // ...
)

3. 保持元数据更新

使用 setState() 当小部件状态发生变化时更新元数据:

onChanged: (_) => setState(() {}),  // Triggers rebuild with fresh metadata

4. 结合语义

你可以同时使用MCP小部件和Flutter的语义功能,以实现最佳的无障碍性:

Semantics(
  label: 'Submit form button',
  hint: 'Tap to submit your information',
  enabled: _formIsValid,
  button: true,
  child: McpButton(
    id: 'submit-button',
    label: 'Submit',
    onPressed: _formIsValid ? _handleSubmit : null,
    // ...
  ),
)

完整示例

这是一个完全由人工智能控制的完整表单:

class MyForm extends StatefulWidget {
  @override
  State<MyForm> createState() => _MyFormState();
}

class _MyFormState extends State<MyForm> {
  final _nameController = TextEditingController();
  final _emailController = TextEditingController();
  bool _acceptedTerms = false;

  bool get _isValid =>
      _nameController.text.isNotEmpty &&
      _emailController.text.contains('@') &&
      _acceptedTerms;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        // Progress indicator
        McpWidget(
          id: 'form-progress',
          type: 'ProgressIndicator',
          label: 'Form Progress',
          metadata: {
            'percentage': _calculateProgress(),
            'fieldsRemaining': _getRemainingFields(),
          },
          child: LinearProgressIndicator(
            value: _calculateProgress() / 100,
          ),
        ),

        // Name field
        McpTextField(
          id: 'name-field',
          label: 'Full Name',
          controller: _nameController,
          metadata: {
            'required': true,
            'isEmpty': _nameController.text.isEmpty,
          },
          onChanged: (_) => setState(() {}),
        ),

        // Email field
        McpTextField(
          id: 'email-field',
          label: 'Email',
          controller: _emailController,
          metadata: {
            'required': true,
            'isValid': _emailController.text.contains('@'),
          },
          onChanged: (_) => setState(() {}),
        ),

        // Terms checkbox
        McpCheckbox(
          id: 'terms-checkbox',
          label: 'Accept terms',
          value: _acceptedTerms,
          onChanged: (val) => setState(() => _acceptedTerms = val ?? false),
        ),

        // Submit button with healing hints
        McpButton(
          id: 'submit-button',
          label: 'Submit',
          onPressed: _isValid ? _submit : null,
          enabled: _isValid,
          metadata: {
            'formValid': _isValid,
            'disabledReasons': _getDisabledReasons(),
            'healingHints': {
              'canAutoHeal': !_isValid,
              'autoHealableFields': _getFixableFields(),
            },
          },
          child: const Text('Submit'),
        ),
      ],
    );
  }
}

现在,人工智能可以:

  • ✅ 查看所有表单字段
  • ✅ 自动填充字段
  • ✅ 理解验证规则
  • ✅ 跟踪进度
  • ✅ 准备好时提交

配置选项

自定义服务器行为以 McpServerConfig:

await McpSemanticsServer.instance.start(
  config: McpServerConfig(
    // App metadata for AI assistants
    appName: 'My App',
    appDescription: 'A demo app showing MCP integration',

    // Logging verbosity
    logLevel: McpLogLevel.verbose,  // none, basic, verbose, debug

    // Error retention
    errorRetentionHours: 48,         // Keep errors for 48 hours
    errorRetentionCount: 1000,       // Max 1000 errors in database

    // User action tracking
    captureUserActions: true,        // Track taps, scrolls, navigation

    // Privacy
    sanitizeRouteParams: true,       // /user/123 → /user/:id
    enableInRelease: false,          // Never enable in production!
  ),
);

可用的MCP资源

MCP服务器提供了以下资源:

semantics://tree

返回以JSON格式表示的完整Flutter语义树。包含所有语义数据字段:标签、值、提示、操作、边界、变换等。

errors://recent

返回最近的错误(默认最后10条)。添加 ?limit=20 进行定制。

errors://all

返回数据库中当前所有的错误。

errors://unresolved

仅返回尚未标记为已解决的错误。

可用的MCP工具

get_semantics_node

通过ID获取特定节点的详细语义数据。

{"node_id": 42}

get_error_details

获取完整的错误详细信息,包括所有上下文(堆栈跟踪、小部件路径、语义快照、用户操作)。

{"error_id": 123}

query_errors

按类型、消息模式、时间范围或解决状态搜索和过滤错误。

{
  "error_type": "RenderFlexOverflow",
  "since": "2025-10-21T10:00:00Z",
  "resolved": false,
  "limit": 20
}

mark_error_resolved

将错误标记为已解决或未解决。

{"error_id": 123, "resolved": true}

clear_errors

从数据库中清除错误,可选择过滤。

{"filter": "resolved", "older_than_hours": 24}

数据库模式错误

错误信息存储在 SQLite 中(mcp_errors.db(附带全面的上下文)

字段 类型 描述
(无) (无) (无)
整数 自动递增的错误ID timestamp
文本 ISO 8601 时间戳 error_type
文本 异常/错误类名 error_message
文本 完整错误信息 stack_trace
文本 完整堆栈跟踪 widget_context
文本 小部件树路径(JSON) semantics_snapshot
TEXT 错误发生时的语义树(JSON格式) app_state
文本 额外的应用状态(JSON) user_actions
文本 最近10次用户交互(JSON格式) is_fatal
整数 1 表示致命,0 表示非致命 is_resolved

| 整数 | 标记为已解决时为1 |

故障排除

  • 服务器无法启动 WidgetsFlutterBinding.ensureInitialized() 确保 start()
  • 在……之前被调用
  • 检查你是否在调试模式或性能分析模式下运行(服务器在发布模式下会自动禁用) [MCP] 在控制台中查找错误信息

前缀

  • 克劳德代码无法连接
  • 在Claude代码设置中验证您的MCP服务器配置
  • 确保您的Flutter应用程序正在运行 [MCP] Semantics Server started on stdio 检查stdio传输是否正常工作(查找
  • (在控制台中) 见 CLAUDE_CODE_SETUP.md(文件名,可译为“克劳德代码设置说明.md”或保持原样,因为文件名通常不翻译,除非有特定的翻译需求)

用于详细故障排除

  • 错误未被捕获 McpSemanticsServer.instance.start() 检查一下
  • 成功完成 [MCP] Error capture initialized 验证错误捕获是否已初始化(查找
  • (在控制台中)

尝试触发一个故意错误以进行测试

  • 性能问题 logLevel 减少 basic 到;向;对于;关于;在(某时间/某方面) none
  • 或者 errorRetentionCount 较低的
  • 如果数据库非常大 captureUserActions 禁用

如果不需要

隐私考量

  • **这个包裹的设计充分考虑了隐私保护:**在发布构建中自动禁用
  • 服务器除非明确启用,否则不会在生产环境中运行文本输入未被捕获
  • 用户按键输入和表单数据绝不会被存储路由消毒(或路由清理)/user/123 URL 参数默认情况下会被清理(或验证) /user/:id→
  • **)**仅限本地
  • 所有数据均存储在设备上,无需网络传输用户行为追踪
  • 捕获交互类型(点击、滚动),但不捕获内容语义快照

仅捕获无障碍数据,不捕获像素内容警告 enableInRelease: true 永不设定

在生产应用中,这样做会暴露内部应用程序的状态。

平台支持

平台 状态 备注
macOS ✅ 支持 完全支持(桌面版)
iOS ✅ 支持 通过USB调试使用模拟器和物理设备
Android ⏳ 第二阶段 计划在未来发布
网站 ⏳ 第二阶段 计划在未来发布
Windows ⏳ 第二阶段 计划在未来发布

| Linux | ⏳ 第二阶段 | 计划在未来发布 |

示例应用程序 example/ 查看

  • 一个完整演示应用程序的目录,展示:
  • MCP服务器初始化
  • 全面的语义标注
  • 故意触发错误
  • 错误恢复模式

用户交互追踪

cd example
flutter run -d macos  # or -d ios

运行示例:

API 文档

dart doc
open doc/api/index.html

完整的API文档已提供: 或者查看生成的文档于pub.dev(注:这个域名通常用于指向Flutter的包发布平台,但直接翻译为中文并无实际意义,因此保留原样)

。

  1. 其工作原理MCP 服务器
  2. 在您的Flutter应用中运行,使用stdio传输方式语义树 WidgetsBinding.instance.pipelineOwner?.semanticsOwner
  3. 通过……访问错误捕获 FlutterError.onError 挂钩于 PlatformDispatcher.instance.onError
  4. 并且SQLite 存储 mcp_errors.db 错误持续存在
  5. 在应用文档目录中用户操作
  6. **通过手势检测器和导航观察者追踪(记录最近10个动作的循环缓冲区)**MCP协议 mcp_dart 通过(某种方式)暴露的资源和工具

包裹;软件包;程序包

性能影响

  • **MCP服务器的设计旨在最小化对性能的影响:**帧渲染
  • **< 2毫秒影响(可忽略不计)**语义查询
  • 对于典型应用(<1000个节点),完成时间小于2秒错误捕获
  • 异步,不阻塞错误处理程序记忆

错误数据库约5-10MB(保留策略可配置)

做出贡献

欢迎贡献!这是一个开源项目。 仓库:

https://github.com/moinsen-dev/mcp-前端-heor(注:这里的“heor”可能是特定项目或分支的名称,根据上下文无法确定其准确含义,因此直接音译。在实际应用中,应根据具体情况或项目文档来确定其确切含义。)

许可证 MIT 许可证 - 详见 许可证

文件中有详细信息。

- 完整演示应用程序

Flutter 语义(或语义分析)

  • 支持问题 :
  • **GitHub Issues(GitHub问题)**讨论 :

GitHub 讨论区