模型上下文协议(MCP)概述
模型上下文协议(MCP)概述
1. 核心概念
模型上下文协议(MCP) 是由 Anthropic 推出的开源协议,旨在实现大型语言模型(LLM)与外部数据源和工具的无缝集成。它在 LLM 和数据源之间建立安全、双向的连接,目标是成为 AI 领域的“HTTP 协议”,推动 LLM 应用的标准化和去中心化。
可以将 MCP 比作 AI 的 USB-C 接口:正如 USB-C 为设备提供了一种通用的连接方式,MCP 也为 AI 模型与各种数据源和工具的连接提供了一个标准化的框架。
1.1 架构
MCP 采用客户端-服务器架构,具体如下:
- 主机:发起连接的 LLM 应用程序(例如桌面版 Claude 或其他 AI 工具)。
- 客户端:位于主机应用程序内部,与服务器保持一对一连接,负责协议通信。
- 服务器:为客户端提供上下文、工具和提示。MCP 服务器通过自身控制资源,避免将 API 密钥共享给主机,从而提高安全性。
1.2 资源
MCP 中的资源指服务器向客户端提供的任何类型的数据,例如文件内容、数据库记录、API 响应、实时系统数据、截图、图片或日志等。每个资源由唯一的 URI 标识,可包含文本或二进制数据。
{
uri: string; // 资源的唯一标识符
name: string; // 可读名称
description?: string; // 可选描述
mimeType?: string; // 可选 MIME 类型
}
1.3 提示
MCP 中的提示是预定义的模板,支持动态参数、上下文数据、链式交互以及特定工作流程。提示还可作为用户界面元素(如斜杠命令)呈现。
{
name: string; // 提示的唯一标识符
description?: string; // 可读描述
arguments?: [ // 可选参数列表
{
name: string; // 参数标识符
description?: string; // 参数描述
required?: boolean; // 参数是否为必填
}
]
}
1.4 工具
MCP 中的工具是服务器公开的可执行函数,客户端可调用,LLM 可利用这些函数执行操作。其关键特性包括:
- 发现:客户端通过
tools/list
端点列出可用工具。 - 调用:通过
tools/call
端点调用工具,服务器执行请求的操作并返回结果。 - 灵活性:工具功能从简单计算到复杂 API 交互不等。
与资源类似,工具由唯一名称标识,并可包含使用说明。不同的是,工具支持动态操作,可修改状态或与外部系统交互。
{
name: string; // 工具的唯一标识符
description?: string; // 可读描述
inputSchema: { // 工具参数的 JSON Schema
type: "object",
properties: { ... } // 工具特定参数
}
}
1.5 采样
采样是 MCP 的一项强大功能,允许服务器通过客户端请求 LLM 完成任务,从而实现复杂的代理行为,同时确保安全性和隐私性。其人机交互设计保证用户能够控制 LLM 的输入和输出内容。采样流程如下:
- 服务器通过
sampling/createMessage
发送请求。 - 客户端审核并可修改请求。
- 客户端从 LLM 采样。
- 客户端检查完成结果。
- 客户端将结果返回给服务器。
{
messages: [
{
role: "user" | "assistant",
content: {
type: "text" | "image",
text?: string, // 文本内容
data?: string, // 图片的 base64 编码
mimeType?: string
}
}
],
modelPreferences?: {
hints?: [{
name?: string // 建议的模型名称/系列
}],
costPriority?: number, // 0-1,降低成本的重要性
speedPriority?: number, // 0-1,低延迟的重要性
intelligencePriority?: number // 0-1,模型能力的重要性
},
systemPrompt?: string,
includeContext?: "none" | "thisServer" | "allServers",
temperature?: number,
maxTokens: number,
stopSequences?: string[],
metadata?: Record<string, unknown>
}
2. 目标与优势
由于 LLM 难以直接访问实时数据源(如企业内部数据库、实时文档或在线服务),开发者通常需要为每个应用场景定制适配器或插件,这既耗时又缺乏扩展性。
- 标准化:MCP 通过定义通用协议,使开发者无需重复开发即可快速连接模型与数据源,降低连接复杂性,提高模型的通用性和落地效率。
- 灵活性:MCP 支持 LLM 与多样化数据和工具的直接集成,确保模型切换的灵活性。
- 开放性:作为开放协议,MCP 允许开发者为其产品创建兼容服务器,促进类似 HTTP 和 REST API 的网络效应,推动模型与应用场景的融合。
- 安全性:MCP 内置严格的权限控制机制,数据源所有者始终掌握访问权限。模型需经过明确授权才能访问数据,避免数据泄露或滥用。
3. 工具示例
MCP 工具调用流程如下:
- 用户提交问题。
- LLM 分析可用工具。
- 客户端通过 MCP 服务器执行选定的工具。
- 服务器将结果返回给 LLM。
- LLM 根据工具结果和用户问题生成回答。
此流程类似于检索增强生成(RAG),但用工具调用替代了检索步骤。以下是两个示例:一个为特定用例定制,另一个来自官方 GitHub 仓库。
3.1 构建获取《流放之路 2》最新版本的工具
由于 RAG 通常无法获取实时信息,我们基于官网流程开发了一个结合网页爬虫的 MCP 工具,用于获取《流放之路 2》的最新更新。
客户端实现:
- 导入
FastMCP
类以动态生成工具定义,并指定目标 URL(《流放之路 2》论坛)。
from typing import Any
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("Path of Exile 2 hotfix")
target_url = "https://www.pathofexile.com/forum/view-forum/2212"
- 定义核心功能函数
poe2_hotfix
,用于爬取目标 URL。
async def poe2_hotfix(url: str):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'
}
async with httpx.AsyncClient() as client:
try:
response = await client.get(url, headers=headers, timeout=30.0)
soup = BeautifulSoup(response.text, 'html.parser')
table = soup.find('table')
result_text = ""
if table:
for row in table.find_all('tr'):
cells = row.find_all('td')
if cells:
for cell in cells:
result_text += cell.get_text(strip=True) + '\n'
result_text += '-' * 50 + '\n'
else:
print('未找到表格元素')
return result_text
except Exception:
return None
- 在 MCP 类中注册工具函数。
@mcp.tool()
async def find_poe2_hotfix() -> str:
hotfix_data = await poe2_hotfix(target_url)
if not hotfix_data:
return "无法找到官方补丁信息"
return hotfix_data
- 初始化并运行服务器。
if __name__ == "__main__":
mcp.run(transport='stdio')
- 使用 MCP 主机测试工具,参考官方客户端构建指南(或通过将服务器添加到主机密钥与桌面版 Claude 集成)。
客户端开发者快速入门指南:https://modelcontextprotocol.io/quickstart/client
包括客户端初始化、服务器连接、查询处理、交互式界面和资源管理。
- 测试:
安装 MCP 依赖并使用 MCP Inspector 进行测试:
pip install mcp
mcp dev server.py
工具将在 MCP Inspector 的工具页面中显示,运行后可查看返回结果。
- 效果展示:
通过命令行将客户端连接到工具:
uv run client.py poe2hotfix.py
当询问最新补丁时,LLM 能准确提供《流放之路 2》的补丁版本和时间戳。对于无关问题,LLM 会拒绝回答。
- 未来优化:
改进提示并添加更多工具,例如使用更高效的爬虫或深度爬取补丁帖子,以在返回版本号的同时提供详细内容。
3.2 构建简单聊天机器人(官方示例)
完整代码见:https://github.com/modelcontextprotocol/python-sdk/tree/main/examples/clients/simple-chatbot
逻辑流程:
- 工具集成:
- 从 MCP 服务器动态发现工具。
- 将工具描述自动纳入系统提示。
- 通过标准化 MCP 协议处理工具执行。
- 运行时流程:
- 接收用户输入。
- 将输入和工具上下文发送给 LLM。
- 解析 LLM 响应:
- 若为工具调用,执行工具并返回结果。
- 若为直接响应,显示给用户。
- 将工具结果返回给 LLM 进行解释。
- 向用户呈现最终响应。
服务器端工具发现:
all_tools = []
for server in self.servers:
tools = await server.list_tools()
all_tools.extend(tools)
工具函数定义:
def format_for_llm(self) -> str:
"""格式化工具信息供 LLM 使用。"""
args_desc = []
if "properties" in self.input_schema:
for param_name, param_info in self.input_schema["properties"].items():
arg_desc = f"- {param_name}: {param_info.get('description', '无描述')}"
if param_name in self.input_schema.get("required", []):
arg_desc += "(必填)"
args_desc.append(arg_desc)
return f"""
工具: {self.name}
描述: {self.description}
参数:
{chr(10).join(args_desc)}
"""
聊天机器人提示:
system_message = (
"你是一个有用的助手,可使用以下工具:\n\n"
f"{tools_description}\n"
"根据用户的问题选择合适的工具。"
"若无需工具,直接回复。\n\n"
"重要提示:当需要使用工具时,仅返回以下精确 JSON 格式,不包含其他内容:\n"
"{\n"
' "tool": "工具名称",\n'
' "arguments": {\n'
' "参数名称": "值"\n'
" }\n"
"}\n\n"
"收到工具响应后:\n"
"1. 将原始数据转化为自然、对话式的回答\n"
"2. 保持回答简洁但信息丰富\n"
"3. 聚焦最相关信息\n"
"4. 结合用户问题提供适当上下文\n"
"5. 避免直接重复原始数据\n\n"
"请仅使用上述明确定义的工具。"
)