📖 MCP 核心概念:掌握 AI 集成的模型上下文协议
模型上下文协议 (MCP) 是一个强大的标准化框架,用于优化大型语言模型 (LLM) 与外部工具、应用程序和数据源之间的通信。本指南经过 SEO 优化,将带您了解 MCP 的核心概念,确保您理解其客户端-服务器架构、基本组件、通信机制和最佳实践。
概述
本课程将探讨构成模型上下文协议 (MCP) 生态系统的基本架构和组件。您将了解支持 MCP 交互的客户端-服务器架构、关键组件和通信机制。
👩🎓 关键学习目标
在本课结束时,您将:
- 了解 MCP 客户端-服务器架构。
- 确定主机、客户端和服务器的角色和职责。
- 分析使 MCP 成为灵活集成层的核心特性。
- 了解信息如何在 MCP 生态系统内流动。
- 通过 .NET、Java、Python 和 JavaScript 中的代码示例获得实用见解。
🔎 MCP 架构:深入了解
MCP 生态系统基于客户端-服务器模型构建。这种模块化结构允许 AI 应用程序高效地与工具、数据库、API 和上下文资源进行交互。让我们将这个架构分解成其核心组件。
1. 主持人
在模型上下文协议 (MCP) 中,主机 (Host) 作为用户与协议交互的主要接口,发挥着至关重要的作用。主机是发起与 MCP 服务器连接以访问数据、工具和提示的应用程序或环境。主机的示例包括集成开发环境 (IDE)(例如 Visual Studio Code)、AI 工具(例如 Claude Desktop)或为特定任务设计的定制代理。
主机是发起连接的 LLM 应用程序。它们:
- 执行或与 AI 模型交互以生成响应。
- 发起与 MCP 服务器的连接。
- 管理对话流和用户界面。
- 控制权限和安全约束。
- 处理用户对数据共享和工具执行的同意。
2. 客户
客户端是促进主机与 MCP 服务器之间交互的重要组件。客户端充当中介,使主机能够访问并使用 MCP 服务器提供的功能。它们在确保 MCP 架构内顺畅通信和高效数据交换方面发挥着至关重要的作用。
客户端是主机应用程序中的连接器。它们:
- 向服务器发送带有提示/说明的请求。
- 与服务器协商功能。
- 管理来自模型的工具执行请求。
- 处理并向用户显示响应。
3. 服务器
服务器负责处理来自 MCP 客户端的请求并提供适当的响应。它们管理各种操作,例如数据检索、工具执行和提示生成。服务器确保客户端和主机之间的通信高效可靠,维护交互过程的完整性。
服务器是提供上下文和功能的服务。它们:
- 注册可用功能(资源、提示、工具)
- 接收并执行来自客户端的工具调用
- 提供上下文信息以增强模型响应
- 将输出返回给客户端
- 在需要时保持交互状态
任何人都可以开发服务器,以使用专门的功能扩展模型功能。
4.服务器功能
模型上下文协议 (MCP) 中的服务器提供了基础构建块,可实现客户端、主机和语言模型之间的丰富交互。这些功能旨在通过提供结构化的上下文、工具和提示来增强 MCP 的功能。
MCP 服务器可以提供以下任意功能:
📑 资源
模型上下文协议 (MCP) 中的资源包含可供用户或 AI 模型使用的各种类型的上下文和数据。这些包括:
- 上下文数据:用户或人工智能模型可以利用这些信息和上下文来进行决策和执行任务。
- 知识库和文档存储库:提供有价值的见解和信息的结构化和非结构化数据的集合,例如文章、手册和研究论文。
- 本地文件和数据库:本地存储在设备或数据库中的数据,可供处理和分析。
- API 和 Web 服务:提供额外数据和功能的外部接口和服务,实现与各种在线资源和工具的集成。
资源的示例可以是数据库模式或可以像这样访问的文件:
file://log.txt
database://schema
🤖 提示
模型上下文协议 (MCP) 中的提示包含各种预定义模板和交互模式,旨在简化用户工作流程并增强沟通。这些包括:
- 模板化消息和工作流程:预先构造的消息和流程,指导用户完成特定的任务和交互。
- 预定义的交互模式:标准化的动作和响应序列,有助于实现一致、有效的沟通。
- 专门的对话模板:针对特定类型的对话量身定制的模板,确保相关且符合上下文的互动。
提示模板如下所示:
Generate a product slogan based on the following {{product}} with the following {{keywords}}
⛏️ 工具
模型上下文协议 (MCP) 中的工具是 AI 模型可以执行特定任务的函数。这些工具旨在通过提供结构化且可靠的操作来增强 AI 模型的功能。关键方面包括:
- 供 AI 模型执行的函数:工具是 AI 模型可以调用来执行各种任务的可执行函数。
- 唯一的名称和描述:每个工具都有一个独特的名称和详细的描述,解释其目的和功能。
- 参数和输出:工具接受特定参数并返回结构化输出,确保一致且可预测的结果。
- 离散函数:工具执行离散功能,例如网络搜索、计算和数据库查询。
示例工具可能如下所示:
server.tool(
"GetProducts",
{
pageSize: z.string().optional(),
pageCount: z.string().optional()
}, () => {
// return results from API
}
)
客户端功能
在模型上下文协议 (MCP) 中,客户端向服务器提供了多项关键功能,增强了协议的整体功能和交互性。其中一项值得关注的功能就是采样。
👉 采样
- 服务器发起的代理行为:客户端使服务器能够自主发起特定的动作或行为,增强系统的动态能力。
- 递归 LLM 交互:此功能允许与大型语言模型 (LLM) 进行递归交互,从而实现更复杂和迭代的任务处理。
- 请求额外的模型完成:服务器可以向模型请求额外的完成,以确保响应是彻底的并且与上下文相关。
MCP 中的信息流
模型上下文协议 (MCP) 定义了主机、客户端、服务器和模型之间的结构化信息流。了解此流程有助于明确如何处理用户请求,以及如何将外部工具和数据集成到模型响应中。
-
主机发起连接
主机应用程序(例如 IDE 或聊天界面)与 MCP 服务器建立连接,通常通过 STDIO、WebSocket 或其他支持的传输方式。 -
功能协商:
客户端(嵌入在主机中)和服务器交换各自支持的功能、工具、资源和协议版本信息。这确保双方了解会话中可用的功能。 -
用户请求:
用户与主机交互(例如,输入提示或命令)。主机收集此输入并将其传递给客户端进行处理。 -
资源或工具使用
- 客户端可能会向服务器请求额外的上下文或资源(例如文件、数据库条目或知识库文章)以丰富模型的理解。
- 如果模型确定需要某个工具(例如,获取数据、执行计算或调用 API),客户端就会向服务器发送工具调用请求,指定工具名称和参数。
-
服务器执行
服务器接收资源或工具请求,执行必要的操作(例如运行函数、查询数据库或检索文件),并以结构化格式将结果返回给客户端。 -
响应生成:
客户端将服务器的响应(资源数据、工具输出等)集成到正在进行的模型交互中。模型将利用这些信息生成全面且与上下文相关的响应。 -
结果呈现
主机从客户端接收最终输出并将其呈现给用户,通常包括模型生成的文本以及工具执行或资源查找的任何结果。
通过将模型与外部工具和数据源无缝连接,该流程使 MCP 能够支持高级、交互式和情境感知的 AI 应用程序。
协议详细信息
MCP(模型上下文协议)建立在JSON-RPC 2.0之上,为主机、客户端和服务器之间的通信提供了一种标准化、与语言无关的消息格式。此基础可实现跨不同平台和编程语言的可靠、结构化且可扩展的交互。
协议主要特点
MCP 扩展了 JSON-RPC 2.0,增加了用于工具调用、资源访问和提示管理的附加约定。它支持多个传输层(STDIO、WebSocket、SSE),并支持组件间安全、可扩展且语言无关的通信。
🧢 基础协议
- JSON-RPC 消息格式:所有请求和响应均使用 JSON-RPC 2.0 规范,确保方法调用、参数、结果和错误处理的结构一致。
- 有状态连接:MCP 会话在多个请求之间保持状态,支持正在进行的对话、上下文积累和资源管理。
- 功能协商:在连接建立期间,客户端和服务器会交换有关支持的功能、协议版本、可用工具和资源的信息。这确保双方了解彼此的功能,并能够相应地进行调整。
➕ 附加实用程序
以下是 MCP 提供的一些附加实用程序和协议扩展,用于增强开发人员体验并实现高级场景:
- 配置选项:MCP 允许动态配置会话参数,例如工具权限、资源访问和模型设置,以适应每次交互。
- 进度跟踪:长时间运行的操作可以报告进度更新,从而实现响应式用户界面并在复杂任务期间提供更好的用户体验。
- 请求取消:客户端可以取消正在进行的请求,允许用户中断不再需要或耗时过长的操作。
- 错误报告:标准化的错误消息和代码有助于诊断问题、妥善处理故障并向用户和开发人员提供可操作的反馈。
- 日志记录:客户端和服务器都可以发出结构化日志,用于审计、调试和监控协议交互。
通过利用这些协议特性,MCP 确保语言模型与外部工具或数据源之间实现稳健、安全和灵活的通信。
🔐 安全注意事项
MCP 实施应遵循几个关键的安全原则,以确保安全可靠的交互:
- 用户同意与控制:在访问任何数据或执行任何操作之前,用户必须明确表示同意。用户应该能够明确控制哪些数据可以共享以及哪些操作可以授权,并通过直观的用户界面进行审核和批准。
- 数据隐私:用户数据应仅在获得明确同意的情况下公开,并必须受到适当的访问控制保护。MCP 实施必须防止未经授权的数据传输,并确保在所有交互过程中维护隐私。
- 工具安全:调用任何工具之前,都需要获得用户的明确同意。用户应清楚了解每个工具的功能,并且必须执行强大的安全边界,以防止意外或不安全的工具执行。
通过遵循这些原则,MCP 确保在所有协议交互中维护用户信任、隐私和安全。
代码示例:关键组件
以下是几种流行编程语言的代码示例,说明如何实现关键的 MCP 服务器组件和工具。
.NET 示例:使用工具创建简单的 MCP 服务器
这是一个实用的 .NET 代码示例,演示如何使用自定义工具实现一个简单的 MCP 服务器。此示例展示了如何定义和注册工具、处理请求以及如何使用模型上下文协议 (MCP) 连接服务器。
using System;
using System.Threading.Tasks;
using ModelContextProtocol.Server;
using ModelContextProtocol.Server.Transport;
using ModelContextProtocol.Server.Tools;
public class WeatherServer
{
public static async Task Main(string[] args)
{
// Create an MCP server
var server = new McpServer(
name: "Weather MCP Server",
version: "1.0.0"
);
// Register our custom weather tool
server.AddTool<string, WeatherData>("weatherTool",
description: "Gets current weather for a location",
execute: async (location) => {
// Call weather API (simplified)
var weatherData = await GetWeatherDataAsync(location);
return weatherData;
});
// Connect the server using stdio transport
var transport = new StdioServerTransport();
await server.ConnectAsync(transport);
Console.WriteLine("Weather MCP Server started");
// Keep the server running until process is terminated
await Task.Delay(-1);
}
private static async Task<WeatherData> GetWeatherDataAsync(string location)
{
// This would normally call a weather API
// Simplified for demonstration
await Task.Delay(100); // Simulate API call
return new WeatherData {
Temperature = 72.5,
Conditions = "Sunny",
Location = location
};
}
}
public class WeatherData
{
public double Temperature { get; set; }
public string Conditions { get; set; }
public string Location { get; set; }
}
Java 示例:MCP 服务器组件
此示例演示了与上面的 .NET 示例相同的 MCP 服务器和工具注册,但以 Java 实现。
import io.modelcontextprotocol.server.McpServer;
import io.modelcontextprotocol.server.McpToolDefinition;
import io.modelcontextprotocol.server.transport.StdioServerTransport;
import io.modelcontextprotocol.server.tool.ToolExecutionContext;
import io.modelcontextprotocol.server.tool.ToolResponse;
public class WeatherMcpServer {
public static void main(String[] args) throws Exception {
// Create an MCP server
McpServer server = McpServer.builder()
.name("Weather MCP Server")
.version("1.0.0")
.build();
// Register a weather tool
server.registerTool(McpToolDefinition.builder("weatherTool")
.description("Gets current weather for a location")
.parameter("location", String.class)
.execute((ToolExecutionContext ctx) -> {
String location = ctx.getParameter("location", String.class);
// Get weather data (simplified)
WeatherData data = getWeatherData(location);
// Return formatted response
return ToolResponse.content(
String.format("Temperature: %.1f°F, Conditions: %s, Location: %s",
data.getTemperature(),
data.getConditions(),
data.getLocation())
);
})
.build());
// Connect the server using stdio transport
try (StdioServerTransport transport = new StdioServerTransport()) {
server.connect(transport);
System.out.println("Weather MCP Server started");
// Keep server running until process is terminated
Thread.currentThread().join();
}
}
private static WeatherData getWeatherData(String location) {
// Implementation would call a weather API
// Simplified for example purposes
return new WeatherData(72.5, "Sunny", location);
}
}
class WeatherData {
private double temperature;
private String conditions;
private String location;
public WeatherData(double temperature, String conditions, String location) {
this.temperature = temperature;
this.conditions = conditions;
this.location = location;
}
public double getTemperature() {
return temperature;
}
public String getConditions() {
return conditions;
}
public String getLocation() {
return location;
}
}
Python 示例:构建 MCP 服务器
本例中,我们将演示如何使用 Python 构建 MCP 服务器。此外,我们还将向您展示两种创建工具的方法。
#!/usr/bin/env python3
import asyncio
from mcp.server.fastmcp import FastMCP
from mcp.server.transports.stdio import serve_stdio
# Create a FastMCP server
mcp = FastMCP(
name="Weather MCP Server",
version="1.0.0"
)
@mcp.tool()
def get_weather(location: str) -> dict:
"""Gets current weather for a location."""
# This would normally call a weather API
# Simplified for demonstration
return {
"temperature": 72.5,
"conditions": "Sunny",
"location": location
}
# Alternative approach using a class
class WeatherTools:
@mcp.tool()
def forecast(self, location: str, days: int = 1) -> dict:
"""Gets weather forecast for a location for the specified number of days."""
# This would normally call a weather API forecast endpoint
# Simplified for demonstration
return {
"location": location,
"forecast": [
{"day": i+1, "temperature": 70 + i, "conditions": "Partly Cloudy"}
for i in range(days)
]
}
# Instantiate the class to register its tools
weather_tools = WeatherTools()
# Start the server using stdio transport
if __name__ == "__main__":
asyncio.run(serve_stdio(mcp))
JavaScript 示例:创建 MCP 服务器
此示例展示了如何使用 JavaScript 创建 MCP 服务器以及如何注册两个与天气相关的工具。
// Using the official Model Context Protocol SDK
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod"; // For parameter validation
// Create an MCP server
const server = new McpServer({
name: "Weather MCP Server",
version: "1.0.0"
});
// Define a weather tool
server.tool(
"weatherTool",
{
location: z.string().describe("The location to get weather for")
},
async ({ location }) => {
// This would normally call a weather API
// Simplified for demonstration
const weatherData = await getWeatherData(location);
return {
content: [
{
type: "text",
text: `Temperature: ${weatherData.temperature}°F, Conditions: ${weatherData.conditions}, Location: ${weatherData.location}`
}
]
};
}
);
// Define a forecast tool
server.tool(
"forecastTool",
{
location: z.string(),
days: z.number().default(3).describe("Number of days for forecast")
},
async ({ location, days }) => {
// This would normally call a weather API
// Simplified for demonstration
const forecast = await getForecastData(location, days);
return {
content: [
{
type: "text",
text: `${days}-day forecast for ${location}: ${JSON.stringify(forecast)}`
}
]
};
}
);
// Helper functions
async function getWeatherData(location) {
// Simulate API call
return {
temperature: 72.5,
conditions: "Sunny",
location: location
};
}
async function getForecastData(location, days) {
// Simulate API call
return Array.from({ length: days }, (_, i) => ({
day: i + 1,
temperature: 70 + Math.floor(Math.random() * 10),
conditions: i % 2 === 0 ? "Sunny" : "Partly Cloudy"
}));
}
// Connect the server using stdio transport
const transport = new StdioServerTransport();
server.connect(transport).catch(console.error);
console.log("Weather MCP Server started");
此 JavaScript 示例演示了如何创建一个连接到服务器、发送提示并处理响应(包括所做的任何工具调用)的 MCP 客户端。
安全和授权
MCP 包含几个内置概念和机制,用于管理整个协议的安全性和授权:
- 工具权限控制:
客户端可以指定模型在会话期间可以使用的工具。这确保只有明确授权的工具才可访问,从而降低意外或不安全操作的风险。权限可以根据用户偏好、组织策略或交互上下文动态配置。 - 身份验证:
服务器在授予对工具、资源或敏感操作的访问权限之前,可能需要进行身份验证。这可能涉及 API 密钥、OAuth 令牌或其他身份验证方案。正确的身份验证可确保只有受信任的客户端和用户才能调用服务器端功能。 - 验证:
所有工具调用均强制执行参数验证。每个工具都定义其参数的预期类型、格式和约束,服务器会相应地验证传入的请求。这可以防止格式错误或恶意的输入到达工具实现,并有助于维护操作的完整性。 - 速率限制:
为了防止滥用并确保服务器资源的公平使用,MCP 服务器可以对工具调用和资源访问实施速率限制。速率限制可以按用户、按会话或全局应用,有助于防止拒绝服务攻击或过度资源消耗。
通过结合这些机制,MCP 为语言模型与外部工具和数据源的集成提供了安全的基础,同时为用户和开发人员提供了对访问和使用的细粒度控制。
协议消息
MCP 通信使用结构化的 JSON 消息,以促进客户端、服务器和模型之间清晰可靠的交互。主要消息类型包括:
-
客户端请求
由客户端发送到服务器,此消息通常包括:- 用户的提示或命令
- 对话历史记录
- 工具配置和权限
- 任何额外的元数据或会话信息
-
模型响应
由模型返回(通过客户端),该消息包含:- 根据提示和上下文生成文本或完成
- 如果模型确定应该调用某个工具,则可选工具调用指令
- 根据需要引用资源或附加背景信息
-
工具请求:
当需要执行工具时,客户端会向服务器发送此消息。此消息包含:- 要调用的工具的名称
- 工具所需的参数(根据工具的架构进行验证)
- 用于跟踪请求的上下文信息或标识符
-
工具响应
执行工具后由服务器返回。此消息提供:- 工具执行的结果(结构化数据或内容)
- 工具调用失败时的任何错误或状态信息
- 可选地,与执行相关的附加元数据或日志
这些结构化消息确保 MCP 工作流中的每个步骤都是明确的、可追踪的和可扩展的,支持多轮对话、工具链和强大的错误处理等高级场景。
关键要点
- MCP 使用客户端-服务器架构将模型与外部功能连接起来
- 生态系统由客户端、主机、服务器、工具和数据源组成
- 通信可以通过 STDIO、SSE 或 WebSockets 进行
- 工具是向模型公开的功能的基本单元
- 结构化的通信协议确保一致的交互
实践
设计一个简单的 MCP 工具,用于你的领域。定义:
- 该工具的名称
- 它会接受什么参数
- 它将返回什么输出
- 模型如何使用此工具来解决用户问题