共用方式為


將 App Service 應用程式整合為適用於 GitHub Copilot Chat 的 MCP 伺服器 (.NET)

在本教學課程中,您將瞭解如何透過模型內容通訊協定 (MCP) 公開 ASP.NET 核心應用程式的功能、將其新增為 GitHub Copilot 的工具,以及在 Copilot 聊天代理程式中使用自然語言與您的應用程式互動。

此螢幕快照顯示 Azure App Service 中裝載的 GitHub Copilot 呼叫 Todos MCP 伺服器。

如果您的 Web 應用程式已經有有用的功能,例如購物、旅館預訂或資料管理,很容易就能讓這些功能可供使用:

藉由將 MCP 伺服器新增至 Web 應用程式,您即可讓代理程式瞭解及使用應用程式在回應使用者提示時的功能。 這表示您的應用程式可以執行的任何動作,代理程式也可以執行。

  • 將 MCP 伺服器新增至 Web 應用程式。
  • 在 GitHub Copilot 聊天代理程式模式中本機測試 MCP 伺服器。
  • 將 MCP 伺服器部署至 Azure App Service,並在 GitHub Copilot Chat 中連線到它。

先決條件

本教學課程假設您使用教學 課程:將 ASP.NET Core 和 Azure SQL Database 應用程式部署至 Azure App Service 中使用的範例。

至少,在 GitHub Codespaces 中開啟 範例應用程式 ,並執行 azd up來部署應用程式。

將 MCP 伺服器新增至 Web 應用程式

  1. 在 Codespace 終端機中,將 NuGet ModelContextProtocol.AspNetCore 套件新增至您的專案:

    dotnet add package ModelContextProtocol.AspNetCore --prerelease
    
  2. 建立 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的功能,這是不必要的,但為了簡單起見,您將保留它。 最佳做法是將應用程式邏輯移至服務類別,然後從 TodosControllerTodosMcpTool呼叫服務方法。

  3. 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 測試它,則必須啟用跨原始資源分享 (CORS)(在 Visual Studio Code 和 GitHub Codespaces 中)。

  4. Program.cs中,啟用 MCP 和 CORS 中間件。

    app.MapMcp("/api/mcp");
    app.UseCors();
    

    此程式代碼會將 MCP 伺服器端點設定為 <url>/api/mcp

在本機測試 MCP 伺服器

  1. 在codespace終端機中,使用 dotnet run執行應用程式。

  2. 選取 [在瀏覽器中開啟],然後新增工作。

    保持 dotnet run 執行狀態。 您的 MCP 伺服器目前正在 http://localhost:5093/api/mcp 運行。

  3. 回到程式代碼空間,開啟 [Copilot Chat],然後在提示方塊中選取 [代理程式 模式]。

  4. 選取 [ 工具] 按鈕,然後在下拉式清單中選取 [ 新增更多工具... ]。

    顯示如何在 GitHub Copilot 聊天代理程式模式中新增 MCP 伺服器的螢幕快照。

  5. 選取 [新增 MCP 伺服器]。

  6. 選取HTTP(HTTP 或 Server-Sent 事件)

  7. [輸入伺服器 URL] 中,輸入 http://localhost:5093/api/mcp

  8. [輸入伺服器標識符] 中,輸入 todos-mcp 或任何您想要的名稱。

  9. 選取 [工作區設定]。

  10. 在新的 [Copilot Chat] 視窗中,輸入類似 「顯示待辦事項」 的指令。

  11. 根據預設,當您叫用 MCP 伺服器時,GitHub Copilot 會顯示安全性確認。 選取繼續

    此螢幕快照顯示 GitHub Copilot Chat 中 MCP 調用的預設安全性訊息。

    您現在應該會看到指出 MCP 工具呼叫成功的回應。

    顯示 GitHub Copilot Chat 視窗中 MCP 工具呼叫回應的螢幕快照。

將您的 MCP 伺服器部署至 App Service

  1. 回到 Codespace 終端機,藉由提交變更(GitHub Actions 方法)或執行 azd up (Azure Developer CLI 方法)來部署變更。

  2. 在 AZD 輸出中,尋找應用程式的 URL。 AZD 輸出中 URL 看起來像這樣:

     Deploying services (azd deploy)
    
       (✓) Done: Deploying service web
       - Endpoint: <app-url>
     
  3. 完成後,azd up開啟.vscode/mcp.json。 將 URL 變更為 <app-url>/api/mcp

  4. 在修改過的 MCP 伺服器組態上方,選取 [ 啟動]。

    顯示如何從本機 mcp.json 檔案手動啟動 MCP 伺服器的螢幕快照。

  5. 啟動新的 GitHub Copilot 聊天視窗。 您應該能夠在 Copilot 代理程式中檢視、建立、更新和刪除工作。

安全性最佳做法

當 MCP 伺服器由由大型語言模型 (LLM) 支援的代理程式呼叫時,請注意 提示插入 式攻擊。 請考慮下列安全性最佳做法:

  • 認證與授權:以 Microsoft Entra 認證保護你的 MCP 伺服器,確保只有授權使用者或代理能存取你的工具。 請參閱透過 Microsoft Entra 驗證,從 Visual Studio Code 向 Azure App Service 發出安全的模型內容通訊協定呼叫 (機器翻譯)
  • 輸入驗證和清理:本教學課程中的範例程式代碼會省略輸入驗證和清理,以求簡單明瞭。 在生產案例中,請一律實作適當的驗證和清理,以保護您的應用程式。 如需 ASP.NET Core,請參閱 ASP.NET Core 中的模型驗證
  • HTTPS: 此範例依賴 Azure App Service,其預設會強制執行 HTTPS,並提供免費的 TLS/SSL 憑證來加密傳輸中的數據。
  • 最低許可權原則:只公開使用案例所需的工具和數據。 除非必要,否則請避免公開敏感性作業。
  • 速率限制和節流:使用 API 管理 或自定義中間件來防止濫用和阻斷服務攻擊。
  • 記錄和監視:記錄存取和使用MCP端點以進行稽核和異常偵測。 監視可疑活動。
  • CORS 設定:如果您的 MCP 伺服器是從瀏覽器存取,請將跨原始來源要求限制為受信任的網域。 如需詳細資訊,請參閱 啟用CORS
  • 一般更新:讓您的相依性保持在最新狀態,以減輕已知的弱點。

更多資源

將 AI 整合到 Azure App Service 應用程式中