Skip to content

MCP 协议 ​

Agent 系统发展到一定阶段会遇到一个瓶颈:内置工具再多,也覆盖不了所有用户的需求。有人需要接入自己公司的数据库,有人需要操作 Notion,有人需要调用内部 API——这些都不是通用工具库能预装的。

MCP(Model Context Protocol,模型上下文协议)解决的就是这个问题:定义一套标准协议,让任何人都能把自己的服务、数据源、工具包装成 MCP Server,然后接入支持 MCP 的 AI 客户端,无需修改客户端本身。

本章目标 ​

  • 理解 MCP 是什么,它解决的核心问题是什么
  • 掌握 MCP 的三类能力:工具、资源、提示词
  • 知道 MCP Server 和 MCP Client 各自做什么
  • 了解 MCP 配置的作用域和实际使用方式

MCP 是什么 ​

MCP 是 Anthropic 于 2024 年底提出的开放协议,目标是标准化「AI 模型与外部数据源/工具之间的通信方式」。

在 MCP 之前,每个 AI 应用都要自己写集成代码:接 Slack 要写 Slack 客户端,接数据库要写数据库驱动,接代码仓库要写 GitHub API 调用。每次集成都是重复造轮子,也导致 AI 工具生态碎片化——A 家的 AI 写的工具,B 家的 AI 用不了。

MCP 的思路类似 USB 接口:定义一个通用插口,符合规格的设备都能连。MCP Server 提供能力,MCP Client(Claude Code、Claude Desktop、Cursor 等)消费能力,中间用标准协议通信。

MCP 本身既非新模型,也非工具库。它是一套接口规范,目标是让工具生态从专有集成走向标准接口。

但 MCP 真正要解决的问题比"多接几个工具"更根本——它要解决的是能力的标准化外部化。

没有协议时,AI 客户端和每个外部系统之间都是一对一集成。工具能力被锁死在具体产品里,迁移成本高,生态也没法共享。MCP 把工具集成从"产品内部实现细节"拉到了"跨产品可复用的协议层"。

MCP 能提供的三类能力 ​

MCP Server 可以向客户端暴露三类东西:

1. 工具(Tools) ​

功能型能力,模型可以主动调用。和 Tool Calling 里的工具概念一样,但工具定义来自外部 Server,不是 AI 客户端内置的。

示例:

  • 数据库查询工具(执行 SQL,返回结果)
  • 文件上传工具(把本地文件传到指定平台)
  • 发送 Slack 消息工具
  • 调用内部 API 的工具

模型调用 MCP 工具的方式和调用内置工具完全一样——它从工具描述里理解这个工具做什么,然后用结构化参数调用,等待结果。

2. 资源(Resources) ​

数据型能力,可以被读取但不执行操作。资源是只读的上下文数据,比工具更轻量。

示例:

  • 项目文档
  • 代码库 README
  • 数据库 Schema
  • 配置文件

模型读取资源,相当于读取一段背景信息,用于辅助回答或执行任务。

3. 提示词模板(Prompts) ​

预定义的 prompt 模板,可以带参数,由用户触发。这类能力更像斜杠命令——用户选择一个预制的 prompt,填入变量,由 MCP Server 渲染成完整的 prompt 再发给模型。

示例:

  • /code-review → 生成标准化代码审查 prompt
  • /summarize-tickets → 生成汇总 Jira 工单的 prompt

这三类能力的拆分非常值得注意,因为它们对应的是三种完全不同的使用语义:

  • Tool:要执行,要产生动作或查询结果
  • Resource:只读,只提供上下文材料
  • Prompt:不直接执行,而是帮助组织用户和模型之间的任务描述

MCP 在协议层就把能力类型分开了,没有把所有外部能力粗暴地塞成"工具"。这个分层会直接影响安全边界、调用方式和用户体验。

MCP Server 和 MCP Client 的分工 ​

MCP Server(服务提供方):

  • 实现具体的工具、资源或提示词
  • 用标准协议对外暴露能力
  • 独立部署,和 AI 客户端解耦
  • 任何语言都可以写:Python、TypeScript、Go……

MCP Client(能力消费方):

  • AI 应用(Claude Code、Claude Desktop、Cursor 等)
  • 连接 MCP Server,获取可用工具列表
  • 把 MCP 工具透明地注入到 AI 模型的工具调用流程里
  • 处理权限管理、连接状态

从模型视角看,MCP 工具和内置工具没有区别——只看到工具名称、描述和参数 Schema,不知道工具是内置的还是来自外部 Server。连接复杂性封装在协议层,模型和用户都不需要感知。

MCP 的核心价值:解耦 ​

Client 不再需要知道每个外部系统的接入细节,Server 也不需要为每个 AI 客户端单独适配一套接口。协议层把两边解开之后,能力就能独立演进:

  • 客户端升级自己的模型和交互界面
  • Server 升级自己的业务逻辑和能力
  • 双方只要仍然说同一种协议,就能继续协作

很多基础设施协议最终带来的价值都是这样的:接入的每个工具都变成了一个可被多个客户端共享的能力节点。

传输方式 ​

MCP 协议支持多种传输方式,适应不同部署场景(来自 Claude Code v2.1.88 源码 services/mcp/types.ts):

传输类型场景
stdio本地子进程,最常见的本地工具场景
sseHTTP Server-Sent Events,适合远程服务
http标准 HTTP,适合 REST 风格的远程 Server
wsWebSocket,适合需要双向实时通信的场景

最简单也最常用的是 stdio:MCP Client 启动一个本地子进程作为 Server,通过标准输入/输出通信。配置只需要写明命令和参数:

json
{
  "mcpServers": {
    "my-tool": {
      "command": "npx",
      "args": ["-y", "my-mcp-server-package"]
    }
  }
}

不同传输方式看起来只是部署差异,实际上也意味着信任边界和运维复杂度不同。

  • stdio 更适合本地、可信、低延迟场景
  • http / sse / ws 更适合远程服务,但也会引入认证、网络抖动、重连和版本兼容等问题

所以选传输方式,不只是看"能不能连上",还要看这项能力是更像本地插件,还是更像远程基础设施。

配置作用域 ​

MCP Server 的配置不只有一个位置,Claude Code 定义了多层作用域(来自 services/mcp/types.ts):

作用域含义
local只对当前项目生效,通常在项目目录的配置文件里
user用户全局,对该用户的所有项目生效
project项目级,团队共享
enterprise企业托管,由管理员统一下发
dynamic运行时动态注册,不写入配置文件

多层作用域让公司可以在企业层面强制启用某些 MCP Server(比如内部数据库工具),用户也可以在个人层面加自己的工具,两者不冲突。

这背后其实是在解决另一类问题:谁有权决定模型能接入哪些外部能力。

对企业来说这其实是个治理问题。MCP Server 一旦能连数据库、消息系统、文档平台,AI 的能力边界就已经被扩展了。作用域分层,本质上是在给这种能力扩展做权限归属划分。

MCP 的连接状态管理 ​

MCP 连接不是一次性的——Server 需要持续运行,Client 需要处理连接失败、重连、认证等情况。Claude Code 对每个 MCP Server 的连接状态做了明确的类型区分(来自 services/mcp/types.ts):

  • connected:正常连接,可以调用工具
  • pending:连接中,包括重连尝试次数
  • needs-auth:需要授权才能连接(支持 OAuth)
  • failed:连接失败,记录了错误信息
  • disabled:被手动禁用

MCP 集成不是「加个配置就好」。网络不稳定、认证过期、Server 崩溃都是真实场景,连接状态管理是工程实现里绕不开的部分。

MCP 是一层运行时基础设施 ​

到了生产环境你会发现,MCP 远不只是静态工具目录,它更像一层活的运行时基础设施。客户端需要持续面对这些问题:

  • 这个 Server 现在连得上吗
  • 需要重新认证吗
  • 当前暴露的工具和资源有没有变化
  • 多个 Server 的命名和描述会不会冲突
  • 出故障时是降级、隐藏,还是让用户显式感知

所以成熟客户端都会单独做连接管理、状态展示和权限控制,MCP 配置项背后有一整套运行时机制在支撑。

从 Claude Code 看 MCP 的实际使用 ​

Claude Code 把 MCP 深度集成进了整个工具系统。当 MCP Server 连接成功后,它的工具会被合并进 Claude Code 的工具列表,模型可以像调用内置工具一样调用它们。

几个细节值得留意:

工具命名规范化:MCP 工具的名称会经过标准化处理(normalization.ts),确保和内置工具名称格式一致,不会因为 Server 命名风格不同而混乱。

Worker 也能用 MCP 工具:在多 Agent 场景下,Coordinator 的系统提示词里会明确告知 Worker 当前有哪些 MCP Server 可用,Worker 也可以直接调用 MCP 工具,不需要通过 Coordinator 中转。

官方注册表:Claude Code 有一个 officialRegistry.ts,维护了经过认证的 MCP Server 列表。用户可以从这个注册表直接安装 Server,而不用手动配置命令和参数。

插件也可以提供 MCP Server:Claude Code 的插件系统支持插件内置 MCP Server 配置,安装一个插件,就同时获得了它携带的 MCP 工具。

MCP 和普通 Tool Calling 的关系 ​

维度普通 Tool CallingMCP
工具来源开发者在代码里定义外部 Server 动态提供
扩展方式修改应用代码连接新的 MCP Server
工具复用每个应用单独实现一个 Server 供多个客户端使用
部署和应用一起打包独立部署,可以是远程服务
标准化无统一标准MCP 协议规范

写一个 MCP Server,可以同时被 Claude Code、Claude Desktop、Cursor 等支持 MCP 的工具使用。

MCP 和 Tool Calling 的关系:标准化扩展层 ​

学过 Tool Calling 的话,可以这样理解分工:Tool Calling 管的是模型怎么决定调哪个工具、传什么参数;MCP 管的是这些工具怎样以统一协议从外部接进来。

简单说,Tool Calling 偏模型侧行为,MCP 偏系统侧扩展性。两者配合,才有了今天"模型像调内置工具一样调用外部生态能力"的体验。

什么时候不需要 MCP ​

如果你的项目只有两三个工具,全部都在同一个后端服务里,而且只服务一个 AI 应用,直接用 Function Calling 往往更简单。比如一个聊天助手里内置 get_weather、search_docs、create_ticket 三个函数,工具定义、权限和业务逻辑都在同一个代码库里,没必要先抽成 MCP Server。

MCP 更适合这些场景:

  • 同一批工具要被 Claude Code、Cursor、内部 AI 平台同时使用
  • 工具背后接的是独立系统,比如数据库、工单、文档平台或企业内部 API
  • 工具需要由另一个团队维护,客户端只负责消费能力
  • 工具列表会动态变化,不适合每次都改 AI 应用代码再发布

一个实用判断是:如果工具只是当前应用的内部函数,用 Function Calling 就够;如果工具已经像一项可复用服务,就值得考虑 MCP。

把已有 REST API 包成 MCP Server ​

很多团队接 MCP 时不需要重写业务系统。已有 REST API 可以继续作为内部实现层,MCP Server 只是外面新加的一层协议适配。

最小改造路径是:

  1. 选出适合暴露给 Agent 的 API,不要一口气把整套内部系统都暴露出来
  2. 为每个能力写清楚工具名、描述和参数 Schema
  3. 在 MCP Server 的工具处理函数里调用原来的 REST API
  4. 在 Server 端做参数校验、鉴权和结果过滤
  5. 把这个 MCP Server 注册到客户端配置里

结构上可以这样理解:

text
AI Client → MCP Server → 现有 REST API → 内部系统

一个极简的 TypeScript 结构如下,真实项目里还要补认证、错误处理和日志:

typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

const server = new McpServer({ name: "orders-api", version: "1.0.0" });

server.tool(
  "get-order",
  "根据订单号查询订单状态,只返回状态、金额和更新时间",
  { orderId: z.string().min(1) },
  async ({ orderId }) => {
    const res = await fetch(`https://internal.example.com/orders/${orderId}`, {
      headers: { Authorization: `Bearer ${process.env.INTERNAL_API_TOKEN}` },
    });
    const order = await res.json();

    return {
      content: [
        {
          type: "text",
          text: JSON.stringify({
            status: order.status,
            amount: order.amount,
            updatedAt: order.updatedAt,
          }),
        },
      ],
    };
  }
);

await server.connect(new StdioServerTransport());

这段代码里最关键的不是 fetch,而是只返回必要字段。内部 API 可能有手机号、地址、支付流水、客服备注,但 Agent 查询订单状态时不一定需要看到这些。MCP Server 应该做一次能力收口,而不是把内部 API 原样透传给模型。

MCP Server 的安全边界 ​

MCP 把工具接入变容易了,也把安全责任推到了更明确的位置:Server 端必须假设来自模型的参数不可信。

几个底线最好一开始就做:

  • 认证放在传输层或 Server 入口层处理,远程 MCP Server 不能默认裸奔
  • 工具按最小权限暴露,一个 Server 不一定要把所有内部 API 都注册成工具
  • 参数在 Server 端重新校验,不能因为模型给了 JSON 就直接拼 SQL、拼路径或拼 URL
  • 写操作默认需要额外确认或幂等 key,避免模型重试导致重复副作用
  • 返回结果先脱敏,尤其是 token、手机号、邮箱、内部备注和调试日志

对于 stdio 本地 Server,安全问题更偏本机权限:它能读哪些文件、能执行哪些命令、环境变量里有没有密钥。对于 http / sse 远程 Server,重点会变成认证、租户隔离、限流和审计。传输方式不同,风险位置也不同。

自己动手:最简单的 MCP Server ​

用 TypeScript 写一个最小的 MCP Server,只需要:

typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

const server = new McpServer({ name: "my-server", version: "1.0.0" });

server.tool("say-hello", "向某人打招呼", { name: z.string() }, async ({ name }) => ({
  content: [{ type: "text", text: `你好,${name}!` }],
}));

const transport = new StdioServerTransport();
await server.connect(transport);

这段代码就是一个可以被 Claude Code 使用的 MCP Server。工具的 description 字段是模型决定何时调用它的唯一依据,和写 System Prompt 是同一个道理。

容易踩的坑 ​

Server 挂了,Agent 不报警:MCP Server 如果因为网络问题断开,模型可能只是看到工具调用失败,不会主动解释"是 Server 断了"。要做好 Server 的监控和重连。

工具描述写得太模糊:MCP 工具的 description 是模型选择调用的唯一线索,写「数据库工具」不如写「查询用户订单记录,返回最近 30 天的订单列表」。

权限没有边界:MCP Server 能做的事情,模型就能让它做。如果你的 Server 接了生产数据库,一定要在 Server 层做只读限制,不能只靠 prompt 约束。

版本不兼容:MCP 协议还在持续演进,不同版本的客户端和 Server 之间可能存在兼容性问题,接入前要核查版本要求。

安全责任到底落在哪一层 ​

这是接 MCP 时特别需要想清楚的一件事。很多人会下意识觉得:"客户端不是会做权限控制吗,那我 Server 端是不是可以简单一点?" 这个想法很危险。

稳妥的做法是:客户端和 Server 各自负责自己的安全边界。

  • Client 负责连接管理、用户确认、权限展示、能力暴露策略
  • Server 负责真正的数据访问边界、只读限制、参数校验、审计和鉴权

因为一旦 Server 本身权限过大、缺乏约束,客户端即使提醒得再好,也只是把风险提前告知,而没有真正收住。

回头看:MCP 作为工程能力意味着什么 ​

到这里可以整理一下 MCP 在工程上到底带来了什么。

MCP 最核心的价值在于把能力从产品私有集成拉到了协议级标准。一个 MCP Server 写好,多个客户端都能用,这才是生态能真正跑起来的前提。

Tools、Resources、Prompts 三类能力的拆分也不是随意的,它直接决定了外部能力以什么语义进入系统——该执行的执行,该只读的只读,该组织对话的组织对话。

传输方式的选择看起来是部署问题,但背后是信任边界和运维复杂度的取舍。stdio 和 http 不只是"本地 vs 远程",更是"可信 vs 需要认证和重连"。

还有一点容易忽视:MCP 接入之后,外部服务就成了系统运行时的一部分。状态管理和故障处理省不了,安全责任也要客户端和 Server 两边各自扛住自己那部分。

和其他章节的关系 ​

  • Tool Calling:MCP 工具的调用方式和普通 Tool Calling 完全一致,读懂了 Tool Calling 就读懂了 MCP 的模型侧。
  • 多 Agent 协调:Worker 可以使用 MCP 工具,MCP 扩展了多 Agent 系统能调用的外部能力边界。
  • AI 应用系统设计:在系统设计层面,MCP Server 是一个独立部署的微服务,需要考虑其稳定性、版本管理和权限控制。

常见面试考点 ​

MCP 相关题目通常会围绕“它和普通工具调用到底差在哪”展开。可以按这几条线准备:

  1. MCP vs Function Calling:Function Calling 描述模型如何调用工具,MCP 描述外部工具和数据源如何标准化接入客户端。
  2. 三类能力:Tools 会执行动作,Resources 提供只读上下文,Prompts 组织任务模板;三者的安全边界不同。
  3. Client / Server 分工:Client 负责连接、展示和权限体验,Server 负责真实的数据访问、参数校验、鉴权和审计。
  4. 传输方式选择:stdio 适合本地可信工具,http / sse / ws 更适合远程服务,但要额外处理认证、重连和运维。
  5. 安全机制:不要只靠 prompt 约束,Server 端必须做只读限制、参数范围校验、最小权限和日志审计。
  6. 生态价值:MCP 的意义不是多一个工具格式,而是让同一个外部能力可以被多个 AI 客户端复用。

下一章:A2A 协议——MCP 解决 Agent 如何接入工具和数据源,A2A 则处理 Agent 如何发现并调用另一个 Agent。

如果你想直接上手体验 MCP,可以先看 MCP 工具入门——里面覆盖了如何在 Cursor 等客户端配置和使用现成的 MCP Server,不需要自己从零写一个。

面向开发者系统学习 AI 应用开发、RAG、Agent 与 Vibe Coding。