Partager via


Créer un agent .NET OpenAI à l’aide d’un serveur MCP sur Azure Container Apps

Cet article explique comment créer un agent MCP (Model Context Protocol) à l’aide de .NET. Dans cet exemple, le client MCP (écrit en C#/.NET) se connecte à un serveur MCP (écrit en TypeScript) pour gérer une liste de tâches. Le client trouve les outils disponibles à partir du serveur et les envoie à un modèle Azure OpenAI. Les utilisateurs peuvent ensuite communiquer avec le système todo à l’aide de la langue quotidienne.

Accéder au code

Consultez le modèle OpenAI MCP Agent Building Block AI. Cet exemple montre comment générer un agent OpenAI qui utilise un client MCP pour consommer un serveur MCP existant.

Accédez à la section de procédure pas à pas du code pour comprendre le fonctionnement de cet exemple.

Vue d’ensemble de l’architecture

Le diagramme suivant montre l’architecture simple de l’exemple d’application : diagramme montrant l’architecture de Visual Studio Code hébergeant l’agent et le client MCP vers MCP Server.

  • Client MCP : se connecte au serveur MCP et recherche des outils disponibles
  • Client de conversation : Fonctionne avec Azure OpenAI pour comprendre le langage naturel
  • Interface utilisateur Blazor : fournit une interface web où les utilisateurs peuvent discuter
  • Couche de transport : utilise des événements Server-Sent (SSE) pour envoyer des messages en temps réel
  • Authentification : utilise des jetons JWT pour sécuriser la connexion

Le serveur MCP s’exécute en tant qu’application conteneurisée sur Azure Container Apps (ACA). Il utilise un back-end TypeScript pour fournir des outils au client MCP via le protocole de contexte du modèle. Tous les outils fonctionnent avec une base de données SQLite principale.

Note

Visitez Générer un serveur MCP TypeScript à l’aide d’Azure Container Apps pour voir la procédure pas à pas du code du serveur MCP TypeScript utilisé dans cet article.

Coûts

Pour réduire les coûts, cet exemple utilise des niveaux tarifaires de base ou de consommation pour la plupart des ressources. Ajustez le niveau en fonction des besoins et supprimez les ressources lorsque vous avez terminé d’éviter les frais.

Prerequisites

Un conteneur de développement inclut toutes les dépendances dont vous avez besoin pour cet article. Vous pouvez l’exécuter dans GitHub Codespaces (dans un navigateur) ou localement à l’aide de Visual Studio Code.

Pour suivre cet article, vérifiez que vous remplissez les conditions préalables suivantes :

Déployer un modèle AI Foundry gpt-5-mini à l’aide de l’extension VS Code AI Foundry

Déployez un gpt-5-mini modèle à l’aide de l’extension AI Foundry dans Visual Studio Code en procédant comme suit :

Créer un projet AI Foundry et déployer le modèle

Créer la chaîne de connexion du modèle OpenAI

  1. Une fois le gpt-5-mini modèle déployé, cliquez avec le bouton droit sur le modèle dans l’extension AI Foundry et sélectionnez Copier la clé API pour copier la clé API du modèle dans le Presse-papiers.

  2. Ensuite, cliquez avec le bouton droit sur le modèle déployé gpt-5-mini dans l’extension AI Foundry et sélectionnez Copier le point de terminaison pour copier le point de terminaison du modèle dans votre Presse-papiers, comme illustré dans la capture d’écran suivante :

    Capture d’écran montrant le menu contextuel du modèle déployé avec les options copier le point de terminaison et copier les clés API mises en surbrillance.

  3. Enfin, créez une chaîne de connexion pour le modèle déployé gpt-5-mini à l’aide du point de terminaison copié et de la clé API au format suivant : Endpoint=<AZURE_OPENAI_ENDPOINT>;Key=<AZURE_OPENAI_API_KEY> Vous avez besoin de cette chaîne de connexion plus loin dans l’article.

Environnement de développement ouvert

Suivez ces étapes pour configurer un environnement de développement préconfiguré avec toutes les dépendances requises.

GitHub Codespaces exécute un conteneur de développement géré par GitHub avec Visual Studio Code pour le web comme interface. Utilisez GitHub Codespaces pour la configuration la plus simple, car il est fourni avec les outils et dépendances nécessaires préinstallés pour cet article.

Important

Tous les comptes GitHub peuvent utiliser Des espaces de code pour jusqu’à 60 heures gratuites chaque mois avec deux instances principales. Pour plus d’informations, consultez GitHub Codespaces mensuels inclus dans le stockage et les heures principales.

Procédez comme suit pour créer un espace de code GitHub sur la main branche du Azure-Samples/openai-mcp-agent-dotnet dépôt GitHub.

  1. Cliquez avec le bouton droit sur le bouton suivant et sélectionnez Ouvrir le lien dans la nouvelle fenêtre. Cette action vous permet d’avoir l’environnement de développement et la documentation ouverte côte à côte.

    Ouvrir dans un GitHub Codespaces

  2. Dans la page Créer un espace de code , passez en revue, puis sélectionnez Créer un espace de code.

  3. Attendez que l’espace de code démarre. Cela peut prendre quelques minutes.

  4. Assurez-vous que le nom de votre modèle déployé est gpt-5-mini. Si votre modèle déployé est différent, mettez à jour src/McpTodo.ClientApp/appsettings.json avec le nom de déploiement approprié.

    {
      "OpenAI": {
        // Make sure this is the right deployment name.
        "DeploymentName": "gpt-5-mini"
      }
    }
    
  5. Connectez-vous à Azure avec Azure Developer CLI dans le terminal en bas de l’écran.

    azd auth login
    
  6. Copiez le code à partir du terminal, puis collez-le dans un navigateur. Suivez les instructions pour vous authentifier auprès de votre compte Azure.

Vous effectuez le reste des tâches dans ce conteneur de développement.

Note

Pour exécuter l’agent MCP localement :

  1. Configurez votre environnement comme décrit dans la section Prise en main dans l’exemple de référentiel.
  2. Installez votre serveur MCP en suivant les instructions de la section Obtenir l’application serveur MCP dans l’exemple de référentiel.
  3. Exécutez l’agent MCP localement en suivant les instructions de la section Exécuter localement dans l’exemple de référentiel.
  4. Passez à la section Utiliser l’agent TODO MCP pour continuer.

Déployer et exécuter

L’exemple de référentiel contient tous les fichiers de code et de configuration du déploiement Azure de l’agent MCP. Les étapes suivantes vous guident dans l’exemple de processus de déploiement Azure de l’agent MCP.

Déployer dans Azure

Important

Les ressources Azure de cette section commencent à coûter de l’argent immédiatement, même si vous arrêtez la commande avant sa fin.

Définir le jeton JWT

  • Définissez le jeton JWT pour le serveur MCP en exécutant la commande suivante dans le terminal en bas de l’écran :

    # zsh/bash
    ./scripts/set-jwttoken.sh
    
    # PowerShell
    ./scripts/Set-JwtToken.ps1
    

Ajouter un jeton JWT à la configuration de l’environnement azd

  1. Ajoutez le jeton JWT à la configuration de l’environnement azd en exécutant la commande suivante dans le terminal en bas de l’écran :

    # zsh/bash
    env_dir=".azure/$(azd env get-value AZURE_ENV_NAME)"
    mkdir -p "$env_dir"
    cat ./src/McpTodo.ServerApp/.env >> "$env_dir/.env"
    
    # PowerShell
    $dotenv = Get-Content ./src/McpTodo.ServerApp/.env
    $dotenv | Add-Content -Path ./.azure/$(azd env get-value AZURE_ENV_NAME)/.env -Encoding utf8 -Force
    

    Note

    Par défaut, l’application cliente MCP est protégée par la fonctionnalité d’authentification intégrée ACA. Vous pouvez désactiver cette fonctionnalité avant d’exécuter azd up en définissant :

    azd env set USE_LOGIN false
    
  2. Exécutez la commande AZURE Developer CLI suivante pour le provisionnement de ressources Azure et le déploiement de code source :

    azd up
    
  3. Utilisez le tableau suivant pour répondre aux invites :

    Prompt Réponse
    Nom de l’environnement Utilisez un nom court en minuscules. Ajoutez votre nom ou alias. Par exemple : my-mcp-agent. Le nom de l’environnement fait partie du nom du groupe de ressources.
    Subscription Choisissez l’abonnement dans lequel vous souhaitez créer des ressources.
    Emplacement (pour l’hébergement) Sélectionnez l’emplacement de déploiement du modèle dans la liste.
    Chaîne de connexion OpenAI Collez la chaîne de connexion pour le modèle OpenAI que vous avez créé précédemment dans la section Créer la chaîne de connexion du modèle OpenAI .
  4. Le déploiement d’applications prend 5 à 10 minutes.

  5. Une fois le déploiement terminé, vous pouvez accéder à l’agent MCP à l’aide de l’URL dans la sortie. L’URL ressemble à ceci :

    https://<env-name>.<container-id>.<region>.azurecontainerapps.io
    
  6. Ouvrez l’URL dans un navigateur web pour utiliser l’agent MCP.

Utiliser l’agent TODO MCP

Une fois l’agent MCP en cours d’exécution, vous pouvez utiliser les outils qu’il fournit en mode agent. Pour utiliser les outils MCP en mode agent :

  1. Accédez à l’URL de l’application cliente et connectez-vous à l’application.

    Note

    si vous définissez la USE_LOGIN valeur falsesur , vous ne serez peut-être pas invité à vous connecter.

  2. Entrez une invite telle que « J’ai besoin d’envoyer un e-mail à mon responsable le mercredi » dans la zone d’entrée de conversation et notez que les outils sont automatiquement appelés en fonction des besoins.

  3. L’agent MCP utilise les outils fournis par le serveur MCP pour répondre à la demande et retourner une réponse dans l’interface de conversation.

  4. Expérimentez avec d’autres invites telles que :

    Give me a list of to dos.
    Set "meeting at 1pm".
    Give me a list of to dos.
    Mark #1 as completed.
    Delete #1 from the to-do list.
    

Explorer le code

L’exemple de référentiel contient tous les fichiers de code et de configuration du déploiement Azure de l’agent MCP. Les sections suivantes vous guident dans les composants clés du code de l’agent MCP.

Configuration et configuration du client MCP

L’application configure le client MCP dans Program.cs. Cette configuration définit comment se connecter et quelles options utiliser. Le code utilise plusieurs modèles avancés, notamment l’intégration et les valeurs par défaut du service .NET Aspire :

builder.Services.AddSingleton<IMcpClient>(sp =>
{
    var config = sp.GetRequiredService<IConfiguration>();
    var loggerFactory = sp.GetRequiredService<ILoggerFactory>();

    var uri = new Uri(config["McpServers:TodoList"]!);

    var clientTransportOptions = new SseClientTransportOptions()
    {
        Endpoint = new Uri($"{uri.AbsoluteUri.TrimEnd('/')}/mcp"),
        AdditionalHeaders = new Dictionary<string, string>
        {
            { "Authorization", $"Bearer {config["McpServers:JWT:Token"]!}" }
        }
    };
    var clientTransport = new SseClientTransport(clientTransportOptions, loggerFactory);

    var clientOptions = new McpClientOptions()
    {
        ClientInfo = new Implementation()
        {
            Name = "MCP Todo Client",
            Version = "1.0.0",
        }
    };

    return McpClientFactory.CreateAsync(clientTransport, clientOptions, loggerFactory).GetAwaiter().GetResult();
});

Détails de l’implémentation clé :

  • Configuration du transport : SseClientTransportOptions prend en charge les événements Server-Sent (SSE) et le transport HTTP streamable. La méthode de transport dépend de l’URL du point de terminaison : les points de terminaison se /sse terminant par l’utilisation de Server-Sent Événements, tandis que les points de terminaison se terminant par /mcp l’utilisation du protocole HTTP streamable. Cette approche permet une communication en temps réel entre le client et le serveur
  • En-têtes d’authentification : les jetons JWT sont connectés pour sécuriser la AdditionalHeaders communication du serveur
  • Informations du client : McpClientOptions indique au serveur le nom et la version du client
  • Modèle de fabrique : McpClientFactory.CreateAsync() connecte et termine l’établissement d’une liaison de protocole

Intégration par défaut du service .NET Aspire

L’application utilise le modèle de service par défaut de .NET Aspire pour les problèmes de coupe croisée :

// McpTodo.ServiceDefaults/Extensions.cs
public static TBuilder AddServiceDefaults<TBuilder>(this TBuilder builder) where TBuilder : IHostApplicationBuilder
{
    builder.ConfigureOpenTelemetry();
    builder.AddDefaultHealthChecks();
    builder.Services.AddServiceDiscovery();
    
    builder.Services.ConfigureHttpClientDefaults(http =>
    {
        // Turn on resilience by default
        http.AddStandardResilienceHandler();
        // Turn on service discovery by default
        http.AddServiceDiscovery();
    });
    
    return builder;
}

Avantages par défaut du service :

  • Méthodes d’extension composables : le système utilise un modèle de générateur propre pour ajouter des fonctionnalités partagées
  • Gestionnaires de résilience standard : le système ajoute des règles de nouvelle tentative intégrée, de disjoncteur et de délai d’attente pour vous
  • Intégration de la découverte de services : le système recherche automatiquement les services dans les environnements de conteneur
  • OpenTelemetry par défaut : le système obtient une surveillance complète sans aucun travail d’installation

Le diagramme suivant montre la relation entre les problèmes de coupe croisée et les services d’application :

Diagramme montrant la relation entre les problèmes croisés et les services d’application.

Résolution d’URL de configuration

L’exemple inclut une résolution d’URL sophistiquée pour différents environnements :

// AspireUrlParserExtensions.cs
public static Uri Resolve(this Uri uri, IConfiguration config)
{
    var absoluteUrl = uri.ToString();
    if (absoluteUrl.StartsWith("https+http://"))
    {
        var appname = absoluteUrl.Substring("https+http://".Length).Split('/')[0];
        var https = config[$"services:{appname}:https:0"]!;
        var http = config[$"services:{appname}:http:0"]!;
        
        return string.IsNullOrWhiteSpace(https) ? new Uri(http) : new Uri(https);
    }
    // Handle other URL formats...
}

Fonctionnalités de gestion de la configuration :

  • Abstraction de la découverte de services : le système gère les URL de développement et de production de manière propre
  • Négociation de protocole : le système choisit d’abord HTTPS, puis revient à HTTP
  • Convention de configuration : le système utilise des modèles de configuration de service .NET Aspire standard

Implémentation de l’authentification

Cet exemple utilise l’authentification JWT (JSON Web Token) pour sécuriser la connexion entre le client MCP et le serveur.

dotnet user-secrets --project ./src/McpTodo.ClientApp set McpServers:JWT:Token "$TOKEN"

Note

Les scripts ont créé la $TOKEN variable automatiquement lorsque vous avez exécuté le script Bash (set-jwttoken.sh) ou PowerShell (Set-JwtToken.ps1) précédemment dans la section Déployer sur Azure . Ces scripts effectuent les étapes suivantes :

  1. Exécuter npm run generate-token dans l’application serveur MCP pour créer un jeton JWT
  2. Analyser le fichier généré .env pour extraire la valeur JWT_TOKEN
  3. Stockez-le automatiquement dans les secrets utilisateur .NET pour MCPClient

Le client MCP récupère le jeton JWT de la configuration et l’inclut dans les en-têtes HTTP pour l’authentification lors de la connexion au serveur MCP :

AdditionalHeaders = new Dictionary<string, string>
{
    { "Authorization", $"Bearer {config["McpServers:JWT:Token"]!}" }
}

Cette approche garantit les points suivants :

  • Communication sécurisée : le système autorise uniquement les clients avec des jetons valides à se connecter au serveur MCP
  • Token-Based Autorisation : les jetons JWT permettent au système de vérifier les utilisateurs sans stocker les données de session
  • Gestion de la configuration : le système stocke les jetons sensibles en toute sécurité dans les secrets utilisateur pendant le développement

Intégration de l’authentification Azure Container Apps

L’infrastructure affiche des modèles d’authentification avancés à l’aide des fonctionnalités d’authentification et d’autorisation intégrées Azure Container Apps (« Authentification simple ») :

// containerapps-authconfigs.bicep
resource containerappAuthConfig 'Microsoft.App/containerApps/authConfigs@2024-10-02-preview' = {
  properties: {
    identityProviders: {
      azureActiveDirectory: {
        enabled: true
        registration: {
          clientId: clientId
          openIdIssuer: openIdIssuer
        }
      }
    }
    login: {
      tokenStore: {
        enabled: true
        azureBlobStorage: {
          blobContainerUri: '${storageAccount.properties.primaryEndpoints.blob}/token-store'
          managedIdentityResourceId: userAssignedIdentity.id
        }
      }
    }
  }
}

Fonctionnalités d’authentification avancées :

  • AuthentificationZero-Code : Azure Container Apps fournit une authentification intégrée
  • Identité managée pour le stockage : le système stocke les jetons de manière sécurisée sans chaînes de connexion
  • Informations d’identification d’identité fédérée : le système active l’identité de charge de travail pour l’authentification de style Kubernetes

Le diagramme suivant montre l’établissement d’une liaison de sécurité entre les composants :

Diagramme montrant l’établissement d’une liaison de sécurité entre les composants.

Découverte et inscription des outils

Le client MCP découvre les outils disponibles à partir du serveur pendant l’initialisation des composants dans Chat.razor:

protected override async Task OnInitializedAsync()
{
    messages.Add(new(ChatRole.System, SystemPrompt));
    tools = await McpClient.ListToolsAsync();
    chatOptions.Tools = [.. tools];
}

Fonctionnement de la découverte des outils :

  1. Requête serveur : McpClient.ListToolsAsync() envoie une requête au serveur MCP pour répertorier les outils disponibles
  2. Récupération de schéma : le serveur renvoie des définitions d’outils avec des noms, des descriptions et des schémas d’entrée
  3. Inscription de l’outil : le système inscrit des outils auprès de l’objet ChatOptions , les rendant disponibles pour le client OpenAI
  4. Sécurité de type : la McpClientTool classe hérite de AIFunction, donnant une intégration fluide avec Microsoft.Extensions.AI

Le diagramme suivant montre comment les schémas d’outil sont analysés et inscrits :

Diagramme montrant le flux de découverte et d’inscription de l’outil.

Appel d’intégration et de fonction OpenAI

La configuration du client de conversation montre comment les outils MCP s’intègrent à Azure OpenAI :

var chatClient = openAIClient.GetChatClient(config["OpenAI:DeploymentName"]).AsIChatClient();

builder.Services.AddChatClient(chatClient)
                .UseFunctionInvocation()
                .UseLogging();

Avantages de l’intégration :

  • Appel automatique de fonction : l’extension .UseFunctionInvocation() active l’exécution automatique des outils en fonction des décisions LLM
  • Accès facile aux outils : les outils MCP fonctionnent en tant que fonctions intégrées pour le modèle OpenAI
  • Traitement des réponses : le système ajoute automatiquement les résultats de l’outil au flux de conversation

implémentation de conversation Real-Time

L’interface de conversation présente Chat.razor les réponses de streaming et l’exécution d’outils avec des modèles Blazor avancés :

private async Task AddUserMessageAsync(ChatMessage userMessage)
{
    CancelAnyCurrentResponse();

    // Add the user message to the conversation
    messages.Add(userMessage);
    chatSuggestions?.Clear();
    await chatInput!.FocusAsync();

    // Stream and display a new response from the IChatClient
    var responseText = new TextContent("");
    currentResponseMessage = new ChatMessage(ChatRole.Assistant, [responseText]);
    currentResponseCancellation = new();
    await foreach (var update in ChatClient.GetStreamingResponseAsync([.. messages], chatOptions, currentResponseCancellation.Token))
    {
        messages.AddMessages(update, filter: c => c is not TextContent);
        responseText.Text += update.Text;
        ChatMessageItem.NotifyChanged(currentResponseMessage);
    }

    // Store the final response in the conversation, and begin getting suggestions
    messages.Add(currentResponseMessage!);
    currentResponseMessage = null;
    chatSuggestions?.Update(messages);
}

Fonctionnalités d’implémentation de streaming :

  • Real-Time Mises à jour : GetStreamingResponseAsync() envoie les mises à jour de réponse bit par bit
  • Exécution de l’outil : le système traite automatiquement les appels de fonction pendant la diffusion en continu
  • Réactivité de l’interface utilisateur : ChatMessageItem.NotifyChanged() met à jour l’interface utilisateur en temps réel
  • Prise en charge de l’annulation : les utilisateurs peuvent annuler des opérations de longue durée

Modèles avancés d’interface utilisateur Blazor

L’implémentation utilise des modèles d’interface utilisateur avancés pour les mises à jour en temps réel :

gestion des événementsMemory-Safe :

// ChatMessageItem.razor
private static readonly ConditionalWeakTable<ChatMessage, ChatMessageItem> SubscribersLookup = new();

public static void NotifyChanged(ChatMessage source)
{
    if (SubscribersLookup.TryGetValue(source, out var subscriber))
    {
        subscriber.StateHasChanged();
    }
}

Intégration des composants web personnalisés :

// ChatMessageList.razor.js
window.customElements.define('chat-messages', class ChatMessages extends HTMLElement {
    connectedCallback() {
        this._observer = new MutationObserver(mutations => this._scheduleAutoScroll(mutations));
        this._observer.observe(this, { childList: true, attributes: true });
    }
    
    _scheduleAutoScroll(mutations) {
        // Debounce the calls and handle smart auto-scrolling
        cancelAnimationFrame(this._nextAutoScroll);
        this._nextAutoScroll = requestAnimationFrame(() => {
            const addedUserMessage = mutations.some(m => 
                Array.from(m.addedNodes).some(n => 
                    n.parentElement === this && n.classList?.contains('user-message')));
            // Smart scrolling logic...
        });
    }
});

Gestion avancée de l’état :

// Chat.razor
private void CancelAnyCurrentResponse()
{
    // If a response was cancelled while streaming, include it in the conversation so it's not lost
    if (currentResponseMessage is not null)
    {
        messages.Add(currentResponseMessage);
    }
    
    currentResponseCancellation?.Cancel();
    currentResponseMessage = null;
}

Avantages de l’interface utilisateur Blazor :

  • Composants web hybrides : le système combine Blazor Server avec des éléments personnalisés pour améliorer les performances
  • Memory-Safe Gestion des événements : le système utilise ConditionalWeakTable pour empêcher les fuites de mémoire
  • Défilement automatique intelligent : le système fournit un comportement de conversation convivial avec le débouchage
  • Annulation appropriée : le système enregistre le travail partiel lorsque les utilisateurs annulent les opérations

Flux de demande/réponse

Voici comment une interaction utilisateur classique transite par le système :

  1. Entrée utilisateur : l’utilisateur tape un message comme « Ajouter « Acheter des épiceries » à ma liste de tâches
  2. Traitement des messages : le système ajoute le message à l’historique des conversations
  3. Analyse LLM : Azure OpenAI analyse la demande et décide quels outils utiliser
  4. Découverte d’outils : le modèle recherche l’outil MCP approprié (par exemple, addTodo)
  5. Exécution de l’outil : le client MCP appelle le serveur avec les paramètres nécessaires
  6. Traitement de la réponse : le système ajoute la réponse du serveur à la conversation
  7. Mise à jour de l’interface utilisateur : le système affiche le résultat à l’utilisateur en temps réel

Le diagramme suivant montre comment les messages circulent de l’entrée utilisateur via OpenAI pour l’exécution de l’outil et revenir à l’interface utilisateur :

Diagramme montrant le flux de requête/réponse.

Gestion des modèles asynchrones

L’application illustre des modèles asynchrones sophistiqués pour les opérations en arrière-plan :

// ChatSuggestions.razor
public void Update(IReadOnlyList<ChatMessage> messages)
{
    // Runs in the background and handles its own cancellation/errors
    _ = UpdateSuggestionsAsync(messages);
}

private async Task UpdateSuggestionsAsync(IReadOnlyList<ChatMessage> messages)
{
    cancellation?.Cancel();
    cancellation = new CancellationTokenSource();
    
    try
    {
        var response = await ChatClient.GetResponseAsync<string[]>(
            [.. ReduceMessages(messages), new(ChatRole.User, Prompt)],
            cancellationToken: cancellation.Token);
        // Handle response...
    }
    catch (Exception ex) when (ex is not OperationCanceledException)
    {
        await DispatchExceptionAsync(ex);
    }
}

Avantages des tâches en arrière-plan :

  • Fire-and-Forget with Safety : le système utilise _ = le modèle avec une gestion appropriée des exceptions
  • Réduction intelligente du contexte : le système limite l’historique des conversations pour empêcher le dépassement de jeton
  • Annulation intelligente : le système nettoie correctement les opérations concurrentes

Gestion des erreurs et résilience

L’implémentation comprend plusieurs modèles de résilience :

private void CancelAnyCurrentResponse()
{
    // If a response was cancelled while streaming, include it in the conversation so it's not lost
    if (currentResponseMessage is not null)
    {
        messages.Add(currentResponseMessage);
    }

    currentResponseCancellation?.Cancel();
    currentResponseMessage = null;
}

Fonctionnalités de résilience :

  • Annulation appropriée : le système enregistre les réponses en cours lorsque les utilisateurs les annulent
  • Récupération de connexion : le transport SSE gère automatiquement la connexion
  • Gestion de l’état : l’état de l’interface utilisateur reste cohérent pendant les erreurs
  • Intégration de la journalisation : le système fournit une journalisation complète pour le débogage et la surveillance

Observabilité et vérifications d’intégrité

L’application comprend des modèles d’observabilité sophistiqués :

Configuration smart Health Check :

// Extensions.cs
public static WebApplication MapDefaultEndpoints(this WebApplication app)
{
    if (app.Environment.IsDevelopment())
    {
        // All health checks must pass for app to be considered ready
        app.MapHealthChecks(HealthEndpointPath);
        
        // Only health checks tagged with "live" must pass for app to be considered alive
        app.MapHealthChecks(AlivenessEndpointPath, new HealthCheckOptions
        {
            Predicate = r => r.Tags.Contains("live")
        });
    }
    return app;
}

OpenTelemetry avec filtrage intelligent :

// Extensions.cs
.AddAspNetCoreInstrumentation(tracing =>
    // Exclude health check requests from tracing
    tracing.Filter = context =>
        !context.Request.Path.StartsWithSegments(HealthEndpointPath)
        && !context.Request.Path.StartsWithSegments(AlivenessEndpointPath)
)

Avantages de l’observabilité :

  • points de terminaisonEnvironment-Aware : exposition au contrôle d’intégrité sensible à la sécurité
  • Liveness vs Readiness : modèles de contrôle d’intégrité de style Kubernetes
  • Réduction du bruit de télémétrie : filtrage des contrôles d’intégrité de routine à partir de traces

Configuration et configuration de l’environnement

L’application prend en charge plusieurs environnements par le biais de la configuration :

var openAIClient = Constants.GitHubModelEndpoints.Contains(endpoint.TrimEnd('/'))
                   ? new OpenAIClient(credential, openAIOptions)
                   : new AzureOpenAIClient(new Uri(endpoint), credential);

Options de configuration :

  • Azure OpenAI : Les déploiements de production utilisent généralement Azure OpenAI Service
  • Modèles GitHub : les scénarios de développement peuvent utiliser des modèles GitHub
  • Développement local : prise en charge des instances de serveur MCP locales
  • Déploiement de conteneurs : Azure Container Apps pour l’hébergement en production

Nettoyer les ressources

Une fois que vous avez terminé d’utiliser l’agent MCP, nettoyez les ressources que vous avez créées pour éviter les coûts inutiles.

Pour nettoyer les ressources, procédez comme suit :

  • Supprimez les ressources Azure créées par Azure Developer CLI en exécutant la commande suivante dans le terminal en bas de l’écran :

    azd down --purge --force
    

Nettoyer GitHub Codespaces

Supprimez l’environnement GitHub Codespaces pour optimiser vos heures de base gratuites.

Important

Pour plus d’informations sur le stockage gratuit et les heures de base de votre compte GitHub, consultez GitHub Codespaces, stockage et heures principales inclus mensuellement.

  1. Connectez-vous au tableau de bord GitHub Codespaces.

  2. Recherchez vos espaces de code actifs créés à partir du Azure-Samples/openai-mcp-agent-dotnet dépôt GitHub.

  3. Ouvrez le menu contextuel de l’espace de code, puis sélectionnez Supprimer.

Obtenir de l’aide

Consignez votre problème dans les problèmes du référentiel.