OpenCode v2 MCP 与插件体系实战:把数据库、工单和内部 API 安全接入 Agent

OpenCode v2 MCP 与插件体系实战:把数据库、工单和内部 API 安全接入 Agent

这是《OpenCode v2 实战:从零搭建企业级 AI 编程助手》专题第 8 篇。上一篇完成了 Skills、Commands 与 Instructions 的分层,本篇继续解决"怎样让 Agent 可靠地连接实时系统":用 MCP 接入数据库、工单、知识库和内部 API,用 Plugin 承载工具、钩子与集成逻辑,再用权限、鉴权、超时和审计守住生产边界。

一个只会读仓库的 Agent,能够解释代码,却很难回答这些问题:某个订单为什么没有排线、这条告警关联了哪个工单、当前接口文档是否已经更新、某次发布使用了哪组配置。答案往往分散在数据库、工单平台、知识库和内部服务中。

最危险的做法,是直接给模型一段数据库连接串或一个权限过大的万能接口。真正可落地的方案,应当把每一种外部能力收敛为窄接口:输入有明确 Schema,输出可追溯,超时可控制,写操作要审批,凭证不进入仓库和上下文。

本文会完成六件事:

  1. 讲清 MCP Server、Plugin、Skill 和 Tool 的边界;
  2. 配置本地与远程 MCP Server;
  3. 设计数据库、工单、知识库和内部 API 工具;
  4. 配置 OAuth、环境变量、超时和协议版本;
  5. 用 Permissions 实现工具级最小权限;
  6. 给出可审计、可回滚的团队落地清单。

一、先建立正确边界:MCP 负责连接,Plugin 负责扩展

1. MCP Server 是外部能力的标准接口

OpenCode v2 可以连接 Model Context Protocol Server,并使用其 Tools、Resources、Prompts 与 Instructions。对开发团队而言,MCP 的价值不只是"多了一种函数调用方式",而是把宿主与外部系统之间的集成从 N×M 适配,收敛成相对稳定的协议边界。

典型职责如下:

  • Tool:执行一次有输入输出的动作,例如按订单号查询诊断信息;
  • Resource:读取只读资源,例如规范文档、工单详情或日志片段;
  • Prompt:提供可复用的任务模板;
  • Instructions:向宿主补充服务端规则与使用说明。

MCP Server 不应该向模型暴露全部底层能力。数据库 Server 最好提供 get_order_diagnosis,而不是 execute_any_sql;工单 Server 最好提供 get_ticket 与 list_related_tickets,而不是一个可以请求任意地址的万能 HTTP 工具。

2. Plugin 扩展 OpenCode 自身行为

OpenCode v2 Plugin 可以增加工具、Hook、集成、命令、Agent 等行为。插件既可以来自已发布的包,也可以来自本地目录。它更像宿主扩展包,而 MCP 更像宿主与外部能力之间的标准连接。

可以用下面这张表快速判断:

目标 更适合的机制 原因
连接数据库、工单、知识库 MCP Server 便于跨宿主复用和独立部署
在会话生命周期执行审计 Plugin Hook 与 OpenCode 生命周期紧密相关
增加宿主内工具或命令 Plugin 需要直接扩展 OpenCode 行为
教 Agent 如何组合工具 Skill 重点是方法、边界和异常分支
长期限制危险操作 Permissions / Policy 需要工具层强制执行

3. 企业方案通常是组合,不是二选一

一个完整的"订单诊断能力包"可以这样拆分:

text 复制代码
OpenCode
├─ Instructions:仓库事实与安全底线
├─ Skill:订单诊断步骤、停止条件、证据要求
├─ Command:/diagnose-order <orderNo>
├─ Plugin:审计 Hook、结果脱敏、统一错误处理
├─ MCP Server:订单、任务、库存的窄接口查询
└─ Permissions:允许查询,写入必须询问或拒绝

这套结构的关键是职责分离:Skill 决定"怎样做",MCP 提供"能查什么",Plugin 处理"宿主怎样扩展",Permissions 决定"是否允许执行"。

二、配置第一个 MCP Server

1. 用 CLI 添加远程服务

OpenCode v2 可以在项目中添加远程 MCP Server:

bash 复制代码
opencode mcp add context7 --url https://mcp.context7.com/mcp
opencode mcp list

加上 --global 后,服务会进入全局配置,供多个项目使用。企业内部工具通常更适合项目级配置:代码仓库可以审查它依赖了哪些能力,也能避免把不相关的生产工具带进每个会话。

2. 手工配置必须放在 mcp.servers 下

v2 的 Server 名称位于 mcp.servers,不要照搬旧版本结构:

jsonc 复制代码
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "servers": {
      "order-tools": {
        "type": "remote",
        "url": "https://mcp.example.com/mcp"
      }
    }
  }
}

服务默认会连接。需要保留配置但暂时停用时,使用 disabled: true,而不是自行发明 enabled 字段。

3. 本地 Server 使用 stdio

本地 Server 由 OpenCode 启动,适合仓库内的辅助程序、开发期适配器和只需访问本机资源的工具:

jsonc 复制代码
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "servers": {
      "repo-inspector": {
        "type": "local",
        "command": ["python", "-m", "repo_inspector"],
        "cwd": ".",
        "environment": {
          "LOG_LEVEL": "info"
        }
      }
    }
  }
}

本地 Server 的 stdout 是协议通道,业务日志应写入 stderr 或独立日志系统。否则一条普通日志就可能污染 JSON-RPC 消息,表现为随机断连或解析失败。

三、把凭证留在环境里,不要写进配置

1. 使用环境变量替换

OpenCode v2 在配置中使用 {env:NAME} 引用环境变量:

jsonc 复制代码
{
  "mcp": {
    "servers": {
      "knowledge": {
        "type": "remote",
        "url": "https://mcp.example.com/mcp",
        "oauth": false,
        "headers": {
          "X-API-Key": "{env:KNOWLEDGE_API_KEY}"
        }
      }
    }
  }
}

JSON 字符串中的 $NAME 不会按 Shell 方式展开。更重要的是,不要把真实 Key 写入示例、Git、截图、日志或聊天记录;环境变量也应该来自系统凭证库、CI Secret 或受控启动环境。

2. 远程服务优先使用 OAuth

远程 MCP Server 默认启用 OAuth。服务需要登录时,可以在 OpenCode 中运行 /mcps 选择目标服务完成授权,也可以使用 CLI:

bash 复制代码
opencode mcp auth company-tools
opencode mcp logout company-tools

OpenCode 会处理 PKCE 与 Token 刷新,并把凭证存放在项目配置之外。只有服务明确使用 API Key 或其他请求头凭证时,才应设置 oauth: false。

3. 预注册客户端仍然不能提交密钥

企业身份平台如果要求预注册 OAuth Client,可以这样引用环境变量:

jsonc 复制代码
{
  "mcp": {
    "servers": {
      "company-tools": {
        "type": "remote",
        "url": "https://mcp.example.com/mcp",
        "oauth": {
          "client_id": "{env:MCP_CLIENT_ID}",
          "client_secret": "{env:MCP_CLIENT_SECRET}",
          "scope": "tools:read tools:execute",
          "callback_port": 19876
        }
      }
    }
  }
}

示例里的变量名可以进入仓库,变量值不可以。Public Client 应省略 client_secret,不要为了"字段完整"生成一个没有意义的伪密钥。

四、四类企业系统怎样设计 MCP 工具

1. 数据库:提供业务查询,不提供任意 SQL

危险接口:

text 复制代码
execute_sql(sql: string)

更稳妥的接口:

text 复制代码
get_order_diagnosis(order_no: string)
list_order_tasks(order_no: string, limit: integer = 20)
get_inventory_snapshot(sku: string, warehouse_code: string)

Server 内部应使用只读账号、参数化查询、行数限制、查询超时和字段白名单。工具返回值要区分"没有数据"和"查询失败",不能把空结果直接解释成某个业务原因。

建议的结构化返回:

json 复制代码
{
  "status": "ok",
  "evidence": [
    {"source": "order", "field": "status", "value": "ALLOCATED"},
    {"source": "task", "field": "task_count", "value": 0}
  ],
  "unknowns": ["未查询承运商系统"],
  "trace_id": "example-trace-id"
}

2. 工单:查询与写入必须拆开

读取工单、搜索工单与创建评论是不同风险等级。不要用一个 ticket_request(method, path, body) 覆盖全部操作,而应拆成:

text 复制代码
get_ticket(ticket_id)
search_tickets(query, limit)
prepare_ticket_comment(ticket_id, content)
submit_ticket_comment(draft_id)

其中 prepare 只生成草稿和影响摘要,submit 才产生外部副作用。Permissions 可以允许查询,对提交设置 ask,同时 Plugin Hook 记录操作者、会话、目标工单和结果。

3. 知识库:Resource 比万能搜索 Tool 更省上下文

规范、架构说明和已发布手册属于只读内容,可以通过 Resource URI 暴露:

text 复制代码
kb://engineering/release-policy
kb://services/order/architecture
ticket://OPS-1024

对大文档,Server 应支持目录、分页、更新时间和内容摘要。不要一次把整个知识库塞入上下文;先列目录,再读取真正相关的资源。

4. 内部 API:把领域语义封装在服务端

不要把"拼 URL、选 Header、解释状态码"的工作交给模型。Server 应把内部 API 封装为稳定领域动作,并统一完成重试、限流、审计和错误映射:

text 复制代码
get_deployment_status(service, environment)
compare_config_versions(service, from_version, to_version)
list_recent_incidents(service, hours = 24)

这样即使底层 API 升级,Agent 看到的工具契约也可以保持兼容。

五、超时、协议与上下文成本要显式治理

1. 分开设置启动、目录和执行超时

OpenCode v2 支持默认超时与单 Server 覆盖:

jsonc 复制代码
{
  "mcp": {
    "timeout": {
      "startup": 45000,
      "catalog": 30000,
      "execution": 180000
    },
    "servers": {
      "slow-reports": {
        "type": "remote",
        "url": "https://mcp.example.com/mcp",
        "timeout": {
          "catalog": 60000,
          "execution": 300000
        }
      }
    }
  }
}

启动超时、能力目录超时与工具执行超时不是一回事。把所有值一味调大,只会让真正的故障更晚暴露。生产工具还应接受取消信号,并用幂等键保护可能重试的写操作。

2. 协议版本要显式测试

OpenCode v2 当前可在 Server 配置中选择 legacy、auto 或 2026-07-28。升级协议前,应在测试环境验证初始化、能力协商、资源读取、工具调用、取消和错误返回,再逐步放量。

jsonc 复制代码
{
  "type": "remote",
  "url": "https://mcp.example.com/mcp",
  "protocol": "auto"
}

不要仅因为某个字段能通过 Schema,就假定服务端已经实现对应语义。

3. 只启用当前任务真正需要的 Server

MCP 工具描述会占用模型上下文。一个项目同时挂载几十个 Server、几百个工具,会让模型更难选择正确入口,也会增加提示注入与误调用面。

治理方法包括:按领域拆分 Server、默认禁用低频连接、减少重叠工具、把确定性流程封装为高层工具,并在 Skill 中写清选择规则。

六、用 Permissions 做工具级最小权限

1. MCP Tool 有独立 Permission Action

OpenCode v2 会把 MCP 工具映射为 <server>_<tool> 形式的权限 action,不支持的字符会被规范化为下划线。因此可以针对具体工具编写规则:

jsonc 复制代码
{
  "permissions": [
    { "action": "order_tools_*", "resource": "*", "effect": "deny" },
    { "action": "order_tools_get_order_diagnosis", "resource": "*", "effect": "allow" },
    { "action": "ticket_tools_get_ticket", "resource": "*", "effect": "allow" },
    { "action": "ticket_tools_submit_ticket_comment", "resource": "*", "effect": "ask" }
  ]
}

规则按顺序合并,最后一个匹配项生效。宽泛规则放前面,具体例外放后面。上线前应以实际工具 ID 验证规范化结果,不要只根据显示名称猜 action。

2. Resource 读取也要控制

列出 MCP Resource 和读取 Resource 有各自的权限动作:

jsonc 复制代码
{
  "permissions": [
    { "action": "opencode_list_mcp_resources", "resource": "knowledge", "effect": "allow" },
    { "action": "opencode_read_mcp_resource", "resource": "knowledge:kb://engineering/*", "effect": "allow" },
    { "action": "opencode_read_mcp_resource", "resource": "knowledge:kb://finance/*", "effect": "deny" }
  ]
}

资源只读不代表可以无边界读取。个人信息、财务信息、密钥文档和生产日志仍需按数据分级授权。

3. 模型授权永远不能替代后端授权

Permissions 是宿主侧控制,MCP Server 自身还必须校验身份、租户、角色与资源范围。任何来自 Agent 的参数都应视为不可信输入;后端不能因为请求来自"内部 Agent"就跳过授权。

七、插件怎样安装、发现和锁定版本

1. 支持包、版本、作用域包和本地目录

OpenCode v2 的 plugins 数组支持多种来源:

jsonc 复制代码
{
  "$schema": "https://opencode.ai/config.json",
  "plugins": [
    "opencode-acme-plugin@1.2.0",
    "@acme/opencode-plugin",
    "./plugins/local",
    {
      "package": "@acme/opencode-plugin",
      "options": {
        "agent": "reviewer",
        "strict": true
      }
    }
  ]
}

相对路径以包含该配置项的配置文件为基准。配置的本地路径必须是目录,OpenCode 会加载目录中的入口模块;把单个脚本路径直接填进去会被跳过。

2. 自动发现目录有明确边界

OpenCode 会从发现到的 .opencode/plugins/ 目录加载直接的 .ts、.js 文件和一级插件包目录:

text 复制代码
.opencode/
└─ plugins/
   ├─ audit.ts
   ├─ redact.js
   └─ company-package/

项目根目录旁普通的 plugins/ 不会自动发现,必须显式配置或移入 .opencode/plugins/。这类路径差异是"插件明明存在却没有加载"的高频原因。

3. 生产环境应锁定确切版本

CLI 可以安装、列出、检查、更新和删除全局包插件:

bash 复制代码
opencode plugin add opencode-acme-plugin@1.2.0
opencode plugin list
opencode plugin check
opencode plugin update opencode-acme-plugin
opencode plugin remove opencode-acme-plugin@1.2.0

正式环境应优先锁定精确 npm 版本或完整 Git Commit。更新前审查依赖、权限、Hook 和新增网络访问;先在测试项目回归,再修改锁定版本。不要让关键插件在启动时悄悄跨大版本漂移。

八、可观测性:每次调用都要能解释

1. 记录调用元数据,不记录秘密

每次工具调用至少记录:

  • 时间、服务、工具与版本;
  • 调用主体、会话和目标环境;
  • 参数摘要与脱敏后的资源标识;
  • 耗时、结果状态、返回数量;
  • Trace ID、审批结果与错误分类。

不要记录 OAuth Token、API Key、Cookie、完整请求头、数据库连接串或未脱敏业务正文。日志平台也应有访问控制和保留期限。

2. 错误必须结构化

比起把异常堆栈直接返回模型,更推荐稳定错误契约:

json 复制代码
{
  "status": "error",
  "code": "UPSTREAM_TIMEOUT",
  "message": "工单服务在限定时间内未响应",
  "retryable": true,
  "trace_id": "example-trace-id"
}

模型需要知道是否可以重试、是否应停止、是否缺少权限。底层堆栈应进入受控日志,而不是泄漏到上下文。

3. 动作结果不明确时先查状态

查询工具失败可以安全重试,写工具不能盲目重放。创建工单评论、触发部署或更新记录后如果连接中断,应先用业务幂等键或查询接口确认结果,再决定是否补偿。

九、从零搭建一个订单诊断能力包

1. 目录设计

text 复制代码
your-project/
├─ AGENTS.md
├─ opencode.jsonc
├─ .opencode/
│  ├─ skills/
│  │  └─ order-diagnosis/
│  │     ├─ SKILL.md
│  │     └─ references/
│  │        └─ status-rules.md
│  ├─ commands/
│  │  └─ diagnose-order.md
│  └─ plugins/
│     └─ audit.ts
└─ mcp/
   └─ order-tools/
      ├─ src/
      └─ tests/

Skill 写业务顺序和停止条件;Command 接收订单号;MCP Server 执行窄接口查询;Plugin 负责审计和脱敏;Permissions 限制工具范围。

2. 推荐调用链

text 复制代码
/diagnose-order SO-EXAMPLE-001
  → 校验订单号格式
  → 加载 order-diagnosis Skill
  → 调用 get_order_diagnosis
  → 仅在需要时调用 list_order_tasks
  → 汇总事实、规则、未知项和下一步
  → 不执行任何订单更新

最终回答应区分"查到的事实""根据规则得到的判断"和"仍未验证的信息"。没有证据时宁可保留未知项,也不要让模型填补一个听起来合理的原因。

3. 最小测试集

至少覆盖以下场景:

  • 正常订单能返回稳定结构;
  • 不存在的订单返回 NOT_FOUND,而不是空对象;
  • 非法参数在服务端被拒绝;
  • 越权租户无法读取数据;
  • 查询超时能取消并返回可判定错误;
  • 返回内容中的敏感字段被脱敏;
  • 提示注入不能绕过工具权限;
  • 写操作在未确认时被 ask 或 deny;
  • 重复写入由幂等键保护;
  • 插件升级可回滚到上一锁定版本。

十、常见故障与排查顺序

1. Server 显示未连接

先执行:

bash 复制代码
opencode mcp list

再依次检查进程是否启动、命令和工作目录是否正确、环境变量是否存在、远程 URL 是否可达、OAuth 是否需要登录、协议版本是否兼容。不要在尚未定位原因时反复重启所有服务。

2. Server 已连接但 Agent 不调用

重点检查工具描述是否写清触发场景、输入 Schema 是否过于复杂、是否存在多个重叠工具、Skill 是否告诉 Agent 何时调用,以及权限是否把对应 action 拒绝了。

3. 调用成功但经常超时

分别测量目录加载和工具执行耗时,检查上游 API、数据库索引、返回体大小、分页和取消处理。只有确认业务确实需要更长时间后,才提高该 Server 的执行超时。

4. Plugin 没有加载

确认它位于 .opencode/plugins/ 可发现目录,或已经在 plugins 中显式配置;本地配置项必须指向目录;入口模块存在;包版本与运行环境兼容。必要时重启服务,但不要把重启当作第一诊断手段。

十一、上线前安全检查清单

MCP Server

  • 工具是窄接口,没有任意 SQL、任意 URL 或任意 Shell;
  • 输入使用严格 Schema、长度限制和枚举;
  • 数据库账号只读并限制表、字段和行数;
  • 每个调用有超时、取消、Trace ID 与结构化错误;
  • 写操作有幂等键、审批和结果复核;
  • Server 自身执行身份、租户和资源授权。

凭证与数据

  • 配置只引用环境变量,不包含真实秘密;
  • OAuth Scope 遵循最小权限;
  • 日志与返回值完成脱敏;
  • Resource 按数据分级授权;
  • Token、Cookie 和连接串不会进入模型上下文。

Plugin 与供应链

  • 包来源可信并完成代码审查;
  • 正式环境锁定精确版本或 Commit;
  • 新增 Hook、网络访问和权限变化有变更记录;
  • 更新前执行回归测试并准备回滚版本;
  • 禁用项与内置策略的优先级已经验证。

Agent 行为

  • Skill 写明输入、输出、异常和停止条件;
  • Permissions 对查询、写入、资源读取分别授权;
  • 提示注入测试无法越过后端授权;
  • 最终报告包含证据、判断、未知项和 Trace ID;
  • 外部副作用前存在明确确认点。

十二、总结

让 OpenCode v2 接入企业系统,真正困难的不是把一个 Server 配到 opencode.jsonc,而是设计一条可长期治理的能力链:

text 复制代码
Instructions 定义底线
  → Skill 组织方法
  → MCP 提供窄接口能力
  → Plugin 扩展宿主与审计
  → Permissions 执行最小权限
  → OAuth、超时、日志和测试保障运行

数据库、工单、知识库和内部 API 一旦变成结构化、可授权、可审计的能力,Agent 才能从"根据代码猜答案"升级为"基于实时证据完成任务"。与此同时,越靠近生产系统,接口就越应该窄,权限越应该小,结果越应该可验证。

下一篇将继续专题第 9 篇:深入 OpenCode v2 的上下文工程与长期任务管理,讨论压缩、快照、记忆分层、证据保留和跨会话恢复,解决 Agent 做长任务时"越做越忘"的问题。

参考资料

本文依据 2026 年 10 月 24 日可访问的 OpenCode v2 官方文档与 Schema 整理。MCP 协议、Plugin 加载规则、OAuth 字段和 Permission action 仍可能演进,生产配置应以实际安装版本对应的官方文档、Schema 和启动诊断为准。

相关推荐
自养Agent2 小时前
AI 私有化实战:一张卡能扛几个并发,答案不在显卡参数里
人工智能
用户360055579002 小时前
Kestrel_VLLM - 21 · 收益区间实测界定:KV 分页与 L3 驻留为何被判「不做」
人工智能
长弓三石2 小时前
企业级开源Harness平台BizBuddy 0.9.9 发布:知识库混合检索与长期记忆托管
人工智能
一线数智2 小时前
来腾讯云AI开放日 加入人类职业进化计划
大数据·人工智能·腾讯云
桦说编程2 小时前
别再追“最强模型”了,先想清楚你要什么
人工智能·llm·agent
深圳市益普科技有限公司2 小时前
半导体 CIM 与 MES 的数据模型分工:工单该由谁持有
1024程序员节
loulanyue_2 小时前
机器换人不是终点,混合智能体重塑制造范式:从自主四要素到组织扁平化破局——读周济李培根院士2026东湖论坛国际智能制造创新论坛演讲实录
大数据·人工智能·制造
乌暮3 小时前
综合案例:宠物电商系统
java·开发语言·spring·mvc·restful·1024程序员节