第 11 章:Skills、Runtime 能力、MCP 与 Connected Apps
11.1 四种容易混淆的能力
Multica 里的“Agent 能做什么”来自四个来源:
| 能力 | 本质 | 生命周期 |
|---|---|---|
| Workspace Skill | 数据库存储的说明与文件包 | 跟随工作区与 Agent 绑定 |
| Runtime-local Skill | Daemon 所在机器已有的 Skill | 跟随机器、Provider 和本地目录 |
| MCP Server | 可调用工具的协议端点 | Agent 静态配置或任务级 Overlay |
| Connected App | 用户已授权的 SaaS 能力 | 跟随 Owner 的连接和本次 Run |
Skill 主要告诉 Agent 如何工作;MCP 提供真正的工具调用;Connected App 是动态生成 MCP Session 的上层产品概念。把它们合成一个“插件列表”会看不懂权限和缓存。
11.2 Workspace Skill 的数据模型
数据库查询入口在 server/pkg/db/queries/skill.sql,Handler 在:
核心关系是:
- Skill:名称、描述、主
SKILL.md内容、来源; - Skill File:References、Scripts、Templates 等支持文件;
- Agent Skill:Agent 与 Skill 的绑定;
- Built-in Skill:随 Server 发布、可按规则装入工作区。
Agent 不直接持有一份可变副本,而是引用 Skill。这样修订、权限、去重与版本归因有统一事实源。
11.3 Import 的资源上限
当前 Handler 明确限制:
- 单文件最多 1 MiB;
- 支持文件总计最多 8 MiB;
- 支持文件最多 256 个;
- 路径必须安全,不能越过 Skill 根;
- 嵌套目录里的其他
SKILL.md不当普通支持文件导入。
这些限制既防内存和网络滥用,也保证每次 Claim 不会携带一个近似仓库大小的能力包。
11.4 内容寻址 Bundle
server/pkg/skillbundle/hash.go 为主内容和每个支持文件计算 SHA-256,并得到整体 Bundle Hash。
Server Claim 可以只发 SkillRefData:
- Source / ID;
- Name / Description;
- Bundle Hash / Size / File Count;
- 各文件 Path / SHA-256 / Size。
Daemon 命中缓存便不下载正文;未命中才通过受控 API Resolve Bundle。
11.5 Daemon 缓存不是盲信磁盘
server/internal/daemon/skill_cache.go 的缓存键包含 Workspace 与引用信息,并在 Load 后调用 validateSkillBundle:
- ID、Source、Hash 必须匹配;
- 文件路径必须安全;
- 逐文件摘要必须一致;
- Bundle 元信息必须与 Ref 对齐。
每个 Ref 还有进程内锁,避免并发任务同时下载和覆盖同一 Bundle。坏缓存按 Miss 处理,不把篡改内容直接注入 Agent。
11.6 下载超时随 Bundle 尺寸缩放
ensureTaskSkillBundles 在 Task Start 前解析所有引用。
当前超时策略:
- 最少 30 秒;
- 按保守 50 KiB/s 估算;
- 最多 5 分钟。
这比固定短超时适合 8 MiB 上限的合法 Bundle,也防止一个卡死下载永久占用 Prepare Lease。
11.7 Skill 物化
解析完成后,execenv/context.go 把 Skill 写入 Provider 可发现目录:
- 主文件固定为
SKILL.md; - 支持文件保留相对目录;
- 路径经过清洗;
- 所有写入进入 Sidecar Manifest;
- 名称转换成文件系统安全 Slug。
如果导入内容没有有效 YAML Frontmatter,Daemon 用 ensureSkillFrontmatter 补出 name 与 description。修复发生在物化层,原始数据库内容仍可追踪。
11.8 Runtime-local Skill
用户的 Claude、Codex 或其他 Provider Home 里可能已经装有 Skills。Daemon 通过 local_skills.go 枚举:
- Provider 专用 Skill Roots;
- 通用
~/.agents/skills; - Claude Plugin 中带命名空间的 Skills;
- 受支持目录深度内的合法
SKILL.md。
Runtime-local Skill 不上传为默认全文。Daemon 先报告摘要,用户可显式 Import 到 Workspace,或让 Runtime 自己按 Provider 规则发现。
11.9 本地枚举同样有限额
本地扫描沿用:
- 1 MiB 单文件;
- 8 MiB Bundle;
- 256 文件;
- 有限目录深度;
- Symlink/Visited 防循环;
- 隐藏、构建产物等忽略规则。
本机文件仍是不可信输入。没有限制的递归扫描会让一个损坏 Plugin 或巨大依赖目录拖垮心跳任务。
11.10 禁用 Runtime Skill
Workspace Agent 可以携带 DisabledRuntimeSkills,身份由 Runtime ID、Provider、Root、Key 共同确定。
runtime_skill_policy.go 按 Provider 选择隐藏办法:
- 有些 Provider 可通过独立 Home 隔离;
- 有些需要复制/链接时排除目录;
- 有些只能在生成配置中撤掉发现路径。
这不是删除用户机器上的 Skill,而是限制当前 Agent 进程的可见性。
11.11 Agent 静态 MCP 配置
Agent 的 mcp_config 使用统一外形:
{
"mcpServers": {
"name": {
"command": "example",
"args": ["serve"]
}
}
}
这一 JSON 是控制平面的规范形状。Daemon 再按 Provider 生成:
- Codex Config;
- Cursor MCP 文件;
- OpenCode/OpenClaw 配置;
- Hermes/ACP Session 参数;
- 支持直接参数的 Provider 调用选项。
“统一存储”并不意味着“统一落盘格式”。
11.12 任务级 MCP Overlay
Connected Apps 等动态能力只应活在本次 Task。Server 在 Claim 时生成 Overlay,并由 mcp_overlay.go 与 Agent 静态配置做浅合并。
合并契约:
- 只在
mcpServers内按 Server Name 合并; - 名称冲突时 Overlay 胜出;
- Agent 其他顶层字段原样保留;
- Overlay 不得偷偷引入其他顶层键;
- Overlay 非法时返回错误,同时不静默丢掉原 Agent 配置;
- 空值和 JSON
null都按“无托管配置”处理。
Overlay 胜出是必要的:动态 Session URL/Token 比管理员留下的静态占位配置更新、更具体。
11.13 Connected App 的真实授权主体
Claim 会把 Connected App 的名称与能力摘要写进 Brief,但真正工具连接由 Server 在任务级构造。
当前实现要分清两条链:
- Task Initiator 决定“谁发起了这个请求”,用于审计、Prompt 归因和入口权限判断;
- Agent Owner / Runtime Owner 决定“运行时可使用谁的已连接应用”。
因此,同事 @ 一个共享 Agent 并不会借出自己的 Gmail/Calendar 连接;Agent 使用 Owner 已建立且允许的连接。源码与相关测试把 Owner Scope 作为当前行为,不能仅凭 Initiator 字段推断凭据切换。
11.14 Composio Overlay
Composio 客户端实现位于 server/pkg/composio;工作区集成 Handler 在 integrations_composio.go。
大体流程:
- 用户为 Toolkit 建立 Connected Account;
- Workspace/Agent 允许该 Toolkit;
- Task Claim 检查 Agent 与调用入口权限;
- Server 为 Owner 创建短期 MCP Session;
- Session Endpoint 进入任务 Overlay;
- Daemon 只把 Overlay 注入当前 Provider 环境;
- Task 结束后不把动态 Session 写回 Agent 静态配置。
Brief 只展示应用元数据,不嵌入秘密 Token。
11.15 Runtime MCP 与浏览器能力
Daemon 还会按 Runtime/Provider 叠加机器能力,相关入口包括:
这类配置描述本机浏览器、Provider 支持或 Runtime Profile 的能力。它与用户 Connected App 不同:前者属于执行节点,后者属于用户授权。
最终配置需要同时满足 Provider Capability、Agent Allowlist、Task Overlay 和 Runtime 可用性。
11.16 能力装配顺序
注意:Skill 文件和 MCP 配置走不同路径。一个 Skill 可以指导 Agent 调某个 CLI,但不会自动授予 MCP 凭据;一个 MCP Server 可调用,也不代表 Agent 知道何时正确使用,除非 Brief/Skill 提供语义。
11.17 Provider 差异
能力交付常见差异:
- 支持原生 Skills 的 Provider 可直接发现目录;
- 不支持者需要把 Skill 摘要写入 Brief;
- Codex 使用隔离的 Codex Home 和配置层;
- Cursor/OpenCode/OpenClaw 有各自 Sidecar Schema;
- ACP Provider 可能在
session/new时声明 MCP Servers; - 部分 Provider 不支持某类 MCP Transport。
所以新 Provider 不能只实现消息解析,还要回答:
- 它从哪里读系统说明?
- 它怎样发现 Skills?
- 它怎样接收 MCP?
- 它是否会读到用户全局能力,从而绕过禁用策略?
11.18 安全边界
能力注入遵循六条底线:
- 动态凭据不写回数据库中的 Agent 静态 JSON;
- 不把 Daemon 长期 Token 交给 Agent;
- Task Overlay 只对本次 Run 可见;
- 路径、大小、文件数、摘要全部校验;
- Agent 自定义参数不能覆盖 Multica 管理的 MCP/协议参数;
- Brief 中只列能力说明,不打印秘密。
即便 Provider CLI 能执行任意代码,也应让“它获得什么身份”保持最小化和可审计。
11.19 缓存一致性与更新
Bundle Hash 是不可变版本键。修改 Skill 后:
- Server 产生新 Hash;
- 新 Claim 携带新 Ref;
- Daemon Cache Miss 并下载新 Bundle;
- 老任务仍使用旧快照;
- GC 可清理不再引用的缓存版本。
这比“按 Skill ID 覆盖当前目录”可靠:并发中的两个 Task 不会互相换掉说明文件。
11.20 排障顺序
当 Agent 说“找不到某能力”时,按层排查:
- Skill/Connected App 是否绑定到正确 Agent;
- Claim Payload 是否含 Skill Ref、Connected App、MCP;
- Daemon 是否成功 Resolve 与校验 Bundle;
- 执行目录是否物化 Skill;
- 禁用策略是否隐藏了 Runtime Skill;
- 合并后的 MCP 是否保留静态 Server;
- Provider Sidecar/Session 参数是否生成;
- Provider 是否声明支持对应 Transport;
- Brief 是否告诉 Agent 何时用它。
直接从 UI 猜通常会漏掉 Claim 快照与 Provider 交付两层。
11.21 本章结论
Multica 的能力系统不是把工具列表塞给模型,而是:
- 用 Skill 组织可复用工作方法;
- 用内容寻址 Bundle 安全分发;
- 用 Runtime-local Discovery 尊重本机生态;
- 用 MCP 统一工具入口;
- 用 Connected App 管理用户授权;
- 用任务级快照把能力锁定在一次可审计运行里。
这套结构的价值,是让能力可组合,但身份、版本和生命周期不混在一起。