Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@
<PackageVersion Include="Microsoft.FluentUI.AspNetCore.Components" Version="4.13.0" />
<PackageVersion Include="Microsoft.FluentUI.AspNetCore.Components.Icons" Version="4.13.0" />
<PackageVersion Include="Milvus.Client" Version="2.3.0-preview.1" />
<PackageVersion Include="ModelContextProtocol" Version="0.3.0-preview.4" />
<PackageVersion Include="ModelContextProtocol" Version="0.4.0-preview.2" />
<PackageVersion Include="ModelContextProtocol.AspNetCore" Version="0.4.0-preview.2" />
<PackageVersion Include="MongoDB.Driver" Version="3.5.0" />
<PackageVersion Include="MongoDB.Driver.Core.Extensions.DiagnosticSources" Version="2.1.0" />
<PackageVersion Include="MySqlConnector.DependencyInjection" Version="2.4.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:16037",
"ASPIRE_DASHBOARD_MCP_ENDPOINT_URL": "https://localhost:16036",
//"ASPIRE_DASHBOARD_OTLP_HTTP_ENDPOINT_URL": "https://localhost:16038",
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:17037"
}
Expand All @@ -22,6 +23,7 @@
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:16031",
"ASPIRE_DASHBOARD_MCP_ENDPOINT_URL": "http://localhost:16033",
//"ASPIRE_DASHBOARD_OTLP_HTTP_ENDPOINT_URL": "http://localhost:16032",
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:17031",
"ASPIRE_ALLOW_UNSECURED_TRANSPORT": "true"
Expand Down
1 change: 1 addition & 0 deletions src/Aspire.Cli/Commands/RunCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ protected override async Task<int> ExecuteAsync(ParseResult parseResult, Cancell
env["ASPNETCORE_ENVIRONMENT"] = "Development";
env["DOTNET_ENVIRONMENT"] = "Development";
env["ASPNETCORE_URLS"] = "https://localhost:17193;http://localhost:15069";
env["ASPIRE_DASHBOARD_MCP_ENDPOINT_URL"] = "https://localhost:21294";
env["ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL"] = "https://localhost:21293";
env["ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL"] = "https://localhost:22086";
}
Expand Down
8 changes: 8 additions & 0 deletions src/Aspire.Dashboard/Aspire.Dashboard.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@
<RollForward>Major</RollForward>

<DefineConstants>$(DefineConstants);ASPIRE_DASHBOARD</DefineConstants>

<!--
Enable raw string literals support in Razor. Can remove when target switches to .NET 10+.
See https://devblogs.microsoft.com/dotnet/enhancing-razor-productivity-with-new-features/
-->
<Features>use-roslyn-tokenizer</Features>
</PropertyGroup>

<PropertyGroup>
Expand Down Expand Up @@ -51,6 +57,8 @@
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" />
<PackageReference Include="Microsoft.FluentUI.AspNetCore.Components" />
<PackageReference Include="Microsoft.FluentUI.AspNetCore.Components.Icons" />
<PackageReference Include="ModelContextProtocol" />
<PackageReference Include="ModelContextProtocol.AspNetCore" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ public enum ConnectionType
{
None,
Frontend,
Otlp
Otlp,
Mcp
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public static class ConnectionTypeAuthenticationDefaults
{
public const string AuthenticationSchemeFrontend = "ConnectionFrontend";
public const string AuthenticationSchemeOtlp = "ConnectionOtlp";
public const string AuthenticationSchemeMcp = "ConnectionMcp";
}

public sealed class ConnectionTypeAuthenticationHandlerOptions : AuthenticationSchemeOptions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
namespace Aspire.Dashboard.Authentication.Connection;

/// <summary>
/// This connection middleware registers an OTLP feature on the connection.
/// OTLP services check for this feature when authorizing incoming requests to
/// ensure OTLP is only available on specified connections.
/// This connection middleware registers a connection type feature on the connection.
/// OTLP and MCP services check for this feature when authorizing incoming requests to
/// ensure services are only available on specified connections.
/// </summary>
internal sealed class ConnectionTypeMiddleware
{
Expand Down
5 changes: 5 additions & 0 deletions src/Aspire.Dashboard/Components/CustomIcons/AspireIcons.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ internal sealed class Logo : Icon { public Logo() : base("Logo", IconVariant.Reg
</defs>
</svg>
") { } }
internal sealed class McpIcon : Icon { public McpIcon() : base("McpIcon", IconVariant.Regular, IconSize.Size24,
"""
<path transform="scale(0.9) translate(2 2)" d="M15.688 2.343a2.588 2.588 0 00-3.61 0l-9.626 9.44a.863.863 0 01-1.203 0 .823.823 0 010-1.18l9.626-9.44a4.313 4.313 0 016.016 0 4.116 4.116 0 011.204 3.54 4.3 4.3 0 013.609 1.18l.05.05a4.115 4.115 0 010 5.9l-8.706 8.537a.274.274 0 000 .393l1.788 1.754a.823.823 0 010 1.18.863.863 0 01-1.203 0l-1.788-1.753a1.92 1.92 0 010-2.754l8.706-8.538a2.47 2.47 0 000-3.54l-.05-.049a2.588 2.588 0 00-3.607-.003l-7.172 7.034-.002.002-.098.097a.863.863 0 01-1.204 0 .823.823 0 010-1.18l7.273-7.133a2.47 2.47 0 00-.003-3.537z"/>
<path transform="scale(0.9) translate(2 2)" d="M14.485 4.703a.823.823 0 000-1.18.863.863 0 00-1.204 0l-7.119 6.982a4.115 4.115 0 000 5.9 4.314 4.314 0 006.016 0l7.12-6.982a.823.823 0 000-1.18.863.863 0 00-1.204 0l-7.119 6.982a2.588 2.588 0 01-3.61 0 2.47 2.47 0 010-3.54l7.12-6.982z"/>
""") { } }
}

internal static class Size48
Expand Down
57 changes: 57 additions & 0 deletions src/Aspire.Dashboard/Components/Dialogs/McpServerDialog.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
@implements IDialogContentComponent

@using Aspire.Dashboard.Components.CustomIcons
@using Aspire.Dashboard.Configuration
@using Aspire.Dashboard.Mcp
@using Aspire.Dashboard.Model.Markdown
@using Microsoft.AspNetCore.Components
@using Microsoft.Extensions.Options
@using System.Text.Encodings.Web
@using System.Text.Json

<div class="mcp-server-dialog-content">
@if (McpEnabled)
{
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi vitae condimentum nulla, nec viverra purus. Morbi cursus egestas leo, eget lacinia quam hendrerit non.
Copy link

Copilot AI Oct 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Placeholder "Lorem ipsum" text should be replaced with real guidance explaining MCP server usage (e.g. purpose, how to install, security considerations); substitute with actionable, product-appropriate content.

Suggested change
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi vitae condimentum nulla, nec viverra purus. Morbi cursus egestas leo, eget lacinia quam hendrerit non.
The Aspire MCP (Model Context Protocol) server enables advanced integration with development tools such as Visual Studio Code. By running the MCP server, you can connect your Aspire application to supported IDEs for enhanced debugging, diagnostics, and management features.

Copilot uses AI. Check for mistakes.

</p>
<h5>Add to VS Code</h5>
<p>
<a href="@($"vscode:mcp/install?{Uri.EscapeDataString(_mcpServerJson)}")">
<svg xmlns="http://www.w3.org/2000/svg" width="225" height="20" role="img" aria-label="VS Code: Install Aspire MCP Server">
<title>VS Code: Install Aspire MCP Server</title>
<g shape-rendering="crispEdges"><rect width="74" height="20" fill="#555" /><rect x="74" width="151" height="20" fill="#0098ff" /></g>
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><image x="5" y="3" width="14" height="14" href="data:image/svg+xml;base64,PHN2ZyBmaWxsPSJ3aGl0ZSIgcm9sZT0iaW1nIiB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHRpdGxlPk1vZGVsIENvbnRleHQgUHJvdG9jb2w8L3RpdGxlPjxwYXRoIGQ9Ik0xMy44NSAwYTQuMTYgNC4xNiAwIDAgMC0yLjk1IDEuMjE3TDEuNDU2IDEwLjY2YS44MzUuODM1IDAgMCAwIDAgMS4xOC44MzUuODM1IDAgMCAwIDEuMTggMGw5LjQ0Mi05LjQ0MmEyLjQ5IDIuNDkgMCAwIDEgMy41NDEgMCAyLjQ5IDIuNDkgMCAwIDEgMCAzLjU0MUw4LjU5IDEyLjk3bC0uMS4xYS44MzUuODM1IDAgMCAwIDAgMS4xOC44MzUuODM1IDAgMCAwIDEuMTggMGwuMS0uMDk4IDcuMDMtNy4wMzRhMi40OSAyLjQ5IDAgMCAxIDMuNTQyIDBsLjA0OS4wNWEyLjQ5IDIuNDkgMCAwIDEgMCAzLjU0bC04LjU0IDguNTRhMS45NiAxLjk2IDAgMCAwIDAgMi43NTVsMS43NTMgMS43NTNhLjgzNS44MzUgMCAwIDAgMS4xOCAwIC44MzUuODM1IDAgMCAwIDAtMS4xOGwtMS43NTMtMS43NTNhLjI2Ni4yNjYgMCAwIDEgMC0uMzk0bDguNTQtOC41NGE0LjE4NSA0LjE4NSAwIDAgMCAwLTUuOWwtLjA1LS4wNWE0LjE2IDQuMTYgMCAwIDAtMi45NS0xLjIxOGMtLjIgMC0uNDAxLjAyLS42LjA0OGE0LjE3IDQuMTcgMCAwIDAtMS4xNy0zLjU1MkE0LjE2IDQuMTYgMCAwIDAgMTMuODUgMG0wIDMuMzMzYS44NC44NCAwIDAgMC0uNTkuMjQ1TDYuMjc1IDEwLjU2YTQuMTg2IDQuMTg2IDAgMCAwIDAgNS45MDIgNC4xODYgNC4xODYgMCAwIDAgNS45MDIgMEwxOS4xNiA5LjQ4YS44MzUuODM1IDAgMCAwIDAtMS4xOC44MzUuODM1IDAgMCAwLTEuMTggMGwtNi45ODUgNi45ODRhMi40OSAyLjQ5IDAgMCAxLTMuNTQgMCAyLjQ5IDIuNDkgMCAwIDEgMC0zLjU0bDYuOTgzLTYuOTg1YS44MzUuODM1IDAgMCAwIDAtMS4xOC44NC44NCAwIDAgMC0uNTktLjI0NSIvPjwvc3ZnPg==" /><text x="465" y="140" transform="scale(.1)" fill="#fff" textLength="470">VS Code</text><text x="1485" y="140" transform="scale(.1)" fill="#fff" textLength="1410">Install Aspire MCP Server</text></g>
</svg>
@*
Generated from:
https://img.shields.io/badge/VS_Code-Install_Aspire_MCP_Server-0098FF?style=flat-square&logo=modelcontextprotocol&logoColor=white
*@
</a>
</p>
<p>
<a href="@($"vscode-insiders:mcp/install?{Uri.EscapeDataString(_mcpServerJson)}")">
<svg xmlns="http://www.w3.org/2000/svg" width="273" height="20" role="img" aria-label="VS Code Insiders: Install Aspire MCP Server">
<title>VS Code Insiders: Install Aspire MCP Server</title>
<g shape-rendering="crispEdges"><rect width="122" height="20" fill="#555" /><rect x="122" width="151" height="20" fill="#65bba5" /></g>
<g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><image x="5" y="3" width="14" height="14" href="data:image/svg+xml;base64,PHN2ZyBmaWxsPSJ3aGl0ZSIgcm9sZT0iaW1nIiB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHRpdGxlPk1vZGVsIENvbnRleHQgUHJvdG9jb2w8L3RpdGxlPjxwYXRoIGQ9Ik0xMy44NSAwYTQuMTYgNC4xNiAwIDAgMC0yLjk1IDEuMjE3TDEuNDU2IDEwLjY2YS44MzUuODM1IDAgMCAwIDAgMS4xOC44MzUuODM1IDAgMCAwIDEuMTggMGw5LjQ0Mi05LjQ0MmEyLjQ5IDIuNDkgMCAwIDEgMy41NDEgMCAyLjQ5IDIuNDkgMCAwIDEgMCAzLjU0MUw4LjU5IDEyLjk3bC0uMS4xYS44MzUuODM1IDAgMCAwIDAgMS4xOC44MzUuODM1IDAgMCAwIDEuMTggMGwuMS0uMDk4IDcuMDMtNy4wMzRhMi40OSAyLjQ5IDAgMCAxIDMuNTQyIDBsLjA0OS4wNWEyLjQ5IDIuNDkgMCAwIDEgMCAzLjU0bC04LjU0IDguNTRhMS45NiAxLjk2IDAgMCAwIDAgMi43NTVsMS43NTMgMS43NTNhLjgzNS44MzUgMCAwIDAgMS4xOCAwIC44MzUuODM1IDAgMCAwIDAtMS4xOGwtMS43NTMtMS43NTNhLjI2Ni4yNjYgMCAwIDEgMC0uMzk0bDguNTQtOC41NGE0LjE4NSA0LjE4NSAwIDAgMCAwLTUuOWwtLjA1LS4wNWE0LjE2IDQuMTYgMCAwIDAtMi45NS0xLjIxOGMtLjIgMC0uNDAxLjAyLS42LjA0OGE0LjE3IDQuMTcgMCAwIDAtMS4xNy0zLjU1MkE0LjE2IDQuMTYgMCAwIDAgMTMuODUgMG0wIDMuMzMzYS44NC44NCAwIDAgMC0uNTkuMjQ1TDYuMjc1IDEwLjU2YTQuMTg2IDQuMTg2IDAgMCAwIDAgNS45MDIgNC4xODYgNC4xODYgMCAwIDAgNS45MDIgMEwxOS4xNiA5LjQ4YS44MzUuODM1IDAgMCAwIDAtMS4xOC44MzUuODM1IDAgMCAwLTEuMTggMGwtNi45ODUgNi45ODRhMi40OSAyLjQ5IDAgMCAxLTMuNTQgMCAyLjQ5IDIuNDkgMCAwIDEgMC0zLjU0bDYuOTgzLTYuOTg1YS44MzUuODM1IDAgMCAwIDAtMS4xOC44NC44NCAwIDAgMC0uNTktLjI0NSIvPjwvc3ZnPg==" /><text x="705" y="140" transform="scale(.1)" fill="#fff" textLength="950">VS Code Insiders</text><text x="1965" y="140" transform="scale(.1)" fill="#fff" textLength="1410">Install Aspire MCP Server</text></g>
</svg>
@*
Generated from:
https://img.shields.io/badge/VS_Code_Insiders-Install_Aspire_MCP_Server-65BBA5?style=flat-square&logo=modelcontextprotocol&logoColor=white
*@
</a>
</p>
<h5>MCP JSON</h5>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi vitae condimentum nulla, nec viverra purus. Morbi cursus egestas leo, eget lacinia quam hendrerit non.
Copy link

Copilot AI Oct 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Second occurrence of placeholder text—replace with an explanation of the MCP JSON configuration (fields meaning, how to use in clients, security of headers).

Suggested change
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi vitae condimentum nulla, nec viverra purus. Morbi cursus egestas leo, eget lacinia quam hendrerit non.
The MCP JSON configuration describes how clients can connect to and authenticate with the Aspire MCP server. Each field in the JSON has a specific purpose:
<ul>
<li><strong>endpoint</strong>: The base URL of the MCP server.</li>
<li><strong>headers</strong>: Optional HTTP headers (such as authentication tokens) that clients should include in requests. <strong>Keep these headers secure</strong>—they may contain sensitive information.</li>
<li><strong>protocolVersion</strong>: The version of the MCP protocol supported by the server.</li>
<!-- Add other fields as appropriate -->
</ul>
<br />
To use this configuration, import the JSON into your client or tool (such as VS Code) to enable secure and authenticated communication with the MCP server. <strong>Do not share this configuration publicly if it contains sensitive headers.</strong>

Copilot uses AI. Check for mistakes.

</p>
<MarkdownRenderer Markdown="@GetJsonConfigurationMarkdown()" MarkdownProcessor="@_markdownProcessor" />
}
else
{
<p>
MCP isn't configured.
</p>
}
</div>
84 changes: 84 additions & 0 deletions src/Aspire.Dashboard/Components/Dialogs/McpServerDialog.razor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// 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.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? _mcpServerJson;
private string? _mcpUrl;

protected override void OnInitialized()
{
_markdownProcessor = new MarkdownProcessor(ControlsStringsLoc, MarkdownHelpers.SafeUrlSchemes, []);
_mcpUrl = DashboardOptions.Value.Mcp.PublicUrl ?? DashboardOptions.Value.Mcp.EndpointUrl;

if (McpEnabled)
{
_mcpServerJson = GetMcpServerJson();
}
}

[MemberNotNullWhen(true, nameof(_mcpServerJson))]
[MemberNotNullWhen(true, nameof(_mcpUrl))]
private bool McpEnabled => !string.IsNullOrEmpty(_mcpUrl);

private string GetMcpServerJson()
{
Dictionary<string, string>? headers = null;

if (DashboardOptions.Value.Mcp.AuthMode == McpAuthMode.ApiKey)
{
headers = new Dictionary<string, string>
{
[McpApiKeyAuthenticationHandler.ApiKeyHeaderName] = DashboardOptions.Value.Mcp.PrimaryApiKey!
};
}

var url = new Uri(baseUri: new Uri(_mcpUrl!), relativeUri: "/mcp").ToString();

return JsonSerializer.Serialize(
new McpServerModel
{
Name = "aspire-dashboard",
Type = "http",
Url = url,
Headers = headers
},
McpServerModelContext.Default.McpServerModel);
}

private string GetJsonConfigurationMarkdown() =>
$"""
```json
{_mcpServerJson}
```
""";
}
11 changes: 10 additions & 1 deletion src/Aspire.Dashboard/Components/Layout/MainLayout.razor
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
@using Aspire.Dashboard.Components.CustomIcons
@using Aspire.Dashboard.Components.Interactions
@using Aspire.Dashboard.Components.Dialogs
@using Aspire.Dashboard.Model
@using Aspire.Dashboard.Model.Assistant
@using Aspire.Dashboard.Resources
Expand Down Expand Up @@ -33,10 +34,18 @@
Title="@Loc[nameof(Layout.MainLayoutAspireDashboardHelpLink)]" aria-label="@Loc[nameof(Layout.MainLayoutAspireDashboardHelpLink)]">
<FluentIcon Value="@(new Icons.Regular.Size24.QuestionCircle())" Color="Color.Neutral"/>
</FluentButton>
@if (!Options.CurrentValue.Mcp.Disabled.GetValueOrDefault())
{
<FluentButton Class="header-button"
Appearance="Appearance.Stealth" OnClick="@LaunchMcpAsync"
Title="MCP Server" aria-label="MCP Server">
<FluentIcon Value="@(new AspireIcons.Size24.McpIcon())" Color="Color.Neutral" />
</FluentButton>
}
@if (AIContextProvider.Enabled)
{
<FluentButton Class="@("header-button" + ((AIContextProvider.AssistantChatViewModel is {} vm && AIContextProvider.ShowAssistantSidebarDialog) ? " header-button-selected" : ""))"
Appearance="Appearance.Stealth" OnClick="@LaunchAssistantAsync"
Appearance="Appearance.Stealth" OnClick="@LaunchAssistantAsync"
Title="@AIAssistantLoc[nameof(AIAssistant.AIAssistantLaunchButtonText)]" aria-label="@AIAssistantLoc[nameof(AIAssistant.AIAssistantLaunchButtonText)]">
<FluentIcon Value="@(new AspireIcons.Size24.GitHubCopilot())" Color="Color.Neutral" />
</FluentButton>
Expand Down
61 changes: 61 additions & 0 deletions src/Aspire.Dashboard/Components/Layout/MainLayout.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public partial class MainLayout : IGlobalKeydownListener, IAsyncDisposable
private IDisposable? _aiDisplayChangedSubscription;
private const string SettingsDialogId = "SettingsDialog";
private const string HelpDialogId = "HelpDialog";
private const string McpDialogId = "McpServerDialog";

[Inject]
public required ThemeManager ThemeManager { get; init; }
Expand Down Expand Up @@ -145,6 +146,36 @@ await MessageService.ShowMessageBarAsync(options =>
}
}

if (Options.CurrentValue.Mcp.AuthMode == Mcp.McpAuthMode.Unsecured)
{
var dismissedResult = await LocalStorage.GetUnprotectedAsync<bool>(BrowserStorageKeys.UnsecuredMcpMessageDismissedKey);
var skipMessage = dismissedResult.Success && dismissedResult.Value;

if (!skipMessage)
{
// ShowMessageBarAsync must come after an await. Otherwise it will NRE.
// I think this order allows the message bar provider to be fully initialized.
await MessageService.ShowMessageBarAsync(options =>
{
options.Title = Loc[nameof(Resources.Layout.MessageMcpTitle)];
options.Body = Loc[nameof(Resources.Layout.MessageMcpBody)];
options.Link = new()
{
Text = Loc[nameof(Resources.Layout.MessageMcpLink)],
Href = "https://aka.ms/dotnet/aspire/mcp-unsecured",
Target = "_blank"
};
options.Intent = MessageIntent.Warning;
options.Section = DashboardUIHelpers.MessageBarSection;
options.AllowDismiss = true;
options.OnClose = async m =>
{
await LocalStorage.SetUnprotectedAsync(BrowserStorageKeys.UnsecuredMcpMessageDismissedKey, true);
};
});
}
}

_aiDisplayChangedSubscription = AIContextProvider.OnDisplayChanged(() => InvokeAsync(StateHasChanged));
}

Expand All @@ -169,6 +200,36 @@ protected override void OnParametersSet()
}
}

private async Task LaunchMcpAsync()
{
DialogParameters parameters = new()
{
Title = "Aspire MCP server",
DismissTitle = DialogsLoc[nameof(Resources.Dialogs.DialogCloseButtonText)],
PrimaryAction = "Close",
PrimaryActionEnabled = true,
SecondaryAction = null,
TrapFocus = true,
Modal = true,
Alignment = HorizontalAlignment.Center,
Width = "700px",
Height = "auto",
Id = McpDialogId,
OnDialogClosing = EventCallback.Factory.Create<DialogInstance>(this, HandleDialogClose)
};

if (_openPageDialog is not null)
{
if (Equals(_openPageDialog.Id, McpDialogId))
{
return;
}

await _openPageDialog.CloseAsync();
}

_openPageDialog = await DialogService.ShowDialogAsync<McpServerDialog>(parameters).ConfigureAwait(true);
}
private async Task LaunchHelpAsync()
{
DialogParameters parameters = new()
Expand Down
Loading
Loading