深入解析 Model Context Protocol (MCP):无缝连接 LLM 与外部世界的开放协议

什么是 MCP?

Model Context Protocol (MCP) 是一个开放协议,旨在实现 LLM 应用与外部数据源和工具之间的无缝集成。无论您是构建 AI 驱动的 IDE、增强聊天界面,还是创建自定义 AI 工作流,MCP 都提供了一种标准化的方式来连接 LLM 与外部世界。

简单来说,MCP 是一种客户端-服务器架构的协议,允许 LLM 应用程序(如 Claude、各种 IDE 等)通过标准化的接口访问外部数据和功能。这解决了 LLM 在实际应用中常见的一些痛点:

  • LLM 无法直接访问实时数据(如天气、股票行情等)
  • LLM 无法执行外部操作(如发送邮件、控制设备等)
  • LLM 无法访问用户的本地文件或其他私有数据

通过 MCP,这些限制得到了优雅的解决,同时保持了安全性和可扩展性。

MCP 的核心架构

MCP 采用客户端-服务器架构,主要包含以下几个组件:

  • MCP 主机(Host):如 Claude Desktop、IDE 或其他 AI 工具,通过 MCP 访问数据
  • MCP 客户端(Client):与服务器保持 1:1 连接的协议客户端
  • MCP 服务器(Server):轻量级程序,通过标准化的 MCP 协议公开特定功能
  • 本地数据源:计算机上的文件、数据库和服务,MCP 服务器可以安全访问这些内容
  • 远程服务:通过互联网可用的外部系统(例如通过 API),MCP 服务器可以连接这些服务

主机可以同时连接多个服务器,每个服务器提供不同的功能,形成一个生态系统:

主机(Claude、IDE 等)<--MCP 协议--> 服务器 A <--> 本地数据源 A
                     <--MCP 协议--> 服务器 B <--> 本地数据源 B
                     <--MCP 协议--> 服务器 C <--> 远程服务 C

MCP 的核心概念

MCP 服务器可以提供三种主要类型的功能:

  1. 资源(Resources):客户端可以读取的文件类数据(如 API 响应或文件内容)
  2. 工具(Tools):LLM 可以调用的函数(需要用户批准)
  3. 提示(Prompts):帮助用户完成特定任务的预写模板

资源(Resources)

资源是可以被客户端读取的文件类数据。它们可以是文本或二进制形式,并有唯一的 URI 标识。资源可以是:

  • 直接资源:固定内容的资源
  • 资源模板:可以通过参数动态生成的资源

例如,一个文件系统 MCP 服务器可以将本地文件作为资源提供给 LLM,使其能够读取用户的文件。

工具(Tools)

工具是 MCP 中最强大的原语之一,允许服务器向客户端公开可执行的功能。通过工具,LLM 可以与外部系统交互,执行计算,并在现实世界中采取行动。

每个工具都有明确的定义,包括:

  • 名称
  • 描述
  • 输入参数模式(使用 JSON Schema)
  • 输出格式

工具设计为由模型控制,但通常需要人类批准才能执行,这保证了安全性。

提示(Prompts)

提示是预定义的模板,可以帮助用户完成特定任务。它们可以包含动态部分,嵌入资源上下文,并支持多步工作流。

MCP 服务器开发案例:天气服务器

让我们通过一个实际例子来理解 MCP 服务器的开发。我们将构建一个简单的天气服务器,它提供两个工具:获取天气警报和获取天气预报。

步骤 1:设置环境

# 创建项目目录
uv init weather
cd weather

# 创建虚拟环境并激活
uv venv
source .venv/bin/activate  # MacOS/Linux
# 或 .venv\Scripts\activate  # Windows

# 安装依赖
uv add "mcp[cli]" httpx

# 创建服务器文件
touch weather.py

步骤 2:实现天气服务器

from typing import Any
import httpx
from mcp.server.fastmcp import FastMCP

# 初始化 FastMCP 服务器
mcp = FastMCP("weather")

# 常量
NWS_API_BASE = "https://api.weather.gov"
USER_AGENT = "weather-app/1.0"

async def make_nws_request(url: str) -> dict[str, Any] | None:
    """向 NWS API 发送请求并进行适当的错误处理。"""
    headers = {
        "User-Agent": USER_AGENT,
        "Accept": "application/geo+json"
    }
    async with httpx.AsyncClient() as client:
        try:
            response = await client.get(url, headers=headers, timeout=30.0)
            response.raise_for_status()
            return response.json()
        except Exception:
            return None

def format_alert(feature: dict) -> str:
    """将警报特征格式化为可读字符串。"""
    props = feature["properties"]
    return f"""
Event: {props.get('event', 'Unknown')}
Area: {props.get('areaDesc', 'Unknown')}
Severity: {props.get('severity', 'Unknown')}
Description: {props.get('description', 'No description available')}
Instructions: {props.get('instruction', 'No specific instructions provided')}
"""

@mcp.tool()
async def get_alerts(state: str) -> str:
    """获取美国州的天气警报。

    Args:
        state: 美国州的两字母代码(例如 CA, NY)
    """
    url = f"{NWS_API_BASE}/alerts/active/area/{state}"
    data = await make_nws_request(url)

    if not data or "features" not in data:
        return "无法获取警报或未找到警报。"

    if not data["features"]:
        return "该州没有活跃警报。"

    alerts = [format_alert(feature) for feature in data["features"]]
    return "\n---\n".join(alerts)

@mcp.tool()
async def get_forecast(latitude: float, longitude: float) -> str:
    """获取某个位置的天气预报。

    Args:
        latitude: 位置的纬度
        longitude: 位置的经度
    """
    # 首先获取预报网格端点
    points_url = f"{NWS_API_BASE}/points/{latitude},{longitude}"
    points_data = await make_nws_request(points_url)

    if not points_data:
        return "无法获取该位置的预报数据。"

    # 从 points 响应获取预报 URL
    forecast_url = points_data["properties"]["forecast"]
    forecast_data = await make_nws_request(forecast_url)

    if not forecast_data:
        return "无法获取详细预报。"

    # 将周期格式化为可读的预报
    periods = forecast_data["properties"]["periods"]
    forecasts = []
    for period in periods[:5]:  # 仅显示接下来的 5 个周期
        forecast = f"""
{period['name']}:
Temperature: {period['temperature']}°{period['temperatureUnit']}
Wind: {period['windSpeed']} {period['windDirection']}
Forecast: {period['detailedForecast']}
"""
        forecasts.append(forecast)

    return "\n---\n".join(forecasts)

if __name__ == "__main__":
    # 初始化并运行服务器
    mcp.run(transport='stdio')

步骤 3:配置 Claude Desktop 连接服务器

要使用 Claude Desktop 连接到我们的服务器,需要编辑配置文件:

{
	"mcpServers": {
		"weather": {
			"command": "uv",
			"args": [
				"--directory",
				"/ABSOLUTE/PATH/TO/PARENT/FOLDER/weather",
				"run",
				"weather.py"
			]
		}
	}
}

此配置告诉 Claude Desktop 如何启动我们的天气服务器,并使 Claude 能够使用我们实现的工具。

MCP 客户端开发案例

接下来,让我们看看如何开发一个 MCP 客户端,该客户端可以连接到任何 MCP 服务器并利用其功能。

步骤 1:设置环境

点击深入解析 Model Context Protocol (MCP):无缝连接 LLM 与外部世界的开放协议查看全文。

### 关于 MCP (Model Context Protocol) 的连接管理深入讲解 MCPModel Context Protocol)是一种由 Anthropic 推出的协议,用于实现大型语言模型(LLM外部数据源和工具之间的无缝集成[^2]。该协议的核心目标之一是提供一种机制来管理和优化 LLM 其运行环境中的各种资源和服务之间的连接。 #### 连接管理的基础概念 在 MCP 中,连接管理涉及如何定义、建立以及维护 LLM外部系统的通信通道。这些连接通常被设计为轻量级且高效的接口,允许模型动态访问所需的数据或功能而无需重新加载整个上下文[^3]。这种灵活性对于处理实时更新的信息尤为重要。 #### 动态上下文切换的支持 为了支持多样的应用场景,MCP 提供了一种灵活的方式来进行动态上下文切换。这意味着当一个请求需要不同类型的背景信息时,可以通过调整当前会话所关联的具体资源集合来满足新的查询需求而不中断整体流程[^1]。例如,在软件开发场景下,如果最初讨论的是某个项目的文档结构,随后转向分析一段具体的代码片段,则系统应能平滑过渡至包含后者细节的新状态之中。 #### 安全性和权限控制措施 考虑到实际应用中可能涉及到敏感操作或者私人资料传输等问题,因此安全可靠的认证授权体系也是连接管理体系不可忽视的一部分内容。通过明确的能力声明(capabilities),每个参方仅限于获得必要的最小化许可范围内的活动权利,从而最大限度减少潜在风险隐患的发生概率。 ```python class ConnectionManager: def __init__(self, capabilities): self.capabilities = capabilities def establish_connection(self, resource_id): # 建立到指定资源的安全连接逻辑 pass def switch_context(self, new_resource_set): # 实现动态上下文切换的功能方法 pass ``` 上述代码展示了一个简单的 `ConnectionManager` 类的设计思路,其中包含了初始化能力声明属性的方法以及两个主要函数:一个是用来设置初始阶段所需的特定资源配置;另一个则是负责后续过程中可能出现的不同业务领域间转换的需求处理过程。 #### 性能考量因素 最后值得注意的一点是在大规模分布式环境下部署此类解决方案时还需要特别关注性能表现方面的要求。比如延迟时间是否可接受?吞吐率能否达到预期标准等等都是决定最终用户体验好坏的关键指标之一。 ---
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值