8.1 MCP 协议简介
模型: claude-opus-4-6 (anthropic/claude-opus-4-6) 生成日期: 2026-02-17
在前面的章节中,我们深入了解了 OpenCode 内置的 Tool 系统——一组由 Tool.define() 工厂函数创建的、经过精心设计的核心工具(如 Bash、Read、Edit、Write 等)。这些工具覆盖了大部分日常编程场景,但现实世界的需求远比一套固定工具集所能满足的要丰富得多:团队可能需要 Agent 连接 Jira 来管理任务,调用 Figma API 来获取设计稿,或者查询内部的知识库来检索文档。如果每一个这样的需求都要在 OpenCode 核心代码中添加一个新的内置工具,代码库将会迅速膨胀,维护也将变得不可持续。
MCP(Model Context Protocol,模型上下文协议) 正是为解决这个问题而生的。它定义了一套标准化的协议,让 AI 应用(如 OpenCode)能够以统一的方式连接到任意的外部工具服务器。本节将介绍 MCP 的核心概念、设计目标,以及它在 OpenCode 中的定位。
8.1.1 MCP 的设计目标与核心概念
衍生解释:MCP(Model Context Protocol)是什么?
MCP 是由 Anthropic 公司于 2024 年发布的一个开放协议规范。它的设计灵感来源于 LSP(Language Server Protocol,语言服务器协议)——如果你使用过 VS Code,你可能已经间接体验过 LSP:VS Code 不需要为每种编程语言内置语法高亮和代码补全的逻辑,而是通过 LSP 协议与独立的"语言服务器"通信,由语言服务器提供语言特定的功能。
MCP 借鉴了这一思想:AI 应用不需要为每个外部工具编写定制的集成代码,而是通过 MCP 协议与独立的"工具服务器"通信,由工具服务器提供工具的定义和执行逻辑。
更具体地说,MCP 定义了一个 Client-Server 架构:
MCP Host(宿主):运行 AI 应用的环境,在我们的场景中就是 OpenCode。
MCP Client(客户端):宿主内部的组件,负责与 MCP Server 建立连接并通信。
MCP Server(服务器):独立的进程或远程服务,暴露工具、资源和提示词供 Client 使用。
这个架构的核心价值在于 解耦:工具的实现与 AI 应用完全分离,任何人都可以开发 MCP Server,而任何支持 MCP 的 AI 应用都可以连接它。
MCP 与 Function Calling 的区别
初学者可能会困惑:LLM 已经有了 Function Calling(函数调用)的能力,为什么还需要 MCP?这两者的关系如下:
层次
LLM 层面的能力——模型决定何时调用哪个函数
应用层面的协议——定义工具如何被发现和执行
工具定义
由应用硬编码或手动定义工具列表
由 MCP Server 动态提供,支持运行时发现
工具执行
应用自行实现执行逻辑
MCP Server 负责执行,应用只需传递参数和接收结果
生态
每个应用独自维护工具集
工具以独立服务形式存在,可被任意 MCP Client 复用
协议
无标准协议,每个 LLM Provider 有自己的格式
标准化的 JSON-RPC 2.0 协议
用一个类比来理解:Function Calling 相当于"我知道有一个叫 get_weather 的函数可以调用",而 MCP 相当于"有一个天气服务,我可以连接上去,它会告诉我它能提供哪些工具,我随时可以调用"。MCP 构建在 Function Calling 之上——MCP Server 提供的工具最终仍然以 Function Calling 的形式呈现给 LLM。
MCP 在 OpenCode 中的定位
在 OpenCode 的工具体系中,MCP 扮演着"外部工具桥梁"的角色:
无论是内置工具还是 MCP 工具,它们最终都被转换为 AI SDK 的 Tool 类型,呈现给 LLM 的是完全一致的接口。LLM 无法区分一个工具是 OpenCode 内置的还是来自 MCP Server 的——这正是 MCP 的优雅之处。
8.1.2 三种传输方式:Stdio、SSE、StreamableHTTP
MCP 协议在传输层面是灵活的——它不绑定到特定的传输方式。MCP SDK 支持三种传输方式,OpenCode 均已实现:
1. Stdio(标准输入输出)
这是最常见的传输方式,也是 OpenCode 中 type: "local" 配置对应的方式。工作原理:
OpenCode 作为父进程启动一个子进程来运行 MCP Server。
通信通过子进程的 stdin(标准输入)和 stdout(标准输出)进行。
每条消息都是一个完整的 JSON-RPC 2.0 消息,以换行符分隔。
子进程的 stderr(标准错误)被单独监听,用于日志输出。
在 OpenCode 源码中的实现:
适用场景:本地开发工具、文件系统操作、需要访问本地资源的工具。
2. SSE(Server-Sent Events)
SSE 是一种基于 HTTP 的单向推送技术。在 MCP 的上下文中:
Client 通过 HTTP POST 发送请求。
Server 通过 SSE(Server-Sent Events)持续推送响应。
这是 MCP 协议早期版本的远程传输方式。
衍生解释:什么是 SSE?
SSE(Server-Sent Events)是 HTML5 规范的一部分,允许服务器通过 HTTP 连接持续向客户端推送事件。与 WebSocket 不同,SSE 是单向的(只能服务器向客户端推送),但它的优势在于:基于标准 HTTP 协议、支持自动重连、天然支持事件类型分类。在 MCP 中,SSE 被用来承载 JSON-RPC 响应。
3. StreamableHTTP(HTTP 流传输)
StreamableHTTP 是 MCP 协议更新版本引入的传输方式,它更加灵活:
支持标准 HTTP 请求/响应和流式推送的混合。
比纯 SSE 更加通用,可以适配更多的服务器环境。
在 OpenCode 中,
type: "remote"配置的 MCP Server 会优先尝试 StreamableHTTP,如果失败则自动回退到 SSE。
这种降级策略是一个值得学习的工程实践——它确保了对不同版本 MCP Server 的最大兼容性。
8.1.3 MCP 的核心原语:Tool、Resource、Prompt
MCP 协议定义了三种核心原语(Primitive),每一种都对应着 AI 应用与外部世界交互的一个维度:
Tool(工具)
Tool 是 MCP 最核心的原语。MCP Server 暴露的 Tool 与我们在第 5 章学习的内置 Tool 在概念上完全一致——它们定义了 LLM 可以调用的操作。
一个 MCP Tool 的定义包括:
name:工具名称(如
search_issues)description:工具描述(供 LLM 理解何时使用)
inputSchema:参数的 JSON Schema 定义
当 LLM 决定调用一个 MCP Tool 时,流程如下:
Resource(资源)
Resource 代表 MCP Server 可以提供的数据资源。与 Tool 不同,Resource 是 被动提供 的——它们代表可以被读取的数据,而不是可以被执行的操作。
在 OpenCode 中,Resource 被定义为:
Resource 的典型应用场景包括:文档内容、数据库记录、API 响应数据等。
Prompt(提示词模板)
Prompt 是 MCP Server 提供的预定义提示词模板。它允许 MCP Server 向 AI 应用提供针对特定任务优化过的提示词。
例如,一个代码审查的 MCP Server 可能提供一个名为 review_code 的 Prompt,其中包含了经过优化的审查指令。用户可以通过 MCP Prompt 来使用这些模板,而不需要自己编写复杂的提示词。
在 OpenCode 中,MCP Prompt 可以通过斜杠命令(/)触发,OpenCode 会列出所有已连接 MCP Server 暴露的 Prompt 供用户选择。
三者的关系
Tool 面向 LLM:LLM 根据上下文自主决定是否调用。
Resource 面向应用:应用代码可以读取资源内容,通常用于上下文注入。
Prompt 面向用户:用户显式选择使用某个预定义的提示词模板。
在 OpenCode 的实现中,Tool 是使用最广泛的原语——几乎所有 MCP 集成场景都是通过 Tool 来实现的。Resource 和 Prompt 的使用相对较少,但它们为更高级的集成场景提供了可能性。
本节小结
MCP(Model Context Protocol)是一个标准化的协议,让 AI 应用能够以统一的方式连接到外部工具服务器。它借鉴了 LSP 的设计思想,将工具的实现与 AI 应用完全解耦。MCP 支持三种传输方式(Stdio、SSE、StreamableHTTP),OpenCode 在连接远程服务器时会自动进行降级尝试以确保最大兼容性。MCP 定义了三种核心原语——Tool(面向 LLM 的主动调用)、Resource(面向应用的被动读取)和 Prompt(面向用户的模板选择),其中 Tool 是最核心和最常用的原语。在接下来的小节中,我们将深入 OpenCode 的 MCP Client 源码,看看这些概念是如何被具体实现的。
Last updated
