Model Context Protocol(MCP)
Model Context Protocol(MCP)是由 Anthropic 开发的开源协议,专注于构建安全且可解释的生成式 AI 系统。
MCP 的诞生源于解决 LLM 应用的一个关键限制,即它们与外部数据源和工具的隔离问题。
LLM 应用的一个核心关注点是数据传输,即如何将数据提供给 LLM 进行推理。这一直是 RAG 和微调的目标,同时也是 MCP 的目标。
MCP 的主要目的是标准化 LLM 应用如何连接到不同的系统,如下图所示:
图片来源:
https://github.com/modelcontextprotocol/servers
AI Agent 在获取数据时面临一个挑战,换句话说,就是如何将 AI Agent 或基于 LLM 的应用集成到外部数据源中。
为了实现无缝集成,已经有许多尝试,例如利用 GUI、Web 浏览器和 Web 搜索等方式。
这些方法各有优劣。
MCP 有潜力成为一个通用接口,可以将其视为 AI 领域的虚拟/软件版 USB-C。
它能够在 LLM/AI Agent 与外部资源之间实现无缝、安全且可扩展的数据交换。
MCP 采用客户端-服务器架构,其中 MCP 主机(AI 应用)与 MCP 服务器(数据/工具提供方)进行通信。
开发者可以使用 MCP 构建可复用、模块化的连接器,并利用针对主流平台的预构建服务器,从而打造一个由社区驱动的生态系统。
MCP 的开源特性鼓励创新,允许开发者扩展其功能,同时通过精细化权限控制等特性确保安全性。
最终,MCP 旨在将 AI Agent 从孤立的聊天机器人转变为具备上下文感知能力、可互操作且深度集成于数字环境的系统。
Anthropic 的 Model Context Protocol(MCP)是一个开源协议,用于将 LLM 连接到上下文、工具和提示词。它支持越来越多的服务器(server),可以用于连接各种工具或数据源。
Anthropic 在发布 MCP 时,公开了详细的 Model Context Protocol 规范以及支持多种语言的 SDK,详见:https://github.com/modelcontextprotocol。
整个规范,可以分几个大块来了解:协议架构、协议基本消息类型、协议生命周期管理、协议的传输层
1. 协议之架构
Model Context Protocol (MCP) 采用 client-host-server 架构,每个 host 可以运行多个client实例。
这种架构使用户能够在各个应用程序中集成人工智能能力,同时保持清晰的安全边界并隔离关注点。
MCP 基于 JSON-RPC 构建,提供了一种有状态的会话协议,专注于上下文交换和 clients 与servers之间的采样协调。
JSON-RPC 2.0 规范: https://www.jsonrpc.org/specification
1.1 基本组件
Host
Host进程充当容器和协调者(比如Cline,cursor等):
-
创建和管理多个客户端实例
-
控制客户端连接权限和生命周期
-
协调 AI/LLM 集成和采样
-
管理Clients之间的上下文聚合
Clients
每个客户端由Host创建,并保持一个独立的 server 连接(比如由Cline代码内嵌的SDK Client):
-
和每个 server 建立一个有状态的会话
-
处理协议协商和能力交换
-
双向路由协议消息
-
管理订阅和通知
-
维护 servers 之间的安全边界
host 应用程序创建并管理多个 clients,每个 client 与特定 server 之间具有一对一的关系。
Servers
server 提供专业的上下文和能力:
-
通过 MCP 原语暴露resources、tools 和prompts
-
通过client 提供的接口请求sampling
-
可以是本地进程或远程服务
1.2 基本消息类型
MCP 定义了基于 JSON-RPC 2.0 的三种核心消息类型:
-
Requests: 双向消息,带有方法和参数,期望有响应
-
Responses: 匹配特定请求 ID 的成功结果或错误
-
Notifications: 无需回复的单向消息
1.3 能力协商
Model Context Protocol 使用了一种基于能力(capability-based)的协商机制,在初始化阶段,clients和servers会明确声明它们支持的功能,而这些能力决定了在会话期间可以使用哪些协议特性和原语(primitives)
2. 协议规范之基本消息类型
所有在 MCP clients 和 servers 之间的消息必须遵循 JSON-RPC 2.0 规范。该协议定义了三种基本类型的消息:
消息类型 | 描述 | 约束 |
---|---|---|
Requests | 用于具体操作的消息,比如查询所有Tool、调用Tool等,支持的所有类型详见2.1.1 | 必须包含唯一的 ID 和方法名称 |
Responses | 应答 | 必须包含与请求相同的 ID |
Notifications | 单向消息,不需要回复 | 不得包含 ID |
2.1 Requests(消息请求)
Requests
可以从Client端或者Server端发起
格式要求:
{
jsonrpc: "2.0";
id: string | number;
method: string;
params?: {
[key: string]: unknown;
};
}
-
请求必须包含一个字符串或整数类型的 ID。
-
ID 不能为
null
。 -
请求 ID 在同一会话中不得被请求者之前使用过。
2.1.1 Requests的关键业务类型:
Request method | 发起方 | 响应方 | 描述 |
---|---|---|---|
initialize | Client | Server | 初始化会话 |
tools/list | Client | Server | 发现可用的工具 |
tools/call | Client | Server | 调用工具 |
resources/list | Client | Server | 发现可用的资源 |
resources/read | Client | Server | 要获取资源内容 |
resources/templates/list | Client | Server | 发现可用的参数化资源 |
resources/subscribe | Client | Server | 以订阅特定资源,并在其发生变化时接收通知 |
prompts/list | Client | Server | 发现可用的提示词 |
prompts/get | Client | Server | 要获取特定的提示词 |
roots/list | Server | Client | 列出Server有权限访问Client的文件系统Root节点,暴露目录和文件 |
sampling/createMessage | Server | Client | 使Server能够利用 AI 能力的生成能力 |
2.2 Responses(消息应答)
Responses
是对requests的回复。
格式要求:
{
jsonrpc: "2.0";
id: string | number;
result?: {
[key: string]: unknown;
}
error?: {
code: number;
message: string;
data?: unknown;
}
}
-
Responses 必须包含与其对应 request 相同的 ID。
-
必须设置
result
或error
之一。不得同时出现。 -
错误代码必须是整数。
2.3 Notifications(通知)
Notifications
是从client 发送到server 或反向发送的。不需要回复。
格式要求:
{
jsonrpc: "2.0";
method: string;
params?: {
[key: string]: unknown;
};
}
通知不得包含 ID。
2.4 举例:Client获取Server Tool列表
要查询可用的工具,Client发送一个 tools/list
请求
Request(请求)
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {
"cursor": "optional-cursor-value"
}
}
Response(响应)
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "get_weather",
"description": "Get current weather information for a location",
"inputSchema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City name or zip code"
}
},
"required": ["location"]
}
}
],
"nextCursor": "next-page-cursor"
}
}
3. 协议规范之生命周期管理
MCP定义了client-server连接的严格生命周期,确保了能力协商和状态管理。
-
Initialization(初始化): 能力协商和协议版本一致
-
Operation(操作): 正常的协议通信
-
Shutdown(关闭): 连接的优雅关闭
3.1 Initialization(初始化):
初始化阶段必须是 client 和 server 之间的第一次交互。在此阶段,client 和 server确定协议版本兼容性、交换和协商各自的能力、分享实施细节。
由client 发送一个包含 initialize
请求来启动此阶段,包含:
-
支持的协议版本
-
Client 能力
-
Client 信息
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {
"roots": {
"listChanged": true
},
"sampling": {}
},
"clientInfo": {
"name": "ExampleClient",
"version": "1.0.0"
}
}
}
server 必须响应其自身的能力和信息:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {
"logging": {},
"prompts": {
"listChanged": true
},
"resources": {
"subscribe": true,
"listChanged": true
},
"tools": {
"listChanged": true
}
},
"serverInfo": {
"name": "ExampleServer",
"version": "1.0.0"
}
}
}
成功初始化后,client 必须发送一个 initialized
通知以表明它已准备好开始正常操作:
{
"jsonrpc": "2.0",
"method": "notifications/initialized"
}
3.1.1 版本协商
在 initialize
请求中,client 必须发送其支持的协议版本。这应该是client 支持的最新版本。
如果server支持请求的协议版本,则必须以相同的版本进行响应。否则,server必须以其支持的其他协议版本进行响应。这应该是server支持的最新版本。
如果client 不支持server响应中的版本,则应该断开连接。
3.1.2 能力协商
client 和server 在会话期间将提供哪些可选的协议功能。
关键能力包括:
类别 | 能力 | 描述 |
---|---|---|
Client | roots | 提供文件系统根目录的能力 |
Client | sampling | 支持LLM采样请求 |
Client | experimental | 描述对非标准实验特性的支持 |
Server | prompts | 提供提示模板 |
Server | resources | 提供可读的资源 |
Server | tools | 公开可调用的工具 |
Server | logging | 发出结构化日志消息 |
Server | experimental | 描述对非标准实验特性的支持 |
3.2 Operation(操作)
在操作阶段,client 和 server 根据协商的能力交换消息。
遵守协商的协议版本
仅使用成功协商的能力
3.3 Shutdown(关闭)
在关闭阶段,连接被优雅地终止。
client 发送断开连接通知
server 关闭连接
清理相关资源
4. 协议规范之传输层
MCP 目前定义了两种标准的 client-server通信传输机制:stdio(标准输入输出)和基于 SSE 的 HTTP。客户端应尽可能支持 stdio。
此外,客户端和服务器也可以以可插拔的方式实现自定义传输机制。
5. 参考
https://spec.modelcontextprotocol.io/specification/2024-11-05/
Model Context Protocol(MCP)开发教程
MCP为连接AI应用与数据源提供了一个通用的开放标准,用单一协议取代了碎片化的集成。通过这个机制, 能力小的AI应用会变成更强的应用
在整个MCP的架构中,我们的AI应用(如Cline)作为MCP Hosts,通过内部的MCP Client去接入不同的MCP Server,从而达到增强能力的目的
根据MCP协议,当AI应用连接到MCP Server后,能够获取多种能力,比如Tool,Prompts、Resources等
详细内容见:一文说清楚让LangChain大佬“开战”的MCP是什么?
1. 常见AI应用对MCP Server能力的支持情况
目前MCP还在发展过程中,我们可以通过官方看到常见AI应用目前可以使用的能力情况。
应用对于Tool能力的使用,目前是最广泛的:
2. 代码实现MCP Server
我们要实现一个简单的server,他将有一个tool,可以通过订单号查询物流信息。
这个server在整个架构中的位置,就是下图中绿色的块:
2.1 配置环境
首先,让我们安装 uv
并设置我们的 Python 项目和环境:
安装uv工具(windows)
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
重新开启一个终端,并确认uv已经安装成功
PS G:\workspace\idea\py\hello-mcp-server> uv version
uv 0.6.6 (c1a0bb85e 2025-03-12)
❝在macos/linux环境中安装uv
curl -LsSf https://astral.sh/uv/install.sh | sh
❝uv是一个用 Rust 编写的极快的 Python 包和项目管理器。
官网:https://github.com/astral-sh/uv
创建项目,初始化环境:
# 初始化项目
uv init hello-mcp-server
# 创建Python虚拟环境
cd hello-mcp-server
uv venv
# 激活虚拟环境
.venv\Scripts\activate
# 安装依赖
uv add mcp[cli]
2.2 新建MCP Server : hello_mcp_server.py
我们新建一个Server,并增加tool来模拟通过订单号查询物流信息的功能
2.2.1 定义一个server
导入包并定义mcp实例
"""
pip install mcp[cli]
"""
from mcp.server.fastmcp import FastMCP
from pydantic import Field
# Initialize FastMCP server
mcp = FastMCP("hello-mcp-server", log_level="ERROR")
2.2.2 定义工具
通过@mcp.tool()
注解,把一个函数注册为Tool
# 注册工具的装饰器,可以很方便的把一个函数注册为工具
@mcp.tool()
asyncdef query_logistics(order_id: str = Field(description="订单号")) -> str:
"""查询物流信息。当用户需要根据订单号查询物流信息时,调用此工具
Args:
order_id: 订单号
Returns:
物流信息的字符串描述
"""
# 统一的物流信息数据
tracking_info = [
{"time": "2024-01-20 10:00:00", "status": "包裹已揽收", "location": "深圳转运中心"},
{"time": "2024-01-20 15:30:00", "status": "运输中", "location": "深圳市"},
{"time": "2024-01-21 09:00:00", "status": "到达目的地", "location": "北京市"},
{"time": "2024-01-21 14:00:00", "status": "派送中", "location": "北京市朝阳区"},
{"time": "2024-01-21 16:30:00", "status": "已签收", "location": "北京市朝阳区三里屯"}
]
# 格式化物流信息
result = f"物流单号:{order_id}\n\n物流轨迹:\n"
for item in tracking_info:
result += f"[{item['time']}] {item['status']} - {item['location']}\n"
return result
2.2.3 使用 MCP Inspector 进行测试
MCP Inspector 是一个用于测试和调试 MCP 服务器的交互式开发工具。
https://modelcontextprotocol.io/docs/tools/inspector
启动MCP Inspector:
执行命令:mcp dev hello_mcp_server.py
(hello-mcp-server) PS G:\workspace\idea\py\hello-mcp-server> mcp dev hello_mcp_server.py
Starting MCP inspector...
Proxy server listening on port 3000
🔍 MCP Inspector is up and running at http://localhost:5173 🚀
通过浏览器打开http://localhost:5173
连接MCP Server:
点击“Connect”启动MCP Server并建立连接
1.使用标准输入输出作为传输层
2.使用命令是uv
3.uv命令的参数
查询所有的Tool:
1.点击“Tools”能力标签
2.点击“List Tools”,查询server中所有的tool(调用了协议的tools/list
端点)
3.显示出所有的tool
执行Tool:
1.选择需要测试的tool
2.输入入参:ORDER-123456,点击“Run Tool”(调用了协议的tools/call
端点)
3.Tool成功返回结果
3. 使用Cline测试Server
打开Cline,点击上边的“MCP Server”
选择“Installed”
点击“Configure MCP Servers”
右边会弹出配置文件
将自己刚写的服务器相关配置填进去,保存
"hello-mcp-server": {
"name": "第一个MCP服务",
"key": "hello-mcp-server",
"command": "uv",
"args": [
"--directory",
"G:\\workspace\\idea\\py\\hello-mcp-server\\",
"run",
"--with",
"mcp",
"mcp",
"run",
"hello_mcp_server.py"
],
"disabled": false,
"autoApprove": []
}
整个完整命令相当于:
uv --directory G:\workspace\idea\py\hello-mcp-server\ run --with mcp mcp run hello_mcp_server.py
分为3段:
-
uv --directory G:\workspace\idea\py\hello-mcp-server\
指定工作目录
-
run --with mcp
运行时必须要有mcp包被安装
-
mcp run hello_mcp_server.py
使用mcp启动server
左边会生成对应的服务列表,点击“Done”退出
在Cline对话框中输入提示词:查一下订单为“ORDER-123456”的物流信息
Cline开始调用MCP Server,点击“Approve”同意
MCP Server调用成功
3.1 Cline连接MCP Server的相关Client源码
Cline(相当于MCP架构中的Host)源码中,MCP相关的代码在src/services/mcp/McpHub.ts
中,MCP Clinet连接MCP Server的代码在connectToServer
:
private async connectToServer(name: string, config: StdioServerParameters): Promise<void> {
...
try {
// 创建新的MCP客户端实例,设置客户端名称和版本信息
const client = new Client(
{
name: "Cline",
version: this.providerRef.deref()?.context.extension?.packageJSON?.version ?? "1.0.0",
},
{
capabilities: {}, // 客户端没有给服务端暴露能力
},
)
// 创建标准输入输出传输实例,配置命令、参数和环境变量
// 这个是我们配置文件的内容
const transport = new StdioClientTransport({
command: config.command,
args: config.args,
env: {
...config.env,
...(process.env.PATH ? { PATH: process.env.PATH } : {}),
},
stderr: "pipe",
})
......
// 启动传输层,建立实际的进程间通信通道
await transport.start()
...
// 建立MCP客户端连接
// 连接成功后更新服务器状态为已连接,清除错误信息
// 初始化并获取服务器提供的工具和资源列表
await client.connect(transport)
connection.server.status = "connected"
connection.server.error = ""
// 初始化获取工具资源列表
connection.server.tools = awaitthis.fetchToolsList(name)
connection.server.resources = awaitthis.fetchResourcesList(name)
connection.server.resourceTemplates = awaitthis.fetchResourceTemplatesList(name)
} catch (error) {
......
}
}
到目前为止我们实现了一个能提供Tool能力的MCP Server
开源MCP服务
1. glama 各种开源MCP服务
https://glama.ai/mcp/servers
2. cursor.directory 可以检索
https://cursor.directory/
3. http://mcp.so