File: Components\Dialogs\McpServerDialog.razor.cs
Web Access
Project: src\src\Aspire.Dashboard\Aspire.Dashboard.csproj (Aspire.Dashboard)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using Aspire.Dashboard.Configuration;
using Aspire.Dashboard.Mcp;
using Aspire.Dashboard.Model.Markdown;
using Aspire.Dashboard.Resources;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using Microsoft.FluentUI.AspNetCore.Components;
 
namespace Aspire.Dashboard.Components.Dialogs;
 
public partial class McpServerDialog
{
    [CascadingParameter]
    public FluentDialog Dialog { get; set; } = default!;
 
    [Inject]
    public required IStringLocalizer<ControlsStrings> ControlsStringsLoc { get; init; }
 
    [Inject]
    public required IStringLocalizer<Resources.Dialogs> Loc { get; init; }
 
    [Inject]
    public required NavigationManager NavigationManager { get; init; }
 
    [Inject]
    public required IOptions<DashboardOptions> DashboardOptions { get; init; }
 
    private MarkdownProcessor _markdownProcessor = default!;
    private string? _mcpServerInstallButtonJson;
    private string? _mcpServerConfigFileJson;
    private string? _mcpUrl;
    private bool _isHttps;
    private McpToolView _activeView;
    private List<McpConfigPropertyViewModel> _mcpConfigProperties = [];
 
    protected override void OnInitialized()
    {
        _markdownProcessor = new MarkdownProcessor(ControlsStringsLoc, MarkdownHelpers.SafeUrlSchemes, []);
        if ((DashboardOptions.Value.Mcp.PublicUrl ?? DashboardOptions.Value.Mcp.EndpointUrl) is { Length: > 0 } mcpUrl)
        {
            var uri = new Uri(baseUri: new Uri(mcpUrl), relativeUri: "/mcp");
 
            _mcpUrl = uri.ToString();
            _isHttps = uri.Scheme == "https";
        }
 
        if (McpEnabled)
        {
            (_mcpServerInstallButtonJson, _mcpServerConfigFileJson) = GetMcpServerInstallButtonJson();
            _mcpConfigProperties =
            [
                new McpConfigPropertyViewModel { Name = "name", Value = "aspire-dashboard" },
                new McpConfigPropertyViewModel { Name = "type", Value = "http" },
                new McpConfigPropertyViewModel { Name = "url", Value = _mcpUrl }
            ];
 
            if (DashboardOptions.Value.Mcp.AuthMode == McpAuthMode.ApiKey)
            {
                _mcpConfigProperties.Add(new McpConfigPropertyViewModel { Name = $"{McpApiKeyAuthenticationHandler.ApiKeyHeaderName} (header)", Value = DashboardOptions.Value.Mcp.PrimaryApiKey! });
            }
        }
        else
        {
            throw new InvalidOperationException("MCP server is not enabled or configured.");
        }
    }
 
    [MemberNotNullWhen(true, nameof(_mcpServerInstallButtonJson))]
    [MemberNotNullWhen(true, nameof(_mcpUrl))]
    private bool McpEnabled => !DashboardOptions.Value.Mcp.Disabled.GetValueOrDefault() && !string.IsNullOrEmpty(_mcpUrl);
 
    private (string InstallButtonJson, string ConfigFileJson) GetMcpServerInstallButtonJson()
    {
        Debug.Assert(_mcpUrl != null);
 
        Dictionary<string, string>? headers = null;
 
        if (DashboardOptions.Value.Mcp.AuthMode == McpAuthMode.ApiKey)
        {
            headers = new Dictionary<string, string>
            {
                [McpApiKeyAuthenticationHandler.ApiKeyHeaderName] = DashboardOptions.Value.Mcp.PrimaryApiKey!
            };
        }
 
        var name = "aspire-dashboard";
 
        var installButtonJson = JsonSerializer.Serialize(
            new McpInstallButtonServerModel
            {
                Name = name,
                Type = "http",
                Url = _mcpUrl,
                Headers = headers
            },
            McpInstallButtonModelContext.Default.McpInstallButtonServerModel);
 
        var configFileJson = JsonSerializer.Serialize(
            new McpJsonFileServerModel
            {
                Servers = new()
                {
                    [name] = new()
                    {
                        Type = "http",
                        Url = _mcpUrl,
                        Headers = headers
                    }
                }
            },
            McpConfigFileModelContext.Default.McpJsonFileServerModel);
 
        return (installButtonJson, configFileJson);
    }
 
    private Task OnTabChangeAsync(FluentTab newTab)
    {
        var id = newTab.Id?.Substring("tab-".Length);
 
        if (id is null
            || !Enum.TryParse(typeof(McpToolView), id, out var o)
            || o is not McpToolView viewKind)
        {
            return Task.CompletedTask;
        }
 
        _activeView = viewKind;
        return Task.CompletedTask;
    }
 
    private string GetJsonConfigurationMarkdown() =>
        $"""
        ```json
        {_mcpServerConfigFileJson}
        ```
        """;
 
    public enum McpToolView
    {
        VisualStudio,
        VSCode,
        Other
    }
}