diff --git a/servers/Azure.Mcp.Server/changelog-entries/1781298285544.yaml b/servers/Azure.Mcp.Server/changelog-entries/1781298285544.yaml
new file mode 100644
index 0000000000..86ff80c750
--- /dev/null
+++ b/servers/Azure.Mcp.Server/changelog-entries/1781298285544.yaml
@@ -0,0 +1,3 @@
+changes:
+ - section: "Breaking Changes"
+ description: "Removed unused parameters from App Service tools."
diff --git a/tools/Azure.Mcp.Tools.AppService/src/Azure.Mcp.Tools.AppService.csproj b/tools/Azure.Mcp.Tools.AppService/src/Azure.Mcp.Tools.AppService.csproj
index d142f82723..ce87031e90 100644
--- a/tools/Azure.Mcp.Tools.AppService/src/Azure.Mcp.Tools.AppService.csproj
+++ b/tools/Azure.Mcp.Tools.AppService/src/Azure.Mcp.Tools.AppService.csproj
@@ -14,6 +14,5 @@
-
diff --git a/tools/Azure.Mcp.Tools.AppService/src/Commands/BaseAppServiceCommand.cs b/tools/Azure.Mcp.Tools.AppService/src/Commands/BaseAppServiceCommand.cs
deleted file mode 100644
index ea7105e340..0000000000
--- a/tools/Azure.Mcp.Tools.AppService/src/Commands/BaseAppServiceCommand.cs
+++ /dev/null
@@ -1,36 +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.AppService.Options;
-using Microsoft.Mcp.Core.Commands;
-using Microsoft.Mcp.Core.Extensions;
-using Microsoft.Mcp.Core.Models.Option;
-
-namespace Azure.Mcp.Tools.AppService.Commands;
-
-public abstract class BaseAppServiceCommand<
- [DynamicallyAccessedMembers(TrimAnnotations.CommandAnnotations)] TOptions>(bool resourceGroupRequired = false, bool appRequired = false)
- : SubscriptionCommand
- where TOptions : BaseAppServiceOptions, new()
-{
- protected override void RegisterOptions(Command command)
- {
- base.RegisterOptions(command);
- command.Options.Add(resourceGroupRequired
- ? OptionDefinitions.Common.ResourceGroup.AsRequired()
- : OptionDefinitions.Common.ResourceGroup.AsOptional());
- command.Options.Add(appRequired
- ? AppServiceOptionDefinitions.AppServiceName.AsRequired()
- : AppServiceOptionDefinitions.AppServiceName.AsOptional());
- }
-
- protected override TOptions BindOptions(ParseResult parseResult)
- {
- var options = base.BindOptions(parseResult);
- options.ResourceGroup ??= parseResult.GetValueOrDefault(OptionDefinitions.Common.ResourceGroup.Name);
- options.AppName = parseResult.GetValueOrDefault(AppServiceOptionDefinitions.AppServiceName.Name);
- return options;
- }
-}
diff --git a/tools/Azure.Mcp.Tools.AppService/src/Commands/Database/DatabaseAddCommand.cs b/tools/Azure.Mcp.Tools.AppService/src/Commands/Database/DatabaseAddCommand.cs
index 68fb394201..471a1713ae 100644
--- a/tools/Azure.Mcp.Tools.AppService/src/Commands/Database/DatabaseAddCommand.cs
+++ b/tools/Azure.Mcp.Tools.AppService/src/Commands/Database/DatabaseAddCommand.cs
@@ -1,13 +1,13 @@
// 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.AppService.Models;
-using Azure.Mcp.Tools.AppService.Options;
using Azure.Mcp.Tools.AppService.Options.Database;
using Azure.Mcp.Tools.AppService.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.AppService.Commands.Database;
@@ -27,51 +27,24 @@ namespace Azure.Mcp.Tools.AppService.Commands.Database;
ReadOnly = false,
Secret = false,
LocalRequired = false)]
-public sealed class DatabaseAddCommand(ILogger logger, IAppServiceService appServiceService)
- : BaseAppServiceCommand(resourceGroupRequired: true, appRequired: true)
+public sealed class DatabaseAddCommand(ILogger logger, IAppServiceService appServiceService, ISubscriptionResolver subscriptionResolver)
+ : SubscriptionCommand(subscriptionResolver)
{
private readonly ILogger _logger = logger;
private readonly IAppServiceService _appServiceService = appServiceService;
- protected override void RegisterOptions(Command command)
+ public override async Task ExecuteAsync(CommandContext context, DatabaseAddOptions options, CancellationToken cancellationToken)
{
- base.RegisterOptions(command);
- command.Options.Add(AppServiceOptionDefinitions.DatabaseTypeOption);
- command.Options.Add(AppServiceOptionDefinitions.DatabaseServerOption);
- command.Options.Add(AppServiceOptionDefinitions.DatabaseNameOption);
- command.Options.Add(AppServiceOptionDefinitions.ConnectionStringOption);
- }
-
- protected override DatabaseAddOptions BindOptions(ParseResult parseResult)
- {
- var options = base.BindOptions(parseResult);
- options.DatabaseType = parseResult.GetValueOrDefault(AppServiceOptionDefinitions.DatabaseTypeOption);
- options.DatabaseServer = parseResult.GetValueOrDefault(AppServiceOptionDefinitions.DatabaseServerOption);
- options.DatabaseName = parseResult.GetValueOrDefault(AppServiceOptionDefinitions.DatabaseNameOption);
- options.ConnectionString = parseResult.GetValueOrDefault(AppServiceOptionDefinitions.ConnectionStringOption);
- return options;
- }
-
- public override async Task ExecuteAsync(CommandContext context, ParseResult parseResult, CancellationToken cancellationToken)
- {
- // Validate first, then bind
- if (!Validate(parseResult.CommandResult, context.Response).IsValid)
- {
- return context.Response;
- }
-
- var options = BindOptions(parseResult);
-
try
{
context.Activity?.AddTag("subscription", options.Subscription);
var connectionInfo = await _appServiceService.AddDatabaseAsync(
- options.AppName!,
- options.ResourceGroup!,
- options.DatabaseType!,
- options.DatabaseServer!,
- options.DatabaseName!,
+ options.App,
+ options.ResourceGroup,
+ options.DatabaseType,
+ options.DatabaseServer,
+ options.Database,
options.ConnectionString ?? string.Empty, // connectionString - will be generated if not provided
options.Subscription!,
options.Tenant,
@@ -82,12 +55,12 @@ public override async Task ExecuteAsync(CommandContext context,
}
catch (Exception ex)
{
- _logger.LogError(ex, "Failed to add database connection to App Service '{AppName}'", options.AppName);
+ _logger.LogError(ex, "Failed to add database connection to App Service '{App}'", options.App);
HandleException(context, ex);
}
return context.Response;
}
- public record DatabaseAddResult(DatabaseConnectionInfo ConnectionInfo);
+ public sealed record DatabaseAddResult(DatabaseConnectionInfo ConnectionInfo);
}
diff --git a/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/Deployment/DeploymentGetCommand.cs b/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/Deployment/DeploymentGetCommand.cs
index d42a33982e..cdecf5d5fd 100644
--- a/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/Deployment/DeploymentGetCommand.cs
+++ b/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/Deployment/DeploymentGetCommand.cs
@@ -1,13 +1,13 @@
// 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.AppService.Models;
-using Azure.Mcp.Tools.AppService.Options;
using Azure.Mcp.Tools.AppService.Options.Webapp.Deployment;
using Azure.Mcp.Tools.AppService.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.AppService.Commands.Webapp.Deployment;
@@ -29,43 +29,22 @@ namespace Azure.Mcp.Tools.AppService.Commands.Webapp.Deployment;
ReadOnly = true,
Secret = false,
LocalRequired = false)]
-public sealed class DeploymentGetCommand(ILogger logger, IAppServiceService appServiceService)
- : BaseAppServiceCommand(resourceGroupRequired: true, appRequired: true)
+public sealed class DeploymentGetCommand(ILogger logger, IAppServiceService appServiceService, ISubscriptionResolver subscriptionResolver)
+ : SubscriptionCommand(subscriptionResolver)
{
private readonly ILogger _logger = logger;
private readonly IAppServiceService _appServiceService = appServiceService;
- protected override void RegisterOptions(Command command)
+ public override async Task ExecuteAsync(CommandContext context, DeploymentGetOptions options, CancellationToken cancellationToken)
{
- base.RegisterOptions(command);
- command.Options.Add(AppServiceOptionDefinitions.DeploymentIdOption);
- }
-
- protected override DeploymentGetOptions BindOptions(ParseResult parseResult)
- {
- var options = base.BindOptions(parseResult);
- options.DeploymentId = parseResult.GetValueOrDefault(AppServiceOptionDefinitions.DeploymentIdOption.Name);
- return options;
- }
-
- public override async Task ExecuteAsync(CommandContext context, ParseResult parseResult, CancellationToken cancellationToken)
- {
- // Validate first, then bind
- if (!Validate(parseResult.CommandResult, context.Response).IsValid)
- {
- return context.Response;
- }
-
- var options = BindOptions(parseResult);
-
try
{
context.Activity?.AddTag("subscription", options.Subscription);
var deployments = await _appServiceService.GetDeploymentsAsync(
options.Subscription!,
- options.ResourceGroup!,
- options.AppName!,
+ options.ResourceGroup,
+ options.App,
options.DeploymentId,
options.Tenant,
options.RetryPolicy,
@@ -77,13 +56,13 @@ public override async Task ExecuteAsync(CommandContext context,
{
if (options.DeploymentId == null)
{
- _logger.LogError(ex, "Failed to list deployments for Web App '{AppName}' in resource group {ResourceGroup} and subscription {Subscription}",
- options.AppName, options.ResourceGroup, options.Subscription);
+ _logger.LogError(ex, "Failed to list deployments for Web App '{App}' in resource group {ResourceGroup} and subscription {Subscription}",
+ options.App, options.ResourceGroup, options.Subscription);
}
else
{
- _logger.LogError(ex, "Failed to get deployment '{DeploymentId}' for Web App '{AppName}' in subscription {Subscription} and resource group {ResourceGroup}",
- options.DeploymentId, options.AppName, options.Subscription, options.ResourceGroup);
+ _logger.LogError(ex, "Failed to get deployment '{DeploymentId}' for Web App '{App}' in subscription {Subscription} and resource group {ResourceGroup}",
+ options.DeploymentId, options.App, options.Subscription, options.ResourceGroup);
}
HandleException(context, ex);
}
@@ -91,5 +70,5 @@ public override async Task ExecuteAsync(CommandContext context,
return context.Response;
}
- public record DeploymentGetResult(List Deployments);
+ public sealed record DeploymentGetResult(List Deployments);
}
diff --git a/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/Diagnostic/DetectorDiagnoseCommand.cs b/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/Diagnostic/DetectorDiagnoseCommand.cs
index 74d05ae0a6..0746636f90 100644
--- a/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/Diagnostic/DetectorDiagnoseCommand.cs
+++ b/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/Diagnostic/DetectorDiagnoseCommand.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.AppService.Models;
-using Azure.Mcp.Tools.AppService.Options;
using Azure.Mcp.Tools.AppService.Options.Webapp.Diagnostic;
using Azure.Mcp.Tools.AppService.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.AppService.Commands.Webapp.Diagnostic;
@@ -29,82 +28,36 @@ namespace Azure.Mcp.Tools.AppService.Commands.Webapp.Diagnostic;
ReadOnly = true,
Secret = false,
LocalRequired = false)]
-public sealed class DetectorDiagnoseCommand(ILogger logger, IAppServiceService appServiceService)
- : BaseAppServiceCommand(resourceGroupRequired: true, appRequired: true)
+public sealed class DetectorDiagnoseCommand(ILogger logger, IAppServiceService appServiceService, ISubscriptionResolver subscriptionResolver)
+ : SubscriptionCommand(subscriptionResolver)
{
private readonly ILogger _logger = logger;
private readonly IAppServiceService _appServiceService = appServiceService;
- protected override void RegisterOptions(Command command)
+ public override void ValidateOptions(DetectorDiagnoseOptions options, ValidationResult validationResult)
{
- base.RegisterOptions(command);
- command.Options.Add(AppServiceOptionDefinitions.DetectorId.AsRequired());
- command.Options.Add(AppServiceOptionDefinitions.StartTime);
- command.Options.Add(AppServiceOptionDefinitions.EndTime);
- command.Options.Add(AppServiceOptionDefinitions.Interval);
- command.Validators.Add(result =>
- {
- var startTime = result.GetValueOrDefault(AppServiceOptionDefinitions.StartTime.Name);
- var endTime = result.GetValueOrDefault(AppServiceOptionDefinitions.EndTime.Name);
-
- bool hasStartTime = !string.IsNullOrEmpty(startTime);
- bool hasEndTime = !string.IsNullOrEmpty(endTime);
-
- if (hasStartTime && !DateTimeOffset.TryParse(startTime, out _))
- {
- result.AddError($"Invalid start time format: {startTime}. Please provide a valid ISO format date time string.");
- }
+ base.ValidateOptions(options, validationResult);
- if (hasEndTime && !DateTimeOffset.TryParse(endTime, out _))
- {
- result.AddError($"Invalid end time format: {endTime}. Please provide a valid ISO format date time string.");
- }
+ options.StartTime = options.StartTime?.ToUniversalTime();
+ options.EndTime = options.EndTime?.ToUniversalTime();
- if (hasStartTime && hasEndTime
- && DateTimeOffset.TryParse(startTime, out var start)
- && DateTimeOffset.TryParse(endTime, out var end)
- && start > end)
- {
- result.AddError($"Start time '{startTime}' must be earlier than end time '{endTime}'.");
- }
- });
- }
-
- protected override DetectorDiagnoseOptions BindOptions(ParseResult parseResult)
- {
- var options = base.BindOptions(parseResult);
- options.DetectorId = parseResult.GetValueOrDefault(AppServiceOptionDefinitions.DetectorId.Name);
- if (DateTimeOffset.TryParse(parseResult.GetValueOrDefault(AppServiceOptionDefinitions.StartTime.Name), out var startTime))
+ if (options.StartTime != null && options.EndTime != null && options.StartTime > options.EndTime)
{
- options.StartTime = startTime.ToUniversalTime();
+ validationResult.Errors.Add($"Start time '{options.StartTime}' must be earlier than end time '{options.EndTime}'.");
}
- if (DateTimeOffset.TryParse(parseResult.GetValueOrDefault(AppServiceOptionDefinitions.EndTime.Name), out var endTime))
- {
- options.EndTime = endTime.ToUniversalTime();
- }
- options.Interval = parseResult.GetValueOrDefault(AppServiceOptionDefinitions.Interval.Name);
- return options;
}
- public override async Task ExecuteAsync(CommandContext context, ParseResult parseResult, CancellationToken cancellationToken)
+ public override async Task ExecuteAsync(CommandContext context, DetectorDiagnoseOptions options, CancellationToken cancellationToken)
{
- // Validate first, then bind
- if (!Validate(parseResult.CommandResult, context.Response).IsValid)
- {
- return context.Response;
- }
-
- var options = BindOptions(parseResult);
-
try
{
context.Activity?.AddTag("subscription", options.Subscription);
var diagnoses = await _appServiceService.DiagnoseDetectorAsync(
options.Subscription!,
- options.ResourceGroup!,
- options.AppName!,
- options.DetectorId!,
+ options.ResourceGroup,
+ options.App,
+ options.DetectorId,
options.StartTime,
options.EndTime,
options.Interval,
@@ -116,13 +69,13 @@ public override async Task ExecuteAsync(CommandContext context,
}
catch (Exception ex)
{
- _logger.LogError(ex, "Failed to get diagnostic detectors for Web App '{AppName}' in subscription {Subscription} and resource group {ResourceGroup}",
- options.AppName, options.Subscription, options.ResourceGroup);
+ _logger.LogError(ex, "Failed to get diagnostic detectors for Web App '{App}' in subscription {Subscription} and resource group {ResourceGroup}",
+ options.App, options.Subscription, options.ResourceGroup);
HandleException(context, ex);
}
return context.Response;
}
- public record DetectorDiagnoseResult(DiagnosisResults Diagnoses);
+ public sealed record DetectorDiagnoseResult(DiagnosisResults Diagnoses);
}
diff --git a/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/Diagnostic/DetectorListCommand.cs b/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/Diagnostic/DetectorListCommand.cs
index 4845c702ab..957b3bbc78 100644
--- a/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/Diagnostic/DetectorListCommand.cs
+++ b/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/Diagnostic/DetectorListCommand.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.AppService.Models;
using Azure.Mcp.Tools.AppService.Options;
using Azure.Mcp.Tools.AppService.Services;
@@ -26,34 +28,22 @@ namespace Azure.Mcp.Tools.AppService.Commands.Webapp.Diagnostic;
ReadOnly = true,
Secret = false,
LocalRequired = false)]
-public sealed class DetectorListCommand(ILogger logger, IAppServiceService appServiceService)
- : BaseAppServiceCommand(resourceGroupRequired: true, appRequired: true)
+public sealed class DetectorListCommand(ILogger logger, IAppServiceService appServiceService, ISubscriptionResolver subscriptionResolver)
+ : SubscriptionCommand(subscriptionResolver)
{
private readonly ILogger _logger = logger;
private readonly IAppServiceService _appServiceService = appServiceService;
- protected override void RegisterOptions(Command command) => base.RegisterOptions(command);
-
- protected override BaseAppServiceOptions BindOptions(ParseResult parseResult) => base.BindOptions(parseResult);
-
- public override async Task ExecuteAsync(CommandContext context, ParseResult parseResult, CancellationToken cancellationToken)
+ public override async Task ExecuteAsync(CommandContext context, BaseAppServiceOptions options, CancellationToken cancellationToken)
{
- // Validate first, then bind
- if (!Validate(parseResult.CommandResult, context.Response).IsValid)
- {
- return context.Response;
- }
-
- var options = BindOptions(parseResult);
-
try
{
context.Activity?.AddTag("subscription", options.Subscription);
var detectors = await _appServiceService.ListDetectorsAsync(
options.Subscription!,
- options.ResourceGroup!,
- options.AppName!,
+ options.ResourceGroup,
+ options.App,
options.Tenant,
options.RetryPolicy,
cancellationToken);
@@ -62,13 +52,13 @@ public override async Task ExecuteAsync(CommandContext context,
}
catch (Exception ex)
{
- _logger.LogError(ex, "Failed to get diagnostic detectors for Web App '{AppName}' in subscription {Subscription} and resource group {ResourceGroup}",
- options.AppName, options.Subscription, options.ResourceGroup);
+ _logger.LogError(ex, "Failed to get diagnostic detectors for Web App '{App}' in subscription {Subscription} and resource group {ResourceGroup}",
+ options.App, options.Subscription, options.ResourceGroup);
HandleException(context, ex);
}
return context.Response;
}
- public record DetectorListResult(List Detectors);
+ public sealed record DetectorListResult(List Detectors);
}
diff --git a/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/Settings/AppSettingsGetCommand.cs b/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/Settings/AppSettingsGetCommand.cs
index df12162761..96a51fce17 100644
--- a/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/Settings/AppSettingsGetCommand.cs
+++ b/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/Settings/AppSettingsGetCommand.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.AppService.Options;
using Azure.Mcp.Tools.AppService.Services;
using Microsoft.Extensions.Logging;
@@ -23,34 +25,22 @@ setting. Application settings may contain sensitive information.
ReadOnly = true,
Secret = true,
LocalRequired = false)]
-public sealed class AppSettingsGetCommand(ILogger logger, IAppServiceService appServiceService)
- : BaseAppServiceCommand(resourceGroupRequired: true, appRequired: true)
+public sealed class AppSettingsGetCommand(ILogger logger, IAppServiceService appServiceService, ISubscriptionResolver subscriptionResolver)
+ : SubscriptionCommand(subscriptionResolver)
{
private readonly ILogger _logger = logger;
private readonly IAppServiceService _appServiceService = appServiceService;
- protected override void RegisterOptions(Command command) => base.RegisterOptions(command);
-
- protected override BaseAppServiceOptions BindOptions(ParseResult parseResult) => base.BindOptions(parseResult);
-
- public override async Task ExecuteAsync(CommandContext context, ParseResult parseResult, CancellationToken cancellationToken)
+ public override async Task ExecuteAsync(CommandContext context, BaseAppServiceOptions options, CancellationToken cancellationToken)
{
- // Validate first, then bind
- if (!Validate(parseResult.CommandResult, context.Response).IsValid)
- {
- return context.Response;
- }
-
- var options = BindOptions(parseResult);
-
try
{
context.Activity?.AddTag("subscription", options.Subscription);
var appSettings = await _appServiceService.GetAppSettingsAsync(
options.Subscription!,
- options.ResourceGroup!,
- options.AppName!,
+ options.ResourceGroup,
+ options.App,
options.Tenant,
options.RetryPolicy,
cancellationToken);
@@ -59,13 +49,13 @@ public override async Task ExecuteAsync(CommandContext context,
}
catch (Exception ex)
{
- _logger.LogError(ex, "Failed to get application settings for Web App details for '{AppName}' in subscription {Subscription} and resource group {ResourceGroup}",
- options.AppName, options.Subscription, options.ResourceGroup);
+ _logger.LogError(ex, "Failed to get application settings for Web App details for '{App}' in subscription {Subscription} and resource group {ResourceGroup}",
+ options.App, options.Subscription, options.ResourceGroup);
HandleException(context, ex);
}
return context.Response;
}
- public record AppSettingsGetResult(IDictionary AppSettings);
+ public sealed record AppSettingsGetResult(IDictionary AppSettings);
}
diff --git a/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/Settings/AppSettingsUpdateCommand.cs b/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/Settings/AppSettingsUpdateCommand.cs
index eda6e82d40..c4f5293c7c 100644
--- a/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/Settings/AppSettingsUpdateCommand.cs
+++ b/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/Settings/AppSettingsUpdateCommand.cs
@@ -1,12 +1,13 @@
// 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.AppService.Options;
using Azure.Mcp.Tools.AppService.Options.Webapp.Settings;
using Azure.Mcp.Tools.AppService.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.AppService.Commands.Webapp.Settings;
@@ -30,43 +31,35 @@ namespace Azure.Mcp.Tools.AppService.Commands.Webapp.Settings;
ReadOnly = false,
Secret = false,
LocalRequired = false)]
-public sealed class AppSettingsUpdateCommand(ILogger logger, IAppServiceService appServiceService)
- : BaseAppServiceCommand(resourceGroupRequired: true, appRequired: true)
+public sealed class AppSettingsUpdateCommand(ILogger logger, IAppServiceService appServiceService, ISubscriptionResolver subscriptionResolver)
+ : SubscriptionCommand(subscriptionResolver)
{
private readonly ILogger _logger = logger;
private readonly IAppServiceService _appServiceService = appServiceService;
- private static readonly HashSet ValidUpdateTypes = ["add", "set", "delete"];
+ private static readonly HashSet s_validUpdateTypes = ["add", "set", "delete"];
- protected override void RegisterOptions(Command command)
+ public override void ValidateOptions(AppSettingsUpdateOptions options, ValidationResult validationResult)
{
- base.RegisterOptions(command);
- command.Options.Add(AppServiceOptionDefinitions.AppSettingName);
- command.Options.Add(AppServiceOptionDefinitions.AppSettingValue);
- command.Options.Add(AppServiceOptionDefinitions.AppSettingUpdateType);
- command.Validators.Add(commandResult =>
+ base.ValidateOptions(options, validationResult);
+
+ if (!ValidateUpdateType(options.SettingUpdateType, out var errorMessage))
+ {
+ validationResult.Errors.Add(errorMessage);
+ }
+
+ if (!ValidateSettingValue(options.SettingUpdateType, options.SettingValue, out errorMessage))
{
- var updateType = commandResult.GetValueOrDefault(AppServiceOptionDefinitions.AppSettingUpdateType.Name);
- var settingValue = commandResult.GetValueOrDefault(AppServiceOptionDefinitions.AppSettingValue.Name);
-
- if (!ValidateUpdateType(updateType, out var errorMessage))
- {
- commandResult.AddError(errorMessage);
- }
-
- if (!ValidateSettingValue(updateType, settingValue, out errorMessage))
- {
- commandResult.AddError(errorMessage);
- }
- });
+ validationResult.Errors.Add(errorMessage);
+ }
}
internal static bool ValidateUpdateType(string? settingUpdateType, out string errorMessage)
{
errorMessage = string.Empty;
- if (!ValidUpdateTypes.Contains(settingUpdateType, StringComparer.OrdinalIgnoreCase))
+ if (!s_validUpdateTypes.Contains(settingUpdateType, StringComparer.OrdinalIgnoreCase))
{
- errorMessage = $"'{AppServiceOptionDefinitions.AppSettingUpdateTypeName}' must be one of the following values: {string.Join(", ", ValidUpdateTypes)}.";
+ errorMessage = $"'{AppServiceOptionDefinitions.AppSettingUpdateTypeName}' must be one of the following values: {string.Join(", ", s_validUpdateTypes)}.";
return false;
}
return true;
@@ -84,35 +77,18 @@ internal static bool ValidateSettingValue(string? settingUpdateType, string? set
return true;
}
- protected override AppSettingsUpdateOptions BindOptions(ParseResult parseResult)
- {
- var options = base.BindOptions(parseResult);
- options.SettingName = parseResult.GetValueOrDefault(AppServiceOptionDefinitions.AppSettingName.Name);
- options.SettingValue = parseResult.GetValueOrDefault(AppServiceOptionDefinitions.AppSettingValue.Name);
- options.SettingUpdateType = parseResult.GetValueOrDefault(AppServiceOptionDefinitions.AppSettingUpdateType.Name);
- return options;
- }
-
- public override async Task ExecuteAsync(CommandContext context, ParseResult parseResult, CancellationToken cancellationToken)
+ public override async Task ExecuteAsync(CommandContext context, AppSettingsUpdateOptions options, CancellationToken cancellationToken)
{
- // Validate first, then bind
- if (!Validate(parseResult.CommandResult, context.Response).IsValid)
- {
- return context.Response;
- }
-
- var options = BindOptions(parseResult);
-
try
{
context.Activity?.AddTag("subscription", options.Subscription);
var updateResult = await _appServiceService.UpdateAppSettingsAsync(
options.Subscription!,
- options.ResourceGroup!,
- options.AppName!,
- options.SettingName!,
- options.SettingUpdateType!,
+ options.ResourceGroup,
+ options.App,
+ options.SettingName,
+ options.SettingUpdateType,
options.SettingValue,
options.Tenant,
options.RetryPolicy,
@@ -122,8 +98,8 @@ public override async Task ExecuteAsync(CommandContext context,
}
catch (Exception ex)
{
- _logger.LogError(ex, "Failed to '{SettingUpdateType}' application setting '{SettingName}' for Web App details for '{AppName}' in subscription {Subscription} and resource group {ResourceGroup}",
- options.SettingUpdateType, options.SettingName, options.AppName, options.Subscription, options.ResourceGroup);
+ _logger.LogError(ex, "Failed to '{SettingUpdateType}' application setting '{SettingName}' for Web App details for '{App}' in subscription {Subscription} and resource group {ResourceGroup}",
+ options.SettingUpdateType, options.SettingName, options.App, options.Subscription, options.ResourceGroup);
HandleException(context, ex);
}
diff --git a/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/WebappChangeStateCommand.cs b/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/WebappChangeStateCommand.cs
index ff50167270..11c03d216e 100644
--- a/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/WebappChangeStateCommand.cs
+++ b/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/WebappChangeStateCommand.cs
@@ -1,12 +1,12 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-using Azure.Mcp.Tools.AppService.Options;
+using Azure.Mcp.Core.Commands.Subscription;
+using Azure.Mcp.Core.Services.Azure.Subscription;
using Azure.Mcp.Tools.AppService.Options.Webapp;
using Azure.Mcp.Tools.AppService.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.AppService.Commands.Webapp;
@@ -34,51 +34,45 @@ Returns a message indicating the result of the operation.
Secret = false,
LocalRequired = false
)]
-public sealed class WebappChangeStateCommand(ILogger logger, IAppServiceService appServiceService)
- : BaseAppServiceCommand(resourceGroupRequired: true, appRequired: true)
+public sealed class WebappChangeStateCommand(ILogger logger, IAppServiceService appServiceService, ISubscriptionResolver subscriptionResolver)
+ : SubscriptionCommand(subscriptionResolver)
{
private readonly ILogger _logger = logger;
- private static readonly HashSet ValidStateChanges = new(StringComparer.OrdinalIgnoreCase)
+ private static readonly HashSet s_validStateChanges = new(StringComparer.OrdinalIgnoreCase)
{
"start",
"stop",
"restart"
};
- protected override void RegisterOptions(Command command)
+ public override void ValidateOptions(WebappChangeStateOptions options, ValidationResult validationResult)
{
- base.RegisterOptions(command);
- command.Options.Add(AppServiceOptionDefinitions.StateChange);
- command.Options.Add(AppServiceOptionDefinitions.SoftRestart);
- command.Options.Add(AppServiceOptionDefinitions.WaitForCompletion);
- command.Validators.Add(result =>
+ base.ValidateOptions(options, validationResult);
+
+ if (!ValidateStateChange(options.StateChange, out var errorMessage))
{
- var stateChange = result.GetValueOrDefault(AppServiceOptionDefinitions.StateChange.Name);
- if (!ValidateStateChange(stateChange, out var errorMessage))
- {
- result.AddError(errorMessage);
- }
- else
+ validationResult.Errors.Add(errorMessage);
+ }
+ else
+ {
+ if (!"restart".Equals(options.StateChange, StringComparison.OrdinalIgnoreCase))
{
- if (!"restart".Equals(stateChange, StringComparison.OrdinalIgnoreCase))
+ if (options.SoftRestart)
+ {
+ validationResult.Errors.Add("soft-restart only applies for change-state 'restart'.");
+ }
+ if (options.WaitForCompletion)
{
- if (result.HasOptionResult(AppServiceOptionDefinitions.SoftRestart))
- {
- result.AddError("soft-restart only applies for change-state 'restart'.");
- }
- if (result.HasOptionResult(AppServiceOptionDefinitions.WaitForCompletion))
- {
- result.AddError("wait-for-completion only applies for change-state 'restart'.");
- }
+ validationResult.Errors.Add("wait-for-completion only applies for change-state 'restart'.");
}
}
- });
+ }
}
internal static bool ValidateStateChange(string? stateChange, out string errorMessage)
{
- if (string.IsNullOrEmpty(stateChange) || !ValidStateChanges.Contains(stateChange))
+ if (string.IsNullOrEmpty(stateChange) || !s_validStateChanges.Contains(stateChange))
{
errorMessage = $"Invalid value '{stateChange}' for state change. Valid values are: start, stop, restart.";
return false;
@@ -88,34 +82,17 @@ internal static bool ValidateStateChange(string? stateChange, out string errorMe
return true;
}
- protected override WebappChangeStateOptions BindOptions(ParseResult parseResult)
- {
- var options = base.BindOptions(parseResult);
- options.StateChange = parseResult.GetValueOrDefault(AppServiceOptionDefinitions.StateChange.Name);
- options.SoftRestart = parseResult.GetValueOrDefault(AppServiceOptionDefinitions.SoftRestart.Name);
- options.WaitForCompletion = parseResult.GetValueOrDefault(AppServiceOptionDefinitions.WaitForCompletion.Name);
- return options;
- }
-
- public override async Task ExecuteAsync(CommandContext context, ParseResult parseResult, CancellationToken cancellationToken)
+ public override async Task ExecuteAsync(CommandContext context, WebappChangeStateOptions options, CancellationToken cancellationToken)
{
- // Validate first, then bind
- if (!Validate(parseResult.CommandResult, context.Response).IsValid)
- {
- return context.Response;
- }
-
- var options = BindOptions(parseResult);
-
try
{
context.Activity?.AddTag("subscription", options.Subscription);
var stateChange = await appServiceService.ChangeWebAppStateAsync(
options.Subscription!,
- options.ResourceGroup!,
- options.AppName!,
- options.StateChange!,
+ options.ResourceGroup,
+ options.App,
+ options.StateChange,
options.SoftRestart,
options.WaitForCompletion,
options.Tenant,
@@ -128,13 +105,13 @@ public override async Task ExecuteAsync(CommandContext context,
{
if ("restart".Equals(options.StateChange, StringComparison.OrdinalIgnoreCase))
{
- _logger.LogError(ex, "Failed to restart the Web App '{AppName}' in subscription {Subscription} and resource group {ResourceGroup} (Soft Restart: {SoftRestart}, Wait For Completion: {WaitForCompletion})",
- options.AppName, options.Subscription, options.ResourceGroup, options.SoftRestart, options.WaitForCompletion);
+ _logger.LogError(ex, "Failed to restart the Web App '{App}' in subscription {Subscription} and resource group {ResourceGroup} (Soft Restart: {SoftRestart}, Wait For Completion: {WaitForCompletion})",
+ options.App, options.Subscription, options.ResourceGroup, options.SoftRestart, options.WaitForCompletion);
}
else
{
- _logger.LogError(ex, "Failed to {StateChange} the Web App '{AppName}' in subscription {Subscription} and resource group {ResourceGroup}",
- options.StateChange, options.AppName, options.Subscription, options.ResourceGroup);
+ _logger.LogError(ex, "Failed to {StateChange} the Web App '{App}' in subscription {Subscription} and resource group {ResourceGroup}",
+ options.StateChange, options.App, options.Subscription, options.ResourceGroup);
}
HandleException(context, ex);
}
@@ -142,5 +119,5 @@ public override async Task ExecuteAsync(CommandContext context,
return context.Response;
}
- public record WebappChangeStateResult(string StateChangeStatus);
+ public sealed record WebappChangeStateResult(string StateChangeStatus);
}
diff --git a/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/WebappGetCommand.cs b/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/WebappGetCommand.cs
index c2a5e90dee..c8198f2646 100644
--- a/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/WebappGetCommand.cs
+++ b/tools/Azure.Mcp.Tools.AppService/src/Commands/Webapp/WebappGetCommand.cs
@@ -1,12 +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.AppService.Models;
using Azure.Mcp.Tools.AppService.Options;
+using Azure.Mcp.Tools.AppService.Options.Webapp;
using Azure.Mcp.Tools.AppService.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;
@@ -28,38 +30,24 @@ namespace Azure.Mcp.Tools.AppService.Commands.Webapp;
ReadOnly = true,
Secret = false,
LocalRequired = false)]
-public sealed class WebappGetCommand(ILogger logger, IAppServiceService appServiceService)
- : BaseAppServiceCommand(resourceGroupRequired: false)
+public sealed class WebappGetCommand(ILogger logger, IAppServiceService appServiceService, ISubscriptionResolver subscriptionResolver)
+ : SubscriptionCommand(subscriptionResolver)
{
private readonly ILogger _logger = logger;
private readonly IAppServiceService _appServiceService = appServiceService;
- protected override void RegisterOptions(Command command)
+ public override void ValidateOptions(WebappGetOptions options, ValidationResult validationResult)
{
- base.RegisterOptions(command);
- command.Validators.Add(commandResult =>
- {
- var appName = commandResult.GetValueOrDefault(AppServiceOptionDefinitions.AppServiceName.Name);
- var resourceGroup = commandResult.GetValueOrDefault(OptionDefinitions.Common.ResourceGroup.Name);
- if (!string.IsNullOrWhiteSpace(appName) && string.IsNullOrWhiteSpace(resourceGroup))
- {
- commandResult.AddError($"When specifying '{AppServiceOptionDefinitions.AppServiceName.Name}', you must also specify '{OptionDefinitions.Common.ResourceGroup.Name}'.");
- }
- });
- }
-
- protected override BaseAppServiceOptions BindOptions(ParseResult parseResult) => base.BindOptions(parseResult);
+ base.ValidateOptions(options, validationResult);
- public override async Task ExecuteAsync(CommandContext context, ParseResult parseResult, CancellationToken cancellationToken)
- {
- // Validate first, then bind
- if (!Validate(parseResult.CommandResult, context.Response).IsValid)
+ if (!string.IsNullOrWhiteSpace(options.App) && string.IsNullOrWhiteSpace(options.ResourceGroup))
{
- return context.Response;
+ validationResult.Errors.Add($"When specifying '{AppServiceOptionDefinitions.AppName}', you must also specify '{OptionDefinitions.Common.ResourceGroupName}'.");
}
+ }
- var options = BindOptions(parseResult);
-
+ public override async Task ExecuteAsync(CommandContext context, WebappGetOptions options, CancellationToken cancellationToken)
+ {
try
{
context.Activity?.AddTag("subscription", options.Subscription);
@@ -67,7 +55,7 @@ public override async Task ExecuteAsync(CommandContext context,
var webapps = await _appServiceService.GetWebAppsAsync(
options.Subscription!,
options.ResourceGroup,
- options.AppName,
+ options.App,
options.Tenant,
options.RetryPolicy,
cancellationToken);
@@ -76,7 +64,7 @@ public override async Task ExecuteAsync(CommandContext context,
}
catch (Exception ex)
{
- if (options.AppName == null)
+ if (options.App == null)
{
if (options.ResourceGroup == null)
{
@@ -90,8 +78,8 @@ public override async Task ExecuteAsync(CommandContext context,
}
else
{
- _logger.LogError(ex, "Failed to get Web App details for '{AppName}' in subscription {Subscription} and resource group {ResourceGroup}",
- options.AppName, options.Subscription, options.ResourceGroup);
+ _logger.LogError(ex, "Failed to get Web App details for '{App}' in subscription {Subscription} and resource group {ResourceGroup}",
+ options.App, options.Subscription, options.ResourceGroup);
}
HandleException(context, ex);
}
@@ -99,5 +87,5 @@ public override async Task ExecuteAsync(CommandContext context,
return context.Response;
}
- public record WebappGetResult(List Webapps);
+ public sealed record WebappGetResult(List Webapps);
}
diff --git a/tools/Azure.Mcp.Tools.AppService/src/GlobalUsings.cs b/tools/Azure.Mcp.Tools.AppService/src/GlobalUsings.cs
deleted file mode 100644
index b41cc886b4..0000000000
--- a/tools/Azure.Mcp.Tools.AppService/src/GlobalUsings.cs
+++ /dev/null
@@ -1,4 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-global using System.CommandLine;
diff --git a/tools/Azure.Mcp.Tools.AppService/src/Options/AppServiceOptionDefinitions.cs b/tools/Azure.Mcp.Tools.AppService/src/Options/AppServiceOptionDefinitions.cs
index bc1d1da009..b80bed658a 100644
--- a/tools/Azure.Mcp.Tools.AppService/src/Options/AppServiceOptionDefinitions.cs
+++ b/tools/Azure.Mcp.Tools.AppService/src/Options/AppServiceOptionDefinitions.cs
@@ -5,118 +5,8 @@ namespace Azure.Mcp.Tools.AppService.Options;
public static class AppServiceOptionDefinitions
{
+ internal const string App = "The name of the Azure App Service (e.g., my-webapp).";
public const string AppName = "app";
- public const string DatabaseType = "database-type";
- public const string DatabaseServer = "database-server";
- public const string DatabaseName = "database";
- public const string ConnectionString = "connection-string";
- public const string AppSettingNameName = "setting-name";
public const string AppSettingValueName = "setting-value";
public const string AppSettingUpdateTypeName = "setting-update-type";
- public const string DeploymentIdName = "deployment-id";
- public const string DetectorIdName = "detector-id";
- public const string StartTimeName = "start-time";
- public const string EndTimeName = "end-time";
- public const string IntervalName = "interval";
- public const string StateChangeName = "state-change";
- public const string SoftRestartName = "soft-restart";
- public const string WaitForCompletionName = "wait-for-completion";
-
- public static readonly Option AppServiceName = new($"--{AppName}")
- {
- Description = "The name of the Azure App Service (e.g., my-webapp).",
- Required = true
- };
-
- public static readonly Option DatabaseTypeOption = new($"--{DatabaseType}")
- {
- Description = "The type of database (e.g., SqlServer, MySQL, PostgreSQL, CosmosDB).",
- Required = true
- };
-
- public static readonly Option DatabaseServerOption = new($"--{DatabaseServer}")
- {
- Description = "The server name or endpoint for the database (e.g., myserver.database.windows.net).",
- Required = true
- };
-
- public static readonly Option DatabaseNameOption = new($"--{DatabaseName}")
- {
- Description = "The name of the database to connect to (e.g., mydb).",
- Required = true
- };
-
- public static readonly Option ConnectionStringOption = new($"--{ConnectionString}")
- {
- Description = "The connection string for the database. If not provided, a default will be generated.",
- Required = false
- };
-
- public static readonly Option AppSettingName = new($"--{AppSettingNameName}")
- {
- Description = "The name of the application setting.",
- Required = true
- };
-
- public static readonly Option AppSettingValue = new($"--{AppSettingValueName}")
- {
- Description = "The value of the application setting. Required for add and set update types.",
- Required = false
- };
-
- public static readonly Option AppSettingUpdateType = new($"--{AppSettingUpdateTypeName}")
- {
- Description = "The type of update to perform on the application setting. Valid values are: add, set, delete.",
- Required = true
- };
-
- public static readonly Option DeploymentIdOption = new($"--{DeploymentIdName}")
- {
- Description = "The ID of the deployment.",
- Required = false
- };
-
- public static readonly Option DetectorId = new($"--{DetectorIdName}")
- {
- Description = "The ID of the diagnostic detector to run. Use the 'id' field from 'azmcp appservice webapp diagnostic list' output (e.g., LinuxContainerRecycle, LinuxMemoryDrillDown).",
- Required = true
- };
-
- public static readonly Option StartTime = new($"--{StartTimeName}")
- {
- Description = "The start time in ISO format (e.g., 2023-01-01T00:00:00Z).",
- Required = false
- };
-
- public static readonly Option EndTime = new($"--{EndTimeName}")
- {
- Description = "The end time in ISO format (e.g., 2023-01-01T00:00:00Z).",
- Required = false
- };
-
- public static readonly Option Interval = new($"--{IntervalName}")
- {
- Description = "The time interval (e.g., PT1H for 1 hour, PT5M for 5 minutes).",
- Required = false
- };
-
- public static readonly Option StateChange = new($"--{StateChangeName}")
- {
- Description = "The state change action to perform. Valid values are: start, stop, restart.",
- Required = true
- };
-
- public static readonly Option SoftRestart = new($"--{SoftRestartName}")
- {
- Description = "When state-change is restart, indicates whether to perform a soft restart.",
- DefaultValueFactory = _ => false,
- Required = false
- };
-
- public static readonly Option WaitForCompletion = new($"--{WaitForCompletionName}")
- {
- Description = "When state-change is restart, indicates whether to synchronously wait for the state change operation to complete before returning.",
- DefaultValueFactory = _ => false,
- Required = false
- };
}
diff --git a/tools/Azure.Mcp.Tools.AppService/src/Options/BaseAppServiceOptions.cs b/tools/Azure.Mcp.Tools.AppService/src/Options/BaseAppServiceOptions.cs
index 1d1e586e3c..a050f7c991 100644
--- a/tools/Azure.Mcp.Tools.AppService/src/Options/BaseAppServiceOptions.cs
+++ b/tools/Azure.Mcp.Tools.AppService/src/Options/BaseAppServiceOptions.cs
@@ -1,13 +1,25 @@
// 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.AppService.Options;
-public class BaseAppServiceOptions : SubscriptionOptions
+public sealed class BaseAppServiceOptions : ISubscriptionOption
{
- [JsonPropertyName(AppServiceOptionDefinitions.AppName)]
- public string? AppName { get; set; }
+ [Option(Description = AppServiceOptionDefinitions.App)]
+ public required string App { get; set; }
+
+ [Option(Description = OptionDescriptions.Tenant)]
+ public string? Tenant { get; set; }
+
+ [Option(Description = OptionDescriptions.Subscription)]
+ public string? Subscription { get; set; }
+
+ [Option(Description = OptionDescriptions.ResourceGroup)]
+ public required string ResourceGroup { get; set; }
+
+ [OptionContainer(Prefix = "retry")]
+ public RetryPolicyOptions? RetryPolicy { get; set; }
}
diff --git a/tools/Azure.Mcp.Tools.AppService/src/Options/Database/DatabaseAddOptions.cs b/tools/Azure.Mcp.Tools.AppService/src/Options/Database/DatabaseAddOptions.cs
index 62e9e5300c..5c221b185a 100644
--- a/tools/Azure.Mcp.Tools.AppService/src/Options/Database/DatabaseAddOptions.cs
+++ b/tools/Azure.Mcp.Tools.AppService/src/Options/Database/DatabaseAddOptions.cs
@@ -1,21 +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.AppService.Options.Database;
-public class DatabaseAddOptions : BaseAppServiceOptions
+public sealed class DatabaseAddOptions : ISubscriptionOption
{
- [JsonPropertyName(AppServiceOptionDefinitions.DatabaseType)]
- public string? DatabaseType { get; set; }
+ [Option(Description = AppServiceOptionDefinitions.App)]
+ public required string App { get; set; }
- [JsonPropertyName(AppServiceOptionDefinitions.DatabaseServer)]
- public string? DatabaseServer { get; set; }
+ [Option(Description = "The type of database (e.g., SqlServer, MySQL, PostgreSQL, CosmosDB).")]
+ public required string DatabaseType { get; set; }
- [JsonPropertyName(AppServiceOptionDefinitions.DatabaseName)]
- public string? DatabaseName { get; set; }
+ [Option(Description = "The server name or endpoint for the database (e.g., myserver.database.windows.net).")]
+ public required string DatabaseServer { get; set; }
- [JsonPropertyName(AppServiceOptionDefinitions.ConnectionString)]
+ [Option(Description = "The name of the database to connect to (e.g., mydb).")]
+ public required string Database { get; set; }
+
+ [Option(Description = "The connection string for the database. If not provided, a default will be generated.")]
public string? ConnectionString { get; set; }
+
+ [Option(Description = OptionDescriptions.Tenant)]
+ public string? Tenant { get; set; }
+
+ [Option(Description = OptionDescriptions.Subscription)]
+ public string? Subscription { get; set; }
+
+ [Option(Description = OptionDescriptions.ResourceGroup)]
+ public required string ResourceGroup { get; set; }
+
+ [OptionContainer(Prefix = "retry")]
+ public RetryPolicyOptions? RetryPolicy { get; set; }
}
diff --git a/tools/Azure.Mcp.Tools.AppService/src/Options/Webapp/Deployment/DeploymentGetOptions.cs b/tools/Azure.Mcp.Tools.AppService/src/Options/Webapp/Deployment/DeploymentGetOptions.cs
index 40c9bbf1b4..9867f06297 100644
--- a/tools/Azure.Mcp.Tools.AppService/src/Options/Webapp/Deployment/DeploymentGetOptions.cs
+++ b/tools/Azure.Mcp.Tools.AppService/src/Options/Webapp/Deployment/DeploymentGetOptions.cs
@@ -1,12 +1,28 @@
// 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.AppService.Options.Webapp.Deployment;
-public class DeploymentGetOptions : BaseAppServiceOptions
+public sealed class DeploymentGetOptions : ISubscriptionOption
{
- [JsonPropertyName(AppServiceOptionDefinitions.DeploymentIdName)]
+ [Option(Description = AppServiceOptionDefinitions.App)]
+ public required string App { get; set; }
+
+ [Option(Description = "The ID of the deployment.")]
public string? DeploymentId { get; set; }
+
+ [Option(Description = OptionDescriptions.Tenant)]
+ public string? Tenant { get; set; }
+
+ [Option(Description = OptionDescriptions.Subscription)]
+ public string? Subscription { get; set; }
+
+ [Option(Description = OptionDescriptions.ResourceGroup)]
+ public required string ResourceGroup { get; set; }
+
+ [OptionContainer(Prefix = "retry")]
+ public RetryPolicyOptions? RetryPolicy { get; set; }
}
diff --git a/tools/Azure.Mcp.Tools.AppService/src/Options/Webapp/Diagnostic/DetectorDiagnoseOptions.cs b/tools/Azure.Mcp.Tools.AppService/src/Options/Webapp/Diagnostic/DetectorDiagnoseOptions.cs
index 096633e21c..f963cebfed 100644
--- a/tools/Azure.Mcp.Tools.AppService/src/Options/Webapp/Diagnostic/DetectorDiagnoseOptions.cs
+++ b/tools/Azure.Mcp.Tools.AppService/src/Options/Webapp/Diagnostic/DetectorDiagnoseOptions.cs
@@ -1,21 +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.AppService.Options.Webapp.Diagnostic;
-public sealed class DetectorDiagnoseOptions : BaseAppServiceOptions
+public sealed class DetectorDiagnoseOptions : ISubscriptionOption
{
- [JsonPropertyName(AppServiceOptionDefinitions.DetectorIdName)]
- public string? DetectorId { get; set; }
+ [Option(Description = AppServiceOptionDefinitions.App)]
+ public required string App { get; set; }
- [JsonPropertyName(AppServiceOptionDefinitions.StartTimeName)]
+ [Option(Description = "The ID of the diagnostic detector to run. Use the 'id' field from 'azmcp appservice webapp diagnostic list' output (e.g., LinuxContainerRecycle, LinuxMemoryDrillDown).")]
+ public required string DetectorId { get; set; }
+
+ [Option(Description = "The start time in ISO format (e.g., 2023-01-01T00:00:00Z).")]
public DateTimeOffset? StartTime { get; set; }
- [JsonPropertyName(AppServiceOptionDefinitions.EndTimeName)]
+ [Option(Description = "The end time in ISO format (e.g., 2023-01-01T00:00:00Z).")]
public DateTimeOffset? EndTime { get; set; }
- [JsonPropertyName(AppServiceOptionDefinitions.IntervalName)]
+ [Option(Description = "The time interval (e.g., PT1H for 1 hour, PT5M for 5 minutes).")]
public string? Interval { get; set; }
+
+ [Option(Description = OptionDescriptions.Tenant)]
+ public string? Tenant { get; set; }
+
+ [Option(Description = OptionDescriptions.Subscription)]
+ public string? Subscription { get; set; }
+
+ [Option(Description = OptionDescriptions.ResourceGroup)]
+ public required string ResourceGroup { get; set; }
+
+ [OptionContainer(Prefix = "retry")]
+ public RetryPolicyOptions? RetryPolicy { get; set; }
}
diff --git a/tools/Azure.Mcp.Tools.AppService/src/Options/Webapp/Settings/AppSettingsUpdateOptions.cs b/tools/Azure.Mcp.Tools.AppService/src/Options/Webapp/Settings/AppSettingsUpdateOptions.cs
index 6b9ad03637..49fc7a0a62 100644
--- a/tools/Azure.Mcp.Tools.AppService/src/Options/Webapp/Settings/AppSettingsUpdateOptions.cs
+++ b/tools/Azure.Mcp.Tools.AppService/src/Options/Webapp/Settings/AppSettingsUpdateOptions.cs
@@ -1,18 +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.AppService.Options.Webapp.Settings;
-public sealed class AppSettingsUpdateOptions : BaseAppServiceOptions
+public sealed class AppSettingsUpdateOptions : ISubscriptionOption
{
- [JsonPropertyName(AppServiceOptionDefinitions.AppSettingNameName)]
- public string? SettingName { get; set; }
+ [Option(Description = AppServiceOptionDefinitions.App)]
+ public required string App { get; set; }
- [JsonPropertyName(AppServiceOptionDefinitions.AppSettingValueName)]
+ [Option(Description = "The name of the application setting.")]
+ public required string SettingName { get; set; }
+
+ [Option(Description = "The value of the application setting. Required for add and set update types.")]
public string? SettingValue { get; set; }
- [JsonPropertyName(AppServiceOptionDefinitions.AppSettingUpdateTypeName)]
- public string? SettingUpdateType { get; set; }
+ [Option(Description = "The type of update to perform on the application setting. Valid values are: add, set, delete.")]
+ public required string SettingUpdateType { get; set; }
+
+ [Option(Description = OptionDescriptions.Tenant)]
+ public string? Tenant { get; set; }
+
+ [Option(Description = OptionDescriptions.Subscription)]
+ public string? Subscription { get; set; }
+
+ [Option(Description = OptionDescriptions.ResourceGroup)]
+ public required string ResourceGroup { get; set; }
+
+ [OptionContainer(Prefix = "retry")]
+ public RetryPolicyOptions? RetryPolicy { get; set; }
}
diff --git a/tools/Azure.Mcp.Tools.AppService/src/Options/Webapp/WebappChangeStateOptions.cs b/tools/Azure.Mcp.Tools.AppService/src/Options/Webapp/WebappChangeStateOptions.cs
index d5da318f8f..2a6e98aacd 100644
--- a/tools/Azure.Mcp.Tools.AppService/src/Options/Webapp/WebappChangeStateOptions.cs
+++ b/tools/Azure.Mcp.Tools.AppService/src/Options/Webapp/WebappChangeStateOptions.cs
@@ -1,18 +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.AppService.Options.Webapp;
-public class WebappChangeStateOptions : BaseAppServiceOptions
+public sealed class WebappChangeStateOptions : ISubscriptionOption
{
- [JsonPropertyName(AppServiceOptionDefinitions.StateChangeName)]
- public string? StateChange { get; set; }
+ [Option(Description = AppServiceOptionDefinitions.App)]
+ public required string App { get; set; }
- [JsonPropertyName(AppServiceOptionDefinitions.SoftRestartName)]
+ [Option(Description = "The state change action to perform. Valid values are: start, stop, restart.")]
+ public required string StateChange { get; set; }
+
+ [Option(Description = "When state-change is restart, indicates whether to perform a soft restart.")]
public bool SoftRestart { get; set; } = false;
- [JsonPropertyName(AppServiceOptionDefinitions.WaitForCompletionName)]
+ [Option(Description = "When state-change is restart, indicates whether to synchronously wait for the state change operation to complete before returning.")]
public bool WaitForCompletion { get; set; } = false;
+
+ [Option(Description = OptionDescriptions.Tenant)]
+ public string? Tenant { get; set; }
+
+ [Option(Description = OptionDescriptions.Subscription)]
+ public string? Subscription { get; set; }
+
+ [Option(Description = OptionDescriptions.ResourceGroup)]
+ public required string ResourceGroup { get; set; }
+
+ [OptionContainer(Prefix = "retry")]
+ public RetryPolicyOptions? RetryPolicy { get; set; }
}
diff --git a/tools/Azure.Mcp.Tools.AppService/src/Options/Webapp/WebappGetOptions.cs b/tools/Azure.Mcp.Tools.AppService/src/Options/Webapp/WebappGetOptions.cs
new file mode 100644
index 0000000000..8737bba3eb
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.AppService/src/Options/Webapp/WebappGetOptions.cs
@@ -0,0 +1,25 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Azure.Mcp.Core.Options;
+using Microsoft.Mcp.Core.Options;
+
+namespace Azure.Mcp.Tools.AppService.Options.Webapp;
+
+public sealed class WebappGetOptions : ISubscriptionOption
+{
+ [Option(Description = AppServiceOptionDefinitions.App)]
+ public string? App { get; set; }
+
+ [Option(Description = OptionDescriptions.Tenant)]
+ public string? Tenant { get; set; }
+
+ [Option(Description = OptionDescriptions.Subscription)]
+ public string? Subscription { get; set; }
+
+ [Option(Description = OptionDescriptions.ResourceGroup)]
+ public string? ResourceGroup { get; set; }
+
+ [OptionContainer(Prefix = "retry")]
+ public RetryPolicyOptions? RetryPolicy { get; set; }
+}
diff --git a/tools/Azure.Mcp.Tools.AppService/src/Services/AppServiceService.cs b/tools/Azure.Mcp.Tools.AppService/src/Services/AppServiceService.cs
index 037e5477e1..86cec21954 100644
--- a/tools/Azure.Mcp.Tools.AppService/src/Services/AppServiceService.cs
+++ b/tools/Azure.Mcp.Tools.AppService/src/Services/AppServiceService.cs
@@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-using System.Net.Http.Headers;
using System.Text.Json;
using Azure.Core;
using Azure.Mcp.Core.Services.Azure;
diff --git a/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/AppServiceCommandTests.cs b/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/AppServiceCommandTests.cs
index e5f62b94b0..0e0871e895 100644
--- a/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/AppServiceCommandTests.cs
+++ b/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/AppServiceCommandTests.cs
@@ -125,7 +125,6 @@ public async Task ExecuteAsync_WithDifferentDatabaseTypes_AcceptsValidTypes(stri
[Theory]
[InlineData("InvalidType")]
- [InlineData("")]
[InlineData("random")]
public async Task ExecuteAsync_WithInvalidDatabaseTypes_ReturnsValidationError(string invalidDatabaseType)
{
diff --git a/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Database/DatabaseAddCommandTests.cs b/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Database/DatabaseAddCommandTests.cs
index d22f279b87..1eff13c07d 100644
--- a/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Database/DatabaseAddCommandTests.cs
+++ b/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Database/DatabaseAddCommandTests.cs
@@ -2,11 +2,11 @@
// Licensed under the MIT License.
using System.Net;
+using Azure.Mcp.Tests.Commands;
using Azure.Mcp.Tools.AppService.Commands.Database;
using Azure.Mcp.Tools.AppService.Models;
using Azure.Mcp.Tools.AppService.Services;
using Microsoft.Mcp.Core.Options;
-using Microsoft.Mcp.Tests.Client;
using NSubstitute;
using NSubstitute.ExceptionExtensions;
using Xunit;
@@ -14,7 +14,7 @@
namespace Azure.Mcp.Tools.AppService.Tests.Commands.Database;
[Trait("Command", "DatabaseAdd")]
-public class DatabaseAddCommandTests : CommandUnitTestsBase
+public class DatabaseAddCommandTests : SubscriptionCommandUnitTestsBase
{
[Theory]
[InlineData("SqlServer", "test-server.database.windows.net", "test-db", null, null)]
diff --git a/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/Deployment/DeploymentGetCommandTests.cs b/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/Deployment/DeploymentGetCommandTests.cs
index 2d67e95d23..db696270db 100644
--- a/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/Deployment/DeploymentGetCommandTests.cs
+++ b/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/Deployment/DeploymentGetCommandTests.cs
@@ -3,12 +3,12 @@
using System.Net;
using System.Text.Json;
+using Azure.Mcp.Tests.Commands;
using Azure.Mcp.Tools.AppService.Commands;
using Azure.Mcp.Tools.AppService.Commands.Webapp.Deployment;
using Azure.Mcp.Tools.AppService.Models;
using Azure.Mcp.Tools.AppService.Services;
using Microsoft.Mcp.Core.Options;
-using Microsoft.Mcp.Tests.Client;
using NSubstitute;
using NSubstitute.ExceptionExtensions;
using Xunit;
@@ -16,7 +16,7 @@
namespace Azure.Mcp.Tools.AppService.Tests.Commands.Webapp.Deployment;
[Trait("Command", "DeploymentGet")]
-public class DeploymentGetCommandTests : CommandUnitTestsBase
+public class DeploymentGetCommandTests : SubscriptionCommandUnitTestsBase
{
[Theory]
[InlineData(null)]
diff --git a/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/Diagnostic/DetectorDiagnoseCommandTests.cs b/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/Diagnostic/DetectorDiagnoseCommandTests.cs
index 73d1e3b19b..f07835cd7a 100644
--- a/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/Diagnostic/DetectorDiagnoseCommandTests.cs
+++ b/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/Diagnostic/DetectorDiagnoseCommandTests.cs
@@ -2,13 +2,13 @@
// Licensed under the MIT License.
using System.Net;
+using Azure.Mcp.Tests.Commands;
using Azure.Mcp.Tools.AppService.Commands;
using Azure.Mcp.Tools.AppService.Commands.Webapp.Diagnostic;
using Azure.Mcp.Tools.AppService.Models;
using Azure.Mcp.Tools.AppService.Services;
using Azure.ResourceManager.AppService.Models;
using Microsoft.Mcp.Core.Options;
-using Microsoft.Mcp.Tests.Client;
using NSubstitute;
using NSubstitute.ExceptionExtensions;
using Xunit;
@@ -16,7 +16,7 @@
namespace Azure.Mcp.Tools.AppService.Tests.Commands.Webapp.Diagnostic;
[Trait("Command", "DetectorDiagnose")]
-public class DetectorDiagnoseCommandTests : CommandUnitTestsBase
+public class DetectorDiagnoseCommandTests : SubscriptionCommandUnitTestsBase
{
[Theory]
[InlineData(null, null, null)]
diff --git a/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/Diagnostic/DetectorListCommandTests.cs b/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/Diagnostic/DetectorListCommandTests.cs
index 16e096bb09..bad57a0350 100644
--- a/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/Diagnostic/DetectorListCommandTests.cs
+++ b/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/Diagnostic/DetectorListCommandTests.cs
@@ -2,12 +2,12 @@
// Licensed under the MIT License.
using System.Net;
+using Azure.Mcp.Tests.Commands;
using Azure.Mcp.Tools.AppService.Commands;
using Azure.Mcp.Tools.AppService.Commands.Webapp.Diagnostic;
using Azure.Mcp.Tools.AppService.Models;
using Azure.Mcp.Tools.AppService.Services;
using Microsoft.Mcp.Core.Options;
-using Microsoft.Mcp.Tests.Client;
using NSubstitute;
using NSubstitute.ExceptionExtensions;
using Xunit;
@@ -15,7 +15,7 @@
namespace Azure.Mcp.Tools.AppService.Tests.Commands.Webapp.Diagnostic;
[Trait("Command", "DetectorList")]
-public class DetectorListCommandTests : CommandUnitTestsBase
+public class DetectorListCommandTests : SubscriptionCommandUnitTestsBase
{
[Fact]
public async Task ExecuteAsync_WithValidParameters_CallsServiceWithCorrectArguments()
diff --git a/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/Settings/AppSettingsGetCommandTests.cs b/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/Settings/AppSettingsGetCommandTests.cs
index e7bc0b206b..38d0448621 100644
--- a/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/Settings/AppSettingsGetCommandTests.cs
+++ b/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/Settings/AppSettingsGetCommandTests.cs
@@ -3,11 +3,11 @@
using System.Net;
using System.Text.Json;
+using Azure.Mcp.Tests.Commands;
using Azure.Mcp.Tools.AppService.Commands;
using Azure.Mcp.Tools.AppService.Commands.Webapp.Settings;
using Azure.Mcp.Tools.AppService.Services;
using Microsoft.Mcp.Core.Options;
-using Microsoft.Mcp.Tests.Client;
using NSubstitute;
using NSubstitute.ExceptionExtensions;
using Xunit;
@@ -15,7 +15,7 @@
namespace Azure.Mcp.Tools.AppService.Tests.Commands.Webapp.Settings;
[Trait("Command", "AppSettingsGet")]
-public class AppSettingsGetCommandTests : CommandUnitTestsBase
+public class AppSettingsGetCommandTests : SubscriptionCommandUnitTestsBase
{
[Fact]
public async Task ExecuteAsync_WithValidParameters_CallsServiceWithCorrectArguments()
diff --git a/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/Settings/AppSettingsUpdateCommandTests.cs b/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/Settings/AppSettingsUpdateCommandTests.cs
index bd240d2b1e..e777f5915a 100644
--- a/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/Settings/AppSettingsUpdateCommandTests.cs
+++ b/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/Settings/AppSettingsUpdateCommandTests.cs
@@ -2,11 +2,11 @@
// Licensed under the MIT License.
using System.Net;
+using Azure.Mcp.Tests.Commands;
using Azure.Mcp.Tools.AppService.Commands;
using Azure.Mcp.Tools.AppService.Commands.Webapp.Settings;
using Azure.Mcp.Tools.AppService.Services;
using Microsoft.Mcp.Core.Options;
-using Microsoft.Mcp.Tests.Client;
using NSubstitute;
using NSubstitute.ExceptionExtensions;
using Xunit;
@@ -14,7 +14,7 @@
namespace Azure.Mcp.Tools.AppService.Tests.Commands.Webapp.Settings;
[Trait("Command", "AppSettingsUpdate")]
-public class AppSettingsUpdateCommandTests : CommandUnitTestsBase
+public class AppSettingsUpdateCommandTests : SubscriptionCommandUnitTestsBase
{
[Theory]
[InlineData("add", "Setting1", "Value1", "Application setting 'Setting1' added successfully.")]
diff --git a/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/WebappChangeStateCommandTests.cs b/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/WebappChangeStateCommandTests.cs
index 5eb16c4722..5f328001bc 100644
--- a/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/WebappChangeStateCommandTests.cs
+++ b/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/WebappChangeStateCommandTests.cs
@@ -2,11 +2,11 @@
// Licensed under the MIT License.
using System.Net;
+using Azure.Mcp.Tests.Commands;
using Azure.Mcp.Tools.AppService.Commands;
using Azure.Mcp.Tools.AppService.Commands.Webapp;
using Azure.Mcp.Tools.AppService.Services;
using Microsoft.Mcp.Core.Options;
-using Microsoft.Mcp.Tests.Client;
using NSubstitute;
using NSubstitute.ExceptionExtensions;
using Xunit;
@@ -14,7 +14,7 @@
namespace Azure.Mcp.Tools.AppService.Tests.Commands.Webapp;
[Trait("Command", "WebappChangeState")]
-public class WebappChangeStateCommandTests : CommandUnitTestsBase
+public class WebappChangeStateCommandTests : SubscriptionCommandUnitTestsBase
{
[Theory]
[InlineData("start", false, false)]
@@ -147,11 +147,11 @@ public async Task ExecuteAsync_ServiceThrowsException_ReturnsErrorResponse(strin
var response = await ExecuteCommandAsync(unparsedArgs.ToArray());
// Assert
- Assert.NotNull(response);
- Assert.Equal(HttpStatusCode.UnprocessableEntity, response.Status);
-
await Service.Received(1).ChangeWebAppStateAsync("sub123", "rg1", "test-app", stateChange,
softRestart, waitForCompletion, Arg.Any(), Arg.Any(),
Arg.Any());
+
+ Assert.NotNull(response);
+ Assert.Equal(HttpStatusCode.UnprocessableEntity, response.Status);
}
}
diff --git a/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/WebappGetCommandTests.cs b/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/WebappGetCommandTests.cs
index 514ef63af3..37ebad84cf 100644
--- a/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/WebappGetCommandTests.cs
+++ b/tools/Azure.Mcp.Tools.AppService/tests/Azure.Mcp.Tools.AppService.Tests/Commands/Webapp/WebappGetCommandTests.cs
@@ -3,12 +3,12 @@
using System.Net;
using System.Text.Json;
+using Azure.Mcp.Tests.Commands;
using Azure.Mcp.Tools.AppService.Commands;
using Azure.Mcp.Tools.AppService.Commands.Webapp;
using Azure.Mcp.Tools.AppService.Models;
using Azure.Mcp.Tools.AppService.Services;
using Microsoft.Mcp.Core.Options;
-using Microsoft.Mcp.Tests.Client;
using NSubstitute;
using NSubstitute.ExceptionExtensions;
using Xunit;
@@ -16,7 +16,7 @@
namespace Azure.Mcp.Tools.AppService.Tests.Commands.Webapp;
[Trait("Command", "WebappGet")]
-public class WebappGetCommandTests : CommandUnitTestsBase
+public class WebappGetCommandTests : SubscriptionCommandUnitTestsBase
{
[Theory]
[InlineData("sub123", null, null)]