关于 FlutterSDK Artisan
FlutterSDK Artisan 是面向 Flutter 和 Dart 项目的 Dart 命令行框架及 stdio MCP 服务。它整合命令注册、项目脚手架、插件安装、代码生成,以及对运行中 Flutter 应用的控制。
主要功能
- 01统一命令注册
- 02项目与命令脚手架
- 03声明式插件安装
- 04可撤销且幂等的安装
- 05热重载与 VM 控制
- 06用于应用生命周期和检查的 MCP 工具
适用场景
- 01为 Flutter 或 Dart 项目搭建命令行工具
- 02安装插件并撤销其变更
- 03通过 Agent 控制运行中的 Flutter 应用
- 04生成并注册项目命令
MCP 相关
其 stdio JSON-RPC MCP 服务提供应用生命周期和检查工具,以及插件贡献的工具。`mcp:install` 命令会写入 MCP 客户端配置。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
Artisan
适用于 Flutter 和 Dart 的可组合命令行框架和标准输入/输出 MCP 服务。
在一个二进制文件中提供脚手架生成、代码生成、事务式插件安装、热重载编排、REPL,以及 AI Agent 工具接口。
为什么选择 Artisan?
Dart 的命令行功能支离破碎。每个软件包都自创一套安装流程、脚手架脚本和手动编辑的入口文件。采用五种工具的团队最终会有五个 bin/*.dart 包装器、五个 README 安装章节,还会有五次因糟糕的合并而悄然导致构建失败的风险。想要驱动正在运行的应用的 AI Agent,只能求助于临时编写的 shell 脚本,因为没有统一的工具接口。
Artisan 解决了这个问题。 一个二进制文件注册所有命令,一套协议描述所有插件安装流程,一个标准输入/输出 MCP 服务将整个技术栈开放给 AI Agent。
# Before, the painful manual setup ritual
edit pubspec.yaml # add the plugin dependency
edit bin/<custom>.dart # wire the provider
edit lib/main.dart # register the config factory
edit android/app/src/AndroidManifest.xml # add the permission
edit ios/Runner/Info.plist # add the entry
write .env stub # remember which keys
restart the app and hope nothing collided
# After, the Artisan way
dart pub add fluttersdk_artisan
dart run fluttersdk_artisan install
dart run fluttersdk_artisan plugin:install <name>
如果你熟悉 php artisan,就已经了解它的命令形式。实现完全采用 Dart 3.4+ 编写,框架核心不依赖 Flutter 运行时。
功能特性
| 功能 | 描述 | |
|---|---|---|
| 🎼 | 命令注册表 | ArtisanRegistry 收集所有已注册 ArtisanServiceProvider 提供的命令,并在启动时检测冲突 |
| 🧰 | 22 个内置命令 | 生命周期管理、脚手架生成、插件管理、MCP、内省、代码生成,集于一个二进制文件 |
| ✍️ | 签名 DSL | String get signature => 'cmd:name {arg} {--flag}',采用 Dart 记录风格的解析器,需要时回退到 ArgParser |
| 🤖 | MCP 服务 | 基于 dart_mcp 构建的标准输入/输出 JSON-RPC 服务,向 AI Agent 暴露底层组件和插件工具 |
| 🌳 | 无 Magic 路径 | install 为普通 Flutter 和 Dart 项目写入规范包装器,无需依赖框架 |
| 🔌 | 插件协议 | 声明式清单 install.yaml,并提供 PluginInstaller 流式 DSL 作为扩展方案 |
| 🔄 | 幂等安装 | 基于前瞻锚点的正则注入、按名称替换注册表,重复运行安装操作不会造成副作用 |
| ↩️ | 可逆操作 | 每项已执行操作都会记录在 .artisan/installed/<plugin>.json 中,plugin:uninstall 会按相反顺序逐项撤销 |
| 🪞 | VM 服务钩子 | tinker、reload、hot-restart 通过 ext.* 扩展直接驱动正在运行的 Flutter VM |
| 🎯 | 上下文感知生成器 | make:command 可检测插件与使用方上下文,make:plugin 会自动切换至 magic 模式 |
| 🧪 | 可测试的基础组件 | VirtualFs 与 InMemoryFs、InstallContext.test、ArtisanContext.bare、BufferedOutput 捕获 |
快速开始
1. 安装并搭建项目骨架
dart pub add fluttersdk_artisan
dart run fluttersdk_artisan install
install 会写入 bin/dispatcher.dart(调用 runArtisan(...) 的使用方入口),以及各个聚合文件(lib/app/_plugins.g.dart、lib/app/commands/_index.g.dart),然后自动接续执行 make:fast-cli,让 bin/fsa 立即可用。重复运行不会产生副作用;传入 --force 可覆盖现有文件。
搭建项目骨架后,通过使用方封装运行任意内置命令:
dart run artisan list
dart run artisan doctor
dart run artisan start --device=chrome
2. 安装插件
dart pub add awesome_plugin
dart run fluttersdk_artisan plugin:install awesome_plugin
插件可以通过 install.yaml 清单(声明式,由 ManifestInstaller 遍历),也可以通过直接驱动 PluginInstaller 的过程式 ArtisanInstallCommand 子类进行安装。无论采用哪种方式,注册表都会记录每项已执行的操作,以便日后安全地通过 plugin:uninstall 撤销。
插件命令会自动显示。安装 fluttersdk_dusk 后,运行 dart run artisan list,即可在独立的命名空间分区下看到新增的 dusk:* 条目。
3. 为 AI Agent 配置 MCP 服务
./bin/fsa mcp:install
# or, on Windows / when bin/fsa is absent:
# dart run fluttersdk_artisan mcp:install
mcp:install 会在 .mcp.json 中写入或更新 mcpServers.fluttersdk 条目。安装后,重新连接一次 MCP 客户端(对于 Claude Code:/mcp reconnect fluttersdk)。该服务会以 stdio JSON-RPC 模式启动,并公开 10 个基底工具(artisan_start、artisan_stop、artisan_status、artisan_logs、artisan_restart、artisan_reload、artisan_hot_restart、artisan_doctor、artisan_list、artisan_tinker),以及插件提供的任何工具。
请阅读完整的配置步骤:MCP 配置指南。
命令
Artisan 在 6 个命名空间中提供 22 个内置命令。每个命令都是一个带有 signature 字符串和 handle() 方法的 final class X extends ArtisanCommand。
| 命名空间 | 数量 | 命令 |
|---|---|---|
| 生命周期 | 7 | start、stop、status、logs、restart、reload、hot-restart |
| 项目搭建 | 4 | make:plugin、make:command、make:fast-cli、install |
| 插件管理 | 3 | plugin:install、plugin:uninstall、plugins:refresh |
| MCP | 3 | mcp:serve、mcp:install、mcp:uninstall |
| 内省 | 4 | help、list、doctor、tinker |
| 代码生成 | 1 | commands:refresh |
亮点:
# Lifecycle
dart run artisan start --device=chrome # spawn flutter run, record the session under ~/.artisan/sessions/<project>/
dart run artisan reload # send r (hot reload) via FIFO bridge to detached process
dart run artisan hot-restart # send R (hot restart, drops Dart state)
# Scaffolding
dart run artisan make:plugin awesome # 7-file plugin skeleton, auto-upgrades to magic-mode when applicable
dart run artisan make:command Greet # context-aware: plugin vs consumer context, auto-registers in provider
dart run artisan make:fast-cli # compile artisan to native binary at bin/fsa (~50ms startup vs ~3s)
# Introspection
dart run artisan tinker # connected REPL against the running VM
dart run artisan tinker --eval='1 + 1' # one-shot evaluation flag for automation
dart run artisan doctor # preflight checks: flutter + dart on PATH, default port availability
完整的命令目录和各命令的标志参考,请参阅命令目录。
编写自己的命令
make:command 会搭建一个扩展 ArtisanCommand 的 final class,并自动在最近的服务提供程序中注册该类。签名 DSL 从一个字符串中解析参数和标志,handle() 方法会接收一个类型化的 ArtisanContext:
final class GreetCommand extends ArtisanCommand {
@override
String get signature => 'greet {name} {--shout}';
@override
String get description => 'Greet a person by name.';
@override
Future<int> handle(ArtisanContext context) async {
final name = context.input.argument('name');
final shout = context.input.option('shout') == 'true';
final greeting = shout ? 'HELLO, ${name.toUpperCase()}!' : 'Hello, $name';
context.output.success(greeting);
return 0;
}
}
对于签名 DSL 无法表达的情况(位置参数剩余项、互斥标志组),可重写 void configure(ArgParser parser),并直接从 context.input.results 读取。签名 DSL 语法请参阅签名 DSL 参考。
插件协议
Artisan 插件在 install.yaml 中声明其安装内容。ManifestInstaller 会读取这个声明式清单。清单支持 publish(要复制的文件)、magic.provider、magic.configFactory 和 magic.routes(框架接线)、native.android(权限、metaData、gradle 插件、gradle 依赖项)、native.ios 和 native.macos(plist 条目、pod 条目)、native.web(head 注入、meta 标签)、env(带默认值的环境变量声明)、prompts(交互式安装提示)、placeholders(根据提示答案解析令牌)以及 bootstrap_command(安装后提示)。请参阅install.yaml 架构。
最精简的 install.yaml 如下:
publish:
- from: stubs/config.dart
to: lib/config/awesome.dart
magic:
provider: package:awesome/awesome_provider.dart
configFactory: package:awesome/config.dart
native:
android:
permissions:
- android.permission.INTERNET
ios:
plistEntries:
NSCameraUsageDescription: "We need the camera to scan codes."
env:
AWESOME_API_KEY:
default: ""
comment: "API key for awesome.example.com"
bootstrap_command: "Run dart run artisan awesome:bootstrap after install."
对于需要进行 YAML 架构无法表达的运行时分支判断的插件,可继承 ArtisanInstallCommand 并直接调用 PluginInstaller。该 DSL 提供文件操作(writeFile、publishConfig、mergeJson)、源码注入操作(injectImport、injectBefore、injectAfter、injectProvider、injectConfigFactory、injectRoute)、原生操作(injectAndroidPermission、injectIosPlistEntry 等)以及环境操作(injectEnvVar)。每项操作都会延迟并批量执行;只有触发 commit(dryRun:, force:) 后才会写入任何内容:
final class AwesomeInstallCommand extends ArtisanInstallCommand {
@override
String get signature => 'awesome:install';
@override
Future<int> handle(ArtisanContext context) async {
final apiKey = await installer.ask('Enter the awesome API key:');
installer
..injectImport('lib/main.dart', 'package:awesome/awesome.dart')
..injectConfigFactory('Awesome.configFactory')
..injectEnvVar('AWESOME_API_KEY', defaultValue: apiKey)
..injectAndroidPermission('android.permission.INTERNET');
final result = await installer.commit(dryRun: false, force: false);
return result is Success ? 0 : 1;
}
}
完整 DSL 参考请参阅 PluginInstaller DSL 参考。
这些操作具有幂等性(以目标代码为锚点的前瞻正则表达式会在目标代码已存在时跳过操作)、原子性(每次写入都通过 .tmp 文件和原子重命名完成,因此并发读取者不会看到不完整状态),且可逆(每项已执行的操作都会记录在 .artisan/installed/<plugin>.json 中,并附带内容哈希以便在卸载时检测篡改)。
MCP 服务
运行 CLI 命令的同一个二进制文件也会通过 stdio JSON-RPC 提供 Model Context Protocol 工具。无需单独进程,也无需额外的软件包。该服务基于官方 dart_mcp SDK 构建,提供两个工具层。
基底工具(始终启用,共 10 个)。 从 artisan CLI 中精选出一部分功能作为 MCP 工具,让 AI Agent 无需离开聊天界面即可引导 Flutter 应用启动:artisan_start、artisan_stop、artisan_status、artisan_logs、artisan_restart、artisan_reload、artisan_hot_restart、artisan_doctor、artisan_list、artisan_tinker。分发通过注册表在进程内运行;只有 artisan_tinker 需要正在运行的 VM Service。每个命令的 inputSchema 都会与底层命令的 configure(ArgParser) 进行逐字节验证,确保线路契约不会偏离 CLI 接口。
插件工具。 由 ArtisanServiceProvider.mcpTools() 重写提供。分发通过 ext.* VM Service 扩展路由。官方配套插件各自在专门的参考页面维护自己的 MCP 工具目录:
| 插件 | MCP 工具参考 |
|---|---|
fluttersdk_dusk | fluttersdk.com/dusk/mcp/tool-reference |
fluttersdk_telescope | fluttersdk.com/telescope/mcp/tool-reference |
三层筛选管道(.artisan/mcp.json 文件、ARTISAN_MCP_* 环境变量、mcp:serve 上的 CLI 标志)允许运维人员按 Cargo 风格的优先级允许或拒绝工具和软件包;每一层都以拒绝规则优先。示例:
// .artisan/mcp.json
{
"packages": { "deny": ["fluttersdk_telescope"] }
}
# Env (process-scoped, overrides file)
export ARTISAN_MCP_PACKAGES_DENY=fluttersdk_telescope
# CLI (session-scoped, overrides env)
dart run fluttersdk_artisan mcp:serve --exclude-tool artisan_stop
结果:Telescope 软件包被文件移除,也被环境变量拒绝(并集操作具有幂等性);本次会话中,artisan_stop 被 CLI 标志移除。
mcp:install 写入客户端配置项后,所有支持 MCP 的 Agent 都可以按需启动该服务:
// .mcp.json (managed by mcp:install)
{
"mcpServers": {
"fluttersdk": {
"command": "./bin/fsa",
"args": ["mcp:serve"],
"cwd": "."
}
}
}
当 bin/fsa 不存在(或主机是 Windows,因为 POSIX shim 不适用)时,mcp:install 会改为写入 {"command": "dart", "args": ["run", ":dispatcher", "mcp:serve"]}。传入 --invocation=<executable> 可覆盖回退入口点:随后 mcp:install 会写入 {"command": "dart", "args": ["run", "<executable>", "mcp:serve"]};当使用方的入口点是插件包装器而非通用的 :dispatcher 时,这是正确的格式(例如,dart run fluttersdk_artisan mcp:install --invocation=fluttersdk_dusk)。优先级:如果主机是 POSIX 且存在 bin/fsa,则使用 bin/fsa;否则,如果提供了 --invocation,则使用它;否则使用默认的 :dispatcher。
如果在 initialize 时没有记录该项目的会话(没有正在运行的 Flutter 应用),服务仍保持在线,可使用 10 个基底工具,且未注册任何插件工具。在下一个需要 VM Service 的 tools/call 中,服务会通过一个经过记忆化的进行中 future 懒惰地重新连接,让 MCP 客户端无需重新连接即可适应 Flutter 应用自然的启动和停止开发周期。
设置步骤请参阅 MCP 设置指南。完整工具参考请参阅 工具参考。
架构
Artisan 在 lib/src/ 下采用子系统优先的组织方式,每个目录负责一个独立的关注点:
lib/
├── artisan.dart # Single barrel, re-exports the full public API
├── fluttersdk_artisan.dart # Convention sibling, re-exports the same surface
└── src/
├── console/ # ArtisanApplication, ArtisanRegistry, CommandSignature DSL, ArtisanContext
├── commands/ # 21 built-in commands, one final class per file
├── installer/ # PluginInstaller DSL, ManifestInstaller, InstallTransaction, sealed InstallOperation
├── mcp/ # McpServer, McpToolDescriptor, McpFilterConfig (3-layer filter pipeline)
├── helpers/ # FileHelper, ConfigEditor, MainDartEditor, EnvEditor, PlistWriter, StringHelper
├── stubs/ # StubLoader, asset bundle plus filesystem resolution
├── state/ # StateFile, JSON persistence for start, stop, status, mcp:serve discovery
├── tinker/ # Connected REPL primitives over ext.tinker.evaluate
└── vm/ # VmServiceClient, wraps package:vm_service, DDS-aware, no isolate-id cache
启动时的流程:
runArtisan(args)
↓
ArtisanApplication.create(providers, builtins)
↓
ArtisanRegistry.registerAll(providers + builtins) # collision-detected
↓
[CLI path] dispatch by signature OR [MCP path] collectMcpTools then serve stdio
↓
ArtisanCommand.handle(ArtisanContext)
所有公共类型都是 final class。只要操作集或结果集是封闭的,就使用 Dart 3 穷尽性检查进行密封分发(InstallOperation 有 28 个密封子类,TransactionResult 有 4 个)。新增操作或结果变体会强制所有分发器同步更新,避免无声偏离。
AI Agent 集成
将 Artisan 与 Claude Code、Cursor 或 GitHub Copilot 等 AI 编码助手搭配使用。MCP 服务可让 Agent 直接访问工具:启动 Flutter 应用,通过 Dusk 驱动 widget 交互,通过 Telescope 检查 HTTP 流量,通过 Tinker 执行 Dart 表达式,无需启动 shell 或通过模式匹配分析日志输出。
典型的 Agent 会话如下:
[agent] artisan_doctor // verify toolchain
[agent] artisan_start { device: chrome } // launch the app
[agent] <fluttersdk_dusk tool> // capture Semantics tree, drive interaction
[agent] <fluttersdk_telescope tool> // inspect HTTP, logs, exceptions
[agent] artisan_tinker { eval: "User.find(1)" } // poke the running VM
[agent] artisan_stop // tear down
请参阅各插件的 MCP 工具参考,了解当前工具目录 (fluttersdk_dusk、 fluttersdk_telescope)。
对于在连接时读取结构化项目上下文的 Agent,规范入口是仓库根目录中的 llms.txt(也发布于 https://fluttersdk.com/artisan/llms.txt)。它以 Agent 可读的形式列出了命令范围、插件协议和 MCP 工具目录。
技能文件和各 Agent 的设置指南:fluttersdk/ai。
文档
完整文档和在线示例请访问 fluttersdk.com/artisan。
| 主题 | |
|---|---|
| 入门 | 概述、要求、第一个命令 |
| 安装 | dart pub add fluttersdk_artisan 以及使用方脚手架 |
| 快速入门 | 从空仓库到运行 MCP 服务的 3 步流程 |
| 命令 | 21 个内置命令,按命名空间分组 |
| 签名 DSL | 参数和标志声明语法 |
| 插件编写 | 插件编写的 5 步流程 |
| install.yaml 架构 | 每个区段、每个键和每个示例 |
| PluginInstaller DSL | 过程式扩展方案参考 |
| MCP 概述 | 基础层与插件工具层、软失败生命周期 |
| MCP 设置 | 按客户端安装(Claude Code、Cursor、Continue) |
| MCP 工具参考 | 所有工具、所有输入架构和所有调用示例 |
贡献
git clone https://github.com/fluttersdk/artisan.git
cd artisan && dart pub get
dart test && dart analyze
基准是在受影响文件范围内约有 1070 项测试通过。新增行为需附带相应测试(红、绿、重构)。dart format lib/ test/ bin/ 必须不产生差异,且 dart analyze 在 lib/、test/ 和 bin/ 中必须报告零问题。
提交拉取请求前,还请运行:
dart format lib/ test/ bin/ # zero diff
dart analyze # zero issues
dart pub publish --dry-run # validate the publish archive
发布归档的压缩大小必须低于 500 KB。.pubignore 会将 example/、example_magic/、build/、coverage/ 和编辑器脚手架排除在 pub 归档之外;如果新增不应发布的顶层目录,请将其加入其中。
许可证
MIT,详情请参阅 LICENSE。
由 FlutterSDK 用心打造
如果 Artisan 为你节省了时间,请在 此处点星,帮助更多人发现它。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。