ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

使用 MCP Python SDK 编写带 OAuth 认证的 MCP 客户端(simple-auth-client 实战解析)

2026/9/20 15:37:40 拓冰建站 浏览量
使用 MCP Python SDK 编写带 OAuth 认证的 MCP 客户端(simple-auth-client 实战解析) 使用 MCP Python SDK 编写带 OAuth 认证的 MCP 客户端simple-auth-client 实战解析【免费下载链接】python-sdkThe official Python SDK for Model Context Protocol servers and clients项目地址: https://gitcode.com/gh_mirrors/pythonsd/python-sdk导读本示例演示如何基于 Model Context ProtocolMCP官方 Python SDK 编写一个带有OAuth 2.0 认证能力的 MCP 客户端并支持StreamableHTTP 与 SSE 两种传输方式。通过本篇文章你将掌握从零启动一个带认证的 MCP 服务端、驱动客户端完成浏览器授权、以及在交互式命令行中列工具与调用工具的完整链路并深入理解 SDK 中OAuthClientProvider底层实现 PKCE、动态客户端注册、令牌刷新等机制的原理。示例概览examples/clients/simple-auth-client/README.md 定位为simple-auth服务端示例的配套客户端是理解MCP OAuth集成方式的最小可运行范例。它具备三大核心特性OAuth 2.0 认证 PKCE采用授权码模式authorization code grant并携带 PKCEProof Key for Code Exchange参数适合无后端秘密的桌面型/本地 CLI 客户端双传输支持同时支持 StreamableHTTP 与 SSE 两种 MCP 传输协议通过环境变量一键切换交互式命令行界面连接成功后提供list、call、quit三个命令便于快速验证工具枚举与工具调用。该客户端本质上是 SDK 中OAuthClientProvider位于 src/mcp/client/auth/oauth2.py的薄封装认证逻辑全部交由 SDK 完成示例自身只负责本地回调服务器、浏览器跳转与交互循环。项目结构与依赖客户端代码位于examples/clients/simple-auth-client/目录下结构非常精简examples/clients/simple-auth-client/ ├── README.md ├── pyproject.toml └── mcp_simple_auth_client/ ├── __init__.py └── main.py # 全部逻辑OAuth 回调、会话管理、交互命令pyproject.toml 中的关键配置依赖click8.2.0与mcpSDK 本身requires-python 3.10入口脚本mcp-simple-auth-client mcp_simple_auth_client.main:cli即安装后可直接以uv run mcp-simple-auth-client运行构建系统使用hatchlingwheel 打包mcp_simple_auth_client包。安装cd examples/clients/simple-auth-client uv sync --reinstalluv sync会根据 pyproject.toml 与仓库根目录的 uv.lock 创建虚拟环境并安装依赖--reinstall强制重新安装确保与当前 SDK 源码保持一致。环境准备先启动支持 OAuth 的 MCP 服务器客户端无法单独运行必须连接到一个支持 OAuth 的 MCP 服务器。examples/servers/simple-auth/README.md 提供了三种服务器配置用于演示新、旧两代 MCP OAuth 架构。方案 A新架构推荐——认证服务器与资源服务器分离新架构遵循RFC 9728规范将 OAuth 职责拆分为两个独立进程# 终端 1在 9000 端口启动 Authorization Server认证服务器 cd examples/servers/simple-auth uv run mcp-simple-auth-as --port9000 # 终端 2在 8001 端口启动 Resource ServerMCP 资源服务器并指向认证服务器 cd examples/servers/simple-auth uv run mcp-simple-auth-rs --port8001 --auth-serverhttp://localhost:9000 --transportstreamable-httpAuthorization ServerAS提供 OAuth 2.0 的注册registration、授权authorization、令牌交换token exchange端点并暴露/introspect令牌内省端点供资源服务器校验令牌内置基于简单凭据的认证方式无需外部身份提供商Resource ServerRS即真正的 MCP 服务器提供工具调用能力并通过--auth-server参数关联 AS。生产环境可追加--oauth-strict开启 RFC 8707 严格资源校验。方案 B旧架构向后兼容——Legacy 一体化服务器为了兼容旧版 MCP 实现旧规范允许 MCP 服务器自身可选地提供 OAuth仓库提供了一体化的 legacy 服务器# 单个服务器同时充当 AS 与 RS默认端口 8000 cd examples/servers/simple-auth uv run mcp-simple-auth-legacy --port8000 --transportstreamable-http新旧两种架构的核心差异如下维度新架构AS/RS 分离Legacy 一体化OAuth 端点提供方独立 Authorization Server如 :9000MCP 服务器自身令牌校验方式RS 通过/introspect内省 AS 校验本地校验无内省RFC 9728 支持提供/.well-known/oauth-protected-resource不提供OAuth 元数据发现走 RFC 9728 发现流程直接在 MCP 服务器 URL 上发现启动带 OAuth 的客户端安装完成后即可在examples/clients/simple-auth-client/目录下启动客户端。客户端通过环境变量确定连接目标具体解析逻辑见 mcp_simple_auth_client/main.py 中的main()函数# 连接新架构 Resource Server默认端口 8001 MCP_SERVER_PORT8001 uv run mcp-simple-auth-client # 连接 Legacy 服务器端口 8000即默认值 uv run mcp-simple-auth-client # 改用 SSE 传输此时连接 /sse 端点 MCP_SERVER_PORT8001 MCP_TRANSPORT_TYPEsse uv run mcp-simple-auth-client客户端会根据传输类型自动拼接 URLStreamableHTTP 走http://localhost:port/mcpSSE 走http://localhost:port/sse。连接成功后OAuthClientProvider会自动执行发现、注册、授权、换发令牌等动作无需人工干预。完整 OAuth 交互流程客户端启动后会打开系统默认浏览器跳转到授权页。完成认证后即可在终端使用交互命令list列出服务器可用的工具工具名 描述call tool_name [args]以可选 JSON 参数调用工具quit退出客户端。一次典型的完整会话输出如下摘自 README 示例 Simple MCP Auth Client Connecting to: http://localhost:8001/mcp Transport type: streamable-http Attempting to connect to http://localhost:8001/mcp... Opening StreamableHTTP transport connection with auth... Opening browser for authorization: http://localhost:9000/authorize?... ✅ Connected to MCP server at http://localhost:8001/mcp mcp list Available tools: 1. get_time Description: Get the current server time. mcp call get_time Tool get_time result: {current_time: 2024-01-15T10:30:00, timezone: UTC, ...} mcp quit手动验证底层端点可选若想确认认证链路的每一步都符合预期可以用curl直接探测两个关键发现端点参考 examples/servers/simple-auth/README.md# Resource Server 的受保护资源元数据新架构 curl http://localhost:8001/.well-known/oauth-protected-resource # {resource: http://localhost:8001, authorization_servers: [http://localhost:9000]} # Authorization Server 的 OAuth 元数据 curl http://localhost:9000/.well-known/oauth-authorization-server # {issuer: http://localhost:9000, authorization_endpoint: http://localhost:9000/authorize, token_endpoint: http://localhost:9000/token}拿到令牌后还可以直接验证内省端点curl -X POST http://localhost:9000/introspect \ -H Content-Type: application/x-www-form-urlencoded \ -d tokenyour_access_token配置项速查表环境变量说明默认值MCP_SERVER_PORTMCP 服务器端口号8000MCP_TRANSPORT_TYPE传输类型streamable-http或ssestreamable-httpMCP_CLIENT_METADATA_URL可选的客户端元数据 URLCIMDURL 型客户端标识无其中MCP_CLIENT_METADATA_URL对应 SDK 中 URL-based client IDCIMD能力当授权服务器声明支持client_id_metadata_document_supported时SDK 会直接以该 URL 作为client_id跳过动态客户端注册详见下文。源码级原理剖析客户端如何完成 OAuth1. 令牌存储TokenStorage协议与内存实现SDK 在 src/mcp/client/auth/oauth2.py 中定义了TokenStorage协议要求实现四个异步方法读写OAuthToken、读写OAuthClientInformationFull。示例中的 InMemoryTokenStorage 是它的最简实现——把令牌与客户端注册信息保存在内存字段中。实际生产场景可替换为文件、数据库或密钥环存储接口不变。2. 本地回调服务器捕获授权码由于本地 CLI 客户端没有公网回调地址示例用 Python 标准库http.server在3030 端口CallbackServer见 main.py启动一个本地 HTTP 服务专门接收授权服务器跳转回http://localhost:3030/callback的授权码。CallbackHandler解析查询参数成功时提取code、state、iss返回 200 并渲染授权成功页面2 秒后自动关闭窗口失败时提取error参数并返回 400既无code也无error则返回 404。捕获到的参数被封装为 SDK 定义的AuthorizationCodeResult见 src/mcp/shared/auth.py含code/state/iss三个字段交给认证处理器完成后续流程。3.OAuthClientProvider五步授权流程客户端在 main.py 中实例化OAuthClientProvider传入服务器地址去掉/mcp路径、客户端元数据、令牌存储、重定向处理器与回调处理器。该类的核心实现在 src/mcp/client/auth/oauth2.py收到 401 或 403insufficient_scope挑战后会在内部执行一个完整的五步流程发现受保护资源元数据PRM按 SEP-985 的 URL 回退链请求/.well-known/oauth-protected-resource解析出授权服务器列表并按 RFC 8707 校验资源标识发现 OAuth 授权服务器元数据OASM请求授权服务器的/.well-known/oauth-authorization-server拿到authorization_endpoint与token_endpointlegacy 服务器在该端点返回 404 时自动回退到直接发现应用 scope 选择策略合并服务器在 WWW-Authenticate 挑战中声明的 scope 与客户端元数据中的 scope客户端注册优先使用 CIMDURL 型客户端标识否则走 RFC 7591 动态客户端注册注册后校验token_endpoint_auth_method是否可用执行授权与令牌交换构造/authorize授权 URL 交由redirect_handler打开浏览器等待回调后携带 PKCEcode_verifier换取访问令牌。4. PKCE 与安全校验授权请求中的 PKCE 参数由 PKCEParameters.generate 生成code_verifier为 128 个字符的随机串code_challenge采用 SHA-256 摘要的 base64url 编码符合 RFC 7636 要求。此外SDK 在回调返回后还执行了两项关键校验见 oauth2.pystate 防 CSRF用secrets.compare_digest常量时间比较回调state与发起请求时生成的随机值不匹配即抛出OAuthFlowErrorRFC 9207 签发者校验回调若携带iss参数会与预期的授权服务器签发者比对防止授权响应注入。5. 令牌刷新与 401 自动重试_auth_flowoauth2.py是整套流程的驱动核心每次请求前若令牌已过期且存在refresh_token会先尝试grant_typerefresh_token静默刷新刷新失败才触发完整重新授权。每次成功换发令牌都会调用storage.set_tokens持久化保证后续请求自动携带Authorization: Bearer token头。SDK 还会在刷新响应省略scope/refresh_token字段时沿用旧值保持令牌自描述对应 RFC 6749 §6 语义。6. CIMDURL 型客户端标识当设置了MCP_CLIENT_METADATA_URL且服务器支持时SDK 会直接以该 URL 作为client_id代码路径见 oauth2.py绕过动态注册。注意该 URL 必须是非根路径的有效 HTTPS URL否则OAuthClientProvider构造函数会直接抛出ValueErroroauth2.py。传输层集成双传输一键切换客户端按MCP_TRANSPORT_TYPE选择不同的传输构造方式见 main.pyStreamableHTTPhttpx2.AsyncClient(authoauth_auth)streamable_http_client(url, http_clientcustom_client)。认证处理器以 httpx auth 插件形式挂载每个请求自动完成令牌注入与 401 重试SSEsse_client(url, authoauth_auth, timeout60.0)认证能力以同等参数接入60 秒为 SSE 连接超时。两种方式最终都产出(read_stream, write_stream)流对交由ClientSessionmain.py完成initialize握手并进入交互循环因此认证逻辑对上层会话完全透明。小结simple-auth-client是零后端秘密的本地 OAuth MCP 客户端范本它把 PKCE 授权码流程、动态注册、令牌刷新等复杂逻辑全部交给 SDK 的OAuthClientProvider自身只需提供令牌存储、本地回调与交互界面三块薄壳。对照 src/mcp/client/auth/oauth2.py 阅读该示例可以快速掌握 MCP 客户端接入 OAuth 的标准姿势并可作为接入真实身份提供商替换为文件/数据库令牌存储即可的起点。若需深入了解服务端一侧的认证配置可继续阅读 docs/run/authorization.md 与 examples/servers/simple-auth/README.md。【免费下载链接】python-sdkThe official Python SDK for Model Context Protocol servers and clients项目地址: https://gitcode.com/gh_mirrors/pythonsd/python-sdk创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考