模型上下文协议(MCP)深度解析:规范、实践与示例
引言
模型上下文协议 (Model Context Protocol, MCP) 旨在为大型语言模型 (LLM) 应用与外部数据源和工具之间建立标准化的桥梁。本文将深入解析 MCP 的核心概念、生命周期、关键功能以及实用工具,结合最新的 2025-03-26
协议修订版本和具体的 JSON-RPC 请求/响应示例,为开发者提供一份全面的实践指南。
MCP 核心组件
MCP 由多个协同工作的关键组件构成:
- 基础协议: 定义核心的 JSON-RPC 消息类型。
- 生命周期管理: 控制连接初始化、能力协商和会话管理。
- 服务器功能: 服务器提供的特性,如资源 (Resources)、提示 (Prompts) 和工具 (Tools)。
- 客户端功能: 客户端提供的特性,如采样 (Sampling) 和根目录 (Roots)。
- 实用工具: 跨领域的功能,如日志 (Logging)、自动完成 (Completion)、进度跟踪 (Progress) 和取消 (Cancellation)。
所有实现 必须 (MUST) 支持基础协议和生命周期管理。其他组件可根据应用需求选择性实现。
基础协议:JSON-RPC 消息
MCP 完全基于 JSON-RPC 2.0 规范。
请求 (Requests)
用于启动操作。
{
"jsonrpc": "2.0",
"id": "req-1", // 必须是字符串或数字,不能是 null,且会话内唯一
"method": "methodName",
"params": { ... }
}
响应 (Responses)
请求的回复,包含结果或错误。
{
"jsonrpc": "2.0",
"id": "req-1", // 与请求 ID 相同
"result": { ... }, // 成功时设置
"error": { // 失败时设置
"code": -32600,
"message": "Error description",
"data": { ... }
}
}
响应中 result
和 error
必须 (MUST) 设置其一,且 不能 (MUST NOT) 同时设置。
通知 (Notifications)
单向消息,无需响应。
{
"jsonrpc": "2.0",
"method": "notificationName",
"params": { ... }
}
通知 不能 (MUST NOT) 包含 id
。
批处理 (Batching)
MCP 实现 可以 (MAY) 发送批处理请求/通知,但 必须 (MUST) 支持接收批处理。
生命周期管理
MCP 连接遵循严格的生命周期:初始化 -> 操作 -> 关闭。
初始化阶段
这是客户端和服务器之间的第一个交互,用于协商协议版本和交换能力。
初始化请求 (来自客户端)
{
"jsonrpc": "2.0",
"id": 1, // 初始化请求ID
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26", // 客户端支持的最新版本
"capabilities": { // 客户端声明的能力
"roots": { // 支持根目录功能
"listChanged": true // 支持根目录列表变化通知
},
"sampling": {} // 支持采样功能
},
"clientInfo": { // 客户端信息
"name": "mcp-example-client",
"version": "1.0.0"
}
}
}
注意: 初始化请求 不能 (MUST NOT) 包含在批处理中。
初始化响应 (来自服务器)
{
"jsonrpc": "2.0",
"id": 1, // 与请求 ID 相同
"result": {
"protocolVersion": "2025-03-26", // 服务器确认或选择的版本
"capabilities": { // 服务器声明的能力
"logging": {}, // 支持日志
"prompts": { // 支持提示
"listChanged": true // 支持提示列表变化通知
},
"resources": { // 支持资源
"subscribe": true, // 支持资源订阅
"listChanged": true // 支持资源列表变化通知
},
"tools": { // 支持工具
"listChanged": true // 支持工具列表变化通知
},
"completion": {} // 支持自动完成
},
"serverInfo": { // 服务器信息
"name": "mcp-example-server",
"version": "1.0.0"
},
"instructions": "Optional instructions for the client" // 可选的服务器指令
}
}
版本协商: 客户端发送其支持的最新版本。如果服务器支持,则返回相同版本;否则,返回服务器支持的最新版本。如果客户端不支持服务器返回的版本,应该 (SHOULD) 断开连接。
能力协商: 双方通过 capabilities
对象声明支持的特性及其子功能(如 listChanged
, subscribe
)。后续操作只能使用协商成功的能力。
初始化完成通知 (来自客户端)
在收到成功的 initialize
响应后,客户端 必须 (MUST) 发送此通知,表明已准备好进入操作阶段。
{
"jsonrpc": "2.0",
"method": "notifications/initialized"
}
在 initialize
响应之前,客户端不应发送除 ping
外的请求。在收到 initialized
通知之前,服务器不应发送除 ping
和 logging
外的请求。
操作阶段
双方根据协商的能力和协议版本进行正常的通信。
关闭阶段
通常由客户端发起,通过底层传输机制(如关闭 stdio 流或 HTTP 连接)来终止连接。没有特定的 MCP 关闭消息。
服务器功能详解
服务器可以暴露以下核心功能:
1. 资源 (Resources)
允许服务器共享上下文数据(文件、数据库模式等),每个资源由唯一的 URI 标识。
能力: resources
(可选 subscribe
, listChanged
)
列出资源 (resources/list
) (支持分页)
// 请求
{
"jsonrpc": "2.0",
"id": "res-list-1",
"method": "resources/list",
"params": { "cursor": "optional-cursor" }
}
// 响应
{
"jsonrpc": "2.0",
"id": "res-list-1",
"result": {
"resources": [
{
"uri": "file:///project/src/main.rs",
"name": "main.rs",
"description": "Primary application entry point",
"mimeType": "text/x-rust"
}
// ... 其他资源
],
"nextCursor": "next-page-cursor" // 如果有更多结果
}
}
读取资源 (resources/read
)
// 请求
{
"jsonrpc": "2.0",
"id": "res-read-1",
"method": "resources/read",
"params": { "uri": "file:///project/src/main.rs" }
}
// 响应 (文本)
{
"jsonrpc": "2.0",
"id": "res-read-1",
"result": {
"contents": [
{
"uri": "file:///project/src/main.rs",
"mimeType": "text/x-rust",
"text": "fn main() { ... }"
}
]
}
}
// 响应 (二进制)
{
"jsonrpc": "2.0",
"id": "res-read-2",
"result": {
"contents": [
{
"uri": "file:///project/logo.png",
"mimeType": "image/png",
"blob": "base64-encoded-data"
}
]
}
}
订阅资源变更 (resources/subscribe
) (需要 subscribe
能力)
// 请求
{
"jsonrpc": "2.0",
"id": "res-sub-1",
"method": "resources/subscribe",
"params": { "uri": "file:///project/src/main.rs" }
}
// 响应 (成功)
{
"jsonrpc": "2.0",
"id": "res-sub-1",
"result": {}
}
资源更新通知 (notifications/resources/updated
) (由服务器发送给订阅者)
{
"jsonrpc": "2.0",
"method": "notifications/resources/updated",
"params": { "uri": "file:///project/src/main.rs" }
}
客户端收到此通知后,通常会重新 resources/read
以获取最新内容。
资源列表变更通知 (notifications/resources/list_changed
) (需要 listChanged
能力)
{
"jsonrpc": "2.0",
"method": "notifications/resources/list_changed"
}
客户端收到此通知后,通常会重新 resources/list
。
资源模板: 服务器可以通过 resources/templates/list
暴露带参数的 URI 模板 (RFC6570)。
常见 URI Schemes: https://
, file://
, git://
(实现可自定义)。
2. 工具 (Tools)
允许语言模型调用服务器提供的外部功能(API、计算等)。
能力: tools
(可选 listChanged
)
列出工具 (tools/list
) (支持分页)
// 请求
{
"jsonrpc": "2.0",
"id": "tool-list-1",
"method": "tools/list"
}
// 响应
{
"jsonrpc": "2.0",
"id": "tool-list-1",
"result": {
"tools": [
{
"name": "get_weather",
"description": "Get current weather for a location",
"inputSchema": { /* JSON Schema for input */ },
"annotations": { /* 行为描述,如 isReadOnly, isDestructive */ }
}
// ... 其他工具
],
"nextCursor": "...
}
}
注意: 客户端 必须 (MUST) 将工具注解视为不可信,除非来自可信服务器。
调用工具 (tools/call
)
// 请求
{
"jsonrpc": "2.0",
"id": "tool-call-1",
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": { "location": "New York" }
}
}
// 响应 (成功)
{
"jsonrpc": "2.0",
"id": "tool-call-1",
"result": {
"content": [
{ "type": "text", "text": "Weather in NY: ..." }
// 可以包含 text, image, audio, resource
],
"isError": false
}
}
// 响应 (工具执行错误)
{
"jsonrpc": "2.0",
"id": "tool-call-2",
"result": {
"content": [
{ "type": "text", "text": "API rate limit exceeded" }
],
"isError": true
}
}
工具列表变更通知 (notifications/tools/list_changed
) (需要 listChanged
能力)
{
"jsonrpc": "2.0",
"method": "notifications/tools/list_changed"
}
安全: 客户端 应该 (SHOULD) 在敏感操作前提示用户确认,并展示工具输入以防数据泄露。
3. 提示 (Prompts)
服务器提供结构化的消息模板,供用户显式选择以与 LLM 交互。
能力: prompts
(可选 listChanged
)
列出提示 (prompts/list
) (支持分页)
// 请求
{
"jsonrpc": "2.0",
"id": "prompt-list-1",
"method": "prompts/list"
}
// 响应
{
"jsonrpc": "2.0",
"id": "prompt-list-1",
"result": {
"prompts": [
{
"name": "code_review",
"description": "Review code quality",
"arguments": [ { "name": "code", ... } ]
}
// ... 其他提示
],
"nextCursor": "...
}
}
获取提示 (prompts/get
)
// 请求
{
"jsonrpc": "2.0",
"id": "prompt-get-1",
"method": "prompts/get",
"params": {
"name": "code_review",
"arguments": { "code": "..." }
}
}
// 响应
{
"jsonrpc": "2.0",
"id": "prompt-get-1",
"result": {
"description": "Code review prompt",
"messages": [
{
"role": "user", // 或 "assistant"
"content": {
"type": "text", // 或 image, audio, resource
"text": "Please review: ..."
}
}
// ... 其他消息
]
}
}
提示列表变更通知 (notifications/prompts/list_changed
) (需要 listChanged
能力)
{
"jsonrpc": "2.0",
"method": "notifications/prompts/list_changed"
}
客户端功能详解
客户端可以暴露以下核心功能:
1. 根目录 (Roots)
允许客户端向服务器暴露文件系统访问的边界。
能力: roots
(可选 listChanged
)
列出根目录 (roots/list
) (由服务器请求)
// 请求
{
"jsonrpc": "2.0",
"id": "roots-list-1",
"method": "roots/list"
}
// 响应
{
"jsonrpc": "2.0",
"id": "roots-list-1",
"result": {
"roots": [
{
"uri": "file:///home/user/projects/myproject",
"name": "My Project"
}
// ... 其他根目录
]
}
}
根目录列表变更通知 (notifications/roots/list_changed
) (由客户端发送,需要 listChanged
能力)
{
"jsonrpc": "2.0",
"method": "notifications/roots/list_changed"
}
2. 采样 (Sampling)
允许服务器请求客户端通过 LLM 生成内容(文本、图像、音频)。客户端控制模型访问和选择。
能力: sampling
创建消息 (sampling/createMessage
) (由服务器请求)
// 请求
{
"jsonrpc": "2.0",
"id": "sampling-1",
"method": "sampling/createMessage",
"params": {
"messages": [
{
"role": "user",
"content": { "type": "text", "text": "Capital of France?" }
}
// 可以包含 text, image, audio 内容
],
"modelPreferences": { // 客户端如何选择模型
"hints": [ { "name": "claude-3-sonnet" } ], // 建议的模型 (可选,客户端决定)
"intelligencePriority": 0.8, // 0-1
"speedPriority": 0.5, // 0-1
"costPriority": 0.3 // 0-1
},
"systemPrompt": "You are helpful.", // 可选
"maxTokens": 100 // 可选
// ... 其他 LLM 参数
}
}
// 响应
{
"jsonrpc": "2.0",
"id": "sampling-1",
"result": {
"role": "assistant",
"content": { "type": "text", "text": "Paris." },
"model": "claude-3-sonnet-20240307", // 实际使用的模型
"stopReason": "endTurn" // 或其他停止原因
}
}
安全: 客户端 应该 (SHOULD) 实现用户批准流程,允许用户在发送前审查和编辑提示。
实用工具
MCP 提供了一系列可选的辅助功能:
Ping
用于检测连接是否存活。
// 请求 (双向)
{
"jsonrpc": "2.0",
"id": "ping-1",
"method": "ping"
}
// 响应
{
"jsonrpc": "2.0",
"id": "ping-1",
"result": {}
}
进度 (Progress)
用于报告长时间运行的操作进度。
请求时携带 progressToken
: 发送方(如客户端)在请求的 _meta
中包含一个唯一的 progressToken
。
// 请求 (例如 tool/call)
{
"jsonrpc": "2.0",
"id": "long-op-1",
"method": "tools/call",
"params": {
"name": "run_analysis",
"arguments": { ... },
"_meta": {
"progressToken": "analysis-job-123"
}
}
}
进度通知 (notifications/progress
): 接收方(如服务器)发送进度更新。
{
"jsonrpc": "2.0",
"method": "notifications/progress",
"params": {
"progressToken": "analysis-job-123",
"progress": 50, // 当前进度值
"total": 100, // 总量 (可选)
"message": "Processing data..." // 描述信息 (可选)
}
}
日志 (Logging)
允许服务器向客户端发送结构化日志。
能力: logging
设置日志级别 (logging/setLevel
): 客户端可以设置服务器应发送的最低日志级别 (debug, info, notice, warning, error, critical, alert, emergency)。
// 请求
{
"jsonrpc": "2.0",
"id": "log-level-1",
"method": "logging/setLevel",
"params": { "level": "info" }
}
日志消息通知 (notifications/message
): 服务器发送日志。
{
"jsonrpc": "2.0",
"method": "notifications/message",
"params": {
"level": "error",
"logger": "database", // 可选的日志记录器名称
"data": { // 任意 JSON 数据
"error": "Connection failed",
"details": { "host": "..." }
}
}
}
取消 (Cancellation)
允许一方请求取消先前发送的、仍在进行中的请求。
取消通知 (notifications/cancelled
): 发送方发出。
{
"jsonrpc": "2.0",
"method": "notifications/cancelled",
"params": {
"requestId": "long-op-1", // 要取消的请求 ID
"reason": "User requested cancellation" // 可选原因
}
}
接收方 应该 (SHOULD) 停止处理被取消的请求,并且 不应 (SHOULD NOT) 为其发送响应。发送方 应该 (SHOULD) 忽略之后可能收到的对已取消请求的响应。
自动完成 (Completion)
服务器为提示参数或资源 URI 提供自动完成建议。
能力: completions
请求自动完成 (completion/complete
)
// 请求 (为提示参数 'language' 获取建议)
{
"jsonrpc": "2.0",
"id": "complete-1",
"method": "completion/complete",
"params": {
"ref": { "type": "ref/prompt", "name": "code_review" },
"argument": { "name": "language", "value": "py" }
}
}
// 响应
{
"jsonrpc": "2.0",
"id": "complete-1",
"result": {
"completion": {
"values": ["python", "pytorch"], // 建议列表 (最多100)
"total": 5, // 可选的总匹配数
"hasMore": true // 是否还有更多结果
}
}
}
分页 (Pagination)
对于可能返回大量结果的列表操作(resources/list
, tools/list
, prompts/list
, resources/templates/list
),MCP 使用基于光标的分页。
服务器响应: 在结果中包含 nextCursor
(如果不为空,表示有更多页)。
{
"jsonrpc": "2.0",
"id": "list-page-1",
"result": {
"items": [...], // 当前页结果
"nextCursor": "opaque-cursor-string"
}
}
客户端请求下一页: 在请求的 params
中包含收到的 cursor
。
{
"jsonrpc": "2.0",
"id": "list-page-2",
"method": "resources/list",
"params": {
"cursor": "opaque-cursor-string"
}
}
客户端 必须 (MUST) 将光标视为不透明字符串。
错误处理
MCP 使用标准的 JSON-RPC 错误代码。
- -32600 Invalid Request: 无效的 JSON 或不符合规范。
- -32601 Method not found: 方法不存在或不可用。
- -32602 Invalid params: 无效的方法参数。
- -32603 Internal error: 服务器内部错误。
- -32000 to -32099 Server error: 特定于实现的服务器错误 (例如,
-32002
用于资源未找到)。
// 示例:资源未找到
{
"jsonrpc": "2.0",
"id": "read-error-1",
"error": {
"code": -32002,
"message": "Resource not found",
"data": { "uri": "file:///nonexistent.txt" }
}
}
安全与信任
MCP 实现者 必须 (MUST) 仔细考虑安全和信任问题:
- 用户同意与控制: 所有数据访问和操作都需要用户明确同意。
- 数据隐私: 未经同意不得共享用户数据。
- 工具安全: 工具调用代表代码执行,需谨慎处理,并获得用户同意。
- 采样控制: 用户应能控制采样请求和审查结果。
- 验证: 客户端和服务器都必须验证输入和输出。
- 权限: 实施适当的访问控制。
结语
模型上下文协议 (MCP) 通过其标准化的消息、生命周期管理和丰富的功能集,为构建强大、安全且可互操作的 AI 应用提供了坚实的基础。理解其核心概念和协议细节,并结合具体的请求/响应示例,将有助于开发者有效地利用 MCP 连接 LLM 与外部世界。
参考资料: