MCP 架构概览
原文:Architecture overview - Model Context Protocol 发布日期:2026-07-28 | 来源:modelcontextprotocol.io
这篇概览介绍 Model Context Protocol(MCP)的范围和核心概念,并通过一个完整示例串起每个核心概念的实际交互流程。
因为 MCP SDK 已经帮你屏蔽了大量底层细节,多数开发者会觉得数据层协议这一节最实用------它讲的就是 MCP server 怎么把 context 喂给 AI 应用。
具体实现细节请参考对应语言的 SDK 文档。
范围
Model Context Protocol 包含以下项目:
- MCP 规范:定义 client 和 server 的实现要求。
- MCP SDK:各语言的 SDK 实现。
- MCP 开发工具 :开发 MCP server 和 client 的工具集,包括 MCP Inspector。
- MCP 参考 server 实现:官方提供的 server 参考实现。
MCP 只管 context 交换这一件事------它不规定 AI 应用怎么用 LLM,也不管你拿到 context 之后怎么处理。
MCP 核心概念
参与方
MCP 采用 client-server 架构。一个 MCP host------也就是 AI 应用本身,比如 Claude Code 或 Claude Desktop------负责建立到一个或多个 MCP server 的连接。具体做法是:host 为每个 MCP server 创建一个 MCP client,每个 client 维护一条到自己对应 server 的专用连接。
用 STDIO transport 的本地 MCP server 通常只服务一个 client;用 Streamable HTTP transport 的远程 server 则同时服务多个 client。
MCP 架构里的三种关键角色:
- MCP Host:协调和管理一个或多个 MCP client 的 AI 应用。
- MCP Client:维护到 MCP server 的连接,从 server 获取 context 供 host 使用。
- MCP Server:向 client 提供 context 的程序。
举个例子 :VS Code 就是一个 MCP host。当 VS Code 连接到一个 MCP server(比如 Sentry MCP server)时,VS Code 运行时会实例化一个 MCP client 对象来维护这条连接。之后 VS Code 再连另一个 server(比如本地文件系统 server),就会再实例化一个 MCP client 对象。
注意,MCP server 指的是提供 context 数据的那个程序,不管它跑在哪。MCP server 可以跑在本地,也可以跑在远端。比如 Claude Desktop 启动的 filesystem server 用 STDIO transport,跑在同一台机器上------这就是所谓的「本地」MCP server。而官方的 Sentry MCP server 跑在 Sentry 平台上,用 Streamable HTTP transport------这就是所谓的「远程」MCP server。
分层
MCP 分两层:
- 数据层(Data layer):定义基于 JSON-RPC 的 client-server 通信协议,包括 capability 和版本发现,以及 tools、resources、prompts、notifications 等核心 primitive。
- 传输层(Transport layer):定义 client 和 server 之间的通信机制和通道,包括连接建立、消息帧格式和鉴权。
概念上,数据层是内层,传输层是外层。
数据层
数据层实现了基于 JSON-RPC 2.0 的交换协议,定义消息结构和语义。包含以下部分:
- Discovery :client 通过
server/discover请求查询 server 支持的协议版本、capability 和身份信息。 - Server 功能:server 提供的核心能力------tools(给 AI 执行动作)、resources(context 数据)、prompts(交互模板)。
- Client 功能 :让 server 可以向用户索取输入。Sampling 在协议版本
2026-07-28中已废弃。 - 辅助功能:notifications(实时更新)和 progress tracking(长时间操作进度跟踪)等附加能力。
传输层
传输层管理 client 和 server 之间的通信通道和鉴权,负责连接建立、消息帧封装和安全通信。
MCP 支持两种传输机制:
- Stdio transport:用标准输入/输出流在同一台机器上的进程之间直接通信,零网络开销,性能最优。
- Streamable HTTP transport:client 到 server 的消息走 HTTP POST,可选 SSE(Server-Sent Events)实现流式传输。支持远程 server 通信和标准 HTTP 鉴权方式(bearer token、API key、自定义 header)。MCP 推荐用 OAuth 获取鉴权 token。
传输层把通信细节从协议层抽象出来,让同一套 JSON-RPC 2.0 消息格式在所有传输机制上通用。
数据层协议
MCP 的核心在于定义 client 和 server 之间的 schema 和语义。开发者最感兴趣的通常是数据层------尤其是 primitive 部分,它定义了 server 向 client 共享 context 的所有方式。
MCP 底层用 JSON-RPC 2.0。Client 和 server 互发请求并响应;不需要响应的场景用 notification。
无状态与发现
MCP 是无状态协议。每个请求都在 _meta 字段里携带协议版本和该请求相关的 capability,server 可以独立处理每个请求。Client 也应该在同一字段里标识自己(除非配置了不这么做)。Server 通过必须响应的 server/discover 请求广播自己支持的版本和 capability,client 可以在发任何其他请求之前先做这一步。详细信息见规范,后面的示例会展示 per-request metadata 和 discovery 流程。
Primitive
MCP primitive 是整个协议里最重要的概念。它定义了 client 和 server 之间能互相提供什么------哪些类型的 context 信息可以共享给 AI 应用,哪些动作可以执行。
MCP 定义了三种 server 可以暴露的核心 primitive:
- Tools:AI 应用可以调用的可执行函数(比如文件操作、API 调用、数据库查询)。
- Resources:为 AI 应用提供 context 数据的数据源(比如文件内容、数据库记录、API 响应)。
- Prompts:帮助组织与 LLM 交互的可复用模板(比如 system prompt、few-shot 示例)。
每种 primitive 都有关联的 discovery 方法(*/list)、retrieval 方法(*/get),部分还有 execution 方法(tools/call)。Client 用 */list 方法来发现可用的 primitive。比如 client 可以先 tools/list 列出所有可用 tool,再执行它们。这种设计让列表可以是动态的。
举个具体例子:一个提供数据库 context 的 MCP server,可以暴露查询数据库的 tool、一个包含数据库 schema 的 resource、以及一个包含 few-shot 示例的 prompt。
更多 server primitive 细节见 server concepts。
MCP 也定义了 client 可以暴露的 primitive,让 server 开发者能构建更丰富的交互:
- Elicitation :允许 server 向用户请求额外信息。当 server 需要更多信息或想确认某个操作时很有用。Server 通过
elicitation/create方法请求用户输入。
Elicitation 请求通过 Multi Round-Trip Requests 模式传递,详见 elicitation 概览。
已废弃 :以下 client primitive 在协议版本 2026-07-28 中已废弃。
- Sampling :允许 server 请求 client 的 AI 应用做 LLM completion。适用于 server 作者想用 LLM 但不想绑定特定模型、也不想在 MCP server 里引入 LLM SDK 的场景。Server 通过
sampling/createMessage方法请求 completion,同样走 Multi Round-Trip Requests 模式。新实现应直接对接 LLM provider API。 - Logging :允许 server 把日志消息发给 client 用于调试和监控。新实现应写到
stderr(stdio transport)或用 OpenTelemetry。
更多 client primitive 细节见 client concepts。
除了 server 和 client primitive,协议还支持可选的 extension,在核心协议之上构建。比如 Tasks extension 让 server 对长时间运行的请求返回一个持久化 handle,client 可以轮询状态、稍后取结果。
Notification
协议支持实时 notification,用于 server 和 client 之间的动态更新。比如当 server 的可用 tools 发生变化(新功能上线、已有 tool 被修改),server 可以发 tool 更新 notification 通知所有已连接的 client。Notification 以 JSON-RPC 2.0 notification 消息发送(不期望响应)。Change notification 是 opt-in 的:client 开一条长连接的 subscriptions/listen stream,声明要接收哪些类型的 notification,server 在这条 stream 上推送匹配的 notification。
示例
数据层
下面用一个完整的 client-server 交互流程,一步步走一遍 MCP 数据层协议。我们会用 JSON-RPC 2.0 消息演示 discovery、tool 操作和 notification。
步骤 1:连接与 Discovery
交互的第一步是 client 发现 server 的能力。Client 发一个 server/discover 请求,server 返回它支持的协议版本、identity 和 capability。这一步让 client 在发任何业务请求之前就知道 server 能干什么。
Discovery 请求:
json
{
"jsonrpc": "2.0",
"id": 1,
"method": "server/discover",
"params": {
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "example-client",
"version": "1.0.0"
},
"io.modelcontextprotocol/clientCapabilities": {
"elicitation": {}
}
}
}
}
Discovery 响应:
json
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2026-07-28",
"serverInfo": {
"name": "example-server",
"version": "1.0.0"
},
"capabilities": {
"tools": {
"listChanged": true
}
}
}
}
理解 Discovery 请求
server/discover 请求除了每个 MCP 请求都必须带的标准 _meta 字段外,不需要额外参数。这里 _meta 包含三样东西:
protocolVersion:client 想用的协议版本。clientInfo:client 的 name 和 version,让 server 知道在跟谁通信。clientCapabilities:client 自己支持的能力(比如elicitation),告诉 server 可以向用户请求额外输入。
理解 Discovery 响应
响应里的 result 对象包含三个关键字段:
protocolVersion:server 选择的协议版本。Client 应该检查这个版本是否兼容。serverInfo:server 的 name 和 version。capabilities:server 支持的能力。这里"tools": {"listChanged": true}表示 server 暴露了 tools,并且支持在 tool 列表变化时发 notification。
AI 应用里怎么工作
AI 应用的 MCP client manager 连接到配置好的 server,缓存 discovery 结果供后续使用。应用用这些信息判断哪些 server 能提供哪些功能(tools、resources、prompts),以及是否支持实时更新。在 Python SDK 里,discovery 在 client 连接时就完成了,结果直接挂在 client 对象上。
python
# 伪代码
async with Client(stdio_client(server_config)) as client:
if client.server_capabilities.tools:
app.register_mcp_server(client, supports_tools=True)
app.set_server_ready(client)
步骤 2:Tool Discovery(Primitive)
Client 通过 tools/list 请求发现可用 tool。这是 MCP tool 发现机制的基础请求------让 client 在尝试使用 tool 之前知道 server 上有哪些。
json
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "example-client",
"version": "1.0.0"
},
"io.modelcontextprotocol/clientCapabilities": {
"elicitation": {}
}
}
}
}
json
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"resultType": "complete",
"tools": [
{
"name": "calculator_arithmetic",
"title": "Calculator",
"description": "Perform mathematical calculations including basic arithmetic, trigonometric functions, and algebraic operations",
"inputSchema": {
"type": "object",
"properties": {
"expression": {
"type": "string",
"description": "Mathematical expression to evaluate (e.g., '2 + 3 * 4', 'sin(30)', 'sqrt(16)')"
}
},
"required": ["expression"]
}
},
{
"name": "weather_current",
"title": "Weather Information",
"description": "Get current weather information for any location worldwide",
"inputSchema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City name, address, or coordinates (latitude,longitude)"
},
"units": {
"type": "string",
"enum": ["metric", "imperial", "kelvin"],
"description": "Temperature units to use in response",
"default": "metric"
}
},
"required": ["location"]
}
}
],
"ttlMs": 300000,
"cacheScope": "public"
}
}
理解 Tool Discovery 请求
tools/list 除了每个 MCP 请求都带的标准 _meta 字段外不需要额外参数。它还接受一个可选的 cursor 参数用于分页,上面的示例省略了。
理解 Tool Discovery 响应
响应里的 tools 数组包含每个可用 tool 的详细 metadata。这种数组结构让 server 可以同时暴露多个 tool,同时在不同功能之间保持清晰的边界。每个 tool 对象包含几个关键字段:
name:tool 在 server namespace 内的唯一标识符。作为 tool 执行的主键,命名应该清晰有规律(比如calculator_arithmetic而不是简单的calculate)。title:client 可以展示给用户的人类可读显示名。description:详细说明 tool 做什么、什么时候该用。inputSchema:JSON Schema,定义期望的输入参数,支持类型校验并提供清晰的参数文档。
响应标记了 "resultType": "complete",并带两个缓存字段。ttlMs 是新鲜度提示(毫秒),表示这个 tool 列表可以缓存 5 分钟。cacheScope 表示谁可以复用这个响应。完整规则见规范的 caching utility。
AI 应用里怎么工作
AI 应用从所有已连接的 MCP server 拉取可用 tool,合并成一个统一的 tool registry 供 LLM 访问。这让 LLM 知道自己能执行哪些动作,并在对话中自动生成合适的 tool call。
python
# 伪代码,使用 MCP Python SDK 模式
available_tools = []
for client in app.mcp_clients():
tools_response = await client.list_tools()
available_tools.extend(tools_response.tools)
conversation.register_available_tools(available_tools)
联邦化多个 server 的 client 可以用渐进式 tool discovery,而不是启动时一次性加载所有 tool。
步骤 3:Tool 执行(Primitive)
Client 现在可以用 tools/call 方法执行一个 tool。这展示了 MCP primitive 的实际用法:发现可用 tool 之后,client 带着合适的参数调用它们。
理解 Tool 执行请求
tools/call 请求遵循结构化格式,确保 client 和 server 之间的类型安全和清晰通信。注意我们用的是 discovery 响应里的正式 tool 名(weather_current),而不是简化名:
json
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "weather_current",
"arguments": {
"location": "San Francisco",
"units": "imperial"
},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "example-client",
"version": "1.0.0"
},
"io.modelcontextprotocol/clientCapabilities": {
"elicitation": {}
}
}
}
}
json
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"resultType": "complete",
"content": [
{
"type": "text",
"text": "Current weather in San Francisco: 68°F, partly cloudy with light winds from the west at 8 mph. Humidity: 65%"
}
]
}
}
Tool 执行的关键要素
请求结构包含几个重要组件:
name:必须精确匹配 discovery 响应里的 tool 名(weather_current),确保 server 能正确识别要执行的 tool。arguments:包含 tool 的inputSchema定义的输入参数。本例中:location:"San Francisco"(必填);units:"imperial"(可选,不指定时默认 "metric")。_meta:携带标准 per-request 字段:协议版本、client capability,以及 client 身份信息。- JSON-RPC 结构 :标准 JSON-RPC 2.0 格式,用唯一
id做请求-响应关联。
理解 Tool 执行响应
响应展示了 MCP 灵活的内容系统:
content数组:tool 响应返回一个 content 对象数组,支持富文本、多格式响应(文本、图片、resource 等)。- Content 类型 :每个 content 对象有
type字段。本例"type": "text"表示纯文本,但 MCP 支持多种 content 类型。 - 结构化输出:响应提供可操作的信息,AI 应用可以把它作为 LLM 交互的 context。
这种执行模式让 AI 应用能动态调用 server 功能,接收结构化响应并整合进 LLM 对话。
AI 应用里怎么工作
当 LLM 在对话中决定使用一个 tool 时,AI 应用拦截这个 tool call,路由到对应的 MCP server 执行,然后把结果返回给 LLM 作为对话流的一部分。这让 LLM 能访问实时数据、在外部世界执行动作。
python
# 伪代码:AI 应用的 tool 执行
async def handle_tool_call(conversation, tool_name, arguments):
client = app.find_mcp_client_for_tool(tool_name)
result = await client.call_tool(tool_name, arguments)
conversation.add_tool_result(result)
return result
步骤 4:订阅 Change Notification
现在 client 已经知道 server 在 discovery 阶段声明了 "listChanged": true,它可以订阅 tool 列表变化的 notification。Client 发一个 subscriptions/listen 请求,声明要接收哪些类型的 notification:
json
{
"jsonrpc": "2.0",
"id": 4,
"method": "subscriptions/listen",
"params": {
"notifications": {
"toolsListChanged": true
},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "example-client",
"version": "1.0.0"
},
"io.modelcontextprotocol/clientCapabilities": {
"elicitation": {}
}
}
}
}
Server 用 notifications/subscriptions/acknowledged 确认订阅,这是第一条携带该 subscription ID 的消息(在确认之前 server 不会发其他 notification)。notifications 字段反映 server 同意处理的订阅子集,不支持的 notification 类型会被省略:
json
{
"jsonrpc": "2.0",
"method": "notifications/subscriptions/acknowledged",
"params": {
"_meta": {
"io.modelcontextprotocol/subscriptionId": 4
},
"notifications": {
"toolsListChanged": true
}
}
}
理解 Tool 列表变化 Notification
确认之后,当 server 的可用 tools 发生变化(新功能上线、已有 tool 被修改、tool 暂时不可用),server 在这条 stream 上推送 notification:
json
{
"jsonrpc": "2.0",
"method": "notifications/tools/list_changed",
"params": {
"_meta": {
"io.modelcontextprotocol/subscriptionId": 4
}
}
}
MCP Notification 的关键特性
- 不需要响应 :注意 notification 里没有
id字段。这遵循 JSON-RPC 2.0 notification 语义------不期望也不发送响应。 - Opt-in :只有 client 在
subscriptions/listen里请求了"toolsListChanged": true,且 server 在 tools capability 里声明了"listChanged": true(如步骤 1 所示),才会收到这个 notification。 - Subscription-ID 标记 :stream 上的每条 notification 都在
_meta里携带io.modelcontextprotocol/subscriptionId,值是打开这条 stream 的subscriptions/listen请求的 JSON-RPC ID(本例是4),client 据此把 notification 关联到对应的订阅。 - 事件驱动:server 根据内部状态变化决定何时发 notification,让 MCP 连接保持动态和响应性。
- 尽力而为:不保证每条 notification 都会被发送或接收,尤其是跨 transport 重连时。Client 也应该靠轮询来保证结果新鲜度。
Client 对 Notification 的响应
收到 notification 后,client 通常会请求更新后的 tool 列表,形成一个刷新循环,保持 client 对可用 tool 的认知是最新的:
json
{
"jsonrpc": "2.0",
"id": 5,
"method": "tools/list",
"params": {
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "example-client",
"version": "1.0.0"
},
"io.modelcontextprotocol/clientCapabilities": {
"elicitation": {}
}
}
}
}
为什么 Notification 重要
这个 notification 机制在几个方面至关重要:
- 动态环境:Tool 可能随 server 状态、外部依赖或用户权限变化而出现或消失。
- 效率:Client 不需要轮询变化,变化发生时会被通知。
- 一致性:确保 client 始终拥有 server capability 的准确信息。
- 实时协作:让 AI 应用能响应式地适应变化的 context。
这种 notification 模式不限于 tools,可以扩展到所有 MCP primitive,实现 client 和 server 之间的全面实时同步。
AI 应用里怎么工作
AI 应用为关心的变化保持一条 notification stream 打开。收到通知后,立即刷新 tool registry 并更新 LLM 的可用 capability。这确保进行中的对话始终能访问最新的 tool 集合,LLM 能动态适应新上线的功能。
python
# 伪代码:AI 应用的 notification 处理
async def follow_tool_changes(client):
async with client.listen(tools_list_changed=True) as sub:
async for _event in sub:
tools_response = await client.list_tools()
app.update_available_tools(client, tools_response.tools)
if app.conversation.is_active():
app.conversation.notify_llm_of_new_capabilities()