架构概览
社区译文;来源: MCP 80041ab0
本概览介绍模型上下文协议(MCP)的范围 和核心概念 ,并通过一个示例 演示各项核心概念。
由于 MCP SDK 已经抽象了许多问题,大多数开发者可能会发现数据层协议 一节最有帮助。该节介绍 MCP 服务器如何向 AI 应用提供上下文。
有关具体实现细节,请参阅所用语言 SDK 的文档。
范围
模型上下文协议包含以下项目:
- MCP 规范 :说明客户端和服务器实现要求的 MCP 规范。
- MCP SDK :面向不同编程语言的 MCP 实现 SDK。
- MCP 开发工具:用于开发 MCP 服务器和客户端的工具,包括 MCP Inspector 。
- MCP 参考服务器实现 :MCP 服务器的参考实现。
MCP 概念
参与者
MCP 采用客户端-服务器架构。MCP 宿主是 Claude Code 或 Claude Desktop 等 AI 应用,它会与一个或多个 MCP 服务器建立连接。MCP 宿主为每个 MCP 服务器创建一个 MCP 客户端,每个 MCP 客户端都与对应的 MCP 服务器保持专用连接。
使用 STDIO 传输的本地 MCP 服务器通常只服务一个 MCP 客户端,而使用 Streamable HTTP 传输的远程 MCP 服务器通常会服务多个 MCP 客户端。
MCP 架构的主要参与者包括:
- MCP 宿主:协调和管理一个或多个 MCP 客户端的 AI 应用
- MCP 客户端:与 MCP 服务器保持连接,并从服务器取得上下文供 MCP 宿主使用的组件
- MCP 服务器:向 MCP 客户端提供上下文的程序
例如:Visual Studio Code 充当 MCP 宿主。当 Visual Studio Code 与 Sentry MCP 服务器 建立连接时,Visual Studio Code 运行时会实例化一个 MCP 客户端对象,由它维护与 Sentry MCP 服务器的连接。 当 Visual Studio Code 随后连接另一个 MCP 服务器,例如本地文件系统服务器 时,Visual Studio Code 运行时会实例化另一个 MCP 客户端对象来维护该连接。
graph TB
subgraph "MCP Host (AI Application)"
Client1["MCP Client 1"]
Client2["MCP Client 2"]
Client3["MCP Client 3"]
Client4["MCP Client 4"]
end
ServerA["MCP Server A - Local<br/>(e.g. Filesystem)"]
ServerB["MCP Server B - Local<br/>(e.g. Database)"]
ServerC["MCP Server C - Remote<br/>(e.g. Sentry)"]
Client1 ---|"Dedicated<br/>connection"| ServerA
Client2 ---|"Dedicated<br/>connection"| ServerB
Client3 ---|"Dedicated<br/>connection"| ServerC
Client4 ---|"Dedicated<br/>connection"| ServerC
请注意,无论程序在哪里运行,MCP 服务器都指提供上下文数据的程序。MCP 服务器可以在本地或远程运行。例如,Claude Desktop 启动文件系统服务器 时,由于该服务器使用 STDIO 传输,因此会在同一台计算机上本地运行。这通常称为“本地”MCP 服务器。官方 Sentry MCP 服务器 运行在 Sentry 平台上,并使用 Streamable HTTP 传输。这通常称为“远程”MCP 服务器。
分层
MCP 由两层组成:
- 数据层:定义基于 JSON-RPC 的客户端-服务器通信协议,包括能力与版本发现,以及工具、资源、提示和通知等核心原语。
- 传输层:定义支持客户端与服务器交换数据的通信机制和通道,包括特定传输的连接建立、消息成帧与授权。
从概念上说,数据层是内层,传输层是外层。
数据层
数据层实现基于 JSON-RPC 2.0 的交换协议,定义消息结构和语义。 该层包括:
- 发现:让客户端通过
server/discover请求查询服务器支持的协议版本、能力和身份 - 服务器功能:让服务器向客户端提供核心功能,包括用于 AI 操作的工具、用于上下文数据的资源,以及用于交互模板的提示
- 客户端功能:让服务器向用户征询输入。自协议版本
2026-07-28起,采样已弃用 。 - 实用功能:支持实时更新通知和长时间运行操作的进度跟踪等附加能力
传输层
传输层管理客户端与服务器之间的通信通道和身份验证,负责连接建立、消息成帧以及 MCP 参与者之间的安全通信。
MCP 支持两种传输机制:
- Stdio 传输:使用标准输入/输出流在同一台计算机的本地进程之间直接通信,没有网络开销,可提供最佳性能。
- Streamable HTTP 传输:使用 HTTP POST 发送客户端到服务器的消息,并可选用 Server-Sent Events 提供流式能力。该传输支持远程服务器通信,以及持有者令牌、API 密钥和自定义 HTTP 标头等标准身份验证方式。MCP 建议使用 OAuth 获取身份验证令牌。
传输层对协议层隐藏通信细节,使所有传输机制都能使用相同的 JSON-RPC 2.0 消息格式。
数据层协议
MCP 的核心内容之一,是定义 MCP 客户端与 MCP 服务器之间的模式和语义。开发者最感兴趣的可能是数据层,尤其是其中的原语 。MCP 正是通过这一部分定义开发者如何把 MCP 服务器中的上下文共享给 MCP 客户端。
MCP 使用 JSON-RPC 2.0 作为底层 RPC 协议。客户端与服务器相互发送请求并作出相应响应。无需响应时可以使用通知。
无状态与发现
MCP 是无状态协议。每个请求都会在 _meta 字段中携带协议版本和与该请求相关的能力,使服务器能够独立处理每个请求。除非另有配置,客户端也应在同一字段中标识自身。服务器通过强制实现的 server/discover
请求公布其支持的版本和能力,客户端可以在其他任何请求之前发送该请求。详细信息请参阅规范
,示例
则展示了每个请求的元数据和发现顺序。
原语
MCP 原语是 MCP 中最重要的概念。它们定义客户端和服务器可以相互提供什么。这些原语规定了可与 AI 应用共享的上下文信息类型,以及可执行的操作范围。
MCP 定义了三种可由_服务器_公开的核心原语:
- 工具:AI 应用可以调用以执行操作的函数(例如文件操作、API 调用和数据库查询)
- 资源:向 AI 应用提供上下文信息的数据源(例如文件内容、数据库记录和 API 响应)
- 提示:帮助组织语言模型交互的可复用模板(例如系统提示和少样本示例)
每种原语都有用于发现(*/list)、获取(*/get),以及某些情况下用于执行(tools/call)的相关方法。
MCP 客户端使用 */list 方法发现可用原语。例如,客户端可以先列出所有可用工具(tools/list),然后执行它们。这种设计支持动态列表。
举一个具体例子:某个 MCP 服务器提供数据库相关上下文。它可以公开用于查询数据库的工具、包含数据库模式的资源,以及包含工具交互少样本示例的提示。
有关服务器原语的更多信息,请参阅服务器概念 。
MCP 还定义了可由_客户端_公开的原语。这些原语让 MCP 服务器作者能够构建更丰富的交互。
- 信息征询:允许服务器向用户请求更多信息。当服务器作者希望从用户处取得更多信息或请求操作确认时,该功能很有用。服务器通过
elicitation/create方法请求用户输入。
信息征询请求通过多轮往返请求 模式传递,详情参阅信息征询概览 。
已弃用:以下客户端原语自协议版本 2026-07-28 起已弃用。
- 采样:允许服务器向客户端的 AI 应用请求语言模型补全。当服务器作者需要访问语言模型,但希望保持模型无关性,并且不在 MCP 服务器中包含语言模型 SDK 时,该功能很有用。服务器通过
sampling/createMessage方法请求补全,该请求同样通过多轮往返请求模式传递。新的实现应直接集成 LLM 提供方 API。 - 日志:让服务器能够出于调试和监控目的向客户端发送日志消息。新的实现应记录到
stderr(stdio 传输),或使用 OpenTelemetry。
有关客户端原语的更多信息,请参阅客户端概念 。
除服务器和客户端原语外,协议还支持基于核心协议构建的可选扩展 。例如,Tasks 扩展 让服务器能够为长时间运行的请求返回持久句柄,使客户端可以轮询状态并在稍后获取结果。
通知
协议支持实时通知,以便服务器与客户端之间进行动态更新。例如,当服务器的可用工具发生变化时(如新增功能或修改现有工具),服务器可以发送工具更新通知,告知已连接客户端这些变化。通知以 JSON-RPC 2.0 通知消息发送,不期待响应。变更通知采用选择加入机制:客户端打开长连接的 subscriptions/listen
通知流,指定希望接收的通知类型,服务器再通过该通知流发送匹配的通知。
示例
数据层
本节逐步讲解 MCP 客户端与服务器之间的交互,重点介绍数据层协议。示例使用 JSON-RPC 2.0 消息演示发现、工具操作和通知。
发现
如无状态与发现
一节所述,每个 MCP 请求都会在 _meta 字段中携带协议版本和客户端能力,客户端也应在其中包含自身身份。客户端若希望在发送其他请求前了解服务器支持的功能,可以发送每个服务器都必须实现的 server/discover 请求。发现响应通常可以缓存并复用,因此无需为每个请求都执行一次发现流程。
{
"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": {}
}
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"resultType": "complete",
"supportedVersions": ["2026-07-28"],
"capabilities": {
"tools": {
"listChanged": true
},
"resources": {}
},
"_meta": {
"io.modelcontextprotocol/serverInfo": {
"name": "example-server",
"version": "1.0.0"
}
},
"ttlMs": 3600000,
"cacheScope": "public"
}
}理解发现交换
_meta 字段与发现响应共同服务于以下几个目的:
协议版本选择:
io.modelcontextprotocol/protocolVersion字段声明客户端在当前请求中使用的版本,响应中的supportedVersions则列出服务器接受的版本。如果服务器不支持请求的版本,会用UnsupportedProtocolVersionError拒绝该请求,并列出其支持的版本;客户端随后使用双方均支持的版本重试。能力发现:客户端在每个请求的
io.modelcontextprotocol/clientCapabilities中声明自身能力,服务器则通过server/discover返回自己的capabilities对象。这使双方能够了解对方可以处理哪些原语 (工具、资源和提示),以及是否支持变更通知 ,从而避免尝试不受支持的操作。身份交换:请求
_meta中的io.modelcontextprotocol/clientInfo字段和结果_meta中的io.modelcontextprotocol/serverInfo字段提供身份与版本信息,用于调试和兼容性处理。
在本例中,该交换展示了 MCP 能力如何声明:
客户端能力:
"elicitation": {}:客户端声明自己可以在服务器提出请求时向用户收集更多输入
服务器能力:
"tools": {"listChanged": true}:服务器支持工具原语,并且可以处理subscriptions/listen中的toolsListChanged过滤条件。请求该过滤条件的客户端会在工具列表变化时收到notifications/tools/list_changed。"resources": {}:服务器还支持资源原语,可以处理resources/list和resources/read方法
调用 server/discover 是可选的。由于每个请求都携带相同的 _meta 字段,客户端可以直接发送任意请求,并在收到版本错误时进行处理。发现提供了一种便利方式,可以通过单个请求获取服务器身份、能力和支持的版本。
在 AI 应用中的工作方式
AI 应用的 MCP 客户端管理器会连接已配置的服务器,并保存发现到的能力以供后续使用。应用使用这些信息判断哪些服务器能够提供特定类型的功能(工具、资源或提示),以及服务器是否支持实时更新。在 Python SDK 中,发现发生在客户端连接期间,结果随后可在客户端对象上取得。
# Pseudo Code
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)工具发现(原语)
客户端可以发送 tools/list 请求发现可用工具。该请求是 MCP 工具发现机制的基础,让客户端能够在尝试使用工具前了解服务器提供了哪些工具。
{
"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": {}
}
}
}
}{
"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"
}
}理解工具发现请求
除每个 MCP 请求都会携带的标准 _meta 字段外,tools/list 请求不要求其他参数。它还接受可选的 cursor 参数以支持分页
,但上例省略了该参数。
理解工具发现响应
响应包含一个 tools 数组,提供每个可用工具的完整元数据。基于数组的结构让服务器能够同时公开多个工具,并在不同功能之间保持清晰边界。
响应中的每个工具对象都包含以下几个关键字段:
name:服务器命名空间内工具的唯一标识符。它是执行工具时使用的主键,应遵循清晰的命名模式(例如使用calculator_arithmetic,而不是只使用calculate)title:客户端可以向用户显示的、人类可读的工具名称description:详细说明工具的功能和适用时机inputSchema:定义预期输入参数的 JSON Schema,用于类型验证,并清晰记录必需参数和可选参数
结果标记为 "resultType": "complete",并带有两个缓存字段。ttlMs 是以毫秒为单位的新鲜度提示,因此该工具列表可以缓存五分钟。cacheScope 表明哪些主体可以复用响应。完整规则由规范中的缓存实用功能
定义。
在 AI 应用中的工作方式
AI 应用从所有已连接的 MCP 服务器获取可用工具,并将它们合并到语言模型可以访问的统一工具注册表中。这样,LLM 就能理解可以执行哪些操作,并在对话期间自动生成适当的工具调用。
# Pseudo-code using MCP Python SDK patterns
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)聚合多个服务器的客户端可以使用渐进式工具发现 ,而不必预先加载所有工具。
工具执行(原语)
客户端现在可以使用 tools/call 方法执行工具。这展示了 MCP 原语的实际用法:客户端发现可用工具后,可以使用适当参数调用它们。
理解工具执行请求
tools/call 请求采用结构化格式,以确保类型安全并实现清晰通信。请注意,这里使用发现响应中的正确工具名称(weather_current),而不是简化名称:
{
"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": {}
}
}
}
}{
"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%"
}
]
}
}工具执行的关键元素
请求结构包含几个重要组成部分:
name:必须与发现响应中的工具名称(weather_current)完全一致,以确保服务器能够正确识别要执行的工具。arguments:包含工具inputSchema定义的输入参数。在本例中:location:"San Francisco"(必需参数)units:"imperial"(可选参数,未指定时默认为"metric")
_meta:携带每个 MCP 请求必须包含的标准字段:协议版本和客户端能力,以及客户端身份;除非另有配置,客户端应包含该身份。JSON-RPC 结构:使用标准 JSON-RPC 2.0 格式,并以唯一
id关联请求与响应。
理解工具执行响应
响应展示了 MCP 灵活的内容系统:
content数组:工具响应返回内容对象数组,因此能够提供丰富的多格式响应,例如文本、图像和资源。内容类型:每个内容对象都有
type字段。本例中的"type": "text"表示纯文本内容,但 MCP 还支持适用于不同场景的多种内容类型。结构化输出:响应提供可执行的信息,AI 应用可以将其用作语言模型交互的上下文。
这种执行模式让 AI 应用可以动态调用服务器功能,并接收能够整合到语言模型对话中的结构化响应。
在 AI 应用中的工作方式
当语言模型决定在对话中使用工具时,AI 应用会拦截工具调用,将其路由到相应 MCP 服务器并执行,再把结果作为对话流程的一部分返回给 LLM。这样,LLM 就能访问实时数据并对外部世界执行操作。
# Pseudo-code for AI application tool execution
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.content)实时更新(通知)
MCP 支持实时通知,让服务器无需客户端轮询即可告知其变化。该功能展示了通知系统如何使客户端保持同步和快速响应。
订阅变更
变更通知采用选择加入机制。客户端若要接收通知,需要发送 subscriptions/listen
请求并通过 notifications 过滤条件指定所需事件类型,以打开长连接的通知流。下面的客户端请求接收工具列表变更:
{
"jsonrpc": "2.0",
"id": 4,
"method": "subscriptions/listen",
"params": {
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {
"name": "example-client",
"version": "1.0.0"
},
"io.modelcontextprotocol/clientCapabilities": {
"elicitation": {}
}
},
"notifications": {
"toolsListChanged": true
}
}
}每个客户端请求都会在 _meta 中携带 io.modelcontextprotocol/protocolVersion 和 io.modelcontextprotocol/clientCapabilities 字段,通常也会包含 io.modelcontextprotocol/clientInfo,使服务器无需依赖连接状态即可识别客户端。
服务器使用 notifications/subscriptions/acknowledged 确认订阅。这是第一条在 _meta 中携带该订阅 ID 的消息;在此之前,服务器不会为该订阅发送其他通知。它的 notifications 字段反映服务器同意处理的请求过滤条件子集,并省略不受支持的通知类型:
{
"jsonrpc": "2.0",
"method": "notifications/subscriptions/acknowledged",
"params": {
"_meta": {
"io.modelcontextprotocol/subscriptionId": 4
},
"notifications": {
"toolsListChanged": true
}
}
}理解工具列表变更通知
确认之后,当服务器的可用工具发生变化时(例如新功能可用、现有工具被修改或工具暂时不可用),服务器会通过该通知流发送通知:
{
"jsonrpc": "2.0",
"method": "notifications/tools/list_changed",
"params": {
"_meta": {
"io.modelcontextprotocol/subscriptionId": 4
}
}
}MCP 通知的主要特征
无需响应:请注意,通知中没有
id字段。这符合 JSON-RPC 2.0 的通知语义,即不期待也不发送响应。选择加入:只有在
subscriptions/listen过滤条件中请求"toolsListChanged": true的客户端才会收到该通知,而且仅当服务器在工具能力中声明"listChanged": true时才可使用该通知(如步骤 1 所示)。订阅 ID 标记:通知流上的每条通知都会在
_meta中携带io.modelcontextprotocol/subscriptionId。该值是打开通知流的subscriptions/listen请求的 JSON-RPC ID(本例为4),使客户端能够把每条通知与产生该通知的订阅关联起来。事件驱动:服务器根据内部状态变化决定何时发送通知,使 MCP 连接保持动态和快速响应。
尽力而为:无法保证每条通知都能发送或接收,尤其是在传输重新连接时。客户端还应依靠轮询来保持结果新鲜度。
客户端对通知的响应
客户端收到通知后,通常会请求更新后的工具列表。这样会形成刷新循环,使客户端对可用工具的认知保持最新:
{
"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": {}
}
}
}
}通知为何重要
该通知系统之所以重要,原因包括:
- 动态环境:工具可能随服务器状态、外部依赖或用户权限出现或消失
- 效率:客户端无需轮询变更,而会在更新发生时收到通知
- 一致性:确保客户端始终掌握准确的可用服务器能力信息
- 实时协作:让 AI 应用能够响应上下文变化并及时调整
该通知模式不仅适用于工具,也适用于其他 MCP 原语,从而实现客户端与服务器之间全面的实时同步。
在 AI 应用中的工作方式
AI 应用会为其关注的变更保持通知流。收到通知后,应用立即刷新工具注册表并更新 LLM 的可用能力。这样,进行中的对话始终能够访问最新工具集,LLM 也能动态适应新功能。
# Pseudo-code for AI application notification handling
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()