VS Code MCP 认证示例
一个完整的参考实现,展示了如何在VS Code中使用OAuth 2.1认证构建一个安全的MCP(模型上下文协议)服务器。
 
🎯 本项目的功能
这个项目展示了如何构建一个可投入生产的(系统/应用) MCP服务器 (它)运行着 在用户本地机器上,与……集成 VS Code(Visual Studio Code,简称VS Code),并使用 OAuth 2.1 认证 (PKCE流程) 配合 Azure AD(Azure Active Directory,Azure活动目录) 作为身份提供者。
主要特点:
- ✅ 专为……设计 本地部署 (在用户机器上与 VS Code 并行运行)
- ✅ 完整的OAuth 2.1授权码流程,支持PKCE(无需客户端密钥)
- ✅ 使用官方实现的MCP服务器
@modelcontextprotocol/sdk - ✅ HTTP传输 - 与VS Code的MCP客户端兼容
- ✅ 通过Microsoft Graph API introspection进行令牌验证
- ✅ 准备就绪的生产级安全模式
- ✅ 具有完整类型安全的TypeScript
部署模型: 这台服务器设计为本地运行(例如 http://localhost:3000)。 对于远程服务器部署,请参阅下文的“我们如何实现OAuth”部分。
重要提示: VS Code 使用其自带的硬编码客户端ID(aebc6443-996d-45c2-90f0-388ff96faa56,定义于 extensions/microsoft-authentication/src/AADHelper.ts在获取令牌时,使用的是API,而不是您的MCP服务器的客户端ID。这意味着您将收到Microsoft Graph API令牌,而不是仅针对您应用程序作用域的令牌。有关完整的技术解释、源代码证据和解决方案,请参阅下面的“挑战#2”。
📖 故事:万物如何协同运作
挑战
构建一个具备OAuth认证的、可投入生产的MCP服务器,该服务器能够与 VS Code(Visual Studio Code) 这个过程很复杂。虽然MCP规范定义了对OAuth的支持,但在实际应用中,很少有示例展示如何将其集成到VS Code中。VS Code的MCP客户端具有特定的行为(如使用其自己的客户端ID),而这些行为在其他地方并未文档化。此项目解决了开发者在为VS Code构建OAuth认证的MCP服务器时面临的两大主要挑战:
1. 缺少OAuth + MCP + VS Code集成示例
问题: 虽然MCP规范包含了对OAuth的支持,但几乎没有完整的、可运行的示例来展示如何实现一个与(其他系统)集成的、通过OAuth认证的MCP服务器 VS Code大多数文档都集中在MCP协议本身或通用的OAuth流程上,但并未涉及:
- 如何处理 VS Code 的特定 OAuth 实现
- VS Code的MCP客户端在认证过程中的行为表现
- 如何使用VS Code自身的客户端ID进行处理(参见挑战#2)
- 如何验证VS Code发送的Microsoft Graph API令牌
我们的解决方案: 此项目提供了一个完整且可直接投入生产的参考实现,专门用于VS Code集成,展示了:
- 如何在VS Code中实现带PKCE的OAuth 2.1授权码流程
- 如何集成VS Code可识别的OAuth元数据发现(RFC 9728)
- 如何使用Bearer令牌认证保护MCP终端点
- 如何处理VS Code的客户端ID行为和Graph API令牌
- 如何使用VS Code的MCP客户端管理完整的身份验证生命周期
2. 微软图谱API令牌验证(最大的惊喜)
问题: 这是最令人惊讶的挑战。你可能会预期,当VS Code通过你的MCP服务器的OAuth流程进行用户身份验证时,它会使用 您的MCP服务器的客户端ID 为了获取代币。但实际情况并非如此。
惊喜发现:VS Code 使用其自身的客户端 ID
相反,VS Code 使用 其自带的硬编码客户端ID (aebc6443-996d-45c2-90f0-388ff96faa56) 以获取令牌,完全忽略您MCP服务器上注册的客户端ID。
来自VS Code源代码的证据:
这种行为在 VS Code 的 Microsoft 认证扩展中是硬编码的:
- 文件:
extensions/microsoft-authentication/src/AADHelper.ts() - 常量:
DEFAULT_CLIENT_ID = 'aebc6443-996d-45c2-90f0-388ff96faa56' - 行为: VS Code 的
getClientId()除非你传递一个特殊的范围标记,否则该方法会使用这个默认值VSCODE_CLIENT_ID:your-id这不属于标准的OAuth,也不是MCP服务器所执行的操作
工作原理:
当VS Code检测到您的MCP服务器使用Microsoft Entra(Azure AD)进行OAuth认证时,它会使用其内置的Microsoft身份验证提供程序。该提供程序会调用 vscode.authentication.getSession('microsoft', scopes),它总是使用VS Code内置的客户端ID来请求令牌。
相关的GitHub问题:
- #115626 - Microsoft 认证提供程序应支持覆盖客户端 ID
- #248775 API用于将认证服务器映射到认证提供者(用于MCP)
- 252892 - 功能:VSCode 能够为 MCP OAuth 注册客户端 ID
这意味着:
- ✅ OAuth流程使用您MCP服务器的授权端点
- ✅ 用户通过您的 Azure AD 租户进行身份验证
- ❌(这个符号在中文中通常没有直接的对应翻译,它表示“错误”或“取消”等意思,具体含义需根据上下文判断。) 但是访问令牌是为VS Code应用程序颁发的,而不是为您颁发的
- ❌ 代币受众是 Microsoft Graph API (
00000003-0000-0000-c000-000000000000),不是你的MCP服务器
认证流程(实际发生的情况):
1. MCP Server registers with: AZURE_CLIENT_ID=your-server-id
2. VS Code detects Microsoft Entra as the IdP
3. VS Code uses built-in Microsoft authentication provider
4. Provider calls: authentication.getSession('microsoft', scopes)
5. Internally uses: DEFAULT_CLIENT_ID = 'aebc6443-996d-45c2-90f0-388ff96faa56'
6. Azure AD issues token for VS Code's application
7. Token audience = '00000003-0000-0000-c000-000000000000' (Graph API)
8. MCP server receives this Graph API token, not a token for your app当你解码这个令牌时,你会看到:
{
"aud": "00000003-0000-0000-c000-000000000000", // Microsoft Graph API
"appid": "aebc6443-996d-45c2-90f0-388ff96faa56", // VS Code's client ID
"iss": "https://sts.windows.net/{your-tenant}/", // Your tenant
"scp": "User.Read openid profile email" // Graph API scopes
}为何这很重要:
这些Microsoft Graph API令牌(具有受众 00000003-0000-0000-c000-000000000000) 无法使用标准的JWT签名验证方法进行验证 由第三方服务提供 - 即使使用来自 Azure AD 的正确 JWKS 签名密钥。这是微软有意为之,以防止 Graph API 令牌被非 Microsoft Graph 的服务滥用。
大多数开发者尝试标准方法却陷入困境:
// ❌ This approach fails with "invalid signature"
jwt.verify(token, getSigningKey, {
issuer: 'https://sts.windows.net/{tenant}/',
audience: '00000003-0000-0000-c000-000000000000'
});
// Error: invalid signature (even though the key is correct!)我们的解决方案:通过图形API进行令牌反向查询
由于我们无法在本地验证签名,我们通过以下方式验证令牌: 调用Microsoft Graph API 其本身。如果API接受令牌并返回用户数据,我们就知道它是有效的:
// ✅ This works - Microsoft validates the token on their end
const response = await axios.get('https://graph.microsoft.com/v1.0/me', {
headers: { 'Authorization': `Bearer ${token}` },
});
// Success (200) = token is valid, returns user profile
// Failure (401) = token is invalid or expired为何这种方法是正确的:
- ✅ 微软在其服务器上执行加密验证
- ✅ 我们作为额外奖励获得了用户资料信息
- ✅ 立即捕获过期或被撤销的令牌
- ✅ 这是 微软官方推荐的方法 为图API令牌
- ✅ 我们为提升性能缓存了已验证的令牌(有效期5分钟)
摘要:
______________________________________________________________________
我们如何实现OAuth(本地部署使用PKCE)
由于这个MCP服务器正在运行 在用户本地机器上 (像 http://localhost:3000),我们使用 带有PKCE(Proof Key for Code Exchange,用于代码交换的证明密钥)的OAuth 2.1 而不是使用客户端密钥。
为何在本地部署中采用PKCE:
当您的服务器代码在用户机器上运行时,代码中的任何客户端密钥都可能被用户访问。PKCE通过使用加密的挑战/响应对来替代密钥,从而解决了这一问题:
User → VS Code → MCP Server → Azure AD
↓
PKCE Challenge
↓
Azure AD Login
↓
Authorization Code
↓
Exchange for Access TokenPKCE的优势:
- ✅ 无需客户端密钥(本地部署安全)
- ✅ 通过代码挑战/验证器对实现加密安全
- ✅ 公共客户端的标准OAuth 2.1
- ✅ 移动应用、单页应用(SPA)、桌面应用均采用相同模式
远程服务器的替代方案:
如果你在部署一个MCP服务器在 远程、安全的服务器 (非本地使用),您可以使用传统的 保密客户流程 而是使用客户端密钥。这个密钥是安全的,因为它存储在您的安全服务器上,终端用户无法访问。
🏗️ 建筑学
┌─────────────┐
│ VS Code │
│ (Client) │
└──────┬──────┘
│
│ 1. User triggers authentication
↓
┌─────────────────────────────────────────┐
│ MCP Server (This Project) │
│ │
│ ┌───────────────────────────────────┐ │
│ │ OAuth 2.1 PKCE Flow │ │
│ │ - /authorize (redirect to Azure) │ │
│ │ - /callback (exchange code) │ │
│ │ - PKCE challenge generation │ │
│ └───────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────┐ │
│ │ MCP HTTP Transport │ │
│ │ - POST /mcp (JSON-RPC) │ │
│ │ - GET /mcp (SSE) │ │
│ │ - Session management │ │
│ └───────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────┐ │
│ │ Authentication Middleware │ │
│ │ - Token structure validation │ │
│ │ - Graph API introspection │ │
│ │ - Token caching (5 min TTL) │ │
│ └───────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────┐ │
│ │ MCP Tools │ │
│ │ - get-user-info │ │
│ │ - echo │ │
│ └───────────────────────────────────┘ │
└─────────────────────────────────────────┘
│ │
│ │ 3. Validate token
│ ↓
│ ┌─────────────────┐
│ │ Microsoft Graph │
│ │ API │
│ └─────────────────┘
│
│ 2. OAuth flow
↓
┌─────────────┐
│ Azure AD │
│ (IdP) │
└─────────────┘🚀 快速入门
先决条件
- Node.js 18+(指18岁及以上)和npm(Node包管理器)
- Azure AD 租户 (免费套餐可用)
- VS Code(Visual Studio Code,简称VS Code) 带有MCP支持
1. 克隆并安装
git clone https://github.com/shiftrightlabs/vscode-mcp-auth-sample.git
cd vscode-mcp-auth-sample
npm install2. Azure AD 设置
- 首选 Azure 门户 → Azure Active Directory(Azure活动目录) → 应用程序注册
- 点击 新注册:
- 名字: MCP Server Auth Sample - 支持的账户类型: 仅限此组织目录中的帐户 - 重定向URI: - 平台: 网络 - URI:(统一资源标识符) http://localhost:3000/callback - 点击 注册
- 注册后:
- 复制 应用程序(客户端)ID - 复制 目录(租户)ID
- 配置 认证:
- 首选 认证 在左侧菜单中 - 在……之下 重定向URI,加: - http://localhost:3000/callback - http://127.0.0.1:3000/callback - 在……之下 隐式授权和混合流程,检查: - ✅ 身份令牌 - 点击 保存
- 配置 API权限:
- 首选 API 权限 在左侧菜单中 - 点击 添加一个权限 → Microsoft Graph → 委托权限 - 添加这些权限: - User.Read - openid - profile - email - 点击 添加权限 - 点击 授予管理员同意 (如果你有管理员权限)
3. 环境配置
创建一个 .env 在根目录中的文件:
cp .env.example .env编辑 .env 并填写您的 Azure AD 凭据:
# Azure AD Configuration
AZURE_CLIENT_ID=your-application-client-id-here
AZURE_TENANT_ID=your-directory-tenant-id-here
# Server Configuration
PORT=3000
SERVER_URL=http://localhost:3000重要提示:
AZURE_CLIENT_SECRET是 不必要 - 这是一个使用PKCE的公有客户端- 永远不要承诺
.env进行版本控制(已在.gitignore)
4. 构建并运行
# Build TypeScript
npm run build
# Start the server
npm start你应该看到:
MCP Server with OAuth running on http://localhost:3000
OAuth endpoints:
- Authorization: http://localhost:3000/authorize
- Callback: http://localhost:3000/callback
- OAuth Metadata: http://localhost:3000/.well-known/oauth-protected-resource
MCP endpoints:
- POST /mcp (JSON-RPC)
- GET /mcp (SSE)5. VS Code 配置
添加到你的VS Code settings.json:
{
"mcp.servers": {
"mcp-auth-sample": {
"url": "http://localhost:3000/mcp",
"authorization": {
"type": "oauth2",
"authorizationUrl": "http://localhost:3000/authorize"
}
}
}
}6. 测试认证
- 打开 VS Code
- 打开 MCP面板 (视图 → MCP 或 Ctrl+Shift+M)
- 你应该能看到“mcp-auth-sample”服务器
- 点击 认证
- 浏览器窗口打开 → 使用您的 Microsoft 帐户登录
- 成功认证后,您应该会看到:
✅ Discovered 2 tools7. 测试工具
一旦认证通过,您可以通过GitHub Copilot或任何支持MCP的AI助手来测试MCP工具。
工具: get-user-info
从访问令牌和Microsoft Graph API返回经过身份验证的用户信息。
触发此工具的示例提示:
- “显示我的已验证用户信息”
- “从访问令牌中,我的用户详细信息是什么?”
- “从 Microsoft Graph API 获取我的个人资料信息”
输出:
{
"title": "✅ Authenticated User Information",
"authentication": {
"method": "OAuth 2.0 Authorization Code with PKCE",
"client_type": "Public Client (no client secret)",
"token_validated": "via Microsoft Graph API introspection"
},
"token_claims": {
"issuer": "https://sts.windows.net/{tenant}/",
"subject": "...",
"audience": "00000003-0000-0000-c000-000000000000",
"scopes": ["User.Read", "openid", "profile", "email"]
},
"graph_api_user": {
"displayName": "Your Name",
"mail": "your.email@example.com",
"id": "...",
"userPrincipalName": "you@example.com"
}
}工具: echo
返回消息并附带认证确认。
触发此工具的示例提示:
- “回声这句话:你好,MCP!”
- “使用‘Authentication is working’测试回声工具”
- “你能重复一遍‘OAuth 2.1 PKCE非常棒’吗?”
输出:
Echo: Hello, MCP!
Authenticated via OAuth 2.0 PKCE📁 项目结构
vscode-mcp-auth-sample/
├── src/
│ ├── server.ts # Express app entry point
│ ├── config.ts # Configuration and validation
│ ├── oauth.ts # OAuth 2.1 PKCE flow
│ ├── metadata.ts # RFC 9728 metadata endpoint
│ ├── middleware/
│ │ └── auth.ts # Token validation middleware
│ └── mcp/
│ └── http-transport.ts # MCP HTTP transport & tools
├── dist/ # Compiled JavaScript (generated)
├── .env.example # Environment template
├── .env # Your credentials (git-ignored)
├── package.json # Dependencies and scripts
├── tsconfig.json # TypeScript configuration
├── CLAUDE.md # Project documentation for Claude Code
└── README.md # This file🔐 安全模型
使用PKCE的OAuth 2.1公共客户端
这个实现使用了 PKCE(用于代码交换的证明密钥) 而不是使用客户端密钥:
// 1. Generate code verifier (random string)
const codeVerifier = crypto.randomBytes(32).toString('base64url');
// 2. Generate code challenge (SHA256 hash)
const codeChallenge = crypto
.createHash('sha256')
.update(codeVerifier)
.digest('base64url');
// 3. Send challenge to Azure AD
const authUrl = `${authorizeUrl}?
client_id=${clientId}&
code_challenge=${codeChallenge}&
code_challenge_method=S256&
...`;
// 4. Azure AD validates: SHA256(code_verifier) === code_challenge好处:
- ✅ 无需客户端密钥(本地部署安全)
- ✅ 通过挑战/验证器对实现加密安全性
- ✅ 适用于在用户机器上运行的应用程序(MCP服务器、单页应用程序、移动应用、桌面应用)
- ✅ OAuth 2.1规范对公有客户端的要求
部署上下文: 这台服务器设计用于运行 本地地 (例如。, http://localhost:3000 (在用户的机器上)。对于远程服务器部署,如果代码对用户不可访问,您可以使用带有客户端密钥的保密客户端流。
令牌验证策略
挑战: Microsoft Graph API令牌无法使用标准JWT签名验证进行验证。
解决方案: 通过图形API进行令牌解析:
// 1. Validate token structure (issuer, expiration)
const payload = jwt.decode(token);
validateIssuer(payload.iss);
validateExpiration(payload.exp);
// 2. Introspect via Microsoft Graph API
const response = await axios.get('https://graph.microsoft.com/v1.0/me', {
headers: { 'Authorization': `Bearer ${token}` }
});
// 3. Cache validated tokens (5-minute TTL)
tokenCache.set(token, { user: response.data, validUntil: now + 5min });安全优势:
- ✅ 真实的加密验证(由微软验证服务器端)
- ✅ 已获取用户个人资料信息
- ✅ 令牌新鲜度检查(捕获已过期/已被撤销的令牌)
- ✅ 准备就绪可投入生产(无签名验证绕过)
🛠️ 开发
可用脚本
# Development mode (auto-reload with ts-node)
npm run dev
# Build TypeScript to JavaScript
npm run build
# Run compiled JavaScript
npm start
# Watch mode (auto-compile on changes)
npm run watch技术栈
- 运行时长: Node.js 18及以上版本
- 语言: TypeScript 5.3及以上版本
- 网络框架: Express 4.x
- MCP SDK:(MCP软件开发工具包)
@modelcontextprotocol/sdk1.20+ - HTTP 客户端: Axios
- 验证: 佐德
- 代币处理: JSON Web Token(简称JWT)
关键依赖项
{
"@modelcontextprotocol/sdk": "^1.20.1", // Official MCP SDK
"express": "^4.18.2", // Web server
"axios": "^1.6.5", // HTTP client (Graph API)
"jsonwebtoken": "^9.0.2", // JWT decoding
"zod": "^3.25.76" // Schema validation
}📚 了解更多
理解代码
理解一切运作方式的最佳途径是跟踪请求流程:
- OAuth 流程 (
src/oauth.ts)
- /authorize - 生成PKCE(Proof Key for Code Exchange)挑战,重定向到Azure AD - /callback - 验证PKCE验证器,用代码换取令牌
- MCP运输 (
src/mcp/http-transport.ts)
- 为每个会话创建传输实例 - 处理三个端点:POST、GET(SSE)、DELETE - 管理会话ID并进行清理
- 验证令牌结构和基本声明 - 调用 Microsoft Graph API 进行内省 - 缓存已验证的令牌以提高性能
- MCP 工具 (
src/mcp/http-transport.ts)
- get-user-info 演示令牌读取+图API访问 - echo - 简单的身份验证工具
标准与规范
这个实现遵循的是:
- MCP授权规范 (2025年6月18日)
- OAuth 2.1 - 带有PKCE的授权框架
- RFC 7636 - OAuth 2.0 的 PKCE(Proof Key for Code Exchange)
- RFC 9728 - OAuth 2.0 受保护资源元数据
- RFC 6750 - 载荷令牌的使用
为何采用这种方法?
为什么选择HTTP传输而不是stdio?
- VS Code 的 MCP 客户端使用的是 HTTP,而不是 stdio
- HTTP允许多个并发客户端
- 更适合生产环境部署
为什么使用 PKCE 而不是客户端密钥?
- 这台MCP服务器正在运行 在用户本地机器上 (代码对用户开放)
- 客户端密钥不能安全地存储在用户机器上运行的代码中
- PKCE 提供加密安全性,无需使用密钥
- OAuth 2.1 对公开客户端的要求
- 注:远程服务器可以使用客户端密钥(机密客户端流)
为什么使用Graph API内省而不是JWT验证?
- Microsoft Graph API令牌对第三方而言是设计上不可读的
- 标准JWT签名验证失败(即使使用了正确的密钥)
- 图形API内省是微软官方推荐的方法
🤝 贡献
欢迎贡献!这是一个教育项目,旨在帮助开发者了解MCP与OAuth的集成。
如何做出贡献
- 在 https://github.com/shiftrightlabs/vscode-mcp-auth-sample 上对该仓库进行 Fork 操作
- 克隆你的叉(分支)
git clone https://github.com/YOUR-USERNAME/vscode-mcp-auth-sample.git) - 创建一个特性分支(
git checkout -b feature/amazing-feature) - 进行你的更改并提交(
git commit -m 'Add amazing feature') - 推送到你的分支(fork)
git push origin feature/amazing-feature) - 在 https://github.com/shiftrightlabs/vscode-mcp-auth-sample/pulls 上打开一个拉取请求
📄 许可证
这个项目遵循以下许可协议: 麻省理工学院许可证(MIT License) - 看到 许可证 详情请查阅文件。
🙏 致谢
- Anthropic(公司名,可译为“安萨里克”或根据具体语境保留原名) - 用于创建和维护模型上下文协议(MCP)规范和软件开发工具包(SDK)
- 微软 针对Azure AD OAuth 2.0平台和Microsoft Graph API的文档
❓ 常见问题
问:如果 VS Code 使用其自己的客户端 ID,为什么我还需要注册一个 Azure AD 应用程序?
A: 很好的问题!尽管VS Code使用其自己的客户端ID来获取访问令牌,但你仍然需要注册你自己的Azure AD应用程序,因为:
- 您的MCP服务器的授权端点(
/authorize) OAuth流程需要一个客户端ID - 您应用程序注册中的租户ID决定了Azure AD租户中的哪些用户进行身份验证
- 您的重定向URI配置(
http://localhost:3000/callback) 必须与您的应用注册信息匹配
这样想:你的应用注册权限控制 哪个租户 并且 重定向URI 是被允许的。VS Code 随后利用这个 OAuth 流程,但在请求令牌时会使用自己的客户端 ID 替换掉原来的。
问:我可以让VS Code使用我MCP服务器的客户端ID,而不是它自己的吗?
A: 不,这是VS Code的Microsoft认证扩展中硬编码的(extensions/microsoft-authentication/src/AADHelper.ts)。 常数 DEFAULT_CLIENT_ID = 'aebc6443-996d-45c2-90f0-388ff96faa56' 默认使用。虽然从技术上讲,该代码支持 VSCODE_CLIENT_ID: 要覆盖这一点,可以使用范围标记,但这是一种非标准的OAuth模式,MCP服务器并不使用。如需更多详情,请参阅 。
问:为什么VS Code要这么做?
A:这允许VS Code使用Microsoft Graph API范围(如)获取令牌 User.Read) 以便其用于自身功能(如账户管理、设置同步等),同时仍然通过您的MCP服务器的OAuth流程对用户进行身份验证。这是一个设计决策,使得VS Code内置的身份验证提供程序能够在不同的扩展和MCP服务器之间保持一致,但这意味着MCP服务器必须处理Graph API令牌,而不是仅限于其自身应用程序的令牌。
问:这是否意味着我的客户端ID配置被忽略了?
A: 你的 AZURE_CLIENT_ID 仍然很重要!它用于:
- OAuth 元数据端点(
/.well-known/oauth-protected-resource) - 配置要使用的 Azure AD 租户(通过租户 ID)
- 在Azure AD中设置重定向URI
尽管最终的访问令牌使用了VS Code的客户端ID,但您的配置仍然控制着身份验证流程。
问:这是安全问题吗?
A: 不,这是有意为之。代币仍然是:
- 由您的Azure AD租户颁发(受您的租户ID控制)
- 通过Microsoft Graph API(加密安全)验证
- 限制在已认证用户范围内
- 仅可用于Microsoft Graph API调用(受众限制)
我们使用的Graph API内省模式是微软推荐的方法,用于验证这些令牌。
💬 支持
- 问题:
- 讨论:
🔗 资源
______________________________________________________________________
由ShiftRight Labs团队倾心打造,助力开发者构建安全的MCP服务器。
