OpenCode 学习笔记 05:扩展与生产

MCP 扩展、流式输出、CLI 与生产级 Agent 架构

January 22, 2026·17 min read·Yimin
#AI#Agent#OpenCode#TypeScript#MCP#CLI#Production

从玩具到生产,从单机到扩展。AI Agent 不只是能用,还要好用。

本篇目标

目标实现
MCP 协议📖 原理介绍
流式输出📖 原理介绍
CLI 实现📖 原理介绍
AI 概念解析✅ Tool/Skill/MCP/Agent
总结架构✅ 完整回顾

一、MCP(Model Context Protocol)

1.1 什么是 MCP?

MCP = AI Agent 的"USB 接口"

┌─────────────────────────────────────────────────────────────┐
│  传统方式:每个工具都要单独适配                               │
│                                                             │
│  Agent ──┬── 文件系统工具                                    │
│          ├── 数据库工具                                      │
│          ├── API 工具                                        │
│          └── 浏览器工具    ← 每个都要写代码适配               │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│  MCP 方式:统一协议,即插即用                                 │
│                                                             │
│  Agent ──── MCP Client ────┬── MCP Server (文件系统)        │
│                            ├── MCP Server (数据库)          │
│                            ├── MCP Server (API)             │
│                            └── MCP Server (浏览器)          │
└─────────────────────────────────────────────────────────────┘

1.2 MCP 核心概念

概念说明
Server提供工具/资源的服务端
Client使用工具的客户端(Agent)
Tool可执行的操作
Resource可读取的数据
Prompt可复用的提示模板

1.3 MCP Server 类型

// OpenCode 配置示例
{
  "mcp": {
    // 本地 Server:运行本地命令
    "filesystem": {
      "type": "local",
      "command": ["npx", "@modelcontextprotocol/server-filesystem", "/path"]
    },
    
    // 远程 Server:连接远程服务
    "github": {
      "type": "remote",
      "url": "https://mcp.github.com",
      "oauth": true  // 支持 OAuth
    }
  }
}

1.4 OpenCode 的 MCP 实现

┌────────────────────────────────────────────────────────────┐
│                     MCP 模块架构                            │
├────────────────────────────────────────────────────────────┤
│                                                            │
│  ┌──────────┐      ┌──────────────────────────────────┐   │
│  │  Config  │ ───▶ │  MCP.create()                     │   │
│  │  (mcp:{})│      │  - StdioClientTransport (local)   │   │
│  └──────────┘      │  - StreamableHTTPTransport (remote)│  │
│                    │  - SSEClientTransport (fallback)  │   │
│                    └──────────────────────────────────┘   │
│                                  │                         │
│                                  ▼                         │
│                    ┌──────────────────────────────────┐   │
│                    │  MCP Client                       │   │
│                    │  - listTools()                    │   │
│                    │  - callTool()                     │   │
│                    │  - listResources()                │   │
│                    │  - readResource()                 │   │
│                    └──────────────────────────────────┘   │
│                                  │                         │
│                                  ▼                         │
│                    ┌──────────────────────────────────┐   │
│                    │  转换为 AI SDK Tool               │   │
│                    │  dynamicTool({ ... })             │   │
│                    └──────────────────────────────────┘   │
│                                                            │
└────────────────────────────────────────────────────────────┘

1.5 MCP 认证流程

远程 MCP Server 的 OAuth 流程:

1. Client 尝试连接
   └── 返回 401 Unauthorized

2. 发现 OAuth 元数据
   └── GET /.well-known/oauth-authorization-server

3. 动态客户端注册(如果需要)
   └── POST /register

4. 获取授权 URL
   └── 跳转浏览器

5. 用户授权
   └── 回调带 code

6. 交换 Token
   └── POST /token

7. 重新连接(带 Token)
   └── 成功!

1.6 为什么 tiny-agent 不实现 MCP

原因说明
依赖复杂需要 @modelcontextprotocol/sdk
认证复杂OAuth 流程、Token 存储
协议复杂JSON-RPC、多种传输方式
MVP 不需要内置工具已够用

建议:生产环境直接使用 OpenCode 或其他成熟框架的 MCP 支持。


二、流式输出

2.1 为什么需要流式?

非流式:
用户: 写一篇 1000 字的文章
AI: ...(等待 30 秒)...
AI: [突然输出全部内容]

流式:
用户: 写一篇 1000 字的文章
AI: 好的,
AI: 我来帮你写
AI: 一篇关于...
AI: (实时输出,用户体验好)

2.2 OpenCode 的流式实现

// 使用 AI SDK 的 streamText
const result = await streamText({
  model: language,
  messages,
  tools,
  // 流式回调
  onChunk(chunk) {
    // 实时处理每个 chunk
  },
  onStepFinish(step) {
    // 每个步骤完成时
    if (step.text) {
      onText(step.text)  // 输出文本
    }
    if (step.toolCalls) {
      // 处理工具调用
    }
  },
})

2.3 流式输出的数据流

┌─────────────────────────────────────────────────────────────┐
│                    流式输出数据流                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   LLM API                                                   │
│     │                                                       │
│     │  SSE (Server-Sent Events)                            │
│     │  data: {"type":"content_block_delta","delta":...}    │
│     │                                                       │
│     ▼                                                       │
│   AI SDK (streamText)                                       │
│     │                                                       │
│     │  解析 SSE,生成 chunks                                │
│     │                                                       │
│     ▼                                                       │
│   onStepFinish / onChunk                                    │
│     │                                                       │
│     │  回调应用代码                                         │
│     │                                                       │
│     ▼                                                       │
│   TUI / CLI                                                 │
│     │                                                       │
│     │  渲染到终端                                           │
│     │                                                       │
│     ▼                                                       │
│   用户看到实时输出                                          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

2.4 tiny-agent 的流式实现

// 使用 generateText 的 onStepFinish
const result = await generateText({
  model: Provider.getModel(modelId),
  messages,
  tools,
  onStepFinish: (step) => {
    if (step.text) {
      options.onText?.(step.text)  // 回调输出
    }
  },
})

// 使用方
const response = await AgentLoop.run(userMessage, {
  onText: (text) => {
    process.stdout.write(text)  // 实时写入终端
  },
})

三、CLI 实现

3.1 OpenCode CLI 架构

┌────────────────────────────────────────────────────────────┐
│                    OpenCode CLI 架构                        │
├────────────────────────────────────────────────────────────┤
│                                                            │
│  命令入口                                                   │
│  ├── opencode          (TUI 模式)                          │
│  ├── opencode run      (单次运行)                          │
│  ├── opencode mcp      (MCP 管理)                          │
│  ├── opencode session  (会话管理)                          │
│  └── opencode debug    (调试工具)                          │
│                                                            │
│  TUI 组件 (Ink + React)                                    │
│  ├── App.tsx           (主应用)                            │
│  ├── Prompt/           (输入组件)                          │
│  ├── Dialog/           (对话框)                            │
│  └── Routes/           (路由)                              │
│                                                            │
│  交互系统                                                   │
│  ├── Keybindings       (快捷键)                            │
│  ├── Theme             (主题)                              │
│  └── Event             (事件)                              │
│                                                            │
└────────────────────────────────────────────────────────────┘

3.2 TUI vs CLI

特性TUI (Terminal UI)CLI (Command Line)
交互方式持续交互单次执行
界面全屏、组件化简单输出
框架Ink (React for CLI)yargs/commander
适用场景复杂交互自动化脚本

3.3 tiny-agent 的 CLI 实现

// 简单的 readline 交互
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
})

const prompt = () => {
  rl.question("You: ", async (input) => {
    // 处理命令
    if (input === "exit") { ... }
    if (input === "mode explore") { ... }
    
    // 调用 AI
    const response = await AgentLoop.run(input, {
      onText: (text) => process.stdout.write(text),
    })
    
    prompt()  // 继续等待输入
  })
}

四、生产级 Agent 架构

4.1 完整架构图

┌─────────────────────────────────────────────────────────────────┐
│                    生产级 AI Agent 架构                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                    用户界面层                            │   │
│  │  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐    │   │
│  │  │   TUI   │  │   CLI   │  │   Web   │  │   API   │    │   │
│  │  └────┬────┘  └────┬────┘  └────┬────┘  └────┬────┘    │   │
│  └───────┴────────────┴────────────┴────────────┴──────────┘   │
│                             │                                   │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                    核心业务层                            │   │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐   │   │
│  │  │    Agent     │  │   Session    │  │    Tool      │   │   │
│  │  │  - build     │  │  - messages  │  │  - read      │   │   │
│  │  │  - explore   │  │  - compact   │  │  - write     │   │   │
│  │  │  - plan      │  │  - persist   │  │  - bash      │   │   │
│  │  └──────────────┘  └──────────────┘  │  - grep/glob │   │   │
│  │                                       │  - skill     │   │   │
│  │                                       └──────────────┘   │   │
│  └─────────────────────────────────────────────────────────┘   │
│                             │                                   │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                    基础设施层                            │   │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐   │   │
│  │  │   Provider   │  │  Permission  │  │   Storage    │   │   │
│  │  │  - OpenAI    │  │  - allow     │  │  - session   │   │   │
│  │  │  - Anthropic │  │  - deny      │  │  - rules     │   │   │
│  │  │  - Proxy     │  │  - ask       │  │  - snapshot  │   │   │
│  │  └──────────────┘  └──────────────┘  └──────────────┘   │   │
│  └─────────────────────────────────────────────────────────┘   │
│                             │                                   │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                    扩展层                                │   │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐   │   │
│  │  │     MCP      │  │     LSP      │  │   Plugin     │   │   │
│  │  │  - local     │  │  - symbols   │  │  - hooks     │   │   │
│  │  │  - remote    │  │  - diagnose  │  │  - transform │   │   │
│  │  │  - oauth     │  │  - complete  │  │              │   │   │
│  │  └──────────────┘  └──────────────┘  └──────────────┘   │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

4.2 关键设计原则

原则说明OpenCode 实现
分层职责分离UI / Core / Infra / Extension
可扩展支持插件MCP / Plugin / Custom Agent
安全权限控制Permission 系统
健壮错误处理Retry / Snapshot
高效性能优化Stream / Prompt Cache

4.3 最佳实践

工具设计

✅ 好的工具设计:
- 单一职责(read 只读,write 只写)
- 清晰的参数定义(Zod schema)
- 详细的描述(给 AI 看)
- 安全检查(权限验证)

❌ 避免的设计:
- 工具功能过于复杂
- 参数含义模糊
- 没有错误处理
- 直接执行危险操作

提示词设计

✅ 好的 System Prompt:
- 明确角色定位
- 列出可用工具和用法
- 设定行为规则
- 包含项目上下文

❌ 避免的设计:
- 过于冗长(token 浪费)
- 缺少工具说明
- 没有约束规则

会话管理

✅ 好的会话设计:
- 保存关键历史
- 及时压缩旧消息
- 持久化重要会话
- 支持恢复和回滚

❌ 避免的设计:
- 无限累积消息
- 丢失重要上下文
- 无法恢复状态

五、AI Agent 核心概念解析

5.1 Tool / Skill / MCP / Agent 的区别

┌─────────────────────────────────────────────────────────────────┐
│                    AI Agent 核心概念                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  Agent(大脑)                                           │   │
│  │  - 决策中枢,负责理解、推理、规划                         │   │
│  │  - 调用 Tools/Skills/MCP 完成任务                        │   │
│  │                                                          │   │
│  │    ┌──────────┐   ┌──────────┐   ┌──────────┐          │   │
│  │    │   Tool   │   │   Skill  │   │   MCP    │          │   │
│  │    │  (双手)   │   │  (知识)  │   │(外部工具) │          │   │
│  │    └──────────┘   └──────────┘   └──────────┘          │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
概念类比说明执行方式
Tool双手(吃饭、喝水)内置的基本能力,直接执行操作代码执行
Skill知识(会开车、换灯泡)可载入的指导知识,告诉 AI 怎么做AI 解读后调用 Tool
MCP外部工具(电钻、汽车)连接外部系统的标准协议通过协议调用外部服务
Agent大脑决策中枢,理解 + 推理 + 执行调用上述所有能力

5.2 Skill 的本质

Skill 是"知识",不是"代码"

┌─────────────────────────────────────────────────────────────┐
│  SKILL.md 内容示例                                          │
├─────────────────────────────────────────────────────────────┤
│  ---                                                        │
│  name: git-commit                                           │
│  description: 帮助生成规范的 Git commit 消息                 │
│  ---                                                        │
│                                                             │
│  # Git Commit 规范                                          │
│                                                             │
│  ## 格式                                                    │
│  type(scope): subject                                       │
│                                                             │
│  ## 类型                                                    │
│  - feat: 新功能                                             │
│  - fix: 修复 bug                                            │
│  - docs: 文档更新                                           │
│  ...                                                        │
└─────────────────────────────────────────────────────────────┘

                    ↓ AI 读取 Skill 内容
                    
┌─────────────────────────────────────────────────────────────┐
│  AI 理解知识后,使用 Tool 执行                               │
│  1. 调用 bash 工具: git diff --staged                       │
│  2. 分析 diff 内容                                          │
│  3. 根据 Skill 规范生成 commit message                       │
│  4. 调用 bash 工具: git commit -m "feat: ..."               │
└─────────────────────────────────────────────────────────────┘

关键点:Skill 本身不执行代码,AI 读取 Skill 内容后,使用 Tool 来执行操作。

5.3 Multi-Agent vs Subtask

概念说明适用场景
Multi-Agent多个专业化的 Agent 切换不同任务需要不同专家
Subtask主 Agent 派遣子 Agent 并行执行大任务分解为多个独立小任务
Multi-Agent(专家切换):
┌─────────────────────────────────────────────────────────────┐
│  用户: 我要修改代码                                         │
│    └── build Agent(全能模式,可读写)                      │
│                                                             │
│  用户: 帮我分析一下这个项目                                  │
│    └── explore Agent(只读模式,安全)                      │
│                                                             │
│  用户: 我想规划一下重构方案                                  │
│    └── plan Agent(规划模式,不执行)                       │
└─────────────────────────────────────────────────────────────┘

Subtask(任务分派):
┌─────────────────────────────────────────────────────────────┐
│  主 Agent: 我需要同时做三件事                               │
│    │                                                        │
│    ├── 子任务1: 重构 auth 模块  ──▶  Sub-Agent-1 ──────┐   │
│    ├── 子任务2: 更新测试用例    ──▶  Sub-Agent-2 ────┐ │   │
│    └── 子任务3: 修改文档        ──▶  Sub-Agent-3 ──┐ │ │   │
│                                                     │ │ │   │
│    ◀──────────── 汇总所有结果 ◀────────────────────┴─┴─┘   │
└─────────────────────────────────────────────────────────────┘

5.4 Claude Code vs OpenCode 的 Skill/Hooks

Claude Code 的 Skill + Hooks

Claude Code 的 Skill 支持内置 Hooks,可以在特定事件时自动执行脚本:

# .claude/skills/auto-format/SKILL.md
---
name: auto-format
description: 自动格式化代码

# Skill 内置 Hooks!
hooks:
  PostToolUse:
    - matcher: "Edit|Write"
      command: "${CLAUDE_PLUGIN_ROOT}/scripts/format.sh"
---

当你修改代码后,自动运行格式化。

Claude Code 支持的 Hook 事件

事件触发时机
PreToolUse工具执行
PostToolUse工具执行
UserPromptSubmit用户发送消息时
SessionStart会话开始
PermissionRequest需要用户授权时

OpenCode 的 Hooks 实现

OpenCode 兼容 Claude Code 的 Skills 目录,但 不支持 SKILL.md 中的 hooks

OpenCode 的 Hooks 通过两种方式实现:

1. 配置文件 hooks(experimental)

// opencode.json
{
  "experimental": {
    "hook": {
      "file_edited": {
        "*.ts": [{ "command": ["npm", "run", "format"] }]
      },
      "session_completed": [{ "command": ["./notify.sh"] }]
    }
  }
}

2. Plugin hooks(TypeScript)

// 支持的 hooks
"chat.message"              // 新消息
"chat.params"               // 修改 LLM 参数  
"permission.ask"            // 权限检查
"command.execute.before"    // 命令执行前
"tool.execute.before"       // 工具执行前
"tool.execute.after"        // 工具执行后

对比总结

特性Claude CodeOpenCode
Skills 目录.claude/skills/.opencode/skill/ + 兼容 .claude/skills/
SKILL.md 内置 Hooks✅ 支持 frontmatter❌ 不支持
Hooks 配置位置SKILL.md配置文件 + Plugin
Hook 事件PreToolUse, PostToolUse...file_edited, tool.execute.before...
执行方式Shell 脚本Shell 脚本 / TypeScript

5.5 概念关系图

┌─────────────────────────────────────────────────────────────────┐
│                    AI Agent 概念全景                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│                        ┌─────────┐                              │
│                        │  User   │                              │
│                        └────┬────┘                              │
│                             │                                   │
│                             ▼                                   │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │                      Agent (大脑)                         │  │
│  │  ┌────────────────────────────────────────────────────┐  │  │
│  │  │              Session (会话/记忆)                    │  │  │
│  │  │   messages + context + rules + skills(知识列表)    │  │  │
│  │  └────────────────────────────────────────────────────┘  │  │
│  │                          │                                │  │
│  │          ┌───────────────┼───────────────┐               │  │
│  │          ▼               ▼               ▼               │  │
│  │    ┌──────────┐   ┌──────────┐   ┌──────────┐           │  │
│  │    │   Tool   │   │   Skill  │   │   MCP    │           │  │
│  │    │ (内置)    │   │ (载入)   │   │ (外部)   │           │  │
│  │    │          │   │          │   │          │           │  │
│  │    │ read     │   │ 知识     │   │ 远程API  │           │  │
│  │    │ write    │   │ 指导     │   │ 本地服务 │           │  │
│  │    │ bash     │   │ 模板     │   │ 数据库   │           │  │
│  │    │ grep     │   │          │   │          │           │  │
│  │    └──────────┘   └──────────┘   └──────────┘           │  │
│  └──────────────────────────────────────────────────────────┘  │
│                             │                                   │
│          ┌──────────────────┼──────────────────┐               │
│          ▼                  ▼                  ▼               │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐         │
│  │  Permission  │  │    Hooks     │  │  Sub-Agent   │         │
│  │  (权限控制)   │  │  (生命周期)  │  │  (子任务)    │         │
│  └──────────────┘  └──────────────┘  └──────────────┘         │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

六、tiny-agent vs OpenCode 总结

6.1 功能对比

功能tiny-agentOpenCode
基础
Tool 系统✅ 简化✅ 完整
Provider✅ 3 个✅ 10+
Agent Loop✅ ReAct✅ ReAct + 变体
工具
read/write/edit✅ + 更多
grep/glob✅ + LSP
bash✅ 简化✅ + 沙箱
会话
多轮对话
上下文压缩✅ 简单截断✅ AI 摘要
项目规则✅ + URL
Skills✅ 渐进式✅ 渐进式
持久化✅ 文件✅ 分层存储
高级
多 Agent✅ 2 种✅ 6+ 种
权限系统✅ 简化✅ 复杂规则
重试机制
Snapshot✅ Git
子任务
扩展
MCP
LSP
Plugin
TUI❌ readline✅ Ink

6.2 代码量对比

tiny-agent:          ~1500 行
OpenCode:           ~50000+ 行

tiny-agent 实现了 OpenCode 核心功能的 ~3%,
但覆盖了核心概念的 ~80%。

6.3 学习收获

通过 tiny-agent,我们学习了:

  1. Tool 系统:定义、参数校验、执行
  2. Provider 抽象:多模型支持、Proxy 配置
  3. Agent Loop:ReAct 模式、工具调用
  4. 会话管理:历史、压缩、持久化
  5. 规则系统:项目规则、Skills
  6. 多 Agent:模式切换、权限隔离
  7. 权限控制:allow/deny/ask
  8. 重试机制:指数退避

七、下一步

7.1 如果想深入学习

  1. 阅读 OpenCode 源码

    • packages/opencode/src/session/prompt.ts - 核心 Agent Loop
    • packages/opencode/src/tool/ - 完整工具实现
    • packages/opencode/src/mcp/ - MCP 实现
  2. 实践项目

    • 添加更多工具(如网页抓取)
    • 实现 Snapshot
    • 集成 MCP Server
  3. 生产部署

    • 使用 OpenCode 或 Claude Code
    • 配置企业 Proxy
    • 自定义 Agent

7.2 相关资源

资源链接
OpenCodegithub.com/opencode-ai/opencode
MCP 协议modelcontextprotocol.io
AI SDKsdk.vercel.ai
Claude Codeclaude.ai/code

总结

┌─────────────────────────────────────────────────────────────┐
│                    AI Agent 学习路线                         │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Phase 1: 基础架构                                          │
│  └── Tool + Provider + Agent Loop                          │
│                                                             │
│  Phase 2: 核心工具                                          │
│  └── read/write/edit/bash/grep/glob                        │
│                                                             │
│  Phase 3: 会话与记忆                                        │
│  └── 多轮对话 + 压缩 + 规则 + Skills                        │
│                                                             │
│  Phase 4: 高级功能                                          │
│  └── 多Agent + 权限 + 重试 + Snapshot                       │
│                                                             │
│  Phase 5: 扩展与生产                                        │
│  └── MCP + 流式 + CLI + 架构                               │
│                                                             │
└─────────────────────────────────────────────────────────────┘

核心心得

  1. 从简单开始:tiny-agent 证明了核心功能可以很简洁
  2. 理解原理:比会用更重要
  3. 渐进增强:先能用,再好用,最后生产级
  4. 善用工具:OpenCode 已经很成熟,生产环境直接用

感谢阅读本系列!🎉