你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
本教程介绍如何通过模型上下文协议(MCP)公开 ASP.NET 核心应用的功能,将其作为工具添加到 GitHub Copilot,并在 Copilot Chat 代理模式下使用自然语言与应用交互。
如果 Web 应用程序已具有有用的功能(如购物、酒店预订或数据管理),则可以轻松地使这些功能可供以下功能使用:
- 支持 MCP 集成的任何应用程序,例如 Visual Studio Code 或 GitHub Codespaces 中的 GitHub Copilot Chat 代理模式。
- 使用 MCP 客户端访问远程工具的自定义代理。
通过将 MCP 服务器添加到 Web 应用,可以在代理响应用户提示时了解和使用应用的功能。 这意味着你的应用可以执行的任何操作,智能助手也可以执行。
- 将 MCP 服务器添加到 Web 应用。
- 在 GitHub Copilot Chat 代理模式下本地测试 MCP 服务器。
- 将 MCP 服务器部署到 Azure 应用服务,并在 GitHub Copilot Chat 中连接到它。
先决条件
本教程假定你使用的是教程中使用的示例 :将 ASP.NET Core 和 Azure SQL 数据库应用部署到 Azure 应用服务。
至少,在 GitHub Codespaces 中打开 示例应用程序 ,并通过运行 azd up来部署应用。
将 MCP 服务器添加到 Web 应用
在 codespace 终端中,将 NuGet
ModelContextProtocol.AspNetCore包添加到项目:dotnet add package ModelContextProtocol.AspNetCore --prerelease创建 McpServer 文件夹,并使用以下代码在其中创建 TodosMcpTool.cs 。
using DotNetCoreSqlDb.Data; using DotNetCoreSqlDb.Models; using Microsoft.EntityFrameworkCore; using System.ComponentModel; using ModelContextProtocol.Server; namespace DotNetCoreSqlDb.McpServer { [McpServerToolType] public class TodosMcpTool { private readonly MyDatabaseContext _db; public TodosMcpTool(MyDatabaseContext db) { _db = db; } [McpServerTool, Description("Creates a new todo with a description and creation date.")] public async Task<string> CreateTodoAsync( [Description("Description of the todo")] string description, [Description("Creation date of the todo")] DateTime createdDate) { var todo = new Todo { Description = description, CreatedDate = createdDate }; _db.Todo.Add(todo); await _db.SaveChangesAsync(); return $"Todo created: {todo.Description} (Id: {todo.ID})"; } [McpServerTool, Description("Reads all todos, or a single todo if an id is provided.")] public async Task<List<Todo>> ReadTodosAsync( [Description("Id of the todo to read (optional)")] string? id = null) { if (!string.IsNullOrWhiteSpace(id) && int.TryParse(id, out int todoId)) { var todo = await _db.Todo.FindAsync(todoId); if (todo == null) return new List<Todo>(); return new List<Todo> { todo }; } var todos = await _db.Todo.OrderBy(t => t.ID).ToListAsync(); return todos; } [McpServerTool, Description("Updates the specified todo fields by id.")] public async Task<string> UpdateTodoAsync( [Description("Id of the todo to update")] string id, [Description("New description (optional)")] string? description = null, [Description("New creation date (optional)")] DateTime? createdDate = null) { if (!int.TryParse(id, out int todoId)) return "Invalid todo id."; var todo = await _db.Todo.FindAsync(todoId); if (todo == null) return $"Todo with Id {todoId} not found."; if (!string.IsNullOrWhiteSpace(description)) todo.Description = description; if (createdDate.HasValue) todo.CreatedDate = createdDate.Value; await _db.SaveChangesAsync(); return $"Todo {todo.ID} updated."; } [McpServerTool, Description("Deletes a todo by id.")] public async Task<string> DeleteTodoAsync( [Description("Id of the todo to delete")] string id) { if (!int.TryParse(id, out int todoId)) return "Invalid todo id."; var todo = await _db.Todo.FindAsync(todoId); if (todo == null) return $"Todo with Id {todoId} not found."; _db.Todo.Remove(todo); await _db.SaveChangesAsync(); return $"Todo {todo.ID} deleted."; } } }上述代码使用以下特定属性为 MCP 服务器提供工具:
-
[McpServerToolType]:将TodosMcpTool类标记为 MCP 服务器工具类型。 它向 MCP 框架发出信号,表明此类包含应作为可调用工具公开的方法。 -
[McpServerTool]:将方法标记为 MCP 服务器的可调用作。 -
[Description]:这些为方法和参数提供人工可读的说明。 它可以帮助调用代理了解如何来使用操作及其参数。
此代码复制了现有
TodosController代码的功能,这是不必要的,但为了简单起见,你将保留它。 最佳做法是将应用逻辑移到服务类,然后既从TodosController调用服务方法,又从TodosMcpTool调用服务方法。-
在 Program.cs中,注册 MCP 服务器服务和 CORS 服务。
builder.Services.AddMcpServer() .WithHttpTransport() // With streamable HTTP .WithToolsFromAssembly(); // Add all classes marked with [McpServerToolType] builder.Services.AddCors(options => { options.AddDefaultPolicy(policy => { policy.AllowAnyOrigin() .AllowAnyHeader() .AllowAnyMethod(); }); });在 MCP 服务器上使用可流式传输的 HTTP 时,如果要使用客户端浏览器工具或 GitHub Copilot(在 Visual Studio Code 和 GitHub Codespaces 中)进行测试,则需要启用跨域资源共享(CORS)。
在 Program.cs中,启用 MCP 和 CORS 中间件。
app.MapMcp("/api/mcp"); app.UseCors();此代码将 MCP 服务器终结点设置为
<url>/api/mcp。
在本地测试 MCP 服务器
在 codespace 终端中,使用
dotnet run.. 运行应用程序。在 浏览器中选择“打开”,然后添加任务。
保持
dotnet run运行状态。 现在,您的 MCP 服务器正在http://localhost:5093/api/mcp运行。返回代码空间,打开 Copilot Chat,然后在提示框中选择 代理 模式。
选择 “工具 ”按钮,然后在下拉列表中选择“ 添加更多工具...” 。
选择 “添加 MCP 服务器”。
选择 HTTP(HTTP 或服务器发送的事件)。
在 Enter 服务器 URL 中,键入 http://localhost:5093/api/mcp。
在 Enter 服务器 ID 中,键入 todos-mcp 或任何喜欢的名称。
选择 工作区设置。
在新的 Copilot 对话助手窗口中,键入类似于“显示待办事项”的内容。
默认情况下,GitHub Copilot 在调用 MCP 服务器时会显示安全确认。 选择继续。
现在应会看到一个响应,指示 MCP 工具调用成功。
将 MCP 服务器部署到应用服务
返回 codespace 终端,通过提交更改(GitHub Actions 方法)或运行
azd up(Azure 开发人员 CLI 方法)来部署更改。在 AZD 输出中,找到应用的 URL。 该 URL 在 AZD 输出中如下所示:
Deploying services (azd deploy) (✓) Done: Deploying service web - Endpoint: <app-url>
azd up完成后,打开 .vscode/mcp.json。 将 URL 更改为<app-url>/api/mcp。在修改后的 MCP 服务器配置上方,选择“ 开始”。
启动新的 GitHub Copilot 聊天窗口。 你应该能够在 Copilot 代理中查看、创建、更新和删除任务。
安全最佳做法
当 MCP 服务器由由大型语言模型(LLM)提供支持的代理调用时,请注意 提示注入 攻击。 请考虑以下安全最佳做法:
- 身份验证和授权:使用 Microsoft Entra 身份验证保护 MCP 服务器,以确保只有经过授权的用户或代理才能访问工具。 有关分步指南,请参阅 使用 Microsoft Entra 身份验证通过 Visual Studio Code 对 Azure 应用服务的安全模型上下文协议调用 。
- 输入验证和清理:本教程中的示例代码省略输入验证和清理,以便简单明了。 在生产方案中,始终实现适当的验证和清理来保护应用程序。 有关 ASP.NET Core,请参阅 ASP.NET Core 中的模型验证。
- HTTPS: 此示例依赖于 Azure 应用服务,该服务默认强制实施 HTTPS,并提供免费的 TLS/SSL 证书来加密传输中的数据。
- 最低特权原则:仅公开用例所需的工具和数据。 除非必要,否则避免公开敏感操作。
- 速率限制和限制:使用 API 管理 或自定义中间件来防止滥用和拒绝服务攻击。
- 日志记录和监视:用于审核和异常检测的 MCP 终结点的日志访问和使用情况。 监视可疑活动。
- CORS 配置:如果从浏览器访问 MCP 服务器,请将跨域请求限制为受信任的域。 有关详细信息,请参阅 “启用 CORS”。
- 常规更新:使依赖项保持最新,以缓解已知漏洞。