一、MCP 基础概念
1.1 什么是 MCP?
定义 :MCP(Model Context Protocol,模型上下文协议)是由Anthropic公司于2024年底提出的一种开放标准协议 ,它标准化了应用程序如何为 LLM 提供上下文,旨在解决大型语言模型(LLM)与外部数据、工具之间的连接交互问题。它为AI应用提供了一种统一的、标准化的方式来访问和处理数据(实时数据、本地数据),解决了AI模型的数据孤岛问题,为 AI 应用提供了连接万物的接口,被誉为 "AI 领域的 USB-C"。
核心价值:
传统的AI模型面临几个关键挑战:
- 知识时效性限制:模型只了解训练截止日期前的信息
- 专有数据访问困难:无法直接访问企业内部系统的数据
- 集成成本高昂:每接入一种新数据源,都需要定制专门的集成方案。传统上,将 AI 系统连接到外部工具涉及集成多个 API。每个 API 集成都意味着单独的代码、文档、身份验证方法、错误处理和维护。
MCP的核心优势:
- 生态:MCP 提供很多现成的插件,你的 AI 可以直接使用。
- 统一性:不限制于特定的 AI 模型,任何支持 MCP 的模型都可以灵活切换。
- 数据安全:你的敏感数据留在自己的电脑上,自行决定上传那些数据。
MCP 是 AI大模型 与数据(包括本地数据和互联网数据)之间的一座桥梁,通过 MCP 服务器和 MCP 客户端,大家只要都遵循这套协议,就能实现"万物互联"。比如,可以和数据和文件系统、开发工具、Web 和浏览器自动化、生产力和通信、各种社区生态能力全部集成,实现强大的协作工作能力。
1.2 核心架构

MCP 遵循客户端-服务器架构(client-server),其中包含以下几个核心概念:
- MCP 主机(MCP Hosts):发起请求的 LLM 应用程序(例如 Claude Desktop、IDE 或 AI 工具)。
- MCP 客户端(MCP Clients):在主机程序内部,与 MCP server 保持 1:1 的连接。
- MCP 服务器(MCP Servers):为 MCP client 提供上下文、工具和 prompt 信息。
- 本地资源(Local Resources):本地计算机中可供 MCP server 安全访问的资源(例如文件、数据库)。
- 远程资源(Remote Resources):MCP server 可以连接到的远程资源(例如通过 API)。
其中,重点关注MCP Client和MCP Server。
MCP Client :
MCP client 充当 LLM 和 MCP server 之间的桥梁,MCP client 的工作流程如下:
❶ MCP client 首先从 MCP server 获取可用的工具列表。 ❷ 将用户的查询连同工具描述通过 function calling 一起发送给 LLM。 ❸ LLM 决定是否需要使用工具以及使用哪些工具。 ❹ 如果需要使用工具,大模型向MCP client发出请求,MCP client 会通过 MCP server 执行相应的工具调用。 ❺ MCP server处理请求,处理结果返回给MCP client ❺ MCP client将结果发送回 LLM。 ❻ LLM 基于所有信息生成自然语言响应。 ❼ MCP Hosts将响应展示给用户。
Claude Desktop 和Cursor都支持了MCP Server接入能力,它们就是作为 MCP client来连接某个MCP Server感知和实现调用。
MCP Server :
MCP server 是 MCP 架构中的关键组件,它可以提供 3 种主要类型的功能:
○ 资源(Resources):将 Server 上的数据和内容开放给大语言模型,可以是文本或二进制数据。如 API 响应、文件内容、图像等。 ○ 工具(Tools):可以被调用的函数,这些函数可由客户端调用,并由 LLM 使用来执行操作。 ○ 提示(Prompts):预先编写的可复用的提示词模板和工作流程。
这些功能使 MCP server 能够为 AI 应用提供丰富的上下文信息和操作能力,从而增强 LLM 的实用性和灵活性。
一个形象的比喻
我在网上看到了一个比较形象的比喻,感觉还不错,摘录到这里,如果需要查看原文请点这里 首先,用户让 LLM 调用工具,就好比我(特工少女,即 User)让男朋友(LLM)去小店(软件服务提供商)买东西(Data & Tool)并使用。如果模型接到的任务则可能需要多个工具调用(Tool Use),这就好比我跟男朋友讲的需求比较复杂,比如做从零做一道番茄炒蛋。
然后男朋友通过规划(Planning)决定去苏泊尔买个锅和铲,去菜场买个西红柿和鸡蛋,再去便利店买个糖和盐,以此来完成番茄炒蛋这道菜。但是在传统的 AI 应用开发过程中,男朋友(LLM)能去的小店(能使用的工具)都需要开发者预先定义线路(编写代码)。
但是,男朋友(LLM)每去一个新地方,都要造一条新路(编写代码),似乎不太方便。于是后来字节扣子、百度千帆、阿里云百炼等平台出现了,他们就好比是开了一个商超。商超跟各种小店说,我这里人气旺,你们直接按我们的要求来货架上架你们的商品就行,再跟我(User)说我这现成的商品多,以后让男朋友(LLM)来这买就行。
小店们觉得这事不错,便遵守平台一定的上架规范,开始把他们的商品(Tool)变成了插件(Plugin),我(User)提的好多需求,男朋友(LLM)在这些平台上就能一站式满足了,选几个插件直接用就行,方便了挺多。
但是,Anthropic 干了一个什么事情呢?他想搞电商!
他跟小店们说,不同平台的插件规范不太一样,你们去各个平台上架插件也挺累的。咱们搞个新玩法,能让天下的男朋友(LLM)都很容易的用到更多商品(调用更多工具)。你们呢按照我这个标准,把你们的商品都做一个数字化的标准信息处理(即变成了 MCP Server),我们再定义一个叫电商组件的东西(即 MCP Client),你们的 MCP Server 要跟电商组件有互动,只要遵守一个开放的规则,这部分就是 MCP 协议,即 Server 和 Client 的通信协议。
此外,Anthropic 基于这个电商平台(Client)的理念做了一个淘宝的外壳,这个淘宝就好比没有包含 LLM 的 Claude Desktop。在这基础上,如果再加上 Claude 的模型,就相当于让"男朋友刷淘宝",这一整体就构成了 MCP Host。
MCP Server 只管提供各种工具,MCP Host 只管通过 MCP Client 获取并使用这些工具。然后淘宝上玲琅满目的商品很多,就形成了 MCP Market。
1.3 通信机制
关于Client和Server之间的通信方式,MCP 协议支持两种主要的通信机制:基于Stdio(标准输入输出)的本地通信和基于SSE(Server-Sent Events)的远程通信。
这两种机制都使用 JSON-RPC 2.0 格式进行消息传输,确保了通信的标准化和可扩展性。
**本地通信:**通过 stdio 传输数据,适用于在同一台机器上运行的客户端和服务器之间的通信。 **远程通信:**利用 SSE 与 HTTP 结合,实现跨网络的实时数据传输,适用于需要访问远程资源或分布式部署的场景。
连接过程 :
- 客户端发送包含协议版本和功能的请求initialize
- Server 使用其协议版本和功能进行响应
- 客户端发送通知作为确认initialized
- 正常消息交换开始
二、MCP与其他技术的比较
2.1 与Function Calling对比
Function Calling,最初是由OpenAI在2023年6月作为其API的一部分提出的,是一种函数调用机制,允许LLM通在生成内容的过程中调用外部函数或服务,从而获取更多能力。现在,很多其他大模型也借鉴了这种概念,纷纷推出了自己的function calling 。借助这个功能,可以调用外网检索引擎、天气查询、图片生成服务、音乐生成服务调用等。
对比项目 | MCP | Function Calling |
---|---|---|
定义 | 模型和其它设备集成的标准接口,包含:工具 Tools、资源 Resources、提示词 Prompts | 将模型连接到外部数据和系统,平铺式的罗列 Tools 工具。和 MCP Tool 不同的在于:MCP Tool 的函数约定了输入输出的协议规范。 |
性质 | 协议 | 功能 |
协议 | JSON-RPC,支持双向通信、可发现性、更新通知能力。 | JSON-Schema,静态函数调用。 |
调用方式 | Stdio / SSE / 同进程调用 | 同进程调用 / 编程语言对应的函数 |
范围 | 通用(多数据源、多功能) | 特定场景(单一数据源或功能) |
目标 | 统一接口,实现互操作 | 扩展模型能力 |
实现 | 基于标准协议 | 没有统一的标准,各个大模型提供厂商都有自己的接入方式 |
开发复杂度 | 低:通过统一协议实现多源兼容 | 高:需要为每个任务单独开发函数 |
复用性 | 高:一次开发,可多场景使用 | 低:函数通常为特定任务设计 |
灵活性 | 高:支持动态适配和扩展 | 低:功能扩展需要额外开发 |
适用场景 | 动态、复杂场景,如跨平台数据访问和整合 | 简单任务。如天气查询、翻译等 |

Function calling 功能单一,不具备上下文管理能力,一次只执行一个任务,一般是同步进行调用。没有特定的标准,需要厂商或者我们自己去开发实现。生态相对封闭,没有多少开源项目,定制化比较多。 MCP 功能复杂,可以支持多轮对话,一次能调用多个任务,也可以异步执行。有统一的标准,只要是适配了 MCP 的 Server 都可以用统一的代码去调用,而且除了工具调用,还提供了提示词和上下文资源。
2.2 举例
-
如果你的 function 最初需要两个参数(例如,天气服务的 location 参数和 date 参数,用户需严格按此参数结构构建应用。
-
之后,如果你决定为该 function 添加第三个必选参数(例如,unit参数(温度单位)),将"契约"进行变更。
-
这意味着该 function 的所有用户都必须更新代码,增加对新参数的支持,如果未及时更新,他们的请求可能会失败、报错或提供不完整的结果。
MCP 的设计解决了这个问题,具体方法如下:
-
MCP 引入了一种动态、灵活的方法。
-
当 Client(例如 Claude Desktop 这类 AI 应用)连接 MCP Server(例如天气服务)时,会发送初始请求,以便了解 Server 的能力。
-
Server 的响应包含可用的 tools、resources、prompts 以及相关参数的详细信息。例如,若天气 API 最初仅支持 location 和 date 参数,服务器会通过能力交换告知这些信息。
-
当新增 unit 参数时,MCP Server 可在下次进行能力交换时动态更新能力描述。Client 无需硬编码或预定义参数,只需查询 Server 的最新能力并自动适配。
-
这样,Client 就能使用更新后的新功能(例如在其请求中包含 unit 参数),实时调整行为,而无需重写或重新部署代码。
当然,mcp协议和function call两者并不直接对立的,反而是进行相互补充:
- mcp协议工作在应用与外部工具对接的阶段,标准化这些工具的开发,以及在应用层接入、执行等过程,更多指的是整个让模型调用工具的整体手段。
- function call 则工作在应用与大模型交互之间,标准化如何让大模型理解、调用外部工具。如Host 里的 LLM 向 Client 调用工具时,大多仍然使用 Function Calling。
三、实战案例:交通态势实时查询
3.1 需求
开发一个支持自然语言查询的某市某条道路的实时交通态势,通过 MCP 调用高德 API。
3.2 实现MCP Server
准备:高德ApiKey、安装@modelcontextprotocol/sdk
代码如下:
ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
// 通过命令行获取key
const API_KEY = process.argv[2];
/**
* @description 创建服务器实例
*/
const server = new McpServer(
{
name: "amap-traffic-mcp-server",
version: "1.0.0",
},
{
capabilities: {
resources: {},
tools: {},
prompts: {},
},
instructions: "交通态势查询服务,使用高德API",
}
);
// 注册交通态势查询工具
server.tool(
"get_traffic",
"线路交通态势查询",
{
city: z.string().describe("城市名称"),
name: z.string().describe("道路名,街道名字"),
},
async ({ city, name }) => {
try {
// URL 编码参数
const encodedCity = encodeURIComponent(city);
const encodedName = encodeURIComponent(name);
// https://lbs.amap.com/api/webservice/guide/api-advanced/traffic-situation-inquiry
// 调用高德地图 API
const response = await fetch(
`https://restapi.amap.com/v3/traffic/status/road?key=${API_KEY}&level=5&name=${encodedName}&city=${encodedCity}`
);
if (!response.ok) {
throw new Error(`API请求失败: ${response.status}`);
}
const data = await response.json();
// 检查 API 响应状态
if (data.status !== "1") {
throw new Error(`高德地图API错误: ${JSON.stringify(data)}`);
}
// 检查是否有交通信息
if (!data.trafficinfo) {
return {
content: [
{
type: "text",
text: `未找到 ${city} 的 ${name} 的交通信息`,
},
],
};
}
const { description, evaluation } = data.trafficinfo;
// 计算道路通畅程度
const status = evaluation?.status || "未知";
let statusText = "";
switch (status) {
case "1":
statusText = "通畅";
break;
case "2":
statusText = "基本通畅";
break;
case "3":
statusText = "轻度拥堵";
break;
case "4":
statusText = "中度拥堵";
break;
case "5":
statusText = "重度拥堵";
break;
default:
statusText = "未知";
}
return {
content: [
{
type: "text",
text: `${city}${name}当前路况:${statusText}\n\n${
description || "暂无详细描述"
}`,
},
{
type: "text",
text: evaluation
? `\n\n道路状况统计:\n- 畅通路段:${evaluation.expedite}\n- 缓行路段:${evaluation.congested}\n- 拥堵路段:${evaluation.blocked}\n- 未知路段:${evaluation.unknown}`
: "",
},
],
};
} catch (error) {
console.error("交通信息查询失败:", error);
throw new Error(
error instanceof Error ? error.message : "服务调用失败,请稍后重试"
);
}
}
);
/**
* @description 启动服务器
*/
async function main() {
try {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("交通态势查询服务已启动");
} catch (error) {
console.error("服务启动失败:", error);
process.exit(1);
}
}
main();
在开发的时候,可以使用@modelcontextprotocol/inspector进行调试。
3.3 实现MCP Client
js
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
const transport = new StdioClientTransport({
command: "node",
args: ["/Users/bwrong/0WorkSpace/00.MyStudy/mcp-demo/server/build/index.js",'API-KEY']
});
const client = new Client(
{
name: "traffic-client",
version: "1.0.0"
}
);
await client.connect(transport);
console.log("connect success");
// List prompts
// const prompts = await client.listPrompts();
// Get a prompt
// const prompt = await client.getPrompt({
// name: "example-prompt",
// arguments: {
// arg1: "value"
// }
// });
// List resources
// const resources = await client.listResources();
// Read a resource
// const resource = await client.readResource({
// uri: "file:///example.txt"
// });
const tools = await client.listTools();
console.log(tools);
// Call a tool
const result = await client.callTool({
name: "get_traffic",
arguments: {
city: "成都市",
name: "天府大道北段"
}
});
console.log(result);
在Client中可以连接Server,然后获取它提供的resource、prompt、tools,并可以执行调用。
当然我们也可以使用现有的一些支持MCP集成的应用来调用,不同的应用支持的功能可能有差异,具体可查看这里。下面我们使用cursor来演示。
- 打开cursor的MCP配置文件。
- 添加配置
js
{
"mcpServers": {
"amap-traffic-mcp-server": {
"type": "stdio",
"command": "node",
"args": [
"/Users/bwrong/0WorkSpace/00.MyStudy/mcp-demo/server/build/index.js",
"111111111111111111" // 你的高德API-key
]
}
}
}
- 正常情况可以看到mcp列表中已出现添加的MCP及它提供的tools
- 在chart面板中输入"帮我查询成都市天府大道北段道路交通情况"。可以看到它调用了MCP,并返回了结果
当然,如果你的MCP想共享给别人使用,那么可以发布到npm上,在
package.json
中添加如下内容,支持使用npx运行。
json
"bin": {
"amap-traffic-mcp-server": "./build/index.js"
}
然后进行发布,发布后,别人就可以使用如下方式进行集成了。
json
"amap-traffic-mcp-server": {
"type": "stdio",
"command": "npx",
"args": [
"amap-traffic-mcp-server",
"cc2b744799eaa97ade23c468e272c731"
]
}
更多代码亲查看这里
四、使用社区现有的MCP服务
MCP的出现,极大降低了大模型调用外部海量工具、软件、接口的门槛,越来越多的软件及工具厂商参与到 MCP 服务(MCP Server)生态的建设中,将其产品能力包装为 MCP 服务开放给 AI 模型使用。以下是一些MCP托管平台:
一些有意思的MCP Server:
参考文档: