带有简易身份验证的Azure Functions MCP服务器
这个项目展示了如何部署一个 模型上下文协议(MCP)服务器 作为……的(一个) Azure Functions 自定义处理程序 使用 Azure 应用服务简易身份验证进行身份验证。
概述
这个MCP服务器提供:
- 添加工具基本算术运算
- 当前用户工具从Azure Easy Auth头部检索已认证的用户信息
- 动态问候资源根据用户情境提供的个性化问候
该服务器作为使用Azure Functions自定义处理程序的Node.js Express应用程序运行,能够在利用Azure的认证基础设施的同时,对HTTP请求/响应生命周期进行完全控制。
建筑学
flowchart LR
A["MCP Client
(Claude, etc.)"] --> B["Azure Function
(Easy Auth)"]
A --> D["Microsoft
Entra ID"]
B --> C["MCP Server
(Node.js/Express)"]
B --> D
style A fill:#2196F3,color:#fff
style B fill:#9C27B0,color:#fff
style C fill:#4CAF50,color:#fff
style D fill:#FF9800,color:#fff关键特性
认证头(Authentication Headers)
当通过Easy Auth进行身份验证时,会自动注入以下头部信息:
x-ms-client-principal包含完整用户声明的Base64编码JSONx-ms-client-principal-id用户标识符x-ms-client-principal-name用户显示名称x-ms-client-principal-idp身份提供者名称
MCP 工具
- 添加执行两个数的加法运算
- 获取当前用户从认证头中提取并返回用户信息
先决条件
- Azure CLI(Azure 命令行接口) 安装并配置
- Node.js 18+(成人内容)和npm(Node包管理器)
- Azure Functions 核心工具 v4.x
- Azure 订阅 具有适当的权限
项目结构
├── host.json # Azure Functions host configuration
├── local.settings.json # Local development settings
├── package.json # Node.js dependencies
├── tsconfig.json # TypeScript configuration
├── mcp-handler/
│ └── function.json # Function trigger configuration
└── src/
└── index.ts # MCP server implementation本地开发
1. 安装依赖项
npm install2. 配置本地设置
创建或更新 local.settings.json:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "node"
}
}3. 构建并运行
npm run build
func startMCP服务器将在 http://localhost:7071/mcp
Azure 部署
步骤1:创建资源组
# Azure CLI
az group create --name myMcpServerRG --location eastus2Azure 门户步骤:
- 导航至 资源组 > 创建
- 输入名称并选择区域
步骤2:创建函数应用
# Azure CLI
az functionapp create \
--resource-group myMcpServerRG \
--consumption-plan-location eastus2 \
--runtime node \
--runtime-version 18 \
--functions-version 4 \
--name myMcpServer \
--storage-account mystorageaccount123Azure 门户步骤:
- 导航至 函数应用 > 创建
- 选择 资源组:
myMcpServerRG - 函数应用名称:
myMcpServer - 运行时Node.js 18
- 托管消费计划
- 点击 回顾 + 创建
步骤3:部署函数代码
# Build the project
npm run build
# Deploy to Azure
func azure functionapp publish myMcpServer身份验证配置
概述
认证设置包括:
- Microsoft Entra ID 应用注册 - 身份提供者配置
- 用户分配的托管身份 - 为函数应用设置安全身份
- 轻松配置认证 - Azure 应用服务身份验证
步骤1:创建应用程序注册
Azure CLI(Azure 命令行接口)
# Create app registration
az ad app create \
--display-name "MyMcpServer-Auth" \
--sign-in-audience "AzureADMyOrg" \
--web-redirect-uris "https://myMcpServer.azurewebsites.net/.auth/login/aad/callback"
# Get the app ID (save this for later steps)
APP_ID=$(az ad app list --display-name "MyMcpServer-Auth" --query "[0].appId" -o tsv)
echo "App ID: $APP_ID"
# Create service principal
az ad sp create --id $APP_ID
# Federated credentials will be configured after creating the managed identityAzure 门户步骤
- 导航至 Microsoft Entra ID(原称Microsoft Azure Active Directory,简称Azure AD) > 应用程序注册 > 新注册
- 名字:
MyMcpServer-Auth - 支持的账户类型仅限此组织目录中的账户
- 重定向URI:
- 类型:网络 - URI:(统一资源标识符) https://myMcpServer.azurewebsites.net/.auth/login/aad/callback
- 点击 注册
- 复制 应用程序(客户端)ID
步骤2:创建用户分配的托管身份
Azure CLI(Azure 命令行接口)
# Create user assigned managed identity
az identity create \
--resource-group myMcpServerRG \
--name myMcpServer-uami
# Get the identity details
IDENTITY_ID=$(az identity show --resource-group myMcpServerRG --name myMcpServer-uami --query id -o tsv)
CLIENT_ID=$(az identity show --resource-group myMcpServerRG --name myMcpServer-uami --query clientId -o tsv)
PRINCIPAL_ID=$(az identity show --resource-group myMcpServerRG --name myMcpServer-uami --query principalId -o tsv)
echo "Identity Resource ID: $IDENTITY_ID"
echo "Client ID: $CLIENT_ID"
echo "Principal ID: $PRINCIPAL_ID"Azure 门户步骤
- 导航至 托管身份 > 创建
- 资源组:
myMcpServerRG - 名字:
myMcpServer-uami - 地区与函数应用相同
- 点击 复习+创作
- 复制 客户端ID 并且 对象(主体)ID
步骤3:为函数应用分配托管身份
Azure CLI(Azure 命令行接口)
# Assign user assigned managed identity to function app
az functionapp identity assign \
--resource-group myMcpServerRG \
--name myMcpServer \
--identities $IDENTITY_IDAzure 门户步骤
- 导航至您的 函数应用 > 设置 > 身份
- 选择 用户指定 制表符(或按Tab键)
- 点击 添加
- 选择您的托管身份:
myMcpServer-uami - 点击 添加
步骤3.1:配置联合凭据(推荐)
联合凭证通过在您的托管身份和应用程序注册之间建立信任关系,为客户端密钥提供了一种更安全的替代方案。
Azure CLI(Azure 命令行接口)
# Create federated credential for the managed identity
az ad app federated-credential create \
--id $APP_ID \
--parameters '{
"name": "myMcpServer-uami-federated-cred",
"issuer": "https://login.microsoftonline.com/'$(az account show --query tenantId -o tsv)'/v2.0",
"subject": "'$PRINCIPAL_ID'",
"description": "Federated credential for myMcpServer managed identity",
"audiences": ["api://AzureADTokenExchange"]
}'Azure 门户步骤
- 导航至您的 应用程序注册 > 证书与密钥
- 选择 联合凭证 制表符(或按Tab键)
- 点击 添加凭据
- 联合凭证场景其他发行方
- 发行者:
https://login.microsoftonline.com/{tenant-id}/v2.0 - 主题标识符输入 对象(主体)ID 您的托管身份
- 名字:
myMcpServer-uami-federated-cred - 描述用于myMcpServer托管身份的联合凭证
- 点击 添加
注当使用联合凭据时,您无需存储客户端密钥。托管身份将直接通过联合信任关系进行身份验证。
步骤4:配置Easy Auth
Azure CLI(Azure 命令行界面)
# Enable authentication with federated credentials
az webapp auth update \
--resource-group myMcpServerRG \
--name myMcpServer \
--enabled true \
--action RedirectToLoginPage \
--aad-client-id $APP_ID \
--aad-client-secret-setting-name OVERRIDE_USE_MI_FIC_ASSERTION_CLIENTID \
--aad-allowed-token-audiences "api://$APP_ID"
# Note: When using federated credentials, the OVERRIDE_USE_MI_FIC_ASSERTION_CLIENTID
# setting tells Easy Auth to use the managed identity's federated credential
# instead of a traditional client secretAzure 门户步骤
- 导航至您的 函数应用 > 设置 > 认证
- 点击 添加身份提供者
- 身份提供者微软
- 应用注册类型选择一个现有的应用程序注册
- 应用程序注册选择您的应用注册
- 客户端应用程序需求允许来自特定客户端应用程序的请求
- 允许的客户端应用程序输入 应用程序ID 从第一步开始
- 身份要求允许来自特定身份的请求
- 允许的身份输入 对象(主体)ID 您所管理的身份
- 限制访问需要认证
- 未认证的请求HTTP 401 未授权
- 令牌存储已启用(已勾选)
- 点击 添加
步骤5:配置应用程序注册API和权限
Azure CLI(Azure 命令行接口)
# Set the Application ID URI
az ad app update --id $APP_ID --identifier-uris "api://$APP_ID"
# Note: Adding oauth2PermissionScopes via CLI requires careful JSON formatting
# It's recommended to use the Azure Portal for scope configuration or use a JSON file
# Example with JSON file approach:
# az ad app update --id $APP_ID --set api.oauth2PermissionScopes=@scopes.json
# where scopes.json contains the scope definition
# Add Microsoft Graph User.Read permission
az ad app permission add \
--id $APP_ID \
--api 00000003-0000-0000-c000-000000000000 \
--api-permissions e1fe6dd8-ba31-4d61-89e7-88639da4683d=Scope
# Grant admin consent
az ad app permission admin-consent --id $APP_ID
# Enable implicit grant flow for tokens (required for Easy Auth)
az ad app update --id $APP_ID --enable-access-token-issuance true
az ad app update --id $APP_ID --enable-id-token-issuance trueAzure 门户步骤
配置API暴露:
- 导航至您的 应用注册 > 公开一个API
- 应用程序ID URI点击 设定;套装 并接受默认值(
api://{app-id}) - 范围(或“作用域”)添加一个范围
- 范围名称: user_impersonation - 管理员同意显示名称访问MCP服务器 - 管理员同意说明以已登录用户的身份访问MCP服务器 - 用户同意显示名称访问MCP服务器 - 用户同意说明允许该应用程序代表您访问MCP服务器 - 国家已启用
配置API权限: 4\. 去到 API权限 5\. 验证 用户读取 已存在对 Microsoft Graph 的委托权限 6\. 点击 为\[您的组织\]授予管理员同意
配置身份验证: 7\. 前往 认证 8\. 在……之下/低于 隐式授权和混合流程:
- ✅ 访问令牌 (用于隐式流)
- ✅ 身份令牌 (用于隐式和混合流)
授权客户端应用程序(可选): 8\. 在 公开一个API > 授权的客户端应用程序 9\. 添加任何无需用户同意即可访问您MCP服务器的预先授权应用程序
配置参考
关键设置
基于参考实现 antchu-test-mcp-auth-win:
| 设置 | 值 | 描述 |
|---|---|---|
| 客户端ID | 12345678-1234-1234-1234-123456789abc | 应用注册客户端ID |
| 应用程序ID URI | api://12345678-1234-1234-1234-123456789abc API的唯一标识符 | |
| 登录受众群体 | AzureADMyOrg | 单租户应用程序 |
| 重定向URI | https://{app-name}.azurewebsites.net/.auth/login/aad/callback | Easy Auth 回调 URL |
| 发行方/发行者 | https://login.microsoftonline.com/{tenant-id}/v2.0 | 令牌发行者URL |
| 令牌存储(或令牌库) | 已启用 | 存储令牌以供后续使用 |
| 未认证操作 | RedirectToLoginPage | 重定向到登录页面 |
| 允许的令牌受众 | api://{client-id} | 有效的令牌受众 |
| 运行时版本 | ~1 | 认证运行时 |
| 认证方法 | 联邦凭据 | 使用托管身份信任(无密钥) |
| 联合凭证主体 | 87654321-4321-4321-4321-abcdef123456 | 管理的标识主体 ID |
| 访问令牌版本 | 2 | 使用v2.0访问令牌 |
| 隐式授权 | 启用了访问令牌和ID令牌 | Easy Auth 所需 |
| API 范围 | user_impersonation | 委托的权限范围 |
环境变量
对于带有认证模拟的本地开发:
{
"Values": {
"OVERRIDE_USE_MI_FIC_ASSERTION_CLIENTID": "11111111-2222-3333-4444-555555555555",
"WEBSITE_AUTH_ENABLED": "true",
"WEBSITE_AUTH_DEFAULT_PROVIDER": "azureactivedirectory"
}
}应用注册清单密钥属性
根据实际配置,以下是重要的清单属性:
{
"appId": "12345678-1234-1234-1234-123456789abc",
"signInAudience": "AzureADMyOrg",
"identifierUris": ["api://12345678-1234-1234-1234-123456789abc"],
"api": {
"requestedAccessTokenVersion": 2,
"oauth2PermissionScopes": [
{
"adminConsentDescription": "user_impersonation",
"adminConsentDisplayName": "user_impersonation",
"id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"isEnabled": true,
"type": "User",
"value": "user_impersonation"
}
]
},
"web": {
"redirectUris": [
"https://antchu-test-mcp-auth-win.azurewebsites.net/.auth/login/aad/callback"
],
"implicitGrantSettings": {
"enableAccessTokenIssuance": true,
"enableIdTokenIssuance": true
}
},
"requiredResourceAccess": [
{
"resourceAppId": "00000003-0000-0000-c000-000000000000",
"resourceAccess": [
{
"id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d",
"type": "Scope"
}
]
}
]
}测试身份验证
1. 测试未认证请求
curl https://myMcpServer.azurewebsites.net/mcp
# Should return 401 Unauthorized or redirect to login2. 在浏览器中进行测试
导航至: https://myMcpServer.azurewebsites.net/mcp
- 应重定向到微软登录页面
- 认证通过后,应返回MCP服务器的响应
3. 测试用户信息
经过认证后,MCP(管理控制点/多协议控制器等,具体含义根据上下文确定) get_current_user 工具应返回:
{
"authenticated": true,
"user": {
"id": "user-principal-id",
"name": "user@domain.com",
"identityProvider": "aad",
"authType": "aad",
"claims": [...]
}
}故障排除
常见问题
- 401 未授权
- 验证应用程序注册客户端ID与认证配置是否匹配 - 检查托管身份是否已正确分配 - 确保允许的客户端应用程序包含正确的应用程序ID - 如果使用联合凭据,请验证主题标识符是否与托管身份主体ID匹配
- 认证循环
- 验证重定向URI是否完全匹配: https://{app-name}.azurewebsites.net/.auth/login/aad/callback - 检查应用程序注册是否已配置为正确的租户
- 缺失的用户索赔
- 验证令牌存储已启用 - 检查API权限是否包含User.Read - 确保已获得管理员同意
- 联邦凭证颁发
- 验证发行者URL是否与您的租户匹配: https://login.microsoftonline.com/{tenant-id}/v2.0 - 确保主题标识符是托管身份的主体ID(而非客户端ID) - 检查观众设置是否为 api://AzureADTokenExchange
- 功能未启动
- 检查 host.json 自定义处理程序设置的配置 - 验证 package.json 构建脚本 - 在 Azure 门户中查看函数应用日志
调试命令
# Check function app authentication status
az webapp auth show --name myMcpServer --resource-group myMcpServerRG
# View function app logs
az webapp log tail --name myMcpServer --resource-group myMcpServerRG
# Test function locally with auth headers
curl -X POST http://localhost:7071/mcp \
-H "Content-Type: application/json" \
-H "x-ms-client-principal-name: test@example.com" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'安全考虑因素
- 联合凭证使用加密信任关系,而非存储的秘密——无需管理或轮换秘密
- 令牌验证Easy Auth 自动处理令牌验证
- 仅使用HTTPS在生产环境中始终使用HTTPS
- 最小特权原则授予最小必要权限
- 令牌过期配置适当的令牌有效期
- 托管身份安全联合凭据消除了存储机密信息的需求
成本考量
- 函数应用每执行一次的消费计划费用
- 托管身份无需额外费用
- Easy Auth(易认证)无需额外费用
- Microsoft Entra ID免费套餐通常足够使用
下一步行动
- 自定义声明为基于角色的访问权限向令牌添加自定义声明
- 多个供应商支持额外的身份提供商
- API管理添加Azure API管理以获取高级功能
- 监测为遥测实施 Application Insights
- 持续集成/持续交付(CI/CD)建立自动化部署流水线
资源
许可证
此项目采用MIT许可证授权,请参阅LICENSE文件了解详情。
