ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

FastMCP Discord OAuth 实战:用 DiscordProvider 保护 MCP 服务器并完成客户端认证

FastMCP Discord OAuth 实战:用 DiscordProvider 保护 MCP 服务器并完成客户端认证 FastMCP Discord OAuth 实战用 DiscordProvider 保护 MCP 服务器并完成客户端认证【免费下载链接】fastmcp The fast, Pythonic way to build MCP servers and clients.项目地址: https://gitcode.com/GitHub_Trending/fa/fastmcp导读本篇技术指南基于 FastMCP 仓库中的 Discord OAuth 示例完整讲解如何用 Discord 账号体系为 FastMCP 服务器开启 OAuth 保护从 Discord Developer Portal 创建应用、配置环境变量到用DiscordProvider启动受保护服务器、用Client(authoauth)完成浏览器授权全流程。读完本文你将掌握 Discord OAuth 端到端集成的完整实操方案并能理解其背后的 OAuth Proxy 代理原理与 Token 校验机制。Discord OAuth 与 FastMCP 的集成方式Discord 是 MCP 生态中常见的第三方身份提供方。由于 Discord 不支持 Dynamic Client Registration动态客户端注册FastMCP 采用OAuth ProxyOAuth 代理模式来桥接 Discord 的传统 OAuth 与 MCP 的认证要求服务器自身充当 Discord 与 MCP 客户端之间的中间层统一负责授权端点转发、Token 换取、校验与用户信息提取。从源码看DiscordProvider直接继承自OAuthProxy见 discord.py并预置了 Discord 的授权端点授权端点https://discord.com/oauth2/authorizeToken 端点https://discord.com/api/oauth2/token这一设计意味着你只需提供client_id、client_secret和base_url三个核心参数即可获得一个开箱即用的 Discord OAuth 集成而不需要手动实现 OAuth 握手、Token 存储与刷新逻辑。前置准备在 Discord Developer Portal 创建应用按示例 README.md 的步骤先到 Discord 开发者平台注册一个 OAuth 应用打开https://discord.com/developers/applications点击New Application并填写一个用户可识别的名称例如 My FastMCP Server在左侧边栏进入OAuth2页面在Redirects区域点击Add Redirect添加回调地址http://127.0.0.1:8000/auth/callback本地开发。生产环境应改为https://your-domain.com/auth/callback且必须使用 HTTPS在同一页面复制Client ID数字字符串与Client Secret可通过 Reset Secret 生成。注意Discord 要求回调地址必须与服务端配置完全一致。默认回调路径是/auth/callback如需自定义可通过DiscordProvider的redirect_path参数修改。Discord 允许http://localhost/127.0.0.1形式的地址用于本地开发。配置凭据环境变量的正确用法示例通过两个环境变量注入凭据README.mdexport FASTMCP_SERVER_AUTH_DISCORD_CLIENT_IDyour-client-id export FASTMCP_SERVER_AUTH_DISCORD_CLIENT_SECRETyour-client-secret需要特别说明的是FastMCP v3 起已移除 auth provider 对环境变量的自动加载机制。在 v2.x 中provider 会通过pydantic-settings自动读取FASTMCP_SERVER_AUTH_PROVIDER_前缀的环境变量而 v3.0 改为完全显式传参由开发者自己通过os.environ读取详见 auth-provider-env-vars.md。示例代码正是这一约定的体现auth DiscordProvider( client_idos.getenv(FASTMCP_SERVER_AUTH_DISCORD_CLIENT_ID) or , client_secretos.getenv(FASTMCP_SERVER_AUTH_DISCORD_CLIENT_SECRET) or , ... )这种设计让参数来源可追踪、更易维护同时也意味着如果你在未设置环境变量时直接运行示例provider 会以空字符串初始化认证将失败。生产环境建议使用 secrets manager 或 dotenv 等工具管理凭据切勿提交到版本控制。服务端实现用 DiscordProvider 保护 MCP 服务器完整代码见 server.py核心逻辑非常简洁import os from fastmcp import FastMCP from fastmcp.server.auth.providers.discord import DiscordProvider auth DiscordProvider( client_idos.getenv(FASTMCP_SERVER_AUTH_DISCORD_CLIENT_ID) or , client_secretos.getenv(FASTMCP_SERVER_AUTH_DISCORD_CLIENT_SECRET) or , base_urlhttp://127.0.0.1:8000, # redirect_path/auth/callback, # 默认路径使用其他回调地址时修改 ) mcp FastMCP(Discord OAuth Example Server, authauth) mcp.tool def echo(message: str) - str: Echo the provided message. return message if __name__ __main__: mcp.run(transporthttp, port8000)核心参数说明结合 DiscordProvider 构造函数 的源码常用参数如下参数必填默认值说明client_id是无Discord OAuth 应用的 Client IDclient_secret是无Discord OAuth 应用的 Client Secretbase_url是无OAuth 端点对外可访问的公共 URL含挂载路径本地开发为http://127.0.0.1:8000redirect_path否/auth/callback与 Discord 应用中配置的回调路径一致required_scopes否[identify]请求的 Discord scope 列表可传字符串或列表timeout_seconds否10调用 Discord API 校验 Token 的超时时间issuer_url否等于base_urlOAuth 元数据中的 issuer 地址路径挂载时建议使用根级 URL 避免发现流程 404jwt_signing_key否由上游 client secret 派生用于签发 FastMCP JWT Token 的密钥client_storage否数据目录下的加密文件存储OAuth 状态客户端注册、加密 Token的存储后端require_authorization_consent否True是否要求用户在授权前看到同意确认页仅限本地开发或测试可设为False从源码看当required_scopes为None时provider 默认使用[identify]获取用户名、头像、discriminator 等资料传入字符串形式的 scope 会被parse_scopes自动解析见 discord.py。启动方式与 README 一致python server.py等价地也可用 CLI 形式fastmcp run server.py --transport http --port 8000。服务器将以 HTTP transport 运行在 8000 端口所有 MCP 请求都会先经过 Discord OAuth 认证保护。客户端实现authoauth 触发完整授权流程客户端代码见 client.pyimport asyncio from fastmcp.client import Client SERVER_URL http://127.0.0.1:8000/mcp async def main(): try: async with Client(SERVER_URL, authoauth) as client: assert await client.ping() print(✅ Successfully authenticated!) tools await client.list_tools() print(f Available tools ({len(tools)}):) for tool in tools: print(f - {tool.name}: {tool.description}) except Exception as e: print(f❌ Authentication failed: {e}) raise if __name__ __main__: asyncio.run(main())关键点在于authoauth这个参数。从 客户端传输层源码 可以看到当auth oauth时FastMCP 会自动构造一个OAuth客户端认证器并绑定服务器 URL若传入的是普通字符串则被当作 Bearer Token 处理。Client构造器的auth参数类型为httpx2.Auth | Literal[oauth] | str | None见 client.pyoauth即触发完整的设备/浏览器授权流程。首次运行客户端时流程如下客户端连接http://127.0.0.1:8000/mcp并发现服务器的 OAuth 元数据你的默认浏览器自动打开 Discord 授权页面登录 Discord 账号并授权该应用授权完成后重定向回回调地址客户端拿到 Token后续请求携带 Tokenping()与list_tools()正常通过认证。Token 会被客户端本地缓存后续运行无需重复授权除非 Token 过期或显式清除缓存。Scopes控制可访问的用户数据范围Discord OAuth 通过 scope 控制应用可访问的数据范围参见 官方集成文档 的 scope 说明Scope说明identify访问用户名、头像、discriminator默认email访问用户邮箱地址guilds访问用户所在的服务器列表guilds.join将用户加入服务器的权限需要额外数据时通过required_scopes指定auth DiscordProvider( client_id..., client_secret..., base_urlhttp://127.0.0.1:8000, required_scopes[identify, email], )源码级原理Token 校验与安全边界DiscordProvider内部通过DiscordTokenVerifier完成 Token 校验discord.py。由于 Discord 的 OAuth Token 是不透明字符串而非 JWT校验器采用回调式验证策略携带Authorization: Bearer token调用 Discord 的https://discord.com/api/oauth2/me端点通过返回结果判断 Token 有效性并依次检查过期时间解析返回的expiresISO 时间戳已过期则拒绝scope 覆盖校验 Token 携带的 scopes 是否包含required_scopes要求的全部权限客户端绑定校验 Token 所属应用 IDapplication.id与配置的expected_client_id一致防止跨应用 Token 混用。验证通过后Discord 用户信息id、username、avatar、email、verified、locale等会被写入AccessToken.claims供服务端依赖注入读取。这些安全边界均有对应测试验证test_discord.py初始化时正确绑定expected_client_idDiscordTokenVerifier与 provider 的 client ID 保持一致test_token_verifier_is_bound_to_provider_client_id来自不同 Discord 应用的 Token 会被明确拒绝test_rejects_token_from_different_discord_application上游端点被正确配置为 Discord 官方地址test_oauth_endpoints_configured_correctly。生产环境配置持久化与加密示例面向本地开发生产部署需考虑 Token 与客户端注册在服务重启后仍然有效。DiscordProvider提供两个配套参数详见 docs/integrations/discord.mdx 的生产配置小节jwt_signing_key用于签发 FastMCP JWT 的密钥。示例未提供时框架会用上游 client secret 通过 PBKDF2 派生 32 字节密钥显式配置后Token 签发不再依赖上游密钥的派生结果稳定性更高client_storageOAuth 状态客户端注册信息、加密后的 Token的存储后端。默认为数据目录下的加密文件存储生产环境可替换为 Redis 等持久化后端并用FernetEncryptionWrapper对敏感 Token 做静态加密。生产配置示例import os from fastmcp import FastMCP from fastmcp.server.auth.providers.discord import DiscordProvider from key_value.aio.stores.redis import RedisStore from key_value.aio.wrappers.encryption import FernetEncryptionWrapper from cryptography.fernet import Fernet auth DiscordProvider( client_id12345, client_secretos.environ[DISCORD_CLIENT_SECRET], base_urlhttps://your-production-domain.com, jwt_signing_keyos.environ[JWT_SIGNING_KEY], client_storageFernetEncryptionWrapper( key_valueRedisStore( hostos.environ[REDIS_HOST], portint(os.environ[REDIS_PORT]), ), fernetFernet(os.environ[STORAGE_ENCRYPTION_KEY]), ), ) mcp FastMCP(nameProduction Discord App, authauth)务必用FernetEncryptionWrapper包裹存储后端否则 OAuth Token 将以明文落盘。生产环境还应通过fastmcp_access_token_expiry_seconds等参数调优 Token 生命周期以适配不同 MCP 客户端的刷新行为。小结通过本文的示例你已经掌握了一条完整的 FastMCP Discord OAuth 集成链路在 Discord Developer Portal 创建应用并配置回调地址用环境变量注入client_id/client_secret通过DiscordProvider一行开启服务器保护使用Client(url, authoauth)自动拉起浏览器完成授权理解 scope、Token 校验与生产级持久化配置。示例代码可直接查看 examples/auth/discord_oauth/ 目录下的 server.py 与 client.py更深层的实现细节与测试用例可分别阅读 DiscordProvider 源码 和 test_discord.py。【免费下载链接】fastmcp The fast, Pythonic way to build MCP servers and clients.项目地址: https://gitcode.com/GitHub_Trending/fa/fastmcp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表