在单个 FastMCP 应用中挂载多套 OAuth 保护的 MCP 服务基于 RFC 8414 路径感知发现的多 Provider 认证实践【免费下载链接】fastmcp The fast, Pythonic way to build MCP servers and clients.项目地址: https://gitcode.com/GitHub_Trending/fa/fastmcp导读本文以 FastMCP 仓库中的 examples/auth/mounted 示例为核心讲解如何在单个 ASGI 应用中同时挂载多个由不同 OAuth ProviderGitHub、Google保护的 MCP 服务并借助RFC 8414 路径感知path-aware授权服务器元数据发现让每个挂载路径下的服务拥有独立的发现端点与回调地址。读完本文你将掌握多 Provider 挂载的 URL 规划、环境变量与重定向 URI 配置、http_app()/get_well_known_routes()的底层行为以及客户端如何通过authoauth逐一建立安全连接。背景为什么需要多 Provider 挂载在真实的 MCP 生产部署中一个网关进程往往要暴露多组能力各异的工具集例如一组工具需要访问 GitHub 资源、另一组工具需要调用 Google API。若把它们拆成多个独立进程分别启动运维成本与端口管理都会成倍增加。FastMCP 允许把多个各自携带auth配置的FastMCP实例挂载到同一个 Starlette 应用的不同路径下每个实例独立拥有自己的授权服务器、令牌端点与回调路径互不干扰。这正是examples/auth/mounted演示的场景GitHub 认证的 MCP 服务挂载在/api/mcp/githubGoogle 认证的 MCP 服务挂载在/api/mcp/google两者共享同一个uvicorn进程与端口8000。URL 架构服务端点与发现端点分离示例中两个服务形成了清晰的资源端点 发现端点双层结构见 examples/auth/mounted/README.md服务MCP 资源端点RFC 8414 路径感知发现端点GitHubhttp://127.0.0.1:8000/api/mcp/github/mcphttp://127.0.0.1:8000/.well-known/oauth-authorization-server/api/mcp/githubGooglehttp://127.0.0.1:8000/api/mcp/google/mcphttp://127.0.0.1:8000/.well-known/oauth-authorization-server/api/mcp/google注意两个关键设计点MCP 资源端点位于路径前缀之下/mcp是每个FastMCP.http_app(path/mcp)暴露的协议入口外层再由 Starlette 的Mount分别挂到/api/mcp/github与/api/mcp/google发现端点注册在根路径.well-known/oauth-authorization-server之后紧跟各服务的挂载路径/api/mcp/github、/api/mcp/google使每个授权服务器的元数据文档互不冲突客户端可根据服务地址自动定位到正确的发现端点。RFC 8414 路径感知发现源码级的实现原理所谓路径感知path-aware是指当授权服务器issuer本身位于 URL 的某个路径之下时其元数据端点不再是固定的/.well-known/oauth-authorization-server而是/.well-known/oauth-authorization-server{issuer_path}。在 fastmcp_slim/fastmcp/server/auth/auth.py 中OAuthProvider.get_well_known_routes()对该行为有精确实现若issuer_url带路径如http://127.0.0.1:8000/api/mcp/github则元数据路由被改写为/.well-known/oauth-authorization-server/api/mcp/github第 1030-1038 行同时按 RFC 8414 §5 注册路径感知的 OIDC 别名/.well-known/openid-configuration{issuer_path}第 1039-1046 行无论路径深度如何根路径的/.well-known/openid-configuration也会被注册以兼容根部署与反向代理剥前缀的场景第 1051-1063 行。而常规的授权端点/authorize、/token以及标准元数据路由由get_routes()生成见 auth.py它调用create_auth_routes()构建 SDK 路由再对元数据路由重建以让issuer字段报告真实的issuer_url并用符合 OAuth 2.1 错误码语义的自定义TokenHandler替换默认/token处理器。从源码结构看get_routes()与get_well_known_routes()的职责分工——操作端点挂载在服务路径下、发现端点挂载在根路径下——正是多 Provider 挂载能够共存的根基。服务端实现server.py 逐步拆解完整代码见 examples/auth/mounted/server.py核心流程分为四步。第一步从环境变量读取凭据并构造 Providergithub_auth GitHubProvider( client_idos.getenv(FASTMCP_SERVER_AUTH_GITHUB_CLIENT_ID) or , client_secretos.getenv(FASTMCP_SERVER_AUTH_GITHUB_CLIENT_SECRET) or , base_urlf{ROOT_URL}{API_PREFIX}/github, redirect_path/auth/callback/github, )GitHubProvider与GoogleProvider均继承自OAuthProxy见 github.py核心参数包括client_id、client_secret、base_url、resource_base_url、issuer_url、redirect_path、required_scopes、timeout_seconds与cache_ttl_seconds。其中base_url必须指向该服务实际的挂载前缀这里分别是/api/mcp/github与/api/mcp/googleOAuth 端点据此生成redirect_path是回调路径后缀最终回调地址为base_url redirect_path即http://127.0.0.1:8000/api/mcp/github/auth/callback/github。需要特别说明的是虽然环境变量仍沿用FASTMCP_SERVER_AUTH_*前缀但自 v3.0 起 FastMCP不再自动从环境变量加载 Provider 配置示例中的os.getenv(...)是显式读取参见仓库设计笔记 dev-docs/v3-notes/auth-provider-env-vars.md。缺失时传入空字符串可保证构造不抛错但认证握手会失败——这正是为了让你把os.getenv换成os.environ[...]或 dotenv 等方案时一目了然。第二步用 auth 参数创建两个 FastMCP 实例github_mcp FastMCP(GitHub Server, authgithub_auth) google_mcp FastMCP(Google Server, authgoogle_auth)每个实例通过auth绑定各自的 Provider随后用装饰器注册工具github_echo、github_info、google_echo、google_info工具集完全隔离。第三步生成 ASGI 子应用与发现路由github_app github_mcp.http_app(path/mcp) google_app google_mcp.http_app(path/mcp) github_well_known github_auth.get_well_known_routes(mcp_path/mcp) google_well_known google_auth.get_well_known_routes(mcp_path/mcp)http_app(path/mcp)将每个服务的 MCP 协议端点生成在/mcp见 fastmcp_slim/fastmcp/server/mixins/transport.pyget_well_known_routes(mcp_path/mcp)返回各服务路径感知的发现路由随后会被直接注册到 Starlette 根路由表。第四步用 Starlette 合并为一个应用app Starlette( routes[ *github_well_known, *google_well_known, Mount(f{API_PREFIX}/github, appgithub_app), Mount(f{API_PREFIX}/google, appgoogle_app), ], lifespangithub_app.lifespan, )两个发现路由列表展开到根路由表两个 MCP 子应用分别挂到各自前缀。最后用uvicorn.run(app, host0.0.0.0, port8000)启动lifespan复用其中一个子应用即可两者功能等价。配置清单环境变量与重定向 URI运行前需要为两个 Provider 分别设置凭据见 examples/auth/mounted/README.mdexport FASTMCP_SERVER_AUTH_GITHUB_CLIENT_IDyour-github-client-id export FASTMCP_SERVER_AUTH_GITHUB_CLIENT_SECRETyour-github-client-secret export FASTMCP_SERVER_AUTH_GOOGLE_CLIENT_IDyour-google-client-id export FASTMCP_SERVER_AUTH_GOOGLE_CLIENT_SECRETyour-google-client-secret随后在 GitHub / Google 各自的开发者控制台注册应用并配置带挂载前缀的重定向 URIGitHubhttp://127.0.0.1:8000/api/mcp/github/auth/callback/githubGooglehttp://127.0.0.1:8000/api/mcp/google/auth/callback/google由于服务被挂载在/api/mcp/{provider}下回调地址必须完整携带此前缀否则 OAuth 服务器收到的回调与注册的不一致握手会失败。运行与客户端连接启动服务端python server.py启动时终端会打印两个 MCP 端点与两个发现端点便于核对 URL 结构。连接客户端examples/auth/mounted/client.pypython client.py客户端为每个服务创建独立连接Client(url, authoauth)会先执行 OAuth 授权流程随后ping()验证令牌有效再用list_tools()列出各自暴露的工具async with Client(GITHUB_URL, authoauth) as client: assert await client.ping() tools await client.list_tools()输出将分别展示 GitHub 与 Google 两个服务的工具列表证明同一进程内两套认证体系独立且并行工作。关键注意事项issuer 路径必须与挂载路径一致base_url与redirect_path的组合决定了回调地址get_well_known_routes()依据issuer_url默认等于base_url推导发现端点路径任何一处不一致都会导致客户端发现失败发现端点务必注册在根路由表示例通过把*github_well_known、*google_well_known展开进根级routes实现若误将发现路由也塞进Mount前缀之下RFC 8414 客户端将无法解析元数据v3 不再自动加载环境变量示例中的os.getenv是显式读取而非框架魔法凭据缺失时服务可启动但认证必然失败排错时优先检查环境变量是否已导出回调地址带前缀Provider 控制台中的重定向 URI 必须写完整路径含/api/mcp/{provider}这是多挂载场景下最容易遗漏的一步。小结通过examples/auth/mounted可以看到一条清晰的多 Provider 挂载路径每个FastMCP(..., authprovider)实例用http_app(path/mcp)生成子应用、用get_well_known_routes()生成路径感知发现路由再由一个 Starlette 应用统一挂载与启动。借助 RFC 8414 的路径感知机制多套 OAuth 体系可以在单进程、单端口下各自独立完成发现、授权与回调是构建多租户或多能力 MCP 网关的可靠参考范式。【免费下载链接】fastmcp The fast, Pythonic way to build MCP servers and clients.项目地址: https://gitcode.com/GitHub_Trending/fa/fastmcp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
