Condividi tramite


Integrare un'app di App Service come server MCP per GitHub Copilot Chat (.NET)

In questa esercitazione si apprenderà come esporre la funzionalità di un'app ASP.NET Core tramite il protocollo MCP (Model Context Protocol), aggiungerla come strumento a GitHub Copilot e interagire con l'app usando il linguaggio naturale in modalità agente di Chat Copilot.

Screenshot che mostra gitHub Copilot che chiama il server Todos MCP ospitato nel servizio app di Azure.

Se l'applicazione Web dispone già di funzionalità utili, ad esempio shopping, prenotazione hotel o gestione dei dati, è facile rendere disponibili queste funzionalità per:

Aggiungendo un server MCP all'app Web, si abilita un agente per comprendere e usare le funzionalità dell'app quando risponde alle richieste degli utenti. Ciò significa che qualsiasi operazione che l'app può fare, anche l'agente può fare.

  • Aggiungi un server MCP alla tua app web.
  • Testare il server MCP in locale in modalità agente Chat di GitHub Copilot.
  • Distribuire il server MCP nel servizio app di Azure e connetterlo in GitHub Copilot Chat.

Prerequisiti

Questa esercitazione presuppone che si stia usando l'esempio usato in Esercitazione: Distribuire un'app di ASP.NET Core e del database SQL di Azure nel servizio app di Azure.

Aprire almeno l'applicazione di esempio in GitHub Codespaces e distribuire l'app eseguendo azd up.

Aggiungere un server MCP alla tua app Web

  1. Nel terminale codespace aggiungere il pacchetto NuGet ModelContextProtocol.AspNetCore al progetto:

    dotnet add package ModelContextProtocol.AspNetCore --prerelease
    
  2. Creare una cartella McpServer e crearne una TodosMcpTool.cs con il codice seguente.

    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.";
            }
        }
    }
    

    Il codice precedente rende disponibili gli strumenti per il server MCP usando gli attributi specifici seguenti:

    • [McpServerToolType]: contrassegna la TodosMcpTool classe come tipo di strumento server MCP. Segnala al framework MCP che questa classe contiene metodi che devono essere esposti come strumenti chiamabili.
    • [McpServerTool]: contrassegna un metodo come azione chiamabile per il server MCP.
    • [Description]: forniscono descrizioni leggibili per metodi e parametri. Consente all'agente chiamante di comprendere come usare le azioni e i relativi parametri.

    Questo codice duplica la funzionalità dell'oggetto esistente TodosController, che non è necessario, ma verrà mantenuto per semplicità. Una procedura consigliata consiste nello spostare la logica dell'app in una classe di servizio, quindi chiamare i metodi del servizio sia da TodosController che da TodosMcpTool.

  3. In Program.cs registrare il servizio server MCP e il servizio 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();
        });
    });
    

    Quando si usa HTTP trasmettebile con il server MCP, è necessario abilitare la condivisione di risorse tra le origini (CORS) se si vuole testarla con gli strumenti del browser client o GitHub Copilot (sia in Visual Studio Code che in GitHub Codespaces).

  4. In Program.cs abilitare il middleware MCP e CORS.

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

    Questo codice imposta l'endpoint server MCP su <url>/api/mcp.

Testare il server MCP in locale

  1. Nel terminale codespace eseguire l'applicazione con dotnet run.

  2. Selezionare Apri nel browser e quindi aggiungere un'attività.

    Lasciare dotnet run in esecuzione. Il server MCP è in esecuzione adesso su http://localhost:5093/api/mcp.

  3. Nel codespace aprire Copilot Chat e quindi selezionare Modalità agente nella casella di richiesta.

  4. Selezionare il pulsante Strumenti e quindi aggiungi altri strumenti nell'elenco a discesa.

    Screenshot che mostra come aggiungere un server MCP in modalità agente Di Chat di GitHub Copilot.

  5. Selezionare Aggiungi server MCP.

  6. Selezionare HTTP (HTTP o Eventi inviati dal server).

  7. In Immettere l'URL del server digitare http://localhost:5093/api/mcp.

  8. In Immettere l'ID server digitare todos-mcp o qualsiasi nome desiderato.

  9. Selezionare Impostazioni area di lavoro.

  10. In una nuova finestra di Copilot Chat, digitare una richiesta simile a "Mostrami le azioni".

  11. Per impostazione predefinita, GitHub Copilot mostra una conferma di sicurezza quando si richiama un server MCP. Seleziona Continua.

    Screenshot che mostra il messaggio di sicurezza predefinito da una chiamata MCP in GitHub Copilot Chat.

    Verrà visualizzata una risposta che indica che la chiamata allo strumento MCP ha esito positivo.

    Screenshot che mostra la risposta del tool MCP nella finestra di GitHub Copilot Chat.

Distribuire il server MCP nel servizio app

  1. Tornare al terminale codespace, distribuire le modifiche eseguendo il commit delle modifiche (metodo GitHub Actions) o eseguendo azd up (metodo dell'interfaccia della riga di comando per sviluppatori di Azure).

  2. Nell'output AZD trovare l'URL dell'app. L'URL è simile al seguente nell'output AZD:

     Deploying services (azd deploy)
    
       (✓) Done: Deploying service web
       - Endpoint: <app-url>
     
  3. Una volta azd up terminato, apri .vscode/mcp.json. Modificare l'URL in <app-url>/api/mcp.

  4. Sopra la configurazione del server MCP modificata, selezionare Avvia.

    Screenshot che mostra come avviare manualmente un server MCP dal file di mcp.json locale.

  5. Avviare una nuova finestra di Chat di GitHub Copilot. Dovrebbe essere possibile visualizzare, creare, aggiornare ed eliminare attività nell'agente Copilot.

Procedure consigliate per la sicurezza

Quando il server MCP viene chiamato da un agente basato su modelli linguistici di grandi dimensioni (LLM), prestare attenzione agli attacchi di prompt injection. Considerare le procedure consigliate per la sicurezza seguenti:

  • Autenticazione e autorizzazione: proteggere il server MCP con l'autenticazione Microsoft Entra per garantire che solo gli utenti o gli agenti autorizzati possano accedere agli strumenti. Per una guida dettagliata, vedere Proteggere le chiamate MCP (Model Context Protocol) al Servizio app di Azure da Visual Studio Code con l'autenticazione di Microsoft Entra.
  • Convalida e purificazione dell'input: il codice di esempio in questa esercitazione omette la convalida e la purificazione dell'input per semplicità e chiarezza. Negli scenari di produzione implementare sempre la convalida e la purificazione appropriate per proteggere l'applicazione. Per ASP.NET Core, vedere Convalida del modello in ASP.NET Core.
  • HTTPS: L'esempio si basa sul servizio app di Azure, che applica HTTPS per impostazione predefinita e fornisce certificati TLS/SSL gratuiti per crittografare i dati in transito.
  • Principio dei privilegi minimi: esporre solo gli strumenti e i dati necessari per il caso d'uso. Evitare di esporre operazioni sensibili, a meno che non sia necessario.
  • Limitazione della velocità e limitazione delle richieste: usare Gestione API o middleware personalizzato per evitare abusi e attacchi di tipo denial-of-service.
  • Registrazione e monitoraggio: accesso e utilizzo dei log degli endpoint MCP per il controllo e il rilevamento delle anomalie. Monitorare l'attività sospetta.
  • Configurazione CORS: limitare le richieste tra le origini ai domini attendibili se si accede al server MCP dai browser. Per altre informazioni, vedere Abilitare CORS.
  • Aggiornamenti regolari: mantenere aggiornate le dipendenze per attenuare le vulnerabilità note.

Altre risorse

Integrare l'intelligenza artificiale nelle applicazioni del servizio app di Azure