关于 flutter-mcp-toolkit-custom-tools
面向 Flutter 开发者的技能,介绍如何通过动态注册表添加应用专属的 MCP 工具和资源,并说明条目类型选择、注册方式与 Agent 发现流程。
主要功能
- 01选择工具或只读资源
- 02在应用启动时注册条目
- 03定义严格的 JSON Schema
- 04发现并调用应用条目
- 05避免生命周期与命名冲突
适用场景
- 01向 Agent 提供购物车摘要
- 02提供只读路由或诊断数据
- 03添加带参数的应用操作
- 04排查动态条目未显示的问题
MCP 相关
介绍如何在 Flutter 进程中注册自定义工具和资源,并通过动态注册表向 MCP 客户端公开。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ arenukvern/ mcp_flutter --skill flutter-mcp-toolkit-custom-tools安装后在 Claude Code 中输入/flutter-mcp-toolkit-custom-tools确认已加载。
详细介绍
自定义 MCP Toolkit 工具与资源(动态注册表)
当捆绑的 MCP 工具(截图、语义快照、点击等)不够用,且你需要特定于应用的读取接口或操作时使用——例如购物车总额、功能标志、精心整理的内部状态调试快照。条目在 Flutter 进程中注册,并通过动态注册表暴露给 Agent。
迁移: 旧版调用条目类型已在 intentcall Phase 6b 中移除。请使用
AgentCallEntry或mcpToolkitTool/mcpToolkitResource。参见flutter-mcp-toolkit-intentcall-migration。
边界: 在此处更改应用发现、Flutter VM-service 扩展或 应用自有调试接口。请在上游 IntentCall 仓库中更改规范注册表/会话语义、 架构策略、平台投影或发布行为。
选择合适的原语
| 需求 | 使用 |
|---|---|
| 一次性读取简单值 | fmt_evaluate_dart_expression(无需更改应用代码)。 |
| 稳定的只读载荷(诊断信息、JSON 快照、“当前路由”) | AgentCallEntry.resource + fmt_client_resource。当契约类似“GET”且具备幂等性时,优先使用资源。 |
| 带参数或会修改状态的操作,或可复用的命名操作 | AgentCallEntry.tool + fmt_client_tool。 |
处理程序签名
原生 AgentCallEntry(新代码首选)
处理程序接收 AgentArguments(Map<String, Object?>)并返回 AgentResult:
import 'package:mcp_toolkit/mcp_toolkit.dart';
final tool = AgentCallEntry.tool(
namespace: 'app',
name: 'cart_get_snapshot',
description: 'Return current cart total and items for a user.',
inputSchema: const {
'type': 'object',
'additionalProperties': false,
'properties': {
'userId': {'type': 'string'},
},
'required': ['userId'],
},
handler: (final args) async {
final userId = args['userId']?.toString() ?? '';
final cart = CartRepository.instance.forUser(userId);
return AgentResult.success(
message: 'ok',
data: {
'total': cart.total,
'items': cart.items.map((final i) => i.toJson()).toList(),
},
);
},
);
await MCPToolkitBinding.instance.addEntries(entries: {tool});
旧版 MCPToolDefinition + MCPCallResult(桥接)
内置工具包仍使用 mcpToolkitTool / mcpToolkitResource,以适配
Map<String, String> 服务扩展处理程序:
final tool = mcpToolkitTool(
namespace: 'app',
handler: (final request) async {
final userId = request['userId'] ?? '';
return MCPCallResult(
message: 'ok',
parameters: {'userId': userId},
);
},
definition: MCPToolDefinition(
name: 'cart_get_snapshot',
description: 'Return current cart total and items for a user.',
inputSchema: ObjectSchema(
properties: {
'userId': StringSchema(),
},
required: ['userId'],
),
),
);
- 线上传输的工具参数是以架构属性名称为键的字符串——使用
int.tryParse、jsonDecode等进行解析。 - 在应用端不要使用
request.arguments。
优先在 bootstrapFlutter(runApp: ...) 之前调用 MCPToolkitBinding.instance.addEntries(entries: { ... }),这样工具/资源可在同一处注册,并设置 zone/错误处理。
在启动时仅注册一次——不要在 build 或每个组件的 initState 中注册。
自定义资源
final resource = AgentCallEntry.resource(
namespace: 'app',
name: 'app_cart_digest',
description: 'Compact cart summary for agents (read-only).',
mimeType: 'application/json',
handler: (final args) async => AgentResult.success(
message: 'Cart digest',
data: {
'itemCount': CartRepository.instance.visibleCount,
'currency': CartRepository.instance.currencyCode,
},
),
);
或者通过桥接方式:
mcpToolkitResource(
namespace: 'app',
definition: MCPResourceDefinition(
name: 'app_cart_digest',
description: 'Compact cart summary for agents (read-only).',
mimeType: 'application/json',
),
handler: (final request) async => MCPCallResult(
message: 'Cart digest',
parameters: {'itemCount': 3},
),
),
name必须为snake_case。已发布的资源 URI 遵循visual://localhost/...约定;Agent 使用fmt_client_resource,并通过fmt_list_client_tools_and_resources获取资源列表。
架构规则(工具)
MCP 服务会强制执行严格的 JSON Schema:
- 除非你有意接受任意键,否则优先设置
additionalProperties: false。 - 对处理程序会无条件读取的所有字段标记为
required。 AgentResult.data/MCPCallResult.parameters必须可序列化为 JSON。
从 Agent 端发现
fmt_list_client_tools_and_resources——列出应用注册的工具和资源。fmt_client_tool——使用 JSON 参数按名称调用动态工具。fmt_client_resource——从列表中的 URI 获取已注册资源。
如果预期内容未出现:确认 addEntries 已完成(使用 await),然后执行热重启。
生命周期注意事项
- 热重载时从组件代码调用
addEntries→ 会重复注册。请在main()/ bootstrap 中注册一次。 - 仅限调试模式——发布版本不会暴露 VM service 扩展。
- 命名: 应用使用扁平的全局命名空间。请为工具/资源添加前缀(
cart_、flags_、nav_)。如果内置条目已使用某个名称,自定义条目会被跳过且不会发出警告;内置条目会处理调用,自定义处理程序不会运行。 - 命名运行中的实例: 使用
MCPToolkitBinding.instance.setAppIdentity(label: 'Fleet app · staging'),并在名称发生变化时再次调用(登录、工作区切换)。发现时会读取该标签;你自行创建的名为app_identity的工具也属于上述冲突之一。
当 Agent 为用户的应用创建界面时
- 确保
pubspec.yaml中包含mcp_toolkit。 - 添加返回
Set<AgentCallEntry>或调用一次addEntries的lib/mcp_tools/<domain>_surfaces.dart。 - 在
bootstrapFlutter(...)之前通过addEntries(...)接入——切勿在StatefulWidget生命周期中接入。 - 使用精简的架构;热重启;然后在首次调用客户端之前运行
fmt_list_client_tools_and_resources。
安全性和范围
- 将处理程序视为强大的调试钩子:避免使用机密信息和未经检查的 IO。
- 保持处理程序精简:委托给现有的应用服务。
常见陷阱
- 混用
AgentArguments和Map<String, String>——选择一种 API(原生 API 或mcpToolkitTool)。 addEntries缺少await→ 在发现前发生竞态。inputSchema与处理程序不同步 → Agent 会信任架构;请同时更新两者。
相关内容
flutter-mcp-toolkit-intentcall-migration——CLI 迁移工具,用于破坏性升级flutter-mcp-toolkit-guide→ 检查 / 控制 / 调试技能- 仓库
ARCHITECTURE.md→ “动态注册表架构”