MCP 基础协议
类别: MCP LLM 标签: MCP LLM目录
模型上下文协议(Model Context Protocol)由几个协同工作的关键组件组成:
- 基础协议:核心 JSON-RPC 消息类型
- 生命周期管理:连接初始化、能力协商和会话控制
- 服务器功能:服务器提供的资源、提示和工具
- 客户端功能:客户端提供的采样和根目录列表
- 实用工具:跨领域关注点,如日志记录和参数补全
所有实现必须支持基础协议和生命周期管理组件。其他组件可以根据应用程序的特定需求来实现。
这些协议层在实现客户端和服务器之间丰富交互的同时,建立了明确的关注点分离。模块化设计允许实现精确支持所需的功能。
消息
MCP 客户端和服务器之间的所有消息必须遵循 JSON-RPC 2.0 规范。协议定义了以下类型的消息:
请求(Requests)
请求从客户端发送到服务器,或者从服务器发送到客户端,用于启动操作。
{
jsonrpc: "2.0";
id: string | number;
method: string;
params?: {
[key: string]: unknown;
};
}
- 请求必须包含字符串或整数 ID。
- 与基本 JSON-RPC 不同,ID 不得为
null
。 - 请求 ID 不得在同一会话中被请求者先前使用过。
响应(Responses)
响应是对请求的回复,包含操作的结果或错误。
{
jsonrpc: "2.0";
id: string | number;
result?: {
[key: string]: unknown;
}
error?: {
code: number;
message: string;
data?: unknown;
}
}
- 响应必须包含与其对应请求相同的 ID。
- 响应进一步分为成功结果或错误。必须设置
result
或error
中的一个。响应不得同时设置两者。 - 结果可以遵循任何 JSON 对象结构,而错误必须至少包含错误代码和消息。
- 错误代码必须是整数。
通知(Notifications)
通知从客户端发送到服务器,或者从服务器发送到客户端,作为单向消息。接收方不得发送响应。
{
jsonrpc: "2.0";
method: string;
params?: {
[key: string]: unknown;
};
}
- 通知不得包含 ID。
批处理(Batching)
JSON-RPC 还定义了批量处理多个请求和通知的方法,将它们放在一个数组中发送。MCP 实现可以支持发送 JSON-RPC 批处理,但必须支持接收 JSON-RPC 批处理。
认证
MCP 提供了一个用于 HTTP 的授权框架。使用基于 HTTP 的传输的实现应该符合此规范,而使用 STDIO 传输的实现不应该遵循此规范,而应该从环境中检索凭据。
此外,客户端和服务器可以协商自己的自定义认证和授权策略。
如需进一步讨论并为 MCP 认证机制的发展做出贡献,请加入我们的 GitHub Discussions,帮助塑造协议的未来!
模式
协议的完整规范定义为 TypeScript 模式。这是所有协议消息和结构的真实来源。
还有一个 JSON Schema,它是从 TypeScript 的真实来源自动生成的,用于各种自动化工具。
生命周期
模型上下文协议 (MCP) 为客户端-服务器连接定义了严格的生命周期,确保适当的能力协商和状态管理。
- 初始化: 能力协商和协议版本约定
- 操作: 正常协议通信
- 关闭: 连接的优雅终止
sequenceDiagram
participant Client
participant Server
Note over Client,Server: 初始化阶段
activate Client
Client->>+Server: initialize 请求
Server-->>Client: initialize 响应
Client--)Server: initialized 通知
Note over Client,Server: 操作阶段
rect rgb(200, 220, 250)
note over Client,Server: 正常协议操作
end
Note over Client,Server: 关闭
Client--)-Server: 断开连接
deactivate Server
Note over Client,Server: 连接关闭
生命周期阶段
初始化
初始化阶段必须是客户端和服务器之间的第一次交互。 在此阶段,客户端和服务器:
- 建立协议版本兼容性
- 交换和协商能力
- 共享实现详情
客户端必须通过发送包含以下内容的 initialize
请求来启动此阶段:
- 支持的协议版本
- 客户端能力
- 客户端实现信息
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {
"roots": {
"listChanged": true
},
"sampling": {}
},
"clientInfo": {
"name": "ExampleClient",
"version": "1.0.0"
}
}
}
初始化请求不得作为 JSON-RPC 批处理的一部分,因为在初始化完成之前无法进行其他请求和通知。这也允许与不明确支持 JSON-RPC 批处理的先前协议版本向后兼容。
服务器必须响应自己的能力和信息:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {
"logging": {},
"prompts": {
"listChanged": true
},
"resources": {
"subscribe": true,
"listChanged": true
},
"tools": {
"listChanged": true
}
},
"serverInfo": {
"name": "ExampleServer",
"version": "1.0.0"
}
}
}
成功初始化后,客户端必须发送 initialized
通知,表明其已准备好开始正常操作:
{
"jsonrpc": "2.0",
"method": "notifications/initialized"
}
- 在服务器响应
initialize
请求之前,客户端不应发送除ping
以外的请求。 - 在接收到
initialized
通知之前,服务器不应发送除ping
和日志
以外的请求。
版本协商
在 initialize
请求中,客户端必须发送其支持的协议版本。这应该是客户端支持的最新版本。
如果服务器支持请求的协议版本,它必须以相同的版本回应。否则,服务器必须响应它支持的另一个协议版本。这应该是服务器支持的最新版本。
如果客户端不支持服务器响应中的版本,它应该断开连接。
能力协商
客户端和服务器能力确定会话期间可用的可选协议功能。
关键能力包括:
类别 | 能力 | 描述 |
---|---|---|
客户端 | roots |
提供文件系统根目录 的能力 |
客户端 | sampling |
支持 LLM 采样 请求 |
客户端 | experimental |
描述对非标准实验性功能的支持 |
服务器 | prompts |
提供提示模板 |
服务器 | resources |
提供可读的资源 |
服务器 | tools |
暴露可调用的工具 |
服务器 | logging |
发出结构化日志消息 |
服务器 | experimental |
描述对非标准实验性功能的支持 |
能力对象可以描述子能力,如:
listChanged
: 支持列表变更通知(适用于提示、资源和工具)subscribe
: 支持订阅单个项目的变更(仅限资源)
操作
在操作阶段,客户端和服务器根据协商的能力交换消息。
双方应该:
- 尊重协商的协议版本
- 仅使用已成功协商的能力
关闭
在关闭阶段,一方(通常是客户端)干净地终止协议连接。未定义特定的关闭消息——相反,应使用底层传输机制来发出连接终止信号:
stdio
对于 stdio 传输
,客户端应该通过以下方式启动关闭:
- 首先,关闭到子进程(服务器)的输入流
- 等待服务器退出,或者如果服务器在合理时间内没有退出,则发送
SIGTERM
- 如果服务器在
SIGTERM
后的合理时间内没有退出,则发送SIGKILL
服务器可以通过关闭其到客户端的输出流并退出来启动关闭。
HTTP
对于 HTTP 传输
,关闭通过关闭相关的 HTTP 连接来表示。
超时
实现应该为所有发送的请求建立超时,以防止连接挂起和资源耗尽。当请求在超时期限内未收到成功或错误响应时,发送方应该为该请求发出取消通知
并停止等待响应。
SDK 和其他中间件应该允许这些超时在每个请求的基础上进行配置。
实现可以选择在接收到与请求相对应的进度通知
时重置超时时钟,因为这意味着工作正在进行。然而,实现应该始终强制执行最大超时,无论进度通知如何,以限制行为不当的客户端或服务器的影响。
错误处理
实现应该准备处理这些错误情况:
- 协议版本不匹配
- 无法协商所需能力
- 请求超时
初始化错误示例:
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32602,
"message": "Unsupported protocol version",
"data": {
"supported": ["2024-11-05"],
"requested": "1.0.0"
}
}
}
传输协议
MCP 使用 JSON-RPC 编码消息。JSON-RPC 消息必须使用 UTF-8 编码。
该协议目前定义了两种标准的客户端-服务器通信传输机制:
客户端在可能的情况下应该支持标准输入输出。
客户端和服务器也可以以可插拔的方式实现自定义传输协议。
标准输入输出
在标准输入输出传输模式中:
- 客户端将 MCP 服务器作为子进程启动。
- 服务器从其标准输入(
stdin
)读取 JSON-RPC 消息,并向其标准输出(stdout
)发送消息。 - 消息可以是 JSON-RPC 请求、通知、响应,或包含一个或多个请求和/或通知的 JSON-RPC 批处理。
- 消息由换行符分隔,并且不得包含嵌入的换行符。
- 服务器可以将 UTF-8 字符串写入其标准错误(
stderr
)以用于日志记录。客户端可以捕获、转发或忽略这些日志。 - 服务器不得向其
stdout
写入任何不是有效 MCP 消息的内容。 - 客户端不得向服务器的
stdin
写入任何不是有效 MCP 消息的内容。
sequenceDiagram
participant Client
participant Server Process
Client->>+Server Process: 启动子进程
loop 消息交换
Client->>Server Process: 写入 stdin
Server Process->>Client: 写入 stdout
Server Process--)Client: 可选的 stderr 日志
end
Client->>Server Process: 关闭 stdin,终止子进程
deactivate Server Process
可流式 HTTP
在可流式 HTTP传输中,服务器作为一个独立进程运行,可以处理多个客户端连接。此传输使用 HTTP POST 和 GET 请求。服务器可以选择使用服务器发送事件(SSE)来流式传输多个服务器消息。这允许基本的 MCP 服务器以及支持流式传输和服务器到客户端通知和请求的更丰富功能的服务器。
服务器必须提供一个支持 POST 和 GET 方法的 HTTP 端点路径(以下称为 MCP 端点)。例如,这可以是类似 https://example.com/mcp
的 URL。
向服务器发送消息
从客户端发送的每个 JSON-RPC 消息必须是一个新的 HTTP POST 请求到 MCP 端点。
- 客户端必须使用 HTTP POST 向 MCP 端点发送 JSON-RPC 消息。
- 客户端必须包含一个
Accept
头,列出application/json
和text/event-stream
作为支持的内容类型。 - POST 请求的主体必须是以下之一:
- 如果输入仅包含(任意数量的)JSON-RPC 响应_或_通知:
- 如果服务器接受输入,服务器必须返回 HTTP 状态码 202 Accepted,且没有响应体。
- 如果服务器无法接受输入,它必须返回 HTTP 错误状态码(例如,400 Bad Request)。HTTP 响应体可以包含没有
id
的 JSON-RPC 错误响应。
- 如果输入包含任意数量的 JSON-RPC 请求,服务器必须返回
Content-Type: text/event-stream
(以启动 SSE 流)或Content-Type: application/json
(以返回一个 JSON 对象)。客户端必须支持这两种情况。 - 如果服务器启动 SSE 流:
- SSE 流应该最终包含每个在 POST 正文中发送的 JSON-RPC 请求_对应的一个 JSON-RPC _响应。这些_响应_可以进行批处理。
- 服务器可以在发送 JSON-RPC 响应_之前发送 JSON-RPC _请求_和_通知。这些消息应该与原始客户端_请求_相关。这些_请求_和_通知_可以进行批处理。
- 除非会话过期,否则服务器不应该在为每个收到的 JSON-RPC _请求_发送 JSON-RPC _响应_之前关闭 SSE 流。
- 在所有 JSON-RPC _响应_都已发送后,服务器应该关闭 SSE 流。
- 断开连接可能随时发生(例如,由于网络条件)。因此:
- 断开连接不应该被解释为客户端取消其请求。
- 若要取消,客户端应该明确发送 MCP
CancelledNotification
。 - 为避免由于断开连接导致的消息丢失,服务器可以使流可恢复。
监听来自服务器的消息
- 客户端可以向 MCP 端点发出 HTTP GET 请求。这可用于打开 SSE 流,允许服务器与客户端通信,而无需客户端首先通过 HTTP POST 发送数据。
- 客户端必须包含一个
Accept
头,将text/event-stream
列为支持的内容类型。 - 服务器必须响应此 HTTP GET 请求返回
Content-Type: text/event-stream
,或者返回 HTTP 405 Method Not Allowed,表明服务器在此端点不提供 SSE 流。 - 如果服务器启动 SSE 流:
- 服务器可以在流上发送 JSON-RPC 请求_和_通知。这些_请求_和_通知_可以进行批处理。
- 这些消息应该与来自客户端的任何当前运行的 JSON-RPC _请求_无关。
- 服务器不得在流上发送 JSON-RPC 响应,除非正在恢复与之前客户端请求相关的流。
- 服务器可以随时关闭 SSE 流。
- 客户端可以随时关闭 SSE 流。
多连接
- 客户端可以同时保持与多个 SSE 流的连接。
- 服务器必须将其每个 JSON-RPC 消息仅发送到一个已连接的流上;也就是说,它不得在多个流上广播相同的消息。
- 消息丢失的风险可以通过使流可恢复来减轻。
可恢复性和重新传递
为了支持恢复断开的连接,并重新传递可能丢失的消息:
- 服务器可以按照SSE 标准所述,为其 SSE 事件附加
id
字段。- 如果存在,ID必须在该会话内的所有流中全局唯一—或者,如果未使用会话管理,则在该特定客户端的所有流中全局唯一。
- 如果客户端希望在连接断开后恢复,它应该向 MCP 端点发出 HTTP GET 请求,并包含
Last-Event-ID
头以指示它接收到的最后一个事件 ID。- 服务器可以使用此头来重播在最后一个事件 ID 之后本应发送的消息(在断开连接的流上),并从该点恢复流。
- 服务器不得重播本应在不同流上传递的消息。
换句话说,这些事件 ID 应由服务器以每流为基础分配,作为该特定流内的游标。
会话管理
MCP “会话” 由客户端和服务器之间逻辑相关的交互组成,始于初始化阶段
。为了支持希望建立有状态会话的服务器:
- 使用可流式 HTTP 传输的服务器可以在初始化时分配会话 ID,方法是在包含
InitializeResult
的 HTTP 响应中包含Mcp-Session-Id
头。- 会话 ID应该全局唯一且具有密码学安全性(例如,安全生成的 UUID、JWT 或加密哈希)。
- 会话 ID必须仅包含可见的 ASCII 字符(范围从 0x21 到 0x7E)。
- 如果服务器在初始化期间返回了
Mcp-Session-Id
,使用可流式 HTTP 传输的客户端必须在其后续所有 HTTP 请求中包含该 ID 作为Mcp-Session-Id
头。- 需要会话 ID 的服务器应该以 HTTP 400 Bad Request 响应没有
Mcp-Session-Id
头的请求(初始化除外)。
- 需要会话 ID 的服务器应该以 HTTP 400 Bad Request 响应没有
- 服务器可以随时终止会话,之后它必须以 HTTP 404 Not Found 响应包含该会话 ID 的请求。
- 当客户端收到对包含
Mcp-Session-Id
的请求的 HTTP 404 响应时,它必须通过发送不附加会话 ID 的新InitializeRequest
来开始新会话。 - 不再需要特定会话的客户端(例如,因为用户正在离开客户端应用程序)应该向带有
Mcp-Session-Id
头的 MCP 端点发送 HTTP DELETE,以明确终止会话。- 服务器可以以 HTTP 405 Method Not Allowed 响应此请求,表明服务器不允许客户端终止会话。
序列图
sequenceDiagram
participant Client
participant Server
note over Client, Server: 初始化
Client->>+Server: POST InitializeRequest
Server->>-Client: InitializeResponse<br>Mcp-Session-Id: 1868a90c...
Client->>+Server: POST InitializedNotification<br>Mcp-Session-Id: 1868a90c...
Server->>-Client: 202 Accepted
note over Client, Server: 客户端请求
Client->>+Server: POST ... request ...<br>Mcp-Session-Id: 1868a90c...
alt 单个 HTTP 响应
Server->>Client: ... response ...
else 服务器打开 SSE 流
loop 连接保持打开状态
Server-)Client: ... 来自服务器的 SSE 消息 ...
end
Server-)Client: SSE event: ... response ...
end
deactivate Server
note over Client, Server: 客户端通知/响应
Client->>+Server: POST ... notification/response ...<br>Mcp-Session-Id: 1868a90c...
Server->>-Client: 202 Accepted
note over Client, Server: 服务器请求
Client->>+Server: GET<br>Mcp-Session-Id: 1868a90c...
loop 连接保持打开状态
Server-)Client: ... 来自服务器的 SSE 消息 ...
end
deactivate Server
向后兼容性
客户端和服务器可以通过以下方式与已弃用的 HTTP+SSE 传输
(来自协议版本 2024-11-05)保持向后兼容:
想要支持旧客户端的服务器应该:
- 继续托管旧传输的 SSE 和 POST 端点,同时提供为可流式 HTTP 传输定义的新”MCP 端点”。
- 也可以将旧的 POST 端点和新的 MCP 端点组合起来,但这可能会引入不必要的复杂性。
想要支持旧服务器的客户端应该:
- 接受用户提供的 MCP 服务器 URL,该 URL 可能指向使用旧传输或新传输的服务器。
- 尝试向服务器 URL 发送
InitializeRequest
的 POST 请求,带有上面定义的Accept
头:- 如果成功,客户端可以假设这是支持新可流式 HTTP 传输的服务器。
- 如果失败并返回 HTTP 4xx 状态码(例如,405 Method Not Allowed 或 404 Not Found):
- 向服务器 URL 发出 GET 请求,期望这将打开一个 SSE 流,并返回
endpoint
事件作为第一个事件。 - 当
endpoint
事件到达时,客户端可以假设这是运行旧 HTTP+SSE 传输的服务器,并应该使用该传输进行所有后续通信。
- 向服务器 URL 发出 GET 请求,期望这将打开一个 SSE 流,并返回
自定义传输
客户端和服务器可以实现额外的自定义传输机制以满足其特定需求。该协议与传输无关,可以在任何支持双向消息交换的通信通道上实现。
选择支持自定义传输的实现者必须确保它们保留 MCP 定义的 JSON-RPC 消息格式和生命周期要求。自定义传输应该记录其特定的连接建立和消息交换模式,以帮助互操作性。
授权
1. 简介
1.1 目的和范围
模型上下文协议(MCP)在传输层提供授权功能,使MCP客户端能够代表资源所有者向受限的MCP服务器发出请求。本规范定义了基于HTTP传输的授权流程。
1.2 协议要求
对MCP实现来说,授权是可选的。当支持授权时:
- 使用基于HTTP传输的实现应当符合本规范。
- 使用STDIO传输的实现不应遵循本规范,而应从环境中检索凭据。
- 使用替代传输的实现必须遵循其协议的既定安全最佳实践。
1.3 标准合规性
此授权机制基于下列既定规范,但实现了其功能的选定子集,以确保安全性和互操作性,同时保持简单性:
- OAuth 2.1 IETF 草案
- OAuth 2.0 授权服务器元数据 (RFC8414)
- OAuth 2.0 动态客户端注册协议 (RFC7591)
2. 授权流程
2.1 概述
-
MCP认证实现必须实现OAuth 2.1,并为机密客户端和公共客户端采取适当的安全措施。
-
MCP认证实现应当支持OAuth 2.0动态客户端注册协议(RFC7591)。
-
MCP服务器应当实现且MCP客户端必须实现OAuth 2.0授权服务器元数据(RFC8414)。不支持授权服务器元数据的服务器必须遵循默认URI架构。
2.2 基本OAuth 2.1授权
当需要授权且客户端尚未提供授权证明时,服务器必须响应_HTTP 401 Unauthorized_。
客户端在收到_HTTP 401 Unauthorized_后启动OAuth 2.1 IETF 草案授权流程。
以下演示了使用PKCE的公共客户端的基本OAuth 2.1流程。
sequenceDiagram
participant B as 用户代理(浏览器)
participant C as 客户端
participant M as MCP服务器
C->>M: MCP请求
M->>C: HTTP 401 Unauthorized
Note over C: 生成code_verifier和code_challenge
C->>B: 打开浏览器并附带授权URL + code_challenge
B->>M: GET /authorize
Note over M: 用户登录并授权
M->>B: 重定向到回调URL并附带授权码
B->>C: 通过授权码回调
C->>M: 令牌请求(附带code + code_verifier)
M->>C: 访问令牌(+ 刷新令牌)
C->>M: 带访问令牌的MCP请求
Note over C,M: 开始标准MCP消息交换
2.3 服务器元数据发现
对于服务器能力发现:
- MCP客户端_必须_遵循RFC8414中定义的OAuth 2.0授权服务器元数据协议。
- MCP服务器_应当_遵循OAuth 2.0授权服务器元数据协议。
- 不支持OAuth 2.0授权服务器元数据协议的MCP服务器_必须_支持备用URL。
发现流程如下图所示:
sequenceDiagram
participant C as 客户端
participant S as 服务器
C->>S: GET /.well-known/oauth-authorization-server
alt 发现成功
S->>C: 200 OK + 元数据文档
Note over C: 使用元数据中的端点
else 发现失败
S->>C: 404 Not Found
Note over C: 回退到默认端点
end
Note over C: 继续授权流程
2.3.1 服务器元数据发现头部
MCP客户端_应当_在服务器元数据发现期间包含头部MCP-Protocol-Version: <protocol-version>
,以允许MCP服务器根据MCP协议版本进行响应。
例如:MCP-Protocol-Version: 2024-11-05
2.3.2 授权基础URL
授权基础URL必须通过舍弃MCP服务器URL中的任何现有路径
组件来确定。例如:
如果MCP服务器URL是https://api.example.com/v1/mcp
,那么:
- 授权基础URL是
https://api.example.com
- 元数据端点必须位于
https://api.example.com/.well-known/oauth-authorization-server
这确保了授权端点始终位于托管MCP服务器的域名根级别,无论MCP服务器URL中有何路径组件。
2.3.3 没有元数据发现的服务器的备用方案
对于不实现OAuth 2.0授权服务器元数据的服务器,客户端必须使用以下相对于授权基础URL(如2.3.2节所定义)的默认端点路径:
端点 | 默认路径 | 描述 |
---|---|---|
授权端点 | /authorize | 用于授权请求 |
令牌端点 | /token | 用于令牌交换和刷新 |
注册端点 | /register | 用于动态客户端注册 |
例如,对于托管在https://api.example.com/v1/mcp
的MCP服务器,默认端点将是:
https://api.example.com/authorize
https://api.example.com/token
https://api.example.com/register
客户端必须首先尝试通过元数据文档发现端点,然后才回退到默认路径。使用默认路径时,所有其他协议要求保持不变。
2.3 动态客户端注册
MCP客户端和服务器应当支持OAuth 2.0动态客户端注册协议,以允许MCP客户端无需用户交互即可获取OAuth客户端ID。这为客户端提供了一种标准化的方式自动注册到新服务器,这对MCP至关重要,因为:
- 客户端无法预先知道所有可能的服务器
- 手动注册会给用户带来摩擦
- 它使连接到新服务器变得无缝
- 服务器可以实现自己的注册策略
任何_不_支持动态客户端注册的MCP服务器需要提供获取客户端ID(以及适用时的客户端密钥)的替代方式。对于这些服务器,MCP客户端必须:
- 专门为该MCP服务器硬编码客户端ID(以及适用时的客户端密钥),或
- 向用户呈现UI,允许他们在自行注册OAuth客户端后(例如,通过服务器托管的配置界面)输入这些详细信息。
2.4 授权流程步骤
完整的授权流程如下进行:
sequenceDiagram
participant B as 用户代理(浏览器)
participant C as 客户端
participant M as MCP服务器
C->>M: GET /.well-known/oauth-authorization-server
alt 服务器支持发现
M->>C: 授权服务器元数据
else 无发现
M->>C: 404(使用默认端点)
end
alt 动态客户端注册
C->>M: POST /register
M->>C: 客户端凭据
end
Note over C: 生成PKCE参数
C->>B: 打开浏览器并附带授权URL + code_challenge
B->>M: 授权请求
Note over M: 用户授权
M->>B: 重定向到回调并附带授权码
B->>C: 授权码回调
C->>M: 令牌请求 + code_verifier
M->>C: 访问令牌(+ 刷新令牌)
C->>M: 带访问令牌的API请求
2.4.1 决策流程概述
flowchart TD
A[开始授权流程] --> B{检查元数据发现}
B -->|可用| C[使用元数据端点]
B -->|不可用| D[使用默认端点]
C --> G{检查注册端点}
D --> G
G -->|可用| H[执行动态注册]
G -->|不可用| I[需要替代注册]
H --> J[开始OAuth流程]
I --> J
J --> K[生成PKCE参数]
K --> L[请求授权]
L --> M[用户授权]
M --> N[交换授权码获取令牌]
N --> O[使用访问令牌]
2.5 访问令牌使用
2.5.1 令牌要求
访问令牌处理必须符合OAuth 2.1第5节对资源请求的要求。具体来说:
- MCP客户端必须使用Authorization请求头字段 第5.1.1节:
Authorization: Bearer <access-token>
请注意,授权必须包含在从客户端到服务器的每个HTTP请求中,即使它们是同一逻辑会话的一部分。
- 访问令牌不得包含在URI查询字符串中
请求示例:
GET /v1/contexts HTTP/1.1
Host: mcp.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
2.5.2 令牌处理
资源服务器必须按照第5.2节所述验证访问令牌。如果验证失败,服务器必须按照第5.3节错误处理要求进行响应。无效或过期的令牌必须收到HTTP 401响应。
2.6 安全考虑
必须实施以下安全要求:
- 客户端必须按照OAuth 2.0最佳实践安全存储令牌
- 服务器应当强制执行令牌过期和轮换
- 所有授权端点必须通过HTTPS提供服务
- 服务器必须验证重定向URI以防止开放重定向漏洞
- 重定向URI必须是localhost URL或HTTPS URL
2.7 错误处理
服务器必须为授权错误返回适当的HTTP状态码:
状态码 | 描述 | 用途 |
---|---|---|
401 | 未授权 | 需要授权或令牌无效 |
403 | 禁止 | 无效的作用域或权限不足 |
400 | 错误请求 | 授权请求格式错误 |
2.8 实施要求
- 实现必须遵循OAuth 2.1安全最佳实践
- 所有客户端必须使用PKCE
- 应当实施令牌轮换以增强安全性
- 根据安全要求,令牌生命周期应当受到限制
2.9 第三方授权流程
2.9.1 概述
MCP服务器可以通过第三方授权服务器支持委托授权。在此流程中,MCP服务器既是OAuth客户端(对第三方授权服务器),又是OAuth授权服务器(对MCP客户端)。
2.9.2 流程描述
第三方授权流程包括以下步骤:
- MCP客户端与MCP服务器启动标准OAuth流程
- MCP服务器将用户重定向到第三方授权服务器
- 用户通过第三方服务器进行授权
- 第三方服务器重定向回MCP服务器并附带授权码
- MCP服务器交换授权码获取第三方访问令牌
- MCP服务器生成与第三方会话绑定的自身访问令牌
- MCP服务器完成与MCP客户端的原始OAuth流程
sequenceDiagram
participant B as 用户代理(浏览器)
participant C as MCP客户端
participant M as MCP服务器
participant T as 第三方授权服务器
C->>M: 初始OAuth请求
M->>B: 重定向到第三方 /authorize
B->>T: 授权请求
Note over T: 用户授权
T->>B: 重定向到MCP服务器回调
B->>M: 授权码
M->>T: 交换授权码获取令牌
T->>M: 第三方访问令牌
Note over M: 生成绑定的MCP令牌
M->>B: 重定向到MCP客户端回调
B->>C: MCP授权码
C->>M: 交换授权码获取令牌
M->>C: MCP访问令牌
2.9.3 会话绑定要求
实施第三方授权的MCP服务器必须:
- 维护第三方令牌与已发行MCP令牌之间的安全映射
- 在信任MCP令牌前验证第三方令牌状态
- 实施适当的令牌生命周期管理
- 处理第三方令牌过期和更新
2.9.4 安全考虑
实施第三方授权时,服务器必须:
- 验证所有重定向URI
- 安全存储第三方凭据
- 实施适当的会话超时处理
- 考虑令牌链接的安全影响
- 为第三方授权失败实施适当的错误处理
3. 最佳实践
3.1 作为公共OAuth 2.1客户端的本地客户端
我们强烈建议本地客户端实现OAuth 2.1作为公共客户端:
- 利用代码挑战(PKCE)进行授权请求,以防止拦截攻击
- 实施适合本地系统的安全令牌存储
- 遵循令牌刷新最佳实践以维持会话
- 正确处理令牌过期和更新
3.2 授权元数据发现
我们强烈建议所有客户端实现元数据发现。这减少了用户手动提供端点或客户端回退到定义的默认值的需求。
3.3 动态客户端注册
由于客户端无法预先知道所有MCP服务器集合,我们强烈建议实现动态客户端注册。这允许应用程序自动向MCP服务器注册,并消除了用户手动获取客户端ID的需要。