官方教程中文版工具与 MCP
创建自定义工具
在 OpenCode 里给模型提供可控、可复用的项目动作。
自定义工具不是让新手一上来写插件系统,而是把“模型总是要靠猜的动作”变成一个清晰、可验证的函数。
官方教程说明了工具文件、tool() 辅助函数、参数 schema、上下文对象和多语言脚本调用。这里重点讲:什么时候你真的需要自定义工具,以及怎么把它做成新手也能维护的形态。
先理解它解决什么问题
模型擅长读代码、写代码、解释问题,但不擅长稳定执行你项目里的专有动作。例如:
- 查询内部数据库。
- 调用公司自己的 API。
- 读取一个只有本项目懂的配置格式。
- 跑一段固定脚本并把结果整理给模型。
这些动作如果每次都让模型临时写 bash 或临时猜接口,结果会不稳定。自定义工具的作用就是把这类动作封装成一个“模型可以调用,但边界由你控制”的入口。
先别急着写工具
新手可以按这个顺序判断:
- 内置工具能解决,就用内置工具:
read、grep、glob、bash已经覆盖大量日常场景。 - 外部服务已有 MCP,就优先接 MCP:数据库、GitHub、浏览器、搜索这类通用能力通常不值得自己写。
- 只有当动作是你项目专有、且会重复使用时,再写自定义工具。
不要把一次性脚本包装成工具。工具一旦进入 OpenCode,就会成为模型可见能力,维护成本和安全边界都要考虑。
工具放哪里
- 项目级:
.opencode/tools/,适合只服务当前仓库的工具。 - 全局级:
~/.config/opencode/tools/,适合你所有项目都会用的个人工具。
大多数新手从项目级开始更安全。项目级工具随仓库一起演进,不会影响其他项目。
最小工具长什么样
工具文件是 TypeScript 或 JavaScript。文件名就是工具名。
例如 .opencode/tools/project-info.ts:
import { tool } from "@opencode-ai/plugin";
export default tool({
description: "Return current project directory information",
args: {},
async execute(args, context) {
return `directory=${context.directory}\nworktree=${context.worktree}`;
},
});这个工具不做危险动作,只把当前工作目录和 worktree 返回给模型。新手可以先用这种只读工具验证机制,再逐步接入真实脚本。
参数要少而明确
工具参数使用 tool.schema 定义。参数越少,模型越不容易误用。
args: {
query: tool.schema.string().describe("Read-only SQL query to execute"),
}描述要写给模型看,不是写给人类炫技。好的描述会说明输入边界,例如“只读 SQL”“仓库内相对路径”“不包含密钥”。
调用其他语言脚本
官方支持用 TypeScript / JavaScript 定义工具,再在工具里调用 Python、Shell 或其他语言脚本。这个模式适合已有稳定脚本的项目。
建议结构:
- 工具定义负责接收参数、校验参数、返回文本。
- Python / Shell 脚本负责实际业务逻辑。
- 不要在工具定义里硬编码密钥。
如果脚本会修改文件、访问网络或查询数据库,先给它加权限边界,再暴露给模型。
安全边界
自定义工具是模型可调用的能力,默认要按“可能被频繁调用、可能被错误参数调用”来设计:
- 工具名不要和内置工具冲突,除非你明确要替换内置行为。
- 默认只读,确认稳定后再允许写入或外部请求。
- 参数必须校验,不要把模型输入直接拼进 shell 命令。
- 返回结果要短,避免把无关日志塞进上下文。
- 需要密钥时,从环境变量或安全凭据读取,不写进工具文件。
如果只是想限制 bash、edit 这类内置能力,不要写一个同名工具去覆盖,直接用 permission。
怎么判断做对了
一个可用的自定义工具应该满足:
- 模型能从
description判断什么时候调用它。 - 参数少且含义明确。
- 错误时返回清楚的原因,而不是一大段堆栈。
- 输出能直接帮助下一步决策。
- 多次调用结果稳定,不依赖当前对话里的隐含假设。
如果模型经常不该调用却调用,通常是 description 太泛。如果模型调用时经常传错参数,通常是 schema 描述不够具体。
新手常见坑
- 把工具写成“万能执行器”。这会让模型失去边界,风险比直接用 bash 更高。
- 一次返回几千行日志。工具输出会占上下文,应该只返回判断所需信息。
- 忘记项目级和全局级的区别。全局工具会影响所有项目,先在项目级验证。
- 直接覆盖内置工具名。除非你非常清楚后果,否则不要用
bash、read、write这类名字。
© Anomaly
最近更新: 2026年5月1日