flutter-mcp-toolkit-custom-tools について
Flutter 開発者向けに、動的レジストリを使ってアプリ固有の MCP ツールやリソースを追加する方法を説明するスキルです。エントリーの選択、登録方法、エージェントからの検出手順を扱います。
主な機能
- 01ツールと読み取り専用リソースの選択
- 02アプリ起動時のエントリー登録
- 03厳密な JSON Schema の定義
- 04アプリ項目の検出と呼び出し
- 05ライフサイクルと名前の衝突回避
活用シーン
- 01エージェントへのカート概要の提供
- 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 ツールキットのツールとリソース(動的レジストリ)
組み込みの MCP ツール(スクリーンショット、セマンティックスナップショット、タップなど)では不十分で、アプリ固有の読み取りサーフェスやアクション(カートの合計、機能フラグ、内部状態を厳選したデバッグスナップショットなど)が必要な場合に使用します。エントリは Flutter プロセス内で登録され、動的レジストリを通じてエージェントに公開されます。
移行: 従来の呼び出しエントリ型は intentcall Phase 6b で削除されました。
AgentCallEntryまたはmcpToolkitTool/mcpToolkitResourceを使用してください。詳しくはflutter-mcp-toolkit-intentcall-migrationを参照してください。
境界: アプリの検出、Flutter VM サービス拡張、または アプリ所有のデバッグサーフェスを変更する場合は、こちらで行います。正規レジストリ/セッションのセマンティクス、 スキーマポリシー、プラットフォーム投影、または公開動作を変更する場合は、上流の 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(ブリッジ)
組み込みのツールキットでは、Map<String, String> のサービス拡張ハンドラーを適合させるため、引き続き mcpToolkitTool / mcpToolkitResource を使用します。
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: { ... }) を使用することを推奨します。
ブートストラップ時に一度だけ登録してください。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/...の規則に従います。エージェントはfmt_client_resourceとfmt_list_client_tools_and_resourcesの一覧を使用します。
スキーマのルール(ツール)
MCP サーバーは厳格な JSON Schema を適用します。
- 任意のキーを意図的に受け入れる場合を除き、
additionalProperties: falseを優先してください。 - ハンドラーが無条件に読み取る項目には
requiredを指定してください。 AgentResult.data/MCPCallResult.parametersは JSON にシリアライズ可能でなければなりません。
エージェント側からの検出
fmt_list_client_tools_and_resources— アプリに登録されたツールとリソースを列挙します。fmt_client_tool— JSON 引数を指定して、名前で動的ツールを呼び出します。fmt_client_resource— 一覧にある登録済みリソース URI を取得します。
表示されるはずのものが表示されない場合は、addEntries が完了していること(await)を確認してから、ホット再起動してください。
ライフサイクルでの注意点
- ホットリロード中にウィジェットコードから
addEntriesを呼び出すと、登録が重複します。main()/ bootstrap で一度だけ登録してください。 - デバッグモードのみ — リリースビルドでは VM サービス拡張は公開されません。
- 命名: アプリではフラットなグローバル名前空間を使用します。ツール/リソースには接頭辞(
cart_、flags_、nav_)を付けてください。組み込みのエントリがすでに同じ名前を使用している場合、カスタムエントリは警告なしでスキップされます。呼び出しは組み込みのエントリが処理し、カスタムハンドラーは実行されません。 - 実行中のインスタンスの命名には
MCPToolkitBinding.instance.setAppIdentity(label: 'Fleet app · staging')を使用します。名前が変わるたび(サインイン、ワークスペース切り替え)に再度呼び出してください。検出ではそのラベルが読み取られます。また、自作のapp_identityというツールは、前述の名前衝突に該当します。
エージェントがユーザーのアプリ向けサーフェスを作成する場合
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(ネイティブかmcpToolkitTool)をどちらか一つ選びます。addEntriesにawaitを付け忘れると、検出前に競合状態が発生します。inputSchemaとハンドラーの内容が一致していないこと。エージェントはスキーマを信頼するため、両方を更新してください。
関連項目
flutter-mcp-toolkit-intentcall-migration— CLI マイグレーター、破壊的変更を伴うアップグレードflutter-mcp-toolkit-guide→ 検査/制御/デバッグのスキル- リポジトリの
ARCHITECTURE.md→ 「動的レジストリアーキテクチャ」