Интеграция приложения службы App Service в качестве сервера MCP для GitHub Copilot Chat (.NET)

В этом руководстве вы узнаете, как предоставить функциональность приложения ASP.NET Core с помощью протокола MCP, добавить его в GitHub Copilot и взаимодействовать с приложением с помощью естественного языка в режиме агента Чата Copilot.

Снимок экрана: GitHub Copilot, вызывающий сервер Todos MCP, размещенный в службе приложений Azure.

Если веб-приложение уже имеет полезные функции, такие как покупки, бронирование отелей или управление данными, это легко сделать эти возможности доступными для:

Добавив сервер MCP в веб-приложение, вы можете агенту понять и использовать возможности приложения при реагировании на запросы пользователей. Это означает, что ваше приложение может сделать все, что может сделать агент.

  • Добавьте сервер MCP в веб-приложение.
  • Протестируйте сервер MCP локально в режиме агента чата GitHub Copilot.
  • Разверните сервер MCP в Службе приложений Azure и подключитесь к нему в GitHub Copilot Chat.

Предпосылки

В этом руководстве предполагается, что вы работаете с примером, используемым в руководстве. Развертывание приложения ASP.NET Core и Базы данных SQL Azure в Службе приложений Azure.

По крайней мере, откройте образец приложения в GitHub Codespaces и разверните приложение, запустив команду azd up.

Добавление сервера MCP в веб-приложение

  1. В терминале пространства кода добавьте пакет 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, который является ненужным, но вы будете хранить его для простоты. Рекомендуется переместить логику приложения в класс сервиса, а затем вызывать методы сервиса как из TodosController, так и из TodosMcpTool.

  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();
        });
    });
    

    При использовании потокового HTTP с сервером MCP необходимо включить совместное использование ресурсов между источниками (CORS), если вы хотите протестировать его с помощью клиентских средств браузера или GitHub Copilot (как в Visual Studio Code, так и в GitHub Codespaces).

  4. В Program.cs включите ПО промежуточного слоя MCP и CORS.

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

    Этот код задает для конечной точки сервера MCP значение <url>/api/mcp.

Тестирование сервера MCP локально

  1. В терминале пространства кода запустите приложение, используя dotnet run.

  2. Выберите "Открыть в браузере", а затем добавьте задачу.

    Оставьте dotnet run запущенным. Сервер MCP сейчас работает на http://localhost:5093/api/mcp.

  3. Вернитесь в пространство кода, откройте Copilot Chat, а затем выберите режим агента в поле запроса.

  4. Нажмите кнопку "Сервис", а затем в раскрывающемся списке нажмите кнопку "Добавить другие инструменты".

    Снимок экрана: добавление сервера MCP в режиме агента чата GitHub Copilot.

  5. Выберите "Добавить СЕРВЕР MCP".

  6. Выберите HTTP (HTTP или Server-Sent события).

  7. Введите URL-адрес сервера, введите http://localhost:5093/api/mcp.

  8. В Введите идентификатор сервера введите todos-mcp или любое имя по вашему выбору.

  9. Выберите параметры рабочей области.

  10. В новом окне чата Copilot введите примерно следующее "Покажи мне дела".

  11. По умолчанию GitHub Copilot показывает подтверждение безопасности при вызове сервера MCP. Нажмите Продолжить.

    Снимок экрана: сообщение о безопасности по умолчанию из вызова MCP в GitHub Copilot Chat.

    Теперь вы увидите ответ, указывающий на успешное выполнение вызова средства MCP.

    Снимок экрана: ответ от вызова средства MCP в окне чата GitHub Copilot.

Разверните ваш сервер MCP в App Service.

  1. Вернитесь в терминал codespace, зафиксируйте изменения (метод GitHub Actions) или запустите azd up (метод Azure Developer CLI).

  2. В выходных данных AZD найдите URL-адрес приложения. URL-адрес выглядит следующим образом в выходных данных AZD:

     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 вручную из локального mcp.json файла.

  5. Запустите новое окно чата GitHub Copilot. Вы должны иметь возможность просматривать, создавать, обновлять и удалять задачи в агенте Copilot.

Рекомендации по обеспечению безопасности

Когда сервер MCP вызывается агентом, управляемым моделями большого языка (LLM), будьте внимательны к атакам типа внедрение команды. Рассмотрим следующие рекомендации по обеспечению безопасности:

  • Аутентификация и авторизация: Защита вашего сервера MCP с использованием аутентификации Microsoft Entra, чтобы обеспечить доступ только авторизованным пользователям или агентам. См. пошаговое руководство по вызовам протокола контекста безопасной модели в Службе приложений Azure из Visual Studio Code с проверкой подлинности Microsoft Entra.
  • Проверка и очистка входных данных. Пример кода в этом руководстве исключает проверку ввода и очистку для простоты и ясности. В рабочих сценариях всегда реализуйте правильную проверку и очистку для защиты приложения. Сведения о ASP.NET Core см. в разделе "Проверка модели" в ASP.NET Core.
  • HTTPS: В примере используется служба приложений Azure, которая по умолчанию применяет ПРОТОКОЛ HTTPS и предоставляет бесплатные СЕРТИФИКАТЫ TLS/SSL для шифрования данных во время передачи.
  • Принцип наименьшей привилегии: предоставление только необходимых средств и данных, необходимых для вашего варианта использования. Избегайте предоставления конфиденциальных операций, если это не необходимо.
  • Ограничение скорости и регулирование. Используйте управление API или пользовательское ПО промежуточного слоя для предотвращения злоупотреблений и атак типа "отказ в обслуживании".
  • Ведение журнала и мониторинг. Доступ к журналам и использование конечных точек MCP для аудита и обнаружения аномалий. Отслеживайте подозрительные действия.
  • Конфигурация CORS: ограничьте кросс-доменные запросы до доверенных доменов, если доступ к вашему серверу MCP осуществляется из браузеров. Дополнительные сведения см. в разделе "Включение CORS".
  • Регулярные обновления: обновляйте зависимости, чтобы устранить известные уязвимости.

Дополнительные ресурсы

Интеграция ИИ в приложения Службы приложений Azure