diff --git a/.editorconfig b/.editorconfig index 9c0d816014..e4dea92413 100644 --- a/.editorconfig +++ b/.editorconfig @@ -15,6 +15,7 @@ indent_size = 4 # C# files [*.cs] +file_header_template = Copyright (c) Microsoft Corporation.\nLicensed under the MIT License. # New line preferences csharp_new_line_before_open_brace = all # vs-default: any csharp_new_line_before_else = true # vs-default: true @@ -33,7 +34,7 @@ csharp_indent_switch_labels = true # vs-default: true csharp_indent_labels = one_less_than_current # vs-default: one_less_than_current # Modifier preferences -csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:error # avoid this. unless absolutely necessary dotnet_style_qualification_for_field = false:suggestion # vs-default: false:none @@ -83,7 +84,7 @@ dotnet_naming_style.camel_case_underscore_style.required_prefix = _ dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case # Code style defaults -csharp_using_directive_placement = outside_namespace:suggestion +csharp_using_directive_placement = outside_namespace:error dotnet_sort_system_directives_first = true # vs-default: true csharp_prefer_braces = true:refactoring csharp_preserve_single_line_blocks = true # vs-default: true @@ -91,10 +92,13 @@ csharp_preserve_single_line_statements = false # vs-default: true csharp_prefer_static_local_function = true:suggestion csharp_prefer_simple_using_statement = false:none csharp_style_prefer_switch_expression = true:suggestion +csharp_style_namespace_declarations = file_scoped:error +csharp_style_namespace_match_folder = true:error # Code quality dotnet_style_readonly_field = true:suggestion -dotnet_code_quality_unused_parameters = non_public:suggestion +# Safe to warn on all unused parameters as the project is shipped as an application and not a library. +dotnet_code_quality_unused_parameters = all:error # Expression-level preferences dotnet_style_object_initializer = true:suggestion # vs-default: true:suggestion @@ -167,6 +171,23 @@ dotnet_code_quality.ca1802.api_surface = private, internal # CA2016: Forward the CancellationToken parameter to methods that take one dotnet_diagnostic.CA2016.severity = error +# Diagnostics without corresponding editorconfig options +# Unused usings +dotnet_diagnostic.IDE0005.severity = error +# Invalid string formatting +dotnet_diagnostic.IDE0043.severity = error +# Unused/unread private members +dotnet_diagnostic.IDE0051.severity = error +dotnet_diagnostic.IDE0052.severity = error +# Require file header +dotnet_diagnostic.IDE0073.severity = error +# Make methods synchronous (remove async modifier from methods without any await statements) +dotnet_diagnostic.IDE0390.severity = error +dotnet_diagnostic.IDE0391.severity = error + +# +dotnet_diagnostic.CS1591.severity = none + # Xml project files [*.{csproj,vcxproj,vcxproj.filters,proj,nativeproj,locproj}] indent_size = 2 diff --git a/Directory.Build.props b/Directory.Build.props index 5562f7fc96..7636c6c1a3 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -20,6 +20,8 @@ See: https://learn.microsoft.com/nuget/reference/errors-and-warnings/nu1901-nu1904 --> $(WarningsNotAsErrors);NU1901;NU1902 + true + true diff --git a/core/Azure.Mcp.Core/src/Services/Azure/BaseAzureResourceService.cs b/core/Azure.Mcp.Core/src/Services/Azure/BaseAzureResourceService.cs index ccb78ebe6e..3b874a1769 100644 --- a/core/Azure.Mcp.Core/src/Services/Azure/BaseAzureResourceService.cs +++ b/core/Azure.Mcp.Core/src/Services/Azure/BaseAzureResourceService.cs @@ -30,7 +30,7 @@ public abstract class BaseAzureResourceService( /// Gets the tenant resource for the specified subscription. /// /// The tenant ID from the subscription - /// Cancellation token + /// The token to monitor for cancellation requests. The default value is . /// The tenant resource associated with the subscription private async Task GetTenantResourceAsync(Guid? tenantId, CancellationToken cancellationToken = default) { @@ -77,7 +77,7 @@ private async Task ValidateResourceGroupExistsAsync(SubscriptionResource s /// Optional table name to query (default: "resources") /// Optional additional KQL filter condition /// Maximum number of results to return (default: 50) - /// Cancellation token + /// The token to monitor for cancellation requests. The default value is . /// Optional tenant to use for the query /// List of resources converted to the specified type protected async Task> ExecuteResourceQueryAsync( @@ -157,8 +157,10 @@ protected async Task> ExecuteResourceQueryAsync( /// The subscription ID or name /// Optional retry policy configuration /// Function to convert JsonElement to the target type + /// Optional table name to query (default: "resources") /// Optional additional KQL filter condition - /// Cancellation token + /// Optional tenant to use for the query + /// The token to monitor for cancellation requests. The default value is . /// Single resource converted to the specified type, or null if not found protected async Task ExecuteSingleResourceQueryAsync( string resourceType, @@ -184,6 +186,7 @@ protected async Task> ExecuteResourceQueryAsync( /// The API version to set for the specified resource type. /// Optional tenant to use when creating the client. /// Optional retry policy used by token acquisition. + /// The token to monitor for cancellation requests. The default value is . /// An initialized configured with the requested API version. protected async Task CreateArmClientWithApiVersionAsync(string resourceTypeForApiVersion, string apiVersion, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default) { @@ -198,7 +201,7 @@ protected async Task CreateArmClientWithApiVersionAsync(string resour /// /// The ArmClient to use for the call. /// The resource identifier of the resource to retrieve. - /// Cancellation token. + /// The token to monitor for cancellation requests. The default value is . /// The instance for the requested resource. /// Thrown when a required parameter is null. protected static async Task GetGenericResourceAsync(ArmClient armClient, ResourceIdentifier resourceIdentifier, CancellationToken cancellationToken = default) @@ -225,6 +228,7 @@ protected static async Task GetGenericResourceAsync(ArmClient a /// The Azure location for the resource. /// The content to create or update the resource with. /// The JSON type information for serialization. + /// The token to monitor for cancellation requests. The default value is . /// The instance for the requested resource. /// Thrown when a required parameter is null. /// Thrown when the content is invalid. diff --git a/core/Azure.Mcp.Core/src/Services/Azure/BaseAzureService.cs b/core/Azure.Mcp.Core/src/Services/Azure/BaseAzureService.cs index 7687afbf3e..4bc7fed160 100644 --- a/core/Azure.Mcp.Core/src/Services/Azure/BaseAzureService.cs +++ b/core/Azure.Mcp.Core/src/Services/Azure/BaseAzureService.cs @@ -7,7 +7,9 @@ using Azure.Core.Pipeline; using Azure.Mcp.Core.Services.Azure.Tenant; using Azure.ResourceManager; +#pragma warning disable IDE0005 // using isn't used in release builds. using Microsoft.Mcp.Core.Helpers; +#pragma warning restore IDE0005 // using isn't used in release builds. using Microsoft.Mcp.Core.Options; using Microsoft.Mcp.Core.Services.Azure; @@ -31,7 +33,7 @@ public abstract class BaseAzureService private static readonly string s_framework; private static readonly string s_platform; private static readonly string s_defaultUserAgent; - private static readonly TimeSpan? s_defaultPollInterval = null; + private static TimeSpan? s_defaultPollInterval = null; static BaseAzureService() { @@ -165,13 +167,11 @@ protected static string EscapeKqlString(string value) protected async Task GetCredential(CancellationToken cancellationToken) { - // TODO @vukelich: separate PR for cancellationToken to be required, not optional default return await GetCredential(null, cancellationToken); } protected async Task GetCredential(string? tenant, CancellationToken cancellationToken) { - // TODO @vukelich: separate PR for cancellationToken to be required, not optional default var tenantId = string.IsNullOrEmpty(tenant) ? null : await ResolveTenantIdAsync(tenant, cancellationToken); try @@ -188,7 +188,8 @@ protected async Task GetCredential(string? tenant, Cancellation /// Gets an ARM access token for the given tenant using the ARM default scope. /// /// Optional tenant ID or name to authenticate against. - /// Cancellation token. + /// The token to monitor for cancellation requests. The default value is . + /// An for the ARM default scope. protected async Task GetArmAccessTokenAsync(string? tenant, CancellationToken cancellationToken) { var credential = await GetCredential(tenant, cancellationToken); @@ -253,6 +254,8 @@ protected static T ConfigureRetryPolicy(T clientOptions, RetryPolicyOptions? /// Optional Azure tenant ID or name. /// Optional retry policy configuration. /// Optional ARM client options. + /// The token to monitor for cancellation requests. The default value is . + /// An initialized instance. protected async Task CreateArmClientAsync( string? tenantIdOrName = null, RetryPolicyOptions? retryPolicy = null, @@ -302,7 +305,7 @@ protected static void ValidateRequiredParameters(params (string name, string? va /// /// The return type. /// The long-running operation. - /// The cancellation token that can cancel the request. + /// The token to monitor for cancellation requests. The default value is . /// The response once the long-running operation completes. protected static async Task WaitForLroCompletionAsync(Operation operation, CancellationToken cancellationToken = default) where T : notnull { @@ -322,7 +325,7 @@ protected static async Task WaitForLroCompletionAsync(Operation operation, /// Waits for the completion of a long-running operation, periodically polling the operation status until it completes. /// /// The long-running operation. - /// The cancellation token that can cancel the request. + /// The token to monitor for cancellation requests. The default value is . /// The response once the long-running operation completes. protected static async Task WaitForLroCompletionAsync(Operation operation, CancellationToken cancellationToken = default) { diff --git a/core/Azure.Mcp.Core/src/Services/Azure/Tenant/ITenantService.cs b/core/Azure.Mcp.Core/src/Services/Azure/Tenant/ITenantService.cs index 4d88d6a2ee..86fda3479d 100644 --- a/core/Azure.Mcp.Core/src/Services/Azure/Tenant/ITenantService.cs +++ b/core/Azure.Mcp.Core/src/Services/Azure/Tenant/ITenantService.cs @@ -20,7 +20,7 @@ public interface ITenantService /// /// Gets the list of all available Azure tenants. /// - /// A token to cancel the operation. + /// The token to monitor for cancellation requests. /// /// A task representing the asynchronous operation, with a list of /// instances. @@ -31,7 +31,7 @@ public interface ITenantService /// Gets the tenant ID from either a tenant ID or tenant name. /// /// The tenant ID or tenant name. - /// A cancellation token. + /// The token to monitor for cancellation requests. /// /// A task representing the asynchronous operation, with the tenant ID or /// if not found. @@ -40,7 +40,7 @@ public interface ITenantService /// Thrown when a tenant with the specified name is not found. /// /// - /// Thrown when the tenant has a TenantId. + /// Thrown when the tenant has a TenantId. /// Task GetTenantId(string tenantIdOrName, CancellationToken cancellationToken); @@ -48,7 +48,7 @@ public interface ITenantService /// Gets the tenant ID by tenant name. /// /// The tenant name. - /// A cancellation token. + /// The token to monitor for cancellation requests. /// /// A task representing the asynchronous operation, with the tenant ID or /// if not found. @@ -57,7 +57,7 @@ public interface ITenantService /// Thrown when a tenant with the specified name is not found. /// /// - /// Thrown when the tenant has a TenantId. + /// Thrown when the tenant has a TenantId. /// Task GetTenantIdByName(string tenantName, CancellationToken cancellationToken); @@ -65,7 +65,7 @@ public interface ITenantService /// Gets the tenant name by tenant ID. /// /// The tenant ID. - /// A cancellation token. + /// The token to monitor for cancellation requests. /// /// A task representing the asynchronous operation, with the tenant name or if not found. /// @@ -73,7 +73,7 @@ public interface ITenantService /// Thrown when a tenant with the specified ID is not found. /// /// - /// Thrown when the tenant has a DisplayName. + /// Thrown when the tenant has a DisplayName. /// Task GetTenantNameById(string tenantId, CancellationToken cancellationToken); @@ -90,7 +90,7 @@ public interface ITenantService /// Gets an instance of . /// /// Optional tenant ID. Use in most cases. - /// A cancellation token. + /// The token to monitor for cancellation requests. /// /// A task representing the asynchronous operation, with a value of . /// diff --git a/core/Azure.Mcp.Core/src/Services/Azure/Tenant/TenantService.cs b/core/Azure.Mcp.Core/src/Services/Azure/Tenant/TenantService.cs index a50affa3ed..2ef51d5ccb 100644 --- a/core/Azure.Mcp.Core/src/Services/Azure/Tenant/TenantService.cs +++ b/core/Azure.Mcp.Core/src/Services/Azure/Tenant/TenantService.cs @@ -57,7 +57,7 @@ public async Task> GetTenants(CancellationToken cancellatio var options = AddDefaultPolicies(new ArmClientOptions()); options.Transport = new HttpClientTransport(GetClient()); options.Environment = CloudConfiguration.ArmEnvironment; - var client = new ArmClient(await GetCredential(cancellationToken), default, options); + var client = new ArmClient(await GetTokenCredentialAsync(null, cancellationToken), default, options); await foreach (var tenant in client.GetTenants().WithCancellation(cancellationToken)) { diff --git a/core/Azure.Mcp.Core/src/Services/Azure/Tenant/TenantServiceCollectionExtensions.cs b/core/Azure.Mcp.Core/src/Services/Azure/Tenant/TenantServiceCollectionExtensions.cs index 97679b84ff..a3affa5718 100644 --- a/core/Azure.Mcp.Core/src/Services/Azure/Tenant/TenantServiceCollectionExtensions.cs +++ b/core/Azure.Mcp.Core/src/Services/Azure/Tenant/TenantServiceCollectionExtensions.cs @@ -29,11 +29,12 @@ public static class TenantServiceCollectionExtensions /// /// /// - /// via . - /// This can be overridden using - /// based on parsed command line arguments and environment variables. + /// via . /// /// + /// + /// via . + /// /// /// public static IServiceCollection AddAzureTenantService(this IServiceCollection services) diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/AccessTokenHandlerTests.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/AccessTokenHandlerTests.cs index 32911ea42a..9d993856b7 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/AccessTokenHandlerTests.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/AccessTokenHandlerTests.cs @@ -4,6 +4,7 @@ using System.Net; using System.Net.Http.Headers; using Azure.Core; +using Microsoft.Mcp.Core; using Microsoft.Mcp.Core.Services.Azure.Authentication; using NSubstitute; using Xunit; diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/CommandFactoryHelpers.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/CommandFactoryHelpers.cs index 88af56bfa5..d8345449c8 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/CommandFactoryHelpers.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/CommandFactoryHelpers.cs @@ -53,6 +53,7 @@ using Microsoft.Mcp.Core.Services.Telemetry; using Microsoft.Mcp.Core.Services.Time; using NSubstitute; +using ExtensionsOptions = Microsoft.Extensions.Options; namespace Azure.Mcp.Core.Tests.Areas.Server; @@ -106,7 +107,7 @@ public static ICommandFactory CreateCommandFactory(IServiceProvider? serviceProv var services = serviceProvider ?? CreateDefaultServiceProvider(); var logger = services.GetRequiredService>(); - var configurationOptions = Microsoft.Extensions.Options.Options.Create(new McpServerConfiguration + var configurationOptions = ExtensionsOptions.Options.Create(new McpServerConfiguration { Name = "Test Server", ShortName = "test", diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/Discovery/CommandGroupDiscoveryStrategyTests.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/Discovery/CommandGroupDiscoveryStrategyTests.cs index da340c547e..205e393a59 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/Discovery/CommandGroupDiscoveryStrategyTests.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/Discovery/CommandGroupDiscoveryStrategyTests.cs @@ -1,11 +1,17 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using System.Diagnostics; +using System.Reflection; +using System.Runtime.InteropServices; +using Microsoft.Extensions.Logging; using Microsoft.Mcp.Core.Areas.Server.Commands.Discovery; using Microsoft.Mcp.Core.Areas.Server.Options; using Microsoft.Mcp.Core.Commands; using Microsoft.Mcp.Tests.Client.Helpers; +using NSubstitute; using Xunit; +using ExtensionsOptions = Microsoft.Extensions.Options; namespace Azure.Mcp.Core.Tests.Areas.Server.Commands.Discovery; @@ -17,8 +23,8 @@ private static CommandGroupDiscoveryStrategy CreateStrategy( string? entryPoint = null) { var factory = commandFactory ?? CommandFactoryHelpers.CreateCommandFactory(); - var startOptions = Microsoft.Extensions.Options.Options.Create(options ?? new ServerStartOptions()); - var logger = NSubstitute.Substitute.For>(); + var startOptions = ExtensionsOptions.Options.Create(options ?? new ServerStartOptions()); + var logger = Substitute.For>(); var strategy = new CommandGroupDiscoveryStrategy(factory, startOptions, logger); if (entryPoint != null) { @@ -31,8 +37,8 @@ private static CommandGroupDiscoveryStrategy CreateStrategy( public void Constructor_WithNullCommandFactory_DoesNotThrow() { // Arrange - var options = Microsoft.Extensions.Options.Options.Create(new ServerStartOptions()); - var logger = NSubstitute.Substitute.For>(); + var options = ExtensionsOptions.Options.Create(new ServerStartOptions()); + var logger = Substitute.For>(); // Act & Assert // Primary constructor syntax doesn't automatically validate null parameters @@ -45,7 +51,7 @@ public void Constructor_WithNullOptions_DoesNotThrow() { // Arrange var commandFactory = CommandFactoryHelpers.CreateCommandFactory(); - var logger = NSubstitute.Substitute.For>(); + var logger = Substitute.For>(); // Act & Assert // Primary constructor syntax doesn't automatically validate null parameters @@ -58,8 +64,8 @@ public void Constructor_WithValidParameters_InitializesCorrectly() { // Arrange var commandFactory = CommandFactoryHelpers.CreateCommandFactory(); - var options = Microsoft.Extensions.Options.Options.Create(new ServerStartOptions()); - var logger = NSubstitute.Substitute.For>(); + var options = ExtensionsOptions.Options.Create(new ServerStartOptions()); + var logger = Substitute.For>(); // Act var strategy = new CommandGroupDiscoveryStrategy(commandFactory, options, logger); @@ -211,7 +217,7 @@ public async Task DiscoverServersAsync_WithNullEntryPoint_UsesCurrentProcessExec // Assert Assert.NotEmpty(result); // When EntryPoint is set to null, CommandGroupServerProvider defaults to current process executable - var currentProcessPath = System.Diagnostics.Process.GetCurrentProcess().MainModule?.FileName; + var currentProcessPath = Process.GetCurrentProcess().MainModule?.FileName; Assert.All(result, provider => { var actualEntryPoint = ((CommandGroupServerProvider)provider).EntryPoint; @@ -232,7 +238,7 @@ public async Task DiscoverServersAsync_WithEmptyEntryPoint_ProvidersDefaultToCur // Assert Assert.NotEmpty(result); - var currentProcessPath = System.Diagnostics.Process.GetCurrentProcess().MainModule?.FileName; + var currentProcessPath = Process.GetCurrentProcess().MainModule?.FileName; Assert.All(result, provider => { var actualEntryPoint = ((CommandGroupServerProvider)provider).EntryPoint; @@ -252,7 +258,7 @@ public async Task DiscoverServersAsync_WithWhitespaceEntryPoint_ProvidersDefault // Assert Assert.NotEmpty(result); - var currentProcessPath = System.Diagnostics.Process.GetCurrentProcess().MainModule?.FileName; + var currentProcessPath = Process.GetCurrentProcess().MainModule?.FileName; Assert.All(result, provider => { var actualEntryPoint = ((CommandGroupServerProvider)provider).EntryPoint; @@ -446,8 +452,8 @@ public async Task DiscoverServersAsync_ResultCountIsConsistent() public async Task ShouldDiscoverServers() { var commandFactory = CommandFactoryHelpers.CreateCommandFactory(); - var options = Microsoft.Extensions.Options.Options.Create(new ServerStartOptions()); - var logger = NSubstitute.Substitute.For>(); + var options = ExtensionsOptions.Options.Create(new ServerStartOptions()); + var logger = Substitute.For>(); var strategy = new CommandGroupDiscoveryStrategy(commandFactory, options, logger); var result = await strategy.DiscoverServersAsync(TestContext.Current.CancellationToken); Assert.NotNull(result); @@ -457,9 +463,9 @@ public async Task ShouldDiscoverServers() public async Task ShouldDiscoverServers_ExcludesIgnoredGroupsAndSetsProperties() { var commandFactory = CommandFactoryHelpers.CreateCommandFactory(); - var options = Microsoft.Extensions.Options.Options.Create(new ServerStartOptions { ReadOnly = true }); + var options = ExtensionsOptions.Options.Create(new ServerStartOptions { ReadOnly = true }); var azmcpEntryPoint = McpTestUtilities.GetAzMcpExecutablePath(); - var logger = NSubstitute.Substitute.For>(); + var logger = Substitute.For>(); var strategy = new CommandGroupDiscoveryStrategy(commandFactory, options, logger) { EntryPoint = azmcpEntryPoint @@ -490,8 +496,8 @@ public void GetAzmcpExecutablePath_ReturnsCorrectPathForCurrentOS() Assert.NotEmpty(azmcpPath); // Should end with the correct executable name for the current OS - if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform( - System.Runtime.InteropServices.OSPlatform.Windows)) + if (RuntimeInformation.IsOSPlatform( + OSPlatform.Windows)) { Assert.EndsWith("azmcp.exe", azmcpPath); } @@ -502,7 +508,7 @@ public void GetAzmcpExecutablePath_ReturnsCorrectPathForCurrentOS() } // Should be in the same directory as the test assembly - var testAssemblyPath = System.Reflection.Assembly.GetExecutingAssembly().Location; + var testAssemblyPath = Assembly.GetExecutingAssembly().Location; var testDirectory = Path.GetDirectoryName(testAssemblyPath); var expectedDirectory = Path.GetDirectoryName(azmcpPath); Assert.Equal(testDirectory, expectedDirectory); diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/Discovery/ConsolidatedToolDiscoveryStrategyTests.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/Discovery/ConsolidatedToolDiscoveryStrategyTests.cs index 0c97c74898..77a25116c3 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/Discovery/ConsolidatedToolDiscoveryStrategyTests.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/Discovery/ConsolidatedToolDiscoveryStrategyTests.cs @@ -9,6 +9,7 @@ using Microsoft.Mcp.Core.Configuration; using NSubstitute; using Xunit; +using ExtensionsOptions = Microsoft.Extensions.Options; namespace Azure.Mcp.Core.Tests.Areas.Server.Commands.Discovery; @@ -21,8 +22,8 @@ private static ConsolidatedToolDiscoveryStrategy CreateStrategy( { var factory = commandFactory ?? CommandFactoryHelpers.CreateCommandFactory(); var serviceProvider = CommandFactoryHelpers.SetupCommonServices().BuildServiceProvider(); - var startOptions = Microsoft.Extensions.Options.Options.Create(options ?? new ServerStartOptions()); - var configurationOptions = Microsoft.Extensions.Options.Options.Create(new McpServerConfiguration + var startOptions = ExtensionsOptions.Options.Create(options ?? new ServerStartOptions()); + var configurationOptions = ExtensionsOptions.Options.Create(new McpServerConfiguration { Name = "Test Server", ShortName = "test", diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/Runtime/McpRuntimeTests.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/Runtime/McpRuntimeTests.cs index 071b009526..6d456528a4 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/Runtime/McpRuntimeTests.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/Runtime/McpRuntimeTests.cs @@ -1,12 +1,13 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#pragma warning disable MCP9003 // Obsolete RequestContext constructor - migrating during Phase 1 +#pragma warning disable MCP9005 // Deprecated Sampling/Logging APIs - backward compat during Phase 1 using System.Diagnostics; using System.Text.Json; using System.Text.Json.Nodes; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; using Microsoft.Mcp.Core.Areas.Server.Commands.Runtime; using Microsoft.Mcp.Core.Areas.Server.Commands.ToolLoading; using Microsoft.Mcp.Core.Areas.Server.Options; @@ -17,6 +18,7 @@ using ModelContextProtocol.Server; using NSubstitute; using Xunit; +using ExtensionsOptions = Microsoft.Extensions.Options; namespace Azure.Mcp.Core.Tests.Areas.Server.Commands.Runtime; @@ -31,8 +33,8 @@ private static ServiceProvider CreateServiceProvider() return services.BuildServiceProvider(); } - private static IOptions CreateOptions(ServerStartOptions? options = null) => - Microsoft.Extensions.Options.Options.Create(options ?? new ServerStartOptions()); + private static ExtensionsOptions.IOptions CreateOptions(ServerStartOptions? options = null) => + ExtensionsOptions.Options.Create(options ?? new ServerStartOptions()); private static McpServer CreateMockServer() => Substitute.For(); diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ServiceCollectionExtensionsSerializedTests.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ServiceCollectionExtensionsSerializedTests.cs index 92279752ff..faebf4aa75 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ServiceCollectionExtensionsSerializedTests.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ServiceCollectionExtensionsSerializedTests.cs @@ -3,19 +3,15 @@ using System.Reflection; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using Microsoft.Mcp.Core.Areas.Server.Commands; using Microsoft.Mcp.Core.Areas.Server.Options; using Microsoft.Mcp.Core.Configuration; using Microsoft.Mcp.Core.Helpers; using Xunit; +using ExtensionsOptions = Microsoft.Extensions.Options; namespace Azure.Mcp.Core.Tests.Areas.Server.Commands; -// This is intentionally placed after the namespace declaration to avoid -// conflicts with Azure.Mcp.Core.Areas.Server.Options -using Options = Microsoft.Extensions.Options.Options; - public class ServiceCollectionExtensionsSerializedTests { private static readonly Assembly s_testAssembly = typeof(ServiceCollectionExtensionsTests).Assembly; @@ -41,7 +37,7 @@ public void InitializeConfigurationAndOptions_Defaults() // Assert var provider = services.BuildServiceProvider(); - var options = provider.GetRequiredService>(); + var options = provider.GetRequiredService>(); Assert.NotNull(options.Value); @@ -65,14 +61,14 @@ public void InitializeConfigurationAndOptions_HttpTransport() { Transport = TransportTypes.Http, }; - var services = SetupBaseServices().AddSingleton(Options.Create(serviceStartOptions)); + var services = SetupBaseServices().AddSingleton(ExtensionsOptions.Options.Create(serviceStartOptions)); // Act services.InitializeConfigurationAndOptions(s_serverAssembly); var provider = services.BuildServiceProvider(); // Assert - var options = provider.GetRequiredService>(); + var options = provider.GetRequiredService>(); Assert.NotNull(options.Value); @@ -96,7 +92,7 @@ public void InitializeConfigurationAndOptions_Stdio() var provider = services.BuildServiceProvider(); // Assert - var options = provider.GetRequiredService>(); + var options = provider.GetRequiredService>(); Assert.NotNull(options.Value); @@ -121,7 +117,7 @@ public void InitializeConfigurationAndOptions_WithSupportLoggingFolder_DisablesT { DangerouslyWriteSupportLogsToDir = "/tmp/logs" }; - var services = SetupBaseServices().AddSingleton(Options.Create(serviceStartOptions)); + var services = SetupBaseServices().AddSingleton(ExtensionsOptions.Options.Create(serviceStartOptions)); // Act Environment.SetEnvironmentVariable("AZURE_MCP_COLLECT_TELEMETRY", null); @@ -129,7 +125,7 @@ public void InitializeConfigurationAndOptions_WithSupportLoggingFolder_DisablesT var provider = services.BuildServiceProvider(); // Assert - var options = provider.GetRequiredService>(); + var options = provider.GetRequiredService>(); Assert.False(options.Value.IsTelemetryEnabled, "Telemetry should be disabled when support logging folder is set"); } @@ -145,7 +141,7 @@ public void InitializeConfigurationAndOptions_WithSupportLoggingFolderAndEnvVarT { DangerouslyWriteSupportLogsToDir = "/tmp/logs" }; - var services = SetupBaseServices().AddSingleton(Options.Create(serviceStartOptions)); + var services = SetupBaseServices().AddSingleton(ExtensionsOptions.Options.Create(serviceStartOptions)); // Act Environment.SetEnvironmentVariable("AZURE_MCP_COLLECT_TELEMETRY", "true"); @@ -153,7 +149,7 @@ public void InitializeConfigurationAndOptions_WithSupportLoggingFolderAndEnvVarT var provider = services.BuildServiceProvider(); // Assert - var options = provider.GetRequiredService>(); + var options = provider.GetRequiredService>(); Assert.False(options.Value.IsTelemetryEnabled, "Telemetry should be disabled when support logging folder is set, regardless of environment variable"); } @@ -171,7 +167,7 @@ public void InitializeConfigurationAndOptions_WithEmptyOrWhitespaceSupportLoggin { DangerouslyWriteSupportLogsToDir = folderPath }; - var services = SetupBaseServices().AddSingleton(Options.Create(serviceStartOptions)); + var services = SetupBaseServices().AddSingleton(ExtensionsOptions.Options.Create(serviceStartOptions)); // Act Environment.SetEnvironmentVariable("AZURE_MCP_COLLECT_TELEMETRY", null); @@ -179,7 +175,7 @@ public void InitializeConfigurationAndOptions_WithEmptyOrWhitespaceSupportLoggin var provider = services.BuildServiceProvider(); // Assert - var options = provider.GetRequiredService>(); + var options = provider.GetRequiredService>(); Assert.True(options.Value.IsTelemetryEnabled, $"Telemetry should be enabled when support logging folder is '{folderPath}'"); } } diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ServiceCollectionExtensionsTests.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ServiceCollectionExtensionsTests.cs index 4531ec380d..5c1e2dff21 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ServiceCollectionExtensionsTests.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ServiceCollectionExtensionsTests.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using Microsoft.Mcp.Core.Areas.Server; using Microsoft.Mcp.Core.Areas.Server.Commands; using Microsoft.Mcp.Core.Areas.Server.Commands.Discovery; @@ -15,12 +14,13 @@ using ModelContextProtocol.Server; using NSubstitute; using Xunit; +using ExtensionsOptions = Microsoft.Extensions.Options; namespace Azure.Mcp.Core.Tests.Areas.Server.Commands; public class ServiceCollectionExtensionsTests { - private IServiceCollection SetupBaseServices() + private static IServiceCollection SetupBaseServices() { var services = CommandFactoryHelpers.SetupCommonServices(); services.AddSingleton(sp => CommandFactoryHelpers.CreateCommandFactory(sp)); @@ -37,7 +37,7 @@ private IServiceCollection SetupBaseServices() Description = "Test description" }; services.AddSingleton(serverConfiguration); - services.AddSingleton(Microsoft.Extensions.Options.Options.Create(serverConfiguration)); + services.AddSingleton(ExtensionsOptions.Options.Create(serverConfiguration)); return services; } @@ -191,7 +191,7 @@ public void AddAzureMcpServer_ConfiguresMcpServerOptions() // Assert var provider = services.BuildServiceProvider(); - var mcpServerOptions = provider.GetService>()?.Value; + var mcpServerOptions = provider.GetService>()?.Value; // Verify server options are configured Assert.NotNull(mcpServerOptions); @@ -219,7 +219,7 @@ public void AddAzureMcpServer_RegistersOptionsWithSameInstance() // Assert var provider = services.BuildServiceProvider(); var registeredOptions = provider.GetService(); - var wrappedOptions = provider.GetService>()?.Value; + var wrappedOptions = provider.GetService>()?.Value; // Verify both registrations point to the same instance Assert.NotNull(registeredOptions); @@ -251,7 +251,7 @@ public void AddAzureMcpServer_WithReadOnlyOption_RegistersOption() Assert.True(registeredOptions.ReadOnly); // Verify the option is also available as IOptions - var optionsMonitor = provider.GetService>(); + var optionsMonitor = provider.GetService>(); Assert.NotNull(optionsMonitor); Assert.True(optionsMonitor.Value.ReadOnly); } @@ -399,7 +399,7 @@ public void AddAzureMcpServer_WithNullProvider_ConfiguresNullServerInstructions( // Assert var provider = services.BuildServiceProvider(); - var mcpServerOptions = provider.GetService>()?.Value; + var mcpServerOptions = provider.GetService>()?.Value; // Verify server instructions are configured Assert.NotNull(mcpServerOptions); @@ -426,7 +426,7 @@ public void AddAzureMcpServer_WithProvider_ConfiguresServerInstructions() // Assert var provider = services.BuildServiceProvider(); - var mcpServerOptions = provider.GetService>()?.Value; + var mcpServerOptions = provider.GetService>()?.Value; // Verify server instructions are configured Assert.NotNull(mcpServerOptions); diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ServiceInfoCommandTests.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ServiceInfoCommandTests.cs index 802c5cf335..6758b266ef 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ServiceInfoCommandTests.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ServiceInfoCommandTests.cs @@ -6,6 +6,7 @@ using Microsoft.Mcp.Core.Configuration; using Microsoft.Mcp.Tests.Client; using Xunit; +using ExtensionsOptions = Microsoft.Extensions.Options; namespace Azure.Mcp.Core.Tests.Areas.Server.Commands; @@ -24,7 +25,7 @@ public ServiceInfoCommandTests() Description = "Test Description", RootCommandGroupName = "azmcp" }; - Services.AddSingleton(Microsoft.Extensions.Options.Options.Create(_mcpServerConfiguration)); + Services.AddSingleton(ExtensionsOptions.Options.Create(_mcpServerConfiguration)); } [Fact] diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/CommandFactoryToolLoaderTests.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/CommandFactoryToolLoaderTests.cs index c1e465638c..70514608de 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/CommandFactoryToolLoaderTests.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/CommandFactoryToolLoaderTests.cs @@ -4,6 +4,7 @@ using System.CommandLine; using System.Net; +using System.Reflection; using System.Text.Json; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -13,8 +14,10 @@ using Microsoft.Mcp.Core.Models.Command; using Microsoft.Mcp.Core.Options; using ModelContextProtocol.Protocol; +using ModelContextProtocol.Server; using NSubstitute; using Xunit; +using ExtensionsOptions = Microsoft.Extensions.Options; namespace Azure.Mcp.Core.Tests.Areas.Server.Commands.ToolLoading; @@ -26,16 +29,16 @@ private static (CommandFactoryToolLoader toolLoader, ICommandFactory commandFact var commandFactory = CommandFactoryHelpers.CreateCommandFactory(serviceProvider); var loggerFactory = serviceProvider.GetRequiredService(); var logger = loggerFactory.CreateLogger(); - var toolLoaderOptions = Microsoft.Extensions.Options.Options.Create(options ?? new ToolLoaderOptions()); + var toolLoaderOptions = ExtensionsOptions.Options.Create(options ?? new ToolLoaderOptions()); var toolLoader = new CommandFactoryToolLoader(commandFactory, toolLoaderOptions, logger); return (toolLoader, commandFactory); } - private static ModelContextProtocol.Server.RequestContext CreateRequest() + private static RequestContext CreateRequest() { - var mockServer = Substitute.For(); - return new ModelContextProtocol.Server.RequestContext(mockServer, new() { Method = RequestMethods.ToolsList }) + var mockServer = Substitute.For(); + return new RequestContext(mockServer, new() { Method = RequestMethods.ToolsList }) { Params = new ListToolsRequestParams() }; @@ -325,8 +328,8 @@ public async Task CallToolHandler_WithValidTool_ExecutesSuccessfully() var availableCommands = CommandFactory.GetVisibleCommands(commandFactory.AllCommands); var firstCommand = availableCommands.First(); - var mockServer = Substitute.For(); - var request = new ModelContextProtocol.Server.RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) + var mockServer = Substitute.For(); + var request = new RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) { Params = new CallToolRequestParams { @@ -347,8 +350,8 @@ public async Task CallToolHandler_WithNullParams_ReturnsError() { var (toolLoader, _) = CreateToolLoader(); - var mockServer = Substitute.For(); - var request = new ModelContextProtocol.Server.RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }, null!); + var mockServer = Substitute.For(); + var request = new RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }, null!); var result = await toolLoader.CallToolHandler(request, TestContext.Current.CancellationToken); @@ -367,8 +370,8 @@ public async Task CallToolHandler_WithUnknownTool_ReturnsError() { var (toolLoader, _) = CreateToolLoader(); - var mockServer = Substitute.For(); - var request = new ModelContextProtocol.Server.RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) + var mockServer = Substitute.For(); + var request = new RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) { Params = new CallToolRequestParams { @@ -458,10 +461,10 @@ public async Task CallToolHandler_BeforeListToolsHandler_ExecutesSuccessfully() var targetCommand = subscriptionListCommand; - var mockServer = Substitute.For(); + var mockServer = Substitute.For(); var arguments = new Dictionary(); - var callToolRequest = new ModelContextProtocol.Server.RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) + var callToolRequest = new RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) { Params = new CallToolRequestParams { @@ -609,7 +612,7 @@ public async Task ListToolsHandler_EnumOption_IsExportedAsStringType() var serviceProvider = CommandFactoryHelpers.CreateDefaultServiceProvider(); var loggerFactory = serviceProvider.GetRequiredService(); var logger = loggerFactory.CreateLogger(); - var toolLoaderOptions = Microsoft.Extensions.Options.Options.Create(new ToolLoaderOptions()); + var toolLoaderOptions = ExtensionsOptions.Options.Create(new ToolLoaderOptions()); var fakeSystemCommand = new Command("fake-enum-get", "A fake command with an enum option for testing."); OptionBinder.RegisterOptions(fakeSystemCommand); @@ -620,7 +623,7 @@ public async Task ListToolsHandler_EnumOption_IsExportedAsStringType() fakeCommand.Metadata.Returns(new ToolMetadata()); var commandFactory = CommandFactoryHelpers.CreateCommandFactory(serviceProvider); - var commandMapField = typeof(CommandFactory).GetField("_commandMap", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + var commandMapField = typeof(CommandFactory).GetField("_commandMap", BindingFlags.NonPublic | BindingFlags.Instance); var commandMap = (Dictionary)commandMapField!.GetValue(commandFactory)!; commandMap["fake-enum-get"] = fakeCommand; @@ -705,7 +708,7 @@ public async Task ListToolsHandler_ToolsWithSecretMetadata_HaveSecretHintInMeta( var serviceProvider = CommandFactoryHelpers.CreateDefaultServiceProvider(); var loggerFactory = serviceProvider.GetRequiredService(); var logger = loggerFactory.CreateLogger(); - var toolLoaderOptions = Microsoft.Extensions.Options.Options.Create(new ToolLoaderOptions()); + var toolLoaderOptions = ExtensionsOptions.Options.Create(new ToolLoaderOptions()); // Create a fake command factory that includes a command with secret metadata var fakeCommand = Substitute.For(); @@ -720,7 +723,7 @@ public async Task ListToolsHandler_ToolsWithSecretMetadata_HaveSecretHintInMeta( var commandFactory = CommandFactoryHelpers.CreateCommandFactory(serviceProvider); // Add our fake command to the internal command map using reflection - var commandMapField = typeof(CommandFactory).GetField("_commandMap", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + var commandMapField = typeof(CommandFactory).GetField("_commandMap", BindingFlags.NonPublic | BindingFlags.Instance); var commandMap = (Dictionary)commandMapField!.GetValue(commandFactory)!; commandMap["fake-secret-get"] = fakeCommand; @@ -760,15 +763,15 @@ public async Task CallToolHandler_WithSecretTool_WhenClientDoesNotSupportElicita .Returns(new CommandResponse { Status = HttpStatusCode.OK, Message = "Secret test response" }); // Add our fake command to the internal command map using reflection - var commandMapField = typeof(CommandFactory).GetField("_commandMap", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + var commandMapField = typeof(CommandFactory).GetField("_commandMap", BindingFlags.NonPublic | BindingFlags.Instance); var commandMap = (Dictionary)commandMapField!.GetValue(commandFactory)!; commandMap["fake-secret-get"] = fakeCommand; // Create mock server without elicitation capabilities - var mockServer = Substitute.For(); + var mockServer = Substitute.For(); mockServer.ClientCapabilities.Returns((ClientCapabilities?)null); - var request = new ModelContextProtocol.Server.RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) + var request = new RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) { Params = new CallToolRequestParams { @@ -800,16 +803,16 @@ public async Task CallToolHandler_WithNonSecretTool_DoesNotTriggerElicitation() .Returns(new CommandResponse { Status = HttpStatusCode.OK, Message = "Test response" }); // Add our fake command to the internal command map using reflection - var commandMapField = typeof(CommandFactory).GetField("_commandMap", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + var commandMapField = typeof(CommandFactory).GetField("_commandMap", BindingFlags.NonPublic | BindingFlags.Instance); var commandMap = (Dictionary)commandMapField!.GetValue(commandFactory)!; commandMap["fake-non-secret-get"] = fakeCommand; // Create mock server with elicitation capabilities - var mockServer = Substitute.For(); + var mockServer = Substitute.For(); var capabilities = new ClientCapabilities { Elicitation = new ElicitationCapability() }; mockServer.ClientCapabilities.Returns(capabilities); - var request = new ModelContextProtocol.Server.RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) + var request = new RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) { Params = new CallToolRequestParams { @@ -842,15 +845,15 @@ public async Task CallToolHandler_WithSecretTool_WhenDangerouslyDisableElicitati .Returns(new CommandResponse { Status = HttpStatusCode.OK, Message = "Secret test response" }); // Add our fake command to the internal command map using reflection - var commandMapField = typeof(CommandFactory).GetField("_commandMap", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + var commandMapField = typeof(CommandFactory).GetField("_commandMap", BindingFlags.NonPublic | BindingFlags.Instance); var commandMap = (Dictionary)commandMapField!.GetValue(commandFactory)!; commandMap["fake-secret-get"] = fakeCommand; // Create mock server - elicitation support doesn't matter when bypassed - var mockServer = Substitute.For(); + var mockServer = Substitute.For(); mockServer.ClientCapabilities.Returns((ClientCapabilities?)null); - var request = new ModelContextProtocol.Server.RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) + var request = new RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) { Params = new CallToolRequestParams { @@ -887,15 +890,15 @@ public async Task CallToolHandler_WithSecretTool_WhenDangerouslyDisableElicitati .Returns(new CommandResponse { Status = HttpStatusCode.OK, Message = "Secret test response" }); // Add our fake command to the internal command map using reflection - var commandMapField = typeof(CommandFactory).GetField("_commandMap", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + var commandMapField = typeof(CommandFactory).GetField("_commandMap", BindingFlags.NonPublic | BindingFlags.Instance); var commandMap = (Dictionary)commandMapField!.GetValue(commandFactory)!; commandMap["fake-secret-get"] = fakeCommand; // Create mock server without elicitation capabilities - var mockServer = Substitute.For(); + var mockServer = Substitute.For(); mockServer.ClientCapabilities.Returns((ClientCapabilities?)null); - var request = new ModelContextProtocol.Server.RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) + var request = new RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) { Params = new CallToolRequestParams { @@ -949,8 +952,8 @@ public async Task CallToolHandler_WithToolFilter_AllowsSpecifiedTool() var toolOptions = new ToolLoaderOptions { Tool = [specificToolName] }; var (toolLoader, _) = CreateToolLoader(toolOptions); - var mockServer = Substitute.For(); - var request = new ModelContextProtocol.Server.RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) + var mockServer = Substitute.For(); + var request = new RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) { Params = new CallToolRequestParams { @@ -992,8 +995,8 @@ public async Task CallToolHandler_WithToolFilter_RejectsNonSpecifiedTool() var toolOptions = new ToolLoaderOptions { Tool = [specificToolName] }; var (toolLoader, _) = CreateToolLoader(toolOptions); - var mockServer = Substitute.For(); - var request = new ModelContextProtocol.Server.RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) + var mockServer = Substitute.For(); + var request = new RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) { Params = new CallToolRequestParams { @@ -1031,8 +1034,8 @@ public async Task CallToolHandler_WithToolFilterCaseInsensitive_AllowsSpecifiedT var toolOptions = new ToolLoaderOptions { Tool = [specificToolName.ToUpperInvariant()] }; // Set filter to uppercase var (toolLoader, _) = CreateToolLoader(toolOptions); - var mockServer = Substitute.For(); - var request = new ModelContextProtocol.Server.RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) + var mockServer = Substitute.For(); + var request = new RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) { Params = new CallToolRequestParams { @@ -1133,12 +1136,12 @@ public async Task CallToolHandler_WithReadOnlyMode_RejectsNonReadOnlyTool() fakeCommand.Title.Returns("Fake Write Tool"); fakeCommand.Metadata.Returns(new ToolMetadata { ReadOnly = false }); - var commandMapField = typeof(CommandFactory).GetField("_commandMap", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + var commandMapField = typeof(CommandFactory).GetField("_commandMap", BindingFlags.NonPublic | BindingFlags.Instance); var commandMap = (Dictionary)commandMapField!.GetValue(commandFactory)!; commandMap["fake-write-tool"] = fakeCommand; - var mockServer = Substitute.For(); - var request = new ModelContextProtocol.Server.RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) + var mockServer = Substitute.For(); + var request = new RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) { Params = new CallToolRequestParams { @@ -1174,12 +1177,12 @@ public async Task CallToolHandler_WithReadOnlyMode_AllowsReadOnlyTool() fakeCommand.ExecuteAsync(Arg.Any(), Arg.Any(), Arg.Any()) .Returns(new CommandResponse { Status = HttpStatusCode.OK, Message = "Read-only test response" }); - var commandMapField = typeof(CommandFactory).GetField("_commandMap", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + var commandMapField = typeof(CommandFactory).GetField("_commandMap", BindingFlags.NonPublic | BindingFlags.Instance); var commandMap = (Dictionary)commandMapField!.GetValue(commandFactory)!; commandMap["fake-readonly-tool"] = fakeCommand; - var mockServer = Substitute.For(); - var request = new ModelContextProtocol.Server.RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) + var mockServer = Substitute.For(); + var request = new RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) { Params = new CallToolRequestParams { @@ -1210,12 +1213,12 @@ public async Task CallToolHandler_WithHttpMode_RejectsLocalRequiredTool() fakeCommand.Title.Returns("Fake Local Tool"); fakeCommand.Metadata.Returns(new ToolMetadata { LocalRequired = true }); - var commandMapField = typeof(CommandFactory).GetField("_commandMap", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + var commandMapField = typeof(CommandFactory).GetField("_commandMap", BindingFlags.NonPublic | BindingFlags.Instance); var commandMap = (Dictionary)commandMapField!.GetValue(commandFactory)!; commandMap["fake-local-tool"] = fakeCommand; - var mockServer = Substitute.For(); - var request = new ModelContextProtocol.Server.RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) + var mockServer = Substitute.For(); + var request = new RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) { Params = new CallToolRequestParams { @@ -1251,12 +1254,12 @@ public async Task CallToolHandler_WithoutReadOnlyMode_AllowsNonReadOnlyTool() fakeCommand.ExecuteAsync(Arg.Any(), Arg.Any(), Arg.Any()) .Returns(new CommandResponse { Status = HttpStatusCode.OK, Message = "Write test response" }); - var commandMapField = typeof(CommandFactory).GetField("_commandMap", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + var commandMapField = typeof(CommandFactory).GetField("_commandMap", BindingFlags.NonPublic | BindingFlags.Instance); var commandMap = (Dictionary)commandMapField!.GetValue(commandFactory)!; commandMap["fake-write-tool-2"] = fakeCommand; - var mockServer = Substitute.For(); - var request = new ModelContextProtocol.Server.RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) + var mockServer = Substitute.For(); + var request = new RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) { Params = new CallToolRequestParams { diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/NamespaceToolLoaderTests.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/NamespaceToolLoaderTests.cs index 2b637a3e8f..a01af8cf42 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/NamespaceToolLoaderTests.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/NamespaceToolLoaderTests.cs @@ -1,19 +1,27 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#pragma warning disable MCP9003 // Obsolete RequestContext constructor - migrating during Phase 1 +#pragma warning disable MCP9005 // Deprecated Sampling/Logging APIs - backward compat during Phase 1 + +using System.CommandLine; +using System.Net; using System.Text.Json; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -using Microsoft.Extensions.Options; using Microsoft.Mcp.Core.Areas.Server.Commands.Discovery; using Microsoft.Mcp.Core.Areas.Server.Commands.ToolLoading; using Microsoft.Mcp.Core.Areas.Server.Options; using Microsoft.Mcp.Core.Commands; using Microsoft.Mcp.Core.Helpers; +using Microsoft.Mcp.Core.Models.Command; +using ModelContextProtocol.Client; using ModelContextProtocol.Protocol; +using ModelContextProtocol.Server; using NSubstitute; using Xunit; +using ExtensionsOptions = Microsoft.Extensions.Options; namespace Azure.Mcp.Core.Tests.Areas.Server.Commands.ToolLoading; @@ -21,7 +29,7 @@ public sealed class NamespaceToolLoaderTests : IAsyncDisposable { private readonly ServiceProvider _serviceProvider; private readonly ICommandFactory _commandFactory; - private readonly IOptions _options; + private readonly ExtensionsOptions.IOptions _options; private readonly ILogger _logger; public NamespaceToolLoaderTests() @@ -29,7 +37,7 @@ public NamespaceToolLoaderTests() _serviceProvider = CommandFactoryHelpers.CreateDefaultServiceProvider() as ServiceProvider ?? throw new InvalidOperationException("Failed to create service provider"); _commandFactory = CommandFactoryHelpers.CreateCommandFactory(_serviceProvider); - _options = Microsoft.Extensions.Options.Options.Create(new ServerStartOptions()); + _options = ExtensionsOptions.Options.Create(new ServerStartOptions()); _logger = NullLogger.Instance; } @@ -104,7 +112,7 @@ public async Task ListToolsHandler_CachesResults() public async Task ListToolsHandler_FiltersNamespacesWhenConfigured() { // Arrange - var options = Microsoft.Extensions.Options.Options.Create(new ServerStartOptions + var options = ExtensionsOptions.Options.Create(new ServerStartOptions { Namespace = ["storage", "keyvault"] }); @@ -138,7 +146,7 @@ public async Task ListToolsHandler_WithReadOnlyOption_ReturnsOnlyReadOnlyTools() rootGroup.SubGroup.AddRange([storageGroup, keyvaultGroup]); commandFactory.RootGroup.Returns(rootGroup); - var options = Microsoft.Extensions.Options.Options.Create(new ServerStartOptions + var options = ExtensionsOptions.Options.Create(new ServerStartOptions { ReadOnly = true }); @@ -171,7 +179,7 @@ public async Task ListToolsHandler_WithIsHttpOption_DoesNotReturnLocalRequiredTo rootGroup.SubGroup.AddRange([stroageGroup, keyvaultGroup]); commandFactory.RootGroup.Returns(rootGroup); - var options = Microsoft.Extensions.Options.Options.Create(new ServerStartOptions + var options = ExtensionsOptions.Options.Create(new ServerStartOptions { Transport = TransportTypes.Http }); @@ -530,7 +538,7 @@ public void CreateClientOptions_WithElicitationCapability_ReturnsOptionsWithElic { // Arrange var loader = new NamespaceToolLoader(_commandFactory, _options, _logger); - var mockServer = Substitute.For(); + var mockServer = Substitute.For(); var capabilities = new ClientCapabilities { Elicitation = new ElicitationCapability() @@ -551,7 +559,7 @@ public void CreateClientOptions_WithNoElicitationCapability_ReturnsOptionsWithou { // Arrange var loader = new NamespaceToolLoader(_commandFactory, _options, _logger); - var mockServer = Substitute.For(); + var mockServer = Substitute.For(); mockServer.ClientCapabilities.Returns(new ClientCapabilities()); // Act @@ -568,7 +576,7 @@ public async Task CreateClientOptions_ElicitationHandler_DelegatesToServerSendRe { // Arrange var loader = new NamespaceToolLoader(_commandFactory, _options, _logger); - var mockServer = Substitute.For(); + var mockServer = Substitute.For(); var capabilities = new ClientCapabilities { Elicitation = new ElicitationCapability() @@ -621,7 +629,7 @@ public async Task CreateClientOptions_ElicitationHandler_ValidatesRequestAndThro { // Arrange var loader = new NamespaceToolLoader(_commandFactory, _options, _logger); - var mockServer = Substitute.For(); + var mockServer = Substitute.For(); var capabilities = new ClientCapabilities { Elicitation = new ElicitationCapability() @@ -648,11 +656,11 @@ public async Task CallToolHandler_ReadOnlyMode_RejectsNonReadOnlyCommand() var executed = false; var writeCmd = Substitute.For(); writeCmd.Metadata.Returns(new ToolMetadata { ReadOnly = false }); - writeCmd.GetCommand().Returns(new System.CommandLine.Command("write-cmd", "A write command")); + writeCmd.GetCommand().Returns(new Command("write-cmd", "A write command")); writeCmd.ExecuteAsync(default!, default!, default!).ReturnsForAnyArgs(call => { executed = true; - return new Microsoft.Mcp.Core.Models.Command.CommandResponse { Status = System.Net.HttpStatusCode.OK }; + return new CommandResponse { Status = HttpStatusCode.OK }; }); storageGroup.AddCommand("write-cmd", writeCmd); @@ -661,7 +669,7 @@ public async Task CallToolHandler_ReadOnlyMode_RejectsNonReadOnlyCommand() commandFactory.GroupCommands(Arg.Any()) .Returns(new Dictionary { ["write-cmd"] = writeCmd }); - var options = Microsoft.Extensions.Options.Options.Create(new ServerStartOptions { ReadOnly = true }); + var options = ExtensionsOptions.Options.Create(new ServerStartOptions { ReadOnly = true }); var loader = new NamespaceToolLoader(commandFactory, options, _logger); var request = CreateCallToolRequest("storage", new Dictionary @@ -688,11 +696,11 @@ public async Task CallToolHandler_ReadOnlyMode_AllowsReadOnlyCommand() var executed = false; var readCmd = Substitute.For(); readCmd.Metadata.Returns(new ToolMetadata { ReadOnly = true, Destructive = false }); - readCmd.GetCommand().Returns(new System.CommandLine.Command("read-cmd", "A read command")); + readCmd.GetCommand().Returns(new Command("read-cmd", "A read command")); readCmd.ExecuteAsync(default!, default!, default!).ReturnsForAnyArgs(call => { executed = true; - return new Microsoft.Mcp.Core.Models.Command.CommandResponse { Status = System.Net.HttpStatusCode.OK }; + return new CommandResponse { Status = HttpStatusCode.OK }; }); storageGroup.AddCommand("read-cmd", readCmd); @@ -701,7 +709,7 @@ public async Task CallToolHandler_ReadOnlyMode_AllowsReadOnlyCommand() commandFactory.GroupCommands(Arg.Any()) .Returns(new Dictionary { ["read-cmd"] = readCmd }); - var options = Microsoft.Extensions.Options.Options.Create(new ServerStartOptions { ReadOnly = true }); + var options = ExtensionsOptions.Options.Create(new ServerStartOptions { ReadOnly = true }); var loader = new NamespaceToolLoader(commandFactory, options, _logger); var request = CreateCallToolRequest("storage", new Dictionary @@ -728,11 +736,11 @@ public async Task CallToolHandler_HttpMode_RejectsLocalRequiredCommand() var executed = false; var localCmd = Substitute.For(); localCmd.Metadata.Returns(new ToolMetadata { LocalRequired = true }); - localCmd.GetCommand().Returns(new System.CommandLine.Command("local-cmd", "A local command")); + localCmd.GetCommand().Returns(new Command("local-cmd", "A local command")); localCmd.ExecuteAsync(default!, default!, default!).ReturnsForAnyArgs(call => { executed = true; - return new Microsoft.Mcp.Core.Models.Command.CommandResponse { Status = System.Net.HttpStatusCode.OK }; + return new CommandResponse { Status = HttpStatusCode.OK }; }); storageGroup.AddCommand("local-cmd", localCmd); @@ -741,7 +749,7 @@ public async Task CallToolHandler_HttpMode_RejectsLocalRequiredCommand() commandFactory.GroupCommands(Arg.Any()) .Returns(new Dictionary { ["local-cmd"] = localCmd }); - var options = Microsoft.Extensions.Options.Options.Create(new ServerStartOptions { Transport = TransportTypes.Http }); + var options = ExtensionsOptions.Options.Create(new ServerStartOptions { Transport = TransportTypes.Http }); var loader = new NamespaceToolLoader(commandFactory, options, _logger); var request = CreateCallToolRequest("storage", new Dictionary @@ -768,11 +776,11 @@ public async Task CallToolHandler_HttpMode_AllowsNonLocalRequiredCommand() var executed = false; var remoteCmd = Substitute.For(); remoteCmd.Metadata.Returns(new ToolMetadata { LocalRequired = false, Destructive = false }); - remoteCmd.GetCommand().Returns(new System.CommandLine.Command("remote-cmd", "A remote command")); + remoteCmd.GetCommand().Returns(new Command("remote-cmd", "A remote command")); remoteCmd.ExecuteAsync(default!, default!, default!).ReturnsForAnyArgs(call => { executed = true; - return new Microsoft.Mcp.Core.Models.Command.CommandResponse { Status = System.Net.HttpStatusCode.OK }; + return new CommandResponse { Status = HttpStatusCode.OK }; }); storageGroup.AddCommand("remote-cmd", remoteCmd); @@ -781,7 +789,7 @@ public async Task CallToolHandler_HttpMode_AllowsNonLocalRequiredCommand() commandFactory.GroupCommands(Arg.Any()) .Returns(new Dictionary { ["remote-cmd"] = remoteCmd }); - var options = Microsoft.Extensions.Options.Options.Create(new ServerStartOptions { Transport = TransportTypes.Http }); + var options = ExtensionsOptions.Options.Create(new ServerStartOptions { Transport = TransportTypes.Http }); var loader = new NamespaceToolLoader(commandFactory, options, _logger); var request = CreateCallToolRequest("storage", new Dictionary @@ -798,10 +806,10 @@ public async Task CallToolHandler_HttpMode_AllowsNonLocalRequiredCommand() } [Fact] - public async Task GetChildToolList_WithReadOnlyOption_ReturnsOnlyReadOnlyTools() + public void GetChildToolList_WithReadOnlyOption_ReturnsOnlyReadOnlyTools() { // Arrange - var options = Microsoft.Extensions.Options.Options.Create(new ServerStartOptions + var options = ExtensionsOptions.Options.Create(new ServerStartOptions { ReadOnly = true }); @@ -818,10 +826,10 @@ public async Task GetChildToolList_WithReadOnlyOption_ReturnsOnlyReadOnlyTools() } [Fact] - public async Task GetChildToolList_WithIsHttpOption_DoesNotReturnLocalRequiredTools() + public void GetChildToolList_WithIsHttpOption_DoesNotReturnLocalRequiredTools() { // Arrange - var options = Microsoft.Extensions.Options.Options.Create(new ServerStartOptions + var options = ExtensionsOptions.Options.Create(new ServerStartOptions { Transport = TransportTypes.Http }); @@ -853,13 +861,13 @@ private string GetFirstAvailableNamespace() return namespaces.FirstOrDefault() ?? "storage"; } - private static ModelContextProtocol.Server.RequestContext CreateListToolsRequest() + private static RequestContext CreateListToolsRequest() { - var mockServer = Substitute.For(); + var mockServer = Substitute.For(); return new(mockServer, new() { Method = RequestMethods.ToolsList }, new ListToolsRequestParams()); } - private static ModelContextProtocol.Server.RequestContext CreateCallToolRequest( + private static RequestContext CreateCallToolRequest( string toolName, Dictionary arguments) { @@ -867,7 +875,7 @@ private static ModelContextProtocol.Server.RequestContext kvp => kvp.Key, kvp => JsonSerializer.SerializeToElement(kvp.Value)); - var mockServer = Substitute.For(); + var mockServer = Substitute.For(); return new(mockServer, new() { Method = RequestMethods.ToolsCall }, new CallToolRequestParams { Name = toolName, @@ -875,11 +883,11 @@ private static ModelContextProtocol.Server.RequestContext }); } - private static ModelContextProtocol.Server.RequestContext CreateCallToolRequestWithJsonElements( + private static RequestContext CreateCallToolRequestWithJsonElements( string toolName, Dictionary arguments) { - var mockServer = Substitute.For(); + var mockServer = Substitute.For(); return new(mockServer, new() { Method = RequestMethods.ToolsCall }, new CallToolRequestParams { Name = toolName, @@ -887,9 +895,9 @@ private static ModelContextProtocol.Server.RequestContext }); } - private static ModelContextProtocol.Client.McpClientOptions CallCreateClientOptions( + private static McpClientOptions CallCreateClientOptions( NamespaceToolLoader loader, - ModelContextProtocol.Server.McpServer server) + McpServer server) { // Use reflection to call the protected CreateClientOptions method var method = typeof(BaseToolLoader).GetMethod( @@ -902,7 +910,7 @@ private static ModelContextProtocol.Client.McpClientOptions CallCreateClientOpti } var result = method.Invoke(loader, [server]); - return (ModelContextProtocol.Client.McpClientOptions)result!; + return (McpClientOptions)result!; } public async ValueTask DisposeAsync() diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/PluginTelemetryCommandTests.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/PluginTelemetryCommandTests.cs index 190d37cdc7..3fb111749d 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/PluginTelemetryCommandTests.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/PluginTelemetryCommandTests.cs @@ -15,6 +15,7 @@ using Microsoft.Mcp.Core.Services.Telemetry; using NSubstitute; using Xunit; +using ExtensionsOptions = Microsoft.Extensions.Options; namespace Azure.Mcp.Core.Tests.Areas.Server.Commands.ToolLoading; @@ -42,7 +43,7 @@ public PluginTelemetryCommandTests() // Build a real CommandFactory with ServerSetup to get actual registered commands var services = new ServiceCollection(); services.AddSingleton(new ServerSetup()); - services.AddSingleton(Microsoft.Extensions.Options.Options.Create(new McpServerConfiguration + services.AddSingleton(ExtensionsOptions.Options.Create(new McpServerConfiguration { RootCommandGroupName = "azmcp", Name = "Azure.Mcp.Server.Test", diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/RegistryToolLoaderTests.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/RegistryToolLoaderTests.cs index 9a5ff261a8..f0d2f7ef2d 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/RegistryToolLoaderTests.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/RegistryToolLoaderTests.cs @@ -12,8 +12,10 @@ using Microsoft.Mcp.Core.Helpers; using ModelContextProtocol.Client; using ModelContextProtocol.Protocol; +using ModelContextProtocol.Server; using NSubstitute; using Xunit; +using ExtensionsOptions = Microsoft.Extensions.Options; namespace Azure.Mcp.Core.Tests.Areas.Server.Commands.ToolLoading; @@ -25,25 +27,25 @@ private static (RegistryToolLoader toolLoader, IMcpDiscoveryStrategy mockDiscove var loggerFactory = serviceProvider.GetRequiredService(); var mockDiscoveryStrategy = new MockMcpDiscoveryStrategyBuilder().Build(); var logger = loggerFactory.CreateLogger(); - var toolLoaderOptions = Microsoft.Extensions.Options.Options.Create(options ?? new ToolLoaderOptions()); + var toolLoaderOptions = ExtensionsOptions.Options.Create(options ?? new ToolLoaderOptions()); var toolLoader = new RegistryToolLoader(mockDiscoveryStrategy, toolLoaderOptions, logger); return (toolLoader, mockDiscoveryStrategy); } - private static ModelContextProtocol.Server.RequestContext CreateListToolsRequest() + private static RequestContext CreateListToolsRequest() { - var mockServer = Substitute.For(); - return new ModelContextProtocol.Server.RequestContext(mockServer, new() { Method = RequestMethods.ToolsList }) + var mockServer = Substitute.For(); + return new RequestContext(mockServer, new() { Method = RequestMethods.ToolsList }) { Params = new ListToolsRequestParams() }; } - private static ModelContextProtocol.Server.RequestContext CreateCallToolRequest(string toolName, IDictionary? arguments = null) + private static RequestContext CreateCallToolRequest(string toolName, IDictionary? arguments = null) { - var mockServer = Substitute.For(); - return new ModelContextProtocol.Server.RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) + var mockServer = Substitute.For(); + return new RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) { Params = new CallToolRequestParams { @@ -87,7 +89,7 @@ public async Task ListToolsHandler_WithMockServerProvider_ReturnsExpectedStructu var serviceProvider = new ServiceCollection().AddLogging().BuildServiceProvider(); var loggerFactory = serviceProvider.GetRequiredService(); var logger = loggerFactory.CreateLogger(); - var serviceOptions = Microsoft.Extensions.Options.Options.Create(new ToolLoaderOptions()); + var serviceOptions = ExtensionsOptions.Options.Create(new ToolLoaderOptions()); var toolLoader = new RegistryToolLoader(discoveryStrategy, serviceOptions, logger); var request = CreateListToolsRequest(); @@ -135,7 +137,7 @@ public async Task ListToolsHandler_WithReadOnlyOption_FiltersProperly() var serviceProvider = new ServiceCollection().AddLogging().BuildServiceProvider(); var loggerFactory = serviceProvider.GetRequiredService(); var logger = loggerFactory.CreateLogger(); - var serviceOptions = Microsoft.Extensions.Options.Options.Create(readOnlyOptions); + var serviceOptions = ExtensionsOptions.Options.Create(readOnlyOptions); var toolLoader = new RegistryToolLoader(discoveryStrategy, serviceOptions, logger); var request = CreateListToolsRequest(); @@ -151,7 +153,7 @@ public async Task ListToolsHandler_WithReadOnlyOption_FiltersProperly() Assert.Single(result.Tools); var returnedTool = result.Tools.First(); Assert.Equal("readonly-tool", returnedTool.Name); - Assert.True(returnedTool.Annotations?.ReadOnlyHint == true, "Returned tool should have ReadOnlyHint = true"); + Assert.True(returnedTool.Annotations?.ReadOnlyHint, "Returned tool should have ReadOnlyHint = true"); // Verify that the write tool was filtered out Assert.DoesNotContain(result.Tools, t => t.Name == "write-tool"); @@ -189,7 +191,7 @@ public async Task ListToolsHandler_WithReadOnlyDisabled_ReturnsAllTools() var serviceProvider = new ServiceCollection().AddLogging().BuildServiceProvider(); var loggerFactory = serviceProvider.GetRequiredService(); var logger = loggerFactory.CreateLogger(); - var serviceOptions = Microsoft.Extensions.Options.Options.Create(defaultOptions); + var serviceOptions = ExtensionsOptions.Options.Create(defaultOptions); var toolLoader = new RegistryToolLoader(discoveryStrategy, serviceOptions, logger); var request = CreateListToolsRequest(); @@ -209,8 +211,8 @@ public async Task ListToolsHandler_WithReadOnlyDisabled_ReturnsAllTools() // Verify annotations are preserved var readOnlyToolResult = result.Tools.First(t => t.Name == "readonly-tool"); var writeToolResult = result.Tools.First(t => t.Name == "write-tool"); - Assert.True(readOnlyToolResult.Annotations?.ReadOnlyHint == true); - Assert.True(writeToolResult.Annotations?.ReadOnlyHint == false); + Assert.True(readOnlyToolResult.Annotations?.ReadOnlyHint); + Assert.False(writeToolResult.Annotations?.ReadOnlyHint); } [Fact] @@ -248,7 +250,7 @@ public async Task ListToolsHandler_WithIsHttpOption_FiltersProperly() var serviceProvider = new ServiceCollection().AddLogging().BuildServiceProvider(); var loggerFactory = serviceProvider.GetRequiredService(); var logger = loggerFactory.CreateLogger(); - var serviceOptions = Microsoft.Extensions.Options.Options.Create(isHttpOptions); + var serviceOptions = ExtensionsOptions.Options.Create(isHttpOptions); var toolLoader = new RegistryToolLoader(discoveryStrategy, serviceOptions, logger); var request = CreateListToolsRequest(); @@ -306,7 +308,7 @@ public async Task ListToolsHandler_WithIsHttpDisabled_ReturnsAllTools() var serviceProvider = new ServiceCollection().AddLogging().BuildServiceProvider(); var loggerFactory = serviceProvider.GetRequiredService(); var logger = loggerFactory.CreateLogger(); - var serviceOptions = Microsoft.Extensions.Options.Options.Create(isHttpOptions); + var serviceOptions = ExtensionsOptions.Options.Create(isHttpOptions); var toolLoader = new RegistryToolLoader(discoveryStrategy, serviceOptions, logger); var request = CreateListToolsRequest(); @@ -373,9 +375,9 @@ public async Task RegistryToolLoader_WithDifferentOptions_BehavesConsistently() var logger2 = loggerFactory.CreateLogger(); var defaultToolLoader = new RegistryToolLoader(defaultDiscoveryStrategy, - Microsoft.Extensions.Options.Options.Create(defaultOptions), logger1); + ExtensionsOptions.Options.Create(defaultOptions), logger1); var readOnlyToolLoader = new RegistryToolLoader(readOnlyDiscoveryStrategy, - Microsoft.Extensions.Options.Options.Create(readOnlyOptions), logger2); + ExtensionsOptions.Options.Create(readOnlyOptions), logger2); var request = CreateListToolsRequest(); @@ -415,7 +417,7 @@ public async Task CallToolHandler_WithoutListToolsFirst_ShouldSucceed() var serviceProvider = new ServiceCollection().AddLogging().BuildServiceProvider(); var loggerFactory = serviceProvider.GetRequiredService(); var logger = loggerFactory.CreateLogger(); - var serviceOptions = Microsoft.Extensions.Options.Options.Create(new ToolLoaderOptions()); + var serviceOptions = ExtensionsOptions.Options.Create(new ToolLoaderOptions()); var toolLoader = new RegistryToolLoader(discoveryStrategy, serviceOptions, logger); var request = CreateCallToolRequest("microsoft_docs_search", @@ -470,7 +472,7 @@ public async Task MockMcpClient_WithExtensionMethods_WorksCorrectly() var serviceProvider = new ServiceCollection().AddLogging().BuildServiceProvider(); var loggerFactory = serviceProvider.GetRequiredService(); var logger = loggerFactory.CreateLogger(); - var serviceOptions = Microsoft.Extensions.Options.Options.Create(new ToolLoaderOptions()); + var serviceOptions = ExtensionsOptions.Options.Create(new ToolLoaderOptions()); var toolLoader = new RegistryToolLoader(discoveryStrategy, serviceOptions, logger); @@ -542,7 +544,7 @@ public async Task ListToolsHandler_WithReadOnlyOption_FilterToolsWithNullAnnotat var serviceProvider = new ServiceCollection().AddLogging().BuildServiceProvider(); var loggerFactory = serviceProvider.GetRequiredService(); var logger = loggerFactory.CreateLogger(); - var serviceOptions = Microsoft.Extensions.Options.Options.Create(readOnlyOptions); + var serviceOptions = ExtensionsOptions.Options.Create(readOnlyOptions); var toolLoader = new RegistryToolLoader(discoveryStrategy, serviceOptions, logger); var request = CreateListToolsRequest(); @@ -559,7 +561,7 @@ public async Task ListToolsHandler_WithReadOnlyOption_FilterToolsWithNullAnnotat Assert.Single(result.Tools); var returnedTool = result.Tools.First(); Assert.Equal("readonly-tool", returnedTool.Name); - Assert.True(returnedTool.Annotations?.ReadOnlyHint == true); + Assert.True(returnedTool.Annotations?.ReadOnlyHint); // Verify that the tool without annotations was filtered out Assert.DoesNotContain(result.Tools, t => t.Name == "tool-no-annotations"); @@ -684,7 +686,7 @@ public async Task ListToolsHandler_WithMultipleServers_InitializesConcurrently() var serviceProvider = new ServiceCollection().AddLogging().BuildServiceProvider(); var loggerFactory = serviceProvider.GetRequiredService(); var logger = loggerFactory.CreateLogger(); - var serviceOptions = Microsoft.Extensions.Options.Options.Create(new ToolLoaderOptions()); + var serviceOptions = ExtensionsOptions.Options.Create(new ToolLoaderOptions()); var toolLoader = new RegistryToolLoader(mockDiscoveryStrategy, serviceOptions, logger); var request = CreateListToolsRequest(); @@ -757,7 +759,7 @@ public async Task ListToolsHandler_WhenCancellationOccursDuringInitialization_Al var serviceProvider = new ServiceCollection().AddLogging().BuildServiceProvider(); var loggerFactory = serviceProvider.GetRequiredService(); var logger = loggerFactory.CreateLogger(); - var serviceOptions = Microsoft.Extensions.Options.Options.Create(new ToolLoaderOptions()); + var serviceOptions = ExtensionsOptions.Options.Create(new ToolLoaderOptions()); var toolLoader = new RegistryToolLoader(mockDiscoveryStrategy, serviceOptions, logger); var request = CreateListToolsRequest(); @@ -793,7 +795,7 @@ public async Task ListToolsHandler_WithToolPrefix_ExposesToolsWithPrefix() var serviceProvider = new ServiceCollection().AddLogging().BuildServiceProvider(); var logger = serviceProvider.GetRequiredService().CreateLogger(); - var toolLoader = new RegistryToolLoader(discoveryStrategy, Microsoft.Extensions.Options.Options.Create(new ToolLoaderOptions()), logger); + var toolLoader = new RegistryToolLoader(discoveryStrategy, ExtensionsOptions.Options.Create(new ToolLoaderOptions()), logger); // Act var result = await toolLoader.ListToolsHandler(CreateListToolsRequest(), TestContext.Current.CancellationToken); @@ -828,7 +830,7 @@ public async Task CallToolHandler_WithToolPrefix_RoutesUsingOriginalName() var serviceProvider = new ServiceCollection().AddLogging().BuildServiceProvider(); var logger = serviceProvider.GetRequiredService().CreateLogger(); - var toolLoader = new RegistryToolLoader(discoveryStrategy, Microsoft.Extensions.Options.Options.Create(new ToolLoaderOptions()), logger); + var toolLoader = new RegistryToolLoader(discoveryStrategy, ExtensionsOptions.Options.Create(new ToolLoaderOptions()), logger); // Act — call using the prefixed name var result = await toolLoader.CallToolHandler( @@ -856,7 +858,7 @@ public async Task ListToolsHandler_WithNoToolPrefix_ExposesToolsUnchanged() var serviceProvider = new ServiceCollection().AddLogging().BuildServiceProvider(); var logger = serviceProvider.GetRequiredService().CreateLogger(); - var toolLoader = new RegistryToolLoader(discoveryStrategy, Microsoft.Extensions.Options.Options.Create(new ToolLoaderOptions()), logger); + var toolLoader = new RegistryToolLoader(discoveryStrategy, ExtensionsOptions.Options.Create(new ToolLoaderOptions()), logger); // Act var result = await toolLoader.ListToolsHandler(CreateListToolsRequest(), TestContext.Current.CancellationToken); @@ -898,7 +900,7 @@ public async Task CallToolHandler_WithReadOnlyMode_RejectsNonReadOnlyTool() var serviceProvider = new ServiceCollection().AddLogging().BuildServiceProvider(); var loggerFactory = serviceProvider.GetRequiredService(); var logger = loggerFactory.CreateLogger(); - var serviceOptions = Microsoft.Extensions.Options.Options.Create(readOnlyOptions); + var serviceOptions = ExtensionsOptions.Options.Create(readOnlyOptions); var toolLoader = new RegistryToolLoader(discoveryStrategy, serviceOptions, logger); @@ -946,7 +948,7 @@ public async Task CallToolHandler_WithReadOnlyMode_AllowsReadOnlyTool() var serviceProvider = new ServiceCollection().AddLogging().BuildServiceProvider(); var loggerFactory = serviceProvider.GetRequiredService(); var logger = loggerFactory.CreateLogger(); - var serviceOptions = Microsoft.Extensions.Options.Options.Create(readOnlyOptions); + var serviceOptions = ExtensionsOptions.Options.Create(readOnlyOptions); var toolLoader = new RegistryToolLoader(discoveryStrategy, serviceOptions, logger); @@ -996,7 +998,7 @@ public async Task CallToolHandler_WithHttpMode_RejectsLocalRequiredTool() var serviceProvider = new ServiceCollection().AddLogging().BuildServiceProvider(); var loggerFactory = serviceProvider.GetRequiredService(); var logger = loggerFactory.CreateLogger(); - var serviceOptions = Microsoft.Extensions.Options.Options.Create(httpOptions); + var serviceOptions = ExtensionsOptions.Options.Create(httpOptions); var toolLoader = new RegistryToolLoader(discoveryStrategy, serviceOptions, logger); @@ -1035,7 +1037,7 @@ public async Task CallToolHandler_WithReadOnlyToolWithNullAnnotations_RejectsInR var serviceProvider = new ServiceCollection().AddLogging().BuildServiceProvider(); var loggerFactory = serviceProvider.GetRequiredService(); var logger = loggerFactory.CreateLogger(); - var serviceOptions = Microsoft.Extensions.Options.Options.Create(readOnlyOptions); + var serviceOptions = ExtensionsOptions.Options.Create(readOnlyOptions); var toolLoader = new RegistryToolLoader(discoveryStrategy, serviceOptions, logger); diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/ServerToolLoaderTests.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/ServerToolLoaderTests.cs index 8368538ed0..bb2129341e 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/ServerToolLoaderTests.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/ServerToolLoaderTests.cs @@ -17,6 +17,7 @@ using ModelContextProtocol.Server; using NSubstitute; using Xunit; +using ExtensionsOptions = Microsoft.Extensions.Options; namespace Azure.Mcp.Core.Tests.Areas.Server.Commands.ToolLoading; @@ -28,7 +29,7 @@ private static (ServerToolLoader toolLoader, IMcpDiscoveryStrategy mockDiscovery var loggerFactory = serviceProvider.GetRequiredService(); var mockDiscoveryStrategy = Substitute.For(); var logger = loggerFactory.CreateLogger(); - var toolLoaderOptions = Microsoft.Extensions.Options.Options.Create(options ?? new ToolLoaderOptions()); + var toolLoaderOptions = ExtensionsOptions.Options.Create(options ?? new ToolLoaderOptions()); var toolLoader = new ServerToolLoader(mockDiscoveryStrategy, toolLoaderOptions, logger); return (toolLoader, mockDiscoveryStrategy); @@ -56,8 +57,8 @@ public async Task CallToolHandler_WithoutListToolsFirst_ShouldSucceed() // Arrange - use real RegistryDiscoveryStrategy since ServerToolLoader depends on it var serviceProvider = new ServiceCollection().AddLogging().BuildServiceProvider(); var loggerFactory = serviceProvider.GetRequiredService(); - var serviceStartOptions = Microsoft.Extensions.Options.Options.Create(new ServerStartOptions()); - var toolLoaderOptions = Microsoft.Extensions.Options.Options.Create(new ToolLoaderOptions()); + var serviceStartOptions = ExtensionsOptions.Options.Create(new ServerStartOptions()); + var toolLoaderOptions = ExtensionsOptions.Options.Create(new ToolLoaderOptions()); var discoveryLogger = loggerFactory.CreateLogger(); var discoveryStrategy = RegistryDiscoveryStrategyHelper.CreateStrategy(serviceStartOptions.Value, discoveryLogger); var logger = loggerFactory.CreateLogger(); @@ -110,8 +111,8 @@ public async Task ListToolsHandler_WithRealRegistryDiscovery_ReturnsExpectedStru // Arrange - use real RegistryDiscoveryStrategy var serviceProvider = new ServiceCollection().AddLogging().BuildServiceProvider(); var loggerFactory = serviceProvider.GetRequiredService(); - var serviceStartOptions = Microsoft.Extensions.Options.Options.Create(new ServerStartOptions()); - var toolLoaderOptions = Microsoft.Extensions.Options.Options.Create(new ToolLoaderOptions()); + var serviceStartOptions = ExtensionsOptions.Options.Create(new ServerStartOptions()); + var toolLoaderOptions = ExtensionsOptions.Options.Create(new ToolLoaderOptions()); var discoveryLogger = loggerFactory.CreateLogger(); var discoveryStrategy = RegistryDiscoveryStrategyHelper.CreateStrategy(serviceStartOptions.Value, discoveryLogger); var logger = loggerFactory.CreateLogger(); @@ -164,7 +165,7 @@ public async Task ListToolsHandler_WithExternalServers_ExposesProxyRouterTools() var serviceProvider = new ServiceCollection().AddLogging().BuildServiceProvider(); var logger = serviceProvider.GetRequiredService().CreateLogger(); - var toolLoader = new ServerToolLoader(discoveryStrategy, Microsoft.Extensions.Options.Options.Create(new ToolLoaderOptions()), logger); + var toolLoader = new ServerToolLoader(discoveryStrategy, ExtensionsOptions.Options.Create(new ToolLoaderOptions()), logger); var request = CreateRequest(); // Act @@ -193,7 +194,7 @@ public async Task CallToolHandler_WithExternalServerCommand_AttemptsProxyRouting var serviceProvider = new ServiceCollection().AddLogging().BuildServiceProvider(); var logger = serviceProvider.GetRequiredService().CreateLogger(); - var toolLoader = new ServerToolLoader(discoveryStrategy, Microsoft.Extensions.Options.Options.Create(new ToolLoaderOptions()), logger); + var toolLoader = new ServerToolLoader(discoveryStrategy, ExtensionsOptions.Options.Create(new ToolLoaderOptions()), logger); var request = CreateCallToolRequest("documentation", new Dictionary @@ -249,7 +250,7 @@ public async Task GetChildToolList_WithReadOnlyOption_ReturnsOnlyReadOnlyTools() var discoveryStrategy = Substitute.For(); discoveryStrategy.GetOrCreateClientAsync("storage", Arg.Any(), TestContext.Current.CancellationToken) .Returns(mcpClient); - var toolLoaderOptions = Microsoft.Extensions.Options.Options.Create(new ToolLoaderOptions() { ReadOnly = true }); + var toolLoaderOptions = ExtensionsOptions.Options.Create(new ToolLoaderOptions() { ReadOnly = true }); var logger = Substitute.For>(); var toolLoader = new ServerToolLoader(discoveryStrategy, toolLoaderOptions, logger); @@ -292,7 +293,7 @@ public async Task GetChildToolList_WithIsHttpOption_DoesNotReturnLocalRequiredTo var discoveryStrategy = Substitute.For(); discoveryStrategy.GetOrCreateClientAsync("storage", Arg.Any(), TestContext.Current.CancellationToken) .Returns(mcpClient); - var toolLoaderOptions = Microsoft.Extensions.Options.Options.Create(new ToolLoaderOptions() { IsHttpMode = true }); + var toolLoaderOptions = ExtensionsOptions.Options.Create(new ToolLoaderOptions() { IsHttpMode = true }); var logger = Substitute.For>(); var toolLoader = new ServerToolLoader(discoveryStrategy, toolLoaderOptions, logger); @@ -321,7 +322,7 @@ private static (ServerToolLoader toolLoader, IMcpDiscoveryStrategy discoveryStra var serviceProvider = new ServiceCollection().AddLogging().BuildServiceProvider(); var logger = serviceProvider.GetRequiredService().CreateLogger(); - var toolLoaderOptions = Microsoft.Extensions.Options.Options.Create(options); + var toolLoaderOptions = ExtensionsOptions.Options.Create(options); return (new ServerToolLoader(discoveryStrategy, toolLoaderOptions, logger), discoveryStrategy); } diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/SingleProxyToolLoaderTests.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/SingleProxyToolLoaderTests.cs index 8243be19f8..57efad62a1 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/SingleProxyToolLoaderTests.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/SingleProxyToolLoaderTests.cs @@ -15,16 +15,18 @@ using Microsoft.Mcp.Core.Helpers; using ModelContextProtocol.Client; using ModelContextProtocol.Protocol; +using ModelContextProtocol.Server; using NSubstitute; using Xunit; +using ExtensionsOptions = Microsoft.Extensions.Options; namespace Azure.Mcp.Core.Tests.Areas.Server.Commands.ToolLoading; public class SingleProxyToolLoaderTests { - private static Microsoft.Extensions.Options.IOptions CreateServerConfigurationOptions() + private static ExtensionsOptions.IOptions CreateServerConfigurationOptions() { - return Microsoft.Extensions.Options.Options.Create(new McpServerConfiguration + return ExtensionsOptions.Options.Create(new McpServerConfiguration { Name = "Azure.Mcp.Server", ShortName = "azure", @@ -37,9 +39,9 @@ private static Microsoft.Extensions.Options.IOptions Cre private static RegistryDiscoveryStrategy CreateStrategy(ServerStartOptions options, ILogger logger) { - var serviceOptions = Microsoft.Extensions.Options.Options.Create(options ?? new ServerStartOptions()); + var serviceOptions = ExtensionsOptions.Options.Create(options ?? new ServerStartOptions()); var httpClientFactory = Substitute.For(); - var registryRoot = RegistryServerHelper.GetRegistryRoot(typeof(Azure.Mcp.Server.Program).Assembly, "Azure.Mcp.Server.Resources.registry.json"); + var registryRoot = RegistryServerHelper.GetRegistryRoot(typeof(Mcp.Server.Program).Assembly, "Azure.Mcp.Server.Resources.registry.json"); return new RegistryDiscoveryStrategy(serviceOptions, logger, httpClientFactory, registryRoot!); } @@ -51,7 +53,7 @@ private static (SingleProxyToolLoader toolLoader, IMcpDiscoveryStrategy discover if (useRealDiscovery) { - var options = Microsoft.Extensions.Options.Options.Create(new ServerStartOptions()); + var options = ExtensionsOptions.Options.Create(new ServerStartOptions()); var commandGroupLogger = serviceProvider.GetRequiredService>(); var commandGroupDiscoveryStrategy = new CommandGroupDiscoveryStrategy( CommandFactoryHelpers.CreateCommandFactory(serviceProvider), @@ -65,32 +67,32 @@ private static (SingleProxyToolLoader toolLoader, IMcpDiscoveryStrategy discover commandGroupDiscoveryStrategy, registryDiscoveryStrategy ], compositeLogger); - var toolLoader = new SingleProxyToolLoader(compositeDiscoveryStrategy, logger, Microsoft.Extensions.Options.Options.Create(toolLoaderOptions ?? new ToolLoaderOptions()), CreateServerConfigurationOptions()); + var toolLoader = new SingleProxyToolLoader(compositeDiscoveryStrategy, logger, ExtensionsOptions.Options.Create(toolLoaderOptions ?? new()), CreateServerConfigurationOptions()); return (toolLoader, compositeDiscoveryStrategy); } else { var mockDiscoveryStrategy = Substitute.For(); - var toolLoader = new SingleProxyToolLoader(mockDiscoveryStrategy, logger, Microsoft.Extensions.Options.Options.Create(toolLoaderOptions ?? new ToolLoaderOptions()), CreateServerConfigurationOptions()); + var toolLoader = new SingleProxyToolLoader(mockDiscoveryStrategy, logger, ExtensionsOptions.Options.Create(toolLoaderOptions ?? new()), CreateServerConfigurationOptions()); return (toolLoader, mockDiscoveryStrategy); } } - private static ModelContextProtocol.Server.RequestContext CreateListToolsRequest() + private static RequestContext CreateListToolsRequest() { - var mockServer = Substitute.For(); - return new ModelContextProtocol.Server.RequestContext(mockServer, new() { Method = RequestMethods.ToolsList }) + var mockServer = Substitute.For(); + return new RequestContext(mockServer, new() { Method = RequestMethods.ToolsList }) { Params = new ListToolsRequestParams() }; } - private static ModelContextProtocol.Server.RequestContext CreateCallToolRequest( + private static RequestContext CreateCallToolRequest( string toolName = "azure", Dictionary? arguments = null) { - var mockServer = Substitute.For(); - return new ModelContextProtocol.Server.RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) + var mockServer = Substitute.For(); + return new RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }) { Params = new CallToolRequestParams { @@ -250,8 +252,8 @@ public async Task CallToolHandler_WithNullParams_ReturnsGuidanceMessage() { // Arrange var (toolLoader, _) = CreateToolLoader(useRealDiscovery: true); - var mockServer = Substitute.For(); - var request = new ModelContextProtocol.Server.RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }, null!); + var mockServer = Substitute.For(); + var request = new RequestContext(mockServer, new() { Method = RequestMethods.ToolsCall }, null!); // Act var result = await toolLoader.CallToolHandler(request, TestContext.Current.CancellationToken); @@ -295,7 +297,7 @@ public async Task GetChildToolList_WithReadOnlyOption_ReturnsOnlyReadOnlyTools() var discoveryStrategy = Substitute.For(); discoveryStrategy.GetOrCreateClientAsync("storage", Arg.Any(), TestContext.Current.CancellationToken) .Returns(mcpClient); - var toolLoaderOptions = Microsoft.Extensions.Options.Options.Create(new ToolLoaderOptions() { ReadOnly = true }); + var toolLoaderOptions = ExtensionsOptions.Options.Create(new ToolLoaderOptions() { ReadOnly = true }); var logger = Substitute.For>(); var toolLoader = new SingleProxyToolLoader(discoveryStrategy, logger, toolLoaderOptions, CreateServerConfigurationOptions()); @@ -338,7 +340,7 @@ public async Task GetChildToolList_WithIsHttpOption_DoesNotReturnLocalRequiredTo var discoveryStrategy = Substitute.For(); discoveryStrategy.GetOrCreateClientAsync("storage", Arg.Any(), TestContext.Current.CancellationToken) .Returns(mcpClient); - var toolLoaderOptions = Microsoft.Extensions.Options.Options.Create(new ToolLoaderOptions() { IsHttpMode = true }); + var toolLoaderOptions = ExtensionsOptions.Options.Create(new ToolLoaderOptions() { IsHttpMode = true }); var logger = Substitute.For>(); var toolLoader = new SingleProxyToolLoader(discoveryStrategy, logger, toolLoaderOptions, CreateServerConfigurationOptions()); @@ -391,7 +393,7 @@ public void SingleProxyToolLoader_Constructor_ThrowsOnNullArguments() // Arrange var logger = Substitute.For>(); var discoveryStrategy = Substitute.For(); - var toolLoaderOptions = Microsoft.Extensions.Options.Options.Create(new ToolLoaderOptions()); + var toolLoaderOptions = ExtensionsOptions.Options.Create(new ToolLoaderOptions()); var serverConfigurationOptions = CreateServerConfigurationOptions(); // Act & Assert @@ -411,12 +413,12 @@ private static SingleProxyToolLoader CreateToolLoaderWithMockClient( .Build(); var logger = Substitute.For>(); - var options = Microsoft.Extensions.Options.Options.Create(toolLoaderOptions); + var options = ExtensionsOptions.Options.Create(toolLoaderOptions); return new SingleProxyToolLoader(discoveryStrategy, logger, options, CreateServerConfigurationOptions()); } - private static ModelContextProtocol.Server.RequestContext CreateCallToolRequestWithToolAndCommand( + private static RequestContext CreateCallToolRequestWithToolAndCommand( string tool, string command) { var arguments = new Dictionary @@ -426,7 +428,7 @@ private static ModelContextProtocol.Server.RequestContext ["command"] = JsonDocument.Parse($"\"{command}\"").RootElement, }; - var mockServer = Substitute.For(); + var mockServer = Substitute.For(); return new(mockServer, new() { Method = RequestMethods.ToolsCall }, new CallToolRequestParams { Name = "azure", diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Helpers/MockMcpClientBuilder.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Helpers/MockMcpClientBuilder.cs index 5bf6256f23..b9a6e8fc25 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Helpers/MockMcpClientBuilder.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Helpers/MockMcpClientBuilder.cs @@ -1,14 +1,13 @@ -#pragma warning disable MCP9003 // Obsolete RequestContext constructor - migrating during Phase 1 -#pragma warning disable MCP9005 // Deprecated Sampling/Logging APIs - backward compat during Phase 1 // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#pragma warning disable MCP9003 // Obsolete RequestContext constructor - migrating during Phase 1 +#pragma warning disable MCP9005 // Deprecated Sampling/Logging APIs - backward compat during Phase 1 + using System.Text.Json; using Microsoft.Mcp.Core.Areas.Server; using ModelContextProtocol.Client; using ModelContextProtocol.Protocol; -using NSubstitute; -using Xunit; namespace Azure.Mcp.Core.Tests.Areas.Server.Helpers; diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Helpers/MockMcpDiscoveryStrategyBuilder.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Helpers/MockMcpDiscoveryStrategyBuilder.cs index d9229b6171..7898bbf520 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Helpers/MockMcpDiscoveryStrategyBuilder.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/Helpers/MockMcpDiscoveryStrategyBuilder.cs @@ -25,6 +25,7 @@ public sealed class MockMcpDiscoveryStrategyBuilder /// The display name of the server. If null, uses the serverId. /// The description of the server. If null, uses a default description. /// The mock client to return for this server. + /// Optional tool prefix for the server. /// The current instance for method chaining. public MockMcpDiscoveryStrategyBuilder AddServer(string serverId, string? serverName = null, string? description = null, McpClient? client = null, string? toolPrefix = null) { @@ -64,6 +65,7 @@ public MockMcpDiscoveryStrategyBuilder AddServer(string serverId, string? server /// The display name of the server. If null, uses the serverId. /// The description of the server. If null, uses a default description. /// The MockMcpClientBuilder to use for creating the client. + /// Optional tool prefix for the server. /// The current instance for method chaining. public MockMcpDiscoveryStrategyBuilder AddServer(string serverId, string? serverName, string? description, MockMcpClientBuilder clientBuilder, string? toolPrefix = null) { diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/ServiceStartCommandTests.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/ServiceStartCommandTests.cs index c87503d98d..028ea0ec3e 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/ServiceStartCommandTests.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Server/ServiceStartCommandTests.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Net; using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Cors.Infrastructure; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -14,6 +15,7 @@ using Microsoft.Mcp.Core.Services.Telemetry; using NSubstitute; using Xunit; +using ExtensionsOptions = Microsoft.Extensions.Options; namespace Azure.Mcp.Core.Tests.Areas.Server; @@ -799,11 +801,11 @@ public void ConfigureCors_DevelopmentWithAuthDisabled_RestrictsToLocalhost() // Assert var serviceProvider = services.BuildServiceProvider(); - var corsService = serviceProvider.GetService(); + var corsService = serviceProvider.GetService(); Assert.NotNull(corsService); // Verify policy was registered - var corsOptions = serviceProvider.GetRequiredService>(); + var corsOptions = serviceProvider.GetRequiredService>(); Assert.NotNull(corsOptions.Value); } finally @@ -845,7 +847,7 @@ public void ConfigureCors_DevelopmentWithAuthDisabled_ValidatesOrigins(string or ServerStartCommand.ConfigureCors(services, environment, serverOptions); var serviceProvider = services.BuildServiceProvider(); - var corsOptions = serviceProvider.GetRequiredService>(); + var corsOptions = serviceProvider.GetRequiredService>(); var policy = corsOptions.Value.GetPolicy("McpCorsPolicy"); Assert.NotNull(policy); @@ -892,7 +894,7 @@ public void ConfigureCors_DevelopmentWithAuthEnabled_AllowsAllOrigins() ServerStartCommand.ConfigureCors(services, environment, serverOptions); var serviceProvider = services.BuildServiceProvider(); - var corsOptions = serviceProvider.GetRequiredService>(); + var corsOptions = serviceProvider.GetRequiredService>(); var policy = corsOptions.Value.GetPolicy("McpCorsPolicy"); Assert.NotNull(policy); @@ -932,7 +934,7 @@ public void ConfigureCors_ProductionWithAuthDisabled_AllowsAllOrigins() ServerStartCommand.ConfigureCors(services, environment, serverOptions); var serviceProvider = services.BuildServiceProvider(); - var corsOptions = serviceProvider.GetRequiredService>(); + var corsOptions = serviceProvider.GetRequiredService>(); var policy = corsOptions.Value.GetPolicy("McpCorsPolicy"); Assert.NotNull(policy); @@ -972,7 +974,7 @@ public void ConfigureCors_ProductionWithAuthEnabled_AllowsAllOrigins() ServerStartCommand.ConfigureCors(services, environment, serverOptions); var serviceProvider = services.BuildServiceProvider(); - var corsOptions = serviceProvider.GetRequiredService>(); + var corsOptions = serviceProvider.GetRequiredService>(); var policy = corsOptions.Value.GetPolicy("McpCorsPolicy"); Assert.NotNull(policy); @@ -1012,7 +1014,7 @@ public void ConfigureCors_NoEnvironmentSet_DefaultsToAllowAllOrigins() ServerStartCommand.ConfigureCors(services, environment, serverOptions); var serviceProvider = services.BuildServiceProvider(); - var corsOptions = serviceProvider.GetRequiredService>(); + var corsOptions = serviceProvider.GetRequiredService>(); var policy = corsOptions.Value.GetPolicy("McpCorsPolicy"); Assert.NotNull(policy); @@ -1051,7 +1053,7 @@ public void ConfigureCors_DevelopmentWithAuthDisabled_AllowsAnyMethodAndHeader() ServerStartCommand.ConfigureCors(services, environment, serverOptions); var serviceProvider = services.BuildServiceProvider(); - var corsOptions = serviceProvider.GetRequiredService>(); + var corsOptions = serviceProvider.GetRequiredService>(); var policy = corsOptions.Value.GetPolicy("McpCorsPolicy"); Assert.NotNull(policy); diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Tools/ToolsListCommandTests.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Tools/ToolsListCommandTests.cs index d03abe1622..b6caae6a08 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Tools/ToolsListCommandTests.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Areas/Tools/ToolsListCommandTests.cs @@ -16,6 +16,7 @@ using Microsoft.Mcp.Core.Services.Telemetry; using NSubstitute; using Xunit; +using ExtensionsOptions = Microsoft.Extensions.Options; namespace Azure.Mcp.Core.Tests.Areas.Tools; @@ -337,7 +338,7 @@ public async Task ExecuteAsync_WithEmptyCommandFactory_ReturnsEmptyResults() var logger = tempServiceProvider.GetRequiredService>(); var telemetryService = Substitute.For(); var emptyAreaSetups = Array.Empty(); - var configurationOptions = Microsoft.Extensions.Options.Options.Create(new McpServerConfiguration + var configurationOptions = ExtensionsOptions.Options.Create(new McpServerConfiguration { Name = "Test Server", ShortName = "test", diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/AssemblyAttributes.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/AssemblyAttributes.cs index 69da1d7967..9068d23bfb 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/AssemblyAttributes.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/AssemblyAttributes.cs @@ -1,2 +1,5 @@ -[assembly: Microsoft.Mcp.Tests.Helpers.ClearEnvironmentVariablesBeforeTest] +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +[assembly: Microsoft.Mcp.Tests.Helpers.ClearEnvironmentVariablesBeforeTest] [assembly: Xunit.CollectionBehavior(Xunit.CollectionBehavior.CollectionPerAssembly)] diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Client/MockClientTests.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Client/MockClientTests.cs index 58fd2d43d2..30f3de2574 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Client/MockClientTests.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Client/MockClientTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System.Text.Json; diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Commands/CommandFactoryTests.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Commands/CommandFactoryTests.cs index d77b98a4c2..244dcb584b 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Commands/CommandFactoryTests.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Commands/CommandFactoryTests.cs @@ -5,13 +5,13 @@ using System.Text.Json; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; using Microsoft.Mcp.Core.Areas; using Microsoft.Mcp.Core.Commands; using Microsoft.Mcp.Core.Configuration; using Microsoft.Mcp.Core.Services.Telemetry; using NSubstitute; using Xunit; +using ExtensionsOptions = Microsoft.Extensions.Options; namespace Azure.Mcp.Core.Tests.Commands; @@ -26,7 +26,7 @@ public class CommandFactoryTests private readonly ILogger _logger; private readonly ITelemetryService _telemetryService; private readonly McpServerConfiguration _serverConfiguration; - private readonly IOptions _configurationOptions; + private readonly ExtensionsOptions.IOptions _configurationOptions; public CommandFactoryTests() { @@ -46,7 +46,7 @@ public CommandFactoryTests() _serviceProvider = services.BuildServiceProvider(); _logger = Substitute.For>(); _telemetryService = Substitute.For(); - _configurationOptions = Microsoft.Extensions.Options.Options.Create(_serverConfiguration); + _configurationOptions = ExtensionsOptions.Options.Create(_serverConfiguration); } [Fact] diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Extensions/McpServerElicitationExtensionsTests.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Extensions/McpServerElicitationExtensionsTests.cs index d3c44ec24b..23b4d1f18d 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Extensions/McpServerElicitationExtensionsTests.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Extensions/McpServerElicitationExtensionsTests.cs @@ -72,7 +72,7 @@ public void ShouldTriggerElicitation_WithJsonObjectMetadata_ReturnsExpectedResul JsonObject metadata = [new(McpHelper.SecretHintMetaKey, secretValue)]; // Act - var result = server.ShouldTriggerElicitation("tool1", metadata); + var result = server.ShouldTriggerElicitation(metadata); // Assert Assert.Equal(expected, result); @@ -85,7 +85,7 @@ public void ShouldTriggerElicitation_WithNullMetadata_ReturnsFalse() var server = CreateMockServer(); // Act - var result = server.ShouldTriggerElicitation("tool1", null); + var result = server.ShouldTriggerElicitation(null); // Assert Assert.False(result); @@ -102,7 +102,7 @@ public void ShouldTriggerElicitation_WithNonJsonObjectMetadata_ReturnsFalse() var metadata = new Dictionary { { "SecretHint", true } }; // Act - var result = server.ShouldTriggerElicitation("tool1", metadata); + var result = server.ShouldTriggerElicitation(metadata); // Assert Assert.False(result); @@ -118,7 +118,7 @@ public void ShouldTriggerElicitation_WithNonSupportingClient_ReturnsFalse() JsonObject metadata = [new(McpHelper.SecretHintMetaKey, true)]; // Act - var result = server.ShouldTriggerElicitation("tool1", metadata); + var result = server.ShouldTriggerElicitation(metadata); // Assert Assert.False(result); @@ -138,7 +138,7 @@ public void ShouldTriggerElicitation_WithMissingSecretProperty_ReturnsFalse() }; // Act - var result = server.ShouldTriggerElicitation("tool1", metadata); + var result = server.ShouldTriggerElicitation(metadata); // Assert Assert.False(result); @@ -155,7 +155,7 @@ public void ShouldTriggerElicitation_WithSecretPropertyButInvalidValue_ReturnsFa JsonObject metadata = [new(McpHelper.SecretHintMetaKey, "not_a_boolean")]; // Act - var result = server.ShouldTriggerElicitation("tool1", metadata); + var result = server.ShouldTriggerElicitation(metadata); // Assert Assert.False(result); @@ -337,7 +337,7 @@ public void ShouldTriggerElicitation_WithDestructiveHint_ReturnsExpectedResult(b }; // Act - var result = server.ShouldTriggerElicitation("tool1", metadata); + var result = server.ShouldTriggerElicitation(metadata); // Assert Assert.Equal(expected, result); @@ -357,7 +357,7 @@ public void ShouldTriggerElicitation_WithDestructiveHintButInvalidValue_ReturnsF }; // Act - var result = server.ShouldTriggerElicitation("tool1", metadata); + var result = server.ShouldTriggerElicitation(metadata); // Assert Assert.False(result); @@ -377,7 +377,7 @@ public void ShouldTriggerElicitation_WithMissingDestructiveHint_ReturnsFalse() }; // Act - var result = server.ShouldTriggerElicitation("tool1", metadata); + var result = server.ShouldTriggerElicitation(metadata); // Assert Assert.False(result); @@ -398,7 +398,7 @@ public void ShouldTriggerElicitation_WithBothSecretAndDestructiveTrue_ReturnsTru ]; // Act - var result = server.ShouldTriggerElicitation("tool1", metadata); + var result = server.ShouldTriggerElicitation(metadata); // Assert Assert.True(result); @@ -419,7 +419,7 @@ public void ShouldTriggerElicitation_WithSecretFalseAndDestructiveTrue_ReturnsTr ]; // Act - var result = server.ShouldTriggerElicitation("tool1", metadata); + var result = server.ShouldTriggerElicitation(metadata); // Assert Assert.True(result); @@ -440,7 +440,7 @@ public void ShouldTriggerElicitation_WithSecretFalseAndDestructiveFalse_ReturnsF ]; // Act - var result = server.ShouldTriggerElicitation("tool1", metadata); + var result = server.ShouldTriggerElicitation(metadata); // Assert Assert.False(result); @@ -459,7 +459,7 @@ public void ShouldTriggerElicitation_WithDestructiveHintAndNonSupportingClient_R }; // Act - var result = server.ShouldTriggerElicitation("tool1", metadata); + var result = server.ShouldTriggerElicitation(metadata); // Assert Assert.False(result); @@ -509,7 +509,7 @@ public void ShouldTriggerElicitation_WithUrlCapabilityOnly_SecretMetadataControl JsonObject metadata = [new(McpHelper.SecretHintMetaKey, secretValue)]; // Act - var result = server.ShouldTriggerElicitation("tool1", metadata); + var result = server.ShouldTriggerElicitation(metadata); // Assert Assert.Equal(expected, result); @@ -535,7 +535,7 @@ public void ShouldTriggerElicitation_WithUrlCapabilityAndMissingSecret_ReturnsFa }; // Act - var result = server.ShouldTriggerElicitation("tool1", metadata); + var result = server.ShouldTriggerElicitation(metadata); // Assert Assert.False(result); @@ -583,7 +583,7 @@ public void ShouldTriggerElicitation_WithExplicitFormCapabilityAndSecretMetadata JsonObject metadata = [new(McpHelper.SecretHintMetaKey, true)]; // Act - var result = server.ShouldTriggerElicitation("tool1", metadata); + var result = server.ShouldTriggerElicitation(metadata); // Assert Assert.True(result); @@ -606,7 +606,7 @@ public void ShouldTriggerElicitation_WithExplicitFormCapabilityAndSecretFalse_Re JsonObject metadata = [new(McpHelper.SecretHintMetaKey, false)]; // Act - var result = server.ShouldTriggerElicitation("tool1", metadata); + var result = server.ShouldTriggerElicitation(metadata); // Assert Assert.False(result); @@ -632,7 +632,7 @@ public void ShouldTriggerElicitation_WithExplicitFormCapabilityAndNestedSecret_R }; // Act - var result = server.ShouldTriggerElicitation("tool1", metadata); + var result = server.ShouldTriggerElicitation(metadata); // Assert Assert.False(result); diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/RecordingFramework/RecordedCommandTestHarness.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/RecordingFramework/RecordedCommandTestHarness.cs index 46d5b9a506..ae51e665a0 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/RecordingFramework/RecordedCommandTestHarness.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/RecordingFramework/RecordedCommandTestHarness.cs @@ -13,6 +13,7 @@ namespace Azure.Mcp.Core.Tests.RecordingFramework; /// /// /// +/// internal sealed class RecordedCommandTestHarness(ITestOutputHelper output, TestProxyFixture fixture, LiveServerFixture liveServerFixture) : RecordedCommandTestsBase(output, fixture, liveServerFixture) { diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/RegistryDiscoveryStrategyHelper.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/RegistryDiscoveryStrategyHelper.cs index 88d3328dce..bdd70b95ca 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/RegistryDiscoveryStrategyHelper.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/RegistryDiscoveryStrategyHelper.cs @@ -6,6 +6,7 @@ using Microsoft.Mcp.Core.Areas.Server.Options; using Microsoft.Mcp.Core.Helpers; using NSubstitute; +using ExtensionsOptions = Microsoft.Extensions.Options; namespace Azure.Mcp.Core.Tests; @@ -13,7 +14,7 @@ public class RegistryDiscoveryStrategyHelper { public static RegistryDiscoveryStrategy CreateStrategy(ServerStartOptions? options = null, ILogger? logger = null) { - var serviceOptions = Microsoft.Extensions.Options.Options.Create(options ?? new ServerStartOptions()); + var serviceOptions = ExtensionsOptions.Options.Create(options ?? new ServerStartOptions()); logger ??= Substitute.For>(); var httpClientFactory = Substitute.For(); var registryRoot = RegistryServerHelper.GetRegistryRoot(typeof(Server.Program).Assembly, "Azure.Mcp.Server.Resources.registry.json"); diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Services/Azure/Authentication/AzureCloudConfigurationTests.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Services/Azure/Authentication/AzureCloudConfigurationTests.cs index 3cda472801..681fd5c9d9 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Services/Azure/Authentication/AzureCloudConfigurationTests.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.Tests/Services/Azure/Authentication/AzureCloudConfigurationTests.cs @@ -6,6 +6,7 @@ using Microsoft.Mcp.Core.Areas.Server.Options; using Microsoft.Mcp.Core.Services.Azure.Authentication; using Xunit; +using ExtensionsOptions = Microsoft.Extensions.Options; namespace Azure.Mcp.Core.Tests.Services.Azure.Authentication; @@ -129,7 +130,7 @@ public void ParseCloudValue_NoConfiguration_ReturnsDefaultPublicCloud() public void ConfigurationPriority_CommandLineOverridesAppsettings() { // Arrange - ServiceStartOptions takes priority - var options = Microsoft.Extensions.Options.Options.Create(new ServerStartOptions { Cloud = "AzureChinaCloud" }); + var options = ExtensionsOptions.Options.Create(new ServerStartOptions { Cloud = "AzureChinaCloud" }); var config = new ConfigurationBuilder() .AddInMemoryCollection(new Dictionary { ["cloud"] = "AzureUSGovernment" }) .Build(); @@ -292,7 +293,7 @@ public void Configuration_SupportsAzureCloudKey() public void ConfigurationPriority_FullPriorityChain() { // Arrange - Set up multiple configuration sources - var options = Microsoft.Extensions.Options.Options.Create(new ServerStartOptions { Cloud = "AzureChinaCloud" }); + var options = ExtensionsOptions.Options.Create(new ServerStartOptions { Cloud = "AzureChinaCloud" }); var config = new ConfigurationBuilder() .AddInMemoryCollection(new Dictionary { diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Tests/Commands/SubscriptionCommandUnitTestsBase.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Tests/Commands/SubscriptionCommandUnitTestsBase.cs index b19a265b70..56303c8951 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Tests/Commands/SubscriptionCommandUnitTestsBase.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Tests/Commands/SubscriptionCommandUnitTestsBase.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + using Azure.Mcp.Core.Services.Azure.Subscription; using Microsoft.Extensions.DependencyInjection; using Microsoft.Mcp.Core.Commands; diff --git a/core/Microsoft.Mcp.Core/src/AccessTokenHandler.cs b/core/Microsoft.Mcp.Core/src/AccessTokenHandler.cs index 5b6cda28d2..2ce6ba821e 100644 --- a/core/Microsoft.Mcp.Core/src/AccessTokenHandler.cs +++ b/core/Microsoft.Mcp.Core/src/AccessTokenHandler.cs @@ -5,7 +5,7 @@ using Azure.Core; using Microsoft.Mcp.Core.Services.Azure.Authentication; -namespace Azure.Mcp.Core; +namespace Microsoft.Mcp.Core; /// /// that adds a Bearer access token to each outgoing request. @@ -32,8 +32,8 @@ public AccessTokenHandler(TokenCredential credential, string[] oauthScopes) /// Sends an HTTP request with a Bearer access token fetched using the embedded . /// This method will overwrite the Authorization header if it already exist on the request. /// - /// - /// + /// The HTTP request message to send. + /// The token to monitor for cancellation requests. protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { TokenCredential credential = _credential diff --git a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/ConsolidatedToolDiscoveryStrategy.cs b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/ConsolidatedToolDiscoveryStrategy.cs index 96f827191c..0978501632 100644 --- a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/ConsolidatedToolDiscoveryStrategy.cs +++ b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/ConsolidatedToolDiscoveryStrategy.cs @@ -17,6 +17,8 @@ namespace Microsoft.Mcp.Core.Areas.Server.Commands.Discovery; /// This strategy converts Azure CLI command groups into MCP servers, allowing them to be accessed via the MCP protocol. /// /// The command factory used to access available command groups. +/// The service provider for dependency injection. +/// The provider for consolidated tool definitions. /// Options for configuring the service behavior. /// Configuration options for the Azure MCP server. /// Logger instance for this discovery strategy. diff --git a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/ConsolidatedToolServerProvider.cs b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/ConsolidatedToolServerProvider.cs index a4738529ab..23e68281ff 100644 --- a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/ConsolidatedToolServerProvider.cs +++ b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/ConsolidatedToolServerProvider.cs @@ -62,7 +62,7 @@ public async Task CreateClientAsync(McpClientOptions clientOptions, C /// /// Builds the command-line arguments for the MCP server process. - /// Pattern: server start --mode all (--tool )+ [--read-only] + /// Pattern: server start --mode all (--tool <qualifiedCommand>)+ [--read-only] /// internal string[] BuildArguments() { diff --git a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/IDiscoveryStrategy.cs b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/IDiscoveryStrategy.cs index 3c5a32f904..7418dc0178 100644 --- a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/IDiscoveryStrategy.cs +++ b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/IDiscoveryStrategy.cs @@ -10,7 +10,7 @@ public interface IMcpDiscoveryStrategy : IAsyncDisposable /// /// Discovers available MCP servers via this strategy. /// - /// A cancellation token. + /// The token to monitor for cancellation requests. /// A collection of discovered MCP servers. Task> DiscoverServersAsync(CancellationToken cancellationToken); @@ -18,7 +18,7 @@ public interface IMcpDiscoveryStrategy : IAsyncDisposable /// Finds a server provider by name. /// /// The name of the server to find. - /// A cancellation token. + /// The token to monitor for cancellation requests. /// The server provider if found. /// Thrown when no server with the specified name is found. Task FindServerProviderAsync(string name, CancellationToken cancellationToken); @@ -28,7 +28,7 @@ public interface IMcpDiscoveryStrategy : IAsyncDisposable /// /// The name of the server to get a client for. /// Optional client configuration options. If null, default options are used. - /// A cancellation token. + /// The token to monitor for cancellation requests. /// An MCP client that can communicate with the specified server. /// Thrown when no server with the specified name is found. /// Thrown when the name parameter is null. diff --git a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/IMcpServerProvider.cs b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/IMcpServerProvider.cs index 6fe6dcfaae..c29a5aa82b 100644 --- a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/IMcpServerProvider.cs +++ b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/IMcpServerProvider.cs @@ -20,7 +20,7 @@ public interface IMcpServerProvider /// Creates an MCP client that can communicate with this server. /// /// Options to configure the client behavior. - /// A token to cancel the operation. + /// The token to monitor for cancellation requests. /// A configured MCP client ready for use. /// Thrown when the server configuration doesn't specify a valid transport type (missing URL or stdio configuration). /// Thrown when the server configuration is valid but client creation fails (e.g., missing command for stdio transport, dependency issues, or external process failures). diff --git a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/RegistryDiscoveryStrategy.cs b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/RegistryDiscoveryStrategy.cs index 90e472d980..b7f485b704 100644 --- a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/RegistryDiscoveryStrategy.cs +++ b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/RegistryDiscoveryStrategy.cs @@ -22,19 +22,19 @@ public sealed class RegistryDiscoveryStrategy(IOptions optio private readonly IHttpClientFactory _httpClientFactory = httpClientFactory; /// - public override async Task> DiscoverServersAsync(CancellationToken cancellationToken) + public override Task> DiscoverServersAsync(CancellationToken cancellationToken) { if (registryRoot?.Servers == null) { - return []; + return Task.FromResult>([]); } - return registryRoot + return Task.FromResult(registryRoot .Servers .Where(s => _options.Value.Namespace == null || _options.Value.Namespace.Length == 0 || _options.Value.Namespace.Contains(s.Key, StringComparer.OrdinalIgnoreCase)) .Select(s => new RegistryServerProvider(s.Key, s.Value, _httpClientFactory)) - .Cast(); + .Cast()); } } diff --git a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/RegistryServerProvider.cs b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/RegistryServerProvider.cs index bc91ae418d..57f710529e 100644 --- a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/RegistryServerProvider.cs +++ b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/RegistryServerProvider.cs @@ -32,7 +32,6 @@ namespace Microsoft.Mcp.Core.Areas.Server.Commands.Discovery; /// The unique identifier for the server. /// Configuration information for the server. /// Factory for creating HTTP clients. -/// The token credential provider for OAuth authentication. public sealed class RegistryServerProvider(string id, RegistryServerInfo serverInfo, IHttpClientFactory httpClientFactory) : IMcpServerProvider { private readonly string _id = id; @@ -178,7 +177,7 @@ This tool may require dependencies that are not installed. /// Arguments to pass to get version output. /// The minimum required version string (e.g., "1.20.0"). /// Regex pattern with a capture group for the version. Defaults to semver pattern. - /// A token to cancel the operation. + /// The token to monitor for cancellation requests. /// An error message if the check fails, or null if the command meets requirements. internal static async Task CheckCommandVersionAsync( string command, IList versionArgs, string minVersion, @@ -284,7 +283,7 @@ This tool may require dependencies that are not installed. /// Creates an MCP client that communicates with the server using Server-Sent Events (SSE). /// /// Options to configure the client behavior. - /// A token to cancel the operation. + /// The token to monitor for cancellation requests. /// A configured MCP client using SSE transport. /// /// For servers configured with OAuth scopes, this method validates MCP 2026-07-28 @@ -326,7 +325,7 @@ private async Task CreateHttpClientAsync(McpClientOptions clientOptio /// Creates an MCP client that communicates with the server using stdio (standard input/output). /// /// Options to configure the client behavior. - /// A token to cancel the operation. + /// The token to monitor for cancellation requests. /// A configured MCP client using stdio transport. /// Thrown when the server configuration doesn't specify a valid command for stdio transport. private async Task CreateStdioClientAsync(McpClientOptions clientOptions, CancellationToken cancellationToken) diff --git a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/OptionSchemaGenerator.cs b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/OptionSchemaGenerator.cs index 92472e285a..dc960f62d1 100644 --- a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/OptionSchemaGenerator.cs +++ b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/OptionSchemaGenerator.cs @@ -24,7 +24,7 @@ namespace Microsoft.Mcp.Core.Areas.Server.Commands; /// runtime values, so this helper has to use /// and /// , both annotated. The -/// attributes below are used +/// attributes below are used /// because this class uses the exporter only to read schema metadata (no /// (de)serialization, no enum materialization), and because the actual option /// types in use are primitives, enums, , nullables of those, @@ -33,9 +33,9 @@ namespace Microsoft.Mcp.Core.Areas.Server.Commands; /// internal static class OptionSchemaGenerator { - private static readonly JsonSerializerOptions SchemaOptions = CreateSchemaOptions(); + private static readonly JsonSerializerOptions s_schemaOptions = CreateSchemaOptions(); - private static readonly JsonSchemaExporterOptions ExporterOptions = new() + private static readonly JsonSchemaExporterOptions s_exporterOptions = new() { TreatNullObliviousAsNonNullable = true, }; @@ -67,7 +67,7 @@ public static JsonNode CreatePropertySchema(Type optionType, string? description { ArgumentNullException.ThrowIfNull(optionType); - var schema = JsonSchemaExporter.GetJsonSchemaAsNode(SchemaOptions, optionType, ExporterOptions); + var schema = JsonSchemaExporter.GetJsonSchemaAsNode(s_schemaOptions, optionType, s_exporterOptions); if (schema is JsonObject schemaObject && !string.IsNullOrWhiteSpace(description)) { diff --git a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/PluginTelemetryCommand.cs b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/PluginTelemetryCommand.cs index d264ed4d94..0bf6bc0c0e 100644 --- a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/PluginTelemetryCommand.cs +++ b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/PluginTelemetryCommand.cs @@ -170,7 +170,7 @@ internal static string StripClientPrefix(string toolName) /// /// The command execution context containing the response object. /// The parsed command-line arguments containing telemetry event data. - /// Cancellation token for the operation. + /// The token to monitor for cancellation requests. /// A task containing the command response with status and any error messages. public override async Task ExecuteAsync(CommandContext context, PluginTelemetryOptions options, CancellationToken cancellationToken) { diff --git a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Runtime/IMcpRuntime.cs b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Runtime/IMcpRuntime.cs index 054ea3fd11..2043be7d75 100644 --- a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Runtime/IMcpRuntime.cs +++ b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Runtime/IMcpRuntime.cs @@ -16,7 +16,7 @@ public interface IMcpRuntime : IAsyncDisposable /// Handles requests to list all tools available in the MCP server. /// /// The request context containing metadata and parameters. - /// A token to monitor for cancellation requests. + /// The token to monitor for cancellation requests. /// A result containing the list of available tools. ValueTask ListToolsHandler(RequestContext request, CancellationToken cancellationToken); @@ -24,7 +24,7 @@ public interface IMcpRuntime : IAsyncDisposable /// Handles requests to call a specific tool with the provided parameters. /// /// The request context containing the tool name and parameters. - /// A token to monitor for cancellation requests. + /// The token to monitor for cancellation requests. /// A result containing the output of the tool invocation. ValueTask CallToolHandler(RequestContext request, CancellationToken cancellationToken); } diff --git a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Runtime/McpRuntime.cs b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Runtime/McpRuntime.cs index 9e894a4be7..bbf94daed1 100644 --- a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Runtime/McpRuntime.cs +++ b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Runtime/McpRuntime.cs @@ -34,6 +34,7 @@ public sealed class McpRuntime : IMcpRuntime /// /// The tool loader responsible for discovering and loading tools. /// Configuration options for the MCP server. + /// Telemetry service for logging and monitoring. /// Logger for runtime operations. /// Thrown if any required dependencies are null. public McpRuntime( @@ -56,7 +57,7 @@ public McpRuntime( /// Delegates tool invocation requests to the configured tool loader. /// /// The request context containing the tool name and parameters. - /// A token to monitor for cancellation requests. + /// The token to monitor for cancellation requests. /// A result containing the output of the tool invocation. public async ValueTask CallToolHandler(RequestContext request, CancellationToken cancellationToken) { @@ -100,7 +101,7 @@ public async ValueTask CallToolHandler(RequestContext /// The request context containing metadata and parameters. - /// A token to monitor for cancellation requests. + /// The token to monitor for cancellation requests. /// A result containing the list of available tools. public async ValueTask ListToolsHandler(RequestContext request, CancellationToken cancellationToken) { diff --git a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ServerStartCommand.cs b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ServerStartCommand.cs index 8cfeb974f0..f541a478b6 100644 --- a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ServerStartCommand.cs +++ b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ServerStartCommand.cs @@ -125,6 +125,7 @@ private static void ValidateSupportLoggingFolder(ServerStartOptions options, Val /// /// The command execution context. /// The parsed command options. + /// The token to monitor for cancellation requests. /// A command response indicating the result of the operation. public override async Task ExecuteAsync(CommandContext context, ServerStartOptions options, CancellationToken cancellationToken) { diff --git a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ServiceCollectionExtensions.cs b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ServiceCollectionExtensions.cs index 07ec1c3fe9..83e9b3c258 100644 --- a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ServiceCollectionExtensions.cs +++ b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ServiceCollectionExtensions.cs @@ -6,7 +6,6 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; using Microsoft.Mcp.Core.Areas.Server.Commands.Discovery; using Microsoft.Mcp.Core.Areas.Server.Commands.Runtime; using Microsoft.Mcp.Core.Areas.Server.Commands.ServerInstructions; @@ -18,13 +17,10 @@ using Microsoft.Mcp.Core.Helpers; using ModelContextProtocol.Protocol; using ModelContextProtocol.Server; +using ExtensionsOptions = Microsoft.Extensions.Options; namespace Microsoft.Mcp.Core.Areas.Server.Commands; -// This is intentionally placed after the namespace declaration to avoid -// conflicts with Microsoft.Mcp.Core.Areas.Server.Options -using Options = Microsoft.Extensions.Options.Options; - /// /// Extension methods for configuring Azure MCP server services. /// @@ -46,7 +42,7 @@ public static IServiceCollection AddAzureMcpServer(this IServiceCollection servi // Register options for service start services.AddSingleton(serviceStartOptions); - services.AddSingleton(Options.Create(serviceStartOptions)); + services.AddSingleton(ExtensionsOptions.Options.Create(serviceStartOptions)); // Register default tool loader options from service start options var defaultToolLoaderOptions = new ToolLoaderOptions @@ -67,7 +63,7 @@ public static IServiceCollection AddAzureMcpServer(this IServiceCollection servi } services.AddSingleton(defaultToolLoaderOptions); - services.AddSingleton(Options.Create(defaultToolLoaderOptions)); + services.AddSingleton(ExtensionsOptions.Options.Create(defaultToolLoaderOptions)); // Register tool loader strategies services.AddSingleton(); @@ -136,7 +132,7 @@ public static IServiceCollection AddAzureMcpServer(this IServiceCollection servi // ServerToolLoader with RegistryDiscoveryStrategy creates proxy tools for external MCP servers. new ServerToolLoader( sp.GetRequiredService(), - sp.GetRequiredService>(), + sp.GetRequiredService>(), loggerFactory.CreateLogger() ), // NamespaceToolLoader enables direct in-process execution for tools in Azure namespaces @@ -155,7 +151,7 @@ public static IServiceCollection AddAzureMcpServer(this IServiceCollection servi toolLoaders.Add(new CommandFactoryToolLoader( sp.GetRequiredService(), - Options.Create(utilityToolLoaderOptions), + ExtensionsOptions.Options.Create(utilityToolLoaderOptions), loggerFactory.CreateLogger() )); @@ -183,13 +179,13 @@ public static IServiceCollection AddAzureMcpServer(this IServiceCollection servi // ServerToolLoader with RegistryDiscoveryStrategy creates proxy tools for external MCP servers. new ServerToolLoader( sp.GetRequiredService(), - sp.GetRequiredService>(), + sp.GetRequiredService>(), loggerFactory.CreateLogger() ), // NamespaceToolLoader enables direct in-process execution for consolidated tools new NamespaceToolLoader( consolidatedCommandFactory, - sp.GetRequiredService>(), + sp.GetRequiredService>(), loggerFactory.CreateLogger(), false ), @@ -216,7 +212,7 @@ public static IServiceCollection AddAzureMcpServer(this IServiceCollection servi var mcpServerOptions = services .AddOptions() - .Configure>((mcpServerOptions, mcpRuntime, serverInstructionsProvider, serverConfiguration) => + .Configure>((mcpServerOptions, mcpRuntime, serverInstructionsProvider, serverConfiguration) => { var configuration = serverConfiguration.Value; @@ -263,7 +259,7 @@ public static void InitializeConfigurationAndOptions(this IServiceCollection ser services.AddSingleton(GetConfiguration()); services.AddOptions() - .Configure>((options, rootConfiguration, serviceStartOptions) => + .Configure>((options, rootConfiguration, serviceStartOptions) => { // Use a scoped IConfiguration for loading server settings. var scopedConfiguration = GetConfiguration(assembly); diff --git a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/BaseToolLoader.cs b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/BaseToolLoader.cs index 25d651317c..2647f78195 100644 --- a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/BaseToolLoader.cs +++ b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/BaseToolLoader.cs @@ -43,7 +43,7 @@ static BaseToolLoader() /// Handles requests to list all tools available in the MCP server. /// /// The request context containing metadata and parameters. - /// A token to monitor for cancellation requests. + /// The token to monitor for cancellation requests. /// A result containing the list of available tools. public abstract ValueTask ListToolsHandler(RequestContext request, CancellationToken cancellationToken); @@ -51,7 +51,7 @@ static BaseToolLoader() /// Handles requests to call a specific tool with the provided parameters. /// /// The request context containing the tool name and parameters. - /// A token to monitor for cancellation requests. + /// The token to monitor for cancellation requests. /// A result containing the output of the tool invocation. public abstract ValueTask CallToolHandler(RequestContext request, CancellationToken cancellationToken); @@ -190,7 +190,7 @@ protected McpClientOptions CreateClientOptions(McpServer server) /// The tool command being invoked. /// Whether elicitation has been disabled via dangerous option. /// Logger instance for recording elicitation events. - /// Cancellation token for the operation. + /// The token to monitor for cancellation requests. /// /// Null if elicitation was accepted or bypassed (operation should proceed). /// A CallToolResult with IsError=true if elicitation was rejected or failed (operation should not proceed). diff --git a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/CommandFactoryToolLoader.cs b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/CommandFactoryToolLoader.cs index 0b80ebe80d..c9cb06504f 100644 --- a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/CommandFactoryToolLoader.cs +++ b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/CommandFactoryToolLoader.cs @@ -37,7 +37,7 @@ public sealed class CommandFactoryToolLoader( /// Lists all tools available from the command factory. /// /// The request context containing parameters and metadata. - /// A cancellation token. + /// The token to monitor for cancellation requests. /// A result containing the list of available tools. public override ValueTask ListToolsHandler(RequestContext request, CancellationToken cancellationToken) { @@ -70,7 +70,7 @@ public override ValueTask ListToolsHandler(RequestContext /// The request context containing parameters and metadata. - /// A cancellation token. + /// The token to monitor for cancellation requests. /// The result of the tool call operation. public override async ValueTask CallToolHandler(RequestContext request, CancellationToken cancellationToken) { diff --git a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/CompositeToolLoader.cs b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/CompositeToolLoader.cs index 342b1e554a..a674c09845 100644 --- a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/CompositeToolLoader.cs +++ b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/CompositeToolLoader.cs @@ -50,7 +50,7 @@ private static IEnumerable InitializeToolLoaders(IEnumerable /// The request context containing metadata and parameters. - /// A token to monitor for cancellation requests. + /// The token to monitor for cancellation requests. /// A result containing the combined list of all available tools, or an empty list if initialization fails. public override async ValueTask ListToolsHandler(RequestContext request, CancellationToken cancellationToken) { @@ -80,7 +80,7 @@ public override async ValueTask ListToolsHandler(RequestContext /// Calls a tool by its name using the appropriate tool loader. /// /// The request context containing the tool name and parameters. - /// A token to monitor for cancellation requests. + /// The token to monitor for cancellation requests. /// A result containing the output of the tool invocation, or an error result if the tool is not found or initialization fails. public override async ValueTask CallToolHandler(RequestContext request, CancellationToken cancellationToken) { @@ -148,7 +148,7 @@ public override async ValueTask CallToolHandler(RequestContext /// The server context for creating list tools requests. - /// A token to monitor for cancellation requests. + /// The token to monitor for cancellation requests. /// A task representing the asynchronous operation. private async Task InitializeAsync(McpServer server, CancellationToken cancellationToken) { diff --git a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/IToolLoader.cs b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/IToolLoader.cs index 90624f6872..861bc331b4 100644 --- a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/IToolLoader.cs +++ b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/IToolLoader.cs @@ -16,16 +16,16 @@ public interface IToolLoader : IAsyncDisposable /// Handles requests to list all tools available in the MCP server. /// /// The request context containing metadata and parameters. - /// A token to monitor for cancellation requests. + /// The token to monitor for cancellation requests. /// A result containing the list of available tools. ValueTask ListToolsHandler(RequestContext request, CancellationToken cancellationToken); /// /// Handles requests to call a specific tool with the provided parameters. If an error occurs while calling the /// tool, loaders should return a where the contents are details of the exception. - /// + /// /// The request context containing the tool name and parameters. - /// A token to monitor for cancellation requests. + /// The token to monitor for cancellation requests. /// A result containing the output of the tool invocation. ValueTask CallToolHandler(RequestContext request, CancellationToken cancellationToken); } diff --git a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/RegistryToolLoader.cs b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/RegistryToolLoader.cs index d061513393..a873a2b5f6 100644 --- a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/RegistryToolLoader.cs +++ b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/RegistryToolLoader.cs @@ -41,7 +41,7 @@ public sealed class RegistryToolLoader( /// Lists all tools available from registered MCP servers. /// /// The request context containing parameters and metadata. - /// A cancellation token. + /// The token to monitor for cancellation requests. /// A result containing the list of available tools. public override async ValueTask ListToolsHandler(RequestContext request, CancellationToken cancellationToken) { @@ -84,7 +84,7 @@ public override async ValueTask ListToolsHandler(RequestContext /// Handles tool calls by routing them to the appropriate MCP client. /// /// The request context containing parameters and metadata. - /// A cancellation token. + /// The token to monitor for cancellation requests. /// The result of the tool call operation. public override async ValueTask CallToolHandler(RequestContext request, CancellationToken cancellationToken) { @@ -206,7 +206,7 @@ public override async ValueTask CallToolHandler(RequestContext /// Initializes the tool client map by discovering servers and populating tools. /// - /// A cancellation token. + /// The token to monitor for cancellation requests. /// A task representing the asynchronous operation. private async Task InitializeAsync(CancellationToken cancellationToken) { diff --git a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/ServerToolLoader.cs b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/ServerToolLoader.cs index a7afc5ecf7..142d97c00a 100644 --- a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/ServerToolLoader.cs +++ b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/ServerToolLoader.cs @@ -424,8 +424,9 @@ private async Task InvokeToolLearn(RequestContext /// Gets the available tools from the child MCP server and caches the result as JSON. /// - /// - /// + /// The request context containing the parameters. + /// The name of the child tool (MCP server) to query for available tools. + /// The token to monitor for cancellation requests. /// internal async Task> GetAllChildToolsAsync(RequestContext request, string tool, CancellationToken cancellationToken) { diff --git a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/SingleProxyToolLoader.cs b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/SingleProxyToolLoader.cs index acceb79524..8b15121346 100644 --- a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/SingleProxyToolLoader.cs +++ b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ToolLoading/SingleProxyToolLoader.cs @@ -111,9 +111,9 @@ public override ValueTask ListToolsHandler(RequestContext /// The request context containing parameters and metadata. - /// A cancellation token. + /// The token to monitor for cancellation requests. /// A representing the result of the operation. - public override async ValueTask CallToolHandler(RequestContext request, CancellationToken cancellationToken = default) + public override async ValueTask CallToolHandler(RequestContext request, CancellationToken cancellationToken) { Activity.Current?.SetTag(TagName.IsServerCommandInvoked, false) .SetTag(TagName.ToolParameters, McpHelper.CreateToolParametersTelemetry(request)); @@ -208,10 +208,11 @@ private async Task InitializeRootToolsCacheAsync(CancellationToken cancellationT } /// - /// Gets the set of within an . + /// Gets the set of within an . /// /// Calling request /// Name of the to get commands for. + /// The token to monitor for cancellation requests. /// JSON serialized string representing the list of commands available in the tool's area. private async Task<(List Commands, string Json)> GetToolCommandsAsync(RequestContext request, string tool, CancellationToken cancellationToken) { diff --git a/core/Microsoft.Mcp.Core/src/Areas/Server/RegistryServerServiceCollectionExtensions.cs b/core/Microsoft.Mcp.Core/src/Areas/Server/RegistryServerServiceCollectionExtensions.cs index 7a14be16f0..14f0b1944e 100644 --- a/core/Microsoft.Mcp.Core/src/Areas/Server/RegistryServerServiceCollectionExtensions.cs +++ b/core/Microsoft.Mcp.Core/src/Areas/Server/RegistryServerServiceCollectionExtensions.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using System.Reflection; -using Azure.Mcp.Core; using Microsoft.Extensions.DependencyInjection; using Microsoft.Mcp.Core.Areas.Server.Models; using Microsoft.Mcp.Core.Helpers; diff --git a/core/Microsoft.Mcp.Core/src/Areas/Server/ServerSetup.cs b/core/Microsoft.Mcp.Core/src/Areas/Server/ServerSetup.cs index 58cda158fa..ba9144c50a 100644 --- a/core/Microsoft.Mcp.Core/src/Areas/Server/ServerSetup.cs +++ b/core/Microsoft.Mcp.Core/src/Areas/Server/ServerSetup.cs @@ -32,8 +32,8 @@ public void ConfigureServices(IServiceCollection services) /// /// Registers command groups and commands related to MCP Server operations. /// - /// The root command group to add server commands to. - /// The logger factory for creating loggers. + /// The service provider used to resolve command instances. + /// A CommandGroup containing all registered commands for the Server area. public CommandGroup RegisterCommands(IServiceProvider serviceProvider) { // Create MCP Server command group diff --git a/core/Microsoft.Mcp.Core/src/Areas/Tools/Commands/ToolsListCommand.cs b/core/Microsoft.Mcp.Core/src/Areas/Tools/Commands/ToolsListCommand.cs index 3ace062edf..0cf6a21e84 100644 --- a/core/Microsoft.Mcp.Core/src/Areas/Tools/Commands/ToolsListCommand.cs +++ b/core/Microsoft.Mcp.Core/src/Areas/Tools/Commands/ToolsListCommand.cs @@ -35,7 +35,7 @@ public sealed class ToolsListCommand(IServiceProvider serviceProvider, ILogger s_ignored = new(StringComparer.OrdinalIgnoreCase) { "server", "tools" }; private static readonly HashSet s_surfaced = new(StringComparer.OrdinalIgnoreCase) { "extension" }; - public override async Task ExecuteAsync(CommandContext context, ToolsListOptions options, CancellationToken cancellationToken) + public override Task ExecuteAsync(CommandContext context, ToolsListOptions options, CancellationToken cancellationToken) { try { @@ -79,15 +79,12 @@ public override async Task ExecuteAsync(CommandContext context, } // If --name-only is also specified, return only the names - if (options.NameOnly) - { - var namespaceNames = namespaceCommands.Select(nc => nc.Command).ToList(); - context.Response.Results = ResponseResult.Create(new(null, namespaceNames), ModelsJsonContext.Default.ToolsListResult); - return context.Response; - } + var result = options.NameOnly + ? new ToolsListResult(Commands: null, Names: namespaceCommands.Select(nc => nc.Command).ToList()) + : new ToolsListResult(Commands: namespaceCommands, Names: null); - context.Response.Results = ResponseResult.Create(new(namespaceCommands, null), ModelsJsonContext.Default.ToolsListResult); - return context.Response; + context.Response.Results = ResponseResult.Create(result, ModelsJsonContext.Default.ToolsListResult); + return Task.FromResult(context.Response); } // If the --name-only flag is set (without namespace mode), return only tool names @@ -104,7 +101,7 @@ public override async Task ExecuteAsync(CommandContext context, var toolNames = allToolNames.OrderBy(name => name, StringComparer.OrdinalIgnoreCase).ToList(); context.Response.Results = ResponseResult.Create(new(null, toolNames), ModelsJsonContext.Default.ToolsListResult); - return context.Response; + return Task.FromResult(context.Response); } // Get all tools with full details @@ -119,14 +116,14 @@ public override async Task ExecuteAsync(CommandContext context, var tools = allTools.ToList(); context.Response.Results = ResponseResult.Create(new(tools, null), ModelsJsonContext.Default.ToolsListResult); - return context.Response; + return Task.FromResult(context.Response); } catch (Exception ex) { logger.LogError(ex, "An exception occurred while processing tool listing."); HandleException(context, ex); - return context.Response; + return Task.FromResult(context.Response); } } diff --git a/core/Microsoft.Mcp.Core/src/Commands/CommandFactory.cs b/core/Microsoft.Mcp.Core/src/Commands/CommandFactory.cs index c63e6b8f53..1c589368b9 100644 --- a/core/Microsoft.Mcp.Core/src/Commands/CommandFactory.cs +++ b/core/Microsoft.Mcp.Core/src/Commands/CommandFactory.cs @@ -44,7 +44,7 @@ public class CommandFactory : ICommandFactory /// Creates a fresh for --learn each time it is called. /// A new instance is required per command because System.CommandLine v2 tracks option /// ownership by object identity; sharing a single static instance causes - /// to return the default value on every command + /// to return the default value on every command /// except the last one the option was added to. /// private static Option CreateLearnOption() diff --git a/core/Microsoft.Mcp.Core/src/Commands/ICommandFactory.cs b/core/Microsoft.Mcp.Core/src/Commands/ICommandFactory.cs index 4f5f5341db..52a21dac39 100644 --- a/core/Microsoft.Mcp.Core/src/Commands/ICommandFactory.cs +++ b/core/Microsoft.Mcp.Core/src/Commands/ICommandFactory.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System.CommandLine; +using Microsoft.Mcp.Core.Models.Command; namespace Microsoft.Mcp.Core.Commands; diff --git a/core/Microsoft.Mcp.Core/src/Extensions/ActivityExtensions.cs b/core/Microsoft.Mcp.Core/src/Extensions/ActivityExtensions.cs index c28a314df7..431ea3022c 100644 --- a/core/Microsoft.Mcp.Core/src/Extensions/ActivityExtensions.cs +++ b/core/Microsoft.Mcp.Core/src/Extensions/ActivityExtensions.cs @@ -10,6 +10,7 @@ public static class ActivityExtensions /// /// Sets a tag in the activity if, and only if, the tag does not already exist. /// + /// The activity to set the tag on. /// The name of the tag. /// The value of the tag. public static Activity SetTagIfNotExists(this Activity? activity, string name, object? value) diff --git a/core/Microsoft.Mcp.Core/src/Extensions/McpServerElicitationExtensions.cs b/core/Microsoft.Mcp.Core/src/Extensions/McpServerElicitationExtensions.cs index 1c8bc19e35..f094b603b1 100644 --- a/core/Microsoft.Mcp.Core/src/Extensions/McpServerElicitationExtensions.cs +++ b/core/Microsoft.Mcp.Core/src/Extensions/McpServerElicitationExtensions.cs @@ -25,7 +25,7 @@ public static class McpServerElicitationExtensions /// /// The MCP server instance. /// The elicitation request parameters. - /// A token to monitor for cancellation requests. + /// The token to monitor for cancellation requests. The default value is . /// A task that represents the asynchronous elicitation operation. public static async Task RequestElicitationAsync( this McpServer server, @@ -204,10 +204,9 @@ public static bool SupportsElicitation(this McpServer server) /// Checks if elicitation should be triggered for a tool based on its metadata. /// /// The MCP server instance. - /// The name of the tool. /// The tool metadata to check. /// True if elicitation should be triggered, false otherwise. - public static bool ShouldTriggerElicitation(this McpServer server, string toolName, object? toolMetadata) + public static bool ShouldTriggerElicitation(this McpServer server, object? toolMetadata) { if (!server.SupportsElicitation()) { diff --git a/core/Microsoft.Mcp.Core/src/Extensions/OpenTelemetryExtensions.cs b/core/Microsoft.Mcp.Core/src/Extensions/OpenTelemetryExtensions.cs index a3a9dd06a7..254308759b 100644 --- a/core/Microsoft.Mcp.Core/src/Extensions/OpenTelemetryExtensions.cs +++ b/core/Microsoft.Mcp.Core/src/Extensions/OpenTelemetryExtensions.cs @@ -4,7 +4,9 @@ using System.Reflection; using System.Runtime.InteropServices; using Azure.Monitor.OpenTelemetry.Exporter; +#pragma warning disable IDE0005 // using isn't used in release builds. using Microsoft.Extensions.Azure; +#pragma warning restore IDE0005 // using isn't used in release builds. using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -23,7 +25,9 @@ public static class OpenTelemetryExtensions /// /// The App Insights connection string to send telemetry to Microsoft. /// +#pragma warning disable IDE0051 // Remove unused private members, used in conditional block private const string MicrosoftOwnedAppInsightsConnectionString = "InstrumentationKey=21e003c0-efee-4d3f-8a98-1868515aa2c9;IngestionEndpoint=https://centralus-2.in.applicationinsights.azure.com/;LiveEndpoint=https://centralus.livediagnostics.monitor.azure.com/;ApplicationId=f14f6a2d-6405-4f88-bd58-056f25fe274f"; +#pragma warning restore IDE0051 public static void ConfigureOpenTelemetry(this IServiceCollection services) { @@ -130,7 +134,9 @@ private static void EnableAzureMonitor(this IServiceCollection services) /// /// The OpenTelemetry builder to configure. /// The Application Insights connection string for Microsoft's telemetry instance. +#pragma warning disable IDE0051 // Remove unused private members, used in conditional block private static void ConfigureMicrosoftAzureMonitorExporter(OpenTelemetry.OpenTelemetryBuilder otelBuilder, string appInsightsConnectionString) +#pragma warning restore IDE0051 { // We don't configure logging for Microsoft telemetry to avoid sending potentially sensitive log data to Microsoft. otelBuilder.WithMetrics(metrics => diff --git a/core/Microsoft.Mcp.Core/src/Helpers/McpHelper.cs b/core/Microsoft.Mcp.Core/src/Helpers/McpHelper.cs index 050d83c73f..ab2412463d 100644 --- a/core/Microsoft.Mcp.Core/src/Helpers/McpHelper.cs +++ b/core/Microsoft.Mcp.Core/src/Helpers/McpHelper.cs @@ -31,6 +31,7 @@ public static class McpHelper /// Determines whether the tool has the hint in its metadata and is true. /// /// The tool to check its metadata for the hint. + /// The key of the hint to check in the tool's metadata. /// True if the hint was found, successfully extracted, and is true; otherwise, false. public static bool HasHint(Tool tool, string hintKey) => tool.Meta != null && tool.Meta.TryGetPropertyValue(hintKey, out var hintNode) diff --git a/core/Microsoft.Mcp.Core/src/Helpers/OptionParsingHelpers.cs b/core/Microsoft.Mcp.Core/src/Helpers/OptionParsingHelpers.cs index 0cf4b7e3e0..32bee83639 100644 --- a/core/Microsoft.Mcp.Core/src/Helpers/OptionParsingHelpers.cs +++ b/core/Microsoft.Mcp.Core/src/Helpers/OptionParsingHelpers.cs @@ -10,6 +10,8 @@ public static class OptionParsingHelpers /// If duplicate keys are found, the last value wins. /// /// Value string containing key-value pairs + /// The character that separates keys from values in the input string. + /// The character that separates key-value pairs in the input string. /// Key Value pairs as dictionary public static Dictionary ParseKeyValuePairStringToDictionary(string value, char keyValueSeparator = '=', char pairSeparator = ',') { @@ -20,7 +22,12 @@ public static Dictionary ParseKeyValuePairStringToDictionary(str /// Parses key value pair string options to a dictionary, assuming a format of "Key=Value,Key=Value" (default separators '=' and ',') /// If duplicate keys are found, the last value wins. /// - /// Value string containing key-value pairs + /// Value string containing key-value pairs + /// The string comparer to use for comparing keys in the resulting dictionary. + /// The character that separates keys from values in the input string. + /// The character that separates key-value pairs in the input string. + /// Thrown when the input value string is null, empty, or consists only of whitespace. + /// Thrown when the keyComparer is null. /// Key Value pairs as dictionary public static Dictionary ParseKeyValuePairStringToDictionary(string value, StringComparer keyComparer, char keyValueSeparator = '=', char pairSeparator = ',') { diff --git a/core/Microsoft.Mcp.Core/src/Models/Command/CommandContext.cs b/core/Microsoft.Mcp.Core/src/Models/Command/CommandContext.cs index e51fb4960f..48cb5d3f1f 100644 --- a/core/Microsoft.Mcp.Core/src/Models/Command/CommandContext.cs +++ b/core/Microsoft.Mcp.Core/src/Models/Command/CommandContext.cs @@ -47,6 +47,7 @@ public class CommandContext /// /// Creates a new command context /// + /// Optional telemetry activity for the command execution public CommandContext(Activity? activity = default) { Activity = activity; diff --git a/core/Microsoft.Mcp.Core/src/Services/Azure/Authentication/IAzureTokenCredentialProvider.cs b/core/Microsoft.Mcp.Core/src/Services/Azure/Authentication/IAzureTokenCredentialProvider.cs index 4b3ec80964..4696dd0bb2 100644 --- a/core/Microsoft.Mcp.Core/src/Services/Azure/Authentication/IAzureTokenCredentialProvider.cs +++ b/core/Microsoft.Mcp.Core/src/Services/Azure/Authentication/IAzureTokenCredentialProvider.cs @@ -14,8 +14,7 @@ namespace Microsoft.Mcp.Core.Services.Azure.Authentication; /// /// /// -/// Callers can either directly depend on this interface or indirectly depend on it through -/// . +/// Callers can either directly depend on this interface or indirectly depend on it through ITenantService. /// /// /// Implementors of this interface are responsible for generating, caching, and retrieving tokens diff --git a/core/Microsoft.Mcp.Core/src/Services/Caching/HttpServiceCacheService.cs b/core/Microsoft.Mcp.Core/src/Services/Caching/HttpServiceCacheService.cs index 59816d5091..6b95c6a6c7 100644 --- a/core/Microsoft.Mcp.Core/src/Services/Caching/HttpServiceCacheService.cs +++ b/core/Microsoft.Mcp.Core/src/Services/Caching/HttpServiceCacheService.cs @@ -6,7 +6,6 @@ namespace Microsoft.Mcp.Core.Services.Caching; /// /// An implementation of for multi-user web API scenarios. /// -/// A memory cache. /// /// /// Do not instantiate directly. Use . diff --git a/core/Microsoft.Mcp.Core/src/Services/Caching/ICacheService.cs b/core/Microsoft.Mcp.Core/src/Services/Caching/ICacheService.cs index 888c0a2a2d..46c5b9fe43 100644 --- a/core/Microsoft.Mcp.Core/src/Services/Caching/ICacheService.cs +++ b/core/Microsoft.Mcp.Core/src/Services/Caching/ICacheService.cs @@ -12,7 +12,7 @@ public interface ICacheService /// The group name. /// The cache key within the group. /// Optional expiration time. - /// A token to cancel the operation. + /// The token to monitor for cancellation requests. The default value is . /// The cached value or default if not found. ValueTask GetAsync(string group, string key, TimeSpan? expiration = null, CancellationToken cancellationToken = default); @@ -24,7 +24,7 @@ public interface ICacheService /// The cache key within the group. /// The data to cache. /// Optional expiration time. - /// A token to cancel the operation. + /// The token to monitor for cancellation requests. The default value is . /// A ValueTask representing the asynchronous operation. ValueTask SetAsync(string group, string key, T data, TimeSpan? expiration = null, CancellationToken cancellationToken = default); @@ -33,7 +33,7 @@ public interface ICacheService /// /// The group name. /// The cache key within the group. - /// A token to cancel the operation. + /// The token to monitor for cancellation requests. /// A ValueTask representing the asynchronous operation. ValueTask DeleteAsync(string group, string key, CancellationToken cancellationToken); @@ -41,14 +41,14 @@ public interface ICacheService /// Gets all keys in a specific group. /// /// The group name. - /// A token to cancel the operation. + /// The token to monitor for cancellation requests. /// A collection of keys in the specified group. ValueTask> GetGroupKeysAsync(string group, CancellationToken cancellationToken); /// /// Clears all items from the cache. /// - /// A token to cancel the operation. + /// The token to monitor for cancellation requests. /// A ValueTask representing the asynchronous operation. ValueTask ClearAsync(CancellationToken cancellationToken); @@ -56,7 +56,7 @@ public interface ICacheService /// Clears all items from a specific group in the cache. /// /// The group name to clear. - /// A token to cancel the operation. + /// The token to monitor for cancellation requests. /// A ValueTask representing the asynchronous operation. ValueTask ClearGroupAsync(string group, CancellationToken cancellationToken); } diff --git a/core/Microsoft.Mcp.Core/src/Services/ProcessExecution/ExternalProcessService.cs b/core/Microsoft.Mcp.Core/src/Services/ProcessExecution/ExternalProcessService.cs index b5e0f8b2c0..67cc23da83 100644 --- a/core/Microsoft.Mcp.Core/src/Services/ProcessExecution/ExternalProcessService.cs +++ b/core/Microsoft.Mcp.Core/src/Services/ProcessExecution/ExternalProcessService.cs @@ -361,7 +361,7 @@ private void HandleCancellation(Process process, string executablePath, string a /// /// Reads either stdout or stderr from a asynchronously. /// Handlers are attached in the constructor, and reading begins when - /// is called after the process has started. + /// is called after the process has started. /// /// /// @@ -371,7 +371,7 @@ private void HandleCancellation(Process process, string executablePath, string a /// Create and configure the with redirected streams. /// Construct (handlers attach immediately). /// Start the process. - /// Call to begin event-driven reading. + /// Call to begin event-driven reading. /// Await the returned task to obtain the full stream content. /// /// @@ -402,8 +402,8 @@ private sealed class ProcessStreamReader : IDisposable public ProcessStreamReader(Process process, bool isErrorStream, ILogger logger) { - this._process = process ?? throw new ArgumentNullException(nameof(process)); - this._isErrorStream = isErrorStream; + _process = process ?? throw new ArgumentNullException(nameof(process)); + _isErrorStream = isErrorStream; _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _handler = (_, e) => @@ -431,7 +431,7 @@ public ProcessStreamReader(Process process, bool isErrorStream, ILogger /// Begins asynchronous reading of the associated stream. - /// Must be called only after has successfully completed. + /// Must be called only after has successfully completed. /// /// /// This method does not accept a because the underlying @@ -582,7 +582,7 @@ public static string SafeName(this Process process) /// The process to check. /// Logger for diagnostic messages. /// - /// An indicating: + /// An indicating: /// /// with null exception if the process has exited. /// with null exception if the process has not exited. @@ -604,9 +604,11 @@ public static ExitCheckResult CheckExitState(this Process process, ILogger logge { // Official docs: "No process is associated with this object." - treat as "already gone". logger.LogDebug( - checkException, - "Process.HasExited reported no associated process. Treating as already exited. " + - "Process: {ProcessName}, PID: {Pid}", process.SafeName(), process.SafeId()); + checkException, + "Process.HasExited reported no associated process. Treating as already exited. " + + "Process: {ProcessName}, PID: {Pid}", + process.SafeName(), + process.SafeId()); return new ExitCheckResult(ExitStatus.Exited, CheckException: null); } catch (System.ComponentModel.Win32Exception checkException) diff --git a/core/Microsoft.Mcp.Core/src/Services/Telemetry/UnixMachineInformationProvider.cs b/core/Microsoft.Mcp.Core/src/Services/Telemetry/UnixMachineInformationProvider.cs index 819145eabb..868a266b8e 100644 --- a/core/Microsoft.Mcp.Core/src/Services/Telemetry/UnixMachineInformationProvider.cs +++ b/core/Microsoft.Mcp.Core/src/Services/Telemetry/UnixMachineInformationProvider.cs @@ -56,7 +56,7 @@ internal abstract class UnixMachineInformationProvider(ILoggerThe value to write in the file. /// True, if the value was successfully written. /// - public async virtual Task WriteValueToDisk(string directoryPath, string fileName, string? value) + public virtual async Task WriteValueToDisk(string directoryPath, string fileName, string? value) { // If the value is not set, return immediately. if (string.IsNullOrWhiteSpace(value)) @@ -91,10 +91,10 @@ public async virtual Task WriteValueToDisk(string directoryPath, string fi } /// - /// Try and read the value from disk. If is null or empty, this method will return false. + /// Try and read the value from disk. /// /// Returns a value if the value could be written on disk. Otherwise, false. - public async virtual Task ReadValueFromDisk(string directoryPath, string fileName) + public virtual async Task ReadValueFromDisk(string directoryPath, string fileName) { var path = Path.Combine(directoryPath, fileName); diff --git a/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Core.Tests/Areas/Server/Commands/CommandExtensionsTests.cs b/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Core.Tests/Areas/Server/Commands/CommandExtensionsTests.cs index 30101f99ec..77c9bd7d3e 100644 --- a/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Core.Tests/Areas/Server/Commands/CommandExtensionsTests.cs +++ b/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Core.Tests/Areas/Server/Commands/CommandExtensionsTests.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using System.CommandLine; -using System.CommandLine.Parsing; using System.Text.Json; using Microsoft.Mcp.Core.Commands; using Microsoft.Mcp.Core.Extensions; diff --git a/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/ToolLoaderTelemetryTests.cs b/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/ToolLoaderTelemetryTests.cs index 1eb31fbe5d..476941b154 100644 --- a/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/ToolLoaderTelemetryTests.cs +++ b/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Core.Tests/Areas/Server/Commands/ToolLoading/ToolLoaderTelemetryTests.cs @@ -16,6 +16,7 @@ using NSubstitute; using NSubstitute.ExceptionExtensions; using Xunit; +using ExtensionsOptions = Microsoft.Extensions.Options; namespace Microsoft.Mcp.Core.Tests.Areas.Server.Commands.ToolLoading; @@ -44,7 +45,7 @@ public async Task CommandFactoryToolLoader_EmitsErrorTelemetry_IfToolIsFiltered( var toolName = "tool"; var mcpServer = Substitute.For(); var commandFactory = Substitute.For(); - var options = Microsoft.Extensions.Options.Options.Create(new ToolLoaderOptions(Tool: ["nevercalled"])); + var options = ExtensionsOptions.Options.Create(new ToolLoaderOptions(Tool: ["nevercalled"])); var logger = Substitute.For>(); var mcpRuntime = CreateRuntime(new CommandFactoryToolLoader(commandFactory, options, logger)); @@ -69,7 +70,7 @@ public async Task CommandFactoryToolLoader_EmitsErrorTelemetry_IfCommandDoesNotE { ["nevercalled"] = Substitute.For() }); - var options = Microsoft.Extensions.Options.Options.Create(new ToolLoaderOptions()); + var options = ExtensionsOptions.Options.Create(new ToolLoaderOptions()); var logger = Substitute.For>(); var mcpRuntime = CreateRuntime(new CommandFactoryToolLoader(commandFactory, options, logger)); @@ -100,7 +101,7 @@ public async Task CommandFactoryToolLoader_EmitsErrorTelemetry_IfClientDoesNotSu { [toolName] = toolCommand }); - var options = Microsoft.Extensions.Options.Options.Create(new ToolLoaderOptions()); + var options = ExtensionsOptions.Options.Create(new ToolLoaderOptions()); var logger = Substitute.For>(); var mcpRuntime = CreateRuntime(new CommandFactoryToolLoader(commandFactory, options, logger)); @@ -134,7 +135,7 @@ public async Task CommandFactoryToolLoader_EmitsErrorTelemetry_IfToolHasAnExcept { [toolName] = toolCommand }); - var options = Microsoft.Extensions.Options.Options.Create(new ToolLoaderOptions()); + var options = ExtensionsOptions.Options.Create(new ToolLoaderOptions()); var logger = Substitute.For>(); var mcpRuntime = CreateRuntime(new CommandFactoryToolLoader(commandFactory, options, logger)); @@ -169,7 +170,7 @@ public async Task CommandFactoryToolLoader_EmitsSuccessTelemetry_WhenToolCallSuc { [toolName] = toolCommand }); - var options = Microsoft.Extensions.Options.Options.Create(new ToolLoaderOptions()); + var options = ExtensionsOptions.Options.Create(new ToolLoaderOptions()); var logger = Substitute.For>(); var mcpRuntime = CreateRuntime(new CommandFactoryToolLoader(commandFactory, options, logger)); @@ -186,7 +187,7 @@ public async Task CommandFactoryToolLoader_EmitsSuccessTelemetry_WhenToolCallSuc private IMcpRuntime CreateRuntime(IToolLoader toolLoader) { - var options = Microsoft.Extensions.Options.Options.Create(new ServerStartOptions()); + var options = ExtensionsOptions.Options.Create(new ServerStartOptions()); var telemetry = Substitute.For(); telemetry.StartActivity(Arg.Any(), Arg.Any(), Arg.Any()).Returns(_activity); var logger = Substitute.For>(); diff --git a/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/CommandTestsBase.cs b/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/CommandTestsBase.cs index 9ad8c49e0e..7682a047de 100644 --- a/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/CommandTestsBase.cs +++ b/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/CommandTestsBase.cs @@ -5,6 +5,7 @@ using System.Text; using System.Text.Json; using System.Text.Json.Nodes; +using Microsoft.Mcp.Core.Models.Command; using Microsoft.Mcp.Tests.Attributes; using Microsoft.Mcp.Tests.Client.Helpers; using Microsoft.Mcp.Tests.Helpers; diff --git a/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/Helpers/BinaryContentHelper.cs b/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/Helpers/BinaryContentHelper.cs index 7c9c27568d..32954b341d 100644 --- a/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/Helpers/BinaryContentHelper.cs +++ b/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/Helpers/BinaryContentHelper.cs @@ -18,7 +18,7 @@ internal static class BinaryContentHelper /// /// Serialize object to JSON UTF8 bytes and wrap into BinaryContent via BinaryData factory. - /// Avoid generic Create which expects IPersistableModel. + /// Avoid generic Create<T> which expects IPersistableModel. /// public static BinaryContent FromObject(T value, JsonSerializerOptions? jsonOptions = null) { diff --git a/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/Helpers/CustomTestTransport.cs b/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/Helpers/CustomTestTransport.cs index 3b6cddc90c..2682dee81b 100644 --- a/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/Helpers/CustomTestTransport.cs +++ b/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/Helpers/CustomTestTransport.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System.Threading.Channels; diff --git a/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/Helpers/McpTestUtilities.cs b/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/Helpers/McpTestUtilities.cs index 426774393b..6ee2197d69 100644 --- a/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/Helpers/McpTestUtilities.cs +++ b/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/Helpers/McpTestUtilities.cs @@ -51,6 +51,7 @@ public static string GetAzMcpExecutablePath() /// Optional test output helper for logging. /// Optional NPM test package name for STDIO mode. /// Optional settings directory for NPM test package. + /// Whether to disable authentication for the MCP client. /// A tuple containing the initialized MCP client and optional server URL (for HTTP transport). public static async Task<(McpClient? Client, string? ServerUrl)> CreateMcpClientAsync( string executablePath, @@ -119,6 +120,7 @@ public static string GetAzMcpExecutablePath() /// Environment variables to set for the server process. /// Callback to store the started process instance. /// Optional test output helper for logging. + /// Whether to disable authentication for the HTTP server. /// The server URL. private static async Task StartHttpServerAsync( string executablePath, @@ -310,12 +312,14 @@ public static async Task WaitForServerReadinessAsync( /// Command-line arguments for the server process. /// Environment variables to set for the server process. /// Optional test output helper for logging. + /// Whether to disable authentication for the HTTP server. /// The started Process instance. public static Process StartHttpServerProcess( string executablePath, List processArguments, Dictionary environmentVariables, - ITestOutputHelper? output = null, bool disableAuthentication = true) + ITestOutputHelper? output = null, + bool disableAuthentication = true) { processArguments.AddRange(["--transport", "http", "--outgoing-auth-strategy", "UseHostingEnvironmentIdentity"]); if (disableAuthentication) diff --git a/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/Helpers/RecordingPathResolver.cs b/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/Helpers/RecordingPathResolver.cs index f922c1798f..23ef2e9748 100644 --- a/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/Helpers/RecordingPathResolver.cs +++ b/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/Helpers/RecordingPathResolver.cs @@ -50,7 +50,7 @@ public static string Sanitize(string name) } /// - /// Builds the session directory path: /SessionRecords/ + /// Builds the session directory path: <relative path to test project>/SessionRecords/<TestClassName or variant> /// Example: tools/Azure.Mcp.Tools.KeyVault/tests/Azure.Mcp.Tools.KeyVault.Tests/SessionRecords/RecordedKeyVaultCommandTests /// public string GetSessionDirectory(Type testType, string? variantSuffix = null) diff --git a/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/LiveServerFixture.cs b/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/LiveServerFixture.cs index 4d29f6f445..550dc48d6c 100644 --- a/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/LiveServerFixture.cs +++ b/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/LiveServerFixture.cs @@ -13,7 +13,6 @@ public sealed class LiveServerFixture() : IAsyncLifetime private readonly SemaphoreSlim _startLock = new(1, 1); private Process? _httpServerProcess; private McpClient? _mcpClient; - private string? _serverUrl; private bool _started; public Dictionary EnvironmentVariables { get; set; } = new(); @@ -49,7 +48,6 @@ public async Task EnsureStartedAsync() Settings?.SettingsDirectory); _mcpClient = client; - _serverUrl = serverUrl; _started = true; } finally diff --git a/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/TestProxy.cs b/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/TestProxy.cs index 48859f3f71..21611957fd 100644 --- a/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/TestProxy.cs +++ b/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Client/TestProxy.cs @@ -16,9 +16,8 @@ namespace Microsoft.Mcp.Tests.Client; /// This version intentionally avoids dependencies on prior internal abstractions that were missing /// (e.g. TestEnvironment / ProcessTracker) while still providing stderr/stdout capture for failed tests. /// -public sealed class TestProxy(bool debug = false) : IDisposable +public sealed class TestProxy() : IDisposable { - private readonly bool _debug = debug; public StringBuilder stderr = new(); public readonly StringBuilder stdout = new(); private Process? _process; @@ -46,7 +45,7 @@ public sealed class TestProxy(bool debug = false) : IDisposable /// private static readonly SemaphoreSlim s_downloadLock = new(1, 1); - private async Task EnsureProxyExecutableAsync(string repositoryRoot, string assetsJsonPath) + private async Task EnsureProxyExecutableAsync() { if (_cachedExecutable != null) { @@ -330,7 +329,7 @@ public async Task Start(string repositoryRoot, string assetsJsonPath) return; } - var proxyExe = await EnsureProxyExecutableAsync(repositoryRoot, assetsJsonPath).ConfigureAwait(false); + var proxyExe = await EnsureProxyExecutableAsync().ConfigureAwait(false); await EnsureProxyRecordings(proxyExe, repositoryRoot, assetsJsonPath).ConfigureAwait(false); if (string.IsNullOrWhiteSpace(proxyExe) || !File.Exists(proxyExe)) diff --git a/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Generated/MicrosoftClientModelTestFrameworkModelFactory.cs b/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Generated/MicrosoftClientModelTestFrameworkModelFactory.cs index e7d375a75b..28d484aaf0 100644 --- a/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Generated/MicrosoftClientModelTestFrameworkModelFactory.cs +++ b/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Generated/MicrosoftClientModelTestFrameworkModelFactory.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#pragma warning disable CS1574 + // #nullable disable diff --git a/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Helpers/ClearEnvironmentVariablesBeforeTestAttribute.cs b/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Helpers/ClearEnvironmentVariablesBeforeTestAttribute.cs index 879c058dd0..750dd03c13 100644 --- a/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Helpers/ClearEnvironmentVariablesBeforeTestAttribute.cs +++ b/core/Microsoft.Mcp.Core/tests/Microsoft.Mcp.Tests/Helpers/ClearEnvironmentVariablesBeforeTestAttribute.cs @@ -4,18 +4,18 @@ using System.Reflection; using Xunit.v3; -namespace Microsoft.Mcp.Tests.Helpers +namespace Microsoft.Mcp.Tests.Helpers; + +/// +/// Xunit attribute to clear known environment variables before each test is run. +/// Live tests should not use this attribute, as they may need environment variables to configure authentication and proxy. +/// +public class ClearEnvironmentVariablesBeforeTestAttribute : BeforeAfterTestAttribute { - /// - /// Xunit attribute to clear known environment variables before each test is run. - /// Live tests should not use this attribute, as they may need environment variables to configure authentication and proxy. - /// - public class ClearEnvironmentVariablesBeforeTestAttribute : BeforeAfterTestAttribute - { - // These are all the known environment variables that our server may use. - // Proper test initialization should clear all of these, then set only the ones needed for the test. - private static readonly List _variablesToClear = [ - "ALL_PROXY", + // These are all the known environment variables that our server may use. + // Proper test initialization should clear all of these, then set only the ones needed for the test. + private static readonly List _variablesToClear = [ + "ALL_PROXY", "ALLOW_INSECURE_EXTERNAL_BINDING", "APPLICATIONINSIGHTS_CONNECTION_STRING", "ASPNETCORE_URLS", @@ -34,12 +34,11 @@ public class ClearEnvironmentVariablesBeforeTestAttribute : BeforeAfterTestAttri "NO_PROXY", ]; - public override void Before(MethodInfo methodUnderTest, IXunitTest test) + public override void Before(MethodInfo methodUnderTest, IXunitTest test) + { + foreach (var envVar in _variablesToClear) { - foreach (var envVar in _variablesToClear) - { - Environment.SetEnvironmentVariable(envVar, null); - } + Environment.SetEnvironmentVariable(envVar, null); } } } diff --git a/core/Microsoft.ModelContextProtocol.HttpServer.Distributed/src/Abstractions/ISessionStore.cs b/core/Microsoft.ModelContextProtocol.HttpServer.Distributed/src/Abstractions/ISessionStore.cs index e245bd8d14..adcabbd371 100644 --- a/core/Microsoft.ModelContextProtocol.HttpServer.Distributed/src/Abstractions/ISessionStore.cs +++ b/core/Microsoft.ModelContextProtocol.HttpServer.Distributed/src/Abstractions/ISessionStore.cs @@ -13,7 +13,7 @@ public interface ISessionStore /// /// The session identifier. /// A factory function that creates the owner information if the session is unclaimed. - /// Cancellation token. + /// The token to monitor for cancellation requests. The default value is . /// The current or newly claimed owner information for the session. Task GetOrClaimOwnershipAsync( string sessionId, @@ -25,7 +25,7 @@ Task GetOrClaimOwnershipAsync( /// Removes a session from the store. /// /// The session identifier to remove. - /// Cancellation token. + /// The token to monitor for cancellation requests. The default value is . /// A task representing the asynchronous operation. Task RemoveAsync(string sessionId, CancellationToken cancellationToken = default); } diff --git a/eng/tools/CopilotCliTester/src/AgentRunner.cs b/eng/tools/CopilotCliTester/src/AgentRunner.cs index 9ba7d46b7a..b6d2429cb0 100644 --- a/eng/tools/CopilotCliTester/src/AgentRunner.cs +++ b/eng/tools/CopilotCliTester/src/AgentRunner.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using System.Diagnostics; using System.Text; using System.Text.RegularExpressions; using CopilotCliTester.Models; @@ -15,8 +14,8 @@ namespace CopilotCliTester; /// internal sealed partial class AgentRunner(CopilotClient client, string serverExecutablePath, string? outputDir = null, string? workspacePath = null) : IAsyncDisposable { - private static readonly string TimeStamp = DateTimeOffset.UtcNow.ToString("yyyyMMdd-HHmmss"); - private readonly Lock eventLock = new(); + private static readonly string s_timeStamp = DateTimeOffset.UtcNow.ToString("yyyyMMdd-HHmmss"); + private readonly Lock _eventLock = new(); private readonly string _outputDirectory = outputDir ?? Path.Combine(AppContext.BaseDirectory, "reports"); [GeneratedRegex(@"eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}")] @@ -108,7 +107,7 @@ public async Task RunAsync(AgentRunConfig config, CancellationTok session.On(ev => { - lock (eventLock) + lock (_eventLock) { if (isComplete) return; @@ -160,7 +159,7 @@ public async Task RunAsync(AgentRunConfig config, CancellationTok } catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) { - lock (eventLock) + lock (_eventLock) { isComplete = true; } @@ -335,7 +334,7 @@ internal static string RedactSecrets(string text) private string BuildReportFilePath(AgentRunConfig config) { - var runDir = $"test-run-{TimeStamp}"; + var runDir = $"test-run-{s_timeStamp}"; var ns = config.Namespace ?? "unknown"; var tool = config.ToolName ?? $"test-{DateTime.UtcNow:yyyyMMdd-HHmmss}"; var file = $"{tool}-{DateTimeOffset.UtcNow:HHmmssfff}.md"; diff --git a/eng/tools/CopilotCliTester/src/AgentRunnerUtils.cs b/eng/tools/CopilotCliTester/src/AgentRunnerUtils.cs index 99f898831b..161cc4c8d5 100644 --- a/eng/tools/CopilotCliTester/src/AgentRunnerUtils.cs +++ b/eng/tools/CopilotCliTester/src/AgentRunnerUtils.cs @@ -3,7 +3,6 @@ using System.Text.Json; using CopilotCliTester.Models; -using GitHub.Copilot.SDK; namespace CopilotCliTester; @@ -13,12 +12,12 @@ namespace CopilotCliTester; internal static class AgentRunnerUtils { // Internal/meta tools we do NOT want to count as "the expected MCP tool" - private static readonly HashSet IgnoredTools = new(StringComparer.OrdinalIgnoreCase) + private static readonly HashSet s_ignoredTools = new(StringComparer.OrdinalIgnoreCase) { "report_intent" }; - private static readonly string[] prefixes = new[] { "azure-", "azure_" }; + private static readonly string[] s_prefixes = ["azure-", "azure_"]; /// /// Returns tool.execution_start events @@ -30,7 +29,7 @@ public static IReadOnlyList GetToolCalls(AgentMetadata metada .Where(e => { var name = e.Data.TryGetValue("toolName", out var tn) ? tn?.ToString() : null; - return !string.IsNullOrWhiteSpace(name) && !IgnoredTools.Contains(name!); + return !string.IsNullOrWhiteSpace(name) && !s_ignoredTools.Contains(name!); }).ToList(); } @@ -47,7 +46,7 @@ public static bool WasToolInvoked(AgentMetadata metadata, string expectedTool) return true; // Strip known single-segment namespace-proxy prefix instead of open-ended suffix match to avoid false positives (e.g., "subscription_list" matching "eventgrid_subscription_list") - foreach (var prefix in prefixes) + foreach (var prefix in s_prefixes) { if (resolved.StartsWith(prefix, StringComparison.OrdinalIgnoreCase) && string.Equals(resolved[prefix.Length..], expectedTool, StringComparison.OrdinalIgnoreCase)) diff --git a/eng/tools/CopilotCliTester/src/CopilotCliTester.csproj b/eng/tools/CopilotCliTester/src/CopilotCliTester.csproj index 92c334f87d..43564c54e5 100644 --- a/eng/tools/CopilotCliTester/src/CopilotCliTester.csproj +++ b/eng/tools/CopilotCliTester/src/CopilotCliTester.csproj @@ -6,6 +6,7 @@ CopilotCliTester enable enable + true diff --git a/eng/tools/ToolDescriptionEvaluator/src/Models/EmbeddingModels.cs b/eng/tools/ToolDescriptionEvaluator/src/Models/EmbeddingModels.cs index d8b49a93ba..bbf10d61c8 100644 --- a/eng/tools/ToolDescriptionEvaluator/src/Models/EmbeddingModels.cs +++ b/eng/tools/ToolDescriptionEvaluator/src/Models/EmbeddingModels.cs @@ -3,7 +3,7 @@ using System.Text.Json.Serialization; -namespace ToolSelection.Models; +namespace ToolDescriptionEvaluator.Models; // Azure OpenAI Embedding API models public class EmbeddingRequest diff --git a/eng/tools/ToolDescriptionEvaluator/src/Models/McpModels.cs b/eng/tools/ToolDescriptionEvaluator/src/Models/McpModels.cs index ed57214a5e..d72ddfff52 100644 --- a/eng/tools/ToolDescriptionEvaluator/src/Models/McpModels.cs +++ b/eng/tools/ToolDescriptionEvaluator/src/Models/McpModels.cs @@ -3,7 +3,7 @@ using System.Text.Json.Serialization; -namespace ToolSelection.Models; +namespace ToolDescriptionEvaluator.Models; // Constants public static class McpConstants diff --git a/eng/tools/ToolDescriptionEvaluator/src/Models/SourceGenerationContext.cs b/eng/tools/ToolDescriptionEvaluator/src/Models/SourceGenerationContext.cs index 1324db6567..8d871df882 100644 --- a/eng/tools/ToolDescriptionEvaluator/src/Models/SourceGenerationContext.cs +++ b/eng/tools/ToolDescriptionEvaluator/src/Models/SourceGenerationContext.cs @@ -3,7 +3,7 @@ using System.Text.Json.Serialization; -namespace ToolSelection.Models; +namespace ToolDescriptionEvaluator.Models; [JsonSourceGenerationOptions(WriteIndented = true, PropertyNameCaseInsensitive = true)] [JsonSerializable(typeof(ListToolsResult))] diff --git a/eng/tools/ToolDescriptionEvaluator/src/Models/SuccessRateMetrics.cs b/eng/tools/ToolDescriptionEvaluator/src/Models/SuccessRateMetrics.cs index ce519a1c4c..0bfb085bb0 100644 --- a/eng/tools/ToolDescriptionEvaluator/src/Models/SuccessRateMetrics.cs +++ b/eng/tools/ToolDescriptionEvaluator/src/Models/SuccessRateMetrics.cs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -namespace ToolSelection.Models; +namespace ToolDescriptionEvaluator.Models; public class SuccessRateMetrics { diff --git a/eng/tools/ToolDescriptionEvaluator/src/Program.cs b/eng/tools/ToolDescriptionEvaluator/src/Program.cs index 79162ea362..ea05f7a454 100644 --- a/eng/tools/ToolDescriptionEvaluator/src/Program.cs +++ b/eng/tools/ToolDescriptionEvaluator/src/Program.cs @@ -5,13 +5,13 @@ using System.Text; using System.Text.Json; using Microsoft.Extensions.VectorData; -using ToolSelection.Models; -using ToolSelection.Services; -using ToolSelection.VectorDb; +using ToolDescriptionEvaluator.Models; +using ToolDescriptionEvaluator.Services; +using ToolDescriptionEvaluator.VectorDb; -namespace ToolSelection; +namespace ToolDescriptionEvaluator; -class Program +internal class Program { private static readonly HttpClient HttpClient = new(); @@ -386,7 +386,7 @@ static async Task Main(string[] args) } } - await PerformAnalysis(toolNameAndPrompts!, embeddingService, db, toolCount, executionTime, writer, maxResultsPerTest, isCiMode); + await PerformAnalysis(toolNameAndPrompts!, embeddingService, db, toolCount, executionTime, writer, maxResultsPerTest); stopwatchTotal.Stop(); @@ -857,7 +857,14 @@ private static async Task>> SearchToolsAsync(Vect return results; } - private static async Task PerformAnalysis(Dictionary> toolNameWithPrompts, EmbeddingService embeddingService, VectorStoreCollection db, int toolCount, TimeSpan databaseSetupTime, StreamWriter writer, int maxResultsPerTest = 5, bool isCiMode = false) + private static async Task PerformAnalysis( + Dictionary> toolNameWithPrompts, + EmbeddingService embeddingService, + VectorStoreCollection db, + int toolCount, + TimeSpan databaseSetupTime, + StreamWriter writer, + int maxResultsPerTest = 5) { var stopwatch = Stopwatch.StartNew(); int promptCount = 0; diff --git a/eng/tools/ToolDescriptionEvaluator/src/Services/EmbeddingService.cs b/eng/tools/ToolDescriptionEvaluator/src/Services/EmbeddingService.cs index 9dd18f8852..8384b471f5 100644 --- a/eng/tools/ToolDescriptionEvaluator/src/Services/EmbeddingService.cs +++ b/eng/tools/ToolDescriptionEvaluator/src/Services/EmbeddingService.cs @@ -3,9 +3,9 @@ using System.Text; using System.Text.Json; -using ToolSelection.Models; +using ToolDescriptionEvaluator.Models; -namespace ToolSelection.Services; +namespace ToolDescriptionEvaluator.Services; public class EmbeddingService(HttpClient httpClient, string endpoint, string apiKey) { diff --git a/eng/tools/ToolDescriptionEvaluator/src/ToolDescriptionEvaluator.csproj b/eng/tools/ToolDescriptionEvaluator/src/ToolDescriptionEvaluator.csproj index 16950bd99f..b2fa6cb20b 100644 --- a/eng/tools/ToolDescriptionEvaluator/src/ToolDescriptionEvaluator.csproj +++ b/eng/tools/ToolDescriptionEvaluator/src/ToolDescriptionEvaluator.csproj @@ -3,6 +3,7 @@ Exe true + true diff --git a/eng/tools/ToolDescriptionEvaluator/src/VectorDb/InMemoryVectorStoreCollection.cs b/eng/tools/ToolDescriptionEvaluator/src/VectorDb/InMemoryVectorStoreCollection.cs index 57e4cac6e3..bbcb774ad6 100644 --- a/eng/tools/ToolDescriptionEvaluator/src/VectorDb/InMemoryVectorStoreCollection.cs +++ b/eng/tools/ToolDescriptionEvaluator/src/VectorDb/InMemoryVectorStoreCollection.cs @@ -5,7 +5,7 @@ using System.Runtime.CompilerServices; using Microsoft.Extensions.VectorData; -namespace ToolSelection.VectorDb; +namespace ToolDescriptionEvaluator.VectorDb; /// /// An in-memory that keeps records sorted by key @@ -174,7 +174,9 @@ public override Task DeleteAsync(string key, CancellationToken cancellationToken public override IAsyncEnumerable GetAsync(Expression> filter, int top, FilteredRecordRetrievalOptions? options = null, CancellationToken cancellationToken = default) => throw new NotSupportedException("Filtered record retrieval is not supported by the in-memory vector store."); +#pragma warning disable IDE0391 // Make method synchronous public override async IAsyncEnumerable> SearchAsync(TInput searchValue, int top, VectorSearchOptions? options = null, [EnumeratorCancellation] CancellationToken cancellationToken = default) +#pragma warning restore IDE0391 // Make method synchronous { ArgumentNullException.ThrowIfNull(searchValue); diff --git a/eng/tools/ToolDescriptionEvaluator/src/VectorDb/VectorDB.cs b/eng/tools/ToolDescriptionEvaluator/src/VectorDb/VectorDB.cs index ee2e4a16de..2197ee710f 100644 --- a/eng/tools/ToolDescriptionEvaluator/src/VectorDb/VectorDB.cs +++ b/eng/tools/ToolDescriptionEvaluator/src/VectorDb/VectorDB.cs @@ -6,7 +6,7 @@ using System.Runtime.CompilerServices; using Microsoft.Extensions.VectorData; -namespace ToolSelection.VectorDb; +namespace ToolDescriptionEvaluator.VectorDb; /// /// A record stored in the vector database. The properties are annotated with @@ -125,7 +125,9 @@ public override VectorStoreCollection GetCollection> GetDynamicCollection(string name, VectorStoreCollectionDefinition definition) => throw new NotSupportedException("Dynamic collections are not supported by the in-memory vector store."); +#pragma warning disable IDE0391 // Make method synchronous public override async IAsyncEnumerable ListCollectionNamesAsync([EnumeratorCancellation] CancellationToken cancellationToken = default) +#pragma warning restore IDE0391 // Make method synchronous { List names; diff --git a/eng/tools/ToolDescriptionEvaluator/tests/ToolDescriptionEvaluator.UnitTests/InMemoryVectorStoreCollectionTests.cs b/eng/tools/ToolDescriptionEvaluator/tests/ToolDescriptionEvaluator.UnitTests/InMemoryVectorStoreCollectionTests.cs index 5a0f8b7712..f4c8f30b96 100644 --- a/eng/tools/ToolDescriptionEvaluator/tests/ToolDescriptionEvaluator.UnitTests/InMemoryVectorStoreCollectionTests.cs +++ b/eng/tools/ToolDescriptionEvaluator/tests/ToolDescriptionEvaluator.UnitTests/InMemoryVectorStoreCollectionTests.cs @@ -1,12 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using Microsoft.Extensions.VectorData; -using ToolSelection.VectorDb; +using ToolDescriptionEvaluator.VectorDb; using Xunit; namespace ToolDescriptionEvaluator.UnitTests; diff --git a/eng/tools/ToolDescriptionEvaluator/tests/ToolDescriptionEvaluator.UnitTests/VectorDBTests.cs b/eng/tools/ToolDescriptionEvaluator/tests/ToolDescriptionEvaluator.UnitTests/VectorDBTests.cs index c358e41f09..2d6d19efca 100644 --- a/eng/tools/ToolDescriptionEvaluator/tests/ToolDescriptionEvaluator.UnitTests/VectorDBTests.cs +++ b/eng/tools/ToolDescriptionEvaluator/tests/ToolDescriptionEvaluator.UnitTests/VectorDBTests.cs @@ -1,11 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using System; -using System.Collections.Generic; -using System.Threading.Tasks; using Microsoft.Extensions.VectorData; -using ToolSelection.VectorDb; +using ToolDescriptionEvaluator.VectorDb; using Xunit; namespace ToolDescriptionEvaluator.UnitTests; diff --git a/eng/tools/ToolMetadataExporter/src/AppConfiguration.cs b/eng/tools/ToolMetadataExporter/src/AppConfiguration.cs index 5061432393..feec232c03 100644 --- a/eng/tools/ToolMetadataExporter/src/AppConfiguration.cs +++ b/eng/tools/ToolMetadataExporter/src/AppConfiguration.cs @@ -27,7 +27,7 @@ public class AppConfiguration /// /// Folder path where Kusto query files are stored. By default, it is "Resources/queries". - /// Used to load file named + /// Used to load file named /// which fetches current MCP tools. /// public string? QueriesFolder { get; set; } = "Resources/queries"; @@ -39,7 +39,7 @@ public class AppConfiguration /// /// true if the application should run in dry-run mode. In dry-run mode, no events are published to Kusto - /// Changes are written locally to . + /// Changes are written locally to . /// false to publish events to Kusto. /// public bool IsDryRun { get; set; } diff --git a/eng/tools/ToolMetadataExporter/src/Models/CommandLineOptions.cs b/eng/tools/ToolMetadataExporter/src/Models/CommandLineOptions.cs index 4397348da9..c015219066 100644 --- a/eng/tools/ToolMetadataExporter/src/Models/CommandLineOptions.cs +++ b/eng/tools/ToolMetadataExporter/src/Models/CommandLineOptions.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using ToolMetadataExporter.Services; + namespace ToolMetadataExporter.Models; /// diff --git a/eng/tools/ToolMetadataExporter/src/Services/AzmcpProgram.cs b/eng/tools/ToolMetadataExporter/src/Services/AzmcpProgram.cs index 8f9bec22de..c70bae17a3 100644 --- a/eng/tools/ToolMetadataExporter/src/Services/AzmcpProgram.cs +++ b/eng/tools/ToolMetadataExporter/src/Services/AzmcpProgram.cs @@ -4,8 +4,8 @@ using System.Text.RegularExpressions; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using ToolDescriptionEvaluator.Models; using ToolMetadataExporter.Models; -using ToolSelection.Models; namespace ToolMetadataExporter.Services; diff --git a/eng/tools/ToolMetadataExporter/src/ToolAnalyzer.cs b/eng/tools/ToolMetadataExporter/src/ToolAnalyzer.cs index a640938f53..0413e11cd9 100644 --- a/eng/tools/ToolMetadataExporter/src/ToolAnalyzer.cs +++ b/eng/tools/ToolMetadataExporter/src/ToolAnalyzer.cs @@ -3,10 +3,10 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using ToolDescriptionEvaluator.Models; using ToolMetadataExporter.Models; using ToolMetadataExporter.Models.Kusto; using ToolMetadataExporter.Services; -using ToolSelection.Models; namespace ToolMetadataExporter; diff --git a/eng/tools/ToolMetadataExporter/src/ToolMetadataExporter.csproj b/eng/tools/ToolMetadataExporter/src/ToolMetadataExporter.csproj index c8e92375d8..f94096d0c8 100644 --- a/eng/tools/ToolMetadataExporter/src/ToolMetadataExporter.csproj +++ b/eng/tools/ToolMetadataExporter/src/ToolMetadataExporter.csproj @@ -7,6 +7,7 @@ true true + true diff --git a/eng/tools/ToolMetadataExporter/src/Utility.cs b/eng/tools/ToolMetadataExporter/src/Utility.cs index 5ae6969a7d..49955d1b7d 100644 --- a/eng/tools/ToolMetadataExporter/src/Utility.cs +++ b/eng/tools/ToolMetadataExporter/src/Utility.cs @@ -4,7 +4,7 @@ using System.Diagnostics; using System.Text.RegularExpressions; using Microsoft.Extensions.Logging; -using ToolSelection.Models; +using ToolDescriptionEvaluator.Models; namespace ToolMetadataExporter; @@ -213,10 +213,10 @@ private static string EscapeCharacters(string text) /// /// Traverse up from a starting directory to find the repo root. - /// Directory containing or .git). + /// Directory containing or .git). /// /// Directory to start upwards traversal - /// Directory containing or .git + /// Directory containing or .git /// If the solution cannot be found. internal static string FindRepoRoot(string startDir) { diff --git a/eng/tools/ToolMetadataExporter/tests/ToolMetadataExporter.UnitTests/Services/AzmcpProgramTests.cs b/eng/tools/ToolMetadataExporter/tests/ToolMetadataExporter.UnitTests/Services/AzmcpProgramTests.cs index e1e968ac7e..03233af220 100644 --- a/eng/tools/ToolMetadataExporter/tests/ToolMetadataExporter.UnitTests/Services/AzmcpProgramTests.cs +++ b/eng/tools/ToolMetadataExporter/tests/ToolMetadataExporter.UnitTests/Services/AzmcpProgramTests.cs @@ -1,4 +1,7 @@ -using System.Text.Json; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Text.Json; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using NSubstitute; diff --git a/eng/tools/ToolMetadataExporter/tests/ToolMetadataExporter.UnitTests/ToolAnalyzerTests.cs b/eng/tools/ToolMetadataExporter/tests/ToolMetadataExporter.UnitTests/ToolAnalyzerTests.cs index 6362e03eda..ffaf7fe2c7 100644 --- a/eng/tools/ToolMetadataExporter/tests/ToolMetadataExporter.UnitTests/ToolAnalyzerTests.cs +++ b/eng/tools/ToolMetadataExporter/tests/ToolMetadataExporter.UnitTests/ToolAnalyzerTests.cs @@ -1,14 +1,13 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using System; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using NSubstitute; +using ToolDescriptionEvaluator.Models; using ToolMetadataExporter.Models; using ToolMetadataExporter.Models.Kusto; using ToolMetadataExporter.Services; -using ToolSelection.Models; using Xunit; namespace ToolMetadataExporter.UnitTests; diff --git a/servers/Azure.Mcp.Server/src/Program.cs b/servers/Azure.Mcp.Server/src/Program.cs index 43029f5e02..9063dbc485 100644 --- a/servers/Azure.Mcp.Server/src/Program.cs +++ b/servers/Azure.Mcp.Server/src/Program.cs @@ -33,12 +33,12 @@ namespace Azure.Mcp.Server; internal class Program { - private static readonly IAreaSetup[] Areas = RegisterAreas(); + private static readonly IAreaSetup[] s_areas = RegisterAreas(); // Derived from the registered ServerSetup instance so the name stays in sync // with the actual area registration — no magic string duplication. - private static readonly string ServerAreaName = - Array.Find(Areas, static a => a is Microsoft.Mcp.Core.Areas.Server.ServerSetup)?.Name ?? "server"; + private static readonly string s_serverAreaName = + Array.Find(s_areas, static a => a is ServerSetup)?.Name ?? "server"; private static async Task Main(string[] args) { @@ -337,7 +337,7 @@ internal static void ConfigureServices(IServiceCollection services, string? area services.AddAzureTenantService(); services.AddSingleUserCliCacheService(disabled: true); - foreach (var area in Areas) + foreach (var area in s_areas) { // When areaFilter is set (CLI path), skip Azure service areas that don't match the target. // Non-Azure-service areas (Category != AzureServices) provide shared infrastructure @@ -357,7 +357,7 @@ internal static void ConfigureServices(IServiceCollection services, string? area // Optimization: server-mode providers (registry, instructions, plugin allowlists) are only // used when running as an MCP server. For CLI area invocations they are never resolved, so // register lightweight stubs to avoid reading embedded resources on every CLI call. - if (areaFilter == null || string.Equals(areaFilter, ServerAreaName, StringComparison.OrdinalIgnoreCase)) + if (areaFilter == null || string.Equals(areaFilter, s_serverAreaName, StringComparison.OrdinalIgnoreCase)) { services.AddRegistryRoot(thisAssembly, $"registry.json"); @@ -446,7 +446,7 @@ internal static async Task InitializeServicesAsync(IServiceProvider serviceProvi // Only apply the optimization when the first token is a known registered area. // If the token doesn't match any area (e.g. a typo), fall through to full initialization // so System.CommandLine can produce helpful "Did you mean..." suggestions. - if (!Array.Exists(Areas, a => string.Equals(a.Name, firstToken, StringComparison.OrdinalIgnoreCase))) + if (!Array.Exists(s_areas, a => string.Equals(a.Name, firstToken, StringComparison.OrdinalIgnoreCase))) { return null; } diff --git a/servers/Azure.Mcp.Server/src/Properties/AssemblyInfo.cs b/servers/Azure.Mcp.Server/src/Properties/AssemblyInfo.cs index ac3708f3da..4af0c4e177 100644 --- a/servers/Azure.Mcp.Server/src/Properties/AssemblyInfo.cs +++ b/servers/Azure.Mcp.Server/src/Properties/AssemblyInfo.cs @@ -1,2 +1,5 @@ -[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Azure.Mcp.Core.Tests")] +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Azure.Mcp.Core.Tests")] [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Azure.Mcp.Server.Tests")] diff --git a/servers/Fabric.Mcp.Server/src/Program.cs b/servers/Fabric.Mcp.Server/src/Program.cs index 376688946b..113d2d689a 100644 --- a/servers/Fabric.Mcp.Server/src/Program.cs +++ b/servers/Fabric.Mcp.Server/src/Program.cs @@ -157,7 +157,7 @@ private static void WriteResponse(CommandResponse response) /// /// /// For example, most instances take an indirect dependency - /// on or , both of which have + /// on ITenantService or , both of which have /// transport-specific implementations. This method can add the stdio-specific /// implementation to allow the first container (used for command picking) to work, /// but such transport-specific registrations must be overridden within diff --git a/servers/Template.Mcp.Server/src/Program.cs b/servers/Template.Mcp.Server/src/Program.cs index 348a4aca95..dd3e48a6d7 100644 --- a/servers/Template.Mcp.Server/src/Program.cs +++ b/servers/Template.Mcp.Server/src/Program.cs @@ -153,7 +153,7 @@ private static void WriteResponse(CommandResponse response) /// /// /// For example, most instances take an indirect dependency - /// on or , both of which have + /// on ITenantService or , both of which have /// transport-specific implementations. This method can add the stdio-specific /// implementation to allow the first container (used for command picking) to work, /// but such transport-specific registrations must be overridden within diff --git a/tools/Azure.Mcp.Tools.Acr/src/Services/AcrService.cs b/tools/Azure.Mcp.Tools.Acr/src/Services/AcrService.cs index d767233df3..ea82b2bfdc 100644 --- a/tools/Azure.Mcp.Tools.Acr/src/Services/AcrService.cs +++ b/tools/Azure.Mcp.Tools.Acr/src/Services/AcrService.cs @@ -8,18 +8,15 @@ using Azure.Mcp.Core.Services.Azure.Subscription; using Azure.Mcp.Core.Services.Azure.Tenant; using Azure.Mcp.Tools.Acr.Models; -using Microsoft.Extensions.Logging; using Microsoft.Mcp.Core.Helpers; using Microsoft.Mcp.Core.Options; using Microsoft.Mcp.Core.Services.Azure.Authentication; namespace Azure.Mcp.Tools.Acr.Services; -public sealed class AcrService(ISubscriptionService subscriptionService, ITenantService tenantService, ILogger logger) +public sealed class AcrService(ISubscriptionService subscriptionService, ITenantService tenantService) : BaseAzureResourceService(subscriptionService, tenantService), IAcrService { - private readonly ILogger _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - public async Task> ListRegistries( string subscription, string? resourceGroup = null, diff --git a/tools/Azure.Mcp.Tools.Acr/tests/Azure.Mcp.Tools.Acr.Tests/AcrCommandTests.cs b/tools/Azure.Mcp.Tools.Acr/tests/Azure.Mcp.Tools.Acr.Tests/AcrCommandTests.cs index da9bd1dc61..e2bfe5bb4d 100644 --- a/tools/Azure.Mcp.Tools.Acr/tests/Azure.Mcp.Tools.Acr.Tests/AcrCommandTests.cs +++ b/tools/Azure.Mcp.Tools.Acr/tests/Azure.Mcp.Tools.Acr.Tests/AcrCommandTests.cs @@ -127,18 +127,4 @@ public async Task Should_list_repositories_for_registries(AuthMethod authMethod) var repos = repoArray.EnumerateArray().Select(e => e.GetString()).Where(s => !string.IsNullOrWhiteSpace(s)).ToList(); Assert.Contains("testrepo", repos); } - - [Fact] - public async Task Should_handle_empty_subscription_gracefully() - { - // Empty subscription should trigger validation failure (400) -> null results - var result = await CallToolAsync( - "acr_registry_list", - new() - { - { "subscription", "" } - }); - - Assert.Null(result); - } } diff --git a/tools/Azure.Mcp.Tools.Acr/tests/Azure.Mcp.Tools.Acr.Tests/AssemblyAttributes.cs b/tools/Azure.Mcp.Tools.Acr/tests/Azure.Mcp.Tools.Acr.Tests/AssemblyAttributes.cs index 69da1d7967..9068d23bfb 100644 --- a/tools/Azure.Mcp.Tools.Acr/tests/Azure.Mcp.Tools.Acr.Tests/AssemblyAttributes.cs +++ b/tools/Azure.Mcp.Tools.Acr/tests/Azure.Mcp.Tools.Acr.Tests/AssemblyAttributes.cs @@ -1,2 +1,5 @@ -[assembly: Microsoft.Mcp.Tests.Helpers.ClearEnvironmentVariablesBeforeTest] +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +[assembly: Microsoft.Mcp.Tests.Helpers.ClearEnvironmentVariablesBeforeTest] [assembly: Xunit.CollectionBehavior(Xunit.CollectionBehavior.CollectionPerAssembly)] diff --git a/tools/Azure.Mcp.Tools.Advisor/src/Commands/AdvisorJsonContext.cs b/tools/Azure.Mcp.Tools.Advisor/src/Commands/AdvisorJsonContext.cs index 449937a001..0eca5104ae 100644 --- a/tools/Azure.Mcp.Tools.Advisor/src/Commands/AdvisorJsonContext.cs +++ b/tools/Azure.Mcp.Tools.Advisor/src/Commands/AdvisorJsonContext.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + using System.Text.Json.Serialization; using Azure.Mcp.Tools.Advisor.Commands.Metadata; using Azure.Mcp.Tools.Advisor.Commands.Recommendation; diff --git a/tools/Azure.Mcp.Tools.Advisor/src/Commands/Metadata/MetadataGetCommand.cs b/tools/Azure.Mcp.Tools.Advisor/src/Commands/Metadata/MetadataGetCommand.cs index aca21066ea..da96005608 100644 --- a/tools/Azure.Mcp.Tools.Advisor/src/Commands/Metadata/MetadataGetCommand.cs +++ b/tools/Azure.Mcp.Tools.Advisor/src/Commands/Metadata/MetadataGetCommand.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using System.Linq; using System.Net; using Azure.Mcp.Tools.Advisor.Options.Metadata; using Azure.Mcp.Tools.Advisor.Services; diff --git a/tools/Azure.Mcp.Tools.Advisor/src/Services/AdvisorService.cs b/tools/Azure.Mcp.Tools.Advisor/src/Services/AdvisorService.cs index b0101f5e7e..5ea8be0172 100644 --- a/tools/Azure.Mcp.Tools.Advisor/src/Services/AdvisorService.cs +++ b/tools/Azure.Mcp.Tools.Advisor/src/Services/AdvisorService.cs @@ -5,7 +5,6 @@ using Azure.Mcp.Core.Services.Azure; using Azure.Mcp.Core.Services.Azure.Subscription; using Azure.Mcp.Core.Services.Azure.Tenant; -using Azure.Mcp.Tools.Advisor.Commands; using Azure.Mcp.Tools.Advisor.Models; using Azure.ResourceManager.ResourceGraph; using Azure.ResourceManager.ResourceGraph.Models; diff --git a/tools/Azure.Mcp.Tools.Advisor/src/Services/Models/RecommendationData.cs b/tools/Azure.Mcp.Tools.Advisor/src/Services/Models/RecommendationData.cs index 60fb7b6248..03bb7f8cf3 100644 --- a/tools/Azure.Mcp.Tools.Advisor/src/Services/Models/RecommendationData.cs +++ b/tools/Azure.Mcp.Tools.Advisor/src/Services/Models/RecommendationData.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System.Text.Json; diff --git a/tools/Azure.Mcp.Tools.Advisor/src/Services/Models/RecommendationDescription.cs b/tools/Azure.Mcp.Tools.Advisor/src/Services/Models/RecommendationDescription.cs index 84c5000ecb..5b3a4a4093 100644 --- a/tools/Azure.Mcp.Tools.Advisor/src/Services/Models/RecommendationDescription.cs +++ b/tools/Azure.Mcp.Tools.Advisor/src/Services/Models/RecommendationDescription.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. namespace Azure.Mcp.Tools.Advisor.Services.Models; diff --git a/tools/Azure.Mcp.Tools.Advisor/src/Services/Models/RecommendationProperties.cs b/tools/Azure.Mcp.Tools.Advisor/src/Services/Models/RecommendationProperties.cs index 8442fea2c1..63899fb86e 100644 --- a/tools/Azure.Mcp.Tools.Advisor/src/Services/Models/RecommendationProperties.cs +++ b/tools/Azure.Mcp.Tools.Advisor/src/Services/Models/RecommendationProperties.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System.Text.Json.Serialization; diff --git a/tools/Azure.Mcp.Tools.Advisor/src/Services/Models/RecommendationResourceMetadata.cs b/tools/Azure.Mcp.Tools.Advisor/src/Services/Models/RecommendationResourceMetadata.cs index 3fcc88842d..233d8471b5 100644 --- a/tools/Azure.Mcp.Tools.Advisor/src/Services/Models/RecommendationResourceMetadata.cs +++ b/tools/Azure.Mcp.Tools.Advisor/src/Services/Models/RecommendationResourceMetadata.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. namespace Azure.Mcp.Tools.Advisor.Services.Models; diff --git a/tools/Azure.Mcp.Tools.Aks/src/Services/AksService.cs b/tools/Azure.Mcp.Tools.Aks/src/Services/AksService.cs index a9d86fda61..db80a12add 100644 --- a/tools/Azure.Mcp.Tools.Aks/src/Services/AksService.cs +++ b/tools/Azure.Mcp.Tools.Aks/src/Services/AksService.cs @@ -8,8 +8,6 @@ using Azure.Mcp.Tools.Aks.Commands; using Azure.Mcp.Tools.Aks.Models; using Azure.ResourceManager.ContainerService; -using Azure.ResourceManager.ContainerService.Models; -using Microsoft.Extensions.Logging; using Microsoft.Mcp.Core.Options; using Microsoft.Mcp.Core.Services.Caching; @@ -18,12 +16,10 @@ namespace Azure.Mcp.Tools.Aks.Services; public sealed class AksService( ISubscriptionService subscriptionService, ITenantService tenantService, - ICacheService cacheService, - ILogger logger) : BaseAzureResourceService(subscriptionService, tenantService), IAksService + ICacheService cacheService) : BaseAzureResourceService(subscriptionService, tenantService), IAksService { private readonly ISubscriptionService _subscriptionService = subscriptionService ?? throw new ArgumentNullException(nameof(subscriptionService)); private readonly ICacheService _cacheService = cacheService ?? throw new ArgumentNullException(nameof(cacheService)); - private readonly ILogger _logger = logger; private const string CacheGroup = "aks"; private const string AksClustersCacheKey = "clusters"; @@ -391,51 +387,4 @@ private static NodePool ConvertToNodePoolModel(ContainerServiceAgentPoolResource VnetSubnetId = data.VnetSubnetId }; } - - private static NodePool ConvertToNodePoolModel(ManagedClusterAgentPoolProfile profile) - { - return new() - { - Name = profile.Name, - Count = profile.Count, - VmSize = profile.VmSize?.ToString(), - OsDiskSizeGB = profile.OSDiskSizeInGB, - OsDiskType = profile.OSDiskType?.ToString(), - KubeletDiskType = profile.KubeletDiskType?.ToString(), - MaxPods = profile.MaxPods, - Type = profile.AgentPoolType?.ToString(), - MaxCount = profile.MaxCount, - MinCount = profile.MinCount, - EnableAutoScaling = profile.EnableAutoScaling, - ScaleDownMode = profile.ScaleDownMode?.ToString(), - ProvisioningState = profile.ProvisioningState?.ToString(), - PowerState = profile.PowerStateCode.HasValue ? new() { Code = profile.PowerStateCode.Value.ToString() } : null, - Mode = profile.Mode?.ToString(), - OrchestratorVersion = profile.OrchestratorVersion, - CurrentOrchestratorVersion = profile.CurrentOrchestratorVersion, - EnableNodePublicIP = profile.EnableNodePublicIP, - ScaleSetPriority = profile.ScaleSetPriority?.ToString(), - ScaleSetEvictionPolicy = profile.ScaleSetEvictionPolicy?.ToString(), - NodeLabels = profile.NodeLabels?.ToDictionary(kvp => kvp.Key, kvp => kvp.Value), - NodeTaints = profile.NodeTaints?.ToList(), - OsType = profile.OSType?.ToString(), - OsSKU = profile.OSSku?.ToString(), - NodeImageVersion = profile.NodeImageVersion, - Tags = profile.Tags?.ToDictionary(kvp => kvp.Key, kvp => kvp.Value), - SpotMaxPrice = profile.SpotMaxPrice, - WorkloadRuntime = profile.WorkloadRuntime?.ToString(), - EnableEncryptionAtHost = profile.EnableEncryptionAtHost, - EnableUltraSSD = profile.EnableUltraSsd, - EnableFIPS = profile.EnableFips, - // Profiles don't expose GPU/Security sub-objects in this API shape - NetworkProfile = profile.NetworkProfile is null ? null : new() - { - AllowedHostPorts = profile.NetworkProfile.AllowedHostPorts?.Select(p => new PortRange { StartPort = p.PortStart, EndPort = p.PortEnd }).ToList(), - ApplicationSecurityGroups = profile.NetworkProfile.ApplicationSecurityGroups?.Select(rid => rid.ToString()).ToList(), - NodePublicIPTags = profile.NetworkProfile.NodePublicIPTags?.Select(t => new IPTag { IpTagType = t.IPTagType, Tag = t.Tag }).ToList() - }, - PodSubnetId = profile.PodSubnetId?.ToString(), - VnetSubnetId = profile.VnetSubnetId?.ToString() - }; - } } diff --git a/tools/Azure.Mcp.Tools.AppConfig/src/Models/KeyValueSetting.cs b/tools/Azure.Mcp.Tools.AppConfig/src/Models/KeyValueSetting.cs index 0820e9ed43..49fe44e870 100644 --- a/tools/Azure.Mcp.Tools.AppConfig/src/Models/KeyValueSetting.cs +++ b/tools/Azure.Mcp.Tools.AppConfig/src/Models/KeyValueSetting.cs @@ -3,15 +3,13 @@ namespace Azure.Mcp.Tools.AppConfig.Models; -using ETag = Microsoft.Mcp.Core.Models.ETag; - public class KeyValueSetting { public string Key { get; set; } = string.Empty; public string Value { get; set; } = string.Empty; public string Label { get; set; } = string.Empty; public string ContentType { get; set; } = string.Empty; - public ETag ETag { get; set; } = new(); + public Microsoft.Mcp.Core.Models.ETag ETag { get; set; } = new(); public DateTimeOffset? LastModified { get; set; } public bool? Locked { get; set; } } diff --git a/tools/Azure.Mcp.Tools.AppConfig/src/Services/AppConfigService.cs b/tools/Azure.Mcp.Tools.AppConfig/src/Services/AppConfigService.cs index 0d8f0356ac..d118262d2d 100644 --- a/tools/Azure.Mcp.Tools.AppConfig/src/Services/AppConfigService.cs +++ b/tools/Azure.Mcp.Tools.AppConfig/src/Services/AppConfigService.cs @@ -8,7 +8,6 @@ using Azure.Mcp.Core.Services.Azure.Subscription; using Azure.Mcp.Core.Services.Azure.Tenant; using Azure.Mcp.Tools.AppConfig.Models; -using Microsoft.Extensions.Logging; using Microsoft.Mcp.Core.Helpers; using Microsoft.Mcp.Core.Models.Identity; using Microsoft.Mcp.Core.Options; @@ -16,12 +15,9 @@ namespace Azure.Mcp.Tools.AppConfig.Services; -using ETag = Microsoft.Mcp.Core.Models.ETag; - -public sealed class AppConfigService(ISubscriptionService subscriptionService, ITenantService tenantService, ILogger logger, IHttpClientFactory httpClientFactory) +public sealed class AppConfigService(ISubscriptionService subscriptionService, ITenantService tenantService, IHttpClientFactory httpClientFactory) : BaseAzureResourceService(subscriptionService, tenantService), IAppConfigService { - private readonly ILogger _logger = logger ?? throw new ArgumentNullException(nameof(logger)); private readonly IHttpClientFactory _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory)); public async Task> GetAppConfigAccounts( diff --git a/tools/Azure.Mcp.Tools.AppLens/src/Services/AppLensService.cs b/tools/Azure.Mcp.Tools.AppLens/src/Services/AppLensService.cs index ca7a43bc8e..5b156f1841 100644 --- a/tools/Azure.Mcp.Tools.AppLens/src/Services/AppLensService.cs +++ b/tools/Azure.Mcp.Tools.AppLens/src/Services/AppLensService.cs @@ -16,7 +16,6 @@ using Azure.ResourceManager.ResourceGraph.Models; using Microsoft.AspNetCore.SignalR.Client; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using Microsoft.Mcp.Core.Helpers; using Microsoft.Mcp.Core.Services.Azure.Authentication; @@ -30,13 +29,11 @@ namespace Azure.Mcp.Tools.AppLens.Services; public class AppLensService( IHttpClientFactory httpClientFactory, ISubscriptionService subscriptionService, - ITenantService tenantService, - ILogger logger) : BaseAzureResourceService(subscriptionService, tenantService), IAppLensService + ITenantService tenantService) : BaseAzureResourceService(subscriptionService, tenantService), IAppLensService { private readonly ISubscriptionService _subscriptionService = subscriptionService ?? throw new ArgumentNullException(nameof(subscriptionService)); private readonly ITenantService _tenantService = tenantService ?? throw new ArgumentNullException(nameof(tenantService)); private readonly IHttpClientFactory _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory)); - private readonly ILogger _logger = logger ?? throw new ArgumentNullException(nameof(logger)); private readonly AppLensOptions _options = new(); /// @@ -313,7 +310,7 @@ private async Task GetAppLensSessionAsync(string resour /// /// The question or query to pose to AppLens. /// The representing the overall conversation. - /// A cancellation token to cancel the request. + /// The token to monitor for cancellation requests. The default value is . public async IAsyncEnumerable AskAppLensAsync( AppLensSession session, string question, @@ -442,6 +439,7 @@ public async IAsyncEnumerable AskAppLensAsync( /// /// The AppLens session. /// The diagnostic question. + /// The token to monitor for cancellation requests. /// A task containing diagnostic insights and solutions. private async Task CollectInsightsAsync(AppLensSession session, string question, CancellationToken cancellationToken) { diff --git a/tools/Azure.Mcp.Tools.AppLens/src/Services/IAppLensService.cs b/tools/Azure.Mcp.Tools.AppLens/src/Services/IAppLensService.cs index 08c988eeff..2b2565b995 100644 --- a/tools/Azure.Mcp.Tools.AppLens/src/Services/IAppLensService.cs +++ b/tools/Azure.Mcp.Tools.AppLens/src/Services/IAppLensService.cs @@ -20,7 +20,7 @@ public interface IAppLensService /// Optional resource group to narrow down resource discovery. /// Optional resource type to narrow down resource discovery. /// Optional tenant ID for authentication. - /// Cancellation token. + /// The token to monitor for cancellation requests. The default value is . /// A diagnostic result containing insights and solutions. Task DiagnoseResourceAsync( string question, diff --git a/tools/Azure.Mcp.Tools.AppService/src/Models/DetectorDetails.cs b/tools/Azure.Mcp.Tools.AppService/src/Models/DetectorDetails.cs index 0faca97358..a3f719d7ba 100644 --- a/tools/Azure.Mcp.Tools.AppService/src/Models/DetectorDetails.cs +++ b/tools/Azure.Mcp.Tools.AppService/src/Models/DetectorDetails.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation.Expand commentComment on line R1Resolved +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System.Text.Json.Serialization; diff --git a/tools/Azure.Mcp.Tools.AppService/src/Models/DiagnosisResult.cs b/tools/Azure.Mcp.Tools.AppService/src/Models/DiagnosisResult.cs index 97eec1c566..32f2930a68 100644 --- a/tools/Azure.Mcp.Tools.AppService/src/Models/DiagnosisResult.cs +++ b/tools/Azure.Mcp.Tools.AppService/src/Models/DiagnosisResult.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation.Expand commentComment on line R1Resolved +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System.Text.Json.Serialization; diff --git a/tools/Azure.Mcp.Tools.ApplicationInsights/src/Services/ApplicationInsightsService.cs b/tools/Azure.Mcp.Tools.ApplicationInsights/src/Services/ApplicationInsightsService.cs index 519c1d4296..7c25744ecf 100644 --- a/tools/Azure.Mcp.Tools.ApplicationInsights/src/Services/ApplicationInsightsService.cs +++ b/tools/Azure.Mcp.Tools.ApplicationInsights/src/Services/ApplicationInsightsService.cs @@ -7,7 +7,6 @@ using Azure.Mcp.Core.Services.Azure.Subscription; using Azure.Mcp.Core.Services.Azure.Tenant; using Azure.ResourceManager.ApplicationInsights; -using Microsoft.Extensions.Logging; using Microsoft.Mcp.Core.Options; namespace Azure.Mcp.Tools.ApplicationInsights.Services; @@ -16,14 +15,12 @@ public class ApplicationInsightsService( ISubscriptionService subscriptionService, ITenantService tenantService, IResourceGroupService resourceGroupService, - IProfilerDataService profilerDataClient, - ILogger logger) : BaseAzureService(tenantService), IApplicationInsightsService + IProfilerDataService profilerDataClient) : BaseAzureService(tenantService), IApplicationInsightsService { private const int MaxRecommendations = 20; private readonly ISubscriptionService _subscriptionService = subscriptionService; private readonly IResourceGroupService _resourceGroupService = resourceGroupService; private readonly IProfilerDataService _profilerDataClient = profilerDataClient ?? throw new ArgumentNullException(nameof(profilerDataClient)); - private readonly ILogger _logger = logger ?? throw new ArgumentNullException(nameof(logger)); public async Task> GetProfilerInsightsAsync( string subscription, diff --git a/tools/Azure.Mcp.Tools.ApplicationInsights/src/Services/IProfilerDataService.cs b/tools/Azure.Mcp.Tools.ApplicationInsights/src/Services/IProfilerDataService.cs index 02e4d451bc..bfd879b2b0 100644 --- a/tools/Azure.Mcp.Tools.ApplicationInsights/src/Services/IProfilerDataService.cs +++ b/tools/Azure.Mcp.Tools.ApplicationInsights/src/Services/IProfilerDataService.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + using System.Text.Json.Nodes; using Azure.Core; diff --git a/tools/Azure.Mcp.Tools.ApplicationInsights/src/Services/ProfilerDataService.cs b/tools/Azure.Mcp.Tools.ApplicationInsights/src/Services/ProfilerDataService.cs index 66e3a27943..0468de67d6 100644 --- a/tools/Azure.Mcp.Tools.ApplicationInsights/src/Services/ProfilerDataService.cs +++ b/tools/Azure.Mcp.Tools.ApplicationInsights/src/Services/ProfilerDataService.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + using System.Collections.Specialized; using System.Net.Http.Headers; using System.Net.Http.Json; @@ -170,10 +173,11 @@ private async Task CreateRequestAsync(HttpMethod method, str /// /// The path /// Optional queries to append to the path. + /// The API version to use. /// Optional client request ID. /// The content of the incoming request. /// Additional headers to be added to the request - /// A cancellation token. + /// The token to monitor for cancellation requests. internal async ValueTask PostAsync(string path, IDictionary? queries, string apiVersion, string? clientRequestId, HttpContent? httpContent, IDictionary>? additionalHeaders, CancellationToken cancellationToken) { using HttpRequestMessage request = await CreateRequestAsync(HttpMethod.Post, path, queries, apiVersion, clientRequestId, httpContent, additionalHeaders, cancellationToken); diff --git a/tools/Azure.Mcp.Tools.Authorization/src/Services/IAuthorizationService.cs b/tools/Azure.Mcp.Tools.Authorization/src/Services/IAuthorizationService.cs index 63a3b4cc18..e4f036c137 100644 --- a/tools/Azure.Mcp.Tools.Authorization/src/Services/IAuthorizationService.cs +++ b/tools/Azure.Mcp.Tools.Authorization/src/Services/IAuthorizationService.cs @@ -16,7 +16,7 @@ public interface IAuthorizationService /// The scope that the resource will apply against. /// Optional tenant ID for cross-tenant operations. /// Optional retry policy for the operation. - /// Optional cancellation token for the operation. + /// The token to monitor for cancellation requests. The default value is . /// List of role assignments in the format "Role Definition ID: Principal ID" Task> ListRoleAssignmentsAsync( string subscription, diff --git a/tools/Azure.Mcp.Tools.AzureBackup/src/Services/Policy/PolicyCreateValidator.cs b/tools/Azure.Mcp.Tools.AzureBackup/src/Services/Policy/PolicyCreateValidator.cs index c003e47e7d..e1a56c9c56 100644 --- a/tools/Azure.Mcp.Tools.AzureBackup/src/Services/Policy/PolicyCreateValidator.cs +++ b/tools/Azure.Mcp.Tools.AzureBackup/src/Services/Policy/PolicyCreateValidator.cs @@ -661,12 +661,4 @@ private static void EnsureFamily(bool value, string flag, WorkloadFamily actual, issues.Add(new PolicyValidationIssue(flag, $"{flag} is supported only for {requiredLabel} workloads.")); } } - - private static void EnsureDpp(string? value, string flag, WorkloadFamily actual, List issues) - { - if (!string.IsNullOrWhiteSpace(value) && IsRsvFamily(actual)) - { - issues.Add(new PolicyValidationIssue(flag, $"{flag} is supported only for DPP (Backup vault) workloads.")); - } - } } diff --git a/tools/Azure.Mcp.Tools.AzureBackup/src/Services/Policy/RsvPolicyBuilder.cs b/tools/Azure.Mcp.Tools.AzureBackup/src/Services/Policy/RsvPolicyBuilder.cs index e2199961db..c20c0fa42d 100644 --- a/tools/Azure.Mcp.Tools.AzureBackup/src/Services/Policy/RsvPolicyBuilder.cs +++ b/tools/Azure.Mcp.Tools.AzureBackup/src/Services/Policy/RsvPolicyBuilder.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using System.Globalization; -using System.Linq; using Azure.ResourceManager.RecoveryServicesBackup.Models; namespace Azure.Mcp.Tools.AzureBackup.Services.Policy; @@ -188,41 +187,6 @@ private static SubProtectionPolicy BuildVmWorkloadFullSubPolicy(PolicyCreateRequ return sub; } - private static SubProtectionPolicy BuildVmWorkloadSnapshotSubPolicy(PolicyCreateRequest req, IList scheduleTimes) - { - // Retained for backward-compatibility with existing unit tests; not currently invoked by Build(). - var schedule = new SimpleSchedulePolicy { ScheduleRunFrequency = ScheduleRunType.Daily }; - foreach (var t in scheduleTimes) - { - schedule.ScheduleRunTimes.Add(t); - } - - var snapshotDays = TryParsePositiveInt(req.SnapshotInstantRpRetentionDays, out var rpDays) ? rpDays : 2; - var retention = new SimpleRetentionPolicy - { - RetentionDuration = new RetentionDuration { Count = snapshotDays, DurationType = RetentionDurationType.Days }, - }; - - var sub = new SubProtectionPolicy - { - PolicyType = new SubProtectionPolicyType("SnapshotCopyOnlyFull"), - SchedulePolicy = schedule, - RetentionPolicy = retention, - }; - - var details = new SnapshotBackupAdditionalDetails - { - InstantRpRetentionRangeInDays = snapshotDays, - }; - if (!string.IsNullOrWhiteSpace(req.SnapshotInstantRpResourceGroup)) - { - details.InstantRPDetails = req.SnapshotInstantRpResourceGroup; - } - sub.SnapshotBackupAdditionalDetails = details; - - return sub; - } - private static void AttachSnapshotDetailsToFullSubPolicy(VmWorkloadProtectionPolicy policy, PolicyCreateRequest req) { // Per Az CLI: snapshot backup for SAPHANA is enabled by adding SnapshotBackupAdditionalDetails @@ -814,18 +778,6 @@ private static bool TryParsePositiveInt(string? text, out int value) private static bool IsWeeklyFrequency(ScheduleRunType? frequency) => frequency == ScheduleRunType.Weekly; - private static bool HasAnyText(params string?[] values) - { - foreach (var v in values) - { - if (!string.IsNullOrWhiteSpace(v)) - { - return true; - } - } - return false; - } - private static string Capitalize(string text) { if (string.IsNullOrEmpty(text)) diff --git a/tools/Azure.Mcp.Tools.AzureIsv/src/Services/IDatadogService.cs b/tools/Azure.Mcp.Tools.AzureIsv/src/Services/IDatadogService.cs index 2fd7a6eb61..b06108ea1f 100644 --- a/tools/Azure.Mcp.Tools.AzureIsv/src/Services/IDatadogService.cs +++ b/tools/Azure.Mcp.Tools.AzureIsv/src/Services/IDatadogService.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using Azure.Identity; + namespace Azure.Mcp.Tools.AzureIsv.Services; public interface IDatadogService @@ -11,6 +13,7 @@ public interface IDatadogService /// The name of the resource group containing the Datadog resource. /// The subscription ID or name where the resource group resides. /// The name of the Datadog resource to query. + /// The token to monitor for cancellation requests. The default value is . /// A list of monitored resources. /// Thrown when authentication fails. /// Thrown when the service request fails. diff --git a/tools/Azure.Mcp.Tools.AzureMigrate/src/Services/IPlatformLandingZoneGuidanceService.cs b/tools/Azure.Mcp.Tools.AzureMigrate/src/Services/IPlatformLandingZoneGuidanceService.cs index f346970ec4..7f6d9e60a8 100644 --- a/tools/Azure.Mcp.Tools.AzureMigrate/src/Services/IPlatformLandingZoneGuidanceService.cs +++ b/tools/Azure.Mcp.Tools.AzureMigrate/src/Services/IPlatformLandingZoneGuidanceService.cs @@ -14,14 +14,14 @@ public interface IPlatformLandingZoneGuidanceService /// Fetches platform landing zone modification guidance for a specific scenario. /// /// The scenario key (e.g., 'bastion', 'ddos', 'policy-assignment'). - /// The cancellation token. + /// The token to monitor for cancellation requests. The default value is . /// The official documentation for the scenario. Task GetGuidanceAsync(string scenario, CancellationToken cancellationToken = default); /// /// Gets all policies organized by archetype. /// - /// The cancellation token. + /// The token to monitor for cancellation requests. The default value is . /// Dictionary of archetype name to list of policy names. Task>> GetAllPoliciesAsync(CancellationToken cancellationToken = default); @@ -29,7 +29,7 @@ public interface IPlatformLandingZoneGuidanceService /// Searches for policies matching a search term across all archetypes. /// /// Partial or full policy name to search for (case-insensitive). - /// The cancellation token. + /// The token to monitor for cancellation requests. The default value is . /// List of matching policies with their archetype locations. Task> SearchPoliciesAsync(string searchTerm, CancellationToken cancellationToken = default); } diff --git a/tools/Azure.Mcp.Tools.AzureMigrate/src/Services/IPlatformLandingZoneService.cs b/tools/Azure.Mcp.Tools.AzureMigrate/src/Services/IPlatformLandingZoneService.cs index 98d766883f..6623964cb4 100644 --- a/tools/Azure.Mcp.Tools.AzureMigrate/src/Services/IPlatformLandingZoneService.cs +++ b/tools/Azure.Mcp.Tools.AzureMigrate/src/Services/IPlatformLandingZoneService.cs @@ -24,7 +24,7 @@ public interface IPlatformLandingZoneService /// The environment name. /// The version control system. /// The organization name. - /// The cancellation token. + /// The token to monitor for cancellation requests. The default value is . /// The updated parameters. Task UpdateParametersAsync( PlatformLandingZoneContext context, @@ -44,7 +44,7 @@ Task UpdateParametersAsync( /// Checks if a platform landing zone already exists for the given context. /// /// The landing zone context. - /// The cancellation token. + /// The token to monitor for cancellation requests. The default value is . /// True if platform landing zone exists, false otherwise. Task CheckExistingAsync( PlatformLandingZoneContext context, @@ -54,7 +54,7 @@ Task CheckExistingAsync( /// Generates a platform landing zone. /// /// The landing zone context. - /// The cancellation token. + /// The token to monitor for cancellation requests. The default value is . /// The download URL if successful, null otherwise. Task GenerateAsync( PlatformLandingZoneContext context, @@ -65,7 +65,7 @@ Task CheckExistingAsync( /// /// The platform landing zone context. /// The output path for the downloaded file. - /// The cancellation token. + /// The token to monitor for cancellation requests. The default value is . /// The path to the downloaded file. Task DownloadAsync( PlatformLandingZoneContext context, diff --git a/tools/Azure.Mcp.Tools.CloudArchitect/tests/Azure.Mcp.Tools.CloudArchitect.Tests/Design/DesignCommandTests.cs b/tools/Azure.Mcp.Tools.CloudArchitect/tests/Azure.Mcp.Tools.CloudArchitect.Tests/Design/DesignCommandTests.cs index c734c7f029..1ce819a610 100644 --- a/tools/Azure.Mcp.Tools.CloudArchitect/tests/Azure.Mcp.Tools.CloudArchitect.Tests/Design/DesignCommandTests.cs +++ b/tools/Azure.Mcp.Tools.CloudArchitect/tests/Azure.Mcp.Tools.CloudArchitect.Tests/Design/DesignCommandTests.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using System.Net; -using System.Reflection; using Azure.Mcp.Tools.CloudArchitect.Commands.Design; using Microsoft.Mcp.Core.Commands; using Microsoft.Mcp.Tests.Client; diff --git a/tools/Azure.Mcp.Tools.Communication/src/Services/ICommunicationService.cs b/tools/Azure.Mcp.Tools.Communication/src/Services/ICommunicationService.cs index 8b1fac1553..059ccfcbb9 100644 --- a/tools/Azure.Mcp.Tools.Communication/src/Services/ICommunicationService.cs +++ b/tools/Azure.Mcp.Tools.Communication/src/Services/ICommunicationService.cs @@ -32,7 +32,9 @@ Task> SendSmsAsync( /// Optional CC recipient email addresses. /// Optional BCC recipient email addresses. /// Optional reply-to addresses. + /// Optional tenant ID. /// Optional retry policy options. + /// The token to monitor for cancellation requests. The default value is . /// The result of the email send operation. Task SendEmailAsync( string endpoint, diff --git a/tools/Azure.Mcp.Tools.Deploy/src/Services/Util/DeploymentPlanTemplateUtil.cs b/tools/Azure.Mcp.Tools.Deploy/src/Services/Util/DeploymentPlanTemplateUtil.cs index d3124a837a..89330eb366 100644 --- a/tools/Azure.Mcp.Tools.Deploy/src/Services/Util/DeploymentPlanTemplateUtil.cs +++ b/tools/Azure.Mcp.Tools.Deploy/src/Services/Util/DeploymentPlanTemplateUtil.cs @@ -18,7 +18,11 @@ public static class DeploymentPlanTemplateUtil /// The name of the project. Can be null or empty. /// The target Azure service. /// The provisioning tool. + /// The source type. + /// The deployment option. /// The Infrastructure as Code options for AZD. + /// The subscription ID for the deployment. + /// The resource group name for the deployment. /// A formatted deployment plan template string. public static string GetPlanTemplate(string projectName, string targetAppService, string provisioningTool, string sourceType, string deployOption, string? iacOptions, string? subscriptionId, string? resourceGroupName) { diff --git a/tools/Azure.Mcp.Tools.EventGrid/src/AssemblyInfo.cs b/tools/Azure.Mcp.Tools.EventGrid/src/AssemblyInfo.cs index 7349d96eaa..734be064df 100644 --- a/tools/Azure.Mcp.Tools.EventGrid/src/AssemblyInfo.cs +++ b/tools/Azure.Mcp.Tools.EventGrid/src/AssemblyInfo.cs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Azure.Mcp.Tools.EventGrid.Tests")] diff --git a/tools/Azure.Mcp.Tools.EventHubs/tests/Azure.Mcp.Tools.EventHubs.Tests/EventHubsCommandTests.cs b/tools/Azure.Mcp.Tools.EventHubs/tests/Azure.Mcp.Tools.EventHubs.Tests/EventHubsCommandTests.cs index 8e57ca002a..68e76a81da 100644 --- a/tools/Azure.Mcp.Tools.EventHubs/tests/Azure.Mcp.Tools.EventHubs.Tests/EventHubsCommandTests.cs +++ b/tools/Azure.Mcp.Tools.EventHubs/tests/Azure.Mcp.Tools.EventHubs.Tests/EventHubsCommandTests.cs @@ -858,30 +858,4 @@ await CallToolAsync( } } } - - /// - /// Sanitizes and records a value based on the test mode. - /// - In Live mode: returns the original unsanitized value - /// - In Record mode: registers the sanitized value for recording, but returns the original value for API calls - /// - In Playback mode: returns the sanitized value from TestVariables - /// - private string SanitizeAndRecord(string unsanitizedValue, string name) - { - if (TestMode == TestMode.Live) - { - // Live tests don't record anything, so just use the actual value. - return unsanitizedValue; - } - else if (TestMode == TestMode.Record) - { - // Record tests need to sanitize and register the value, but use the actual value in the test. - RegisterVariable(name, "Sanitized"); - return unsanitizedValue; - } - else - { - // Playback tests need to use the sanitized value. - return TestVariables[name]; - } - } } diff --git a/tools/Azure.Mcp.Tools.Extension/src/ExtensionSetup.cs b/tools/Azure.Mcp.Tools.Extension/src/ExtensionSetup.cs index bc300cc483..6ded33d8ff 100644 --- a/tools/Azure.Mcp.Tools.Extension/src/ExtensionSetup.cs +++ b/tools/Azure.Mcp.Tools.Extension/src/ExtensionSetup.cs @@ -8,6 +8,7 @@ using Microsoft.Mcp.Core.Areas.Server.Options; using Microsoft.Mcp.Core.Commands; using Microsoft.Mcp.Core.Extensions; +using Microsoft.Mcp.Core.Services.ProcessExecution; namespace Azure.Mcp.Tools.Extension; diff --git a/tools/Azure.Mcp.Tools.Extension/src/Services/CliInstallService.cs b/tools/Azure.Mcp.Tools.Extension/src/Services/CliInstallService.cs index 9d48a1e468..782c0719e8 100644 --- a/tools/Azure.Mcp.Tools.Extension/src/Services/CliInstallService.cs +++ b/tools/Azure.Mcp.Tools.Extension/src/Services/CliInstallService.cs @@ -1,5 +1,5 @@ // Copyright (c) Microsoft Corporation. -// Licensed under the MIT License +// Licensed under the MIT License. using System.Runtime.InteropServices; diff --git a/tools/Azure.Mcp.Tools.FileShares/src/Services/IFileSharesService.cs b/tools/Azure.Mcp.Tools.FileShares/src/Services/IFileSharesService.cs index 6fb16ed87c..c9d17a60bd 100644 --- a/tools/Azure.Mcp.Tools.FileShares/src/Services/IFileSharesService.cs +++ b/tools/Azure.Mcp.Tools.FileShares/src/Services/IFileSharesService.cs @@ -159,6 +159,7 @@ Task DeleteSnapshotAsync( RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default); + /// /// Get file share limits for a subscription and location. /// Task GetLimitsAsync( diff --git a/tools/Azure.Mcp.Tools.FileShares/tests/Azure.Mcp.Tools.FileShares.Tests/FileSharesCommandTests.cs b/tools/Azure.Mcp.Tools.FileShares/tests/Azure.Mcp.Tools.FileShares.Tests/FileSharesCommandTests.cs index 370251b038..996e5bae4b 100644 --- a/tools/Azure.Mcp.Tools.FileShares/tests/Azure.Mcp.Tools.FileShares.Tests/FileSharesCommandTests.cs +++ b/tools/Azure.Mcp.Tools.FileShares/tests/Azure.Mcp.Tools.FileShares.Tests/FileSharesCommandTests.cs @@ -615,6 +615,4 @@ public async Task Should_update_private_endpoint_connection_status() Assert.Equal("Approved", connectionState.GetString()); } } - - private new const string TenantNameReason = "Tenant name resolution is not supported for service principals"; } diff --git a/tools/Azure.Mcp.Tools.Functions/src/Services/Helpers/GitHubUrlValidator.cs b/tools/Azure.Mcp.Tools.Functions/src/Services/Helpers/GitHubUrlValidator.cs index 14e4c0f2dd..50d6de51cf 100644 --- a/tools/Azure.Mcp.Tools.Functions/src/Services/Helpers/GitHubUrlValidator.cs +++ b/tools/Azure.Mcp.Tools.Functions/src/Services/Helpers/GitHubUrlValidator.cs @@ -163,8 +163,8 @@ public static bool IsValidRepositoryUrl(string? url) /// Enforces the limit in bytes and then decodes to UTF-8 string. /// /// The HTTP content to read. - /// Maximum allowed size in bytes (must be <= int.MaxValue). - /// Cancellation token. + /// Maximum allowed size in bytes (must be <= ). + /// The token to monitor for cancellation requests. /// The content as a string. /// Thrown when content exceeds the size limit. /// Thrown when maxSizeBytes exceeds int.MaxValue. diff --git a/tools/Azure.Mcp.Tools.Functions/src/Services/IManifestService.cs b/tools/Azure.Mcp.Tools.Functions/src/Services/IManifestService.cs index 1db52f97e0..0196f033bb 100644 --- a/tools/Azure.Mcp.Tools.Functions/src/Services/IManifestService.cs +++ b/tools/Azure.Mcp.Tools.Functions/src/Services/IManifestService.cs @@ -13,7 +13,7 @@ public interface IManifestService /// /// Fetches the template manifest from CDN, using cache when available. /// - /// Cancellation token. + /// The token to monitor for cancellation requests. /// The template manifest. Task FetchManifestAsync(CancellationToken cancellationToken); } diff --git a/tools/Azure.Mcp.Tools.Grafana/src/Services/GrafanaService.cs b/tools/Azure.Mcp.Tools.Grafana/src/Services/GrafanaService.cs index cb28aea129..8c66dda1e7 100644 --- a/tools/Azure.Mcp.Tools.Grafana/src/Services/GrafanaService.cs +++ b/tools/Azure.Mcp.Tools.Grafana/src/Services/GrafanaService.cs @@ -1,6 +1,5 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -// cSpell:ignore Grafanas using System.Text.Json; using Azure.Core; @@ -9,20 +8,14 @@ using Azure.Mcp.Core.Services.Azure.Tenant; using Azure.Mcp.Tools.Grafana.Models; using Azure.Mcp.Tools.Grafana.Services.Models; -using Microsoft.Extensions.Logging; using Microsoft.Mcp.Core.Models.Identity; using Microsoft.Mcp.Core.Options; namespace Azure.Mcp.Tools.Grafana.Services; -public class GrafanaService( - ISubscriptionService subscriptionService, - ITenantService tenantService, - ILogger logger) +public class GrafanaService(ISubscriptionService subscriptionService, ITenantService tenantService) : BaseAzureResourceService(subscriptionService, tenantService), IGrafanaService { - private readonly ILogger _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - public async Task> ListWorkspacesAsync( string subscription, string? resourceGroup = null, diff --git a/tools/Azure.Mcp.Tools.Grafana/src/Services/IGrafanaService.cs b/tools/Azure.Mcp.Tools.Grafana/src/Services/IGrafanaService.cs index f5a985d33e..f71ca5c311 100644 --- a/tools/Azure.Mcp.Tools.Grafana/src/Services/IGrafanaService.cs +++ b/tools/Azure.Mcp.Tools.Grafana/src/Services/IGrafanaService.cs @@ -13,8 +13,10 @@ public interface IGrafanaService /// Lists Azure Managed Grafana workspaces in the specified subscription. /// /// The subscription ID or name + /// Optional resource group name to filter the workspaces /// Optional tenant ID for cross-tenant operations /// Optional retry policy configuration + /// The token to monitor for cancellation requests. The default value is . /// List of Grafana workspace details /// When the service request fails Task> ListWorkspacesAsync( diff --git a/tools/Azure.Mcp.Tools.Insights/src/Services/IInsightsService.cs b/tools/Azure.Mcp.Tools.Insights/src/Services/IInsightsService.cs index ef4464f63d..738f453fda 100644 --- a/tools/Azure.Mcp.Tools.Insights/src/Services/IInsightsService.cs +++ b/tools/Azure.Mcp.Tools.Insights/src/Services/IInsightsService.cs @@ -15,8 +15,13 @@ public interface IInsightsService /// Aggregates resources in a single subscription, returning the top-3 most-common observed /// values for each whitelisted property leaf. /// + /// The subscription ID to aggregate. + /// The tenant ID to use for authentication; if null, the default tenant is used. + /// Optional retry policy for transient failures. + /// The token to monitor for cancellation requests. /// Progress reporter; receives a message per ARG page fetched. /// Fetch new ARG data if true, else use cached data. + /// A SubscriptionAggregation object containing the aggregated results. Task AggregateSubscriptionAsync( string subscription, string? tenant, @@ -29,8 +34,12 @@ Task AggregateSubscriptionAsync( /// Aggregates resources across every accessible subscription in the tenant, returning /// the top-3 most-common observed values for each whitelisted property leaf. /// + /// The tenant ID to use for authentication; if null, the default tenant is used. + /// Optional retry policy for transient failures. + /// The token to monitor for cancellation requests. /// Progress reporter; receives a message per ARG page fetched. /// Fetch new ARG data if true, else use cached data. + /// A SubscriptionAggregation object containing the aggregated results. Task AggregateTenantAsync( string? tenant, RetryPolicyOptions? retryPolicy, diff --git a/tools/Azure.Mcp.Tools.IoTHub/src/GlobalUsings.cs b/tools/Azure.Mcp.Tools.IoTHub/src/GlobalUsings.cs index 2ad8af129c..aaa0c89e73 100644 --- a/tools/Azure.Mcp.Tools.IoTHub/src/GlobalUsings.cs +++ b/tools/Azure.Mcp.Tools.IoTHub/src/GlobalUsings.cs @@ -2,6 +2,5 @@ // Licensed under the MIT License. global using System; -global using System.Collections.Generic; global using System.Threading; global using System.Threading.Tasks; diff --git a/tools/Azure.Mcp.Tools.IoTHub/src/Services/IIoTHubService.cs b/tools/Azure.Mcp.Tools.IoTHub/src/Services/IIoTHubService.cs index 1b859cede2..311e67da59 100644 --- a/tools/Azure.Mcp.Tools.IoTHub/src/Services/IIoTHubService.cs +++ b/tools/Azure.Mcp.Tools.IoTHub/src/Services/IIoTHubService.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using Azure.Mcp.Core.Services.Azure; using Azure.Mcp.Tools.IoTHub.Models; using Microsoft.Mcp.Core.Options; diff --git a/tools/Azure.Mcp.Tools.IoTHub/src/Services/IoTHubService.cs b/tools/Azure.Mcp.Tools.IoTHub/src/Services/IoTHubService.cs index f4d80c606b..4edcb1f648 100644 --- a/tools/Azure.Mcp.Tools.IoTHub/src/Services/IoTHubService.cs +++ b/tools/Azure.Mcp.Tools.IoTHub/src/Services/IoTHubService.cs @@ -7,7 +7,6 @@ using Azure.Mcp.Core.Services.Azure.Tenant; using Azure.Mcp.Tools.IoTHub.Commands; using Azure.Mcp.Tools.IoTHub.Models; -using Azure.ResourceManager; using Azure.ResourceManager.Resources; using Microsoft.Extensions.Logging; using Microsoft.Mcp.Core.Options; diff --git a/tools/Azure.Mcp.Tools.KeyVault/src/Services/IKeyVaultService.cs b/tools/Azure.Mcp.Tools.KeyVault/src/Services/IKeyVaultService.cs index aeed6882e3..13b8ca499e 100644 --- a/tools/Azure.Mcp.Tools.KeyVault/src/Services/IKeyVaultService.cs +++ b/tools/Azure.Mcp.Tools.KeyVault/src/Services/IKeyVaultService.cs @@ -19,7 +19,7 @@ public interface IKeyVaultService /// The subscription ID or name /// Optional tenant ID for cross-tenant operations /// Optional retry policy for the operation - /// A cancellation token + /// The token to monitor for cancellation requests. The default value is . /// The created certificate Task CreateCertificate( string vaultName, @@ -38,6 +38,7 @@ Task CreateCertificate( /// The subscription ID or name /// Optional tenant ID for cross-tenant operations /// Optional retry policy for the operation + /// The token to monitor for cancellation requests. The default value is . /// The created key Task CreateKey( string vaultName, @@ -57,6 +58,7 @@ Task CreateKey( /// The subscription ID or name /// Optional tenant ID for cross-tenant operations /// Optional retry policy for the operation + /// The token to monitor for cancellation requests. The default value is . /// The created secret Task CreateSecret( string vaultName, @@ -75,6 +77,7 @@ Task CreateSecret( /// The subscription ID or name /// Optional tenant ID for cross-tenant operations /// Optional retry policy for the operation + /// The token to monitor for cancellation requests. The default value is . /// The certificate Task GetCertificate( string vaultName, @@ -92,6 +95,7 @@ Task GetCertificate( /// The subscription ID or name /// Optional tenant ID for cross-tenant operations /// Optional retry policy for the operation + /// The token to monitor for cancellation requests. The default value is . /// The key Task GetKey( string vaultName, @@ -109,6 +113,7 @@ Task GetKey( /// The subscription ID or name /// Optional tenant ID for cross-tenant operations /// Optional retry policy for the operation + /// The token to monitor for cancellation requests. The default value is . /// The secret value Task GetSecret( string vaultName, @@ -125,6 +130,7 @@ Task GetSecret( /// Subscription ID containing the Key Vault. /// Optional tenant ID for cross-tenant operations. /// Optional retry policy for the operation. + /// The token to monitor for cancellation requests. The default value is . /// List of certificate names in the vault. Task> ListCertificates( string vaultName, @@ -137,9 +143,11 @@ Task> ListCertificates( /// List all keys in a Key Vault. /// /// Name of the Key Vault. + /// Whether to include managed keys in the results. /// Subscription ID containing the Key Vault. /// Optional tenant ID for cross-tenant operations. /// Optional retry policy for the operation. + /// The token to monitor for cancellation requests. The default value is . /// List of key names in the vault. Task> ListKeys( string vaultName, @@ -156,6 +164,7 @@ Task> ListKeys( /// Subscription ID containing the Key Vault. /// Optional tenant ID for cross-tenant operations. /// Optional retry policy for the operation. + /// The token to monitor for cancellation requests. The default value is . /// List of secret names in the vault. Task> ListSecrets( string vaultName, @@ -174,6 +183,7 @@ Task> ListSecrets( /// The subscription ID or name. /// Optional tenant ID for cross-tenant operations. /// Optional retry policy for the operation. + /// The token to monitor for cancellation requests. The default value is . /// The imported certificate. Task ImportCertificate( string vaultName, @@ -192,6 +202,7 @@ Task ImportCertificate( /// The subscription ID or name. /// Optional tenant ID for cross-tenant operations. /// Optional retry policy for the operation. + /// The token to monitor for cancellation requests. The default value is . /// Structured vault settings. Task GetVaultSettings( string vaultName, diff --git a/tools/Azure.Mcp.Tools.KeyVault/tests/Azure.Mcp.Tools.KeyVault.Tests/AssemblyAttributes.cs b/tools/Azure.Mcp.Tools.KeyVault/tests/Azure.Mcp.Tools.KeyVault.Tests/AssemblyAttributes.cs index 69da1d7967..9068d23bfb 100644 --- a/tools/Azure.Mcp.Tools.KeyVault/tests/Azure.Mcp.Tools.KeyVault.Tests/AssemblyAttributes.cs +++ b/tools/Azure.Mcp.Tools.KeyVault/tests/Azure.Mcp.Tools.KeyVault.Tests/AssemblyAttributes.cs @@ -1,2 +1,5 @@ -[assembly: Microsoft.Mcp.Tests.Helpers.ClearEnvironmentVariablesBeforeTest] +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +[assembly: Microsoft.Mcp.Tests.Helpers.ClearEnvironmentVariablesBeforeTest] [assembly: Xunit.CollectionBehavior(Xunit.CollectionBehavior.CollectionPerAssembly)] diff --git a/tools/Azure.Mcp.Tools.Kusto/src/Services/IKustoService.cs b/tools/Azure.Mcp.Tools.Kusto/src/Services/IKustoService.cs index bdda69c34a..d7d2538153 100644 --- a/tools/Azure.Mcp.Tools.Kusto/src/Services/IKustoService.cs +++ b/tools/Azure.Mcp.Tools.Kusto/src/Services/IKustoService.cs @@ -4,7 +4,6 @@ using System.Text.Json; using Azure.Mcp.Core.Services.Azure; using Azure.Mcp.Tools.Kusto.Models; -using Microsoft.Mcp.Core.Models; using Microsoft.Mcp.Core.Options; namespace Azure.Mcp.Tools.Kusto.Services; diff --git a/tools/Azure.Mcp.Tools.Kusto/src/Services/KustoService.cs b/tools/Azure.Mcp.Tools.Kusto/src/Services/KustoService.cs index 9b82690647..ce416365e3 100644 --- a/tools/Azure.Mcp.Tools.Kusto/src/Services/KustoService.cs +++ b/tools/Azure.Mcp.Tools.Kusto/src/Services/KustoService.cs @@ -8,7 +8,6 @@ using Azure.Mcp.Core.Services.Azure.Tenant; using Azure.Mcp.Tools.Kusto.Models; using Azure.Mcp.Tools.Kusto.Validation; -using Microsoft.Extensions.Logging; using Microsoft.Mcp.Core.Helpers; using Microsoft.Mcp.Core.Options; using Microsoft.Mcp.Core.Services.Caching; @@ -21,16 +20,12 @@ public sealed class KustoService( ISubscriptionService subscriptionService, ITenantService tenantService, ICacheService cacheService, - IHttpClientFactory httpClientFactory, - ILogger logger) : BaseAzureResourceService(subscriptionService, tenantService), IKustoService + IHttpClientFactory httpClientFactory) : BaseAzureResourceService(subscriptionService, tenantService), IKustoService { private readonly ICacheService _cacheService = cacheService ?? throw new ArgumentNullException(nameof(cacheService)); private readonly IHttpClientFactory _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory)); - private readonly ILogger _logger = logger ?? throw new ArgumentNullException(nameof(logger)); private const string CacheGroup = "kusto"; - private const string KustoClustersCacheKey = "clusters"; - private static readonly TimeSpan s_cacheDuration = CacheDurations.ServiceData; private static readonly TimeSpan s_providerCacheDuration = CacheDurations.AuthenticatedClient; /// diff --git a/tools/Azure.Mcp.Tools.ManagedLustre/src/Commands/FileSystem/Sku/SkuGetCommand.cs b/tools/Azure.Mcp.Tools.ManagedLustre/src/Commands/FileSystem/Sku/SkuGetCommand.cs index 4e5980c500..fefbdb7658 100644 --- a/tools/Azure.Mcp.Tools.ManagedLustre/src/Commands/FileSystem/Sku/SkuGetCommand.cs +++ b/tools/Azure.Mcp.Tools.ManagedLustre/src/Commands/FileSystem/Sku/SkuGetCommand.cs @@ -3,14 +3,11 @@ using Azure.Mcp.Core.Commands.Subscription; using Azure.Mcp.Core.Services.Azure.Subscription; -using Azure.Mcp.Tools.ManagedLustre.Options; using Azure.Mcp.Tools.ManagedLustre.Options.FileSystem.Sku; using Azure.Mcp.Tools.ManagedLustre.Services; using Microsoft.Extensions.Logging; using Microsoft.Mcp.Core.Commands; -using Microsoft.Mcp.Core.Extensions; using Microsoft.Mcp.Core.Models.Command; -using Microsoft.Mcp.Core.Models.Option; namespace Azure.Mcp.Tools.ManagedLustre.Commands.FileSystem.Sku; diff --git a/tools/Azure.Mcp.Tools.Marketplace/src/Services/MarketplaceService.cs b/tools/Azure.Mcp.Tools.Marketplace/src/Services/MarketplaceService.cs index e15ea03b90..ea4c66720e 100644 --- a/tools/Azure.Mcp.Tools.Marketplace/src/Services/MarketplaceService.cs +++ b/tools/Azure.Mcp.Tools.Marketplace/src/Services/MarketplaceService.cs @@ -33,6 +33,7 @@ public class MarketplaceService(ITenantService tenantService) /// Include service instruction templates. /// Optional. The Azure tenant ID for authentication. /// Optional. Policy parameters for retrying failed requests. + /// The token to monitor for cancellation requests. The default value is . /// A JSON node containing the product information. /// Thrown when required parameters are missing or invalid. /// Thrown when parsing the product response fails. @@ -73,6 +74,7 @@ public async Task GetProduct( /// OData expand expression to include related data. /// Optional. The Azure tenant ID for authentication. /// Optional. Policy parameters for retrying failed requests. + /// The token to monitor for cancellation requests. The default value is . /// A list of ProductSummary objects containing the marketplace products. /// Thrown when required parameters are missing or invalid. /// Thrown when parsing the products response fails. diff --git a/tools/Azure.Mcp.Tools.Monitor/src/Instrumentation/Detectors/DotNetAppTypeDetector.cs b/tools/Azure.Mcp.Tools.Monitor/src/Instrumentation/Detectors/DotNetAppTypeDetector.cs index 00d956eb88..3b76d7babf 100644 --- a/tools/Azure.Mcp.Tools.Monitor/src/Instrumentation/Detectors/DotNetAppTypeDetector.cs +++ b/tools/Azure.Mcp.Tools.Monitor/src/Instrumentation/Detectors/DotNetAppTypeDetector.cs @@ -172,7 +172,7 @@ private ProjectInfo DetectLegacyProjectType(string csprojPath, XDocument doc) else if (IsClassicAspNet(projectDir, doc)) { // Differentiate between MVC and WebForms - if (HasMvcIndicators(projectDir, doc)) + if (HasMvcIndicators(projectDir)) { appType = AppType.AspNetMvc; entryPoint = FindGlobalAsax(projectDir); @@ -376,7 +376,7 @@ private bool IsClassicAspNet(string projectDir, XDocument doc) return false; } - private static bool HasMvcIndicators(string projectDir, XDocument doc) + private static bool HasMvcIndicators(string projectDir) { // Check for MVC packages var packagesConfig = Path.Combine(projectDir, "packages.config"); diff --git a/tools/Azure.Mcp.Tools.Monitor/src/Instrumentation/Pipeline/WorkspaceAnalyzer.cs b/tools/Azure.Mcp.Tools.Monitor/src/Instrumentation/Pipeline/WorkspaceAnalyzer.cs index 354d1b36e1..7111023c37 100644 --- a/tools/Azure.Mcp.Tools.Monitor/src/Instrumentation/Pipeline/WorkspaceAnalyzer.cs +++ b/tools/Azure.Mcp.Tools.Monitor/src/Instrumentation/Pipeline/WorkspaceAnalyzer.cs @@ -3,7 +3,6 @@ using Azure.Mcp.Tools.Monitor.Instrumentation.Detectors; using Azure.Mcp.Tools.Monitor.Instrumentation.Generators; -using Azure.Mcp.Tools.Monitor.Models; using Azure.Mcp.Tools.Monitor.Models.Instrumentation; using static Azure.Mcp.Tools.Monitor.Models.Instrumentation.OnboardingConstants; diff --git a/tools/Azure.Mcp.Tools.Monitor/src/Models/MetricTimeSeries.cs b/tools/Azure.Mcp.Tools.Monitor/src/Models/MetricTimeSeries.cs index 8e1e2a2374..2bb09726d4 100644 --- a/tools/Azure.Mcp.Tools.Monitor/src/Models/MetricTimeSeries.cs +++ b/tools/Azure.Mcp.Tools.Monitor/src/Models/MetricTimeSeries.cs @@ -3,76 +3,75 @@ using System.Text.Json.Serialization; -namespace Azure.Mcp.Tools.Monitor.Models +namespace Azure.Mcp.Tools.Monitor.Models; + +/// +/// Represents a compact time series optimized for minimal JSON payload +/// +public class MetricTimeSeries { /// - /// Represents a compact time series optimized for minimal JSON payload + /// The dimension metadata for this time series (omitted if empty) /// - public class MetricTimeSeries - { - /// - /// The dimension metadata for this time series (omitted if empty) - /// - [JsonPropertyName("metadata")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public Dictionary Metadata { get; set; } = new(); + [JsonPropertyName("metadata")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public Dictionary Metadata { get; set; } = new(); - /// - /// Start time of the time series - /// - [JsonPropertyName("start")] - public DateTime Start { get; set; } + /// + /// Start time of the time series + /// + [JsonPropertyName("start")] + public DateTime Start { get; set; } - /// - /// End time of the time series - /// - [JsonPropertyName("end")] - public DateTime End { get; set; } + /// + /// End time of the time series + /// + [JsonPropertyName("end")] + public DateTime End { get; set; } - /// - /// Time grain (interval) between data points (e.g., "PT1M" for 1 minute) - /// - [JsonPropertyName("interval")] - public string Interval { get; set; } = string.Empty; + /// + /// Time grain (interval) between data points (e.g., "PT1M" for 1 minute) + /// + [JsonPropertyName("interval")] + public string Interval { get; set; } = string.Empty; - /// - /// Array of average values (omitted if no average values) - /// - [JsonPropertyName("avgBuckets")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonConverter(typeof(RoundedDoubleArrayConverter))] - public double[]? AvgBuckets { get; set; } + /// + /// Array of average values (omitted if no average values) + /// + [JsonPropertyName("avgBuckets")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonConverter(typeof(RoundedDoubleArrayConverter))] + public double[]? AvgBuckets { get; set; } - /// - /// Array of minimum values (omitted if no minimum values) - /// - [JsonPropertyName("minBuckets")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonConverter(typeof(RoundedDoubleArrayConverter))] - public double[]? MinBuckets { get; set; } + /// + /// Array of minimum values (omitted if no minimum values) + /// + [JsonPropertyName("minBuckets")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonConverter(typeof(RoundedDoubleArrayConverter))] + public double[]? MinBuckets { get; set; } - /// - /// Array of maximum values (omitted if no maximum values) - /// - [JsonPropertyName("maxBuckets")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonConverter(typeof(RoundedDoubleArrayConverter))] - public double[]? MaxBuckets { get; set; } + /// + /// Array of maximum values (omitted if no maximum values) + /// + [JsonPropertyName("maxBuckets")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonConverter(typeof(RoundedDoubleArrayConverter))] + public double[]? MaxBuckets { get; set; } - /// - /// Array of total values (omitted if no total values) - /// - [JsonPropertyName("totalBuckets")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonConverter(typeof(RoundedDoubleArrayConverter))] - public double[]? TotalBuckets { get; set; } + /// + /// Array of total values (omitted if no total values) + /// + [JsonPropertyName("totalBuckets")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonConverter(typeof(RoundedDoubleArrayConverter))] + public double[]? TotalBuckets { get; set; } - /// - /// Array of count values (omitted if no count values) - /// - [JsonPropertyName("countBuckets")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - [JsonConverter(typeof(RoundedDoubleArrayConverter))] - public double[]? CountBuckets { get; set; } - } + /// + /// Array of count values (omitted if no count values) + /// + [JsonPropertyName("countBuckets")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + [JsonConverter(typeof(RoundedDoubleArrayConverter))] + public double[]? CountBuckets { get; set; } } diff --git a/tools/Azure.Mcp.Tools.Monitor/src/Models/RoundedDoubleArrayConverter.cs b/tools/Azure.Mcp.Tools.Monitor/src/Models/RoundedDoubleArrayConverter.cs index 03d8ec9b3e..5d3271fd7e 100644 --- a/tools/Azure.Mcp.Tools.Monitor/src/Models/RoundedDoubleArrayConverter.cs +++ b/tools/Azure.Mcp.Tools.Monitor/src/Models/RoundedDoubleArrayConverter.cs @@ -4,43 +4,42 @@ using System.Text.Json; using System.Text.Json.Serialization; -namespace Azure.Mcp.Tools.Monitor.Models +namespace Azure.Mcp.Tools.Monitor.Models; + +/// +/// Custom JSON converter that rounds double arrays to 2 decimal places +/// +public class RoundedDoubleArrayConverter : JsonConverter { - /// - /// Custom JSON converter that rounds double arrays to 2 decimal places - /// - public class RoundedDoubleArrayConverter : JsonConverter + public override double[]? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - public override double[]? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - if (reader.TokenType == JsonTokenType.Null) - return null; + if (reader.TokenType == JsonTokenType.Null) + return null; - var list = new List(); - if (reader.TokenType == JsonTokenType.StartArray) + var list = new List(); + if (reader.TokenType == JsonTokenType.StartArray) + { + while (reader.Read() && reader.TokenType != JsonTokenType.EndArray) { - while (reader.Read() && reader.TokenType != JsonTokenType.EndArray) - { - list.Add(reader.GetDouble()); - } + list.Add(reader.GetDouble()); } - return [.. list]; } + return [.. list]; + } - public override void Write(Utf8JsonWriter writer, double[]? value, JsonSerializerOptions options) + public override void Write(Utf8JsonWriter writer, double[]? value, JsonSerializerOptions options) + { + if (value == null) { - if (value == null) - { - writer.WriteNullValue(); - return; - } + writer.WriteNullValue(); + return; + } - writer.WriteStartArray(); - foreach (var item in value) - { - writer.WriteNumberValue(Math.Round(item, 2)); - } - writer.WriteEndArray(); + writer.WriteStartArray(); + foreach (var item in value) + { + writer.WriteNumberValue(Math.Round(item, 2)); } + writer.WriteEndArray(); } } diff --git a/tools/Azure.Mcp.Tools.Monitor/src/Services/IMonitorHealthModelService.cs b/tools/Azure.Mcp.Tools.Monitor/src/Services/IMonitorHealthModelService.cs index 379ef9e462..7d6e09e79a 100644 --- a/tools/Azure.Mcp.Tools.Monitor/src/Services/IMonitorHealthModelService.cs +++ b/tools/Azure.Mcp.Tools.Monitor/src/Services/IMonitorHealthModelService.cs @@ -15,7 +15,7 @@ public interface IMonitorHealthModelService /// Optional resource group to scope the listing. /// Optional tenant ID. /// Optional retry policy. - /// A cancellation token. + /// The token to monitor for cancellation requests. The default value is . /// List health models. Task> ListHealthModels( string subscription, @@ -32,7 +32,7 @@ Task> ListHealthModels( /// The health model name. /// Optional tenant ID. /// Optional retry policy. - /// A cancellation token. + /// The token to monitor for cancellation requests. The default value is . /// The health model resource. Task GetHealthModel( string subscription, diff --git a/tools/Azure.Mcp.Tools.Monitor/src/Services/IMonitorMetricsService.cs b/tools/Azure.Mcp.Tools.Monitor/src/Services/IMonitorMetricsService.cs index 739f1e789a..9008a3dcad 100644 --- a/tools/Azure.Mcp.Tools.Monitor/src/Services/IMonitorMetricsService.cs +++ b/tools/Azure.Mcp.Tools.Monitor/src/Services/IMonitorMetricsService.cs @@ -27,7 +27,7 @@ public interface IMonitorMetricsService /// Required metric namespace /// Optional tenant ID for multi-tenant scenarios /// Optional retry policy parameters - /// Cancellation token + /// The token to monitor for cancellation requests. The default value is . /// List of metric results with time series data Task> QueryMetricsAsync( string subscription, @@ -56,7 +56,7 @@ Task> QueryMetricsAsync( /// Optional search string to filter metric definitions by name and description /// Optional tenant ID for multi-tenant scenarios /// Optional retry policy parameters - /// Cancellation token + /// The token to monitor for cancellation requests. The default value is . /// List of metric definitions Task> ListMetricDefinitionsAsync( string subscription, @@ -79,7 +79,7 @@ Task> ListMetricDefinitionsAsync( /// Optional search string to filter namespaces /// Optional tenant ID for multi-tenant scenarios /// Optional retry policy parameters - /// Cancellation token + /// The token to monitor for cancellation requests. The default value is . /// List of metric namespaces Task> ListMetricNamespacesAsync( string subscription, diff --git a/tools/Azure.Mcp.Tools.Monitor/src/Services/IResourceResolverService.cs b/tools/Azure.Mcp.Tools.Monitor/src/Services/IResourceResolverService.cs index e53a5bbef7..e54ae14e83 100644 --- a/tools/Azure.Mcp.Tools.Monitor/src/Services/IResourceResolverService.cs +++ b/tools/Azure.Mcp.Tools.Monitor/src/Services/IResourceResolverService.cs @@ -20,6 +20,7 @@ public interface IResourceResolverService /// The resource name or full resource ID /// Optional tenant ID for multi-tenant scenarios /// Optional retry policy parameters + /// The token to monitor for cancellation requests. The default value is . /// The full Azure resource ID Task ResolveResourceIdAsync( string subscription, diff --git a/tools/Azure.Mcp.Tools.Monitor/src/Services/MonitorHealthModelService.cs b/tools/Azure.Mcp.Tools.Monitor/src/Services/MonitorHealthModelService.cs index 57f2c1984a..4435f98e57 100644 --- a/tools/Azure.Mcp.Tools.Monitor/src/Services/MonitorHealthModelService.cs +++ b/tools/Azure.Mcp.Tools.Monitor/src/Services/MonitorHealthModelService.cs @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using System.Linq; -using Azure; using Azure.Mcp.Core.Services.Azure; using Azure.Mcp.Core.Services.Azure.Subscription; using Azure.Mcp.Core.Services.Azure.Tenant; diff --git a/tools/Azure.Mcp.Tools.Monitor/src/Services/MonitorService.cs b/tools/Azure.Mcp.Tools.Monitor/src/Services/MonitorService.cs index a74ebae1fe..662abe1ffc 100644 --- a/tools/Azure.Mcp.Tools.Monitor/src/Services/MonitorService.cs +++ b/tools/Azure.Mcp.Tools.Monitor/src/Services/MonitorService.cs @@ -385,7 +385,7 @@ public async Task> ListActivityLogs( ?? throw new ArgumentException($"Unable to extract subscription ID from resource ID: {resourceId}"); // Get the activity logs from the Azure Management API - var activityLogs = await CallActivityLogApiAsync(subscriptionId, resourceId, hours, eventLevel, tenant, retryPolicy, cancellationToken); + var activityLogs = await CallActivityLogApiAsync(subscriptionId, resourceId, hours, eventLevel, tenant, cancellationToken); // Take only the requested number of logs return activityLogs.Take(top).ToList(); @@ -397,7 +397,6 @@ private async Task> CallActivityLogApiAsync( double hours, ActivityLogEventLevel? eventLevel, string? tenant, - RetryPolicyOptions? retryPolicy, CancellationToken cancellationToken) { var returnValue = new List(); diff --git a/tools/Azure.Mcp.Tools.Monitor/src/Services/MonitorWebTestService.cs b/tools/Azure.Mcp.Tools.Monitor/src/Services/MonitorWebTestService.cs index aa6c99187b..890aa63bdb 100644 --- a/tools/Azure.Mcp.Tools.Monitor/src/Services/MonitorWebTestService.cs +++ b/tools/Azure.Mcp.Tools.Monitor/src/Services/MonitorWebTestService.cs @@ -10,7 +10,6 @@ using Azure.Mcp.Tools.Monitor.Models.WebTests; using Azure.ResourceManager.ApplicationInsights; using Azure.ResourceManager.ApplicationInsights.Models; -using Microsoft.Extensions.Logging; using Microsoft.Mcp.Core.Helpers; using Microsoft.Mcp.Core.Options; @@ -19,13 +18,11 @@ namespace Azure.Mcp.Tools.Monitor.Services; public class MonitorWebTestService( ISubscriptionService subscriptionService, ITenantService tenantService, - IResourceGroupService resourceGroupService, - ILogger logger) + IResourceGroupService resourceGroupService) : BaseAzureService(tenantService), IMonitorWebTestService { private readonly ISubscriptionService _subscriptionService = subscriptionService ?? throw new ArgumentNullException(nameof(subscriptionService)); private readonly IResourceGroupService _resourceGroupService = resourceGroupService ?? throw new ArgumentNullException(nameof(resourceGroupService)); - private readonly ILogger _logger = logger ?? throw new ArgumentNullException(nameof(logger)); public async Task> ListWebTests( string subscription, diff --git a/tools/Azure.Mcp.Tools.Monitor/src/Tools/Instrumentation/OrchestratorTool.cs b/tools/Azure.Mcp.Tools.Monitor/src/Tools/Instrumentation/OrchestratorTool.cs index 4fe36893b4..82f7624c3d 100644 --- a/tools/Azure.Mcp.Tools.Monitor/src/Tools/Instrumentation/OrchestratorTool.cs +++ b/tools/Azure.Mcp.Tools.Monitor/src/Tools/Instrumentation/OrchestratorTool.cs @@ -130,7 +130,9 @@ public string Start(string workspacePath) }); } +#pragma warning disable IDE0060 // Remove unused parameter public string Next(string sessionId, string completionNote) +#pragma warning restore IDE0060 // Remove unused parameter { CleanupExpiredSessions(); diff --git a/tools/Azure.Mcp.Tools.Monitor/tests/Azure.Mcp.Tools.Monitor.Tests/Log/WorkspaceLogQueryCommandTests.cs b/tools/Azure.Mcp.Tools.Monitor/tests/Azure.Mcp.Tools.Monitor.Tests/Log/WorkspaceLogQueryCommandTests.cs index 052062be1f..c617db1a5d 100644 --- a/tools/Azure.Mcp.Tools.Monitor/tests/Azure.Mcp.Tools.Monitor.Tests/Log/WorkspaceLogQueryCommandTests.cs +++ b/tools/Azure.Mcp.Tools.Monitor/tests/Azure.Mcp.Tools.Monitor.Tests/Log/WorkspaceLogQueryCommandTests.cs @@ -17,7 +17,6 @@ public sealed class WorkspaceLogQueryCommandTests : SubscriptionCommandUnitTests { private const string _knownSubscription = "knownSubscription"; private const string _knownWorkspace = "knownWorkspace"; - private const string _knownResourceGroup = "knownResourceGroup"; private const string _knownTable = "knownTable"; private const string _knownTenant = "knownTenant"; private const string _knownHours = "24"; diff --git a/tools/Azure.Mcp.Tools.Monitor/tests/Azure.Mcp.Tools.Monitor.Tests/Metrics/MonitorMetricsServiceTests.cs b/tools/Azure.Mcp.Tools.Monitor/tests/Azure.Mcp.Tools.Monitor.Tests/Metrics/MonitorMetricsServiceTests.cs index b0bd28a834..508853af04 100644 --- a/tools/Azure.Mcp.Tools.Monitor/tests/Azure.Mcp.Tools.Monitor.Tests/Metrics/MonitorMetricsServiceTests.cs +++ b/tools/Azure.Mcp.Tools.Monitor/tests/Azure.Mcp.Tools.Monitor.Tests/Metrics/MonitorMetricsServiceTests.cs @@ -22,7 +22,6 @@ public class MonitorMetricsServiceTests private const string TestResourceType = "Microsoft.Storage/storageAccounts"; private const string TestResourceName = "test"; private const string TestResourceId = "/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/test-rg/providers/Microsoft.Storage/storageAccounts/test"; - private const string TestTenant = "tenant-123"; public MonitorMetricsServiceTests() { diff --git a/tools/Azure.Mcp.Tools.Monitor/tests/Azure.Mcp.Tools.Monitor.Tests/Metrics/ResourceResolverServiceTests.cs b/tools/Azure.Mcp.Tools.Monitor/tests/Azure.Mcp.Tools.Monitor.Tests/Metrics/ResourceResolverServiceTests.cs index 9583ebbd29..292626dbca 100644 --- a/tools/Azure.Mcp.Tools.Monitor/tests/Azure.Mcp.Tools.Monitor.Tests/Metrics/ResourceResolverServiceTests.cs +++ b/tools/Azure.Mcp.Tools.Monitor/tests/Azure.Mcp.Tools.Monitor.Tests/Metrics/ResourceResolverServiceTests.cs @@ -124,8 +124,8 @@ public async Task ResolveResourceIdAsync_ResourceDiscovery_MultipleResourcesFoun var subscription = Guid.NewGuid().ToString(); var resourceName = "duplicate-resource"; - var resource1 = CreateMockGenericResource($"/subscriptions/{subscription}/resourceGroups/rg1/providers/Microsoft.Storage/storageAccounts/{resourceName}", "rg1", "Microsoft.Storage/storageAccounts", resourceName); - var resource2 = CreateMockGenericResource($"/subscriptions/{subscription}/resourceGroups/rg2/providers/Microsoft.Compute/virtualMachines/{resourceName}", "rg2", "Microsoft.Compute/virtualMachines", resourceName); + var resource1 = CreateMockGenericResource($"/subscriptions/{subscription}/resourceGroups/rg1/providers/Microsoft.Storage/storageAccounts/{resourceName}", "Microsoft.Storage/storageAccounts", resourceName); + var resource2 = CreateMockGenericResource($"/subscriptions/{subscription}/resourceGroups/rg2/providers/Microsoft.Compute/virtualMachines/{resourceName}", "Microsoft.Compute/virtualMachines", resourceName); var resourcesAsyncPageable = CreateAsyncPageableWithItems(resource1, resource2); @@ -147,7 +147,7 @@ public async Task ResolveResourceIdAsync_ResourceDiscovery_SingleResourceFound_R var resourceName = "unique-resource"; var expectedResourceId = $"/subscriptions/{subscription}/resourceGroups/rg1/providers/Microsoft.Storage/storageAccounts/{resourceName}"; - var resource = CreateMockGenericResource(expectedResourceId, "rg1", "Microsoft.Storage/storageAccounts", resourceName); + var resource = CreateMockGenericResource(expectedResourceId, "Microsoft.Storage/storageAccounts", resourceName); var subscriptionResource = Substitute.For(); var resourcesAsyncPageable = CreateAsyncPageableWithItems(resource); @@ -173,8 +173,8 @@ public async Task ResolveResourceIdAsync_WithResourceGroupFilter_FiltersCorrectl var expectedResourceId = $"/subscriptions/{subscription}/resourceGroups/{resourceGroup}/providers/Microsoft.Storage/storageAccounts/{resourceName}"; // Create resources in different resource groups with same name - var resource1 = CreateMockGenericResource(expectedResourceId, "rg1", "Microsoft.Storage/storageAccounts", resourceName); - var resource2 = CreateMockGenericResource($"/subscriptions/{subscription}/resourceGroups/rg2/providers/Microsoft.Storage/storageAccounts/{resourceName}", "rg2", "Microsoft.Storage/storageAccounts", resourceName); + var resource1 = CreateMockGenericResource(expectedResourceId, "Microsoft.Storage/storageAccounts", resourceName); + var resource2 = CreateMockGenericResource($"/subscriptions/{subscription}/resourceGroups/rg2/providers/Microsoft.Storage/storageAccounts/{resourceName}", "Microsoft.Storage/storageAccounts", resourceName); var resourcesAsyncPageable = CreateAsyncPageableWithItems(resource1, resource2); @@ -197,8 +197,8 @@ public async Task ResolveResourceIdAsync_WithResourceTypeFilter_FiltersCorrectly var expectedResourceId = $"/subscriptions/{subscription}/resourceGroups/rg1/providers/Microsoft.Storage/storageAccounts/{resourceName}"; // Create resources of different types with same name - var resource1 = CreateMockGenericResource(expectedResourceId, "rg1", "Microsoft.Storage/storageAccounts", resourceName); - var resource2 = CreateMockGenericResource($"/subscriptions/{subscription}/resourceGroups/rg1/providers/Microsoft.Compute/virtualMachines/{resourceName}", "rg1", "Microsoft.Compute/virtualMachines", resourceName); + var resource1 = CreateMockGenericResource(expectedResourceId, "Microsoft.Storage/storageAccounts", resourceName); + var resource2 = CreateMockGenericResource($"/subscriptions/{subscription}/resourceGroups/rg1/providers/Microsoft.Compute/virtualMachines/{resourceName}", "Microsoft.Compute/virtualMachines", resourceName); var resourcesAsyncPageable = CreateAsyncPageableWithItems(resource1, resource2); @@ -215,7 +215,7 @@ public async Task ResolveResourceIdAsync_WithResourceTypeFilter_FiltersCorrectly #region Helper Methods - private static GenericResource CreateMockGenericResource(string resourceId, string resourceGroupName, string resourceType, string resourceName) + private static GenericResource CreateMockGenericResource(string resourceId, string resourceType, string resourceName) { var result = Substitute.For(); diff --git a/tools/Azure.Mcp.Tools.Policy/src/Services/IPolicyService.cs b/tools/Azure.Mcp.Tools.Policy/src/Services/IPolicyService.cs index 02d40974fe..4d5bcc2a0d 100644 --- a/tools/Azure.Mcp.Tools.Policy/src/Services/IPolicyService.cs +++ b/tools/Azure.Mcp.Tools.Policy/src/Services/IPolicyService.cs @@ -15,7 +15,7 @@ public interface IPolicyService /// Optional scope to filter policy assignments. If not provided, lists all assignments in the subscription. /// Optional tenant ID for cross-tenant operations. /// Optional retry policy for the operation. - /// Optional cancellation token for the operation. + /// The token to monitor for cancellation requests. The default value is . /// A list of policy assignments. Task> ListPolicyAssignmentsAsync( string subscription, @@ -30,7 +30,7 @@ Task> ListPolicyAssignmentsAsync( /// The resource ID of the policy definition. /// Optional tenant ID for cross-tenant operations. /// Optional retry policy for the operation. - /// Optional cancellation token for the operation. + /// The token to monitor for cancellation requests. The default value is . /// The policy definition or null if not found. Task GetPolicyDefinitionAsync( string policyDefinitionId, diff --git a/tools/Azure.Mcp.Tools.Postgres/src/Options/AuthTypes.cs b/tools/Azure.Mcp.Tools.Postgres/src/Options/AuthTypes.cs index a5b6bd7669..3b8fc8cf16 100644 --- a/tools/Azure.Mcp.Tools.Postgres/src/Options/AuthTypes.cs +++ b/tools/Azure.Mcp.Tools.Postgres/src/Options/AuthTypes.cs @@ -1,12 +1,11 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -namespace Azure.Mcp.Tools.Postgres.Options +namespace Azure.Mcp.Tools.Postgres.Options; + +public static class AuthTypes { - public class AuthTypes - { - public const string MicrosoftEntra = "MicrosoftEntra"; + public const string MicrosoftEntra = "MicrosoftEntra"; - public const string PostgreSQL = "PostgreSQL"; - } + public const string PostgreSQL = "PostgreSQL"; } diff --git a/tools/Azure.Mcp.Tools.Postgres/tests/Azure.Mcp.Tools.Postgres.Tests/Services/PostgresServiceRowLimitTests.cs b/tools/Azure.Mcp.Tools.Postgres/tests/Azure.Mcp.Tools.Postgres.Tests/Services/PostgresServiceRowLimitTests.cs index ee602f5427..28b150c9cf 100644 --- a/tools/Azure.Mcp.Tools.Postgres/tests/Azure.Mcp.Tools.Postgres.Tests/Services/PostgresServiceRowLimitTests.cs +++ b/tools/Azure.Mcp.Tools.Postgres/tests/Azure.Mcp.Tools.Postgres.Tests/Services/PostgresServiceRowLimitTests.cs @@ -24,8 +24,6 @@ public class PostgresServiceRowLimitTests private readonly IDbProvider _dbProvider = Substitute.For(); private readonly PostgresService _postgresService; - private const string SubscriptionId = "test-sub"; - private const string ResourceGroup = "test-rg"; private const string User = "test-user"; private const string Server = "test-server"; private const string Database = "test-db"; diff --git a/tools/Azure.Mcp.Tools.Pricing/src/Client/RetailPrices.cs b/tools/Azure.Mcp.Tools.Pricing/src/Client/RetailPrices.cs index 95f840d6de..7b9797cd35 100644 --- a/tools/Azure.Mcp.Tools.Pricing/src/Client/RetailPrices.cs +++ b/tools/Azure.Mcp.Tools.Pricing/src/Client/RetailPrices.cs @@ -147,7 +147,7 @@ public virtual AsyncCollectionResult GetPricesAsync(string currencyCode, string /// Supported with API version 2021-10-01 and later. /// /// Number of records to skip (for pagination). - /// The cancellation token that can be used to cancel the operation. + /// The token to monitor for cancellation requests. The default value is . /// Service returned a non-success status code. public virtual CollectionResult GetPrices(string currencyCode = default, string filter = default, string meterRegion = default, long? skip = default, CancellationToken cancellationToken = default) { @@ -185,7 +185,7 @@ public virtual CollectionResult GetPrices(string currencyCode = /// Supported with API version 2021-10-01 and later. /// /// Number of records to skip (for pagination). - /// The cancellation token that can be used to cancel the operation. + /// The token to monitor for cancellation requests. The default value is . /// Service returned a non-success status code. public virtual AsyncCollectionResult GetPricesAsync(string currencyCode = default, string filter = default, string meterRegion = default, long? skip = default, CancellationToken cancellationToken = default) { diff --git a/tools/Azure.Mcp.Tools.Pricing/src/Services/IPricingService.cs b/tools/Azure.Mcp.Tools.Pricing/src/Services/IPricingService.cs index 17dd13b4f1..20e65a2799 100644 --- a/tools/Azure.Mcp.Tools.Pricing/src/Services/IPricingService.cs +++ b/tools/Azure.Mcp.Tools.Pricing/src/Services/IPricingService.cs @@ -21,7 +21,7 @@ public interface IPricingService /// Currency code (e.g., USD). Default is USD. /// Whether to include savings plan pricing. /// Raw OData filter for advanced queries. - /// Cancellation token. + /// The token to monitor for cancellation requests. The default value is . /// List of retail price items matching the criteria. Task> GetPricesAsync( string? sku = null, diff --git a/tools/Azure.Mcp.Tools.Redis/src/Services/IRedisService.cs b/tools/Azure.Mcp.Tools.Redis/src/Services/IRedisService.cs index 2bde1827b6..30b0d65d78 100644 --- a/tools/Azure.Mcp.Tools.Redis/src/Services/IRedisService.cs +++ b/tools/Azure.Mcp.Tools.Redis/src/Services/IRedisService.cs @@ -14,7 +14,7 @@ public interface IRedisService /// The subscription ID or name /// Optional tenant ID for cross-tenant operations /// Optional retry policy configuration - /// A cancellation token + /// The token to monitor for cancellation requests. The default value is . /// List of Redis resource details /// When the service request fails Task> ListResourcesAsync( @@ -37,7 +37,7 @@ Task> ListResourcesAsync( /// The modules to enable (e.g. "RedisJSON", "RedisBloom") /// Optional tenant ID for cross-tenant operations /// Optional retry policy configuration - /// A cancellation token + /// The token to monitor for cancellation requests. The default value is . /// Details of the Redis resource being created. /// When the service request fails Task CreateResourceAsync( diff --git a/tools/Azure.Mcp.Tools.ResourceHealth/src/Services/IResourceHealthService.cs b/tools/Azure.Mcp.Tools.ResourceHealth/src/Services/IResourceHealthService.cs index 53dda36d46..2c76754c3f 100644 --- a/tools/Azure.Mcp.Tools.ResourceHealth/src/Services/IResourceHealthService.cs +++ b/tools/Azure.Mcp.Tools.ResourceHealth/src/Services/IResourceHealthService.cs @@ -13,6 +13,7 @@ public interface IResourceHealthService /// /// The Azure resource ID /// Optional retry policy configuration + /// The token to monitor for cancellation requests. The default value is . /// The availability status of the resource /// When the service request fails Task GetAvailabilityStatusAsync( @@ -27,6 +28,7 @@ Task GetAvailabilityStatusAsync( /// Optional resource group name to filter results /// Optional tenant ID /// Optional retry policy configuration + /// The token to monitor for cancellation requests. The default value is . /// List of availability statuses for resources /// When the service request fails Task> ListAvailabilityStatusesAsync( @@ -48,6 +50,7 @@ Task> ListAvailabilityStatusesAsync( /// Optional end time for the query /// Optional tenant ID /// Optional retry policy configuration + /// The token to monitor for cancellation requests. The default value is . /// List of service health events /// When the service request fails Task> ListServiceHealthEventsAsync( diff --git a/tools/Azure.Mcp.Tools.ServiceBus/src/Services/IServiceBusService.cs b/tools/Azure.Mcp.Tools.ServiceBus/src/Services/IServiceBusService.cs index 122df0e301..3f3895ce9d 100644 --- a/tools/Azure.Mcp.Tools.ServiceBus/src/Services/IServiceBusService.cs +++ b/tools/Azure.Mcp.Tools.ServiceBus/src/Services/IServiceBusService.cs @@ -17,6 +17,7 @@ public interface IServiceBusService /// The subscription name to get details for /// Optional tenant ID /// Optional retry policy + /// The token to monitor for cancellation requests. The default value is . /// Subscription details /// When the service request fails Task GetSubscriptionDetails( @@ -32,9 +33,9 @@ Task GetSubscriptionDetails( /// /// The Service Bus namespace name /// The queue name to get details for - /// Subscription ID or name /// Optional tenant ID /// Optional retry policy + /// The token to monitor for cancellation requests. The default value is . /// Queue details /// When the service request fails Task GetQueueDetails( @@ -51,6 +52,7 @@ Task GetQueueDetails( /// The topic name to get details for /// Optional tenant ID /// Optional retry policy + /// The token to monitor for cancellation requests. The default value is . /// Topic details /// When the service request fails Task GetTopicDetails( @@ -66,9 +68,9 @@ Task GetTopicDetails( /// The Service Bus namespace name /// The queue name to peek messages from /// Maximum number of messages to peek (default: 1) - /// Subscription ID or name /// Optional tenant ID /// Optional retry policy + /// The token to monitor for cancellation requests. The default value is . /// List of peeked messages /// When the service request fails Task> PeekQueueMessages( @@ -86,9 +88,9 @@ Task> PeekQueueMessages( /// The topic name containing the subscription /// The subscription name to peek messages from /// Maximum number of messages to peek (default: 1) - /// Subscription ID or name /// Optional tenant ID /// Optional retry policy + /// The token to monitor for cancellation requests. The default value is . /// List of peeked messages /// When the service request fails Task> PeekSubscriptionMessages( diff --git a/tools/Azure.Mcp.Tools.Speech/src/Services/Recognizers/IFastTranscriptionRecognizer.cs b/tools/Azure.Mcp.Tools.Speech/src/Services/Recognizers/IFastTranscriptionRecognizer.cs index efa938e98c..e541c3413e 100644 --- a/tools/Azure.Mcp.Tools.Speech/src/Services/Recognizers/IFastTranscriptionRecognizer.cs +++ b/tools/Azure.Mcp.Tools.Speech/src/Services/Recognizers/IFastTranscriptionRecognizer.cs @@ -20,6 +20,7 @@ public interface IFastTranscriptionRecognizer /// Optional phrases to improve recognition accuracy /// Profanity filtering option /// Optional retry policy for resilience + /// The token to monitor for cancellation requests. The default value is . /// Continuous recognition result converted from Fast Transcription response Task RecognizeAsync( string endpoint, diff --git a/tools/Azure.Mcp.Tools.Speech/src/Services/Recognizers/IRealtimeTranscriptionRecognizer.cs b/tools/Azure.Mcp.Tools.Speech/src/Services/Recognizers/IRealtimeTranscriptionRecognizer.cs index 55605415f9..a8f6aa7749 100644 --- a/tools/Azure.Mcp.Tools.Speech/src/Services/Recognizers/IRealtimeTranscriptionRecognizer.cs +++ b/tools/Azure.Mcp.Tools.Speech/src/Services/Recognizers/IRealtimeTranscriptionRecognizer.cs @@ -22,7 +22,7 @@ public interface IRealtimeTranscriptionRecognizer /// Output format (simple or detailed) /// Profanity filtering option (masked, removed, or raw) /// Optional retry policy for resilience - /// A cancellation token. + /// The token to monitor for cancellation requests. The default value is . /// Continuous recognition result containing full text and individual segments Task RecognizeAsync( string endpoint, diff --git a/tools/Azure.Mcp.Tools.Speech/src/Services/SpeechService.cs b/tools/Azure.Mcp.Tools.Speech/src/Services/SpeechService.cs index 7ec4dfc13c..fbf91e2e79 100644 --- a/tools/Azure.Mcp.Tools.Speech/src/Services/SpeechService.cs +++ b/tools/Azure.Mcp.Tools.Speech/src/Services/SpeechService.cs @@ -34,7 +34,7 @@ public class SpeechService( /// Output format (simple or detailed) /// Profanity filtering option (masked, removed, or raw) /// Optional retry policy for resilience - /// Cancellation token to cancel the operation + /// The token to monitor for cancellation requests. The default value is . /// Continuous recognition result containing full text and individual segments public async Task RecognizeSpeechFromFile( string endpoint, @@ -104,7 +104,7 @@ public async Task RecognizeSpeechFromFile( /// Output audio format (default: Riff24Khz16BitMonoPcm) /// Optional endpoint ID for custom voice model /// Optional retry policy for resilience - /// Cancellation token to cancel the operation + /// The token to monitor for cancellation requests. The default value is . /// Synthesis result with file information public async Task SynthesizeSpeechToFile( string endpoint, diff --git a/tools/Azure.Mcp.Tools.Speech/src/Services/Synthesizers/IRealtimeTtsSynthesizer.cs b/tools/Azure.Mcp.Tools.Speech/src/Services/Synthesizers/IRealtimeTtsSynthesizer.cs index fe186d9284..aff27f17b1 100644 --- a/tools/Azure.Mcp.Tools.Speech/src/Services/Synthesizers/IRealtimeTtsSynthesizer.cs +++ b/tools/Azure.Mcp.Tools.Speech/src/Services/Synthesizers/IRealtimeTtsSynthesizer.cs @@ -22,7 +22,7 @@ public interface IRealtimeTtsSynthesizer /// Output audio format (default: Riff24Khz16BitMonoPcm) /// Optional endpoint ID for custom voice model /// Optional retry policy for resilience - /// A cancellation token. + /// The token to monitor for cancellation requests. The default value is . /// Synthesis result with file information Task SynthesizeToFileAsync( string endpoint, diff --git a/tools/Azure.Mcp.Tools.Speech/tests/Azure.Mcp.Tools.Speech.Tests/Services/SpeechServiceTests.cs b/tools/Azure.Mcp.Tools.Speech/tests/Azure.Mcp.Tools.Speech.Tests/Services/SpeechServiceTests.cs index b79fc473c3..91686c00cf 100644 --- a/tools/Azure.Mcp.Tools.Speech/tests/Azure.Mcp.Tools.Speech.Tests/Services/SpeechServiceTests.cs +++ b/tools/Azure.Mcp.Tools.Speech/tests/Azure.Mcp.Tools.Speech.Tests/Services/SpeechServiceTests.cs @@ -18,7 +18,6 @@ public class SpeechServiceTests private readonly IFastTranscriptionRecognizer _fastTranscriptionRecognizer; private readonly IRealtimeTranscriptionRecognizer _realtimeTranscriptionRecognizer; private readonly IRealtimeTtsSynthesizer _realtimeTtsSynthesizer; - private readonly SpeechService _speechService; public SpeechServiceTests() { @@ -27,8 +26,6 @@ public SpeechServiceTests() _fastTranscriptionRecognizer = Substitute.For(); _realtimeTranscriptionRecognizer = Substitute.For(); _realtimeTtsSynthesizer = Substitute.For(); - - _speechService = new SpeechService(_tenantService, _logger, _fastTranscriptionRecognizer, _realtimeTranscriptionRecognizer, _realtimeTtsSynthesizer); } [Fact] diff --git a/tools/Azure.Mcp.Tools.Sql/src/Commands/Server/ServerCreateCommand.cs b/tools/Azure.Mcp.Tools.Sql/src/Commands/Server/ServerCreateCommand.cs index bddde472d9..43a272d921 100644 --- a/tools/Azure.Mcp.Tools.Sql/src/Commands/Server/ServerCreateCommand.cs +++ b/tools/Azure.Mcp.Tools.Sql/src/Commands/Server/ServerCreateCommand.cs @@ -5,12 +5,10 @@ using Azure.Mcp.Core.Commands.Subscription; using Azure.Mcp.Core.Services.Azure.Subscription; using Azure.Mcp.Tools.Sql.Models; -using Azure.Mcp.Tools.Sql.Options; using Azure.Mcp.Tools.Sql.Options.Server; using Azure.Mcp.Tools.Sql.Services; using Microsoft.Extensions.Logging; using Microsoft.Mcp.Core.Commands; -using Microsoft.Mcp.Core.Extensions; using Microsoft.Mcp.Core.Models.Command; namespace Azure.Mcp.Tools.Sql.Commands.Server; diff --git a/tools/Azure.Mcp.Tools.Sql/src/Services/ISqlService.cs b/tools/Azure.Mcp.Tools.Sql/src/Services/ISqlService.cs index 0b6e51c2ad..145f939d04 100644 --- a/tools/Azure.Mcp.Tools.Sql/src/Services/ISqlService.cs +++ b/tools/Azure.Mcp.Tools.Sql/src/Services/ISqlService.cs @@ -17,7 +17,7 @@ public interface ISqlService /// The resource group name /// The subscription ID or name /// Optional retry policy options - /// Cancellation token + /// The token to monitor for cancellation requests. The default value is . /// The SQL database information /// Thrown when the database is not found Task GetDatabaseAsync( @@ -44,7 +44,7 @@ Task GetDatabaseAsync( /// Optional zone redundancy setting /// Optional read scale setting /// Optional retry policy options - /// Cancellation token + /// The token to monitor for cancellation requests. The default value is . /// The created SQL database information Task CreateDatabaseAsync( string serverName, @@ -78,7 +78,7 @@ Task CreateDatabaseAsync( /// Optional zone redundancy setting /// Optional read scale setting /// Optional retry policy options - /// Cancellation token + /// The token to monitor for cancellation requests. The default value is . /// The updated SQL database information Task UpdateDatabaseAsync( string serverName, @@ -105,7 +105,7 @@ Task UpdateDatabaseAsync( /// The resource group name /// The subscription ID or name /// Optional retry policy options - /// Cancellation token + /// The token to monitor for cancellation requests. The default value is . /// The renamed SQL database information Task RenameDatabaseAsync( string serverName, @@ -123,7 +123,7 @@ Task RenameDatabaseAsync( /// The name of the resource group /// The subscription ID or name /// Optional retry policy options - /// Cancellation token + /// The token to monitor for cancellation requests. The default value is . /// A list of SQL databases Task> ListDatabasesAsync( string serverName, @@ -139,7 +139,7 @@ Task> ListDatabasesAsync( /// The name of the resource group /// The subscription ID or name /// Optional retry policy options - /// Cancellation token + /// The token to monitor for cancellation requests. The default value is . /// A list of SQL server Entra administrators Task> GetEntraAdministratorsAsync( string serverName, @@ -155,7 +155,7 @@ Task> GetEntraAdministratorsAsync( /// The name of the resource group /// The subscription ID or name /// Optional retry policy options - /// Cancellation token + /// The token to monitor for cancellation requests. The default value is . /// A list of SQL elastic pools Task> GetElasticPoolsAsync( string serverName, @@ -171,7 +171,7 @@ Task> GetElasticPoolsAsync( /// The name of the resource group /// The subscription ID or name /// Optional retry policy options - /// Cancellation token + /// The token to monitor for cancellation requests. The default value is . /// A list of SQL server firewall rules Task> ListFirewallRulesAsync( string serverName, @@ -190,7 +190,7 @@ Task> ListFirewallRulesAsync( /// The start IP address of the firewall rule range /// The end IP address of the firewall rule range /// Optional retry policy options - /// Cancellation token + /// The token to monitor for cancellation requests. The default value is . /// The created SQL server firewall rule Task CreateFirewallRuleAsync( string serverName, @@ -210,7 +210,7 @@ Task CreateFirewallRuleAsync( /// The subscription ID or name /// The name of the firewall rule to delete /// Optional retry policy options - /// Cancellation token + /// The token to monitor for cancellation requests. The default value is . /// True if the firewall rule was successfully deleted Task DeleteFirewallRuleAsync( string serverName, @@ -228,7 +228,7 @@ Task DeleteFirewallRuleAsync( /// The resource group name /// The subscription ID or name /// Optional retry policy options - /// Cancellation token + /// The token to monitor for cancellation requests. The default value is . /// True if the database was successfully deleted Task DeleteDatabaseAsync( string serverName, @@ -250,7 +250,7 @@ Task DeleteDatabaseAsync( /// The version of SQL Server to create (optional, defaults to latest) /// Whether public network access is enabled (optional) /// Optional retry policy options - /// Cancellation token + /// The token to monitor for cancellation requests. The default value is . /// The created SQL server information Task CreateServerAsync( string serverName, @@ -271,7 +271,7 @@ Task CreateServerAsync( /// The name of the resource group /// The subscription ID or name /// Optional retry policy options - /// Cancellation token + /// The token to monitor for cancellation requests. The default value is . /// The SQL server information /// Thrown when the server is not found Task GetServerAsync( @@ -287,7 +287,7 @@ Task GetServerAsync( /// The name of the resource group /// The subscription ID or name /// Optional retry policy options - /// Cancellation token + /// The token to monitor for cancellation requests. The default value is . /// A list of SQL servers Task> ListServersAsync( string resourceGroup, @@ -302,7 +302,7 @@ Task> ListServersAsync( /// The name of the resource group /// The subscription ID or name /// Optional retry policy options - /// Cancellation token + /// The token to monitor for cancellation requests. The default value is . /// True if the server was successfully deleted Task DeleteServerAsync( string serverName, diff --git a/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlDatabaseData.cs b/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlDatabaseData.cs index 31005c67c2..c4f9c2cb93 100644 --- a/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlDatabaseData.cs +++ b/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlDatabaseData.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System.Text.Json; diff --git a/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlDatabaseProperties.cs b/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlDatabaseProperties.cs index e745add33b..a689c1dd6f 100644 --- a/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlDatabaseProperties.cs +++ b/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlDatabaseProperties.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System.Text.Json.Serialization; diff --git a/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlFirewallRuleData.cs b/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlFirewallRuleData.cs index 307ca5f930..37532a64e8 100644 --- a/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlFirewallRuleData.cs +++ b/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlFirewallRuleData.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System.Text.Json; diff --git a/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlFirewallRuleProperties.cs b/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlFirewallRuleProperties.cs index 29830d25c7..6aa3efe608 100644 --- a/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlFirewallRuleProperties.cs +++ b/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlFirewallRuleProperties.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System.Text.Json.Serialization; diff --git a/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlServerAadAdministratorData.cs b/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlServerAadAdministratorData.cs index c388378903..28084cc4ff 100644 --- a/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlServerAadAdministratorData.cs +++ b/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlServerAadAdministratorData.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System.Text.Json; diff --git a/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlServerAadAdministratorProperties.cs b/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlServerAadAdministratorProperties.cs index 7b8845b5ef..05d24dd23d 100644 --- a/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlServerAadAdministratorProperties.cs +++ b/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlServerAadAdministratorProperties.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System.Text.Json.Serialization; diff --git a/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlSku.cs b/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlSku.cs index 48736f3460..a98c2ccefe 100644 --- a/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlSku.cs +++ b/tools/Azure.Mcp.Tools.Sql/src/Services/Models/SqlSku.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. namespace Azure.Mcp.Tools.Sql.Services.Models; diff --git a/tools/Azure.Mcp.Tools.Sql/src/Services/SqlService.cs b/tools/Azure.Mcp.Tools.Sql/src/Services/SqlService.cs index 7a93d48540..8a5330fa3e 100644 --- a/tools/Azure.Mcp.Tools.Sql/src/Services/SqlService.cs +++ b/tools/Azure.Mcp.Tools.Sql/src/Services/SqlService.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using System.Net; -using System.Text.Json; using Azure.Core; using Azure.Mcp.Core.Services.Azure; using Azure.Mcp.Core.Services.Azure.Subscription; @@ -30,7 +29,7 @@ public class SqlService(ISubscriptionService subscriptionService, ITenantService /// /// The subscription ID or name /// Optional retry policy configuration - /// Token to observe for cancellation requests + /// The token to monitor for cancellation requests. /// The resolved subscription ID private async Task ResolveSubscriptionIdAsync( string subscription, @@ -49,7 +48,7 @@ private async Task ResolveSubscriptionIdAsync( /// The name of the resource group containing the server /// The subscription ID or name /// Optional retry policy configuration - /// Token to observe for cancellation requests + /// The token to monitor for cancellation requests. The default value is . /// The SQL Server resource private async Task GetSqlServerResourceAsync( string serverName, @@ -72,7 +71,7 @@ private async Task GetSqlServerResourceAsync( /// The name of the resource group containing the server /// The subscription ID or name /// Optional retry policy configuration for resilient operations - /// Token to observe for cancellation requests + /// The token to monitor for cancellation requests. The default value is . /// The SQL database if found, otherwise throws KeyNotFoundException /// Thrown when the specified database is not found /// Thrown when required parameters are null or empty @@ -120,7 +119,7 @@ public async Task GetDatabaseAsync( /// Optional zone redundancy setting /// Optional read scale setting /// Optional retry policy configuration for resilient operations - /// Token to observe for cancellation requests + /// The token to monitor for cancellation requests. The default value is . /// The created SQL database information /// Thrown when required parameters are null or empty public async Task CreateDatabaseAsync( @@ -224,7 +223,7 @@ public async Task CreateDatabaseAsync( /// Optional zone redundancy setting /// Optional read scale setting /// Optional retry policy configuration for resilient operations - /// Token to observe for cancellation requests + /// The token to monitor for cancellation requests. The default value is . /// The updated SQL database information /// Thrown when required parameters are null or empty public async Task UpdateDatabaseAsync( @@ -328,7 +327,7 @@ public async Task UpdateDatabaseAsync( /// The name of the resource group containing the server /// The subscription ID or name /// Optional retry policy configuration for resilient operations - /// Token to observe for cancellation requests + /// The token to monitor for cancellation requests. The default value is . /// The renamed SQL database information /// Thrown when required parameters are null or empty public async Task RenameDatabaseAsync( @@ -381,7 +380,7 @@ public async Task RenameDatabaseAsync( /// The name of the resource group containing the server /// The subscription ID or name /// Optional retry policy configuration for resilient operations - /// Token to observe for cancellation requests + /// The token to monitor for cancellation requests. The default value is . /// A list of SQL databases on the specified server /// Thrown when required parameters are null or empty public async Task> ListDatabasesAsync( @@ -420,7 +419,7 @@ public async Task> ListDatabasesAsync( /// The name of the resource group containing the server /// The subscription ID or name /// Optional retry policy configuration for resilient operations - /// Token to observe for cancellation requests + /// The token to monitor for cancellation requests. The default value is . /// A list of Entra ID administrators configured for the SQL server /// Thrown when required parameters are null or empty public async Task> GetEntraAdministratorsAsync( @@ -467,7 +466,7 @@ public async Task> GetEntraAdministratorsAsync /// The name of the resource group containing the server /// The subscription ID or name /// Optional retry policy configuration for resilient operations - /// Token to observe for cancellation requests + /// The token to monitor for cancellation requests. The default value is . /// A list of elastic pools configured on the SQL server /// Thrown when required parameters are null or empty public async Task> GetElasticPoolsAsync( @@ -506,7 +505,7 @@ public async Task> GetElasticPoolsAsync( /// The name of the resource group containing the server /// The subscription ID or name /// Optional retry policy configuration for resilient operations - /// Token to observe for cancellation requests + /// The token to monitor for cancellation requests. The default value is . /// A list of firewall rules configured on the SQL server /// Thrown when required parameters are null or empty public async Task> ListFirewallRulesAsync( @@ -553,7 +552,7 @@ public async Task> ListFirewallRulesAsync( /// The start IP address of the firewall rule range /// The end IP address of the firewall rule range /// Optional retry policy configuration for resilient operations - /// Token to observe for cancellation requests + /// The token to monitor for cancellation requests. The default value is . /// The created firewall rule /// Thrown when required parameters are null or empty public async Task CreateFirewallRuleAsync( @@ -607,7 +606,7 @@ public async Task CreateFirewallRuleAsync( /// The subscription ID or name /// The name of the firewall rule to delete /// Optional retry policy configuration for resilient operations - /// Token to observe for cancellation requests + /// The token to monitor for cancellation requests. The default value is . /// True if the firewall rule was successfully deleted /// Thrown when required parameters are null or empty public async Task DeleteFirewallRuleAsync( @@ -616,7 +615,7 @@ public async Task DeleteFirewallRuleAsync( string subscription, string firewallRuleName, RetryPolicyOptions? retryPolicy, - CancellationToken cancellationToken) + CancellationToken cancellationToken = default) { ValidateRequiredParameters( (nameof(serverName), serverName), @@ -661,7 +660,7 @@ public async Task DeleteFirewallRuleAsync( /// The version of SQL Server to create (optional, defaults to latest) /// Whether public network access is enabled (optional) /// Optional retry policy configuration for resilient operations - /// Token to observe for cancellation requests + /// The token to monitor for cancellation requests. The default value is . /// The created SQL server /// Thrown when required parameters are null or empty public async Task CreateServerAsync( @@ -674,7 +673,7 @@ public async Task CreateServerAsync( string? version, string? publicNetworkAccess, RetryPolicyOptions? retryPolicy, - CancellationToken cancellationToken) + CancellationToken cancellationToken = default) { ValidateRequiredParameters( (nameof(serverName), serverName), @@ -729,7 +728,7 @@ public async Task CreateServerAsync( /// The name of the resource group containing the server /// The subscription ID or name /// Optional retry policy configuration for resilient operations - /// Token to observe for cancellation requests + /// The token to monitor for cancellation requests. The default value is . /// The SQL server if found, otherwise throws KeyNotFoundException /// Thrown when the specified server is not found /// Thrown when required parameters are null or empty @@ -767,7 +766,7 @@ public async Task GetServerAsync( /// The name of the resource group containing the servers /// The subscription ID or name /// Optional retry policy configuration for resilient operations - /// Token to observe for cancellation requests + /// The token to monitor for cancellation requests. The default value is . /// A list of SQL servers found in the specified resource group /// Thrown when required parameters are null or empty public async Task> ListServersAsync( @@ -845,7 +844,7 @@ public async Task DeleteServerAsync( /// The name of the resource group containing the server /// The subscription ID or name /// Optional retry policy configuration for resilient operations - /// Token to observe for cancellation requests + /// The token to monitor for cancellation requests. The default value is . /// True if the database was successfully deleted /// Thrown when required parameters are null or empty public async Task DeleteDatabaseAsync( @@ -916,36 +915,6 @@ private static SqlDatabase ConvertToSqlDatabaseModel(SqlDatabaseResource databas ); } - private static SqlDatabase ConvertToSqlDatabaseModel(JsonElement item) - { - Models.SqlDatabaseData? sqlDatabase = Models.SqlDatabaseData.FromJson(item) - ?? throw new InvalidOperationException("Failed to parse SQL database data"); - - return new( - Name: sqlDatabase.ResourceName ?? "Unknown", - Id: sqlDatabase.ResourceId ?? "Unknown", - Type: sqlDatabase.ResourceType ?? "Unknown", - Location: sqlDatabase.Location, - Sku: sqlDatabase.Sku != null ? new( - Name: sqlDatabase.Sku.Name, - Tier: sqlDatabase.Sku.Tier, - Capacity: sqlDatabase.Sku.Capacity, - Family: sqlDatabase.Sku.Family, - Size: sqlDatabase.Sku.Size - ) : null, - Status: sqlDatabase.Properties?.Status, - Collation: sqlDatabase.Properties?.Collation, - CreationDate: sqlDatabase.Properties?.CreatedOn, - MaxSizeBytes: sqlDatabase.Properties?.MaxSizeBytes, - ServiceLevelObjective: sqlDatabase.Properties?.CurrentServiceObjectiveName, - Edition: sqlDatabase.Properties?.CurrentSku?.Name, - ElasticPoolName: sqlDatabase.Properties?.ElasticPoolId?.ToString().Split('/').LastOrDefault(), - EarliestRestoreDate: sqlDatabase.Properties?.EarliestRestoreOn, - ReadScale: sqlDatabase.Properties?.ReadScale, - ZoneRedundant: sqlDatabase.Properties?.IsZoneRedundant - ); - } - private static SqlServer ConvertToSqlServerModel(SqlServerResource serverResource) { ArgumentNullException.ThrowIfNull(serverResource); diff --git a/tools/Azure.Mcp.Tools.SreAgent/src/Models/SreAgentThreadModels.cs b/tools/Azure.Mcp.Tools.SreAgent/src/Models/SreAgentThreadModels.cs index 183f7f1e52..e940463862 100644 --- a/tools/Azure.Mcp.Tools.SreAgent/src/Models/SreAgentThreadModels.cs +++ b/tools/Azure.Mcp.Tools.SreAgent/src/Models/SreAgentThreadModels.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using System.Text.Json; -using System.Text.Json.Serialization; namespace Azure.Mcp.Tools.SreAgent.Models; diff --git a/tools/Azure.Mcp.Tools.SreAgent/src/Options/ScheduledTasks/ScheduledTasksDeleteOptions.cs b/tools/Azure.Mcp.Tools.SreAgent/src/Options/ScheduledTasks/ScheduledTasksDeleteOptions.cs index 5cc55f83c8..c94c4facd9 100644 --- a/tools/Azure.Mcp.Tools.SreAgent/src/Options/ScheduledTasks/ScheduledTasksDeleteOptions.cs +++ b/tools/Azure.Mcp.Tools.SreAgent/src/Options/ScheduledTasks/ScheduledTasksDeleteOptions.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using Azure.Mcp.Core.Options; using Microsoft.Mcp.Core.Options; namespace Azure.Mcp.Tools.SreAgent.Options.ScheduledTasks; diff --git a/tools/Azure.Mcp.Tools.SreAgent/src/Services/ISreAgentService.cs b/tools/Azure.Mcp.Tools.SreAgent/src/Services/ISreAgentService.cs index bcbef0cc3a..fa65fb380c 100644 --- a/tools/Azure.Mcp.Tools.SreAgent/src/Services/ISreAgentService.cs +++ b/tools/Azure.Mcp.Tools.SreAgent/src/Services/ISreAgentService.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using Azure.Mcp.Tools.SreAgent.Models; -using Azure.Mcp.Tools.SreAgent.Options.Threads; using Microsoft.Mcp.Core.Options; namespace Azure.Mcp.Tools.SreAgent.Services; diff --git a/tools/Azure.Mcp.Tools.SreAgent/src/Services/SreAgentService.cs b/tools/Azure.Mcp.Tools.SreAgent/src/Services/SreAgentService.cs index 7ad1c9c511..d6ced473da 100644 --- a/tools/Azure.Mcp.Tools.SreAgent/src/Services/SreAgentService.cs +++ b/tools/Azure.Mcp.Tools.SreAgent/src/Services/SreAgentService.cs @@ -116,7 +116,7 @@ public async Task> ListAgentsAsync( /// HTTP method. /// Optional JSON body to send. /// Optional tenant to use when acquiring the credential. - /// Cancellation token. + /// The token to monitor for cancellation requests. The default value is . /// The response body as a string (caller deserializes into the appropriate model). internal async Task CallDataPlaneAsync( string endpoint, @@ -189,7 +189,7 @@ private static void ValidateDataPlaneEndpoint(Uri endpointUri) /// HTTP method. /// Optional JSON request body. /// Optional tenant to use when acquiring the credential. - /// Cancellation token. + /// The token to monitor for cancellation requests. The default value is . /// Response body as a string. Empty string for 204 No Content responses. internal async Task CallArmAsync( string path, diff --git a/tools/Azure.Mcp.Tools.SreAgent/tests/Azure.Mcp.Tools.SreAgent.Tests/AssemblyAttributes.cs b/tools/Azure.Mcp.Tools.SreAgent/tests/Azure.Mcp.Tools.SreAgent.Tests/AssemblyAttributes.cs index 9596e9a4eb..92cc1acc9f 100644 --- a/tools/Azure.Mcp.Tools.SreAgent/tests/Azure.Mcp.Tools.SreAgent.Tests/AssemblyAttributes.cs +++ b/tools/Azure.Mcp.Tools.SreAgent/tests/Azure.Mcp.Tools.SreAgent.Tests/AssemblyAttributes.cs @@ -1,2 +1,5 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + [assembly: Microsoft.Mcp.Tests.Helpers.ClearEnvironmentVariablesBeforeTest] [assembly: Xunit.CollectionBehavior(Xunit.CollectionBehavior.CollectionPerAssembly)] diff --git a/tools/Azure.Mcp.Tools.SreAgent/tests/Azure.Mcp.Tools.SreAgent.Tests/SreAgentCommandTests.cs b/tools/Azure.Mcp.Tools.SreAgent/tests/Azure.Mcp.Tools.SreAgent.Tests/SreAgentCommandTests.cs index 06906ce609..5a8524a3f0 100644 --- a/tools/Azure.Mcp.Tools.SreAgent/tests/Azure.Mcp.Tools.SreAgent.Tests/SreAgentCommandTests.cs +++ b/tools/Azure.Mcp.Tools.SreAgent/tests/Azure.Mcp.Tools.SreAgent.Tests/SreAgentCommandTests.cs @@ -6,25 +6,25 @@ using Microsoft.Mcp.Tests.Generated.Models; using Xunit; -namespace Azure.Mcp.Tools.SreAgent.Tests +namespace Azure.Mcp.Tools.SreAgent.Tests; + +public class SreAgentCommandTests(ITestOutputHelper output, TestProxyFixture fixture, LiveServerFixture liveServerFixture) + : RecordedCommandTestsBase(output, fixture, liveServerFixture) { - public class SreAgentCommandTests(ITestOutputHelper output, TestProxyFixture fixture, LiveServerFixture liveServerFixture) - : RecordedCommandTestsBase(output, fixture, liveServerFixture) + // Disable body comparison: SRE Agent data-plane responses contain dynamic fields + // (timestamps, generated IDs, system state) that would cause spurious playback mismatches. + public override CustomDefaultMatcher? TestMatcher => new() { - // Disable body comparison: SRE Agent data-plane responses contain dynamic fields - // (timestamps, generated IDs, system state) that would cause spurious playback mismatches. - public override CustomDefaultMatcher? TestMatcher => new() - { - ExcludedHeaders = "Authorization,Content-Type", - CompareBodies = false - }; - - // Sanitize SRE Agent data-plane hostname in response bodies so recordings don't - // contain the real resource name (e.g. "mcpfb80ce3a--e5d0b29a.00632926.eastus2.azuresre.ai"). - // Also sanitize tenant IDs and Owners fields (resource creator alias) from response bodies. - public override List BodyRegexSanitizers => - [ - new BodyRegexSanitizer(new BodyRegexSanitizerBody + ExcludedHeaders = "Authorization,Content-Type", + CompareBodies = false + }; + + // Sanitize SRE Agent data-plane hostname in response bodies so recordings don't + // contain the real resource name (e.g. "mcpfb80ce3a--e5d0b29a.00632926.eastus2.azuresre.ai"). + // Also sanitize tenant IDs and Owners fields (resource creator alias) from response bodies. + public override List BodyRegexSanitizers => + [ + new BodyRegexSanitizer(new BodyRegexSanitizerBody { Regex = @"(?<=https://)(?[^/""\s]+\.azuresre\.ai)", GroupForReplace = "host", @@ -42,387 +42,386 @@ public class SreAgentCommandTests(ITestOutputHelper output, TestProxyFixture fix GroupForReplace = "owner", Value = "sanitized" }) - ]; + ]; - // Sanitize SRE Agent data-plane hostname in request/response URIs. - public override List UriRegexSanitizers => - [ - new UriRegexSanitizer(new UriRegexSanitizerBody + // Sanitize SRE Agent data-plane hostname in request/response URIs. + public override List UriRegexSanitizers => + [ + new UriRegexSanitizer(new UriRegexSanitizerBody { Regex = @"(?<=https://)(?[^/]+\.azuresre\.ai)", GroupForReplace = "host", Value = "sanitized.eastus2.azuresre.ai" }) - ]; + ]; - // Sanitize x-ms-operation-identifier response header which contains real tenant ID and object ID. - public override List HeaderRegexSanitizers => - [ - new HeaderRegexSanitizer(new HeaderRegexSanitizerBody("x-ms-operation-identifier") + // Sanitize x-ms-operation-identifier response header which contains real tenant ID and object ID. + public override List HeaderRegexSanitizers => + [ + new HeaderRegexSanitizer(new HeaderRegexSanitizerBody("x-ms-operation-identifier") { Value = "sanitized" }) - ]; - - [Fact] - public async Task Should_list_sre_agents_by_subscription_id() - { - var result = await CallToolAsync( - "sreagent_agents_list", - new() - { + ]; + + [Fact] + public async Task Should_list_sre_agents_by_subscription_id() + { + var result = await CallToolAsync( + "sreagent_agents_list", + new() + { { "subscription", Settings.SubscriptionId } - }); - - // Result may be an array directly or wrapped; just assert call succeeded. - Assert.NotNull(result); - } - - [Fact] - public async Task Should_get_sre_agent_details() - { - var result = await CallToolAsync( - "sreagent_agents_get", - new() - { + }); + + // Result may be an array directly or wrapped; just assert call succeeded. + Assert.NotNull(result); + } + + [Fact] + public async Task Should_get_sre_agent_details() + { + var result = await CallToolAsync( + "sreagent_agents_get", + new() + { { "subscription", Settings.SubscriptionId }, { "resource-group", Settings.ResourceGroupName }, { "agent", Settings.ResourceBaseName } - }); - - Assert.NotNull(result); - } - - [Fact] - public async Task Should_list_threads() - { - var result = await CallToolAsync( - "sreagent_threads_list", - new() - { + }); + + Assert.NotNull(result); + } + + [Fact] + public async Task Should_list_threads() + { + var result = await CallToolAsync( + "sreagent_threads_list", + new() + { { "subscription", Settings.SubscriptionId }, { "resource-group", Settings.ResourceGroupName }, { "agent", Settings.ResourceBaseName } - }); - - Assert.NotNull(result); - } - - [Fact] - public async Task Should_list_connectors() - { - var result = await CallToolAsync( - "sreagent_connectors_list", - new() - { + }); + + Assert.NotNull(result); + } + + [Fact] + public async Task Should_list_connectors() + { + var result = await CallToolAsync( + "sreagent_connectors_list", + new() + { { "subscription", Settings.SubscriptionId }, { "resource-group", Settings.ResourceGroupName }, { "agent", Settings.ResourceBaseName } - }); - - Assert.NotNull(result); - } - - [Fact] - public async Task Should_list_scheduled_tasks() - { - var result = await CallToolAsync( - "sreagent_scheduledtasks_list", - new() - { + }); + + Assert.NotNull(result); + } + + [Fact] + public async Task Should_list_scheduled_tasks() + { + var result = await CallToolAsync( + "sreagent_scheduledtasks_list", + new() + { { "subscription", Settings.SubscriptionId }, { "resource-group", Settings.ResourceGroupName }, { "agent", Settings.ResourceBaseName } - }); - - Assert.NotNull(result); - } - - [Fact] - public async Task Should_list_active_incidents() - { - var result = await CallToolAsync( - "sreagent_incidents_active_list", - new() - { + }); + + Assert.NotNull(result); + } + + [Fact] + public async Task Should_list_active_incidents() + { + var result = await CallToolAsync( + "sreagent_incidents_active_list", + new() + { { "subscription", Settings.SubscriptionId }, { "resource-group", Settings.ResourceGroupName }, { "agent", Settings.ResourceBaseName } - }); - - Assert.NotNull(result); - } - - [Fact] - public async Task Should_list_common_prompts() - { - var result = await CallToolAsync( - "sreagent_commonprompts_list", - new() - { + }); + + Assert.NotNull(result); + } + + [Fact] + public async Task Should_list_common_prompts() + { + var result = await CallToolAsync( + "sreagent_commonprompts_list", + new() + { { "subscription", Settings.SubscriptionId }, { "resource-group", Settings.ResourceGroupName }, { "agent", Settings.ResourceBaseName } - }); - - Assert.NotNull(result); - } - - [Fact] - public async Task Should_list_agent_tools() - { - var result = await CallToolAsync( - "sreagent_agents_tools_list", - new() - { + }); + + Assert.NotNull(result); + } + + [Fact] + public async Task Should_list_agent_tools() + { + var result = await CallToolAsync( + "sreagent_agents_tools_list", + new() + { { "subscription", Settings.SubscriptionId }, { "resource-group", Settings.ResourceGroupName }, { "agent", Settings.ResourceBaseName } - }); - - Assert.NotNull(result); - } - - [Fact] - public async Task Should_list_skills() - { - var result = await CallToolAsync( - "sreagent_skills_list", - new() - { + }); + + Assert.NotNull(result); + } + + [Fact] + public async Task Should_list_skills() + { + var result = await CallToolAsync( + "sreagent_skills_list", + new() + { { "subscription", Settings.SubscriptionId }, { "resource-group", Settings.ResourceGroupName }, { "agent", Settings.ResourceBaseName } - }); - - Assert.NotNull(result); - } - - [Fact] - public async Task Should_list_hooks() - { - var result = await CallToolAsync( - "sreagent_hooks_list", - new() - { + }); + + Assert.NotNull(result); + } + + [Fact] + public async Task Should_list_hooks() + { + var result = await CallToolAsync( + "sreagent_hooks_list", + new() + { { "subscription", Settings.SubscriptionId }, { "resource-group", Settings.ResourceGroupName }, { "agent", Settings.ResourceBaseName } - }); - - Assert.NotNull(result); - } - - [Fact] - public async Task Should_list_incident_plans() - { - var result = await CallToolAsync( - "sreagent_incidents_plans_list", - new() - { + }); + + Assert.NotNull(result); + } + + [Fact] + public async Task Should_list_incident_plans() + { + var result = await CallToolAsync( + "sreagent_incidents_plans_list", + new() + { { "subscription", Settings.SubscriptionId }, { "resource-group", Settings.ResourceGroupName }, { "agent", Settings.ResourceBaseName } - }); - - Assert.NotNull(result); - } - - [Fact] - public async Task Should_list_memories() - { - var result = await CallToolAsync( - "sreagent_docs_memories_list", - new() - { + }); + + Assert.NotNull(result); + } + + [Fact] + public async Task Should_list_memories() + { + var result = await CallToolAsync( + "sreagent_docs_memories_list", + new() + { { "subscription", Settings.SubscriptionId }, { "resource-group", Settings.ResourceGroupName }, { "agent", Settings.ResourceBaseName } - }); + }); - Assert.NotNull(result); - } + Assert.NotNull(result); + } - [Fact] - public async Task Should_create_get_and_delete_common_prompt() - { - const string promptName = "live-test-prompt"; + [Fact] + public async Task Should_create_get_and_delete_common_prompt() + { + const string promptName = "live-test-prompt"; - // Create - var createResult = await CallToolAsync( - "sreagent_commonprompts_create", - new() - { + // Create + var createResult = await CallToolAsync( + "sreagent_commonprompts_create", + new() + { { "subscription", Settings.SubscriptionId }, { "resource-group", Settings.ResourceGroupName }, { "agent", Settings.ResourceBaseName }, { "name", promptName }, { "content", "You are a helpful SRE assistant." } - }); - Assert.NotNull(createResult); - - // Get - var getResult = await CallToolAsync( - "sreagent_commonprompts_get", - new() - { + }); + Assert.NotNull(createResult); + + // Get + var getResult = await CallToolAsync( + "sreagent_commonprompts_get", + new() + { { "subscription", Settings.SubscriptionId }, { "resource-group", Settings.ResourceGroupName }, { "agent", Settings.ResourceBaseName }, { "name", promptName } - }); - Assert.NotNull(getResult); - - // Delete - var deleteResult = await CallToolAsync( - "sreagent_commonprompts_delete", - new() - { + }); + Assert.NotNull(getResult); + + // Delete + var deleteResult = await CallToolAsync( + "sreagent_commonprompts_delete", + new() + { { "subscription", Settings.SubscriptionId }, { "resource-group", Settings.ResourceGroupName }, { "agent", Settings.ResourceBaseName }, { "name", promptName }, { "confirm", true } - }); - Assert.NotNull(deleteResult); - } - - [Fact] - public async Task Should_add_search_and_delete_memory() - { - const string memoryName = "live-test-memory.md"; - - // Add - var addResult = await CallToolAsync( - "sreagent_docs_memories_add", - new() - { + }); + Assert.NotNull(deleteResult); + } + + [Fact] + public async Task Should_add_search_and_delete_memory() + { + const string memoryName = "live-test-memory.md"; + + // Add + var addResult = await CallToolAsync( + "sreagent_docs_memories_add", + new() + { { "subscription", Settings.SubscriptionId }, { "resource-group", Settings.ResourceGroupName }, { "agent", Settings.ResourceBaseName }, { "name", memoryName }, { "content", "# Live Test Memory\nThis document is used by automated live tests." } - }); - Assert.NotNull(addResult); - - // Search (best-effort; indexing may be asynchronous) - var searchResult = await CallToolAsync( - "sreagent_docs_memories_search", - new() - { + }); + Assert.NotNull(addResult); + + // Search (best-effort; indexing may be asynchronous) + var searchResult = await CallToolAsync( + "sreagent_docs_memories_search", + new() + { { "subscription", Settings.SubscriptionId }, { "resource-group", Settings.ResourceGroupName }, { "agent", Settings.ResourceBaseName }, { "query", "live test memory" } - }); - Assert.NotNull(searchResult); - - // Delete - var deleteResult = await CallToolAsync( - "sreagent_docs_memories_delete", - new() - { + }); + Assert.NotNull(searchResult); + + // Delete + var deleteResult = await CallToolAsync( + "sreagent_docs_memories_delete", + new() + { { "subscription", Settings.SubscriptionId }, { "resource-group", Settings.ResourceGroupName }, { "agent", Settings.ResourceBaseName }, { "name", memoryName }, { "confirm", true } - }); - Assert.NotNull(deleteResult); - } - - [Fact] - public async Task Should_reindex_memories() - { - var result = await CallToolAsync( - "sreagent_docs_memories_reindex", - new() - { + }); + Assert.NotNull(deleteResult); + } + + [Fact] + public async Task Should_reindex_memories() + { + var result = await CallToolAsync( + "sreagent_docs_memories_reindex", + new() + { { "subscription", Settings.SubscriptionId }, { "resource-group", Settings.ResourceGroupName }, { "agent", Settings.ResourceBaseName } - }); + }); - Assert.NotNull(result); - } + Assert.NotNull(result); + } - [Fact] - public async Task Should_create_get_and_delete_mcp_connector() - { - const string connectorName = "live-test-mcp-connector"; + [Fact] + public async Task Should_create_get_and_delete_mcp_connector() + { + const string connectorName = "live-test-mcp-connector"; - // Create (HTTP type with a placeholder endpoint) - var createResult = await CallToolAsync( - "sreagent_connectors_create_mcp", - new() - { + // Create (HTTP type with a placeholder endpoint) + var createResult = await CallToolAsync( + "sreagent_connectors_create_mcp", + new() + { { "subscription", Settings.SubscriptionId }, { "resource-group", Settings.ResourceGroupName }, { "agent", Settings.ResourceBaseName }, { "name", connectorName }, { "type", "http" }, { "endpoint", "https://example.com/mcp" } - }); - Assert.NotNull(createResult); - - // Get - var getResult = await CallToolAsync( - "sreagent_connectors_get", - new() - { + }); + Assert.NotNull(createResult); + + // Get + var getResult = await CallToolAsync( + "sreagent_connectors_get", + new() + { { "subscription", Settings.SubscriptionId }, { "resource-group", Settings.ResourceGroupName }, { "agent", Settings.ResourceBaseName }, { "name", connectorName } - }); - Assert.NotNull(getResult); - - // Delete - var deleteResult = await CallToolAsync( - "sreagent_connectors_delete", - new() - { + }); + Assert.NotNull(getResult); + + // Delete + var deleteResult = await CallToolAsync( + "sreagent_connectors_delete", + new() + { { "subscription", Settings.SubscriptionId }, { "resource-group", Settings.ResourceGroupName }, { "agent", Settings.ResourceBaseName }, { "name", connectorName }, { "confirm", true } - }); - Assert.NotNull(deleteResult); - } - - [Fact] - public async Task Should_create_and_delete_skill() - { - const string skillName = "live-test-skill"; - - // Create - var createResult = await CallToolAsync( - "sreagent_skills_create", - new() - { + }); + Assert.NotNull(deleteResult); + } + + [Fact] + public async Task Should_create_and_delete_skill() + { + const string skillName = "live-test-skill"; + + // Create + var createResult = await CallToolAsync( + "sreagent_skills_create", + new() + { { "subscription", Settings.SubscriptionId }, { "resource-group", Settings.ResourceGroupName }, { "agent", Settings.ResourceBaseName }, { "name", skillName }, { "content", "## Restart Service\nRestart the given service using `systemctl restart `." }, { "description", "Runbook for restarting a service" } - }); - Assert.NotNull(createResult); - - // Delete - var deleteResult = await CallToolAsync( - "sreagent_skills_delete", - new() - { + }); + Assert.NotNull(createResult); + + // Delete + var deleteResult = await CallToolAsync( + "sreagent_skills_delete", + new() + { { "subscription", Settings.SubscriptionId }, { "resource-group", Settings.ResourceGroupName }, { "agent", Settings.ResourceBaseName }, { "name", skillName }, { "confirm", true } - }); - Assert.NotNull(deleteResult); - } - + }); + Assert.NotNull(deleteResult); } + } diff --git a/tools/Azure.Mcp.Tools.Storage/src/Services/StorageService.cs b/tools/Azure.Mcp.Tools.Storage/src/Services/StorageService.cs index 20dff22ee3..68ba2d7bfd 100644 --- a/tools/Azure.Mcp.Tools.Storage/src/Services/StorageService.cs +++ b/tools/Azure.Mcp.Tools.Storage/src/Services/StorageService.cs @@ -14,21 +14,15 @@ using Azure.ResourceManager; using Azure.Storage.Blobs; using Azure.Storage.Blobs.Models; -using Microsoft.Extensions.Logging; using Microsoft.Mcp.Core.Options; using Microsoft.Mcp.Core.Services.Azure.Authentication; namespace Azure.Mcp.Tools.Storage.Services; -public sealed class StorageService( - ISubscriptionService subscriptionService, - ITenantService tenantService, - ILogger logger) +public sealed class StorageService(ISubscriptionService subscriptionService, ITenantService tenantService) : BaseAzureResourceService(subscriptionService, tenantService), IStorageService { private readonly ISubscriptionService _subscriptionService = subscriptionService; - private readonly ITenantService _tenantService = tenantService ?? throw new ArgumentNullException(nameof(tenantService)); - private readonly ILogger _logger = logger ?? throw new ArgumentNullException(nameof(logger)); private static readonly HashSet s_validSkus = new(StringComparer.OrdinalIgnoreCase) { @@ -431,7 +425,6 @@ private static StorageAccountInfo ConvertToAccountInfoModel(JsonElement item) private async Task CreateTableServiceClient( string account, - string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default) @@ -456,7 +449,6 @@ public async Task> ListTables( // First attempt with requested auth method var tableServiceClient = await CreateTableServiceClient( account, - subscription, tenant, retryPolicy, cancellationToken); @@ -495,7 +487,7 @@ private string GetBlobEndpoint(string account) { account = account.ToLowerInvariant(); ValidateStorageAccountName(account); - return _tenantService.CloudConfiguration.CloudType switch + return TenantService.CloudConfiguration.CloudType switch { AzureCloudConfiguration.AzureCloud.AzurePublicCloud => $"https://{account}.blob.core.windows.net", AzureCloudConfiguration.AzureCloud.AzureChinaCloud => $"https://{account}.blob.core.chinacloudapi.cn", @@ -508,7 +500,7 @@ private string GetTableEndpoint(string account) { account = account.ToLowerInvariant(); ValidateStorageAccountName(account); - return _tenantService.CloudConfiguration.CloudType switch + return TenantService.CloudConfiguration.CloudType switch { AzureCloudConfiguration.AzureCloud.AzurePublicCloud => $"https://{account}.table.core.windows.net", AzureCloudConfiguration.AzureCloud.AzureChinaCloud => $"https://{account}.table.core.chinacloudapi.cn", diff --git a/tools/Azure.Mcp.Tools.Workbooks/src/Commands/Workbooks/CreateWorkbooksCommand.cs b/tools/Azure.Mcp.Tools.Workbooks/src/Commands/Workbooks/CreateWorkbooksCommand.cs index b3013f4aae..225a1891d6 100644 --- a/tools/Azure.Mcp.Tools.Workbooks/src/Commands/Workbooks/CreateWorkbooksCommand.cs +++ b/tools/Azure.Mcp.Tools.Workbooks/src/Commands/Workbooks/CreateWorkbooksCommand.cs @@ -42,7 +42,7 @@ public override async Task ExecuteAsync(CommandContext context, options.ResourceGroup, options.DisplayName, options.SerializedContent, - /** + /* * The source ID is optional, defaulting to "azure monitor" if not provided. * "azure monitor" is the default for workbooks created in the Azure Monitor extension, * otherwise the workbook will display an error when opening. diff --git a/tools/Fabric.Mcp.Tools.Docs/src/Services/FabricPublicApiService.cs b/tools/Fabric.Mcp.Tools.Docs/src/Services/FabricPublicApiService.cs index e2ab5ec767..32d639f6b0 100644 --- a/tools/Fabric.Mcp.Tools.Docs/src/Services/FabricPublicApiService.cs +++ b/tools/Fabric.Mcp.Tools.Docs/src/Services/FabricPublicApiService.cs @@ -21,7 +21,6 @@ public class FabricPublicApiService( private const string APISpecDefinitionsDirName = "definitions/"; private const string APISpecExamplesDirName = "examples/"; - private const string FormattedItemDefinitionPath = "item-definitions/{0}-definition.md"; private const string BaseResourcePath = PublicAPISpecRepo + "/contents/"; private const string FormattedSpecPath = BaseResourcePath + "{0}/" + APISpecFileName; diff --git a/tools/Fabric.Mcp.Tools.OneLake/src/Models/OneLakeJsonContext.cs b/tools/Fabric.Mcp.Tools.OneLake/src/Models/OneLakeJsonContext.cs index 9675ea0714..50d3bb2030 100644 --- a/tools/Fabric.Mcp.Tools.OneLake/src/Models/OneLakeJsonContext.cs +++ b/tools/Fabric.Mcp.Tools.OneLake/src/Models/OneLakeJsonContext.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using System.Collections.Generic; using System.Text.Json.Serialization; using Fabric.Mcp.Tools.OneLake.Commands.File; using Fabric.Mcp.Tools.OneLake.Commands.Item; diff --git a/tools/Fabric.Mcp.Tools.OneLake/src/Services/OneLakeService.cs b/tools/Fabric.Mcp.Tools.OneLake/src/Services/OneLakeService.cs index a0a9fe765d..3e0ce81dd6 100644 --- a/tools/Fabric.Mcp.Tools.OneLake/src/Services/OneLakeService.cs +++ b/tools/Fabric.Mcp.Tools.OneLake/src/Services/OneLakeService.cs @@ -184,7 +184,7 @@ public async Task CreateItemAsync(string workspaceId, CreateItemReq { var url = $"{OneLakeEndpoints.GetFabricApiBaseUrl()}/workspaces/{workspaceId}/items"; var jsonContent = JsonSerializer.Serialize(request, OneLakeJsonContext.Default.CreateItemRequest); - var response = await SendFabricApiRequestAsync(HttpMethod.Post, url, jsonContent, null, cancellationToken); + var response = await SendFabricApiRequestAsync(HttpMethod.Post, url, jsonContent, cancellationToken); return await JsonSerializer.DeserializeAsync(response, OneLakeJsonContext.Default.OneLakeItem, cancellationToken) ?? new OneLakeItem(); } @@ -702,55 +702,6 @@ public async Task> ListPathAsync(string workspaceId, string return fileSystemItems.OrderBy(f => f.Type == "directory" ? 0 : 1).ThenBy(f => f.Name).ToList(); } - private List BuildHierarchicalStructure(List flatItems, string basePath) - { - var root = new List(); - var pathPrefix = basePath.TrimEnd('/') + "/"; - - // Group items by their immediate parent directory - var grouped = flatItems - .Where(item => item.Path.StartsWith(pathPrefix, StringComparison.OrdinalIgnoreCase) || item.Path == basePath.TrimEnd('/')) - .GroupBy(item => - { - var relativePath = item.Path.Substring(pathPrefix.Length); - var firstSlash = relativePath.IndexOf('/'); - return firstSlash == -1 ? "" : relativePath.Substring(0, firstSlash); - }); - - foreach (var group in grouped) - { - if (string.IsNullOrEmpty(group.Key)) - { - // Direct children of the base path - root.AddRange(group); - } - else - { - // Create directory entry with children - var dirPath = $"{pathPrefix}{group.Key}"; - var directoryItem = group.FirstOrDefault(item => item.Path == dirPath && item.Type == "directory"); - - if (directoryItem == null) - { - directoryItem = new FileSystemItem - { - Name = group.Key, - Path = dirPath, - Type = "directory", - Size = null, - LastModified = null, - ContentType = "application/x-directory" - }; - } - - directoryItem.Children = group.Where(item => item.Path != dirPath).ToList(); - root.Add(directoryItem); - } - } - - return root.OrderBy(f => f.Type == "directory" ? 0 : 1).ThenBy(f => f.Name).ToList(); - } - public async Task> ListOneLakeItemsAsync(string workspaceId, string? continuationToken = null, CancellationToken cancellationToken = default) { var xmlContent = await ExecuteWithWorkspaceFallbackAsync( @@ -1642,9 +1593,9 @@ private static void ValidatePathForTraversal(string path, string paramName) } } - private async Task SendFabricApiRequestAsync(HttpMethod method, string url, string? jsonContent = null, string? tenant = null, CancellationToken cancellationToken = default) + private async Task SendFabricApiRequestAsync(HttpMethod method, string url, string? jsonContent = null, CancellationToken cancellationToken = default) { - var tokenContext = new TokenRequestContext(new[] { OneLakeEndpoints.GetFabricScope() }); + var tokenContext = new TokenRequestContext([OneLakeEndpoints.GetFabricScope()]); var token = await _credential.GetTokenAsync(tokenContext, cancellationToken); using var request = new HttpRequestMessage(method, url); @@ -1791,15 +1742,15 @@ private async Task SendOneLakeApiRequestAsync(HttpMethod method, string return await response.Content.ReadAsStreamAsync(cancellationToken); } - private async Task SendDataPlaneRequestAsync(HttpMethod method, string url, string? tenant = null, CancellationToken cancellationToken = default) + private async Task SendDataPlaneRequestAsync(HttpMethod method, string url, CancellationToken cancellationToken = default) { using var request = new HttpRequestMessage(method, url); - return await SendDataPlaneRequestAsync(request, tenant, cancellationToken); + return await SendDataPlaneRequestAsync(request, cancellationToken); } - private async Task SendDataPlaneRequestAsync(HttpRequestMessage request, string? tenant = null, CancellationToken cancellationToken = default) + private async Task SendDataPlaneRequestAsync(HttpRequestMessage request, CancellationToken cancellationToken = default) { - var tokenContext = new TokenRequestContext(new[] { OneLakeEndpoints.StorageScope }); + var tokenContext = new TokenRequestContext([OneLakeEndpoints.StorageScope]); var token = await _credential.GetTokenAsync(tokenContext, cancellationToken); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.Token); @@ -2248,17 +2199,6 @@ private async Task ResolvePrincipalsAsync(List members, Ca } } - private static string ExtractWarehouseQueryValue(string warehousePrefix) - { - const string WarehousePrefixRoot = "warehouse/"; - if (warehousePrefix.StartsWith(WarehousePrefixRoot, StringComparison.OrdinalIgnoreCase)) - { - return warehousePrefix[WarehousePrefixRoot.Length..]; - } - - return warehousePrefix; - } - private async Task<(string WorkspaceId, string ItemIdentifier, string WarehousePrefix, string WarehouseQueryValue)> GetWarehousePrefixAsync(string workspaceIdentifier, string itemIdentifier, CancellationToken cancellationToken) { var normalizedWorkspaceId = NormalizeWorkspaceIdentifier(workspaceIdentifier); diff --git a/tools/Fabric.Mcp.Tools.OneLake/tests/Fabric.Mcp.Tools.OneLake.Tests/Services/OneLakeServiceLroTests.cs b/tools/Fabric.Mcp.Tools.OneLake/tests/Fabric.Mcp.Tools.OneLake.Tests/Services/OneLakeServiceLroTests.cs index 12fd6381d4..88a59efa0f 100644 --- a/tools/Fabric.Mcp.Tools.OneLake/tests/Fabric.Mcp.Tools.OneLake.Tests/Services/OneLakeServiceLroTests.cs +++ b/tools/Fabric.Mcp.Tools.OneLake/tests/Fabric.Mcp.Tools.OneLake.Tests/Services/OneLakeServiceLroTests.cs @@ -20,7 +20,6 @@ public class OneLakeServiceLroTests private const string OperationId = "op-lro-12345"; private const string OperationUrl = $"https://dailyapi.fabric.microsoft.com/v1/operations/{OperationId}"; private const string ResultUrl = $"https://dailyapi.fabric.microsoft.com/v1/operations/{OperationId}/result"; - private const string ShortcutsUrl = $"https://dailyapi.fabric.microsoft.com/v1/workspaces/{WorkspaceId}/items/{ItemId}/shortcuts/bulkCreate"; private static OneLakeService CreateService(Func handler) {