< Summary

Information
Class: UIBlazor.Components.Settings.MCPSettingsTab
Assembly: UIBlazor
File(s): /home/runner/work/InvAit/InvAit/UIBlazor/Components/Settings/MCPSettingsTab.razor
Tag: 71_26091983037
Line coverage
0%
Covered lines: 0
Uncovered lines: 79
Coverable lines: 79
Total lines: 212
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 56
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_McpSettingsProvider()100%210%
get_NotificationService()100%210%
get_DialogService()100%210%
get_ToolManager()100%210%
OnMcpEnabledChanged()0%620%
OnOpenMcpSettings()100%210%
OnReloadMcpSettings()100%210%
OnRefreshMcpTools()0%2040%
GetMcpServerApprovalMode(...)0%620%
OnMcpServerApprovalChanged()100%210%
OnMcpToolSettingChanged()0%7280%
TestRun()100%210%

File(s)

/home/runner/work/InvAit/InvAit/UIBlazor/Components/Settings/MCPSettingsTab.razor

#LineLine coverage
 1@using Shared.Contracts.Mcp
 2@inherits RadzenComponent
 3
 4<RadzenStack Gap="0.5rem">
 5    <RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" JustifyContent="JustifyContent.Spac
 6        <CheckBox Text="Enable MCP" @bind-Value="@McpSettingsProvider.Current.Enabled" @bind-Value:after="OnMcpEnabledCh
 7        <RadzenStack Orientation="Orientation.Horizontal" Gap="0.3rem" JustifyContent="JustifyContent.End">
 8            <RadzenButton Icon="edit_note" ButtonStyle="ButtonStyle.Info" Size="ButtonSize.Small" Click="@OnOpenMcpSetti
 9            <RadzenButton Icon="refresh" ButtonStyle="ButtonStyle.Light" Size="ButtonSize.Small" Click="@OnReloadMcpSett
 10        </RadzenStack>
 11    </RadzenStack>
 12
 013    @if (McpSettingsProvider.Current.Enabled)
 14    {
 015        @if (!McpSettingsProvider.Current.Servers.Any())
 16        {
 17            <RadzenText TextStyle="TextStyle.Caption" class="server-error-text">
 018                @SharedResource.NoMCP
 19            </RadzenText>
 20        }
 21
 022        @foreach (var server in McpSettingsProvider.Current.Servers)
 23        {
 024            var hasError = McpSettingsProvider.Current.ServerErrors.TryGetValue(server.Name, out var errorMsg);
 025            var borderColor = hasError ? "var(--rz-error-color)" : "var(--rz-border-color)";
 026            var serverStyle = $"border: 1px solid {borderColor}; border-radius: var(--rz-border-radius);";
 27
 28            <RadzenStack Gap="0.5rem" Style="@serverStyle">
 29                <RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" JustifyContent="Justify
 30                    <RadzenStack Orientation="Orientation.Horizontal" Gap="0.5rem" AlignItems="AlignItems.Center">
 31                        <CheckBox Text="@server.Name" @bind-Value="@server.Enabled" @bind-Value:after="OnMcpToolSettingC
 32                    </RadzenStack>
 33                    <ApprovalModeSelector Value="@GetMcpServerApprovalMode(server)" Disabled="@(!server.Enabled)"
 034                                          ValueChanged="@(mode => OnMcpServerApprovalChanged(server, mode))" />
 35                </RadzenStack>
 36
 037                @if (hasError && !string.IsNullOrEmpty(errorMsg))
 38                {
 39                    <RadzenStack class="server-error-text">
 040                        <strong>Error:</strong> @errorMsg
 41                    </RadzenStack>
 42                }
 43
 044                @if (server.Enabled)
 45                {
 46                    <RadzenStack Orientation="Orientation.Horizontal" Gap="0.5rem" Style="padding-left: 2rem;">
 47                        <RadzenBadge Text="@server.Transport" />
 048                        @if (hasError)
 49                        {
 50                            <RadzenBadge Text="@SharedResource.Error" Style="font-size: 0.7rem; background: var(--rz-err
 51                        }
 052                        else if (server.Enabled && server.Tools.Any())
 53                        {
 54                            <RadzenBadge Text="@SharedResource.Ready" Style="font-size: 0.7rem; background: var(--rz-suc
 55                        }
 56                    </RadzenStack>
 57                    <RadzenStack Gap="0.2rem" class="server-commands">
 058                        @if (server.Transport == "stdio")
 59                        {
 060                            <div>Command: @server.Command @(string.Join(" ", server.Args))</div>
 61                        }
 62                        else
 63                        {
 064                            <div>URL: @server.Url</div>
 65                        }
 066                        @if (server.Env.Any())
 67                        {
 068                            <div>Env: @server.Env.Count variable(s)</div>
 69                        }
 70                    </RadzenStack>
 71
 72                    <RadzenStack Orientation="Orientation.Horizontal" Gap="0.3rem" Style="padding-left: 2rem;">
 73                        <RadzenButton Text="@SharedResource.RefreshTools" Icon="sync" Size="ButtonSize.ExtraSmall" Butto
 074                                      Click="@(() => OnRefreshMcpTools(server))" IsBusy="@(_refreshingServerId == server
 75                    </RadzenStack>
 76
 077                    @if (server.Tools.Any())
 78                    {
 79                        <RadzenAccordion Style="margin-top: 0.3rem; border: none;">
 80                            <Items>
 81                                <RadzenAccordionItem Text="@SharedResource.Tools" Icon="build">
 82                                    <RadzenStack Gap="0.5rem">
 083                                        @foreach (var tool in server.Tools)
 84                                        {
 85                                            <RadzenStack Orientation="Orientation.Vertical" JustifyContent="JustifyConte
 86                                                <RadzenStack Orientation="Orientation.Horizontal" JustifyContent="Justif
 87                                                    <CheckBox Text="@tool.Name" @bind-Value="@tool.Enabled" @bind-Value:
 088                                                    <RadzenButton Icon="science" Size="ButtonSize.ExtraSmall" ButtonStyl
 89                                                </RadzenStack>
 090                                                <RadzenText TextStyle="TextStyle.Caption" class="tool-description">@tool
 91                                            </RadzenStack>
 92                                        }
 93                                    </RadzenStack>
 94                                </RadzenAccordionItem>
 95                            </Items>
 96                        </RadzenAccordion>
 97                    }
 98                }
 99            </RadzenStack>
 100        }
 101    }
 102</RadzenStack>
 103
 104    @code {
 0105    [Inject] IMcpSettingsProvider McpSettingsProvider { get; set; } = null!;
 0106    [Inject] NotificationService NotificationService { get; set; } = null!;
 0107    [Inject] DialogService DialogService { get; set; } = null!;
 0108    [Inject] IToolManager ToolManager { get; set; } = null!;
 109
 110    private string? _refreshingServerId;
 111
 112    private async Task OnMcpEnabledChanged()
 113    {
 0114        if (!McpSettingsProvider.Current.Enabled)
 115        {
 0116            await McpSettingsProvider.StopAllAsync();
 117        }
 0118        await McpSettingsProvider.SaveAsync();
 0119    }
 120
 121    private async Task OnOpenMcpSettings()
 122    {
 0123        await McpSettingsProvider.OpenSettingsFileAsync();
 0124    }
 125
 126    private async Task OnReloadMcpSettings()
 127    {
 0128        await McpSettingsProvider.LoadMcpFileAsync();
 0129        StateHasChanged();
 0130    }
 131
 132    private async Task OnRefreshMcpTools(McpServerConfig server)
 133    {
 0134        _refreshingServerId = server.Name;
 0135        StateHasChanged();
 136
 0137        var result = await McpSettingsProvider.RefreshToolsAsync(server);
 138
 0139        _refreshingServerId = null;
 140
 141        // Update error state
 0142        if (result.StartsWith("Success"))
 143        {
 0144            McpSettingsProvider.Current.ServerErrors.Remove(server.Name);
 145        }
 146        else
 147        {
 0148            McpSettingsProvider.Current.ServerErrors[server.Name] = result;
 149        }
 150
 0151        NotificationService.Notify(new NotificationMessage
 0152        {
 0153            Severity = result.StartsWith("Success") ? NotificationSeverity.Success : NotificationSeverity.Error,
 0154            Summary = result,
 0155            Duration = 4000
 0156        });
 157
 0158        await McpSettingsProvider.SaveAsync();
 0159        StateHasChanged();
 0160    }
 161
 162    private ToolApprovalMode GetMcpServerApprovalMode(McpServerConfig server)
 163    {
 0164        return McpSettingsProvider.Current.ServerApprovalModes.TryGetValue(server.Name, out var mode)
 0165            ? mode
 0166            : ToolApprovalMode.Allow;
 167    }
 168
 169    private async Task OnMcpServerApprovalChanged(McpServerConfig server, ToolApprovalMode mode)
 170    {
 0171        McpSettingsProvider.Current.ServerApprovalModes[server.Name] = mode;
 0172        await McpSettingsProvider.SaveAsync();
 0173    }
 174
 175    private void OnMcpToolSettingChanged()
 176    {
 177        // Update server enabled states
 0178        foreach (var server in McpSettingsProvider.Current.Servers)
 179        {
 0180            McpSettingsProvider.Current.ServerEnabledStates[server.Name] = server.Enabled;
 181        }
 182
 0183        McpSettingsProvider.Current.ToolDisabledStates.Clear();
 184
 0185        foreach (var server in McpSettingsProvider.Current.Servers)
 186        {
 0187            foreach (var tool in server.Tools)
 188            {
 0189                var toolKey = $"{server.Name}:{tool.Name}";
 0190                if (!tool.Enabled)
 191                {
 0192                    McpSettingsProvider.Current.ToolDisabledStates.Add(toolKey);
 193                }
 194            }
 195        }
 196
 0197        McpSettingsProvider.CallSaveTrigger();
 0198    }
 199
 200    private async Task TestRun(string serverName, McpToolConfig mcpTool) {
 0201        await DialogService.OpenAsync<MCPTestRun>(
 0202            $"{serverName} - {mcpTool.Name}",
 0203            new Dictionary<string, object?> { { "Tool", mcpTool }, { "ServerName", serverName } },
 0204            new DialogOptions {
 0205                Resizable = true,
 0206                Icon = "science",
 0207                Top = "1em",
 0208                Width = "50em"
 0209            }
 0210        );
 0211    }
 212}