模型上下文协议(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 的输入和输出内容。采样流程如下:

  1. 服务器通过 sampling/createMessage 发送请求。
  2. 客户端审核并可修改请求。
  3. 客户端从 LLM 采样。
  4. 客户端检查完成结果。
  5. 客户端将结果返回给服务器。
{
  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 工具调用流程如下:

  1. 用户提交问题。
  2. LLM 分析可用工具。
  3. 客户端通过 MCP 服务器执行选定的工具。
  4. 服务器将结果返回给 LLM。
  5. LLM 根据工具结果和用户问题生成回答。

此流程类似于检索增强生成(RAG),但用工具调用替代了检索步骤。以下是两个示例:一个为特定用例定制,另一个来自官方 GitHub 仓库。

3.1 构建获取《流放之路 2》最新版本的工具

由于 RAG 通常无法获取实时信息,我们基于官网流程开发了一个结合网页爬虫的 MCP 工具,用于获取《流放之路 2》的最新更新。

客户端实现:

  1. 导入 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"
  1. 定义核心功能函数 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
  1. 在 MCP 类中注册工具函数。
@mcp.tool()
async def find_poe2_hotfix() -> str:
    hotfix_data = await poe2_hotfix(target_url)
    if not hotfix_data:
        return "无法找到官方补丁信息"
    return hotfix_data
  1. 初始化并运行服务器。
if __name__ == "__main__":
    mcp.run(transport='stdio')
  1. 使用 MCP 主机测试工具,参考官方客户端构建指南(或通过将服务器添加到主机密钥与桌面版 Claude 集成)。

客户端开发者快速入门指南https://modelcontextprotocol.io/quickstart/client

包括客户端初始化、服务器连接、查询处理、交互式界面和资源管理。

  1. 测试
    安装 MCP 依赖并使用 MCP Inspector 进行测试:
pip install mcp
mcp dev server.py

工具将在 MCP Inspector 的工具页面中显示,运行后可查看返回结果。

  1. 效果展示
    通过命令行将客户端连接到工具:
uv run client.py poe2hotfix.py

当询问最新补丁时,LLM 能准确提供《流放之路 2》的补丁版本和时间戳。对于无关问题,LLM 会拒绝回答。

  1. 未来优化
    改进提示并添加更多工具,例如使用更高效的爬虫或深度爬取补丁帖子,以在返回版本号的同时提供详细内容。

3.2 构建简单聊天机器人(官方示例)

完整代码见:https://github.com/modelcontextprotocol/python-sdk/tree/main/examples/clients/simple-chatbot

逻辑流程:

  1. 工具集成
    • 从 MCP 服务器动态发现工具。
    • 将工具描述自动纳入系统提示。
    • 通过标准化 MCP 协议处理工具执行。
  2. 运行时流程
    • 接收用户输入。
    • 将输入和工具上下文发送给 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"
    "请仅使用上述明确定义的工具。"
)