Skip to content
Merged
1 change: 1 addition & 0 deletions src/Tools/McpServer/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
FluentUIComponentsDocumentation.json
all-icons.json

# VS Code local settings (users should use the .example files)
.vscode/launch.json
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ public static IServiceCollection AddFluentUIDocumentation(this IServiceCollectio
// Excludes the 'mcp' folder
services.AddSingleton(_ => new DocumentationService(["mcp"]));

// Icon catalog service (loaded from embedded all-icons.json)
services.AddSingleton<IconSynonymService>();
services.AddSingleton<IconService>();

return services;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@

<!-- Path to the generated documentation JSON file -->
<McpDocumentationJsonPath>$(MSBuildThisFileDirectory)FluentUIComponentsDocumentation.json</McpDocumentationJsonPath>

<!-- Path to the generated icon catalog JSON file -->
<McpIconCatalogJsonPath>$(MSBuildThisFileDirectory)all-icons.json</McpIconCatalogJsonPath>
</PropertyGroup>

<!-- Expose internals to test project -->
Expand Down Expand Up @@ -83,6 +86,13 @@
Link="Documentation\Components\%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>

<!-- Embed the generated icon catalog JSON file as a resource (added dynamically to handle multi-target timing) -->
<Target Name="AddIconCatalogEmbeddedResource" BeforeTargets="PrepareForBuild" Condition="Exists('$(McpIconCatalogJsonPath)')">
<ItemGroup>
<EmbeddedResource Include="all-icons.json" LogicalName="Microsoft.FluentUI.AspNetCore.McpServer.all-icons.json" />
</ItemGroup>
</Target>

<!-- Code Analysis -->
<ItemGroup>
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers">
Expand Down Expand Up @@ -139,7 +149,7 @@
This runs DocApiGen to extract documentation from the FluentUI Components assembly
and creates a JSON file that is then embedded as a resource.
-->
<Target Name="GenerateMcpDocumentation" BeforeTargets="BeforeBuild" Condition="'$(TargetFramework)' == '$(NetVersion)' AND (!Exists('$(McpDocumentationJsonPath)') OR '$(ForceGenerateMcpDocs)' == 'true')">
<Target Name="GenerateMcpDocumentation" BeforeTargets="BeforeBuild" Condition="'$(TargetFramework)' == '$(NetVersion)' AND (!Exists('$(McpDocumentationJsonPath)') OR !Exists('$(McpIconCatalogJsonPath)') OR '$(ForceGenerateMcpDocs)' == 'true')">
<PropertyGroup>
<DocApiGenProject>$(MSBuildThisFileDirectory)..\..\..\examples\Tools\FluentUI.Demo.DocApiGen\FluentUI.Demo.DocApiGen.csproj</DocApiGenProject>
<FluentUIComponentsDll>$(MSBuildThisFileDirectory)..\..\Core\bin\$(Configuration)\$(NetVersion)\Microsoft.FluentUI.AspNetCore.Components.dll</FluentUIComponentsDll>
Expand All @@ -159,6 +169,11 @@
<Exec Command="dotnet run --project &quot;$(DocApiGenProject)&quot; --no-build -c $(Configuration) -- --xml &quot;$(FluentUIComponentsXml)&quot; --dll &quot;$(FluentUIComponentsDll)&quot; --output &quot;$(McpDocumentationJsonPath)&quot; --format json --mode all" WorkingDirectory="$(MSBuildThisFileDirectory)" ConsoleToMSBuild="true" />

<Message Text="MCP documentation JSON generated at $(McpDocumentationJsonPath)" Importance="high" />

<!-- Run DocApiGen to generate icon catalog JSON -->
<Exec Command="dotnet run --project &quot;$(DocApiGenProject)&quot; --no-build -c $(Configuration) -- --xml &quot;$(FluentUIComponentsXml)&quot; --dll &quot;$(FluentUIComponentsDll)&quot; --output &quot;$(McpIconCatalogJsonPath)&quot; --format json --mode icons" WorkingDirectory="$(MSBuildThisFileDirectory)" ConsoleToMSBuild="true" />

<Message Text="Icon catalog JSON generated at $(McpIconCatalogJsonPath)" Importance="high" />
</Target>

<!--
Expand All @@ -168,7 +183,7 @@
-->
<Target Name="GenerateMcpDocumentationBeforeDispatch"
BeforeTargets="DispatchToInnerBuilds"
Condition="'$(TargetFramework)' == '' AND (!Exists('$(McpDocumentationJsonPath)') OR '$(ForceGenerateMcpDocs)' == 'true')">
Condition="'$(TargetFramework)' == '' AND (!Exists('$(McpDocumentationJsonPath)') OR !Exists('$(McpIconCatalogJsonPath)') OR '$(ForceGenerateMcpDocs)' == 'true')">
<Message Text="Generating MCP documentation JSON before multi-target dispatch..." Importance="high" />
<MSBuild Projects="$(MSBuildProjectFile)"
Targets="GenerateMcpDocumentation"
Expand All @@ -180,6 +195,9 @@
<Message Text="Cleaning MCP documentation JSON at $(McpDocumentationJsonPath)..." Importance="high" Condition="Exists('$(McpDocumentationJsonPath)')" />
<Delete Files="$(McpDocumentationJsonPath)" Condition="Exists('$(McpDocumentationJsonPath)')" />
<Message Text="MCP documentation JSON cleaned." Importance="high" Condition="Exists('$(McpDocumentationJsonPath)')" />
<Message Text="Cleaning icon catalog JSON at $(McpIconCatalogJsonPath)..." Importance="high" Condition="Exists('$(McpIconCatalogJsonPath)')" />
<Delete Files="$(McpIconCatalogJsonPath)" Condition="Exists('$(McpIconCatalogJsonPath)')" />
<Message Text="Icon catalog JSON cleaned." Importance="high" Condition="Exists('$(McpIconCatalogJsonPath)')" />
</Target>

<!--
Expand Down
39 changes: 39 additions & 0 deletions src/Tools/McpServer/Models/IconModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// ------------------------------------------------------------------------
// This file is licensed to you under the MIT License.
// ------------------------------------------------------------------------

namespace Microsoft.FluentUI.AspNetCore.McpServer.Models;

/// <summary>
/// Represents a Fluent UI icon with its available variants and sizes.
/// </summary>
/// <param name="Name">The icon name (e.g., "Bookmark", "Alert", "Add").</param>
/// <param name="Variants">Dictionary of variant names (e.g., "Filled", "Regular", "Light", "Color") to available sizes.</param>
public sealed record IconModel(string Name, IDictionary<string, IList<int>> Variants)
{
/// <summary>
/// Gets all variant names available for this icon.
/// </summary>
public IEnumerable<string> VariantNames => Variants.Keys;

/// <summary>
/// Gets all unique sizes available across all variants.
/// </summary>
public IEnumerable<int> AllSizes => Variants.Values.SelectMany(s => s).Distinct().OrderBy(s => s);

/// <summary>
/// Checks whether a specific variant and size combination is available.
/// </summary>
public bool HasVariantAndSize(string variant, int size)
{
return Variants.TryGetValue(variant, out var sizes) && sizes.Contains(size);
}

/// <summary>
/// Gets the sizes available for a specific variant.
/// </summary>
public IReadOnlyList<int> GetSizesForVariant(string variant)
{
return Variants.TryGetValue(variant, out var sizes) ? sizes.ToList() : [];
}
}
Loading
Loading