次の方法で共有


チュートリアル: .NET MCP サーバーを Azure Container Apps にデプロイする

このチュートリアルでは、ASP.NET Core と ModelContextProtocol.AspNetCore NuGet パッケージを使用して、タスク管理ツールを公開するモデル コンテキスト プロトコル (MCP) サーバーを構築します。 サーバーを Azure Container Apps にデプロイし、VS Code の GitHub Copilot Chat からサーバーに接続します。

このチュートリアルでは、次の操作を行います。

  • MCP ツールを公開する ASP.NET Core アプリを作成する
  • GitHub Copilot を使用して MCP サーバーをローカルでテストする
  • アプリをコンテナー化して Azure Container Apps にデプロイする
  • デプロイされた MCP サーバーに GitHub Copilot を接続する

[前提条件]

アプリの雛形を作成する

このセクションでは、新しい ASP.NET Core プロジェクトを作成し、MCP サーバーとして構成します。

  1. 新しい ASP.NET Core Web API プロジェクトを作成します。

    dotnet new web -n TasksMcpServer
    cd TasksMcpServer
    
  2. MCP サーバー NuGet パッケージを追加します。

    dotnet add package ModelContextProtocol.AspNetCore --prerelease
    
  3. Program.cs の内容を次のコードに置き換えます。

    var builder = WebApplication.CreateBuilder(args);
    
    builder.Services.AddMcpServer()
        .WithHttpTransport()
        .WithToolsFromAssembly();
    
    builder.Services.AddCors(options =>
    {
        options.AddDefaultPolicy(policy =>
        {
            policy.AllowAnyOrigin()
                  .AllowAnyHeader()
                  .AllowAnyMethod();
        });
    });
    
    builder.Services.AddSingleton<TaskStore>();
    
    var app = builder.Build();
    
    app.UseCors();
    
    app.MapGet("/health", () => Results.Ok("healthy"));
    app.MapMcp("/mcp");
    
    app.Run();
    

    重要なポイント:

    • AddMcpServer().WithHttpTransport().WithToolsFromAssembly() は MCP サーバーを登録し、 [McpServerToolType]でマークされているすべてのクラスを検出します。
    • MapMcp("/mcp") は、 /mcpでストリーミング可能な HTTP エンドポイントをマウントします。
    • AddSingleton<TaskStore>() は、次のセクションで作成するメモリ内データ ストアを登録します。
    • /health エンドポイントは、Azure Container Apps 正常性プローブ用に個別に追加します。 MCP エンドポイントは、正常性チェックに適していない JSON-RPC 応答を返します。
    • VS Code の GitHub Copilot が MCP サーバーにクロスオリジン要求を行うため、CORS を有効にします。

MCP ツールを定義する

次に、タスク管理データ ストアと、それを AI クライアントに公開する MCP ツールを定義します。

  1. インメモリ データ ストアの TaskStore.cs という名前のファイルを作成します。

    namespace TasksMcpServer;
    
    public record TaskItem(int Id, string Title, string Description, bool IsComplete, DateTime CreatedAt);
    
    public class TaskStore
    {
        private readonly List<TaskItem> _tasks = new()
        {
            new(1, "Buy groceries", "Milk, eggs, bread", false, DateTime.UtcNow),
            new(2, "Write docs", "Draft the MCP tutorial", true, DateTime.UtcNow.AddDays(-1)),
        };
    
        private int _nextId = 3;
    
        public List<TaskItem> GetAll() => _tasks.ToList();
    
        public TaskItem? GetById(int id) => _tasks.FirstOrDefault(t => t.Id == id);
    
        public TaskItem Create(string title, string description)
        {
            var task = new TaskItem(_nextId++, title, description, false, DateTime.UtcNow);
            _tasks.Add(task);
            return task;
        }
    
        public TaskItem? ToggleComplete(int id)
        {
            var index = _tasks.FindIndex(t => t.Id == id);
            if (index < 0) return null;
            var old = _tasks[index];
            var updated = old with { IsComplete = !old.IsComplete };
            _tasks[index] = updated;
            return updated;
        }
    
        public bool Delete(int id)
        {
            var task = _tasks.FirstOrDefault(t => t.Id == id);
            if (task is null) return false;
            _tasks.Remove(task);
            return true;
        }
    }
    

    TaskItem レコードは、5 つのプロパティを持つデータ モデルを定義します。 TaskStore クラスは、サンプル データが事前に設定されたメモリ内リストを管理し、タスクの一覧表示、検索、作成、切り替え、および削除を行うメソッドを提供します。

  2. MCP ツール定義を使用して TasksMcpTools.cs という名前のファイルを作成します。

    using System.ComponentModel;
    using ModelContextProtocol.Server;
    
    namespace TasksMcpServer;
    
    [McpServerToolType]
    public class TasksMcpTools
    {
        private readonly TaskStore _store;
    
        public TasksMcpTools(TaskStore store)
        {
            _store = store;
        }
    
        [McpServerTool, Description("Lists all tasks with their ID, title, description, and completion status.")]
        public List<TaskItem> ListTasks()
        {
            return _store.GetAll();
        }
    
        [McpServerTool, Description("Gets a single task by its ID.")]
        public TaskItem? GetTask(
            [Description("The numeric ID of the task to retrieve")] int id)
        {
            return _store.GetById(id);
        }
    
        [McpServerTool, Description("Creates a new task with the given title and description. Returns the created task.")]
        public TaskItem CreateTask(
            [Description("A short title for the task")] string title,
            [Description("A detailed description of what the task involves")] string description)
        {
            return _store.Create(title, description);
        }
    
        [McpServerTool, Description("Toggles a task's completion status between complete and incomplete.")]
        public string ToggleTaskComplete(
            [Description("The numeric ID of the task to toggle")] int id)
        {
            var task = _store.ToggleComplete(id);
            return task is not null
                ? $"Task {task.Id} is now {(task.IsComplete ? "complete" : "incomplete")}."
                : $"Task with ID {id} not found.";
        }
    
        [McpServerTool, Description("Deletes a task by its ID.")]
        public string DeleteTask(
            [Description("The numeric ID of the task to delete")] int id)
        {
            return _store.Delete(id)
                ? $"Task {id} deleted."
                : $"Task with ID {id} not found.";
        }
    }
    

    [McpServerToolType]属性は、クラスを MCP ツール プロバイダーとしてマークします。 各 [McpServerTool] メソッドは、インボカブル ツールになります。 [Description]属性を使用して、AI モデルが各ツールの目的とパラメーターを理解するのに役立ちます。

MCP サーバーをローカルでテストする

Azure にデプロイする前に、MCP サーバーがローカルで実行され、GitHub Copilot から接続されて動作することを確認します。

  1. アプリケーションを実行します。

    dotnet run
    

    サーバーは、 http://localhost:5000 (またはコンソール出力に示されているポート) で起動します。 MCP エンドポイントは http://localhost:5000/mcpにあります。

  2. VS Code を開き、 Copilot チャット を開き、[ エージェント モード] を選択します。

  3. [ ツール ] ボタンを選択し、[ その他のツールの追加] を選択します。..>MCP サーバーを追加します

  4. HTTP (HTTP または Server-Sent イベント) を選択します。

  5. サーバーの URL を入力します。 http://localhost:5000/mcp

  6. サーバー ID を入力します。 tasks-mcp

  7. [ ワークスペースの設定] を選択します

  8. 新しい Copilot チャット プロンプトで、「すべてのタスクを表示する」と入力します。

  9. GitHub Copilot では、MCP ツールを呼び出す前に確認が表示されます。 続行を選択します。

Copilot がメモリ内ストアからタスクの一覧を返すことがわかります。

ヒント

「PR を確認するタスクを作成する」、「タスク 1 を完了としてマークする」、「タスク 2 を削除する」などの他のプロンプトを試してください。

アプリケーションのコンテナー格納

Azure にデプロイする前にローカルでテストできるように、アプリケーションを Docker コンテナーとしてパッケージ化します。

  1. プロジェクト ルートに Dockerfile を作成します。

    FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
    WORKDIR /src
    COPY *.csproj .
    RUN dotnet restore
    COPY . .
    RUN dotnet publish -c Release -o /app
    
    FROM mcr.microsoft.com/dotnet/aspnet:8.0
    WORKDIR /app
    COPY --from=build /app .
    ENV ASPNETCORE_URLS=http://+:8080
    EXPOSE 8080
    ENTRYPOINT ["dotnet", "TasksMcpServer.dll"]
    

    マルチステージ ビルドでは、SDK イメージを使用してアプリの復元、ビルド、発行を行い、発行された出力のみを小さな ASP.NET ランタイム イメージにコピーします。 ASPNETCORE_URLS環境変数は、ポート 8080 でリッスンするようにアプリを構成します。

  2. コンテナーがビルドされ、ローカルで実行されていることを確認します。

    docker build -t tasks-mcp-server .
    docker run -p 8080:8080 tasks-mcp-server
    

    ヘルスエンドポイントが応答することを確認してください。 curl http://localhost:8080/health

Azure Container Apps へのデプロイ

アプリケーションをコンテナー化したら、Azure CLI を使用して Azure Container Apps にデプロイします。 az containerapp up コマンドはクラウドにコンテナー イメージをビルドするため、この手順ではマシン上に Docker は必要ありません。

  1. 環境変数を設定します。

    RESOURCE_GROUP="mcp-tutorial-rg"
    LOCATION="eastus"
    ENVIRONMENT_NAME="mcp-env"
    APP_NAME="tasks-mcp-server"
    
  2. リソース グループを作成します。

    az group create --name $RESOURCE_GROUP --location $LOCATION
    
  3. Container Apps 環境を作成します。

    az containerapp env create \
        --name $ENVIRONMENT_NAME \
        --resource-group $RESOURCE_GROUP \
        --location $LOCATION
    
  4. コンテナー アプリをデプロイします。

    az containerapp up \
        --name $APP_NAME \
        --resource-group $RESOURCE_GROUP \
        --environment $ENVIRONMENT_NAME \
        --source . \
        --ingress external \
        --target-port 8080
    
  5. GitHub Copilot 要求を許可するように CORS を構成します。

    az containerapp ingress cors enable \
        --name $APP_NAME \
        --resource-group $RESOURCE_GROUP \
        --allowed-origins "*" \
        --allowed-methods "GET,POST,DELETE,OPTIONS" \
        --allowed-headers "*"
    

    運用環境では、ワイルドカード * オリジンを特定の信頼されたオリジンに置き換えます。 ガイダンスについては、 Container Apps 上の MCP サーバーのセキュリティ保護に関 するトピックを参照してください。

  6. デプロイを検証します。

    APP_URL=$(az containerapp show \
        --name $APP_NAME \
        --resource-group $RESOURCE_GROUP \
        --query "properties.configuration.ingress.fqdn" -o tsv)
    
    curl https://$APP_URL/health
    

デプロイされたサーバーに GitHub Copilot を接続する

MCP サーバーが Azure で実行されたので、デプロイされたエンドポイントに GitHub Copilot を接続するように VS Code を構成します。

  1. プロジェクトで、 .vscode/mcp.jsonを作成または更新します。

    {
        "servers": {
            "tasks-mcp-server": {
                "type": "http",
                "url": "https://<your-app-fqdn>/mcp"
            }
        }
    }
    

    <your-app-fqdn>をデプロイ出力の FQDN に置き換えます。

  2. VS Code で、エージェント モードで Copilot チャットを開きます。

  3. サーバーが自動的に表示されない場合は、[ ツール ] ボタンを選択し、 tasks-mcp-server が一覧表示されていることを確認します。 必要に応じて [開始] を選択します

  4. "List all my tasks" のようなプロンプトでテストし、デプロイされた MCP サーバーが応答することを確認します。

対話型使用のスケーリングを構成する

既定では、Azure Container Apps は 0 個のレプリカにスケーリングできます。 Copilot などの対話型クライアントにサービスを提供する MCP サーバーの場合、コールド スタートは顕著な遅延を引き起こします。 少なくとも 1 つのインスタンスを実行し続けるために、レプリカの最小数を設定します。

az containerapp update \
    --name $APP_NAME \
    --resource-group $RESOURCE_GROUP \
    --min-replicas 1

セキュリティに関する考慮事項

このチュートリアルでは、簡単にするために認証されていない MCP サーバーを使用します。 運用環境で MCP サーバーを実行する前に、次の推奨事項を確認してください。 大規模言語モデル (LLM) を利用するエージェントが MCP サーバーを呼び出す場合は、 迅速なインジェクション 攻撃に注意してください。

  • 認証と承認: Microsoft Entra ID を使用して MCP サーバーをセキュリティで保護します。 Container Apps での MCP サーバーのセキュリティ保護に関する情報を参照してください。
  • 入力検証: 常にツール パラメーターを検証します。 ASP.NET Core でデータ注釈または FluentValidation を使用します。 ASP.NET Core のモデル検証を参照してください。
  • HTTPS: Azure Container Apps では、自動 TLS 証明書を使用して既定で HTTPS が適用されます。
  • 最小権限: ユース ケースで必要なツールのみを公開します。 確認なしで破壊的な操作を実行するツールは避けてください。
  • CORS: 許可された配信元を運用環境の信頼されたドメインに制限します。
  • ログ記録と監視: MCP ツールの呼び出しを監査用にログに記録します。 Azure Monitor と Log Analytics を使用します。

リソースをクリーンアップする

このアプリケーションを引き続き使用する予定がない場合は、リソース グループを削除して、このチュートリアルで作成したすべてのリソースを削除します。

az group delete --resource-group $RESOURCE_GROUP --yes --no-wait

次のステップ