1. 背景与定位
1.1 问题起源
LLM 应用落地过程中,长期存在一个核心矛盾:模型本身是封闭的,而现实世界的数据和工具是分散的。要让模型访问数据库、调用 API、操作文件系统,每个应用都要自己实现一套”模型 ↔ 外部系统”的胶水层,结果是:
- 重复造轮子:每个 Agent 框架都有自己的 Tool 定义格式(LangChain、LlamaIndex、AutoGPT……),互不兼容
- 集成爆炸:N 个 AI 应用 × M 个外部工具 = N×M 个点对点集成,维护成本指数级增长
- 安全边界模糊:工具权限、数据访问控制没有统一规范,各平台自行实现
1.2 MCP 的定位
MCP(Model Context Protocol) 由 Anthropic 于 2024 年 11 月开源,目标是成为 AI 应用连接外部工具和数据的通用标准接口。
一句话概括:MCP 之于 AI 工具调用,相当于 USB-C 之于设备充电接口。 它定义了一套标准化的通信协议,使 AI 应用(Host)可以通过统一方式接入任意符合规范的外部服务(MCP Server)。
1.3 与现有方案对比
| 特性 | OpenAI Function Calling | LangChain Tools | MCP |
|---|---|---|---|
| 标准化程度 | 厂商私有 | 框架私有 | 开放协议(RFC 级) |
| 传输层 | HTTP/REST | 进程内调用 | stdio / HTTP+SSE |
| 服务发现 | 无 | 无 | capabilities 协商 |
| 双向通信 | 单向(模型→工具) | 单向 | 双向(含 Sampling) |
| 资源订阅 | 不支持 | 不支持 | 支持(实时变更通知) |
| 跨语言 | 受限于 SDK | 受限于 Python | 任意语言实现 |
| 生态复用 | 需重写适配 | 需重写适配 | 一次实现,处处接入 |
2. 核心架构
2.1 三层模型
MCP 定义了三个角色:
1 | ┌─────────────────────────────────────────────┐ |
Host(宿主):运行 LLM 的应用程序,是整个系统的控制中心。它管理用户交互、持有 LLM 上下文,并决定何时以及是否调用外部能力。一个 Host 可以同时连接多个 MCP Client。
Client(客户端):Host 内部的连接组件,每个 Client 对应一个 MCP Server 连接,负责协议握手、消息路由和会话管理。Client 与 Server 是 1:1 关系。
Server(服务端):独立进程或远程服务,对外暴露 Tools、Resources、Prompts 三类能力。Server 不持有对话上下文,是无状态服务(会话状态由 Client 维护)。
2.2 设计原则
- Server 轻量化:Server 只需专注于暴露能力,不需要了解 LLM 上下文
- Host 掌控决策权:所有工具调用决策由 Host 做出,Server 无法主动推送工具调用指令(除 Sampling 外)
- 进程级隔离:每个 Server 运行在独立进程,权限边界清晰
3. 通信协议:JSON-RPC 2.0
3.1 消息格式基础
MCP 基于 JSON-RPC 2.0 规范,所有消息都是 JSON 对象,通过传输层流式传输。共三种消息类型:
请求(Request):Client 或 Server 发起,需要响应。
1 | { |
响应(Response):对应请求的回复,成功或错误二选一。
1 | { |
通知(Notification):单向推送,不需要响应,id 字段省略。
1 | { |
3.2 会话生命周期
1 | Client Server |
关键细节:
initialize是第一条消息,必须在任何其他请求之前完成initialized通知是客户端确认握手完成的信号,Server 收到后才可发送主动通知- 协议版本协商:Client 声明支持的最新版本,Server 选择兼容版本返回
- MCP 规范没有定义显式的 shutdown 方法,会话结束由 Client 直接关闭 stdio 管道或断开 HTTP 连接实现
3.3 错误处理
JSON-RPC 标准错误码:
| 错误码 | 含义 |
|---|---|
| -32700 | Parse error(JSON 解析失败) |
| -32600 | Invalid Request(请求格式错误) |
| -32601 | Method not found |
| -32602 | Invalid params |
| -32603 | Internal error |
MCP 扩展错误码(-32000 到 -32099 范围)由各 Server 自定义。
需要注意:工具执行错误(业务逻辑失败)不使用 JSON-RPC 错误码,而是通过 result.isError: true 标记。这样 LLM 才能理解错误含义并决定重试还是换策略:
1 | { |
4. 三大核心能力
MCP Server 对外暴露三类能力:Tools(工具)、Resources(资源)、Prompts(提示模板)。三者职责不同,配合使用覆盖了 AI 应用对外部世界的全部交互需求。
4.1 Tools(工具)
Tools 是 MCP 最核心的能力,允许 LLM 执行具有副作用的操作(写文件、发请求、改数据)。
工具定义格式
1 | { |
inputSchema 遵循 JSON Schema 规范(Draft 7),支持类型校验、枚举、范围限制等。Host 在传递参数给 Server 前会先做 Schema 校验。
调用流程
1 | 1. Client 调用 tools/list → 获取所有可用工具定义 |
工具调用请求/响应示例
1 | // 请求 |
工具注解(Annotations)
MCP 2025-03-26 版本引入了工具注解,用于声明工具的行为特征,帮助 Host 做策略决策(例如:只读工具可自动放行,危险工具必须强制用户确认):
1 | { |
| 注解字段 | 含义 |
|---|---|
readOnlyHint |
工具是否只读(不修改外部状态) |
destructiveHint |
操作是否不可逆(删除、覆盖等) |
idempotentHint |
重复执行是否安全 |
openWorldHint |
是否会访问互联网/外部服务 |
4.2 Resources(资源)
Resources 用于向 LLM 暴露上下文数据,适合文件内容、数据库记录、配置信息等只读或读多写少的场景。与 Tools 的区别在于:Resources 是数据源,被动提供内容;Tools 是动作,主动执行操作。
URI 寻址
每个资源有唯一的 URI,格式由 Server 自定义,常见模式:
1 | file:///home/user/project/README.md |
资源类型
1 | // 静态资源(列举时可见) |
读取资源
1 | // 请求 |
资源订阅与变更通知
1 | Client Server |
订阅机制让 LLM 上下文能感知外部状态变化,这是传统 Function Calling 完全不具备的能力。
4.3 Prompts(提示模板)
Prompts 允许 Server 向 Host 暴露可复用的提示模板,模板可以包含动态参数,适合标准化工作流场景(如代码审查、日志分析、报告生成)。
模板定义
1 | { |
获取渲染后的提示
1 | // 请求 |
Prompt 结果是一组结构化消息,Host 可以直接注入 LLM 上下文,启动特定的对话流程。这让 Server 可以把”如何向 LLM 提问”封装成可复用的资产。
5. 传输层实现
MCP 协议本身与传输层解耦,目前官方支持两种传输方式:stdio(本地子进程) 和 HTTP+SSE(远程服务)。
5.1 stdio 传输(本地子进程模式)
适用场景:MCP Server 以本地进程运行,Host 和 Server 在同一台机器上。
1 | Host Process |
启动配置示例(Claude Desktop config.json):
1 | { |
消息格式:每条消息是一行 JSON,以 \n 分隔(newline-delimited JSON)。
优点:
- 无需网络配置,天然安全(进程间通信)
- 启动简单,零依赖网络栈
- 进程崩溃时 Host 可以直接重启
缺点:
- 不支持远程 Server
- 每个 Host 实例需要独立启动 Server 进程,资源占用随 Host 数量线性增长
5.2 HTTP + SSE 传输(远程服务模式)
适用场景:MCP Server 作为 HTTP 服务独立部署,多个 Client 可以共享同一个 Server。
1 | Host MCP Server (HTTP) |
SSE 事件格式:
1 | event: message |
Session ID:SSE 初始化时 Server 返回 endpoint 事件,其中包含带 sessionId 的 POST URL,保证请求与响应的关联。
2025-03-26 规范更新:引入 Streamable HTTP 传输,合并了旧的 HTTP+SSE 双连接模式,支持在单个 HTTP 连接上同时处理请求和响应流,降低实现复杂度。
5.3 传输方式选型对比
| 维度 | stdio | HTTP+SSE |
|---|---|---|
| 部署位置 | 本地进程 | 本地或远程 |
| 多客户端共享 | 不支持 | 支持 |
| 网络穿透 | 不需要 | 需要处理防火墙/TLS |
| 安全隔离 | OS 进程隔离 | 需要认证机制 |
| 调试难度 | 低(直接看 stderr) | 中(需要抓包或日志) |
| 适用规模 | 个人/小团队 | 企业级部署 |
6. Sampling:服务端反向推理
Sampling 是 MCP 最独特的能力之一,允许 Server 主动请求 Client 执行 LLM 推理,实现真正的双向协作。这是 MCP 与传统 Function Calling 最大的架构差异——后者只能由模型单向调用工具。
6.1 核心机制
1 | Server Client/Host LLM |
6.2 请求格式
1 | { |
6.3 典型使用场景
- 代理式工具链:Server 接收工具调用结果后,自主决定下一步要做什么(如:SQL 查询完成后,让 LLM 分析结果,再决定是否需要再查一张表)
- 内容生成辅助:Server 在处理文件时,调用 LLM 生成摘要或注释
- 多轮推理循环:Server 实现 ReAct 风格的推理循环,在工具调用之间插入 LLM 判断
6.4 人机循环(Human-in-the-Loop)
关键安全规定:Host 在执行 Sampling 请求前,必须将请求内容展示给用户,允许用户:
- 修改要发送给 LLM 的消息
- 拒绝执行
- 修改 LLM 返回的内容再传回 Server
这确保人类对 AI-to-AI 通信始终保持控制权,防止恶意 Server 绕过用户监督。
7. 安全模型
7.1 核心安全原则
MCP 规范对安全性有明确要求,三个核心原则:
- 用户同意优先(User Consent):任何数据访问或工具调用,都必须经过用户明确授权
- 最小权限(Least Privilege):Server 只应请求完成任务所需的最小权限
- 透明可审计(Transparency):用户应该能够理解 AI 正在做什么、访问什么数据
7.2 工具敏感级别分类
工具注解(见 4.1 节)声明了工具的行为特征,Host 可据此制定授权策略。推荐实践如下:
| 级别 | 操作类型 | 建议策略 |
|---|---|---|
| 只读 | 文件读取、数据库 SELECT | 可以自动执行 |
| 写入 | 文件修改、数据库 INSERT/UPDATE | 提示用户确认 |
| 危险 | 删除操作、发邮件、支付 | 必须强制确认,展示详情 |
| 不可逆 | 数据库 DROP、账户注销 | 禁止自动执行,双重确认 |
7.3 凭证管理最佳实践
服务端凭证(数据库密码、API Key 等):通过环境变量注入,不硬编码在配置文件中:
1 | { |
传输安全:
- HTTP+SSE 传输必须使用 HTTPS(TLS 1.2+)
- 远程 Server 应实现 OAuth 2.0 或 API Key 认证
- stdio 模式天然安全,无需额外网络加密
7.4 提示注入防护
恶意 Resource 内容可能包含指令,试图操控 LLM 行为(Prompt Injection)。例如:
1 | 风险示例: |
防护措施:
- Resource 内容与 System Prompt 严格隔离,不直接拼接
- Host 在注入 Resource 内容前,包裹明确的标签边界:
1
2
3<resource uri="file:///data.txt">
[文件内容...]
</resource> - 高风险工具(删除、发送)不依赖 LLM 决策,必须用户手动触发
8. 能力协商机制
能力协商是 MCP 握手的核心环节,决定了 Client 和 Server 在本次会话中能使用哪些能力。这部分内容是对前文安全模型中”能力声明”的展开,给出完整的协议级示例。
8.1 initialize 请求完整示例
1 | // Client → Server |
注意几个细节:
- Client 端能力(
roots、sampling)由 Client 在capabilities中声明,Server 才能反向调用 - Server 端能力(
tools、resources、prompts、logging)由 Server 声明,Client 据此决定是否发送对应请求 listChanged: true表示该能力的列表可能动态变化,Server 会在变化时推送notifications/xxx/listChanged通知
8.2 版本兼容规则
- 如果 Server 不支持 Client 请求的版本,返回自己支持的最新版本
- Client 收到不同于请求版本的响应时,必须判断是否可以接受该版本,不能接受则断开连接
- 目前正式版本:
2024-11-05(稳定)、2025-03-26(最新)
8.3 能力可选性
并非所有能力都必须实现,Server 按需声明:
| 能力 | 声明方 | 是否必需 | 说明 |
|---|---|---|---|
| tools | Server | 可选 | 不声明则 Client 不会请求工具列表 |
| resources | Server | 可选 | 不声明则无资源能力 |
| prompts | Server | 可选 | 不声明则无提示模板 |
| logging | Server | 可选 | 声明后 Client 可通过 logging/setLevel 控制日志级别 |
| sampling | Client | 可选 | Client 声明支持后,Server 才能发起 Sampling 请求 |
| roots | Client | 可选 | Client 声明工作区根目录,帮助 Server 理解上下文范围 |
9. 开发实践
9.1 Python SDK 快速上手
安装:
1 | pip install mcp |
最简单的 MCP Server(Python):
1 | from mcp.server import Server |
9.2 TypeScript SDK 快速上手
安装:
1 | npm install @modelcontextprotocol/sdk |
TypeScript MCP Server 示例:
1 | import { Server } from "@modelcontextprotocol/sdk/server/index.js"; |
9.3 本地调试:MCP Inspector
官方提供了调试工具 MCP Inspector,无需配置 Claude Desktop 即可测试 Server:
1 | # 安装 |
Inspector 提供 Web UI(默认 http://localhost:5173),可以:
- 查看 Server 暴露的工具/资源/提示列表
- 手动发送工具调用,查看原始请求响应 JSON
- 查看实时通知消息流
9.4 常见陷阱与最佳实践
陷阱 1:Tool description 写得不清楚
LLM 完全依赖 description 字段决定是否及如何调用工具,描述模糊会导致:
- 工具被错误触发
- 参数传错(如 path 写成相对路径而非绝对路径)
推荐写法:
1 | { |
陷阱 2:忘记处理工具执行异常
工具执行失败应返回 isError: true,而不是抛出 JSON-RPC 错误:
1 | # 错误做法:抛出异常会导致 JSON-RPC 错误,LLM 无法理解 |
陷阱 3:Server 启动慢导致超时
stdio 模式下,Host 有握手超时限制(通常 30 秒)。避免在启动时做耗时操作(如连接数据库、加载大型模型),改为懒加载:
1 | # 懒加载数据库连接 |
陷阱 4:Resource URI 命名冲突
多个 Server 可能暴露相同 URI scheme(如多个 Server 都用 file://),Host 需要处理命名空间冲突。Server 端的最佳实践是在 URI 中包含自身标识,避免与其他 Server 撞车:
1 | # 好的 URI 设计(带 Server 标识) |
最佳实践总结:
| 实践 | 说明 |
|---|---|
| 工具描述精确 | 包含参数格式、限制、示例 |
| 幂等性设计 | 只读工具设计成幂等,方便重试 |
| 错误信息可读 | isError 时返回人类可读的错误说明 |
| 日志输出到 stderr | stdout 只输出协议消息 |
| 工具数量控制 | 单个 Server 工具数 < 20,过多影响 LLM 决策质量 |
| 版本化 URI | Resource URI 包含版本信息,方便缓存管理 |
10. 生态与展望
10.1 主流支持方(Host 端)
| 产品 | 类型 | MCP 支持状态 |
|---|---|---|
| Claude Desktop | 桌面应用 | 官方原生支持(最早) |
| Cursor | 代码编辑器 | 支持,深度集成 |
| VS Code(GitHub Copilot) | 代码编辑器 | 支持 |
| WorkBuddy | AI 工作台 | 支持(本文档所在环境) |
| Zed | 代码编辑器 | 支持 |
| Windsurf | 代码编辑器 | 支持 |
| Continue.dev | VS Code 插件 | 支持 |
| LibreChat | 开源 AI 客户端 | 支持 |
10.2 官方 MCP Server 清单
Anthropic 官方维护了一批参考实现(@modelcontextprotocol/ npm scope):
| Server 名称 | 能力 |
|---|---|
| server-filesystem | 本地文件系统读写 |
| server-github | GitHub 仓库、Issues、PR 操作 |
| server-google-drive | Google Drive 文件管理 |
| server-google-maps | 地图、地址解析、路线规划 |
| server-postgres | PostgreSQL 查询 |
| server-sqlite | SQLite 数据库操作 |
| server-slack | Slack 消息发送/读取 |
| server-memory | 持久化键值存储(跨会话记忆) |
| server-puppeteer | 无头浏览器(网页截图、自动化) |
| server-brave-search | Brave Search API |
| server-fetch | 通用 HTTP 请求(含 HTML→Markdown 转换) |
| server-sequential-thinking | 结构化多步推理工具 |
社区维护的热门 Server 数量远超官方,常见的有 mcp-server-gitlab、mcp-server-docker、mcp-server-kubernetes、mcp-server-jira、mcp-server-notion 等,且持续增长。完整列表参见 awesome-mcp-servers。
10.3 MCP 的定位与技术选型
1 | Tools(进程内调用) |
Tool、MCP、Skills 三者的本质区别:
- Tools 是进程内的函数调用,耦合在 Agent 代码里
- MCP 是进程外的标准协议,工具可以独立部署、独立升级
- Skills 是知识层面的规范约定(Markdown 文档),不是代码,而是告诉 Agent”这个项目怎么工作”
三者协作模式:MCP 负责能力接入,Skills 负责上下文约定,Tools 负责轻量逻辑(不需要独立部署的简单操作)。
理解了 MCP 在 Agent 体系中的定位后,实际选型时该用 MCP 还是直接用 Function Calling?参考以下场景划分:
1 | 用 MCP 的场景: |
附录
A. MCP 完整方法列表
| 方法 | 方向 | 说明 |
|---|---|---|
initialize |
C→S | 握手初始化 |
tools/list |
C→S | 获取工具列表 |
tools/call |
C→S | 调用工具 |
resources/list |
C→S | 获取资源列表 |
resources/read |
C→S | 读取资源内容 |
resources/subscribe |
C→S | 订阅资源变更 |
resources/unsubscribe |
C→S | 取消订阅 |
prompts/list |
C→S | 获取提示模板列表 |
prompts/get |
C→S | 获取渲染后的提示 |
logging/setLevel |
C→S | 设置日志级别 |
ping |
C↔S | 心跳检测 |
sampling/createMessage |
S→C | Server 请求 LLM 推理 |
roots/list |
S→C | 获取 Client 工作区根目录 |
notifications/tools/listChanged |
S→C | 工具列表变更通知 |
notifications/resources/listChanged |
S→C | 资源列表变更通知 |
notifications/resources/updated |
S→C | 特定资源内容变更通知 |
notifications/prompts/listChanged |
S→C | 提示模板列表变更通知 |
B. 参考资料
- 官方规范:https://spec.modelcontextprotocol.io
- 官方文档:https://modelcontextprotocol.io/docs
- Python SDK:https://github.com/modelcontextprotocol/python-sdk
- TypeScript SDK:https://github.com/modelcontextprotocol/typescript-sdk
- MCP Inspector:https://github.com/modelcontextprotocol/inspector
- 社区 Server 列表:https://github.com/punkpeye/awesome-mcp-servers