- 教程
- 文档
- 人工智能
【免费下载链接】mcp-for-beginners
This open-source curriculum introduces the fundamentals of Model Context Protocol (MCP) through real-world, cross-language examples in .NET, Java, TypeScript, JavaScript, Rust and Python. Designed for developers, it focuses on practical techniques for building modular, scalable, and secure AI workflows from session setup to service orchestration.
本教程源自本开源课程 mcp-security-entra 章节,系统讲解如何为 Model Context Protocol(MCP)服务器接入 Microsoft Entra ID 认证,覆盖从本地
stdio服务器(公共客户端)到远程 HTTP 服务器(机密客户端)两大经典场景。读完本文,你将掌握 OAuth 2.0 认证的核心原理、MSAL 库的集成方式、两种客户端模型的选型依据,以及一套可直接落地复制的安全最佳实践清单。
为什么 MCP 服务器必须上锁:安全与 MCP
把 MCP 服务器暴露在公开环境中而不做任何认证,等同于把家门虚掩——任何人都可能推门而入。假设你的 MCP 服务器上有一个"发送邮件"工具,或一个能访问客户数据库的工具,那么未加保护的服务器意味着任何人都有可能调用这些工具,进而导致未授权数据访问、垃圾邮件泛滥,甚至更严重的恶意操作。
通过在服务器上实施认证(Authentication),你可以确保发往服务器的每一个请求都经过身份核验,确认发起请求的用户或应用确实"是谁"。这是保护 AI 工作流安全的第一道、也是最关键的一道防线。认证与授权是两个相辅相成的概念:
- 认证(Authentication):判断"你是否被允许进入"——即请求方是否有权访问承载 MCP 工具与数据的资源服务器;
- 授权(Authorization):判断"你被允许做什么"——即请求方能否访问其索取的特定资源(例如只能读取订单列表而不能删除)。
Microsoft Entra ID:面向 MCP 的云端身份与访问管理
Microsoft Entra ID 是一种云端的身份与访问管理(Identity and Access Management)服务,可以把它想象成你所有应用的"通用保安":它负责完成验证用户身份(认证)这一复杂过程,并决定用户被允许做什么(授权)。
对 MCP 服务器而言,使用 Entra ID 可以带来三方面能力:
- 为用户启用安全登录;
- 保护 API 与后端服务;
- 从统一位置集中管理访问策略。
对于 MCP 服务器来说,Entra ID 提供了一个健壮且被广泛信任的方案,用于管理"谁能使用服务器上的工具和数据"这一核心问题。在课程体系内,这一章节是渐进式安全学习的进阶环节——11-simple-auth 章节先从最基础的 Authorization 头认证讲起,再过渡到 JWT,最后明确指向:"采用 Entra 这样的 IdP 让我们把令牌签发、校验与生命周期管理交给可信平台",进而引向本文所讲的 Entra ID 进阶章节。
理解认证的"魔法":OAuth 2.0 与代客泊车钥匙
Entra ID 基于OAuth 2.0等开放标准来管理认证。细节虽然复杂,但核心概念用一个类比就能讲清楚。
代客泊车钥匙(Valet Key)类比
把 OAuth 2.0 想象成餐厅的代客泊车服务:你到达餐厅时,不会把主钥匙交给泊车员,而是交给一把代客泊车钥匙(Valet Key)——它拥有受限权限,可以启动汽车、锁车门,但打不开后备箱和手套箱。对应关系如下:
| 类比对象 | 实际角色 |
|---|---|
| 你 | 用户(User) |
| 你的汽车 | MCP 服务器(及其承载的工具与数据) |
| 泊车服务方 | Microsoft Entra ID |
| 停车接待员 | MCP 客户端(试图访问服务器的应用) |
| 代客泊车钥匙 | 访问令牌(Access Token) |
访问令牌是一串受保护的安全文本。MCP 客户端在你登录后从 Entra ID 获取它,并在每次请求时将它出示给 MCP 服务器。服务器可以校验令牌,确认请求合法且客户端具备所需权限——整个过程无需接触你的真实凭据(例如密码)。
认证流程全景图
整个流程在实操中的时序如下(该图同时包含了服务器侧对令牌的密码学校验环节,即服务器并不需要每次请求都回调 Entra ID):
这里有一个容易被误解的关键点:MCP 服务器并不会为每个访问令牌都回调 Entra ID 做在线校验。服务器从 OpenID Connect 元数据中读取jwks_uri,拉取并缓存 Entra ID 的公钥,然后本地密码学验证 JWT 签名,并校验令牌中的issuer(签发者)、audience(受众)与exp(有效期)等声明。为应对密钥轮换,服务器会周期性刷新公钥。强烈建议使用受支持的令牌校验库来完成这一逻辑,而不是自行实现签名验证。
认识 MSAL:Microsoft 认证库
在深入代码之前,需要先认识贯穿两个示例的核心组件——Microsoft Authentication Library(MSAL)。MSAL 是微软开发的认证库,把安全令牌处理、登录管理与会话刷新的复杂逻辑封装起来,开发者只需几行代码即可接入健壮的认证能力。推荐使用 MSAL 的原因有三:
- 安全:实现了行业标准协议与安全最佳实践,降低代码中的漏洞风险;
- 简化开发:屏蔽了 OAuth 2.0 与 OpenID Connect 的复杂度;
- 持续维护:微软会持续更新以应对新威胁与平台变化。
MSAL 支持 .NET、JavaScript/TypeScript、Python、Java、Go 以及 iOS/Android 等移动平台,意味着你可以在整个技术栈中使用一致的认证模式。
场景一:保护本地 MCP 服务器(公共客户端)
本地场景下的 MCP 服务器通过stdio与客户端通信,适合运行在用户本机(如桌面应用或本地开发服务器)。此场景使用公共客户端(Public Client)。示例服务器的核心功能是:先通过 Entra ID 认证用户,然后提供一个从 Microsoft Graph API 拉取用户档案信息的工具。
第一步:在 Entra ID 中注册应用
写代码之前,需要先在 Microsoft Entra 门户中注册应用,让 Entra ID 认识你的应用并允许其使用认证服务:
- 进入Microsoft Entra 门户;
- 打开应用注册(App registrations),点击新建注册(New registration);
- 为应用命名(例如 "My Local MCP Server");
- 支持的账户类型选择仅此组织目录中的账户(Accounts in this organizational directory only);
- 本例可将重定向 URI(Redirect URI)留空;
- 点击注册。
注册完成后,务必记录应用程序(客户端)ID(Application (client) ID)与目录(租户)ID(Directory (tenant) ID),代码中会用到。
第二步:代码拆解
完整的参考实现位于 mcp-auth-servers 仓库的entra-id-local-wam示例目录(此处为外部参考资源,本课程仓库内可对照学习 11-simple-auth 的基础认证演进过程)。
AuthenticationService.cs—— 与 Entra ID 交互的服务类
该类负责与 Entra ID 的全部交互,包含三个核心方法:
CreateAsync:初始化 MSAL 的PublicClientApplication,并配置应用的clientId与tenantId;WithBroker:启用 Broker(如 Windows Web Account Manager),提供更安全、更顺滑的单一登录(SSO)体验;AcquireTokenAsync:核心方法。首先尝试静默获取令牌(若用户已有有效会话则无需再次登录);若静默获取失败,则弹出窗口引导用户交互式登录。
// 为清晰起见做了简化 public static async Task<AuthenticationService> CreateAsync(ILogger<AuthenticationService> logger) { var msalClient = PublicClientApplicationBuilder .Create(_clientId) // 你的 Application (client) ID .WithAuthority(AadAuthorityAudience.AzureAdMyOrg) .WithTenantId(_tenantId) // 你的 Directory (tenant) ID .WithBroker(new BrokerOptions(BrokerOptions.OperatingSystems.Windows)) .Build(); // ... 缓存注册 ... return new AuthenticationService(logger, msalClient); } public async Task<string> AcquireTokenAsync() { try { // 优先尝试静默认证 var accounts = await _msalClient.GetAccountsAsync(); var account = accounts.FirstOrDefault(); AuthenticationResult? result = null; if (account != null) { result = await _msalClient.AcquireTokenSilent(_scopes, account).ExecuteAsync(); } else { // 无账户或静默失败时,转为交互式登录 result = await _msalClient.AcquireTokenInteractive(_scopes).ExecuteAsync(); } return result.AccessToken; } catch (Exception ex) { _logger.LogError(ex, "An error occurred while acquiring the token."); throw; // 可选:向上抛出以由上层统一处理 } }Program.cs—— MCP 服务器装配与认证服务集成
AddSingleton<AuthenticationService>:把AuthenticationService注册进依赖注入容器,供应用其他部分(如工具)使用;GetUserDetailsFromGraph工具:该工具要求注入AuthenticationService实例。在执行任何动作之前,它先调用authService.AcquireTokenAsync()获取有效访问令牌;认证成功后,用该令牌构造GraphServiceClient调用 Microsoft Graph API 拉取用户信息。
// 为清晰起见做了简化 [McpServerTool(Name = "GetUserDetailsFromGraph")] public static async Task<string> GetUserDetailsFromGraph( AuthenticationService authService) { try { // 触发认证流程 var accessToken = await authService.AcquireTokenAsync(); // 使用令牌构造 GraphServiceClient var graphClient = new GraphServiceClient( new BaseBearerTokenAuthenticationProvider(new TokenProvider(authService))); var user = await graphClient.Me.GetAsync(); return System.Text.Json.JsonSerializer.Serialize(user); } catch (Exception ex) { return $"Error: {ex.Message}"; } }第三步:完整工作链路
- MCP 客户端尝试调用
GetUserDetailsFromGraph工具,工具首先调用AcquireTokenAsync; AcquireTokenAsync触发 MSAL 检查是否已有有效令牌;- 若无令牌,MSAL 通过 Broker 提示用户使用 Entra ID 账户登录;
- 用户登录后,Entra ID 签发访问令牌;
- 工具拿到令牌,用它向 Microsoft Graph API 发起安全调用;
- 用户详情返回给 MCP 客户端。
这一流程确保只有通过认证的用户才能使用该工具,从而有效保护本地 MCP 服务器。
场景二:保护远程 MCP 服务器(机密客户端)
当 MCP 服务器运行在远程机器(如云服务器)上、通过 HTTP Streaming 等协议通信时,安全要求截然不同。此时必须使用机密客户端(Confidential Client)与Authorization Code Flow。这种方式更安全,因为应用的机密永远不会暴露给浏览器。示例采用 TypeScript 编写、以 Express.js 处理 HTTP 请求的 MCP 服务器。
版本提示:原课程明确指出,本节远程服务器的示例代码保护的是遗留的
/sse与/message端点,目标协议为 MCP2025-11-25。新实现应保留其中的身份与令牌校验实践,但改用与2026-07-28兼容的Streamable HTTP 传输。关于新版规范的授权相关变更(如客户端须校验授权响应中的iss参数、弃用动态客户端注册等),可参阅 What's Changed in MCP: The 2026-07-28 Specification。
第一步:在 Entra ID 中注册应用
设置过程与公共客户端类似,但有一个关键差异:需要创建客户端机密(Client Secret)。
- 进入Microsoft Entra 门户;
- 在应用注册中打开证书和机密(Certificates & secrets)选项卡;
- 点击新建客户端机密(New client secret),填写描述后点击添加;
- 重要:立即复制机密值——之后你将无法再次查看它;
- 还需配置重定向 URI:进入身份验证(Authentication)选项卡,点击添加平台(Add a platform),选择Web,并输入应用的重定向 URI(例如
http://localhost:3001/auth/callback)。
⚠️ 重要安全提示:对生产应用,微软强烈推荐使用**无秘密认证(Secretless Authentication)**方式,例如托管标识(Managed Identity)或工作负载身份联合(Workload Identity Federation),而不是客户端机密。客户端机密存在被泄露或攻破的风险;托管标识通过消除在代码或配置中存储凭据的需求,提供了更安全的方案。
第二步:代码拆解
本示例采用基于会话的方案:用户认证后,服务器把访问令牌与刷新令牌存入会话,并向用户发放一个会话令牌;后续请求都携带该会话令牌。完整参考实现位于 mcp-auth-servers 仓库的entra-id-cca-session示例目录。
Server.ts—— Express 服务器与 MCP 传输层
requireBearerAuth:保护/sse与/message端点的中间件,检查请求Authorization头中的有效 Bearer 令牌;EntraIdServerAuthProvider:实现McpServerAuthorizationProvider接口的自定义类,负责管理 OAuth 2.0 流程;/auth/callback:处理用户认证后来自 Entra ID 的重定向,将授权码(authorization code)兑换为访问令牌与刷新令牌。
// 为清晰起见做了简化 const app = express(); const { server } = createServer(); const provider = new EntraIdServerAuthProvider(); // 保护 SSE 端点 app.get("/sse", requireBearerAuth({ provider, requiredScopes: ["User.Read"] }), async (req, res) => { // ... 连接传输层 ... }); // 保护消息端点 app.post("/message", requireBearerAuth({ provider, requiredScopes: ["User.Read"] }), async (req, res) => { // ... 处理消息 ... }); // 处理 OAuth 2.0 回调 app.get("/auth/callback", (req, res) => { provider.handleCallback(req.query.code, req.query.state) .then(result => { // ... 处理成功或失败 ... }); });Tools.ts—— MCP 工具定义
getUserDetails工具与前一个示例类似,但访问令牌改为从会话中获取:
// 为清晰起见做了简化 server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name } = request.params; const context = request.params?.context as { token?: string } | undefined; const sessionToken = context?.token; if (name === ToolName.GET_USER_DETAILS) { if (!sessionToken) { throw new AuthenticationError("Authentication token is missing or invalid. Ensure the token is provided in the request context."); } // 从会话存储中取出 Entra ID 令牌 const tokenData = tokenStore.getToken(sessionToken); const entraIdToken = tokenData.accessToken; const graphClient = Client.init({ authProvider: (done) => { done(null, entraIdToken); } }); const user = await graphClient.api('/me').get(); // ... 返回用户详情 ... } });auth/EntraIdServerAuthProvider.ts—— OAuth 2.0 流程核心
该类负责处理四类逻辑:将用户重定向到 Entra ID 登录页;将授权码兑换为访问令牌;把令牌存入tokenStore;在访问令牌过期时用刷新令牌自动续期。
第三步:完整工作链路
- 用户首次尝试连接 MCP 服务器时,
requireBearerAuth中间件发现其没有有效会话,将其重定向到 Entra ID 登录页; - 用户使用 Entra ID 账户登录;
- Entra ID 携带授权码将用户重定向回
/auth/callback端点; - 服务器把授权码兑换为访问令牌与刷新令牌并存储,同时创建一个会话令牌发送给客户端;
- 客户端此后在所有对 MCP 服务器的请求中,都在
Authorization头携带该会话令牌; - 当调用
getUserDetails工具时,它用会话令牌查找对应的 Entra ID 访问令牌,再用该令牌调用 Microsoft Graph API。
该流程比公共客户端流程更复杂,但对于暴露在公网上的端点来说是必需的。远程 MCP 服务器可通过公共互联网访问,必须采用更强有力的安全措施来抵御未授权访问与潜在攻击。
安全最佳实践清单
无论哪种场景,以下安全实践都应当落实:
- 始终使用 HTTPS:加密客户端与服务器之间的通信,防止令牌被截获;
- 实施基于角色的访问控制(RBAC):不要只检查用户是否经过认证,还要检查有权做什么。可以在 Entra ID 中定义角色,并在 MCP 服务器中校验;
- 监控与审计:记录所有认证事件,以便发现并响应可疑活动;
- 处理速率限制与限流:Microsoft Graph 等 API 会实施速率限制以防滥用。在 MCP 服务器中实现指数退避(exponential backoff)与重试逻辑,优雅处理 HTTP 429(Too Many Requests);考虑缓存高频访问数据以减少 API 调用;
- 令牌安全存储:安全存储访问令牌与刷新令牌。本地应用使用系统级安全存储机制;服务器应用考虑使用加密存储或 Azure Key Vault 等密钥管理服务;
- 令牌过期处理:访问令牌生命周期有限。使用刷新令牌实现自动续期,在不要求重新认证的前提下维持流畅的用户体验;
- 考虑 Azure API Management:直接在 MCP 服务器中实现安全拥有精细控制力,但 APIM 这类 API 网关可以自动处理认证、授权、限流与监控等大量安全诉求,为客户端与 MCP 服务器之间提供一个集中式安全层。
仓库源码佐证:Spring Boot OAuth2 参考实现
课程仓库中提供了与本主题同源的落地参考:mcp-oauth2-demo。这是一个最小化 Spring Boot 应用,同时扮演两类角色:作为Spring Authorization Server(通过client_credentials流程签发 JWT 访问令牌)与资源服务器(保护自身/hello端点)。它的存在印证了 OAuth2 在 MCP 认证中的两个核心机制——令牌签发与令牌校验。
其安全配置源码 SecurityConfiguration.java 展示了关键实现:
- 通过
oauth2ResourceServer(...).jwt(...)启用资源服务器的 JWT 校验; jwkSource()在启动时生成 2048 位 RSA 密钥对,构建ImmutableJWKSet作为签名密钥源——这正对应前文"服务器本地缓存公钥、校验 JWT 签名"的原理;registeredClientRepository()以CLIENT_SECRET_BASIC认证方式注册mcp-client,仅开放client_credentials授权类型与mcp.access作用域,演示了机器对机器通信的最小权限模型。
对应的测试用例 SecurityConfigurationTest.java 验证了空clientId与空clientSecret均会触发IllegalArgumentException——从代码层面强制了"机密不得为空"这一基础安全约束。此外,apimoauth.md 还给出了将 Spring Auth Server 部署到 Azure Container Apps、并用 APIMvalidate-jwt策略做集中令牌校验的完整链路,可作为生产化网关方案(对应最佳实践中的 APIM 建议)的延伸阅读。
同时,课程 02-Security 章节给出了更宏观的安全上下文:MCP 服务器禁止接受任何并非明确签发给该 MCP 服务器的令牌(即禁止 token passthrough 反模式),并应校验令牌的 audience 声明与 MCP 服务器身份一致。这与本教程"服务器校验令牌的 issuer、audience 与有效期"的实践完全呼应。该章节还列出了 OWASP MCP Top 10 风险中的MCP07(认证与授权不足),其推荐的 Azure 缓解措施正是Entra ID 与 OAuth 2.1 + PKCE——进一步印证了本文方案在整体安全架构中的定位。
关键要点
- 保护 MCP 服务器对守护数据与工具至关重要;
- Microsoft Entra ID 为认证与授权提供了健壮、可扩展的方案;
- 本地应用使用公共客户端,远程服务器使用机密客户端;
- Authorization Code Flow是 Web 应用最安全的选择。
思考与动手练习
思考题:
- 设想一个你可能构建的 MCP 服务器:它是本地服务器还是远程服务器?
- 基于你的答案,你会选择公共客户端还是机密客户端?
- 你的 MCP 服务器针对 Microsoft Graph 执行操作时需要申请什么权限?
动手练习:
- 练习 1:在 Entra ID 中注册应用——进入 Microsoft Entra 门户,为 MCP 服务器注册新应用,记录 Application (client) ID 与 Directory (tenant) ID;
- 练习 2:保护本地 MCP 服务器(公共客户端)——按示例代码集成 MSAL 完成用户认证;通过调用"从 Microsoft Graph 拉取用户详情"的 MCP 工具测试认证流程;
- 练习 3:保护远程 MCP 服务器(机密客户端)——在 Entra ID 注册机密客户端并创建客户端机密;配置 Express.js MCP 服务器使用 Authorization Code Flow;测试受保护端点并确认基于令牌的访问;
- 练习 4:落地安全最佳实践——为本地或远程服务器启用 HTTPS;在服务器逻辑中实现 RBAC;加入令牌过期处理与安全令牌存储。
学习成果
完成本教程后,你将能够:解释认证为何对 MCP 服务器与 AI 工作流至关重要;为本地与远程 MCP 服务器场景配置 Entra ID 认证;根据服务器部署形态选择恰当的客户端类型(公共或机密);落实包括令牌存储与基于角色的授权在内的安全编码实践;自信地保护 MCP 服务器及其工具免受未授权访问。
继续深入
- 5.13 Model Context Protocol(MCP)与 Microsoft Foundry 集成
- 更完整的安全全景与 OWASP MCP Top 10:02-Security
- 从基础认证到 JWT 的渐进式实战:11-simple-auth
- 本主题对应的 OAuth2 演示工程与部署文档:mcp-oauth2-demo、apimoauth.md
- 教程
- 文档
- 人工智能
【免费下载链接】mcp-for-beginners
This open-source curriculum introduces the fundamentals of Model Context Protocol (MCP) through real-world, cross-language examples in .NET, Java, TypeScript, JavaScript, Rust and Python. Designed for developers, it focuses on practical techniques for building modular, scalable, and secure AI workflows from session setup to service orchestration.
相关推荐
用 Microsoft Entra ID 为 MCP 服务器构建企业级认证:mcp-for-beginners 实战指南
用 Microsoft Entra ID 为 MCP 服务器构建企业级认证:mcp for beginners 实战指南 Microsoft Entra ID
教程文档人工智能用 Microsoft Entra ID 保护 MCP 服务器:公共客户端与机密客户端的 OAuth 2.0 认证实战(mcp-for-beginners)
用 Microsoft Entra ID 保护 MCP 服务器:公共客户端与机密客户端的 OAuth 2.0 认证实战(mcp for beginners) !
教程文档人工智能mcp-for-beginners 实战指南:使用 Microsoft Foundry Toolkit 构建、调试与部署 MCP 服务器
mcp for beginners 实战指南:使用 Microsoft Foundry Toolkit 构建、调试与部署 MCP 服务器 本文以 mcp for
教程文档人工智能
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考