Mcp已授权
概念验证(PoC)演示如何构建 C#MCP(模型上下文协议)服务器 随着 HTTP传输 和 认证,由 .NET Aspire 并由 钥匙锁.
概述
这 模型上下文协议(MCP) 是一个开放标准,允许人工智能模型安全地连接到外部工具和数据源。本项目展示了如何:
- 将MCP服务器作为ASP托管。NET Core web应用程序使用HTTP(流式HTTP)传输。
- 使用由颁发的JWT承载身份验证保护MCP端点 钥匙锁.
- 协调所有服务(MCP服务器+Keycloak) .NET Aspire.
- 导入预配置的Keycloak 领域 使测试快速且可重复。
- 使用现成的工具执行完整的身份验证和工具调用流程
.http文件.
建筑
┌────────────────────────────────────────────────────────────────┐
│ .NET Aspire AppHost │
│ │
│ ┌─────────────────────┐ ┌──────────────────────────┐ │
│ │ Keycloak (Docker) │◄────►│ McpAuthorized (ASP.NET) │ │
│ │ realm: api │ │ / → MCP endpoint │ │
│ │ client: mcp-user │ │ JWT Bearer validation │ │
│ └─────────────────────┘ └──────────────────────────┘ │
└────────────────────────────────────────────────────────────────┘- 钥匙锁 作为一个持久的Docker容器启动
api从自动导入的域McpAuthorized.AppHost/Realms/api-realm.json. - Mcp已授权 (MCP服务器)从其环境中读取Keycloak URL,并根据由颁发的JWT令牌验证每个传入请求
api王国。 - MCP服务器公开了一个工具(
get_random_number)通过POST /终点。
先决条件
| 要求 | 版本 |
|---|---|
| .NET SDK | 10.0+ |
| .NET Aspire工作负载 | 9.x/13.x预览 |
| 码头工人 | 任何最新版本 |
如果您还没有安装Aspire工作负载:
dotnet workload install aspire运行项目
cd McpAuthorized.AppHost
dotnet runAspire将:
- 拉动并启动 钥匙锁 港口集装箱
8080,自动导入api王国。 - 开始 Mcp已授权 web服务器(默认为
https://localhost:5092). - 在启动MCP服务器之前,请等待Keycloak恢复正常。
打开Aspire仪表板(控制台中打印的URL)以监控这两个服务。
钥匙斗篷配置
⚠️ 安全通知: api-realm.json 包含用于以下目的的硬编码客户端凭据 仅限于本地开发。切勿将此领域文件部署到共享或生产环境。在本地计算机之外使用此配置之前,请重新生成所有机密。这 api 域从导入 McpAuthorized.AppHost/Realms/api-realm.json。它预先配置了:
| 设置 | 值 |
|---|---|
| 领域 | api |
| 客户端ID | mcp-user |
| 客户端密码 | 7lrl6I10qLM5LaUUoLSI2KfBJoIsBWRg |
| 资助类型 | client_credentials |
| 范围 | mcp:tools |
MCP服务器配置为接受来自以下来源的令牌:
http:///realms/api并验证 aud (观众)声明包含 account.
身份验证流程
MCP服务器使用 MCP OAuth 2.0受保护的资源 图案:
- 客户端使用以下命令从Keycloak请求令牌
client_credentials赠款。 - 令牌作为
Bearer令牌在Authorization向MCP服务器发送的每个请求上的标头。 - 服务器通过标准验证令牌(颁发者、受众、生存期、签名)
JwtBearer中间件。 - 如果验证成功,则将请求转发到MCP管道。
使用HTTP文件进行测试
McpAuthorized/McpAuthorized.http 包含一个现成的请求序列,可以执行整个流程。您可以直接在中运行它们 Visual Studio, VS Code (使用REST客户端扩展),或 JetBrains骑手.
步骤1–获取令牌
POST http://localhost:8080/realms/api/protocol/openid-connect/token
Content-Type: application/x-www-form-urlencoded
client_id=mcp-user&client_secret=7lrl6I10qLM5LaUUoLSI2KfBJoIsBWRg&grant_type=client_credentials&scope=mcp:tools响应正文包含 access_tokenThe .http 文件将其存储为 {{login.response.body.$.access_token}} 以便在后续请求中使用。
步骤2–启动MCP会话
POST https://localhost:5092/
Authorization: Bearer {{login.response.body.$.access_token}}
MCP-Protocol-Version: 2025-11-25
Content-Type: application/json
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
...
}响应标头 Mcp-Session-Id 包含后续调用中使用的会话标识符。
步骤3–调用MCP工具
POST https://localhost:5092/
Authorization: Bearer {{login.response.body.$.access_token}}
MCP-Session-Id: {{NewSession.response.headers.Mcp-Session-Id}}
Content-Type: application/json
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": { "name": "get_random_number" }
}服务器返回一个介于0和99之间的随机整数(默认边界)。
项目结构
McpAuthorized.sln
│
├── McpAuthorized/ # MCP server (ASP.NET Core)
│ ├── Program.cs # Authentication & MCP setup
│ ├── Tools/
│ │ └── RandomNumberTools.cs # Example MCP tool
│ └── McpAuthorized.http # Test HTTP file
│
├── McpAuthorized.AppHost/ # .NET Aspire orchestration
│ ├── AppHost.cs # Defines Keycloak + MCP server
│ └── Realms/
│ └── api-realm.json # Keycloak realm import
│
└── McpAuthorized.ServiceDefaults/ # Shared Aspire service defaults
└── Extensions.cs关键包
| 包装 | 用途 |
|---|---|
ModelContextProtocol.AspNetCore | ASP的MCP服务器SDK。NET核心(HTTP传输) |
Aspire.Keycloak.Authentication | Aspire集成Keycloak JWT身份验证 |
Aspire.Hosting.Keycloak | Aspire托管扩展在Docker中运行Keycloak |
