MCP 协议深度解析
Model Context Protocol 架构、MCP Server / Client 通信协议、Tool / Resource / Prompt 三大原语
MCP 协议背景
随着大型语言模型(LLM)能力的不断提升,如何让模型与外部工具、数据源进行有效交互成为关键挑战。2024 年,Anthropic 提出了 Model Context Protocol(MCP),旨在为 LLM 应用程序提供一个标准化的工具集成协议。
在 MCP 出现之前,每个 LLM 应用都需要自定义工具调用接口:有的使用 Function Calling,有的直接注入 Prompt,有的自行封装 HTTP 服务。这种碎片化的集成方式导致开发成本高、复用性差。MCP 的诞生正是为了解决这一问题——它定义了一套通用的协议规范,让 LLM 应用能够以统一的方式发现、调用和管理外部工具与资源。
可以将 MCP 类比为 HTTP 协议在 Web 领域的角色。HTTP 标准化了浏览器与服务器之间的通信方式,而 MCP 则标准化了 LLM 应用与工具服务之间的通信方式。正如 HTTP 催生了整个互联网生态,MCP 有望成为 AI 工具集成领域的通用底层协议,推动 AI 应用生态的快速发展。
架构概览
MCP 采用经典的三层客户端-服务器架构:
MCP Host (客户端应用)
|
v
MCP Client (协议客户端)
|
v
MCP Server (工具服务端)MCP Host 是用户直接交互的客户端应用,如 Cline、Cursor、Trae 等 IDE 插件或 AI 聊天界面。Host 负责承载用户会话,并在需要时触发工具调用。
MCP Client 是协议层的核心实现,作为 Host 与 Server 之间的通信桥梁。它负责建立连接、发送请求、接收响应,并管理连接生命周期。一个 Host 可以同时连接多个 MCP Client。
MCP Server 是实际提供工具能力的一端。它暴露具体的 Tool、Resource 或 Prompt 供客户端调用。Server 可以是本地进程(如 Python 脚本),也可以是远程服务(如云端的 API 网关)。
这种三层架构的核心理念是关注点分离:Host 专注于用户体验,Server 专注于工具实现,Client 负责协议通信。这使得两端可以独立演进,任何遵循 MCP 协议的 Server 都可以接入任何兼容的 Host。
MCP Server / Client 通信协议
传输层
MCP 定义了两类标准传输方式:
| 传输方式 | 适用场景 | 特点 |
|---|---|---|
| stdio | 本地进程通信 | 基于标准输入/输出,启动快,延迟低,适合本地开发工具 |
| SSE | 远程通信 | 基于 Server-Sent Events,支持跨网络调用,适合云端服务 |
stdio 模式:Host 以子进程方式启动 MCP Server,通过进程的标准输入流发送请求,从标准输出流读取响应。这种模式延迟极低,适合 IDE 等需要实时响应的场景。
SSE 模式:MCP Server 作为 HTTP 服务运行,客户端通过 HTTP POST 发送请求,通过 SSE 连接接收服务端的推送消息。这种模式支持远程部署和水平扩展。
JSON-RPC 2.0 消息格式
MCP 的消息层基于 JSON-RPC 2.0 协议,所有通信都以结构化的 JSON 消息进行。核心消息格式包括三种:
请求(Request):
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": {
"city": "Beijing"
}
}
}响应(Response):
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "北京当前温度:25°C,晴"
}
]
}
}通知(Notification):
{
"jsonrpc": "2.0",
"method": "notifications/initialized",
"params": {}
}通知不需要 id 字段,服务端无需返回响应。
生命周期
MCP 连接的完整生命周期分为四个阶段:
Initialize(初始化):客户端发送
initialize请求,携带协议版本和客户端能力信息。服务端返回其支持的协议版本、服务器能力及 Server 信息。双方在此阶段完成能力协商。Ready(就绪):初始化完成后,客户端发送
notifications/initialized通知,表示已准备就绪。此时连接进入可用状态,双方可以开始正常的消息交换。Operation(运行):这是连接的主要工作阶段。客户端可以发送
tools/call、resources/read、prompts/get等请求,服务端返回相应的结果。双方还可以互发各类通知消息。Shutdown(关闭):当对话结束或 Host 关闭时,连接被销毁。对于 stdio 模式,通常通过终止子进程来关闭;对于 SSE 模式,通过断开 HTTP 连接来关闭。
三大原语
MCP 定义了三种核心原语,构成了协议的功能基础:
Tool(工具)
Tool 是 MCP 中最核心的原语,它让 LLM 能够执行外部操作。每个 Tool 包含:
- name:工具的唯一标识名称
- description:工具功能的自然语言描述,供 LLM 理解何时调用
- inputSchema:工具参数的 JSON Schema 定义,描述参数的类型、格式和约束
工具定义示例:
{
"name": "search_codebase",
"description": "在代码库中搜索指定的关键字或模式",
"inputSchema": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "搜索关键字"
},
"path": {
"type": "string",
"description": "限定搜索路径(可选)"
}
},
"required": ["query"]
}
}工具调用流程:LLM 根据用户请求决定调用某个 Tool → 客户端发送 tools/call 请求 → Server 执行对应逻辑 → 返回 CallToolResult 响应。
Resource(资源)
Resource 原语允许 MCP Server 向客户端暴露数据资源,支持以统一的方式读取文件、数据库查询结果、API 响应等内容。
- 资源通过 URI 模式 进行标识和定位,例如
file:///path/to/file、db:///users/123、api:///weather/beijing - 客户端通过
resources/read请求读取资源内容 - 服务端可通过
resources/list返回可用资源列表
资源读取示例:
{
"method": "resources/read",
"params": {
"uri": "file:///projects/myapp/config.json"
}
}Prompt(提示模板)
Prompt 原语让 MCP Server 可以定义和管理可复用的提示模板。这对于提供领域特定的 Prompt 模板非常有用。
- 模板可以包含动态参数,支持在调用时注入具体值
- 客户端通过
prompts/get请求获取渲染后的 Prompt 内容 - 服务端可通过
prompts/list返回可用 Prompt 列表
原语对比
| 维度 | Tool(工具) | Resource(资源) | Prompt(提示模板) |
|---|---|---|---|
| 核心作用 | 执行操作/动作 | 提供数据/内容 | 提供提示模板 |
| 调用方式 | tools/call | resources/read | prompts/get |
| 典型用途 | 搜索代码、读写文件、调用 API | 读取配置文件、查询数据库 | 代码审查模板、问答模板 |
| 有无副作用 | 有(执行操作) | 无(只读) | 无(只读) |
| 参数机制 | JSON Schema 定义参数 | URI 定位资源 | 模板变量替换 |
| 返回内容 | CallToolResult | ResourceContents | PromptMessage |
实际应用场景
IDE 中集成 MCP
现代化 AI 编程工具广泛采用 MCP 协议。以 Cline、Cursor 和 Trae 为代表的 IDE 插件通过 MCP 接入各类工具:
- 代码搜索工具:在大型代码库中快速定位相关代码
- 文件操作工具:读取、创建、修改项目文件
- 终端命令工具:在 IDE 内执行编译、测试等命令
- Web 抓取工具:获取文档或网页内容辅助开发
IDE 通常以 stdio 模式启动 MCP Server,以获得最低延迟的本地通信体验。每个插件可以同时管理多个 MCP Server,每个 Server 提供一组特定的工具能力。
自动化工作流
MCP 也可用于构建自动化工作流。例如,一个 CI/CD Pipeline 中的 MCP Server 可以暴露构建、测试、部署等工具,LLM Agent 根据任务描述自动编排和执行这些工具,实现端到端的自动化。
代码示例
Python MCP Server 实现
以下是一个简单的 MCP Server 示例,提供一个天气查询工具:
import json
import sys
from typing import Any
def handle_request(request: dict) -> dict:
"""处理 MCP 请求"""
method = request.get("method")
req_id = request.get("id")
if method == "initialize":
return {
"jsonrpc": "2.0",
"id": req_id,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {
"tools": {}
},
"serverInfo": {
"name": "simple-weather-server",
"version": "1.0.0"
}
}
}
elif method == "tools/list":
return {
"jsonrpc": "2.0",
"id": req_id,
"result": {
"tools": [
{
"name": "get_weather",
"description": "获取指定城市的当前天气信息",
"inputSchema": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称"
}
},
"required": ["city"]
}
}
]
}
}
elif method == "tools/call":
params = request.get("params", {})
tool_name = params.get("name")
args = params.get("arguments", {})
if tool_name == "get_weather":
city = args.get("city", "未知")
# 实际项目中在此调用天气 API
weather_info = f"{city}:晴,温度 22°C,湿度 45%"
return {
"jsonrpc": "2.0",
"id": req_id,
"result": {
"content": [
{"type": "text", "text": weather_info}
]
}
}
return {
"jsonrpc": "2.0",
"id": req_id,
"error": {"code": -32601, "message": "Method not found"}
}
def main():
"""通过 stdio 运行 MCP Server"""
for line in sys.stdin:
request = json.loads(line.strip())
response = handle_request(request)
sys.stdout.write(json.dumps(response) + "\n")
sys.stdout.flush()
if __name__ == "__main__":
main()MCP Client 调用示例
以下是一个 MCP Client 通过 stdio 调用 Server 工具的示例:
import json
import subprocess
class MCPClient:
"""简单的 MCP 客户端"""
def __init__(self, server_command: list[str]):
self.process = subprocess.Popen(
server_command,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
text=True
)
self.request_id = 0
def _send_request(self, method: str, params: dict = None) -> dict:
self.request_id += 1
request = {
"jsonrpc": "2.0",
"id": self.request_id,
"method": method,
"params": params or {}
}
self.process.stdin.write(json.dumps(request) + "\n")
self.process.stdin.flush()
response = self.process.stdout.readline()
return json.loads(response.strip())
def initialize(self) -> dict:
return self._send_request("initialize", {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {
"name": "demo-client",
"version": "1.0.0"
}
})
def list_tools(self) -> list:
result = self._send_request("tools/list")
return result.get("result", {}).get("tools", [])
def call_tool(self, name: str, arguments: dict) -> dict:
return self._send_request("tools/call", {
"name": name,
"arguments": arguments
})
def close(self):
self.process.terminate()
# 使用示例
if __name__ == "__main__":
client = MCPClient(["python", "weather_server.py"])
client.initialize()
tools = client.list_tools()
print("可用工具:", tools)
result = client.call_tool("get_weather", {"city": "上海"})
content = result["result"]["content"]
for item in content:
print(item["text"])
client.close()总结
MCP 协议为 LLM 工具集成提供了一套标准化、可扩展的通信框架。通过定义清晰的三层架构、基于 JSON-RPC 2.0 的消息格式、以及 Tool / Resource / Prompt 三大原语,MCP 有效解决了 AI 应用与外部工具之间的集成碎片化问题。随着 AI 编程工具、自动化 Agent 等场景的快速发展,MCP 正在成为 AI 工具集成领域的事实标准协议。