03 MCP 工具如何进入注册表并受权限约束 本节摘要:连上 MCP server、认证通过后,server 提供的工具怎么被 Agent 用?本节讲 MCP 工具如何进入第 5 章的注册表——它们通过一个「目录(catalog)」汇入,和内置工具并列;然后强调一个关键点:MCP 工具受同一套权限约束,它们不是法外之地,第 4 章的允许/询问/拒绝一样适用。 一、MCP 工具不是「另起炉灶」 先破除一个误解:有人以为 MCP 工具是「外部进来的特殊工具,和内置工具走不同通道」。不是。MCP 工具一旦进入 OpenCode,就和内置工具走同一套注册表、同一套权限、同一套调度。这种「归一」是 OpenCode 工具系统设计的关键——不管工具来自哪,治理方式一致。
本节摘要:连上 MCP server、认证通过后,server 提供的工具怎么被 Agent 用?本节讲 MCP 工具如何进入第 5 章的注册表——它们通过一个「目录(catalog)」汇入,和内置工具并列;然后强调一个关键点:MCP 工具受同一套权限约束,它们不是法外之地,第 4 章的允许/询问/拒绝一样适用。
先破除一个误解:有人以为 MCP 工具是「外部进来的特殊工具,和内置工具走不同通道」。不是。MCP 工具一旦进入 OpenCode,就和内置工具走同一套注册表、同一套权限、同一套调度。这种「归一」是 OpenCode 工具系统设计的关键——不管工具来自哪,治理方式一致。
内置工具 ─┐ 自定义工具 ─┤ 插件工具 ──┼─► 同一个注册表 ──► 同一套权限 ──► 同一套调度 MCP工具 ──┘
MCP server 连上后,它会告诉客户端「我提供哪些工具」(工具列表,每个含名字、描述、参数 schema)。OpenCode 把这些工具汇入注册表,过程大致是:
MCP server 连上 │ ▼ 列出 server 提供的工具 工具列表 [{name, description, schema}, ...] │ ▼ 给每个工具命名(客户端名+工具名,防冲突) "McpCatalog.toolName(客户端名, 工具名)" │ ▼ 通过「应用工具注册器」注册进注册表 注册表里多了这些 MCP 工具
注意「命名」这一步——MCP 工具的全名是「客户端名 + 工具名」组合,这样不同 server 的同名工具不会冲突。比如 server A 和 server B 都有 read 工具,在注册表里是 A.read 和 B.read,各是各的。
MCP 工具进注册表后,要过权限可见性过滤——和内置工具一样。第 4 章权限规则决定当前 Agent 能看到哪些 MCP 工具:
注册表里有 MCP 工具 [A.read, A.write, B.search] │ ▼ 权限可见性过滤(第 4 章) │ 当前 Agent 能看到: [A.read, B.search](A.write 被权限隐藏)
这意味着 MCP 工具不是「连上了就全能用」——它们受当前 Agent 权限约束,无权用的连看都看不到。
有个细节:MCP server 的工具列表可能变化(server 动态增减工具)。OpenCode 怎么感知?通过 MCP 协议的「工具列表变化通知」:
server 增/删了工具 │ ▼ server 发「工具列表变化」通知 │ ▼ OpenCode 收到,重新拉取工具列表 │ ▼ 更新注册表 + 发「工具已变化」事件 │ ▼ 相关方(如会话)感知并刷新
这让 MCP 工具集能动态更新,不用重连。
这是本节最重要的认知,值得反复强调。MCP 工具虽然来自外部 server,但:
所以「接了个 MCP server」不等于「给 Agent 开了后门」——所有 MCP 工具的调用都过权限、都受控。这是 OpenCode 安全模型的一致性体现。
⚠️ 但仍要小心第三方 server:虽然 OpenCode 这层治理一致,但 MCP server 本身可能是恶意的(它的工具做坏事)。所以接第三方 MCP server 时,要确认 server 可信——OpenCode 治理的是「工具调用」,server 内部干什么它管不到。OpenWork 教程第 7 章会讲企业版如何对 MCP server 做更严的准入。
Agent 调一个 MCP 工具时,执行链和内置工具类似,只是「执行函数」变成「经 MCP 协议调 server」:
Agent 调 A.read({ path: "xxx" }) │ ▼ 权限求解(第 4 章) │ ▼ 执行: │ └─ 不是本地函数,而是经 MCP 协议发请求给 server A │ ▼ server A 执行它的 read 工具,返回结果 │ ▼ 结果回流(经输出边界控制,第 5 章 04 节) │ ▼ 给模型
从 Agent 视角,MCP 工具和内置工具调用体验一样——差别只在执行是本地函数还是远程 server 调用,这个差别被工具系统屏蔽了。
客户端用法讲完了,下一节讲反向——把 OpenCode 自己暴露成 MCP server。