- 桌面应用
- 开发工具
【免费下载链接】MooTool
Handy tool set for developers
导读
本文基于 MooTool 仓库next-compose子项目的 DIFF-131 设计文档,深入讲解 Compose 桌面版如何对照 Electron 版AiIntegrationSettings与aiIntegrationService,落地"设置中的 AI 接入 + MCP(Model Context Protocol)子进程运行时"这一首版能力。你将掌握:AI 接入设置面板的完整形态与交互、--mcp子进程的引导与工具注册机制、Codex/Claude Code/Cursor 三类客户端配置文件的合并写入策略,以及安装预览、连接测试、数据只读授权等核心流程的实现原理与测试证据。
一、DIFF-131 要解决什么问题
MooTool 的next(Electron)分支已经具备完整的 AI 接入能力(设置窗口中的AiIntegrationSettings、主进程aiIntegrationService)。DIFF-131 的目标是:在next-compose(Kotlin Compose Desktop 重写版)中把同一套能力按首版标准落地,形成三条工作线:
- A01 设置(Settings):在设置导航中新增AI 接入(Ai)分类,位于"运行环境(Runtime)"与"工具(Tools)"之间,提供客户端/模式选择、安装预览、测试连接、随手记与 JSON 只读授权开关。
- MCP 运行时:新增
--mcp子进程入口(Main.kt→McpBootstrap),以 stdio 传输方式对外提供 MCP 工具,复用现有的JsonEngine/EncodeEngine/TimeEngine/DiffEngine等领域引擎。 - 安装(Install):向 Codex 的 TOML 配置、Claude Code / Cursor 的
mcp.json合并mootool服务器配置;Skill 文件写入SKILL.md(模板来自 resources/mcp/SKILL.md)与runtime.md。
这一阶段明确的两项边界:安装 receipt 与manageServer的细节落在 DIFF-133,Vault MCP 只读工具落在 DIFF-132;且首版未在本机对真实 Codex/Claude/Cursor 客户端做端到端安装验收。
二、A01 设置面板:AI 接入导航分类
2.1 导航位置
SettingsNavCategory枚举(SettingsNavCategory.kt)的声明顺序为:General, Appearance, Layout, Editor, Network, Data, Vault, Runtime, Ai, Tools, Shortcuts, About。Ai恰好位于Runtime(运行环境)与Tools(工具)之间,与文档描述一致,并在设置界面通过SettingsNavCategory.Ai -> AiIntegrationSettingsPanel(container)挂载(SettingsScreen.kt)。
2.2 面板能力与交互
AiIntegrationSettingsPanel(AiIntegrationSettingsPanel.kt)由remember { mutableStateOf(...) }维护全部状态,核心要素如下:
| 控件 | 可选项 / 行为 | 说明 |
|---|---|---|
| 客户端(client) | Codex/Claude Code/Cursor | 切换为Cursor时,安装模式被强制为MCP(Cursor 只支持 MCP 安装) |
| 安装模式(mode) | MCP + Skill/MCP/Skill | Cursor客户端不展示MCP + Skill与Skill选项 |
| 安装状态 | MCP: …Skill: … | 状态机为NotInstalled / Installed / NeedsRepair / Conflict四态 |
| 安装按钮 | 点击后执行container.aiIntegration.install(id) | 依赖预览存在且非忙态 |
| 测试连接 | 点击后执行testConnection() | 成功时 Toast 显示返回的工具数量 |
| 刷新 | 使revision += 1,触发LaunchedEffect重新拉取状态/预览 |
每个控件的变更都会触发refresh():在Dispatchers.IO中并行读取getStatus(client)、getDataAccess()与preview(AiInstallRequest(client, mode)),任何失败都会显示在面板的错误文本中(红色,colors.danger)。
2.3 数据只读授权开关
面板底部是"数据访问"分组,包含两个MooSwitch:
- 随手记(notes)授权:
container.aiIntegration.setDataAccess(AiDataAccessRequest(notes = enabled, json = jsonAccess)) - JSON 文档(json)授权:
container.aiIntegration.setDataAccess(AiDataAccessRequest(notes = notesAccess, json = enabled))
底层实现(AiIntegrationService.kt)把授权结果持久化到ai-integration/access.json(McpLaunchResolver.accessFile),字段为{"version":1, "notes": "<realpath 绝对路径>", "json": "<realpath 绝对路径>"}:
- 开启授权前校验对应 Vault 根目录必须存在,否则抛出
The MooTool vault directory is unavailable; - 保存的是
root.toRealPath().toString()规范化后的绝对路径(与 ElectronsetDataAccess对齐); - 当用户在设置中更换数据目录或 Vault 路径时,
AppContainer会自动把授权重置为关闭(AppContainer.kt),避免旧路径悬空。
这些只读工具与访问控制落在 DIFF-132 的VaultMcpReadService/VaultMcpTools中,未授权时调用会直接失败。
三、MCP 子进程运行时:--mcp入口与工具注册
3.1 入口分流
main函数(Main.kt)先检查命令行参数:
fun main(args: Array<String>) { if (args.contains("--mcp")) { McpBootstrap.run(args) return } application { /* 正常桌面 GUI 启动 */ } }即:当 AI 客户端以命令 + --mcp方式拉起本进程时,进程不再启动 Compose 窗口,而是以纯 MCP stdio 服务模式运行——这与 Electron 版ELECTRON_RUN_AS_NODE=1+mcp.js的启动路径不同,但对外协议一致。
3.2 McpBootstrap 引导逻辑
MCP 引导类完成以下步骤:
parseAccessFile(args):解析--access-file <path>,用于向 Vault 工具传递授权文件位置;- 通过
StdioServerTransportProvider+McpJsonDefaults.getMapper()建立标准输入输出传输; McpServer.sync(transport).serverInfo("MooTool", ProductIdentity.VERSION)声明服务标识;- 遍历
McpToolCatalog.registrations(),为每个注册表项构建带inputSchema与annotations(readOnlyHint等)的McpSchema.Tool; - 在工具调用回调中按名称分流:
VaultMcpTools.isVaultTool(name)走VaultMcpTools.call(name, map, accessFile),否则走MooToolMcpTools.call(name, map); builder.build()后Thread.currentThread().join()常驻等待。
3.3 工具目录:从 7 个到 12 个
DIFF-131 基线登记了mootool_json_format等7 个通用工具;后续迭代(例如 DIFF-554 中补充protobuf_wire)使目录扩展。当前仓库McpToolCatalog(McpToolCatalog.kt)注册了8 个通用工具 + 4 个 Vault 只读工具 = 12 个,测试AiIntegrationMcpListToolsTest与AiIntegrationConnectionTest均断言tools.size == 12。
通用工具(mootool_*)
| 工具名 | 能力 | 入参 Schema 要点 |
|---|---|---|
mootool_json_format | 格式化/压缩 JSON,可排序键、拒绝重复键 | text(≤100000, 必填),spaces(0–8, 默认2),sortKeys(默认false),checkDuplicateKeys(默认true) |
mootool_json_query | JSONPath 查询,返回匹配数组 | text(≤100000, 必填),path(1–1000, 必填);禁用脚本/过滤表达式 |
mootool_encode | Base64/URL/十六进制/Unicode 转码 | text,format(base64|url|hex|unicode),direction(encode|decode),charset(utf-8|gb2312) |
mootool_timestamp | Unix 时间戳与本地时间互转 | text(≤100),direction(to-local|to-timestamp),unit(second|millisecond),zone(默认UTC);13+ 位按毫秒识别 |
mootool_diff | 双文本对比 | left/right(各≤8000),ignoreWhitespace(默认false) |
mootool_hash | 计算摘要(十六进制) | text,algorithm(md5|sha1|sha256|sha384|sha512, 默认sha256) |
mootool_uuid | 本地生成 v4 UUID | count(1–100, 默认1) |
mootool_protobuf_wire | protobuf wire 字节解码(无需 .proto) | text,format(hex|base64) |
Vault 只读工具(4 个):mootool_notes_search/mootool_notes_read/mootool_json_documents_search/mootool_json_documents_read,均标记idempotentHint=true;search 参数为query(≤200)、limit(1–50)、offset(0–2000),read 参数为path(必填)、offset(0–2,000,000)、length(1–50,000)。这些工具严格遵守只读授权与.gitignore/符号链接排除规则。
3.4 复用领域引擎与输入边界
MooToolMcpTools(MooToolMcpTools.kt)把每个工具映射到既有引擎,做到"一套引擎、多端复用":
mootool_json_format→JsonEngine.formatAdvanced(..., JsonFormatOptions(spaces, sortKeys, checkDuplicateKeys, ignoreCase=false));mootool_json_query→JsonEngine.queryPath,且显式拒绝含?(的 JSONPath 过滤表达式(JSONPath filter expressions are disabled for MCP tools);mootool_encode→EncodeEngine.urlEncode/urlDecode/textToHex/hexToText/toUnicode/fromUnicode,Base64 解码前用正则校验;mootool_timestamp→TimeEngine.timestampToLocal / localToTimestamp,13+ 位数字自动按毫秒解释(对齐 ElectrontimeTools.timestampToLocal);mootool_diff→DiffEngine.compare,返回包含unified/added/removed/changed的 JSON 对象;mootool_hash→MessageDigest实现五种算法;mootool_protobuf_wire→ProtobufEngine.decodeWire(Hex/Base64 两种输入)。
安全与健壮性设计值得在集成时注意:
- 输入上限:通用文本工具
100_000字符,时间戳100、diff 每侧8_000、JSONPath1_000; - 参数白名单:
requireKnownKeys拒绝任何未登记字段;requireStringArg/boundedIntArg对类型与边界做严格校验,越界直接报错而非静默钳制; - 所有工具返回
McpToolResult(text, isError),异常信息原样返回给调用方。
四、安装流程:配置文件合并、Skill 写入与 receipt
4.1 三类客户端的目标文件
AiIntegrationService.configPath()(AiIntegrationService.kt)按客户端解析家目录下的配置文件:
| 客户端 | 配置文件 | 格式 |
|---|---|---|
| Codex | ~/.codex/config.toml | TOML,[mcp_servers.mootool] |
| Claude Code | ~/.claude.json | JSON/JSONC,mcpServers.mootool |
| Cursor | ~/.cursor/mcp.json | JSON/JSONC,mcpServers.mootool |
4.2 合并策略与冲突检测
AiClientConfigMerge(AiClientConfigMerge.kt)负责安全合并,与 ElectronaiIntegrationConfig.ts(next/electron/main/aiIntegrationConfig.ts)逐项对齐:
- TOML 侧:用
org.tomlj解析;若已存在mcp_servers.mootool且与期望 launch 不一致,抛出"已存在不同配置,请重命名或删除后重装";追加的块为:[mcp_servers.mootool] command = "…" args = ["--mcp", "--access-file", "…"] - JSON 侧:用 Jackson 解析,开启
ALLOW_COMMENTS、ALLOW_TRAILING_COMMA与STRICT_DUPLICATE_DETECTION。若源文件含注释/尾逗号(JSONC 风格),走insertJsonServerEntry文本级插入以保留用户注释;否则用 pretty printer 规范化输出;重复键、mcpServers非对象、语法损坏都会拒绝合并(测试见 AiClientConfigMergeTest.kt)。 - 外部篡改防护:
manageServer在安装/修复/卸载时对照安装时保存的 receiptmcp字段;若条目被用户或第三方改过且不在 receipt 中,直接拒绝并提示"配置在安装器之外被修改"。
4.3 MCP 启动命令(launch)
McpLaunchResolver(McpLaunchResolver.kt)生成当前进程的 MCP 启动命令:
fun clientLaunch(accessFile: Path): McpLaunch { val command = ProcessHandle.current().info().command().orElse(javaBinary()) val args = listOf("--mcp", "--access-file", accessFile.absolutePathString()) return McpLaunch(command = command, args = args) }- 开发阶段:
command为 JVMjava(javaBinary()回退逻辑处理了java.exe的 Windows 差异); - 打包后:为当前进程可执行文件 +
--mcp; - 与 Electron 的
ELECTRON_RUN_AS_NODE=1+mcp.js路径不同,但 stdio 协议一致。
4.4 Skill 文件与运行时提示
安装时(模式含 Skill)写入两个文件到~/.agents/skills/mootool/(Codex)或~/.claude/skills/mootool/(Claude Code):
SKILL.md:模板来自打包资源 resources/mcp/SKILL.md,frontmatter 声明name: mootool与"使用本地 MooTool 做开发工具与只读搜索/读取"的描述,正文指导模型优先使用mootool_*MCP 工具、遵守授权开关、不要绕过只读授权读取底层文件;runtime.md:运行时生成,记录本次安装的可执行文件与命令行调用方式,例如:<当前命令> <--mcp …参数> --list
SKILL.md同时记录了无 MCP 连接时的 CLI 兜底路径(--list发现工具、--call TOOL_NAME从 stdin 传 JSON 参数),该路径由 Electron 侧 next/electron/mcp/index.ts 实现。
4.5 安装事务:预览 → 校验 → 写盘 → 回滚
AiIntegrationService的安装是"事务式"的(AiIntegrationService.kt):
- preview():生成
AiInstallPreview,列出每个文件的前后内容与动作(create/update/delete/unchanged),记录 receipt 内部变更,plan 有效期10 分钟,并发只保留最多 20 个 plan; - install(id):执行前逐文件
assertUnchanged(防止预览过期后文件被改);非卸载场景先做连接验证(testConnection()或注入的connectionVerifier); - 每个变更文件先
atomicWrite一个*.mootool-backup-*备份,再写目标文件; - 全部写完后逐文件比对校验;任何一步失败则逆序回滚已写文件;回滚也失败时提示用户从备份手动恢复。
安装 receipt 持久化到ai-integration/{codex|claude-code|cursor}.json,包含schemaVersion=1、appVersion、mcp与skills(内容 SHA-256 摘要),用于状态判定与外部篡改检测(详见 DIFF-133)。
五、测试连接:真正的端到端握手
设置面板的"测试连接"调用AiIntegrationService.testConnection()(AiIntegrationService.kt),它不是桩实现,而是真实启动一次 stdio 子进程:
- 用
StdioClientTransport+ServerParameters以当前 launch 启动子进程,10 秒请求超时; initialize()完成 MCP 握手,listTools()必须覆盖MooToolMcpTools.toolNames()+VaultMcpTools.toolNames全部12 个工具,缺失即失败;- 调用
mootool_json_format({"moo":true}, spaces=0),断言返回文本严格等于{"moo":true}; - 返回
AiConnectionResult(serverName = "MooTool", tools = [...])。
对应的自动化测试是 AiIntegrationConnectionTest.kt:它用临时目录构造AppContainer,以desktopTestMcpLaunch注入测试 launch,真实拉起子进程完成握手并断言 12 个工具齐全——这直接印证了生产路径testConnection的实现;AiIntegrationMcpListToolsTest.kt 则额外校验readOnlyHint与inputSchema.type === object。
六、依赖与资源
MCP 与 TOML 解析依赖集中在 gradle/libs.versions.toml:
| 依赖 | 版本 | 用途 |
|---|---|---|
io.modelcontextprotocol.sdk:mcp | 0.18.1 | MCP 客户端/服务端 SDK、stdio 传输、schema 构建 |
org.tomlj:tomlj | 1.1.1 | Codexconfig.toml的解析与合并 |
在 build.gradle.kts 中分别以implementation(libs.mcp)、implementation(libs.tomlj)声明于desktopMain依赖块。实现相关的主要源文件:
- 入口分流:Main.kt
- MCP 服务:McpBootstrap.kt、McpToolCatalog.kt、MooToolMcpTools.kt
- 安装与状态:AiIntegrationService.kt、AiClientConfigMerge.kt、McpLaunchResolver.kt
- 设置面板与导航:AiIntegrationSettingsPanel.kt、SettingsNavCategory.kt
- Skill 模板:resources/mcp/SKILL.md
- 对照参考:Electron aiIntegrationService.ts、mcp/server.ts、mcp/index.ts
七、已知边界与后续演进
按 DIFF-131 的自我声明,本阶段存在两项明确边界:
- 未做真实客户端端到端验收:未在本机对真实 Codex / Claude / Cursor 客户端执行安装后的端到端验证,
AiClientConfigMergeTest等单测通过隔离的临时目录模拟了合并与安装行为; - 打包后
--mcp路径待验证:开发态 launch 为java,打包态为"当前进程可执行文件 +--mcp",该打包态路径的验证被推迟到 P7 阶段。
后续 DIFF 系列补齐了 receipt 管理(DIFF-133)、Vault 只读工具(DIFF-132)、重复键检测、Codex TOML Skill 安装等能力。集成方在复刻这套方案时,建议重点守住三条底线:合并前必须语法校验与重复键检测、写盘必须可回滚并留备份、只读工具必须受 access.json 授权约束。
- 桌面应用
- 开发工具
【免费下载链接】MooTool
Handy tool set for developers
相关推荐
MooTool 格式化与配置转换导入 toast 的实现解析:Compose 版对照 Electron ToastProvider 的 DIFF-119 落地
MooTool 格式化与配置转换导入 toast 的实现解析:Compose 版对照 Electron ToastProvider 的 DIFF 119 落地
桌面应用开发工具MooTool Compose 桌面版 P5 工具工作区壳(local-tool-shell)样式对齐实现解析(DIFF-091)
MooTool Compose 桌面版 P5 工具工作区壳(local tool shell)样式对齐实现解析(DIFF 091) 导读 本文解析 MooToo
桌面应用开发工具MooTool Next Compose 交互反馈与 Vault 重载一致性落地:DIFF-124 全解析
MooTool Next Compose 交互反馈与 Vault 重载一致性落地:DIFF 124 全解析 导读 本文围绕 MooTool 仓库中 next c
桌面应用开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考