diff --git a/servers/Azure.Mcp.Server/changelog-entries/1781294298905.yaml b/servers/Azure.Mcp.Server/changelog-entries/1781294298905.yaml new file mode 100644 index 0000000000..ab792c89fe --- /dev/null +++ b/servers/Azure.Mcp.Server/changelog-entries/1781294298905.yaml @@ -0,0 +1,3 @@ +changes: + - section: "Breaking Changes" + description: "Removed unused parameters from AppConfig tools." diff --git a/tools/Azure.Mcp.Tools.AppConfig/src/Commands/Account/AccountListCommand.cs b/tools/Azure.Mcp.Tools.AppConfig/src/Commands/Account/AccountListCommand.cs index 152c8ee7bb..4c3659d398 100644 --- a/tools/Azure.Mcp.Tools.AppConfig/src/Commands/Account/AccountListCommand.cs +++ b/tools/Azure.Mcp.Tools.AppConfig/src/Commands/Account/AccountListCommand.cs @@ -2,14 +2,13 @@ // Licensed under the MIT License. using Azure.Mcp.Core.Commands.Subscription; +using Azure.Mcp.Core.Services.Azure.Subscription; using Azure.Mcp.Tools.AppConfig.Models; using Azure.Mcp.Tools.AppConfig.Options.Account; using Azure.Mcp.Tools.AppConfig.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.AppConfig.Commands.Account; @@ -27,33 +26,14 @@ stores available in the specified subscription. Results include store names retu ReadOnly = true, Secret = false, LocalRequired = false)] -public sealed class AccountListCommand(ILogger logger, IAppConfigService appConfigService) : SubscriptionCommand() +public sealed class AccountListCommand(ILogger logger, IAppConfigService appConfigService, ISubscriptionResolver subscriptionResolver) + : SubscriptionCommand(subscriptionResolver) { private readonly ILogger _logger = logger; private readonly IAppConfigService _appConfigService = appConfigService; - protected override void RegisterOptions(Command command) + public override async Task ExecuteAsync(CommandContext context, AccountListOptions options, CancellationToken cancellationToken) { - base.RegisterOptions(command); - command.Options.Add(OptionDefinitions.Common.ResourceGroup.AsOptional()); - } - - protected override AccountListOptions BindOptions(ParseResult parseResult) - { - var options = base.BindOptions(parseResult); - options.ResourceGroup = parseResult.GetValueOrDefault(OptionDefinitions.Common.ResourceGroup.Name); - return options; - } - - public override async Task ExecuteAsync(CommandContext context, ParseResult parseResult, CancellationToken cancellationToken) - { - if (!Validate(parseResult.CommandResult, context.Response).IsValid) - { - return context.Response; - } - - var options = BindOptions(parseResult); - try { var accounts = await _appConfigService.GetAppConfigAccounts( @@ -74,5 +54,5 @@ public override async Task ExecuteAsync(CommandContext context, return context.Response; } - internal record AccountListCommandResult(List Accounts, bool AreResultsTruncated); + public sealed record AccountListCommandResult(List Accounts, bool AreResultsTruncated); } diff --git a/tools/Azure.Mcp.Tools.AppConfig/src/Commands/BaseAppConfigCommand.cs b/tools/Azure.Mcp.Tools.AppConfig/src/Commands/BaseAppConfigCommand.cs deleted file mode 100644 index 1c58aba29d..0000000000 --- a/tools/Azure.Mcp.Tools.AppConfig/src/Commands/BaseAppConfigCommand.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System.Diagnostics.CodeAnalysis; -using Azure.Mcp.Core.Commands.Subscription; -using Azure.Mcp.Tools.AppConfig.Options; -using Microsoft.Mcp.Core.Commands; -using Microsoft.Mcp.Core.Extensions; - -namespace Azure.Mcp.Tools.AppConfig.Commands; - -public abstract class BaseAppConfigCommand< - [DynamicallyAccessedMembers(TrimAnnotations.CommandAnnotations)] T> - : SubscriptionCommand where T : BaseAppConfigOptions, new() -{ - protected override void RegisterOptions(Command command) - { - base.RegisterOptions(command); - command.Options.Add(AppConfigOptionDefinitions.Account); - } - - protected override T BindOptions(ParseResult parseResult) - { - var options = base.BindOptions(parseResult); - options.Account = parseResult.GetValueOrDefault(AppConfigOptionDefinitions.Account.Name); - return options; - } -} diff --git a/tools/Azure.Mcp.Tools.AppConfig/src/Commands/KeyValue/BaseKeyValueCommand.cs b/tools/Azure.Mcp.Tools.AppConfig/src/Commands/KeyValue/BaseKeyValueCommand.cs deleted file mode 100644 index 845c6aaa34..0000000000 --- a/tools/Azure.Mcp.Tools.AppConfig/src/Commands/KeyValue/BaseKeyValueCommand.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System.Diagnostics.CodeAnalysis; -using Azure.Mcp.Tools.AppConfig.Options; -using Azure.Mcp.Tools.AppConfig.Options.KeyValue; -using Microsoft.Mcp.Core.Commands; -using Microsoft.Mcp.Core.Extensions; - -namespace Azure.Mcp.Tools.AppConfig.Commands.KeyValue; - -public abstract class BaseKeyValueCommand< - [DynamicallyAccessedMembers(TrimAnnotations.CommandAnnotations)] T> - : BaseAppConfigCommand where T : BaseKeyValueOptions, new() -{ - protected override void RegisterOptions(Command command) - { - base.RegisterOptions(command); - command.Options.Add(AppConfigOptionDefinitions.Key); - command.Options.Add(AppConfigOptionDefinitions.Label); - command.Options.Add(AppConfigOptionDefinitions.ContentType); - } - - protected override T BindOptions(ParseResult parseResult) - { - var options = base.BindOptions(parseResult); - options.Key = parseResult.GetValueOrDefault(AppConfigOptionDefinitions.Key.Name); - options.Label = parseResult.GetValueOrDefault(AppConfigOptionDefinitions.Label.Name); - options.ContentType = parseResult.GetValueOrDefault(AppConfigOptionDefinitions.ContentType.Name); - return options; - } -} diff --git a/tools/Azure.Mcp.Tools.AppConfig/src/Commands/KeyValue/KeyValueDeleteCommand.cs b/tools/Azure.Mcp.Tools.AppConfig/src/Commands/KeyValue/KeyValueDeleteCommand.cs index e78d09bdfa..fe71e7d506 100644 --- a/tools/Azure.Mcp.Tools.AppConfig/src/Commands/KeyValue/KeyValueDeleteCommand.cs +++ b/tools/Azure.Mcp.Tools.AppConfig/src/Commands/KeyValue/KeyValueDeleteCommand.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using Azure.Mcp.Core.Commands.Subscription; +using Azure.Mcp.Core.Services.Azure.Subscription; using Azure.Mcp.Tools.AppConfig.Options.KeyValue; using Azure.Mcp.Tools.AppConfig.Services; using Microsoft.Extensions.Logging; @@ -24,26 +26,19 @@ Delete a key-value pair from an App Configuration store. This command removes th ReadOnly = false, Secret = false, LocalRequired = false)] -public sealed class KeyValueDeleteCommand(ILogger logger, IAppConfigService appConfigService) - : BaseKeyValueCommand() +public sealed class KeyValueDeleteCommand(ILogger logger, IAppConfigService appConfigService, ISubscriptionResolver subscriptionResolver) + : SubscriptionCommand(subscriptionResolver) { private readonly ILogger _logger = logger; private readonly IAppConfigService _appConfigService = appConfigService; - public override async Task ExecuteAsync(CommandContext context, ParseResult parseResult, CancellationToken cancellationToken) + public override async Task ExecuteAsync(CommandContext context, KeyValueDeleteOptions options, CancellationToken cancellationToken) { - if (!Validate(parseResult.CommandResult, context.Response).IsValid) - { - return context.Response; - } - - var options = BindOptions(parseResult); - try { var existed = await _appConfigService.DeleteKeyValue( - options.Account!, - options.Key!, + options.Account, + options.Key, options.Subscription!, options.Tenant, options.RetryPolicy, @@ -65,5 +60,5 @@ public override async Task ExecuteAsync(CommandContext context, return context.Response; } - internal record KeyValueDeleteCommandResult(string? Key, string? Label, bool Existed, string Message); + public sealed record KeyValueDeleteCommandResult(string? Key, string? Label, bool Existed, string Message); } diff --git a/tools/Azure.Mcp.Tools.AppConfig/src/Commands/KeyValue/KeyValueGetCommand.cs b/tools/Azure.Mcp.Tools.AppConfig/src/Commands/KeyValue/KeyValueGetCommand.cs index c5fdc851c1..92358368fa 100644 --- a/tools/Azure.Mcp.Tools.AppConfig/src/Commands/KeyValue/KeyValueGetCommand.cs +++ b/tools/Azure.Mcp.Tools.AppConfig/src/Commands/KeyValue/KeyValueGetCommand.cs @@ -1,15 +1,14 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using Azure.Mcp.Core.Commands.Subscription; +using Azure.Mcp.Core.Services.Azure.Subscription; using Azure.Mcp.Tools.AppConfig.Models; -using Azure.Mcp.Tools.AppConfig.Options; using Azure.Mcp.Tools.AppConfig.Options.KeyValue; using Azure.Mcp.Tools.AppConfig.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.AppConfig.Commands.KeyValue; @@ -29,53 +28,31 @@ Gets key-values in an App Configuration store. This command can either retrieve ReadOnly = true, Secret = false, LocalRequired = false)] -public sealed class KeyValueGetCommand(ILogger logger, IAppConfigService appConfigService) - : BaseAppConfigCommand() +public sealed class KeyValueGetCommand(ILogger logger, IAppConfigService appConfigService, ISubscriptionResolver subscriptionResolver) + : SubscriptionCommand(subscriptionResolver) { private readonly ILogger _logger = logger; private readonly IAppConfigService _appConfigService = appConfigService; - protected override void RegisterOptions(Command command) + public override void ValidateOptions(KeyValueGetOptions options, ValidationResult validationResult) { - base.RegisterOptions(command); - command.Options.Add(AppConfigOptionDefinitions.Key.AsOptional()); - command.Options.Add(AppConfigOptionDefinitions.Label); - command.Options.Add(AppConfigOptionDefinitions.KeyFilter); - command.Options.Add(AppConfigOptionDefinitions.LabelFilter); - command.Validators.Add(result => + base.ValidateOptions(options, validationResult); + if (!string.IsNullOrEmpty(options.Key) && !string.IsNullOrEmpty(options.KeyFilter)) { - var key = result.GetValueOrDefault(AppConfigOptionDefinitions.Key.Name); - var keyFilter = result.GetValueOrDefault(AppConfigOptionDefinitions.KeyFilter); - if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(keyFilter)) - { - result.AddError("Cannot specify both --key and --key-filter options together. Use only one to get a specific key-value or to filter the list of key-values."); - } - }); - } - - protected override KeyValueGetOptions BindOptions(ParseResult parseResult) - { - var options = base.BindOptions(parseResult); - options.Key = parseResult.GetValueOrDefault(AppConfigOptionDefinitions.Key.Name); - options.Label = parseResult.GetValueOrDefault(AppConfigOptionDefinitions.Label.Name); - options.KeyFilter = parseResult.GetValueOrDefault(AppConfigOptionDefinitions.KeyFilter.Name); - options.LabelFilter = parseResult.GetValueOrDefault(AppConfigOptionDefinitions.LabelFilter.Name); - return options; - } - - public override async Task ExecuteAsync(CommandContext context, ParseResult parseResult, CancellationToken cancellationToken) - { - if (!Validate(parseResult.CommandResult, context.Response).IsValid) + validationResult.Errors.Add("Cannot specify both --key and --key-filter options together. Use only one to get a specific key-value or to filter the list of key-values."); + } + if (!string.IsNullOrEmpty(options.Label) && !string.IsNullOrEmpty(options.LabelFilter)) { - return context.Response; + validationResult.Errors.Add("Cannot specify both --label and --label-filter options together. Use only one to get a specific key-value or to filter the list of key-values."); } + } - var options = BindOptions(parseResult); - + public override async Task ExecuteAsync(CommandContext context, KeyValueGetOptions options, CancellationToken cancellationToken) + { try { var settings = await _appConfigService.GetKeyValues( - options.Account!, + options.Account, options.Subscription!, options.Key, options.Label, @@ -96,5 +73,5 @@ public override async Task ExecuteAsync(CommandContext context, return context.Response; } - internal record KeyValueGetCommandResult(List Settings); + public sealed record KeyValueGetCommandResult(List Settings); } diff --git a/tools/Azure.Mcp.Tools.AppConfig/src/Commands/KeyValue/KeyValueSetCommand.cs b/tools/Azure.Mcp.Tools.AppConfig/src/Commands/KeyValue/KeyValueSetCommand.cs index f759b61266..3836d7ce5e 100644 --- a/tools/Azure.Mcp.Tools.AppConfig/src/Commands/KeyValue/KeyValueSetCommand.cs +++ b/tools/Azure.Mcp.Tools.AppConfig/src/Commands/KeyValue/KeyValueSetCommand.cs @@ -1,12 +1,12 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using Azure.Mcp.Tools.AppConfig.Options; +using Azure.Mcp.Core.Commands.Subscription; +using Azure.Mcp.Core.Services.Azure.Subscription; using Azure.Mcp.Tools.AppConfig.Options.KeyValue; using Azure.Mcp.Tools.AppConfig.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.AppConfig.Commands.KeyValue; @@ -27,44 +27,20 @@ Set a key-value setting in an App Configuration store. This command creates or u ReadOnly = false, Secret = false, LocalRequired = false)] -public sealed class KeyValueSetCommand(ILogger logger, IAppConfigService appConfigService) - : BaseKeyValueCommand() +public sealed class KeyValueSetCommand(ILogger logger, IAppConfigService appConfigService, ISubscriptionResolver subscriptionResolver) + : SubscriptionCommand(subscriptionResolver) { - private const string CommandTitle = "Set App Configuration Key-Value Setting"; private readonly ILogger _logger = logger; private readonly IAppConfigService _appConfigService = appConfigService; - protected override void RegisterOptions(Command command) + public override async Task ExecuteAsync(CommandContext context, KeyValueSetOptions options, CancellationToken cancellationToken) { - base.RegisterOptions(command); - command.Options.Add(AppConfigOptionDefinitions.Value); - command.Options.Add(AppConfigOptionDefinitions.Tags); - } - - protected override KeyValueSetOptions BindOptions(ParseResult parseResult) - { - var options = base.BindOptions(parseResult); - options.Value = parseResult.GetValueOrDefault(AppConfigOptionDefinitions.Value.Name); - options.Tags = parseResult.GetValueOrDefault(AppConfigOptionDefinitions.Tags.Name); - return options; - } - - [McpServerTool(Destructive = true, ReadOnly = false, Title = CommandTitle)] - public override async Task ExecuteAsync(CommandContext context, ParseResult parseResult, CancellationToken cancellationToken) - { - if (!Validate(parseResult.CommandResult, context.Response).IsValid) - { - return context.Response; - } - - var options = BindOptions(parseResult); - try { await _appConfigService.SetKeyValue( - options.Account!, - options.Key!, - options.Value!, + options.Account, + options.Key, + options.Value, options.Subscription!, options.Tenant, options.RetryPolicy, @@ -86,5 +62,5 @@ await _appConfigService.SetKeyValue( return context.Response; } - internal record KeyValueSetCommandResult(string? Key, string? Value, string? Label, string? ContentType = null, string[]? Tags = null); + public sealed record KeyValueSetCommandResult(string? Key, string? Value, string? Label, string? ContentType = null, string[]? Tags = null); } diff --git a/tools/Azure.Mcp.Tools.AppConfig/src/Commands/KeyValue/Lock/KeyValueLockSetCommand.cs b/tools/Azure.Mcp.Tools.AppConfig/src/Commands/KeyValue/Lock/KeyValueLockSetCommand.cs index f2c4f7611e..a4d8bade3a 100644 --- a/tools/Azure.Mcp.Tools.AppConfig/src/Commands/KeyValue/Lock/KeyValueLockSetCommand.cs +++ b/tools/Azure.Mcp.Tools.AppConfig/src/Commands/KeyValue/Lock/KeyValueLockSetCommand.cs @@ -60,5 +60,5 @@ await _appConfigService.SetKeyValueLockState( return context.Response; } - public record KeyValueLockSetCommandResult(string Key, string? Label, bool Locked); + public sealed record KeyValueLockSetCommandResult(string Key, string? Label, bool Locked); } diff --git a/tools/Azure.Mcp.Tools.AppConfig/src/GlobalUsings.cs b/tools/Azure.Mcp.Tools.AppConfig/src/GlobalUsings.cs deleted file mode 100644 index 94f2998749..0000000000 --- a/tools/Azure.Mcp.Tools.AppConfig/src/GlobalUsings.cs +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -global using System.CommandLine; -global using ModelContextProtocol.Server; diff --git a/tools/Azure.Mcp.Tools.AppConfig/src/Options/Account/AccountListOptions.cs b/tools/Azure.Mcp.Tools.AppConfig/src/Options/Account/AccountListOptions.cs index 579519ca70..a998aaea98 100644 --- a/tools/Azure.Mcp.Tools.AppConfig/src/Options/Account/AccountListOptions.cs +++ b/tools/Azure.Mcp.Tools.AppConfig/src/Options/Account/AccountListOptions.cs @@ -1,8 +1,22 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using Azure.Mcp.Core.Options; using Microsoft.Mcp.Core.Options; namespace Azure.Mcp.Tools.AppConfig.Options.Account; -public class AccountListOptions : SubscriptionOptions; +public sealed class AccountListOptions : ISubscriptionOption +{ + [Option(OptionDescriptions.Tenant)] + public string? Tenant { get; set; } + + [Option(OptionDescriptions.Subscription)] + public string? Subscription { get; set; } + + [Option(OptionDescriptions.ResourceGroup)] + public string? ResourceGroup { get; set; } + + [Option(Name = "retry")] + public RetryPolicyOptions? RetryPolicy { get; set; } +} diff --git a/tools/Azure.Mcp.Tools.AppConfig/src/Options/AppConfigOptionDefinitions.cs b/tools/Azure.Mcp.Tools.AppConfig/src/Options/AppConfigOptionDefinitions.cs deleted file mode 100644 index 518f31dd52..0000000000 --- a/tools/Azure.Mcp.Tools.AppConfig/src/Options/AppConfigOptionDefinitions.cs +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -namespace Azure.Mcp.Tools.AppConfig.Options; - -public static class AppConfigOptionDefinitions -{ - public const string AccountName = "account"; - public const string KeyName = "key"; - public const string ValueName = "value"; - public const string LabelName = "label"; - public const string ContentTypeName = "content-type"; - public const string TagsName = "tags"; - public const string LockName = "lock"; - public const string KeyFilterName = "key-filter"; - public const string LabelFilterName = "label-filter"; - - public static readonly Option Account = new($"--{AccountName}") - { - Description = "The name of the App Configuration store (e.g., my-appconfig).", - Required = true - }; - - public static readonly Option Key = new($"--{KeyName}") - { - Description = "The name of the key to access within the App Configuration store.", - Required = true - }; - - public static readonly Option Value = new($"--{ValueName}") - { - Description = "The value to set for the configuration key.", - Required = true - }; - - public static readonly Option Label = new($"--{LabelName}") - { - Description = "The label to apply to the configuration key. Labels are used to group and organize settings.", - Required = false - }; - - public static readonly Option ContentType = new($"--{ContentTypeName}") - { - Description = "The content type of the configuration value. This is used to indicate how the value should be interpreted or parsed.", - Required = false - }; - - public static readonly Option Tags = new($"--{TagsName}") - { - Description = "The tags to associate with the configuration key. Tags should be in the format 'key=value'. Multiple tags can be specified.", - Required = false, - AllowMultipleArgumentsPerToken = true - }; - - public static readonly Option Lock = new($"--{LockName}") - { - Description = "Whether a key-value will be locked (set to read-only) or unlocked (read-only removed).", - Required = false - }; - - public static readonly Option KeyFilter = new($"--{KeyFilterName}") - { - Description = "Specifies the key filter, if any, to be used when retrieving key-values. The filter can be an exact match, for example a filter of 'foo' would get all key-values with a key of 'foo', or the filter can include a '*' character at the end of the string for wildcard searches (e.g., 'App*'). If omitted all keys will be retrieved.", - Required = false - }; - - public static readonly Option LabelFilter = new($"--{LabelFilterName}") - { - Description = "Specifies the label filter, if any, to be used when retrieving key-values. The filter can be an exact match, for example a filter of 'foo' would get all key-values with a label of 'foo', or the filter can include a '*' character at the end of the string for wildcard searches (e.g., 'Prod*'). This filter is case-sensitive. If omitted, all labels will be retrieved.", - Required = false - }; -} diff --git a/tools/Azure.Mcp.Tools.AppConfig/src/Options/AppConfigOptionDescriptions.cs b/tools/Azure.Mcp.Tools.AppConfig/src/Options/AppConfigOptionDescriptions.cs new file mode 100644 index 0000000000..931d844f42 --- /dev/null +++ b/tools/Azure.Mcp.Tools.AppConfig/src/Options/AppConfigOptionDescriptions.cs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace Azure.Mcp.Tools.AppConfig.Options; + +/// +/// Common option descriptions for App Configuration. +/// +public static class AppConfigOptionDescriptions +{ + internal const string Account = "The name of the App Configuration store (e.g., my-appconfig)."; + internal const string Key = "The name of the key to access within the App Configuration store."; + internal const string Label = "The label to apply to the configuration key. Labels are used to group and organize settings."; +} diff --git a/tools/Azure.Mcp.Tools.AppConfig/src/Options/BaseAppConfigOptions.cs b/tools/Azure.Mcp.Tools.AppConfig/src/Options/BaseAppConfigOptions.cs deleted file mode 100644 index 03c60cf303..0000000000 --- a/tools/Azure.Mcp.Tools.AppConfig/src/Options/BaseAppConfigOptions.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System.Text.Json.Serialization; -using Microsoft.Mcp.Core.Options; - -namespace Azure.Mcp.Tools.AppConfig.Options; - -public class BaseAppConfigOptions : SubscriptionOptions -{ - [JsonPropertyName(AppConfigOptionDefinitions.AccountName)] - public string? Account { get; set; } -} diff --git a/tools/Azure.Mcp.Tools.AppConfig/src/Options/KeyValue/BaseKeyValueOptions.cs b/tools/Azure.Mcp.Tools.AppConfig/src/Options/KeyValue/BaseKeyValueOptions.cs deleted file mode 100644 index 8774707110..0000000000 --- a/tools/Azure.Mcp.Tools.AppConfig/src/Options/KeyValue/BaseKeyValueOptions.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System.Text.Json.Serialization; - -namespace Azure.Mcp.Tools.AppConfig.Options.KeyValue; - -public class BaseKeyValueOptions : BaseAppConfigOptions -{ - [JsonPropertyName(AppConfigOptionDefinitions.KeyName)] - public string? Key { get; set; } - - [JsonPropertyName(AppConfigOptionDefinitions.LabelName)] - public string? Label { get; set; } - - [JsonPropertyName(AppConfigOptionDefinitions.ContentTypeName)] - public string? ContentType { get; set; } -} diff --git a/tools/Azure.Mcp.Tools.AppConfig/src/Options/KeyValue/KeyValueDeleteOptions.cs b/tools/Azure.Mcp.Tools.AppConfig/src/Options/KeyValue/KeyValueDeleteOptions.cs index 0e4244b596..fd142a5606 100644 --- a/tools/Azure.Mcp.Tools.AppConfig/src/Options/KeyValue/KeyValueDeleteOptions.cs +++ b/tools/Azure.Mcp.Tools.AppConfig/src/Options/KeyValue/KeyValueDeleteOptions.cs @@ -1,6 +1,28 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using Azure.Mcp.Core.Options; +using Microsoft.Mcp.Core.Options; + namespace Azure.Mcp.Tools.AppConfig.Options.KeyValue; -public class KeyValueDeleteOptions : BaseKeyValueOptions; +public sealed class KeyValueDeleteOptions : ISubscriptionOption +{ + [Option(OptionDescriptions.Tenant)] + public string? Tenant { get; set; } + + [Option(OptionDescriptions.Subscription)] + public string? Subscription { get; set; } + + [Option(Name = "retry")] + public RetryPolicyOptions? RetryPolicy { get; set; } + + [Option(AppConfigOptionDescriptions.Account)] + public required string Account { get; set; } + + [Option(AppConfigOptionDescriptions.Key)] + public required string Key { get; set; } + + [Option(AppConfigOptionDescriptions.Label)] + public string? Label { get; set; } +} diff --git a/tools/Azure.Mcp.Tools.AppConfig/src/Options/KeyValue/KeyValueGetOptions.cs b/tools/Azure.Mcp.Tools.AppConfig/src/Options/KeyValue/KeyValueGetOptions.cs index d0cbe0eb2b..94efd2f765 100644 --- a/tools/Azure.Mcp.Tools.AppConfig/src/Options/KeyValue/KeyValueGetOptions.cs +++ b/tools/Azure.Mcp.Tools.AppConfig/src/Options/KeyValue/KeyValueGetOptions.cs @@ -1,21 +1,34 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using System.Text.Json.Serialization; +using Azure.Mcp.Core.Options; +using Microsoft.Mcp.Core.Options; namespace Azure.Mcp.Tools.AppConfig.Options.KeyValue; -public class KeyValueGetOptions : BaseAppConfigOptions +public class KeyValueGetOptions : ISubscriptionOption { - [JsonPropertyName(AppConfigOptionDefinitions.KeyName)] + [Option(OptionDescriptions.Tenant)] + public string? Tenant { get; set; } + + [Option(OptionDescriptions.Subscription)] + public string? Subscription { get; set; } + + [Option(Name = "retry")] + public RetryPolicyOptions? RetryPolicy { get; set; } + + [Option(AppConfigOptionDescriptions.Account)] + public required string Account { get; set; } + + [Option(AppConfigOptionDescriptions.Key)] public string? Key { get; set; } - [JsonPropertyName(AppConfigOptionDefinitions.LabelName)] + [Option(AppConfigOptionDescriptions.Label)] public string? Label { get; set; } - [JsonPropertyName(AppConfigOptionDefinitions.KeyFilterName)] + [Option("Specifies the key filter, if any, to be used when retrieving key-values. The filter can be an exact match, for example a filter of 'foo' would get all key-values with a key of 'foo', or the filter can include a '*' character at the end of the string for wildcard searches (e.g., 'App*'). If omitted all keys will be retrieved.")] public string? KeyFilter { get; set; } - [JsonPropertyName(AppConfigOptionDefinitions.LabelFilterName)] + [Option("Specifies the label filter, if any, to be used when retrieving key-values. The filter can be an exact match, for example a filter of 'foo' would get all key-values with a label of 'foo', or the filter can include a '*' character at the end of the string for wildcard searches (e.g., 'Prod*'). This filter is case-sensitive. If omitted, all labels will be retrieved.")] public string? LabelFilter { get; set; } } diff --git a/tools/Azure.Mcp.Tools.AppConfig/src/Options/KeyValue/KeyValueSetOptions.cs b/tools/Azure.Mcp.Tools.AppConfig/src/Options/KeyValue/KeyValueSetOptions.cs index 3da8d6da10..e9c58e4e0a 100644 --- a/tools/Azure.Mcp.Tools.AppConfig/src/Options/KeyValue/KeyValueSetOptions.cs +++ b/tools/Azure.Mcp.Tools.AppConfig/src/Options/KeyValue/KeyValueSetOptions.cs @@ -1,15 +1,37 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using System.Text.Json.Serialization; +using Azure.Mcp.Core.Options; +using Microsoft.Mcp.Core.Options; namespace Azure.Mcp.Tools.AppConfig.Options.KeyValue; -public class KeyValueSetOptions : BaseKeyValueOptions +public class KeyValueSetOptions : ISubscriptionOption { - [JsonPropertyName(AppConfigOptionDefinitions.ValueName)] - public string? Value { get; set; } + [Option(OptionDescriptions.Tenant)] + public string? Tenant { get; set; } - [JsonPropertyName(AppConfigOptionDefinitions.TagsName)] + [Option(OptionDescriptions.Subscription)] + public string? Subscription { get; set; } + + [Option(Name = "retry")] + public RetryPolicyOptions? RetryPolicy { get; set; } + + [Option(AppConfigOptionDescriptions.Account)] + public required string Account { get; set; } + + [Option(AppConfigOptionDescriptions.Key)] + public required string Key { get; set; } + + [Option(AppConfigOptionDescriptions.Label)] + public string? Label { get; set; } + + [Option("The content type of the configuration value. This is used to indicate how the value should be interpreted or parsed.")] + public string? ContentType { get; set; } + + [Option("The value to set for the configuration key.")] + public required string Value { get; set; } + + [Option("The tags to associate with the configuration key. Tags should be in the format 'key=value'. Multiple tags can be specified.")] public string[]? Tags { get; set; } } diff --git a/tools/Azure.Mcp.Tools.AppConfig/src/Options/KeyValue/Lock/KeyValueLockSetOptions.cs b/tools/Azure.Mcp.Tools.AppConfig/src/Options/KeyValue/Lock/KeyValueLockSetOptions.cs index 2d31551398..eaab5ffc4b 100644 --- a/tools/Azure.Mcp.Tools.AppConfig/src/Options/KeyValue/Lock/KeyValueLockSetOptions.cs +++ b/tools/Azure.Mcp.Tools.AppConfig/src/Options/KeyValue/Lock/KeyValueLockSetOptions.cs @@ -8,24 +8,24 @@ namespace Azure.Mcp.Tools.AppConfig.Options.KeyValue.Lock; public class KeyValueLockSetOptions : ISubscriptionOption { + [Option(OptionDescriptions.Tenant)] + public string? Tenant { get; set; } + [Option(OptionDescriptions.Subscription)] public string? Subscription { get; set; } + [Option(Name = "retry")] + public RetryPolicyOptions? RetryPolicy { get; set; } + [Option("Whether a key-value will be locked (set to read-only) or unlocked (read-only removed).")] public bool? Lock { get; set; } - [Option("The name of the App Configuration store (e.g., my-appconfig).")] + [Option(AppConfigOptionDescriptions.Account)] public required string Account { get; set; } - [Option("The name of the key to access within the App Configuration store.")] + [Option(AppConfigOptionDescriptions.Key)] public required string Key { get; set; } - [Option("The label to apply to the configuration key. Labels are used to group and organize settings.")] + [Option(AppConfigOptionDescriptions.Label)] public string? Label { get; set; } - - [Option(OptionDescriptions.Tenant)] - public string? Tenant { get; set; } - - [Option(Name = "retry")] - public RetryPolicyOptions? RetryPolicy { get; set; } } diff --git a/tools/Azure.Mcp.Tools.AppConfig/tests/Azure.Mcp.Tools.AppConfig.Tests/Account/AccountListCommandTests.cs b/tools/Azure.Mcp.Tools.AppConfig/tests/Azure.Mcp.Tools.AppConfig.Tests/Account/AccountListCommandTests.cs index 816b4ad840..0fabdd8fea 100644 --- a/tools/Azure.Mcp.Tools.AppConfig/tests/Azure.Mcp.Tools.AppConfig.Tests/Account/AccountListCommandTests.cs +++ b/tools/Azure.Mcp.Tools.AppConfig/tests/Azure.Mcp.Tools.AppConfig.Tests/Account/AccountListCommandTests.cs @@ -3,19 +3,19 @@ using System.Net; using Azure.Mcp.Core.Services.Azure; +using Azure.Mcp.Tests.Commands; using Azure.Mcp.Tools.AppConfig.Commands; using Azure.Mcp.Tools.AppConfig.Commands.Account; using Azure.Mcp.Tools.AppConfig.Models; using Azure.Mcp.Tools.AppConfig.Services; using Microsoft.Mcp.Core.Options; -using Microsoft.Mcp.Tests.Client; using NSubstitute; using NSubstitute.ExceptionExtensions; using Xunit; namespace Azure.Mcp.Tools.AppConfig.Tests.Account; -public class AccountListCommandTests : CommandUnitTestsBase +public class AccountListCommandTests : SubscriptionCommandUnitTestsBase { [Fact] public async Task ExecuteAsync_ReturnsAccounts_WhenAccountsExist() diff --git a/tools/Azure.Mcp.Tools.AppConfig/tests/Azure.Mcp.Tools.AppConfig.Tests/KeyValue/KeyValueDeleteCommandTests.cs b/tools/Azure.Mcp.Tools.AppConfig/tests/Azure.Mcp.Tools.AppConfig.Tests/KeyValue/KeyValueDeleteCommandTests.cs index 6b27adac88..73c94733ea 100644 --- a/tools/Azure.Mcp.Tools.AppConfig/tests/Azure.Mcp.Tools.AppConfig.Tests/KeyValue/KeyValueDeleteCommandTests.cs +++ b/tools/Azure.Mcp.Tools.AppConfig/tests/Azure.Mcp.Tools.AppConfig.Tests/KeyValue/KeyValueDeleteCommandTests.cs @@ -2,18 +2,18 @@ // Licensed under the MIT License. using System.Net; +using Azure.Mcp.Tests.Commands; using Azure.Mcp.Tools.AppConfig.Commands; using Azure.Mcp.Tools.AppConfig.Commands.KeyValue; using Azure.Mcp.Tools.AppConfig.Services; using Microsoft.Mcp.Core.Options; -using Microsoft.Mcp.Tests.Client; using NSubstitute; using NSubstitute.ExceptionExtensions; using Xunit; namespace Azure.Mcp.Tools.AppConfig.Tests.KeyValue; -public class KeyValueDeleteCommandTests : CommandUnitTestsBase +public class KeyValueDeleteCommandTests : SubscriptionCommandUnitTestsBase { [Fact] public async Task ExecuteAsync_DeletesKeyValue_WhenValidParametersProvided() diff --git a/tools/Azure.Mcp.Tools.AppConfig/tests/Azure.Mcp.Tools.AppConfig.Tests/KeyValue/KeyValueGetCommandTests.cs b/tools/Azure.Mcp.Tools.AppConfig/tests/Azure.Mcp.Tools.AppConfig.Tests/KeyValue/KeyValueGetCommandTests.cs index a1852095bf..dffa375dac 100644 --- a/tools/Azure.Mcp.Tools.AppConfig/tests/Azure.Mcp.Tools.AppConfig.Tests/KeyValue/KeyValueGetCommandTests.cs +++ b/tools/Azure.Mcp.Tools.AppConfig/tests/Azure.Mcp.Tools.AppConfig.Tests/KeyValue/KeyValueGetCommandTests.cs @@ -2,19 +2,19 @@ // Licensed under the MIT License. using System.Net; +using Azure.Mcp.Tests.Commands; using Azure.Mcp.Tools.AppConfig.Commands; using Azure.Mcp.Tools.AppConfig.Commands.KeyValue; using Azure.Mcp.Tools.AppConfig.Models; using Azure.Mcp.Tools.AppConfig.Services; using Microsoft.Mcp.Core.Options; -using Microsoft.Mcp.Tests.Client; using NSubstitute; using NSubstitute.ExceptionExtensions; using Xunit; namespace Azure.Mcp.Tools.AppConfig.Tests.KeyValue; -public class KeyValueGetCommandTests : CommandUnitTestsBase +public class KeyValueGetCommandTests : SubscriptionCommandUnitTestsBase { [Fact] public async Task ExecuteAsync_ReturnsSettingsList_WhenSettingsExist() diff --git a/tools/Azure.Mcp.Tools.AppConfig/tests/Azure.Mcp.Tools.AppConfig.Tests/KeyValue/KeyValueSetCommandTests.cs b/tools/Azure.Mcp.Tools.AppConfig/tests/Azure.Mcp.Tools.AppConfig.Tests/KeyValue/KeyValueSetCommandTests.cs index 4caac3f35b..76d685a96b 100644 --- a/tools/Azure.Mcp.Tools.AppConfig/tests/Azure.Mcp.Tools.AppConfig.Tests/KeyValue/KeyValueSetCommandTests.cs +++ b/tools/Azure.Mcp.Tools.AppConfig/tests/Azure.Mcp.Tools.AppConfig.Tests/KeyValue/KeyValueSetCommandTests.cs @@ -2,18 +2,18 @@ // Licensed under the MIT License. using System.Net; +using Azure.Mcp.Tests.Commands; using Azure.Mcp.Tools.AppConfig.Commands; using Azure.Mcp.Tools.AppConfig.Commands.KeyValue; using Azure.Mcp.Tools.AppConfig.Services; using Microsoft.Mcp.Core.Options; -using Microsoft.Mcp.Tests.Client; using NSubstitute; using NSubstitute.ExceptionExtensions; using Xunit; namespace Azure.Mcp.Tools.AppConfig.Tests.KeyValue; -public class KeyValueSetCommandTests : CommandUnitTestsBase +public class KeyValueSetCommandTests : SubscriptionCommandUnitTestsBase { [Fact] public async Task ExecuteAsync_SetsKeyValue_WhenValidParametersProvided()