OpenCode MCP + Plugin:无限扩展 AI 能力
OpenCode MCP + Plugin:无限扩展 AI 能力
你有没有遇到这种情况:AI Agent 正在帮你写代码,突然你想让它查一下数据库里的某条记录,或者调一下公司的内部 API——然后发现,它做不到。Agent 再聪明,手里没有工具也就是个光杆司令。
OpenCode 从设计之初就想到了这个问题。它通过两套扩展机制——MCP Server 和 Plugin 系统——让 AI Agent 的能力几乎可以无限扩展。我用了几个月,最大的感受是:这套扩展体系设计得相当优雅,上手简单但上限极高。
今天咱们就聊聊这两套系统怎么玩,以及怎么用它们打造属于你自己的超级 Agent。
本文提纲
- MCP 协议:让 Agent 连接一切
- Local MCP Server:命令行启动,即插即用
- Remote MCP Server:连接云端服务
- OAuth 认证:安全的第三方接入
- MCP 工具发现与管理
- Plugin 系统:更深度的定制
- Plugin 生命周期:从安装到运行
- 通过 Plugin 创建自定义工具
- 实战案例:Database MCP + Search MCP + 自定义 Plugin
MCP 协议:让 Agent 连接一切
MCP(Model Context Protocol)是 Anthropic 提出的一种开放协议,目的是让 LLM 能够统一地调用外部工具。你可以把它理解成 AI 世界的 USB 接口——不管你后面接的是数据库、搜索引擎还是企业内部系统,Agent 都用同一套标准来调用。
OpenCode 对 MCP 的支持非常完整,覆盖了三种接入方式:
- Local MCP:在本机启动一个进程,通过 stdin/stdout 通信
- Remote MCP:连接一个远程 HTTP 服务器(SSE)
- OAuth MCP:基于 OAuth 2.0 的安全认证接入
所有 MCP 工具在被添加后,会自动出现在 LLM 的工具列表里,跟 OpenCode 内置的 bash、edit、read 等工具平起平坐。也就是说,LLM 会根据任务需要,自主决定调用哪个 MCP 工具,你不需要手动干预。
有一点需要注意:每个 MCP Server 注册的工具会占用 context 窗口的 token。如果你挂了一堆 MCP 但平时只用其中一两个,反而会拖慢 Agent 的响应速度。所以别贪多,用到什么加什么。
Local MCP Server:命令行启动,即插即用
Local MCP 是最简单的接入方式。你只需要告诉 OpenCode 怎么启动这个 Server,剩下的通信协议它全包了。
配置写在 opencode.json 里:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"my-local-server": {
"type": "local",
"command": ["npx", "-y", "@modelcontextprotocol/server-everything"],
"enabled": true,
"environment": {
"MY_ENV_VAR": "my_env_var_value"
}
}
}
}command 是一个数组,第一个元素是可执行文件,后面的是参数。最常见的方式就是用 npx 或 bunx 直接运行 npm 包里的 MCP Server。environment 可以传环境变量,比如 API Key 之类的敏感信息可以从这里注入。
启动之后,OpenCode 会通过 stdio 跟这个进程通信,自动发现它提供的所有工具。你在对话里加一句 use the my-local-server tool,Agent 就知道该调哪个 MCP 了。
可配置的选项:
| 选项 | 类型 | 说明 |
|---|---|---|
type |
string | 必须是 "local" |
command |
array | 启动命令和参数 |
environment |
object | 环境变量 |
enabled |
boolean | 是否启用 |
timeout |
number | 工具发现超时(毫秒),默认 5000 |
Remote MCP Server:连接云端服务
Remote MCP 让你直接连接一个远端的 HTTP 端点。对于那些已经部署好的 MCP 服务(比如 Sentry、Context7、Grep),这种方式最方便——不用在本机装任何东西。
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"my-remote-mcp": {
"type": "remote",
"url": "https://my-mcp-server.com",
"enabled": true,
"headers": {
"Authorization": "Bearer MY_API_KEY"
}
}
}
}url 指向 MCP Server 的端点地址,headers 用来传认证信息。如果你有 API Key,可以通过 headers 直接带上;如果需要 OAuth 认证,那就用下面要讲的 OAuth 方式。
Remote MCP 的可配置选项:
| 选项 | 类型 | 说明 |
|---|---|---|
type |
string | 必须是 "remote" |
url |
string | 远端 MCP Server 地址 |
enabled |
boolean | 是否启用 |
headers |
object | 请求头 |
oauth |
object/false | OAuth 配置,或 false 禁用自动检测 |
timeout |
number | 工具发现超时(毫秒),默认 5000 |
OAuth 认证:安全的第三方接入
OpenCode 对 OAuth 的支持做得相当到位,基于 RFC 7591 的 Dynamic Client Registration 实现。大部分情况下你不需要手动配置任何 OAuth 参数——OpenCode 会自动处理整个流程。
自动 OAuth
只需要配置一个普通的 Remote MCP:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"my-oauth-server": {
"type": "remote",
"url": "https://mcp.example.com/mcp"
}
}
}当你第一次使用这个 MCP 时,OpenCode 会检测到 401 响应,自动发起 OAuth 流程,打开浏览器让你授权,然后把 token 安全地存储在 ~/.local/share/opencode/mcp-auth.json。
预注册 OAuth
如果服务提供商给了你 Client ID 和 Client Secret,可以直接配置:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"my-oauth-server": {
"type": "remote",
"url": "https://mcp.example.com/mcp",
"oauth": {
"clientId": "{env:MY_MCP_CLIENT_ID}",
"clientSecret": "{env:MY_MCP_CLIENT_SECRET}",
"scope": "tools:read tools:execute"
}
}
}
}{env:XXX} 语法会自动从环境变量中读取值,避免在配置文件里硬编码敏感信息。
OAuth 管理命令
OpenCode 提供了几个 CLI 命令来管理 OAuth:
# 手动触发某个 MCP 的认证流程
opencode mcp auth my-oauth-server
# 列出所有 MCP Server 及其认证状态
opencode mcp list
# 移除已存储的凭据
opencode mcp logout my-oauth-server
# 调试连接和 OAuth 流程
opencode mcp debug my-oauth-server如果你的 MCP 不需要 OAuth(用 API Key 就够了),可以显式禁用:
{
"type": "remote",
"url": "https://mcp.example.com/mcp",
"oauth": false,
"headers": {
"Authorization": "Bearer {env:MY_API_KEY}"
}
}MCP 工具发现与管理
MCP Server 启动后,OpenCode 会自动发现它提供的所有工具,并以 {server-name}_{tool-name} 的格式注册。比如你有一个叫 sentry 的 MCP Server,它提供了 list_issues 和 get_issue 两个工具,那在 OpenCode 里就变成 sentry_list_issues 和 sentry_get_issue。
全局管理
你可以在 opencode.json 的 tools 字段里控制 MCP 工具的启用状态:
{
"mcp": {
"my-mcp-foo": { "type": "local", "command": ["bun", "x", "foo"] },
"my-mcp-bar": { "type": "local", "command": ["bun", "x", "bar"] }
},
"tools": {
"my-mcp-foo": false
}
}甚至支持 glob 模式批量控制:
{
"tools": {
"my-mcp*": false
}
}按 Agent 分配
如果你有很多 MCP Server 但不是每个 Agent 都需要,可以全局禁用、按 Agent 开启:
{
"mcp": {
"my-mcp": {
"type": "local",
"command": ["bun", "x", "my-mcp"],
"enabled": true
}
},
"tools": {
"my-mcp*": false
},
"agent": {
"my-agent": {
"tools": {
"my-mcp*": true
}
}
}
}这样 my-mcp 的工具只对 my-agent 这个 Agent 可见。这种按需分配的方式对管理大型项目特别有用——避免给每个 Agent 都塞一堆它用不到的工具,既浪费 context 又拖慢速度。
Plugin 系统:更深度的定制
如果说 MCP 是"连接外部工具",那 Plugin 就是"改造 OpenCode 本身"。
Plugin 系统让你可以钩入 OpenCode 的内部事件流,修改默认行为,甚至注入新的工具。它比 MCP 的粒度更细,控制力更强。
两种加载方式
1. 从 npm 安装
在 opencode.json 里声明:
{
"$schema": "https://opencode.ai/config.json",
"plugin": [
"opencode-helicone-session",
"opencode-wakatime",
"@my-org/custom-plugin"
]
}OpenCode 启动时会用 Bun 自动安装这些包,缓存在 ~/.cache/opencode/node_modules/。支持 scoped package,跟平时装 npm 包没有区别。
2. 从本地文件加载
把 .js 或 .ts 文件放到指定目录即可:
- 项目级:
.opencode/plugins/ - 全局级:
~/.config/opencode/plugins/
不需要任何配置,放进目录就会被自动加载。
加载顺序
OpenCode 按 4 个层级依次加载:
- 全局配置(
~/.config/opencode/opencode.json)里的 npm plugin - 项目配置(
opencode.json)里的 npm plugin - 全局 plugin 目录(
~/.config/opencode/plugins/) - 项目 plugin 目录(
.opencode/plugins/)
所有 hook 按顺序执行,同名同版本的 npm package 只加载一次,但本地 plugin 和 npm plugin 即使名字一样也会分别加载。
Plugin 生命周期:从安装到运行
写一个 Plugin 很简单——导出一个异步函数,接收 context,返回一个 hooks 对象:
export const MyPlugin = async ({ project, client, $, directory, worktree }) => {
console.log("Plugin initialized!")
return {
// 各种 hook 在这里注册
}
}Plugin 函数接收的 context 包含:
project:当前项目信息directory:当前工作目录worktree:git worktree 路径client:OpenCode SDK 客户端,可以调用 AI$:Bun 的 Shell API,用来执行命令
可以订阅的事件
Plugin 可以订阅的事件类型非常丰富,涵盖了 OpenCode 运行的方方面面:
工具事件:tool.execute.before、tool.execute.after——在工具执行前后插入自定义逻辑,比如拦截 bash 命令、记录执行日志。
会话事件:session.created、session.idle、session.error、session.compacted——跟踪会话状态变化,比如会话完成时发通知。
文件事件:file.edited、file.watcher.updated——监控文件变化。
Shell 事件:shell.env——注入环境变量到所有 shell 执行中。
TUI 事件:tui.prompt.append、tui.command.execute、tui.toast.show——自定义终端界面行为。
还有 LSP、权限、TODO 等各种事件,总共 20 多个 hook 点。
TypeScript 支持
如果你用 TypeScript,可以从 @opencode-ai/plugin 导入类型:
import type { Plugin } from "@opencode-ai/plugin"
export const MyPlugin: Plugin = async (ctx) => {
return {
// 类型安全的 hook 实现
}
}依赖管理
本地 Plugin 如果需要外部依赖,在 .opencode/ 目录下创建一个 package.json:
{
"dependencies": {
"shescape": "^2.1.0"
}
}OpenCode 启动时会自动 bun install,你的 Plugin 就可以直接 import 了。
通过 Plugin 创建自定义工具
这是 Plugin 系统最强大的能力之一——你可以直接给 Agent 添加新工具。
import { type Plugin, tool } from "@opencode-ai/plugin"
export const CustomToolsPlugin: Plugin = async (ctx) => {
return {
tool: {
mytool: tool({
description: "This is a custom tool",
args: {
foo: tool.schema.string(),
},
async execute(args, context) {
const { directory, worktree } = context
return `Hello ${args.foo} from ${directory} (worktree: ${worktree})`
},
}),
},
}
}tool() 是一个 helper 函数,接收三个参数:
description:告诉 LLM 这个工具干什么args:用 Zod schema 定义参数类型(tool.schema就是 Zod)execute:工具被调用时执行的函数
这些自定义工具跟内置工具完全平级,LLM 会自动识别并在需要时调用。如果自定义工具和内置工具同名,自定义工具会覆盖内置工具。
Custom Tools 的另一种写法
除了通过 Plugin,你还可以直接在 .opencode/tools/ 目录下创建工具文件:
// .opencode/tools/database.ts
import { tool } from "@opencode-ai/plugin"
export default tool({
description: "Query the project database",
args: {
query: tool.schema.string().describe("SQL query to execute"),
},
async execute(args) {
return `Executed query: ${args.query}`
},
})文件名就是工具名。这个文件会创建一个叫 database 的工具。也可以一个文件导出多个工具,它们会以 {filename}_{exportname} 命名。
这种方式比 Plugin 更轻量,适合只需要加一两个独立工具的场景。
实战案例:Database MCP + Search MCP + 自定义 Plugin
光说理论不够过瘾,来看几个真实场景。
场景一:Database MCP Server
假设你的项目用 PostgreSQL,想让 Agent 能直接查数据库。你可以用一个 PostgreSQL MCP Server:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"postgres": {
"type": "local",
"command": ["npx", "-y", "@modelcontextprotocol/server-postgres"],
"environment": {
"POSTGRES_CONNECTION_STRING": "postgresql://user:pass@localhost:5432/mydb"
}
}
}
}配好之后,在对话里你可以这样说:
查一下 users 表里最近注册的 10 个用户,use postgresAgent 会自动调用 postgres_query 工具,执行 SQL,把结果返回给你。调试数据的时候再也不用手动切换到数据库客户端了。
场景二:Search MCP Server
Context7 是一个文档搜索 MCP,可以让 Agent 实时查找技术文档:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"context7": {
"type": "remote",
"url": "https://mcp.context7.com/mcp"
}
}
}用的时候:
怎么用 Cloudflare Worker 缓存 JSON API 响应 5 分钟?use context7Agent 会搜索最新的文档并给出准确的配置方案。再也不用担心 LLM 的训练数据过时了。
更聪明的做法是在 AGENTS.md 里加一条规则:
When you need to search docs, use `context7` tools.这样 Agent 在遇到不确定的问题时会主动去查文档,你甚至不需要提醒它。
场景三:自定义通知 Plugin
写一个 Plugin,在 Agent 完成任务后给你发系统通知:
// .opencode/plugins/notification.js
export const NotificationPlugin = async ({ $ }) => {
return {
event: async ({ event }) => {
if (event.type === "session.idle") {
await $`osascript -e 'display notification "Task done!" with title "OpenCode"'`
}
},
}
}把这个文件放到 .opencode/plugins/ 目录,OpenCode 启动时自动加载。当你让 Agent 跑一个长时间任务,去做别的事,完成后 macOS 会弹出通知。
场景四:.env 文件保护 Plugin
防止 Agent 读取你的 .env 文件:
// .opencode/plugins/env-protection.js
export const EnvProtection = async () => {
return {
"tool.execute.before": async (input, output) => {
if (input.tool === "read" && output.args.filePath.includes(".env")) {
throw new Error("Do not read .env files")
}
},
}
}几行代码就给 Agent 加了一道安全护栏。这个思路可以扩展到任何你想要限制的操作——比如禁止删除某些目录、限制网络请求等等。
场景五:环境变量注入 Plugin
给所有 shell 执行注入环境变量:
// .opencode/plugins/inject-env.js
export const InjectEnvPlugin = async () => {
return {
"shell.env": async (input, output) => {
output.env.MY_API_KEY = "secret"
output.env.PROJECT_ROOT = input.cwd
},
}
}这样不管是 Agent 执行的 bash 命令还是你自己开的终端,都会有这些环境变量。特别适合在团队里统一配置开发环境。
社区生态
OpenCode 的社区已经有不少现成的 Plugin 可以直接用。比较有意思的几个:
- opencode-wakatime:自动记录编程时间到 WakaTime
- opencode-supermemory:跨会话持久化记忆
- opencode-firecrawl:网页抓取和搜索
- opencode-background-agents:Claude Code 风格的后台 Agent
- opencode-vibeguard:在 LLM 调用前自动脱敏敏感信息
- opencode-pty:让 Agent 能在 PTY 里跑交互式程序
完整的列表可以在 OpenCode Ecosystem 页面找到。如果你写了好的 Plugin,也可以提交 PR 加进去。
MCP 和 Plugin 这两套系统搭配起来,基本能覆盖你能想到的所有扩展需求。MCP 负责连接外部服务,Plugin 负责改造 Agent 行为,各司其职又相互补充。开始的话,建议先试几个 Remote MCP(比如 Context7 和 Grep),体验一下工具发现和自动调用的感觉;然后再写一两个本地 Plugin(比如通知或环境变量注入),熟悉一下 hook 机制。搞清楚这两样,你的 OpenCode 就不再是开箱即用的标准版,而是专为你量身定制的专属 Agent。
作者: itech001 来源: 公众号:AI人工智能时代 主页: https://www.theaiera.cn(每日分享最前沿的AI新闻和技术)
本文首发于 AI人工智能时代,转载请注明出处。