diff --git a/Directory.Packages.props b/Directory.Packages.props
index 136351699a..6b08f9f8ce 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -58,6 +58,7 @@
+
diff --git a/Microsoft.Mcp.slnx b/Microsoft.Mcp.slnx
index 63ed2d9daa..68a606aa88 100644
--- a/Microsoft.Mcp.slnx
+++ b/Microsoft.Mcp.slnx
@@ -372,6 +372,13 @@
+
+
+
+
+
+
+
diff --git a/servers/Azure.Mcp.Server/Azure.Mcp.Server.slnx b/servers/Azure.Mcp.Server/Azure.Mcp.Server.slnx
index 25ae7510c2..dafac9bd08 100644
--- a/servers/Azure.Mcp.Server/Azure.Mcp.Server.slnx
+++ b/servers/Azure.Mcp.Server/Azure.Mcp.Server.slnx
@@ -326,6 +326,13 @@
+
+
+
+
+
+
+
diff --git a/servers/Azure.Mcp.Server/changelog-entries/1782548815102.yaml b/servers/Azure.Mcp.Server/changelog-entries/1782548815102.yaml
new file mode 100644
index 0000000000..206fbc3ae1
--- /dev/null
+++ b/servers/Azure.Mcp.Server/changelog-entries/1782548815102.yaml
@@ -0,0 +1,3 @@
+changes:
+ - section: "Features Added"
+ description: "Added the 'resilience' toolset (Azure Resilience Management) with read-only 'get' commands for goals (templates, assignments, resources), usage plans and enrollments, drills (drills, runs, resources), and recovery plans (plans, resources, jobs)."
diff --git a/servers/Azure.Mcp.Server/docs/azmcp-commands.md b/servers/Azure.Mcp.Server/docs/azmcp-commands.md
index 36d68c404a..58f8df0d87 100644
--- a/servers/Azure.Mcp.Server/docs/azmcp-commands.md
+++ b/servers/Azure.Mcp.Server/docs/azmcp-commands.md
@@ -3611,6 +3611,98 @@ azmcp redis create --subscription \
azmcp redis list --subscription
```
+### Azure Resilience Management Operations
+
+```bash
+# Get a resilience goal template, or list all goal templates in a service group (omit --name)
+# ❌ Destructive | ✅ Idempotent | ❌ OpenWorld | ✅ ReadOnly | ❌ Secret | ❌ LocalRequired
+azmcp resilience goal template get --subscription \
+ --service-group \
+ [--name ]
+
+# Get a resilience goal assignment, or list all goal assignments in a service group (omit --name)
+# ❌ Destructive | ✅ Idempotent | ❌ OpenWorld | ✅ ReadOnly | ❌ Secret | ❌ LocalRequired
+azmcp resilience goal assignment get --subscription \
+ --service-group \
+ [--name ]
+
+# Get a resource (member) of a goal assignment, or list all resources of the assignment (omit --name)
+# ❌ Destructive | ✅ Idempotent | ❌ OpenWorld | ✅ ReadOnly | ❌ Secret | ❌ LocalRequired
+azmcp resilience goal resource get --subscription \
+ --service-group \
+ --goal-assignment \
+ [--name ]
+
+# Get a resilience usage plan, or list usage plans (omit --name; omit --resource-group to list across the subscription)
+# ❌ Destructive | ✅ Idempotent | ❌ OpenWorld | ✅ ReadOnly | ❌ Secret | ❌ LocalRequired
+azmcp resilience usageplan get --subscription \
+ [--resource-group ] \
+ [--name ]
+
+# Get a usage plan enrollment, or list all enrollments of a usage plan (omit --name)
+# ❌ Destructive | ✅ Idempotent | ❌ OpenWorld | ✅ ReadOnly | ❌ Secret | ❌ LocalRequired
+azmcp resilience usageplan enrollment get --subscription \
+ --resource-group \
+ --usage-plan \
+ [--name ]
+
+# Get a resilience drill, or list all drills in a service group (omit --name)
+# ❌ Destructive | ✅ Idempotent | ❌ OpenWorld | ✅ ReadOnly | ❌ Secret | ❌ LocalRequired
+azmcp resilience drill get --subscription \
+ --service-group \
+ [--name ]
+
+# Get a resource (target) of a drill, or list all resources of the drill (omit --name)
+# ❌ Destructive | ✅ Idempotent | ❌ OpenWorld | ✅ ReadOnly | ❌ Secret | ❌ LocalRequired
+azmcp resilience drill resource get --subscription \
+ --service-group \
+ --drill \
+ [--name ]
+
+# Get a drill run, or list all runs of a drill (omit --name)
+# ❌ Destructive | ✅ Idempotent | ❌ OpenWorld | ✅ ReadOnly | ❌ Secret | ❌ LocalRequired
+azmcp resilience drill run get --subscription \
+ --service-group \
+ --drill \
+ [--name ]
+
+# Get a resource (target) of a drill run, or list all resources of the drill run (omit --name)
+# ❌ Destructive | ✅ Idempotent | ❌ OpenWorld | ✅ ReadOnly | ❌ Secret | ❌ LocalRequired
+azmcp resilience drill run resource get --subscription \
+ --service-group \
+ --drill \
+ --drill-run \
+ [--name ]
+
+# Get a resilience recovery plan, or list all recovery plans in a service group (omit --name)
+# ❌ Destructive | ✅ Idempotent | ❌ OpenWorld | ✅ ReadOnly | ❌ Secret | ❌ LocalRequired
+azmcp resilience recovery plan get --subscription \
+ --service-group \
+ [--name ]
+
+# Get a resource (member) of a recovery plan, or list all resources of the plan (omit --name)
+# ❌ Destructive | ✅ Idempotent | ❌ OpenWorld | ✅ ReadOnly | ❌ Secret | ❌ LocalRequired
+azmcp resilience recovery plan resource get --subscription \
+ --service-group \
+ --recovery-plan \
+ [--name ]
+
+# Get a recovery job, or list all recovery jobs of a recovery plan (omit --name)
+# ❌ Destructive | ✅ Idempotent | ❌ OpenWorld | ✅ ReadOnly | ❌ Secret | ❌ LocalRequired
+azmcp resilience recovery job get --subscription \
+ --service-group \
+ --recovery-plan \
+ [--name ]
+
+# Get a resource (target) of a recovery job, or list all resources of the job (omit --name)
+# ❌ Destructive | ✅ Idempotent | ❌ OpenWorld | ✅ ReadOnly | ❌ Secret | ❌ LocalRequired
+azmcp resilience recovery job resource get --subscription \
+ --service-group \
+ --recovery-plan \
+ --recovery-job \
+ [--name ]
+```
+
### Azure Resource Group Operations
```bash
diff --git a/servers/Azure.Mcp.Server/docs/e2eTestPrompts.md b/servers/Azure.Mcp.Server/docs/e2eTestPrompts.md
index ca609e5301..dcb61546e2 100644
--- a/servers/Azure.Mcp.Server/docs/e2eTestPrompts.md
+++ b/servers/Azure.Mcp.Server/docs/e2eTestPrompts.md
@@ -854,6 +854,39 @@ This file contains prompts used for end-to-end testing to ensure each tool is in
| redis_list | Show me my Redis caches |
| redis_list | Get Redis clusters |
+## Azure Resilience Management
+
+| Tool Name | Test Prompt |
+|:----------|:----------|
+| resilience_drill_get | List all resilience drills in service group |
+| resilience_drill_get | Show me the resilience drills in service group |
+| resilience_drill_get | Get the details of resilience drill in service group |
+| resilience_drill_resource_get | List all resources (targets) of resilience drill in service group |
+| resilience_drill_resource_get | Get the resilience drill resource for drill in service group |
+| resilience_drill_run_get | List all runs of resilience drill in service group |
+| resilience_drill_run_get | Get the details of drill run for drill in service group |
+| resilience_drill_run_resource_get | List all resources (targets) of drill run for drill in service group |
+| resilience_drill_run_resource_get | Get the drill run resource for drill run of drill in service group |
+| resilience_goal_assignment_get | List all resilience goal assignments in service group |
+| resilience_goal_assignment_get | Get the details of goal assignment in service group |
+| resilience_goal_resource_get | List all resources (members) of goal assignment in service group |
+| resilience_goal_resource_get | Get the goal resource for goal assignment in service group |
+| resilience_goal_template_get | List all resilience goal templates in service group |
+| resilience_goal_template_get | Get the details of goal template in service group |
+| resilience_recovery_job_get | List all recovery jobs of recovery plan in service group |
+| resilience_recovery_job_get | Get the details of recovery job for recovery plan in service group |
+| resilience_recovery_job_resource_get | List all resources (targets) of recovery job for recovery plan in service group |
+| resilience_recovery_job_resource_get | Get the recovery job resource for recovery job of recovery plan in service group |
+| resilience_recovery_plan_get | List all resilience recovery plans in service group |
+| resilience_recovery_plan_get | Get the details of recovery plan in service group |
+| resilience_recovery_plan_resource_get | List all resources (members) of recovery plan in service group |
+| resilience_recovery_plan_resource_get | Get the recovery resource for recovery plan in service group |
+| resilience_usageplan_enrollment_get | List all enrollments of usage plan in resource group |
+| resilience_usageplan_enrollment_get | Get the details of usage plan enrollment for usage plan in resource group |
+| resilience_usageplan_get | List all resilience usage plans in my subscription |
+| resilience_usageplan_get | List all resilience usage plans in resource group |
+| resilience_usageplan_get | Get the details of usage plan in resource group |
+
## Azure Resource Group
| Tool Name | Test Prompt |
diff --git a/servers/Azure.Mcp.Server/src/Program.cs b/servers/Azure.Mcp.Server/src/Program.cs
index c9c1bfead2..7ec75aa81f 100644
--- a/servers/Azure.Mcp.Server/src/Program.cs
+++ b/servers/Azure.Mcp.Server/src/Program.cs
@@ -222,6 +222,7 @@ private static IAreaSetup[] RegisterAreas()
new Azure.Mcp.Tools.Postgres.PostgresSetup(),
new Azure.Mcp.Tools.Pricing.PricingSetup(),
new Azure.Mcp.Tools.Redis.RedisSetup(),
+ new Azure.Mcp.Tools.ResilienceManagement.ResilienceManagementSetup(),
new Azure.Mcp.Tools.ResourceHealth.ResourceHealthSetup(),
new Azure.Mcp.Tools.Search.SearchSetup(),
new Azure.Mcp.Tools.Speech.SpeechSetup(),
diff --git a/servers/Azure.Mcp.Server/src/Resources/consolidated-tools.json b/servers/Azure.Mcp.Server/src/Resources/consolidated-tools.json
index 9b0bd58efe..f862dfbc9e 100644
--- a/servers/Azure.Mcp.Server/src/Resources/consolidated-tools.json
+++ b/servers/Azure.Mcp.Server/src/Resources/consolidated-tools.json
@@ -1,5 +1,50 @@
{
"consolidated_tools": [
+ {
+ "name": "get_azure_resilience_management_details",
+ "description": "Get details about Azure Resilience Management resources, including resilience goals (templates, assignments, and their resources), usage plans and enrollments, disaster recovery drills (drills, runs, and their resources), and recovery plans (plans, resources, and jobs) for Azure service groups.",
+ "toolMetadata": {
+ "destructive": {
+ "value": false,
+ "description": "This tool performs only additive updates without deleting or modifying existing resources."
+ },
+ "idempotent": {
+ "value": true,
+ "description": "Running this operation multiple times with the same arguments produces the same result without additional effects."
+ },
+ "openWorld": {
+ "value": false,
+ "description": "This tool's domain of interaction is closed and well-defined, limited to a specific set of entities."
+ },
+ "readOnly": {
+ "value": true,
+ "description": "This tool only performs read operations without modifying any state or data."
+ },
+ "secret": {
+ "value": false,
+ "description": "This tool does not handle sensitive or secret information."
+ },
+ "localRequired": {
+ "value": false,
+ "description": "This tool is available in both local and remote server modes."
+ }
+ },
+ "mappedToolList": [
+ "resilience_goal_template_get",
+ "resilience_goal_assignment_get",
+ "resilience_goal_resource_get",
+ "resilience_usageplan_get",
+ "resilience_usageplan_enrollment_get",
+ "resilience_drill_get",
+ "resilience_drill_resource_get",
+ "resilience_drill_run_get",
+ "resilience_drill_run_resource_get",
+ "resilience_recovery_plan_get",
+ "resilience_recovery_plan_resource_get",
+ "resilience_recovery_job_get",
+ "resilience_recovery_job_resource_get"
+ ]
+ },
{
"name": "get_azure_subscriptions_and_resource_groups",
"description": "Get information about Azure subscriptions, resource groups, and resources within resource groups that the user has access to.",
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/AssemblyInfo.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/AssemblyInfo.cs
new file mode 100644
index 0000000000..be08af097f
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/AssemblyInfo.cs
@@ -0,0 +1,6 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("Azure.Mcp.Tools.ResilienceManagement.Tests")]
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Azure.Mcp.Tools.ResilienceManagement.csproj b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Azure.Mcp.Tools.ResilienceManagement.csproj
new file mode 100644
index 0000000000..b9064cdc62
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Azure.Mcp.Tools.ResilienceManagement.csproj
@@ -0,0 +1,19 @@
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Drills/DrillGetCommand.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Drills/DrillGetCommand.cs
new file mode 100644
index 0000000000..90bca37619
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Drills/DrillGetCommand.cs
@@ -0,0 +1,93 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Net;
+using System.Text.Json;
+using Azure.Mcp.Core.Commands.Subscription;
+using Azure.Mcp.Core.Services.Azure.Subscription;
+using Azure.Mcp.Tools.ResilienceManagement.Commands;
+using Azure.Mcp.Tools.ResilienceManagement.Models;
+using Azure.Mcp.Tools.ResilienceManagement.Options.Drills;
+using Azure.Mcp.Tools.ResilienceManagement.Services;
+using Microsoft.Extensions.Logging;
+using Microsoft.Mcp.Core.Commands;
+using Microsoft.Mcp.Core.Models.Command;
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Commands.Drills;
+
+[CommandMetadata(
+ Id = "f0b6d31a-2c84-4e79-9a51-7d3f8c0b2e65",
+ Name = "get",
+ Title = "Get or List Resilience Drills",
+ Description = """
+ Gets resilience drills in the specified service group. Provide a drill name to get the full details of
+ that drill (including its identity, properties, and provisioning state). Omit the name to list all
+ drills in the service group, returning only their id and name.
+ """,
+ Destructive = false,
+ Idempotent = true,
+ OpenWorld = false,
+ ReadOnly = true,
+ Secret = false,
+ LocalRequired = false)]
+public sealed class DrillGetCommand(ILogger logger, IResilienceManagementService resilienceManagementService, ISubscriptionResolver subscriptionResolver)
+ : SubscriptionCommand(subscriptionResolver)
+{
+ private readonly ILogger _logger = logger;
+ private readonly IResilienceManagementService _resilienceManagementService = resilienceManagementService;
+
+ public override async Task ExecuteAsync(CommandContext context, DrillGetOptions options, CancellationToken cancellationToken)
+ {
+ try
+ {
+ DrillGetCommandResult result;
+ if (string.IsNullOrEmpty(options.Name))
+ {
+ var drills = await _resilienceManagementService.ListDrillsAsync(
+ options.ServiceGroup,
+ options.Subscription!,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+ result = new DrillGetCommandResult(Drills: drills.ToList());
+ }
+ else
+ {
+ var drill = await _resilienceManagementService.GetDrillAsync(
+ options.ServiceGroup,
+ options.Name,
+ options.Subscription!,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+ result = new DrillGetCommandResult(Drill: drill);
+ }
+
+ context.Response.Results = ResponseResult.Create(
+ result,
+ ResilienceManagementJsonContext.Default.DrillGetCommandResult);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex,
+ "Error getting drill(s). ServiceGroup: {ServiceGroup}, Name: {Name}, Subscription: {Subscription}.",
+ options.ServiceGroup, options.Name, options.Subscription);
+ HandleException(context, ex);
+ }
+
+ return context.Response;
+ }
+
+ protected override string GetErrorMessage(Exception ex) => ex switch
+ {
+ KeyNotFoundException => "Drill not found. Verify the drill name, service group, subscription, and that you have access.",
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.Forbidden =>
+ $"Authorization failed getting the drill. Details: {reqEx.Message}",
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.NotFound =>
+ "Drill not found. Verify the drill and service group exist and you have access.",
+ RequestFailedException reqEx => reqEx.Message,
+ _ => base.GetErrorMessage(ex)
+ };
+
+ public record DrillGetCommandResult(List? Drills = null, JsonElement Drill = default);
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Drills/Resources/DrillResourceGetCommand.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Drills/Resources/DrillResourceGetCommand.cs
new file mode 100644
index 0000000000..9ce7f66612
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Drills/Resources/DrillResourceGetCommand.cs
@@ -0,0 +1,95 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Net;
+using System.Text.Json;
+using Azure.Mcp.Core.Commands.Subscription;
+using Azure.Mcp.Core.Services.Azure.Subscription;
+using Azure.Mcp.Tools.ResilienceManagement.Commands;
+using Azure.Mcp.Tools.ResilienceManagement.Models;
+using Azure.Mcp.Tools.ResilienceManagement.Options.Drills.Resources;
+using Azure.Mcp.Tools.ResilienceManagement.Services;
+using Microsoft.Extensions.Logging;
+using Microsoft.Mcp.Core.Commands;
+using Microsoft.Mcp.Core.Models.Command;
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Commands.Drills.Resources;
+
+[CommandMetadata(
+ Id = "a4c8e1f2-7b39-4d06-8e12-5c9a0d4b6f31",
+ Name = "get",
+ Title = "Get or List Resilience Drill Resources",
+ Description = """
+ Gets the resources (targets) of a resilience drill. Provide a drill resource name to get the full
+ details of that resource. Omit the name to list all resources of the drill, returning only their id
+ and name.
+ """,
+ Destructive = false,
+ Idempotent = true,
+ OpenWorld = false,
+ ReadOnly = true,
+ Secret = false,
+ LocalRequired = false)]
+public sealed class DrillResourceGetCommand(ILogger logger, IResilienceManagementService resilienceManagementService, ISubscriptionResolver subscriptionResolver)
+ : SubscriptionCommand(subscriptionResolver)
+{
+ private readonly ILogger _logger = logger;
+ private readonly IResilienceManagementService _resilienceManagementService = resilienceManagementService;
+
+ public override async Task ExecuteAsync(CommandContext context, DrillResourceGetOptions options, CancellationToken cancellationToken)
+ {
+ try
+ {
+ DrillResourceGetCommandResult result;
+ if (string.IsNullOrEmpty(options.Name))
+ {
+ var drillResources = await _resilienceManagementService.ListDrillResourcesAsync(
+ options.ServiceGroup,
+ options.Drill,
+ options.Subscription!,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+ result = new DrillResourceGetCommandResult(DrillResources: drillResources.ToList());
+ }
+ else
+ {
+ var drillResource = await _resilienceManagementService.GetDrillResourceAsync(
+ options.ServiceGroup,
+ options.Drill,
+ options.Name,
+ options.Subscription!,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+ result = new DrillResourceGetCommandResult(DrillResource: drillResource);
+ }
+
+ context.Response.Results = ResponseResult.Create(
+ result,
+ ResilienceManagementJsonContext.Default.DrillResourceGetCommandResult);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex,
+ "Error getting drill resource(s). ServiceGroup: {ServiceGroup}, Drill: {Drill}, Name: {Name}, Subscription: {Subscription}.",
+ options.ServiceGroup, options.Drill, options.Name, options.Subscription);
+ HandleException(context, ex);
+ }
+
+ return context.Response;
+ }
+
+ protected override string GetErrorMessage(Exception ex) => ex switch
+ {
+ KeyNotFoundException => "Drill resource not found. Verify the drill resource name, drill, service group, subscription, and that you have access.",
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.Forbidden =>
+ $"Authorization failed getting the drill resource. Details: {reqEx.Message}",
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.NotFound =>
+ "Drill resource not found. Verify the drill resource and drill exist and you have access.",
+ RequestFailedException reqEx => reqEx.Message,
+ _ => base.GetErrorMessage(ex)
+ };
+
+ public record DrillResourceGetCommandResult(List? DrillResources = null, JsonElement DrillResource = default);
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Drills/Runs/DrillRunGetCommand.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Drills/Runs/DrillRunGetCommand.cs
new file mode 100644
index 0000000000..c67534b858
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Drills/Runs/DrillRunGetCommand.cs
@@ -0,0 +1,94 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Net;
+using System.Text.Json;
+using Azure.Mcp.Core.Commands.Subscription;
+using Azure.Mcp.Core.Services.Azure.Subscription;
+using Azure.Mcp.Tools.ResilienceManagement.Commands;
+using Azure.Mcp.Tools.ResilienceManagement.Models;
+using Azure.Mcp.Tools.ResilienceManagement.Options.Drills.Runs;
+using Azure.Mcp.Tools.ResilienceManagement.Services;
+using Microsoft.Extensions.Logging;
+using Microsoft.Mcp.Core.Commands;
+using Microsoft.Mcp.Core.Models.Command;
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Commands.Drills.Runs;
+
+[CommandMetadata(
+ Id = "d5f8b1c3-6a27-4e94-8c50-2b7d9f0a3e16",
+ Name = "get",
+ Title = "Get or List Resilience Drill Runs",
+ Description = """
+ Gets the runs of a resilience drill. Provide a drill run name to get the full details of that run. Omit
+ the name to list all runs of the drill, returning only their id and name.
+ """,
+ Destructive = false,
+ Idempotent = true,
+ OpenWorld = false,
+ ReadOnly = true,
+ Secret = false,
+ LocalRequired = false)]
+public sealed class DrillRunGetCommand(ILogger logger, IResilienceManagementService resilienceManagementService, ISubscriptionResolver subscriptionResolver)
+ : SubscriptionCommand(subscriptionResolver)
+{
+ private readonly ILogger _logger = logger;
+ private readonly IResilienceManagementService _resilienceManagementService = resilienceManagementService;
+
+ public override async Task ExecuteAsync(CommandContext context, DrillRunGetOptions options, CancellationToken cancellationToken)
+ {
+ try
+ {
+ DrillRunGetCommandResult result;
+ if (string.IsNullOrEmpty(options.Name))
+ {
+ var drillRuns = await _resilienceManagementService.ListDrillRunsAsync(
+ options.ServiceGroup,
+ options.Drill,
+ options.Subscription!,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+ result = new DrillRunGetCommandResult(DrillRuns: drillRuns.ToList());
+ }
+ else
+ {
+ var drillRun = await _resilienceManagementService.GetDrillRunAsync(
+ options.ServiceGroup,
+ options.Drill,
+ options.Name,
+ options.Subscription!,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+ result = new DrillRunGetCommandResult(DrillRun: drillRun);
+ }
+
+ context.Response.Results = ResponseResult.Create(
+ result,
+ ResilienceManagementJsonContext.Default.DrillRunGetCommandResult);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex,
+ "Error getting drill run(s). ServiceGroup: {ServiceGroup}, Drill: {Drill}, Name: {Name}, Subscription: {Subscription}.",
+ options.ServiceGroup, options.Drill, options.Name, options.Subscription);
+ HandleException(context, ex);
+ }
+
+ return context.Response;
+ }
+
+ protected override string GetErrorMessage(Exception ex) => ex switch
+ {
+ KeyNotFoundException => "Drill run not found. Verify the drill run name, drill, service group, subscription, and that you have access.",
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.Forbidden =>
+ $"Authorization failed getting the drill run. Details: {reqEx.Message}",
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.NotFound =>
+ "Drill run not found. Verify the drill run and drill exist and you have access.",
+ RequestFailedException reqEx => reqEx.Message,
+ _ => base.GetErrorMessage(ex)
+ };
+
+ public record DrillRunGetCommandResult(List? DrillRuns = null, JsonElement DrillRun = default);
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Drills/Runs/Resources/DrillRunResourceGetCommand.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Drills/Runs/Resources/DrillRunResourceGetCommand.cs
new file mode 100644
index 0000000000..15ac9c88e8
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Drills/Runs/Resources/DrillRunResourceGetCommand.cs
@@ -0,0 +1,97 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Net;
+using System.Text.Json;
+using Azure.Mcp.Core.Commands.Subscription;
+using Azure.Mcp.Core.Services.Azure.Subscription;
+using Azure.Mcp.Tools.ResilienceManagement.Commands;
+using Azure.Mcp.Tools.ResilienceManagement.Models;
+using Azure.Mcp.Tools.ResilienceManagement.Options.Drills.Runs.Resources;
+using Azure.Mcp.Tools.ResilienceManagement.Services;
+using Microsoft.Extensions.Logging;
+using Microsoft.Mcp.Core.Commands;
+using Microsoft.Mcp.Core.Models.Command;
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Commands.Drills.Runs.Resources;
+
+[CommandMetadata(
+ Id = "f3b7d2a8-1c64-4e90-9b25-6a0f8c3d5e74",
+ Name = "get",
+ Title = "Get or List Resilience Drill Run Resources",
+ Description = """
+ Gets the resources (targets) of a resilience drill run. Provide a drill run resource name to get the
+ full details of that resource. Omit the name to list all resources of the drill run, returning only
+ their id and name.
+ """,
+ Destructive = false,
+ Idempotent = true,
+ OpenWorld = false,
+ ReadOnly = true,
+ Secret = false,
+ LocalRequired = false)]
+public sealed class DrillRunResourceGetCommand(ILogger logger, IResilienceManagementService resilienceManagementService, ISubscriptionResolver subscriptionResolver)
+ : SubscriptionCommand(subscriptionResolver)
+{
+ private readonly ILogger _logger = logger;
+ private readonly IResilienceManagementService _resilienceManagementService = resilienceManagementService;
+
+ public override async Task ExecuteAsync(CommandContext context, DrillRunResourceGetOptions options, CancellationToken cancellationToken)
+ {
+ try
+ {
+ DrillRunResourceGetCommandResult result;
+ if (string.IsNullOrEmpty(options.Name))
+ {
+ var drillRunResources = await _resilienceManagementService.ListDrillRunResourcesAsync(
+ options.ServiceGroup,
+ options.Drill,
+ options.DrillRun,
+ options.Subscription!,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+ result = new DrillRunResourceGetCommandResult(DrillRunResources: drillRunResources.ToList());
+ }
+ else
+ {
+ var drillRunResource = await _resilienceManagementService.GetDrillRunResourceAsync(
+ options.ServiceGroup,
+ options.Drill,
+ options.DrillRun,
+ options.Name,
+ options.Subscription!,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+ result = new DrillRunResourceGetCommandResult(DrillRunResource: drillRunResource);
+ }
+
+ context.Response.Results = ResponseResult.Create(
+ result,
+ ResilienceManagementJsonContext.Default.DrillRunResourceGetCommandResult);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex,
+ "Error getting drill run resource(s). ServiceGroup: {ServiceGroup}, Drill: {Drill}, DrillRun: {DrillRun}, Name: {Name}, Subscription: {Subscription}.",
+ options.ServiceGroup, options.Drill, options.DrillRun, options.Name, options.Subscription);
+ HandleException(context, ex);
+ }
+
+ return context.Response;
+ }
+
+ protected override string GetErrorMessage(Exception ex) => ex switch
+ {
+ KeyNotFoundException => "Drill run resource not found. Verify the drill run resource name, drill run, drill, service group, subscription, and that you have access.",
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.Forbidden =>
+ $"Authorization failed getting the drill run resource. Details: {reqEx.Message}",
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.NotFound =>
+ "Drill run resource not found. Verify the drill run resource, drill run, and drill exist and you have access.",
+ RequestFailedException reqEx => reqEx.Message,
+ _ => base.GetErrorMessage(ex)
+ };
+
+ public record DrillRunResourceGetCommandResult(List? DrillRunResources = null, JsonElement DrillRunResource = default);
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Goals/Assignments/GoalAssignmentGetCommand.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Goals/Assignments/GoalAssignmentGetCommand.cs
new file mode 100644
index 0000000000..48f3c06e37
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Goals/Assignments/GoalAssignmentGetCommand.cs
@@ -0,0 +1,92 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Net;
+using Azure.Mcp.Core.Commands.Subscription;
+using Azure.Mcp.Core.Services.Azure.Subscription;
+using Azure.Mcp.Tools.ResilienceManagement.Commands;
+using Azure.Mcp.Tools.ResilienceManagement.Models;
+using Azure.Mcp.Tools.ResilienceManagement.Options.Goals.Assignments;
+using Azure.Mcp.Tools.ResilienceManagement.Services;
+using Microsoft.Extensions.Logging;
+using Microsoft.Mcp.Core.Commands;
+using Microsoft.Mcp.Core.Models.Command;
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Commands.Goals.Assignments;
+
+[CommandMetadata(
+ Id = "c1f4a82e-6d39-4b57-9e08-2a7c5b9d4f61",
+ Name = "get",
+ Title = "Get or List Resilience Goal Assignments",
+ Description = """
+ Gets resilience goal assignments in the specified service group. Provide a goal assignment name to get
+ the full details of that assignment (id, name, goal assignment type, goal template id, and provisioning
+ state). Omit the name to list all goal assignments in the service group, returning only their id and name.
+ """,
+ Destructive = false,
+ Idempotent = true,
+ OpenWorld = false,
+ ReadOnly = true,
+ Secret = false,
+ LocalRequired = false)]
+public sealed class GoalAssignmentGetCommand(ILogger logger, IResilienceManagementService resilienceManagementService, ISubscriptionResolver subscriptionResolver)
+ : SubscriptionCommand(subscriptionResolver)
+{
+ private readonly ILogger _logger = logger;
+ private readonly IResilienceManagementService _resilienceManagementService = resilienceManagementService;
+
+ public override async Task ExecuteAsync(CommandContext context, GoalAssignmentGetOptions options, CancellationToken cancellationToken)
+ {
+ try
+ {
+ GoalAssignmentGetCommandResult result;
+ if (string.IsNullOrEmpty(options.Name))
+ {
+ var goalAssignments = await _resilienceManagementService.ListGoalAssignmentsAsync(
+ options.ServiceGroup,
+ options.Subscription!,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+ result = new GoalAssignmentGetCommandResult(GoalAssignments: goalAssignments.ToList());
+ }
+ else
+ {
+ var goalAssignment = await _resilienceManagementService.GetGoalAssignmentAsync(
+ options.ServiceGroup,
+ options.Name,
+ options.Subscription!,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+ result = new GoalAssignmentGetCommandResult(GoalAssignment: goalAssignment);
+ }
+
+ context.Response.Results = ResponseResult.Create(
+ result,
+ ResilienceManagementJsonContext.Default.GoalAssignmentGetCommandResult);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex,
+ "Error getting goal assignment(s). ServiceGroup: {ServiceGroup}, Name: {Name}, Subscription: {Subscription}.",
+ options.ServiceGroup, options.Name, options.Subscription);
+ HandleException(context, ex);
+ }
+
+ return context.Response;
+ }
+
+ protected override string GetErrorMessage(Exception ex) => ex switch
+ {
+ KeyNotFoundException => "Goal assignment not found. Verify the goal assignment name, service group, subscription, and that you have access.",
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.Forbidden =>
+ $"Authorization failed getting the goal assignment. Details: {reqEx.Message}",
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.NotFound =>
+ "Goal assignment not found. Verify the goal assignment and service group exist and you have access.",
+ RequestFailedException reqEx => reqEx.Message,
+ _ => base.GetErrorMessage(ex)
+ };
+
+ public record GoalAssignmentGetCommandResult(List? GoalAssignments = null, GoalAssignmentInfo? GoalAssignment = null);
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Goals/Resources/GoalResourceGetCommand.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Goals/Resources/GoalResourceGetCommand.cs
new file mode 100644
index 0000000000..57f4fcf336
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Goals/Resources/GoalResourceGetCommand.cs
@@ -0,0 +1,95 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Net;
+using Azure.Mcp.Core.Commands.Subscription;
+using Azure.Mcp.Core.Services.Azure.Subscription;
+using Azure.Mcp.Tools.ResilienceManagement.Commands;
+using Azure.Mcp.Tools.ResilienceManagement.Models;
+using Azure.Mcp.Tools.ResilienceManagement.Options.Goals.Resources;
+using Azure.Mcp.Tools.ResilienceManagement.Services;
+using Microsoft.Extensions.Logging;
+using Microsoft.Mcp.Core.Commands;
+using Microsoft.Mcp.Core.Models.Command;
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Commands.Goals.Resources;
+
+[CommandMetadata(
+ Id = "a3e7f29c-5b81-4d06-8f53-2c9b1e7a4d68",
+ Name = "get",
+ Title = "Get or List Resilience Goal Resources",
+ Description = """
+ Gets the resources (members) of a resilience goal assignment. Provide a goal resource name to get the
+ full details of that resource (id, name, disaster recovery and high availability attestation status and
+ goal participation, exclusion reasons, provisioning state, the resource ARM id, and service group
+ memberships). Omit the name to list all resources of the goal assignment, returning only their id and name.
+ """,
+ Destructive = false,
+ Idempotent = true,
+ OpenWorld = false,
+ ReadOnly = true,
+ Secret = false,
+ LocalRequired = false)]
+public sealed class GoalResourceGetCommand(ILogger logger, IResilienceManagementService resilienceManagementService, ISubscriptionResolver subscriptionResolver)
+ : SubscriptionCommand(subscriptionResolver)
+{
+ private readonly ILogger _logger = logger;
+ private readonly IResilienceManagementService _resilienceManagementService = resilienceManagementService;
+
+ public override async Task ExecuteAsync(CommandContext context, GoalResourceGetOptions options, CancellationToken cancellationToken)
+ {
+ try
+ {
+ GoalResourceGetCommandResult result;
+ if (string.IsNullOrEmpty(options.Name))
+ {
+ var goalResources = await _resilienceManagementService.ListGoalResourcesAsync(
+ options.ServiceGroup,
+ options.GoalAssignment,
+ options.Subscription!,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+ result = new GoalResourceGetCommandResult(GoalResources: goalResources.ToList());
+ }
+ else
+ {
+ var goalResource = await _resilienceManagementService.GetGoalResourceAsync(
+ options.ServiceGroup,
+ options.GoalAssignment,
+ options.Name,
+ options.Subscription!,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+ result = new GoalResourceGetCommandResult(GoalResource: goalResource);
+ }
+
+ context.Response.Results = ResponseResult.Create(
+ result,
+ ResilienceManagementJsonContext.Default.GoalResourceGetCommandResult);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex,
+ "Error getting goal resource(s). ServiceGroup: {ServiceGroup}, GoalAssignment: {GoalAssignment}, Name: {Name}, Subscription: {Subscription}.",
+ options.ServiceGroup, options.GoalAssignment, options.Name, options.Subscription);
+ HandleException(context, ex);
+ }
+
+ return context.Response;
+ }
+
+ protected override string GetErrorMessage(Exception ex) => ex switch
+ {
+ KeyNotFoundException => "Goal resource not found. Verify the goal resource name, goal assignment, service group, subscription, and that you have access.",
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.Forbidden =>
+ $"Authorization failed getting the goal resource. Details: {reqEx.Message}",
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.NotFound =>
+ "Goal resource not found. Verify the goal resource, goal assignment, and service group exist and you have access.",
+ RequestFailedException reqEx => reqEx.Message,
+ _ => base.GetErrorMessage(ex)
+ };
+
+ public record GoalResourceGetCommandResult(List? GoalResources = null, GoalResourceInfo? GoalResource = null);
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Goals/Templates/GoalTemplateGetCommand.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Goals/Templates/GoalTemplateGetCommand.cs
new file mode 100644
index 0000000000..1af722e39c
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Goals/Templates/GoalTemplateGetCommand.cs
@@ -0,0 +1,93 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Net;
+using Azure.Mcp.Core.Commands.Subscription;
+using Azure.Mcp.Core.Services.Azure.Subscription;
+using Azure.Mcp.Tools.ResilienceManagement.Commands;
+using Azure.Mcp.Tools.ResilienceManagement.Models;
+using Azure.Mcp.Tools.ResilienceManagement.Options.Goals.Templates;
+using Azure.Mcp.Tools.ResilienceManagement.Services;
+using Microsoft.Extensions.Logging;
+using Microsoft.Mcp.Core.Commands;
+using Microsoft.Mcp.Core.Models.Command;
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Commands.Goals.Templates;
+
+[CommandMetadata(
+ Id = "e5b71c93-4d8a-42f6-9b0c-3a7e1d6f8025",
+ Name = "get",
+ Title = "Get or List Resilience Goal Templates",
+ Description = """
+ Gets resilience goal templates in the specified service group. Provide a goal template name to get the
+ full details of that template (id, name, goal type, provisioning state, recovery point and time
+ objectives, and high availability and disaster recovery requirements). Omit the name to list all goal
+ templates in the service group, returning only their id and name.
+ """,
+ Destructive = false,
+ Idempotent = true,
+ OpenWorld = false,
+ ReadOnly = true,
+ Secret = false,
+ LocalRequired = false)]
+public sealed class GoalTemplateGetCommand(ILogger logger, IResilienceManagementService resilienceManagementService, ISubscriptionResolver subscriptionResolver)
+ : SubscriptionCommand(subscriptionResolver)
+{
+ private readonly ILogger _logger = logger;
+ private readonly IResilienceManagementService _resilienceManagementService = resilienceManagementService;
+
+ public override async Task ExecuteAsync(CommandContext context, GoalTemplateGetOptions options, CancellationToken cancellationToken)
+ {
+ try
+ {
+ GoalTemplateGetCommandResult result;
+ if (string.IsNullOrEmpty(options.Name))
+ {
+ var goalTemplates = await _resilienceManagementService.ListGoalTemplatesAsync(
+ options.ServiceGroup,
+ options.Subscription!,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+ result = new GoalTemplateGetCommandResult(GoalTemplates: goalTemplates.ToList());
+ }
+ else
+ {
+ var goalTemplate = await _resilienceManagementService.GetGoalTemplateAsync(
+ options.ServiceGroup,
+ options.Name,
+ options.Subscription!,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+ result = new GoalTemplateGetCommandResult(GoalTemplate: goalTemplate);
+ }
+
+ context.Response.Results = ResponseResult.Create(
+ result,
+ ResilienceManagementJsonContext.Default.GoalTemplateGetCommandResult);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex,
+ "Error getting goal template(s). ServiceGroup: {ServiceGroup}, Name: {Name}, Subscription: {Subscription}.",
+ options.ServiceGroup, options.Name, options.Subscription);
+ HandleException(context, ex);
+ }
+
+ return context.Response;
+ }
+
+ protected override string GetErrorMessage(Exception ex) => ex switch
+ {
+ KeyNotFoundException => "Goal template not found. Verify the goal template name, service group, subscription, and that you have access.",
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.Forbidden =>
+ $"Authorization failed getting the goal template. Details: {reqEx.Message}",
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.NotFound =>
+ "Goal template not found. Verify the goal template and service group exist and you have access.",
+ RequestFailedException reqEx => reqEx.Message,
+ _ => base.GetErrorMessage(ex)
+ };
+
+ public record GoalTemplateGetCommandResult(List? GoalTemplates = null, GoalTemplateInfo? GoalTemplate = null);
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Recovery/Jobs/RecoveryJobGetCommand.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Recovery/Jobs/RecoveryJobGetCommand.cs
new file mode 100644
index 0000000000..05cd04404d
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Recovery/Jobs/RecoveryJobGetCommand.cs
@@ -0,0 +1,95 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Net;
+using System.Text.Json;
+using Azure.Mcp.Core.Commands.Subscription;
+using Azure.Mcp.Core.Services.Azure.Subscription;
+using Azure.Mcp.Tools.ResilienceManagement.Commands;
+using Azure.Mcp.Tools.ResilienceManagement.Models;
+using Azure.Mcp.Tools.ResilienceManagement.Options.Recovery.Jobs;
+using Azure.Mcp.Tools.ResilienceManagement.Services;
+using Microsoft.Extensions.Logging;
+using Microsoft.Mcp.Core.Commands;
+using Microsoft.Mcp.Core.Models.Command;
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Commands.Recovery.Jobs;
+
+[CommandMetadata(
+ Id = "c7e1b4a9-2d63-4f08-8b95-1a6c3f0d7e42",
+ Name = "get",
+ Title = "Get or List Resilience Recovery Jobs",
+ Description = """
+ Gets the recovery jobs of a resilience recovery plan. Provide a recovery job name to get the full
+ details of that job. Omit the name to list all recovery jobs of the recovery plan, returning only their
+ id and name.
+ """,
+ Destructive = false,
+ Idempotent = true,
+ OpenWorld = false,
+ ReadOnly = true,
+ Secret = false,
+ LocalRequired = false)]
+public sealed class RecoveryJobGetCommand(ILogger logger, IResilienceManagementService resilienceManagementService, ISubscriptionResolver subscriptionResolver)
+ : SubscriptionCommand(subscriptionResolver)
+{
+ private readonly ILogger _logger = logger;
+ private readonly IResilienceManagementService _resilienceManagementService = resilienceManagementService;
+
+ public override async Task ExecuteAsync(CommandContext context, RecoveryJobGetOptions options, CancellationToken cancellationToken)
+ {
+ try
+ {
+ RecoveryJobGetCommandResult result;
+ if (string.IsNullOrEmpty(options.Name))
+ {
+ var recoveryJobs = await _resilienceManagementService.ListRecoveryJobsAsync(
+ options.ServiceGroup,
+ options.RecoveryPlan,
+ options.Subscription!,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+ result = new RecoveryJobGetCommandResult(RecoveryJobs: recoveryJobs.ToList());
+ }
+ else
+ {
+ var recoveryJob = await _resilienceManagementService.GetRecoveryJobAsync(
+ options.ServiceGroup,
+ options.RecoveryPlan,
+ options.Name,
+ options.Subscription!,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+ result = new RecoveryJobGetCommandResult(RecoveryJob: recoveryJob);
+ }
+
+ context.Response.Results = ResponseResult.Create(
+ result,
+ ResilienceManagementJsonContext.Default.RecoveryJobGetCommandResult);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex,
+ "Error getting recovery job(s). ServiceGroup: {ServiceGroup}, RecoveryPlan: {RecoveryPlan}, Name: {Name}, Subscription: {Subscription}.",
+ options.ServiceGroup, options.RecoveryPlan, options.Name, options.Subscription);
+ HandleException(context, ex);
+ }
+
+ return context.Response;
+ }
+
+ protected override string GetErrorMessage(Exception ex) => ex switch
+ {
+ KeyNotFoundException => "Recovery job not found. Verify the recovery job name, recovery plan, service group, subscription, and that you have access.",
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.Forbidden =>
+ $"Authorization failed getting the recovery job. Details: {reqEx.Message}",
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.NotFound =>
+ "Recovery job not found. Verify the recovery job, recovery plan, and service group exist and you have access.",
+ RequestFailedException reqEx => reqEx.Message,
+ _ => base.GetErrorMessage(ex)
+ };
+
+ public record RecoveryJobGetCommandResult(List? RecoveryJobs = null, JsonElement RecoveryJob = default);
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Recovery/Jobs/Resources/RecoveryJobResourceGetCommand.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Recovery/Jobs/Resources/RecoveryJobResourceGetCommand.cs
new file mode 100644
index 0000000000..f007e3ad72
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Recovery/Jobs/Resources/RecoveryJobResourceGetCommand.cs
@@ -0,0 +1,97 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Net;
+using System.Text.Json;
+using Azure.Mcp.Core.Commands.Subscription;
+using Azure.Mcp.Core.Services.Azure.Subscription;
+using Azure.Mcp.Tools.ResilienceManagement.Commands;
+using Azure.Mcp.Tools.ResilienceManagement.Models;
+using Azure.Mcp.Tools.ResilienceManagement.Options.Recovery.Jobs.Resources;
+using Azure.Mcp.Tools.ResilienceManagement.Services;
+using Microsoft.Extensions.Logging;
+using Microsoft.Mcp.Core.Commands;
+using Microsoft.Mcp.Core.Models.Command;
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Commands.Recovery.Jobs.Resources;
+
+[CommandMetadata(
+ Id = "a1d6f3c8-7b94-4e25-9c08-2f5b7d0a3e69",
+ Name = "get",
+ Title = "Get or List Resilience Recovery Job Resources",
+ Description = """
+ Gets the resources (targets) of a resilience recovery job. Provide a recovery job resource name to get
+ the full details of that resource. Omit the name to list all resources of the recovery job, returning
+ only their id and name.
+ """,
+ Destructive = false,
+ Idempotent = true,
+ OpenWorld = false,
+ ReadOnly = true,
+ Secret = false,
+ LocalRequired = false)]
+public sealed class RecoveryJobResourceGetCommand(ILogger logger, IResilienceManagementService resilienceManagementService, ISubscriptionResolver subscriptionResolver)
+ : SubscriptionCommand(subscriptionResolver)
+{
+ private readonly ILogger _logger = logger;
+ private readonly IResilienceManagementService _resilienceManagementService = resilienceManagementService;
+
+ public override async Task ExecuteAsync(CommandContext context, RecoveryJobResourceGetOptions options, CancellationToken cancellationToken)
+ {
+ try
+ {
+ RecoveryJobResourceGetCommandResult result;
+ if (string.IsNullOrEmpty(options.Name))
+ {
+ var recoveryJobResources = await _resilienceManagementService.ListRecoveryJobResourcesAsync(
+ options.ServiceGroup,
+ options.RecoveryPlan,
+ options.RecoveryJob,
+ options.Subscription!,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+ result = new RecoveryJobResourceGetCommandResult(RecoveryJobResources: recoveryJobResources.ToList());
+ }
+ else
+ {
+ var recoveryJobResource = await _resilienceManagementService.GetRecoveryJobResourceAsync(
+ options.ServiceGroup,
+ options.RecoveryPlan,
+ options.RecoveryJob,
+ options.Name,
+ options.Subscription!,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+ result = new RecoveryJobResourceGetCommandResult(RecoveryJobResource: recoveryJobResource);
+ }
+
+ context.Response.Results = ResponseResult.Create(
+ result,
+ ResilienceManagementJsonContext.Default.RecoveryJobResourceGetCommandResult);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex,
+ "Error getting recovery job resource(s). ServiceGroup: {ServiceGroup}, RecoveryPlan: {RecoveryPlan}, RecoveryJob: {RecoveryJob}, Name: {Name}, Subscription: {Subscription}.",
+ options.ServiceGroup, options.RecoveryPlan, options.RecoveryJob, options.Name, options.Subscription);
+ HandleException(context, ex);
+ }
+
+ return context.Response;
+ }
+
+ protected override string GetErrorMessage(Exception ex) => ex switch
+ {
+ KeyNotFoundException => "Recovery job resource not found. Verify the recovery job resource name, recovery job, recovery plan, service group, subscription, and that you have access.",
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.Forbidden =>
+ $"Authorization failed getting the recovery job resource. Details: {reqEx.Message}",
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.NotFound =>
+ "Recovery job resource not found. Verify the recovery job resource, recovery job, recovery plan, and service group exist and you have access.",
+ RequestFailedException reqEx => reqEx.Message,
+ _ => base.GetErrorMessage(ex)
+ };
+
+ public record RecoveryJobResourceGetCommandResult(List? RecoveryJobResources = null, JsonElement RecoveryJobResource = default);
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Recovery/Plans/RecoveryPlanGetCommand.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Recovery/Plans/RecoveryPlanGetCommand.cs
new file mode 100644
index 0000000000..9eb655a3da
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Recovery/Plans/RecoveryPlanGetCommand.cs
@@ -0,0 +1,93 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Net;
+using System.Text.Json;
+using Azure.Mcp.Core.Commands.Subscription;
+using Azure.Mcp.Core.Services.Azure.Subscription;
+using Azure.Mcp.Tools.ResilienceManagement.Commands;
+using Azure.Mcp.Tools.ResilienceManagement.Models;
+using Azure.Mcp.Tools.ResilienceManagement.Options.Recovery.Plans;
+using Azure.Mcp.Tools.ResilienceManagement.Services;
+using Microsoft.Extensions.Logging;
+using Microsoft.Mcp.Core.Commands;
+using Microsoft.Mcp.Core.Models.Command;
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Commands.Recovery.Plans;
+
+[CommandMetadata(
+ Id = "d4a8f1c6-3b75-4e29-9c08-2f6b5d0a7e31",
+ Name = "get",
+ Title = "Get or List Resilience Recovery Plans",
+ Description = """
+ Gets resilience recovery plans in the specified service group. Provide a recovery plan name to get the
+ full details of that plan (including its properties and provisioning state). Omit the name to list all
+ recovery plans in the service group, returning only their id and name.
+ """,
+ Destructive = false,
+ Idempotent = true,
+ OpenWorld = false,
+ ReadOnly = true,
+ Secret = false,
+ LocalRequired = false)]
+public sealed class RecoveryPlanGetCommand(ILogger logger, IResilienceManagementService resilienceManagementService, ISubscriptionResolver subscriptionResolver)
+ : SubscriptionCommand(subscriptionResolver)
+{
+ private readonly ILogger _logger = logger;
+ private readonly IResilienceManagementService _resilienceManagementService = resilienceManagementService;
+
+ public override async Task ExecuteAsync(CommandContext context, RecoveryPlanGetOptions options, CancellationToken cancellationToken)
+ {
+ try
+ {
+ RecoveryPlanGetCommandResult result;
+ if (string.IsNullOrEmpty(options.Name))
+ {
+ var recoveryPlans = await _resilienceManagementService.ListRecoveryPlansAsync(
+ options.ServiceGroup,
+ options.Subscription!,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+ result = new RecoveryPlanGetCommandResult(RecoveryPlans: recoveryPlans.ToList());
+ }
+ else
+ {
+ var recoveryPlan = await _resilienceManagementService.GetRecoveryPlanAsync(
+ options.ServiceGroup,
+ options.Name,
+ options.Subscription!,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+ result = new RecoveryPlanGetCommandResult(RecoveryPlan: recoveryPlan);
+ }
+
+ context.Response.Results = ResponseResult.Create(
+ result,
+ ResilienceManagementJsonContext.Default.RecoveryPlanGetCommandResult);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex,
+ "Error getting recovery plan(s). ServiceGroup: {ServiceGroup}, Name: {Name}, Subscription: {Subscription}.",
+ options.ServiceGroup, options.Name, options.Subscription);
+ HandleException(context, ex);
+ }
+
+ return context.Response;
+ }
+
+ protected override string GetErrorMessage(Exception ex) => ex switch
+ {
+ KeyNotFoundException => "Recovery plan not found. Verify the recovery plan name, service group, subscription, and that you have access.",
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.Forbidden =>
+ $"Authorization failed getting the recovery plan. Details: {reqEx.Message}",
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.NotFound =>
+ "Recovery plan not found. Verify the recovery plan and service group exist and you have access.",
+ RequestFailedException reqEx => reqEx.Message,
+ _ => base.GetErrorMessage(ex)
+ };
+
+ public record RecoveryPlanGetCommandResult(List? RecoveryPlans = null, JsonElement RecoveryPlan = default);
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Recovery/Plans/Resources/RecoveryResourceGetCommand.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Recovery/Plans/Resources/RecoveryResourceGetCommand.cs
new file mode 100644
index 0000000000..27c2a01881
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/Recovery/Plans/Resources/RecoveryResourceGetCommand.cs
@@ -0,0 +1,95 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Net;
+using System.Text.Json;
+using Azure.Mcp.Core.Commands.Subscription;
+using Azure.Mcp.Core.Services.Azure.Subscription;
+using Azure.Mcp.Tools.ResilienceManagement.Commands;
+using Azure.Mcp.Tools.ResilienceManagement.Models;
+using Azure.Mcp.Tools.ResilienceManagement.Options.Recovery.Plans.Resources;
+using Azure.Mcp.Tools.ResilienceManagement.Services;
+using Microsoft.Extensions.Logging;
+using Microsoft.Mcp.Core.Commands;
+using Microsoft.Mcp.Core.Models.Command;
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Commands.Recovery.Plans.Resources;
+
+[CommandMetadata(
+ Id = "b9d2f74c-1a85-4e30-8c67-3f0b6a2d9e51",
+ Name = "get",
+ Title = "Get or List Resilience Recovery Resources",
+ Description = """
+ Gets the resources (members) of a resilience recovery plan. Provide a recovery resource name to get the
+ full details of that resource. Omit the name to list all resources of the recovery plan, returning only
+ their id and name.
+ """,
+ Destructive = false,
+ Idempotent = true,
+ OpenWorld = false,
+ ReadOnly = true,
+ Secret = false,
+ LocalRequired = false)]
+public sealed class RecoveryResourceGetCommand(ILogger logger, IResilienceManagementService resilienceManagementService, ISubscriptionResolver subscriptionResolver)
+ : SubscriptionCommand(subscriptionResolver)
+{
+ private readonly ILogger _logger = logger;
+ private readonly IResilienceManagementService _resilienceManagementService = resilienceManagementService;
+
+ public override async Task ExecuteAsync(CommandContext context, RecoveryResourceGetOptions options, CancellationToken cancellationToken)
+ {
+ try
+ {
+ RecoveryResourceGetCommandResult result;
+ if (string.IsNullOrEmpty(options.Name))
+ {
+ var recoveryResources = await _resilienceManagementService.ListRecoveryResourcesAsync(
+ options.ServiceGroup,
+ options.RecoveryPlan,
+ options.Subscription!,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+ result = new RecoveryResourceGetCommandResult(RecoveryResources: recoveryResources.ToList());
+ }
+ else
+ {
+ var recoveryResource = await _resilienceManagementService.GetRecoveryResourceAsync(
+ options.ServiceGroup,
+ options.RecoveryPlan,
+ options.Name,
+ options.Subscription!,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+ result = new RecoveryResourceGetCommandResult(RecoveryResource: recoveryResource);
+ }
+
+ context.Response.Results = ResponseResult.Create(
+ result,
+ ResilienceManagementJsonContext.Default.RecoveryResourceGetCommandResult);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex,
+ "Error getting recovery resource(s). ServiceGroup: {ServiceGroup}, RecoveryPlan: {RecoveryPlan}, Name: {Name}, Subscription: {Subscription}.",
+ options.ServiceGroup, options.RecoveryPlan, options.Name, options.Subscription);
+ HandleException(context, ex);
+ }
+
+ return context.Response;
+ }
+
+ protected override string GetErrorMessage(Exception ex) => ex switch
+ {
+ KeyNotFoundException => "Recovery resource not found. Verify the recovery resource name, recovery plan, service group, subscription, and that you have access.",
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.Forbidden =>
+ $"Authorization failed getting the recovery resource. Details: {reqEx.Message}",
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.NotFound =>
+ "Recovery resource not found. Verify the recovery resource, recovery plan, and service group exist and you have access.",
+ RequestFailedException reqEx => reqEx.Message,
+ _ => base.GetErrorMessage(ex)
+ };
+
+ public record RecoveryResourceGetCommandResult(List? RecoveryResources = null, JsonElement RecoveryResource = default);
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/ResilienceManagementJsonContext.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/ResilienceManagementJsonContext.cs
new file mode 100644
index 0000000000..ac2e146cc5
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/ResilienceManagementJsonContext.cs
@@ -0,0 +1,58 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using Azure.Mcp.Tools.ResilienceManagement.Commands.Drills;
+using Azure.Mcp.Tools.ResilienceManagement.Commands.Drills.Resources;
+using Azure.Mcp.Tools.ResilienceManagement.Commands.Drills.Runs;
+using Azure.Mcp.Tools.ResilienceManagement.Commands.Drills.Runs.Resources;
+using Azure.Mcp.Tools.ResilienceManagement.Commands.Goals.Assignments;
+using Azure.Mcp.Tools.ResilienceManagement.Commands.Goals.Resources;
+using Azure.Mcp.Tools.ResilienceManagement.Commands.Goals.Templates;
+using Azure.Mcp.Tools.ResilienceManagement.Commands.Recovery.Jobs;
+using Azure.Mcp.Tools.ResilienceManagement.Commands.Recovery.Jobs.Resources;
+using Azure.Mcp.Tools.ResilienceManagement.Commands.Recovery.Plans;
+using Azure.Mcp.Tools.ResilienceManagement.Commands.Recovery.Plans.Resources;
+using Azure.Mcp.Tools.ResilienceManagement.Commands.UsagePlans;
+using Azure.Mcp.Tools.ResilienceManagement.Commands.UsagePlans.Enrollments;
+using Azure.Mcp.Tools.ResilienceManagement.Models;
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Commands;
+
+[JsonSerializable(typeof(GoalTemplateGetCommand.GoalTemplateGetCommandResult))]
+[JsonSerializable(typeof(GoalTemplateInfo))]
+[JsonSerializable(typeof(GoalTemplateInfoProperties))]
+[JsonSerializable(typeof(GoalTemplateInfoSystemData))]
+[JsonSerializable(typeof(GoalAssignmentGetCommand.GoalAssignmentGetCommandResult))]
+[JsonSerializable(typeof(GoalAssignmentInfo))]
+[JsonSerializable(typeof(GoalAssignmentInfoProperties))]
+[JsonSerializable(typeof(GoalAssignmentInfoSystemData))]
+[JsonSerializable(typeof(GoalResourceGetCommand.GoalResourceGetCommandResult))]
+[JsonSerializable(typeof(GoalResourceInfo))]
+[JsonSerializable(typeof(GoalResourceInfoProperties))]
+[JsonSerializable(typeof(GoalResourceServiceGroupMembership))]
+[JsonSerializable(typeof(GoalResourceInfoSystemData))]
+[JsonSerializable(typeof(UsagePlanGetCommand.UsagePlanGetCommandResult))]
+[JsonSerializable(typeof(UsagePlanInfo))]
+[JsonSerializable(typeof(UsagePlanInfoProperties))]
+[JsonSerializable(typeof(UsagePlanInfoSystemData))]
+[JsonSerializable(typeof(UsagePlanEnrollmentGetCommand.UsagePlanEnrollmentGetCommandResult))]
+[JsonSerializable(typeof(UsagePlanEnrollmentInfo))]
+[JsonSerializable(typeof(UsagePlanEnrollmentInfoProperties))]
+[JsonSerializable(typeof(UsagePlanEnrollmentInfoErrorDetails))]
+[JsonSerializable(typeof(UsagePlanEnrollmentInfoSystemData))]
+[JsonSerializable(typeof(DrillGetCommand.DrillGetCommandResult))]
+[JsonSerializable(typeof(DrillResourceGetCommand.DrillResourceGetCommandResult))]
+[JsonSerializable(typeof(DrillRunGetCommand.DrillRunGetCommandResult))]
+[JsonSerializable(typeof(DrillRunResourceGetCommand.DrillRunResourceGetCommandResult))]
+[JsonSerializable(typeof(RecoveryPlanGetCommand.RecoveryPlanGetCommandResult))]
+[JsonSerializable(typeof(RecoveryResourceGetCommand.RecoveryResourceGetCommandResult))]
+[JsonSerializable(typeof(RecoveryJobGetCommand.RecoveryJobGetCommandResult))]
+[JsonSerializable(typeof(RecoveryJobResourceGetCommand.RecoveryJobResourceGetCommandResult))]
+[JsonSerializable(typeof(ResourceSummary))]
+[JsonSerializable(typeof(JsonElement))]
+[JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault)]
+internal sealed partial class ResilienceManagementJsonContext : JsonSerializerContext
+{
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/UsagePlans/Enrollments/UsagePlanEnrollmentGetCommand.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/UsagePlans/Enrollments/UsagePlanEnrollmentGetCommand.cs
new file mode 100644
index 0000000000..776186cd41
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/UsagePlans/Enrollments/UsagePlanEnrollmentGetCommand.cs
@@ -0,0 +1,94 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Net;
+using Azure.Mcp.Core.Commands.Subscription;
+using Azure.Mcp.Core.Services.Azure.Subscription;
+using Azure.Mcp.Tools.ResilienceManagement.Commands;
+using Azure.Mcp.Tools.ResilienceManagement.Models;
+using Azure.Mcp.Tools.ResilienceManagement.Options.UsagePlans.Enrollments;
+using Azure.Mcp.Tools.ResilienceManagement.Services;
+using Microsoft.Extensions.Logging;
+using Microsoft.Mcp.Core.Commands;
+using Microsoft.Mcp.Core.Models.Command;
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Commands.UsagePlans.Enrollments;
+
+[CommandMetadata(
+ Id = "f6c29a47-8b51-43d0-9e62-1d4a7c8e9b50",
+ Name = "get",
+ Title = "Get or List Resilience Usage Plan Enrollments",
+ Description = """
+ Gets enrollments of a resilience usage plan. Provide an enrollment name to get the full details of that
+ enrollment (id, name, the associated service group id, provisioning state, and error details). Omit the
+ name to list all enrollments of the usage plan, returning only their id and name.
+ """,
+ Destructive = false,
+ Idempotent = true,
+ OpenWorld = false,
+ ReadOnly = true,
+ Secret = false,
+ LocalRequired = false)]
+public sealed class UsagePlanEnrollmentGetCommand(ILogger logger, IResilienceManagementService resilienceManagementService, ISubscriptionResolver subscriptionResolver)
+ : SubscriptionCommand(subscriptionResolver)
+{
+ private readonly ILogger _logger = logger;
+ private readonly IResilienceManagementService _resilienceManagementService = resilienceManagementService;
+
+ public override async Task ExecuteAsync(CommandContext context, UsagePlanEnrollmentGetOptions options, CancellationToken cancellationToken)
+ {
+ try
+ {
+ UsagePlanEnrollmentGetCommandResult result;
+ if (string.IsNullOrEmpty(options.Name))
+ {
+ var enrollments = await _resilienceManagementService.ListUsagePlanEnrollmentsAsync(
+ options.ResourceGroup,
+ options.UsagePlan,
+ options.Subscription!,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+ result = new UsagePlanEnrollmentGetCommandResult(Enrollments: enrollments.ToList());
+ }
+ else
+ {
+ var enrollment = await _resilienceManagementService.GetUsagePlanEnrollmentAsync(
+ options.ResourceGroup,
+ options.UsagePlan,
+ options.Name,
+ options.Subscription!,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+ result = new UsagePlanEnrollmentGetCommandResult(Enrollment: enrollment);
+ }
+
+ context.Response.Results = ResponseResult.Create(
+ result,
+ ResilienceManagementJsonContext.Default.UsagePlanEnrollmentGetCommandResult);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex,
+ "Error getting usage plan enrollment(s). ResourceGroup: {ResourceGroup}, UsagePlan: {UsagePlan}, Name: {Name}, Subscription: {Subscription}.",
+ options.ResourceGroup, options.UsagePlan, options.Name, options.Subscription);
+ HandleException(context, ex);
+ }
+
+ return context.Response;
+ }
+
+ protected override string GetErrorMessage(Exception ex) => ex switch
+ {
+ KeyNotFoundException => "Usage plan enrollment not found. Verify the enrollment name, usage plan, resource group, subscription, and that you have access.",
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.Forbidden =>
+ $"Authorization failed getting the usage plan enrollment. Details: {reqEx.Message}",
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.NotFound =>
+ "Usage plan enrollment not found. Verify the enrollment and usage plan exist and you have access.",
+ RequestFailedException reqEx => reqEx.Message,
+ _ => base.GetErrorMessage(ex)
+ };
+
+ public record UsagePlanEnrollmentGetCommandResult(List? Enrollments = null, UsagePlanEnrollmentInfo? Enrollment = null);
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/UsagePlans/UsagePlanGetCommand.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/UsagePlans/UsagePlanGetCommand.cs
new file mode 100644
index 0000000000..85fc6207c9
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Commands/UsagePlans/UsagePlanGetCommand.cs
@@ -0,0 +1,108 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Net;
+using Azure.Mcp.Core.Commands.Subscription;
+using Azure.Mcp.Core.Services.Azure.Subscription;
+using Azure.Mcp.Tools.ResilienceManagement.Commands;
+using Azure.Mcp.Tools.ResilienceManagement.Models;
+using Azure.Mcp.Tools.ResilienceManagement.Options.UsagePlans;
+using Azure.Mcp.Tools.ResilienceManagement.Services;
+using Microsoft.Extensions.Logging;
+using Microsoft.Mcp.Core.Commands;
+using Microsoft.Mcp.Core.Models.Command;
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Commands.UsagePlans;
+
+[CommandMetadata(
+ Id = "a8d3f60b-5c27-4e19-8f74-0b6a2d9c5e83",
+ Name = "get",
+ Title = "Get or List Resilience Usage Plans",
+ Description = """
+ Gets resilience usage plans. Provide a usage plan name (with its resource group) to get the full details
+ of that plan (id, name, resource type, location, tags, plan type, and provisioning state). Omit the name
+ to list usage plans (id and name only): for the given resource group, or for the whole subscription when
+ no resource group is provided.
+ """,
+ Destructive = false,
+ Idempotent = true,
+ OpenWorld = false,
+ ReadOnly = true,
+ Secret = false,
+ LocalRequired = false)]
+public sealed class UsagePlanGetCommand(ILogger logger, IResilienceManagementService resilienceManagementService, ISubscriptionResolver subscriptionResolver)
+ : SubscriptionCommand(subscriptionResolver)
+{
+ private readonly ILogger _logger = logger;
+ private readonly IResilienceManagementService _resilienceManagementService = resilienceManagementService;
+
+ public override async Task ExecuteAsync(CommandContext context, UsagePlanGetOptions options, CancellationToken cancellationToken)
+ {
+ try
+ {
+ UsagePlanGetCommandResult result;
+ if (!string.IsNullOrEmpty(options.Name))
+ {
+ if (string.IsNullOrEmpty(options.ResourceGroup))
+ {
+ throw new ArgumentException("A resource group is required when getting a specific usage plan. Provide --resource-group.");
+ }
+
+ var usagePlan = await _resilienceManagementService.GetUsagePlanAsync(
+ options.ResourceGroup,
+ options.Name,
+ options.Subscription!,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+ result = new UsagePlanGetCommandResult(UsagePlan: usagePlan);
+ }
+ else if (!string.IsNullOrEmpty(options.ResourceGroup))
+ {
+ var usagePlans = await _resilienceManagementService.ListUsagePlansAsync(
+ options.ResourceGroup,
+ options.Subscription!,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+ result = new UsagePlanGetCommandResult(UsagePlans: usagePlans.ToList());
+ }
+ else
+ {
+ var usagePlans = await _resilienceManagementService.ListUsagePlansBySubscriptionAsync(
+ options.Subscription!,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+ result = new UsagePlanGetCommandResult(UsagePlans: usagePlans.ToList());
+ }
+
+ context.Response.Results = ResponseResult.Create(
+ result,
+ ResilienceManagementJsonContext.Default.UsagePlanGetCommandResult);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex,
+ "Error getting usage plan(s). ResourceGroup: {ResourceGroup}, Name: {Name}, Subscription: {Subscription}.",
+ options.ResourceGroup, options.Name, options.Subscription);
+ HandleException(context, ex);
+ }
+
+ return context.Response;
+ }
+
+ protected override string GetErrorMessage(Exception ex) => ex switch
+ {
+ ArgumentException argEx => argEx.Message,
+ KeyNotFoundException => "Usage plan not found. Verify the usage plan name, resource group, subscription, and that you have access.",
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.Forbidden =>
+ $"Authorization failed getting the usage plan. Details: {reqEx.Message}",
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.NotFound =>
+ "Usage plan not found. Verify the usage plan and resource group exist and you have access.",
+ RequestFailedException reqEx => reqEx.Message,
+ _ => base.GetErrorMessage(ex)
+ };
+
+ public record UsagePlanGetCommandResult(List? UsagePlans = null, UsagePlanInfo? UsagePlan = null);
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/GlobalUsings.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/GlobalUsings.cs
new file mode 100644
index 0000000000..b41cc886b4
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/GlobalUsings.cs
@@ -0,0 +1,4 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+global using System.CommandLine;
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/GoalAssignmentInfo.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/GoalAssignmentInfo.cs
new file mode 100644
index 0000000000..d7c169a93d
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/GoalAssignmentInfo.cs
@@ -0,0 +1,22 @@
+using System.Text.Json.Serialization;
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Models;
+
+public sealed record GoalAssignmentInfo(
+ [property: JsonPropertyName("id")] string Id,
+ [property: JsonPropertyName("name")] string Name,
+ [property: JsonPropertyName("properties")] GoalAssignmentInfoProperties? Properties = null,
+ [property: JsonPropertyName("systemData")] GoalAssignmentInfoSystemData? SystemData = null);
+
+public sealed record GoalAssignmentInfoProperties(
+ [property: JsonPropertyName("goalAssignmentType")] string GoalAssignmentType,
+ [property: JsonPropertyName("goalTemplateId")] string GoalTemplateId,
+ [property: JsonPropertyName("provisioningState")] string ProvisioningState);
+
+public sealed record GoalAssignmentInfoSystemData(
+ [property: JsonPropertyName("createdAt")] string CreatedAt,
+ [property: JsonPropertyName("createdBy")] string CreatedBy,
+ [property: JsonPropertyName("createdByType")] string CreatedByType,
+ [property: JsonPropertyName("lastModifiedAt")] string LastModifiedAt,
+ [property: JsonPropertyName("lastModifiedBy")] string LastModifiedBy,
+ [property: JsonPropertyName("lastModifiedByType")] string LastModifiedByType);
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/GoalAssignmentKind.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/GoalAssignmentKind.cs
new file mode 100644
index 0000000000..c62fcba981
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/GoalAssignmentKind.cs
@@ -0,0 +1,9 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Models;
+
+public enum GoalAssignmentKind
+{
+ Resiliency
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/GoalRequirement.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/GoalRequirement.cs
new file mode 100644
index 0000000000..7f12a731d6
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/GoalRequirement.cs
@@ -0,0 +1,10 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Models;
+
+public enum GoalRequirement
+{
+ Required,
+ NotRequired
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/GoalResourceInfo.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/GoalResourceInfo.cs
new file mode 100644
index 0000000000..31dd258d68
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/GoalResourceInfo.cs
@@ -0,0 +1,32 @@
+using System.Text.Json.Serialization;
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Models;
+
+public sealed record GoalResourceInfo(
+ [property: JsonPropertyName("id")] string Id,
+ [property: JsonPropertyName("name")] string Name,
+ [property: JsonPropertyName("properties")] GoalResourceInfoProperties? Properties = null,
+ [property: JsonPropertyName("systemData")] GoalResourceInfoSystemData? SystemData = null);
+
+public sealed record GoalResourceInfoProperties(
+ [property: JsonPropertyName("disasterRecoveryAttestationStatus")] string DisasterRecoveryAttestationStatus,
+ [property: JsonPropertyName("disasterRecoveryGoalParticipation")] string DisasterRecoveryGoalParticipation,
+ [property: JsonPropertyName("exclusionReasonForDisasterRecoveryGoals")] string ExclusionReasonForDisasterRecoveryGoals,
+ [property: JsonPropertyName("exclusionReasonForHighAvailabilityGoals")] string ExclusionReasonForHighAvailabilityGoals,
+ [property: JsonPropertyName("highAvailabilityAttestationStatus")] string HighAvailabilityAttestationStatus,
+ [property: JsonPropertyName("highAvailabilityGoalParticipation")] string HighAvailabilityGoalParticipation,
+ [property: JsonPropertyName("provisioningState")] string ProvisioningState,
+ [property: JsonPropertyName("resourceArmId")] string ResourceArmId,
+ [property: JsonPropertyName("serviceGroupMemberships")] IReadOnlyList? ServiceGroupMemberships = null);
+
+public sealed record GoalResourceServiceGroupMembership(
+ [property: JsonPropertyName("membershipType")] string MembershipType,
+ [property: JsonPropertyName("serviceGroupId")] string ServiceGroupId);
+
+public sealed record GoalResourceInfoSystemData(
+ [property: JsonPropertyName("createdAt")] string CreatedAt,
+ [property: JsonPropertyName("createdBy")] string CreatedBy,
+ [property: JsonPropertyName("createdByType")] string CreatedByType,
+ [property: JsonPropertyName("lastModifiedAt")] string LastModifiedAt,
+ [property: JsonPropertyName("lastModifiedBy")] string LastModifiedBy,
+ [property: JsonPropertyName("lastModifiedByType")] string LastModifiedByType);
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/GoalTemplateInfo.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/GoalTemplateInfo.cs
new file mode 100644
index 0000000000..f75e9a2236
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/GoalTemplateInfo.cs
@@ -0,0 +1,25 @@
+using System.Text.Json.Serialization;
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Models;
+
+public sealed record GoalTemplateInfo(
+ [property: JsonPropertyName("id")] string Id,
+ [property: JsonPropertyName("name")] string Name,
+ [property: JsonPropertyName("properties")] GoalTemplateInfoProperties? Properties = null,
+ [property: JsonPropertyName("systemData")] GoalTemplateInfoSystemData? SystemData = null);
+
+public sealed record GoalTemplateInfoProperties(
+ [property: JsonPropertyName("goalType")] string GoalType,
+ [property: JsonPropertyName("provisioningState")] string ProvisioningState,
+ [property: JsonPropertyName("regionalRecoveryPointObjective")] string RegionalRecoveryPointObjective,
+ [property: JsonPropertyName("regionalRecoveryTimeObjective")] string RegionalRecoveryTimeObjective,
+ [property: JsonPropertyName("requireDisasterRecovery")] string RequireDisasterRecovery,
+ [property: JsonPropertyName("requireHighAvailability")] string RequireHighAvailability);
+
+public sealed record GoalTemplateInfoSystemData(
+ [property: JsonPropertyName("createdAt")] string CreatedAt,
+ [property: JsonPropertyName("createdBy")] string CreatedBy,
+ [property: JsonPropertyName("createdByType")] string CreatedByType,
+ [property: JsonPropertyName("lastModifiedAt")] string LastModifiedAt,
+ [property: JsonPropertyName("lastModifiedBy")] string LastModifiedBy,
+ [property: JsonPropertyName("lastModifiedByType")] string LastModifiedByType);
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/GoalTemplateKind.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/GoalTemplateKind.cs
new file mode 100644
index 0000000000..25d6d10e9b
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/GoalTemplateKind.cs
@@ -0,0 +1,9 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Models;
+
+public enum GoalTemplateKind
+{
+ Resiliency
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/ResourceSummary.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/ResourceSummary.cs
new file mode 100644
index 0000000000..e49c999a8c
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/ResourceSummary.cs
@@ -0,0 +1,10 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Text.Json.Serialization;
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Models;
+
+public sealed record ResourceSummary(
+ [property: JsonPropertyName("id")] string Id,
+ [property: JsonPropertyName("name")] string Name);
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/UsagePlanEnrollmentInfo.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/UsagePlanEnrollmentInfo.cs
new file mode 100644
index 0000000000..c7ad8042c2
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/UsagePlanEnrollmentInfo.cs
@@ -0,0 +1,26 @@
+using System.Text.Json.Serialization;
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Models;
+
+public sealed record UsagePlanEnrollmentInfo(
+ [property: JsonPropertyName("id")] string Id,
+ [property: JsonPropertyName("name")] string Name,
+ [property: JsonPropertyName("properties")] UsagePlanEnrollmentInfoProperties? Properties = null,
+ [property: JsonPropertyName("systemData")] UsagePlanEnrollmentInfoSystemData? SystemData = null);
+
+public sealed record UsagePlanEnrollmentInfoProperties(
+ [property: JsonPropertyName("serviceGroupId")] string ServiceGroupId,
+ [property: JsonPropertyName("provisioningState")] string ProvisioningState,
+ [property: JsonPropertyName("errorDetails")] UsagePlanEnrollmentInfoErrorDetails? ErrorDetails = null);
+
+public sealed record UsagePlanEnrollmentInfoErrorDetails(
+ [property: JsonPropertyName("code")] string Code,
+ [property: JsonPropertyName("message")] string Message);
+
+public sealed record UsagePlanEnrollmentInfoSystemData(
+ [property: JsonPropertyName("createdAt")] string CreatedAt,
+ [property: JsonPropertyName("createdBy")] string CreatedBy,
+ [property: JsonPropertyName("createdByType")] string CreatedByType,
+ [property: JsonPropertyName("lastModifiedAt")] string LastModifiedAt,
+ [property: JsonPropertyName("lastModifiedBy")] string LastModifiedBy,
+ [property: JsonPropertyName("lastModifiedByType")] string LastModifiedByType);
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/UsagePlanInfo.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/UsagePlanInfo.cs
new file mode 100644
index 0000000000..58f6931da8
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/UsagePlanInfo.cs
@@ -0,0 +1,22 @@
+using System.Text.Json.Serialization;
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Models;
+
+public sealed record UsagePlanInfo(
+ [property: JsonPropertyName("id")] string Id,
+ [property: JsonPropertyName("name")] string Name,
+ [property: JsonPropertyName("resourceType")] string ResourceType,
+ [property: JsonPropertyName("location")] string Location,
+ [property: JsonPropertyName("tags")] IReadOnlyDictionary? Tags = null,
+ [property: JsonPropertyName("properties")] UsagePlanInfoProperties? Properties = null,
+ [property: JsonPropertyName("systemData")] UsagePlanInfoSystemData? SystemData = null);
+
+public sealed record UsagePlanInfoProperties(
+ [property: JsonPropertyName("planType")] string PlanType,
+ [property: JsonPropertyName("provisioningState")] string ProvisioningState);
+
+public sealed record UsagePlanInfoSystemData(
+ [property: JsonPropertyName("createdAt")] string CreatedAt,
+ [property: JsonPropertyName("createdBy")] string CreatedBy,
+ [property: JsonPropertyName("lastModifiedAt")] string LastModifiedAt,
+ [property: JsonPropertyName("lastModifiedBy")] string LastModifiedBy);
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/UsagePlanKind.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/UsagePlanKind.cs
new file mode 100644
index 0000000000..3e3edefab2
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Models/UsagePlanKind.cs
@@ -0,0 +1,10 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Models;
+
+public enum UsagePlanKind
+{
+ Basic,
+ Standard
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Drills/DrillGetOption.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Drills/DrillGetOption.cs
new file mode 100644
index 0000000000..6a0cf4e8dc
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Drills/DrillGetOption.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.ResilienceManagement.Options.Drills;
+
+public class DrillGetOptions : ISubscriptionOption
+{
+ [Option(Description = "The name of the service group.")]
+ public required string ServiceGroup { get; set; }
+
+ [Option(Description = "The name of the drill. Provide this argument to get the details of a particular drill; omit it to list all drills in the service group (id and name only).")]
+ public string? Name { get; set; }
+
+ [Option(Description = OptionDescriptions.Subscription)]
+ public string? Subscription { get; set; }
+
+ [Option(Description = OptionDescriptions.Tenant)]
+ public string? Tenant { get; set; }
+
+ [OptionContainer(Prefix = "retry")]
+ public RetryPolicyOptions? RetryPolicy { get; set; }
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Drills/Resources/DrillResourceGetOption.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Drills/Resources/DrillResourceGetOption.cs
new file mode 100644
index 0000000000..b6f7ac0e2f
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Drills/Resources/DrillResourceGetOption.cs
@@ -0,0 +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.ResilienceManagement.Options.Drills.Resources;
+
+public class DrillResourceGetOptions : ISubscriptionOption
+{
+ [Option(Description = "The name of the service group.")]
+ public required string ServiceGroup { get; set; }
+
+ [Option(Description = "The name of the drill.")]
+ public required string Drill { get; set; }
+
+ [Option(Description = "The name of the drill resource (target). Provide this argument to get the details of a particular drill resource; omit it to list all resources (targets) of the drill (id and name only).")]
+ public string? Name { get; set; }
+
+ [Option(Description = OptionDescriptions.Subscription)]
+ public string? Subscription { get; set; }
+
+ [Option(Description = OptionDescriptions.Tenant)]
+ public string? Tenant { get; set; }
+
+ [OptionContainer(Prefix = "retry")]
+ public RetryPolicyOptions? RetryPolicy { get; set; }
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Drills/Runs/DrillRunGetOption.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Drills/Runs/DrillRunGetOption.cs
new file mode 100644
index 0000000000..14928bce93
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Drills/Runs/DrillRunGetOption.cs
@@ -0,0 +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.ResilienceManagement.Options.Drills.Runs;
+
+public class DrillRunGetOptions : ISubscriptionOption
+{
+ [Option(Description = "The name of the service group.")]
+ public required string ServiceGroup { get; set; }
+
+ [Option(Description = "The name of the drill.")]
+ public required string Drill { get; set; }
+
+ [Option(Description = "The name of the drill run. Provide this argument to get the details of a particular drill run; omit it to list all runs of the drill (id and name only).")]
+ public string? Name { get; set; }
+
+ [Option(Description = OptionDescriptions.Subscription)]
+ public string? Subscription { get; set; }
+
+ [Option(Description = OptionDescriptions.Tenant)]
+ public string? Tenant { get; set; }
+
+ [OptionContainer(Prefix = "retry")]
+ public RetryPolicyOptions? RetryPolicy { get; set; }
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Drills/Runs/Resources/DrillRunResourceGetOption.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Drills/Runs/Resources/DrillRunResourceGetOption.cs
new file mode 100644
index 0000000000..7e8e12b2f9
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Drills/Runs/Resources/DrillRunResourceGetOption.cs
@@ -0,0 +1,31 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Azure.Mcp.Core.Options;
+using Microsoft.Mcp.Core.Options;
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Options.Drills.Runs.Resources;
+
+public class DrillRunResourceGetOptions : ISubscriptionOption
+{
+ [Option(Description = "The name of the service group.")]
+ public required string ServiceGroup { get; set; }
+
+ [Option(Description = "The name of the drill.")]
+ public required string Drill { get; set; }
+
+ [Option(Description = "The name of the drill run.")]
+ public required string DrillRun { get; set; }
+
+ [Option(Description = "The name of the drill run resource (target). Provide this argument to get the details of a particular drill run resource; omit it to list all resources (targets) of the drill run (id and name only).")]
+ public string? Name { get; set; }
+
+ [Option(Description = OptionDescriptions.Subscription)]
+ public string? Subscription { get; set; }
+
+ [Option(Description = OptionDescriptions.Tenant)]
+ public string? Tenant { get; set; }
+
+ [OptionContainer(Prefix = "retry")]
+ public RetryPolicyOptions? RetryPolicy { get; set; }
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Goals/Assignments/GoalAssignmentGetOption.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Goals/Assignments/GoalAssignmentGetOption.cs
new file mode 100644
index 0000000000..5a37fb0df3
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Goals/Assignments/GoalAssignmentGetOption.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.ResilienceManagement.Options.Goals.Assignments;
+
+public class GoalAssignmentGetOptions : ISubscriptionOption
+{
+ [Option(Description = "The name of the service group.")]
+ public required string ServiceGroup { get; set; }
+
+ [Option(Description = "The name of the goal assignment. Provide this argument to get the details of a particular goal assignment; omit it to list all goal assignments in the service group (id and name only).")]
+ public string? Name { get; set; }
+
+ [Option(Description = OptionDescriptions.Subscription)]
+ public string? Subscription { get; set; }
+
+ [Option(Description = OptionDescriptions.Tenant)]
+ public string? Tenant { get; set; }
+
+ [OptionContainer(Prefix = "retry")]
+ public RetryPolicyOptions? RetryPolicy { get; set; }
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Goals/Resources/GoalResourceGetOption.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Goals/Resources/GoalResourceGetOption.cs
new file mode 100644
index 0000000000..6a727113b9
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Goals/Resources/GoalResourceGetOption.cs
@@ -0,0 +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.ResilienceManagement.Options.Goals.Resources;
+
+public class GoalResourceGetOptions : ISubscriptionOption
+{
+ [Option(Description = "The name of the service group.")]
+ public required string ServiceGroup { get; set; }
+
+ [Option(Description = "The name of the goal assignment.")]
+ public required string GoalAssignment { get; set; }
+
+ [Option(Description = "The name of the goal resource. Provide this argument to get the details of a particular goal resource; omit it to list all resources (members) of the goal assignment (id and name only).")]
+ public string? Name { get; set; }
+
+ [Option(Description = OptionDescriptions.Subscription)]
+ public string? Subscription { get; set; }
+
+ [Option(Description = OptionDescriptions.Tenant)]
+ public string? Tenant { get; set; }
+
+ [OptionContainer(Prefix = "retry")]
+ public RetryPolicyOptions? RetryPolicy { get; set; }
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Goals/Templates/GoalTemplateGetOption.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Goals/Templates/GoalTemplateGetOption.cs
new file mode 100644
index 0000000000..f41961605f
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Goals/Templates/GoalTemplateGetOption.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.ResilienceManagement.Options.Goals.Templates;
+
+public class GoalTemplateGetOptions : ISubscriptionOption
+{
+ [Option(Description = "The name of the service group.")]
+ public required string ServiceGroup { get; set; }
+
+ [Option(Description = "The name of the goal template. Provide this argument to get the details of a particular goal template; omit it to list all goal templates in the service group (id and name only).")]
+ public string? Name { get; set; }
+
+ [Option(Description = OptionDescriptions.Subscription)]
+ public string? Subscription { get; set; }
+
+ [Option(Description = OptionDescriptions.Tenant)]
+ public string? Tenant { get; set; }
+
+ [OptionContainer(Prefix = "retry")]
+ public RetryPolicyOptions? RetryPolicy { get; set; }
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Recovery/Jobs/RecoveryJobGetOption.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Recovery/Jobs/RecoveryJobGetOption.cs
new file mode 100644
index 0000000000..2061e14f69
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Recovery/Jobs/RecoveryJobGetOption.cs
@@ -0,0 +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.ResilienceManagement.Options.Recovery.Jobs;
+
+public class RecoveryJobGetOptions : ISubscriptionOption
+{
+ [Option(Description = "The name of the service group.")]
+ public required string ServiceGroup { get; set; }
+
+ [Option(Description = "The name of the recovery plan.")]
+ public required string RecoveryPlan { get; set; }
+
+ [Option(Description = "The name of the recovery job. Provide this argument to get the details of a particular recovery job; omit it to list all recovery jobs of the recovery plan (id and name only).")]
+ public string? Name { get; set; }
+
+ [Option(Description = OptionDescriptions.Subscription)]
+ public string? Subscription { get; set; }
+
+ [Option(Description = OptionDescriptions.Tenant)]
+ public string? Tenant { get; set; }
+
+ [OptionContainer(Prefix = "retry")]
+ public RetryPolicyOptions? RetryPolicy { get; set; }
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Recovery/Jobs/Resources/RecoveryJobResourceGetOption.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Recovery/Jobs/Resources/RecoveryJobResourceGetOption.cs
new file mode 100644
index 0000000000..e92757a1b4
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Recovery/Jobs/Resources/RecoveryJobResourceGetOption.cs
@@ -0,0 +1,31 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Azure.Mcp.Core.Options;
+using Microsoft.Mcp.Core.Options;
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Options.Recovery.Jobs.Resources;
+
+public class RecoveryJobResourceGetOptions : ISubscriptionOption
+{
+ [Option(Description = "The name of the service group.")]
+ public required string ServiceGroup { get; set; }
+
+ [Option(Description = "The name of the recovery plan.")]
+ public required string RecoveryPlan { get; set; }
+
+ [Option(Description = "The name of the recovery job.")]
+ public required string RecoveryJob { get; set; }
+
+ [Option(Description = "The name of the recovery job resource (target). Provide this argument to get the details of a particular recovery job resource; omit it to list all resources (targets) of the recovery job (id and name only).")]
+ public string? Name { get; set; }
+
+ [Option(Description = OptionDescriptions.Subscription)]
+ public string? Subscription { get; set; }
+
+ [Option(Description = OptionDescriptions.Tenant)]
+ public string? Tenant { get; set; }
+
+ [OptionContainer(Prefix = "retry")]
+ public RetryPolicyOptions? RetryPolicy { get; set; }
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Recovery/Plans/RecoveryPlanGetOption.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Recovery/Plans/RecoveryPlanGetOption.cs
new file mode 100644
index 0000000000..c6929e9a60
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Recovery/Plans/RecoveryPlanGetOption.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.ResilienceManagement.Options.Recovery.Plans;
+
+public class RecoveryPlanGetOptions : ISubscriptionOption
+{
+ [Option(Description = "The name of the service group.")]
+ public required string ServiceGroup { get; set; }
+
+ [Option(Description = "The name of the recovery plan. Provide this argument to get the details of a particular recovery plan; omit it to list all recovery plans in the service group (id and name only).")]
+ public string? Name { get; set; }
+
+ [Option(Description = OptionDescriptions.Subscription)]
+ public string? Subscription { get; set; }
+
+ [Option(Description = OptionDescriptions.Tenant)]
+ public string? Tenant { get; set; }
+
+ [OptionContainer(Prefix = "retry")]
+ public RetryPolicyOptions? RetryPolicy { get; set; }
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Recovery/Plans/Resources/RecoveryResourceGetOption.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Recovery/Plans/Resources/RecoveryResourceGetOption.cs
new file mode 100644
index 0000000000..fceaae6199
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/Recovery/Plans/Resources/RecoveryResourceGetOption.cs
@@ -0,0 +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.ResilienceManagement.Options.Recovery.Plans.Resources;
+
+public class RecoveryResourceGetOptions : ISubscriptionOption
+{
+ [Option(Description = "The name of the service group.")]
+ public required string ServiceGroup { get; set; }
+
+ [Option(Description = "The name of the recovery plan.")]
+ public required string RecoveryPlan { get; set; }
+
+ [Option(Description = "The name of the recovery resource (member). Provide this argument to get the details of a particular recovery resource; omit it to list all resources (members) of the recovery plan (id and name only).")]
+ public string? Name { get; set; }
+
+ [Option(Description = OptionDescriptions.Subscription)]
+ public string? Subscription { get; set; }
+
+ [Option(Description = OptionDescriptions.Tenant)]
+ public string? Tenant { get; set; }
+
+ [OptionContainer(Prefix = "retry")]
+ public RetryPolicyOptions? RetryPolicy { get; set; }
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/ResilienceManagementOptionDefinitions.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/ResilienceManagementOptionDefinitions.cs
new file mode 100644
index 0000000000..a645f00cb6
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/ResilienceManagementOptionDefinitions.cs
@@ -0,0 +1,15 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Options;
+
+public static class ResilienceManagementOptionDefinitions
+{
+ public const string ServiceGroupName = "service-group";
+
+ public static readonly Option ServiceGroup = new($"--{ServiceGroupName}")
+ {
+ Description = "The name of the service group.",
+ Required = true
+ };
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/UsagePlans/Enrollments/UsagePlanEnrollmentGetOption.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/UsagePlans/Enrollments/UsagePlanEnrollmentGetOption.cs
new file mode 100644
index 0000000000..a5a2d3d39f
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/UsagePlans/Enrollments/UsagePlanEnrollmentGetOption.cs
@@ -0,0 +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.ResilienceManagement.Options.UsagePlans.Enrollments;
+
+public class UsagePlanEnrollmentGetOptions : ISubscriptionOption
+{
+ [Option(Description = OptionDescriptions.ResourceGroup)]
+ public required string ResourceGroup { get; set; }
+
+ [Option(Description = "The name of the usage plan.")]
+ public required string UsagePlan { get; set; }
+
+ [Option(Description = "The name of the usage plan enrollment. Provide this argument to get the details of a particular enrollment; omit it to list all enrollments of the usage plan (id and name only).")]
+ public string? Name { get; set; }
+
+ [Option(Description = OptionDescriptions.Subscription)]
+ public string? Subscription { get; set; }
+
+ [Option(Description = OptionDescriptions.Tenant)]
+ public string? Tenant { get; set; }
+
+ [OptionContainer(Prefix = "retry")]
+ public RetryPolicyOptions? RetryPolicy { get; set; }
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/UsagePlans/UsagePlanGetOption.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/UsagePlans/UsagePlanGetOption.cs
new file mode 100644
index 0000000000..2854a3735a
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Options/UsagePlans/UsagePlanGetOption.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.ResilienceManagement.Options.UsagePlans;
+
+public class UsagePlanGetOptions : ISubscriptionOption
+{
+ [Option(Description = "The name of the resource group. If omitted (and no usage plan name is given), all usage plans in the subscription are listed (id and name only).")]
+ public string? ResourceGroup { get; set; }
+
+ [Option(Description = "The name of the usage plan. Provide this argument to get the details of a particular usage plan (requires a resource group); omit it to list usage plans (id and name only) for the resource group, or for the whole subscription when no resource group is given.")]
+ public string? Name { get; set; }
+
+ [Option(Description = OptionDescriptions.Subscription)]
+ public string? Subscription { get; set; }
+
+ [Option(Description = OptionDescriptions.Tenant)]
+ public string? Tenant { get; set; }
+
+ [OptionContainer(Prefix = "retry")]
+ public RetryPolicyOptions? RetryPolicy { get; set; }
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/ResilienceManagementSetup.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/ResilienceManagementSetup.cs
new file mode 100644
index 0000000000..0364ca8cbf
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/ResilienceManagementSetup.cs
@@ -0,0 +1,146 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Azure.Mcp.Tools.ResilienceManagement.Commands.Drills;
+using Azure.Mcp.Tools.ResilienceManagement.Commands.Drills.Resources;
+using Azure.Mcp.Tools.ResilienceManagement.Commands.Drills.Runs;
+using Azure.Mcp.Tools.ResilienceManagement.Commands.Drills.Runs.Resources;
+using Azure.Mcp.Tools.ResilienceManagement.Commands.Goals.Assignments;
+using Azure.Mcp.Tools.ResilienceManagement.Commands.Goals.Resources;
+using Azure.Mcp.Tools.ResilienceManagement.Commands.Goals.Templates;
+using Azure.Mcp.Tools.ResilienceManagement.Commands.Recovery.Jobs;
+using Azure.Mcp.Tools.ResilienceManagement.Commands.Recovery.Jobs.Resources;
+using Azure.Mcp.Tools.ResilienceManagement.Commands.Recovery.Plans;
+using Azure.Mcp.Tools.ResilienceManagement.Commands.Recovery.Plans.Resources;
+using Azure.Mcp.Tools.ResilienceManagement.Commands.UsagePlans;
+using Azure.Mcp.Tools.ResilienceManagement.Commands.UsagePlans.Enrollments;
+using Azure.Mcp.Tools.ResilienceManagement.Services;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Mcp.Core.Areas;
+using Microsoft.Mcp.Core.Commands;
+
+namespace Azure.Mcp.Tools.ResilienceManagement;
+
+public class ResilienceManagementSetup : IAreaSetup
+{
+ public string Name => "resilience";
+
+ public string Title => "Azure Resilience Management";
+
+ public void ConfigureServices(IServiceCollection services)
+ {
+ services.AddSingleton();
+
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ }
+
+ public CommandGroup RegisterCommands(IServiceProvider serviceProvider)
+ {
+ var resilienceManagement = new CommandGroup(Name,
+ """
+ Azure Resilience Management operations - Commands for working with resilience goals and goal
+ templates for Azure service groups. Use this tool to list the resilience goal templates available
+ for a service group, including goal type, provisioning state, recovery point and time objectives,
+ and high availability and disaster recovery requirements.
+ """,
+ Title);
+
+ // Create goal subgroup
+ var goals = new CommandGroup("goal", "Resilience goal operations - Commands for working with resilience goals and goal templates for Azure service groups.");
+ resilienceManagement.AddSubGroup(goals);
+
+ // Create template subgroup under goal
+ var templates = new CommandGroup("template", "Resilience goal template operations - Commands for listing resilience goal templates for Azure service groups.");
+ goals.AddSubGroup(templates);
+
+ // Create assignment subgroup under goal
+ var assignments = new CommandGroup("assignment", "Resilience goal assignment operations - Commands for listing resilience goal assignments for Azure service groups.");
+ goals.AddSubGroup(assignments);
+
+ // Create resource subgroup under goal
+ var goalResources = new CommandGroup("resource", "Resilience goal resource operations - Commands for listing the resources (members) of a resilience goal assignment.");
+ goals.AddSubGroup(goalResources);
+
+ // Register commands
+ templates.AddCommand(serviceProvider);
+ assignments.AddCommand(serviceProvider);
+ goalResources.AddCommand(serviceProvider);
+
+ // Create usageplan subgroup
+ var usagePlans = new CommandGroup("usageplan", "Resilience usage plan operations - Commands for listing resilience usage plans in an Azure resource group.");
+ resilienceManagement.AddSubGroup(usagePlans);
+
+ usagePlans.AddCommand(serviceProvider);
+
+ // Create enrollment subgroup under usageplan
+ var enrollments = new CommandGroup("enrollment", "Resilience usage plan enrollment operations - Commands for listing enrollments of a resilience usage plan.");
+ usagePlans.AddSubGroup(enrollments);
+
+ enrollments.AddCommand(serviceProvider);
+
+ // Create drill subgroup
+ var drills = new CommandGroup("drill", "Resilience drill operations - Commands for listing and getting resilience drills for an Azure service group.");
+ resilienceManagement.AddSubGroup(drills);
+
+ drills.AddCommand(serviceProvider);
+
+ // Create resource subgroup under drill
+ var drillResources = new CommandGroup("resource", "Resilience drill resource operations - Commands for listing and getting the resources (targets) of a resilience drill.");
+ drills.AddSubGroup(drillResources);
+
+ drillResources.AddCommand(serviceProvider);
+
+ // Create run subgroup under drill
+ var drillRuns = new CommandGroup("run", "Resilience drill run operations - Commands for listing and getting the runs of a resilience drill.");
+ drills.AddSubGroup(drillRuns);
+
+ drillRuns.AddCommand(serviceProvider);
+
+ // Create resource subgroup under drill run
+ var drillRunResources = new CommandGroup("resource", "Resilience drill run resource operations - Commands for listing and getting the resources (targets) of a resilience drill run.");
+ drillRuns.AddSubGroup(drillRunResources);
+
+ drillRunResources.AddCommand(serviceProvider);
+
+ // Create recovery subgroup with a plan subgroup
+ var recovery = new CommandGroup("recovery", "Resilience recovery operations - Commands for working with resilience recovery plans for an Azure service group.");
+ resilienceManagement.AddSubGroup(recovery);
+
+ var recoveryPlans = new CommandGroup("plan", "Resilience recovery plan operations - Commands for listing and getting resilience recovery plans for an Azure service group.");
+ recovery.AddSubGroup(recoveryPlans);
+
+ recoveryPlans.AddCommand(serviceProvider);
+
+ // Create resource subgroup under recovery plan
+ var recoveryResources = new CommandGroup("resource", "Resilience recovery resource operations - Commands for listing and getting the resources (members) of a resilience recovery plan.");
+ recoveryPlans.AddSubGroup(recoveryResources);
+
+ recoveryResources.AddCommand(serviceProvider);
+
+ // Create job subgroup under recovery
+ var recoveryJobs = new CommandGroup("job", "Resilience recovery job operations - Commands for listing and getting the recovery jobs of a resilience recovery plan.");
+ recovery.AddSubGroup(recoveryJobs);
+
+ recoveryJobs.AddCommand(serviceProvider);
+
+ // Create resource subgroup under recovery job
+ var recoveryJobResources = new CommandGroup("resource", "Resilience recovery job resource operations - Commands for listing and getting the resources (targets) of a resilience recovery job.");
+ recoveryJobs.AddSubGroup(recoveryJobResources);
+
+ recoveryJobResources.AddCommand(serviceProvider);
+
+ return resilienceManagement;
+ }
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Services/IReseilienceManagementService.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Services/IReseilienceManagementService.cs
new file mode 100644
index 0000000000..21f6627f04
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Services/IReseilienceManagementService.cs
@@ -0,0 +1,66 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Text.Json;
+using Azure.Mcp.Core.Services.Azure;
+using Azure.Mcp.Tools.ResilienceManagement.Models;
+using Microsoft.Mcp.Core.Options;
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Services;
+
+public interface IResilienceManagementService
+{
+ Task> ListGoalTemplatesAsync(string serviceGroup, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default);
+
+ Task GetGoalTemplateAsync(string serviceGroup, string goalTemplate, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default);
+
+ Task> ListGoalAssignmentsAsync(string serviceGroup, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default);
+
+ Task GetGoalAssignmentAsync(string serviceGroup, string goalAssignment, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default);
+
+ Task> ListUsagePlansAsync(string resourceGroup, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default);
+
+ Task GetUsagePlanAsync(string resourceGroup, string usagePlan, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default);
+
+ Task> ListUsagePlansBySubscriptionAsync(string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default);
+
+ Task> ListUsagePlanEnrollmentsAsync(string resourceGroup, string usagePlan, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default);
+
+ Task GetUsagePlanEnrollmentAsync(string resourceGroup, string usagePlan, string enrollment, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default);
+
+ Task> ListGoalResourcesAsync(string serviceGroup, string goalAssignment, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default);
+
+ Task GetGoalResourceAsync(string serviceGroup, string goalAssignment, string goalResource, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default);
+
+ Task> ListDrillsAsync(string serviceGroup, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default);
+
+ Task GetDrillAsync(string serviceGroup, string drill, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default);
+
+ Task> ListDrillRunsAsync(string serviceGroup, string drill, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default);
+
+ Task GetDrillRunAsync(string serviceGroup, string drill, string drillRun, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default);
+
+ Task> ListDrillRunResourcesAsync(string serviceGroup, string drill, string drillRun, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default);
+
+ Task GetDrillRunResourceAsync(string serviceGroup, string drill, string drillRun, string drillRunTarget, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default);
+
+ Task> ListDrillResourcesAsync(string serviceGroup, string drill, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default);
+
+ Task GetDrillResourceAsync(string serviceGroup, string drill, string drillTarget, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default);
+
+ Task> ListRecoveryPlansAsync(string serviceGroup, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default);
+
+ Task GetRecoveryPlanAsync(string serviceGroup, string recoveryPlan, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default);
+
+ Task> ListRecoveryResourcesAsync(string serviceGroup, string recoveryPlan, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default);
+
+ Task GetRecoveryResourceAsync(string serviceGroup, string recoveryPlan, string recoveryResource, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default);
+
+ Task> ListRecoveryJobsAsync(string serviceGroup, string recoveryPlan, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default);
+
+ Task GetRecoveryJobAsync(string serviceGroup, string recoveryPlan, string recoveryJob, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default);
+
+ Task> ListRecoveryJobResourcesAsync(string serviceGroup, string recoveryPlan, string recoveryJob, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default);
+
+ Task GetRecoveryJobResourceAsync(string serviceGroup, string recoveryPlan, string recoveryJob, string recoveryJobTarget, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default);
+}
diff --git a/tools/Azure.Mcp.Tools.ResilienceManagement/src/Services/ResilienceManagementService.cs b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Services/ResilienceManagementService.cs
new file mode 100644
index 0000000000..49b350eef3
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.ResilienceManagement/src/Services/ResilienceManagementService.cs
@@ -0,0 +1,634 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Text.Json;
+using Azure;
+using Azure.Core;
+using Azure.Core.Pipeline;
+using Azure.Mcp.Core.Services.Azure;
+using Azure.Mcp.Core.Services.Azure.Subscription;
+using Azure.Mcp.Core.Services.Azure.Tenant;
+using Azure.Mcp.Tools.ResilienceManagement.Models;
+using Azure.ResourceManager;
+using Azure.ResourceManager.ResilienceManagement;
+using Azure.ResourceManager.ResilienceManagement.Models;
+using Microsoft.Extensions.Logging;
+using Microsoft.Mcp.Core.Options;
+using Microsoft.Mcp.Core.Services.Azure.Authentication;
+
+namespace Azure.Mcp.Tools.ResilienceManagement.Services;
+
+public sealed class ResilienceManagementService(
+ ISubscriptionService subscriptionService,
+ ITenantService tenantService,
+ ILogger logger)
+ : BaseAzureResourceService(subscriptionService, tenantService), IResilienceManagementService
+{
+
+ private readonly ISubscriptionService _subscriptionService = subscriptionService;
+ private readonly ITenantService _tenantService = tenantService ?? throw new ArgumentNullException(nameof(tenantService));
+ private readonly ILogger _logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ public async Task> ListGoalTemplatesAsync(string serviceGroup, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default)
+ {
+ var subscriptionId = _subscriptionService.IsSubscriptionId(subscription)
+ ? subscription
+ : (await _subscriptionService.GetSubscription(subscription, tenant, retryPolicy, cancellationToken)).Data.SubscriptionId;
+
+ ArmClient armClient = await CreateArmClientAsync(tenantIdOrName: tenant, cancellationToken: cancellationToken);
+
+ var serviceGroupId = new ResourceIdentifier($"/providers/Microsoft.Management/serviceGroups/{serviceGroup}");
+ GoalTemplateCollection goalTemplates = armClient.GetGoalTemplates(serviceGroupId);
+
+ var result = new List();
+ await foreach (var goalTemplate in goalTemplates.GetAllAsync(cancellationToken: cancellationToken))
+ {
+ result.Add(new ResourceSummary(
+ Id: goalTemplate.Data.Id?.ToString() ?? string.Empty,
+ Name: goalTemplate.Data.Name ?? string.Empty));
+ }
+
+ return result;
+ }
+
+ public async Task GetGoalTemplateAsync(string serviceGroup, string goalTemplate, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default)
+ {
+ var subscriptionId = _subscriptionService.IsSubscriptionId(subscription)
+ ? subscription
+ : (await _subscriptionService.GetSubscription(subscription, tenant, retryPolicy, cancellationToken)).Data.SubscriptionId;
+
+ ArmClient armClient = await CreateArmClientAsync(tenantIdOrName: tenant, cancellationToken: cancellationToken);
+
+ var serviceGroupId = new ResourceIdentifier($"/providers/Microsoft.Management/serviceGroups/{serviceGroup}");
+ GoalTemplateCollection goalTemplates = armClient.GetGoalTemplates(serviceGroupId);
+ GoalTemplateResource resource = await goalTemplates.GetAsync(goalTemplate, cancellationToken);
+
+ return MapGoalTemplate(resource.Data);
+ }
+
+ private static GoalTemplateInfo MapGoalTemplate(GoalTemplateData data)
+ {
+ var props = data.Properties;
+ var systemData = data.SystemData;
+
+ var mappedProperties = props is null
+ ? null
+ : new GoalTemplateInfoProperties(
+ GoalType: props.GoalType.ToString(),
+ ProvisioningState: props.ProvisioningState?.ToString() ?? string.Empty,
+ RegionalRecoveryPointObjective: props.RegionalRecoveryPointObjective ?? string.Empty,
+ RegionalRecoveryTimeObjective: props.RegionalRecoveryTimeObjective ?? string.Empty,
+ RequireDisasterRecovery: props.RequireDisasterRecovery?.ToString() ?? string.Empty,
+ RequireHighAvailability: props.RequireHighAvailability?.ToString() ?? string.Empty);
+
+ var mappedSystemData = systemData is null
+ ? null
+ : new GoalTemplateInfoSystemData(
+ CreatedAt: systemData.CreatedOn?.ToString("o") ?? string.Empty,
+ CreatedBy: systemData.CreatedBy ?? string.Empty,
+ CreatedByType: systemData.CreatedByType?.ToString() ?? string.Empty,
+ LastModifiedAt: systemData.LastModifiedOn?.ToString("o") ?? string.Empty,
+ LastModifiedBy: systemData.LastModifiedBy ?? string.Empty,
+ LastModifiedByType: systemData.LastModifiedByType?.ToString() ?? string.Empty);
+
+ return new GoalTemplateInfo(
+ Id: data.Id?.ToString() ?? string.Empty,
+ Name: data.Name ?? string.Empty,
+ Properties: mappedProperties,
+ SystemData: mappedSystemData);
+ }
+
+ public async Task> ListGoalAssignmentsAsync(string serviceGroup, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default)
+ {
+ var subscriptionId = _subscriptionService.IsSubscriptionId(subscription)
+ ? subscription
+ : (await _subscriptionService.GetSubscription(subscription, tenant, retryPolicy, cancellationToken)).Data.SubscriptionId;
+
+ ArmClient armClient = await CreateArmClientAsync(tenantIdOrName: tenant, cancellationToken: cancellationToken);
+
+ var serviceGroupId = new ResourceIdentifier($"/providers/Microsoft.Management/serviceGroups/{serviceGroup}");
+ GoalAssignmentCollection goalAssignments = armClient.GetGoalAssignments(serviceGroupId);
+
+ var result = new List();
+ await foreach (var goalAssignment in goalAssignments.GetAllAsync(cancellationToken: cancellationToken))
+ {
+ result.Add(new ResourceSummary(
+ Id: goalAssignment.Data.Id?.ToString() ?? string.Empty,
+ Name: goalAssignment.Data.Name ?? string.Empty));
+ }
+
+ return result;
+ }
+
+ public async Task GetGoalAssignmentAsync(string serviceGroup, string goalAssignment, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default)
+ {
+ var subscriptionId = _subscriptionService.IsSubscriptionId(subscription)
+ ? subscription
+ : (await _subscriptionService.GetSubscription(subscription, tenant, retryPolicy, cancellationToken)).Data.SubscriptionId;
+
+ ArmClient armClient = await CreateArmClientAsync(tenantIdOrName: tenant, cancellationToken: cancellationToken);
+
+ var serviceGroupId = new ResourceIdentifier($"/providers/Microsoft.Management/serviceGroups/{serviceGroup}");
+ GoalAssignmentCollection goalAssignments = armClient.GetGoalAssignments(serviceGroupId);
+ GoalAssignmentResource resource = await goalAssignments.GetAsync(goalAssignment, cancellationToken);
+
+ return MapGoalAssignment(resource.Data);
+ }
+
+ private static GoalAssignmentInfo MapGoalAssignment(GoalAssignmentData data)
+ {
+ var props = data.Properties;
+ var systemData = data.SystemData;
+
+ var mappedProperties = props is null
+ ? null
+ : new GoalAssignmentInfoProperties(
+ GoalAssignmentType: props.GoalAssignmentType.ToString(),
+ GoalTemplateId: props.GoalTemplateId?.ToString() ?? string.Empty,
+ ProvisioningState: props.ProvisioningState?.ToString() ?? string.Empty);
+
+ var mappedSystemData = systemData is null
+ ? null
+ : new GoalAssignmentInfoSystemData(
+ CreatedAt: systemData.CreatedOn?.ToString("o") ?? string.Empty,
+ CreatedBy: systemData.CreatedBy ?? string.Empty,
+ CreatedByType: systemData.CreatedByType?.ToString() ?? string.Empty,
+ LastModifiedAt: systemData.LastModifiedOn?.ToString("o") ?? string.Empty,
+ LastModifiedBy: systemData.LastModifiedBy ?? string.Empty,
+ LastModifiedByType: systemData.LastModifiedByType?.ToString() ?? string.Empty);
+
+ return new GoalAssignmentInfo(
+ Id: data.Id?.ToString() ?? string.Empty,
+ Name: data.Name ?? string.Empty,
+ Properties: mappedProperties,
+ SystemData: mappedSystemData);
+ }
+
+ public async Task> ListUsagePlansAsync(string resourceGroup, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default)
+ {
+ var subscriptionId = _subscriptionService.IsSubscriptionId(subscription)
+ ? subscription
+ : (await _subscriptionService.GetSubscription(subscription, tenant, retryPolicy, cancellationToken)).Data.SubscriptionId;
+
+ ArmClient armClient = await CreateArmClientAsync(tenantIdOrName: tenant, cancellationToken: cancellationToken);
+
+ var resourceGroupId = new ResourceIdentifier($"/subscriptions/{subscriptionId}/resourceGroups/{resourceGroup}");
+ var resourceGroupResource = armClient.GetResourceGroupResource(resourceGroupId);
+ UsagePlanCollection usagePlans = resourceGroupResource.GetUsagePlans();
+
+ var result = new List();
+ await foreach (var usagePlan in usagePlans.GetAllAsync(cancellationToken: cancellationToken))
+ {
+ result.Add(new ResourceSummary(
+ Id: usagePlan.Data.Id?.ToString() ?? string.Empty,
+ Name: usagePlan.Data.Name ?? string.Empty));
+ }
+
+ return result;
+ }
+
+ public async Task> ListUsagePlansBySubscriptionAsync(string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default)
+ {
+ var subscriptionId = _subscriptionService.IsSubscriptionId(subscription)
+ ? subscription
+ : (await _subscriptionService.GetSubscription(subscription, tenant, retryPolicy, cancellationToken)).Data.SubscriptionId;
+
+ ArmClient armClient = await CreateArmClientAsync(tenantIdOrName: tenant, cancellationToken: cancellationToken);
+
+ var subscriptionId2 = new ResourceIdentifier($"/subscriptions/{subscriptionId}");
+ var subscriptionResource = armClient.GetSubscriptionResource(subscriptionId2);
+
+ var result = new List();
+ await foreach (var usagePlan in subscriptionResource.GetUsagePlansAsync(cancellationToken: cancellationToken))
+ {
+ result.Add(new ResourceSummary(
+ Id: usagePlan.Data.Id?.ToString() ?? string.Empty,
+ Name: usagePlan.Data.Name ?? string.Empty));
+ }
+
+ return result;
+ }
+
+ private static UsagePlanInfo MapUsagePlan(UsagePlanData data)
+ {
+ var props = data.Properties;
+ var systemData = data.SystemData;
+
+ var mappedProperties = props is null
+ ? null
+ : new UsagePlanInfoProperties(
+ PlanType: props.PlanType.ToString() ?? string.Empty,
+ ProvisioningState: props.ProvisioningState?.ToString() ?? string.Empty);
+
+ var mappedSystemData = systemData is null
+ ? null
+ : new UsagePlanInfoSystemData(
+ CreatedAt: systemData.CreatedOn?.ToString("o") ?? string.Empty,
+ CreatedBy: systemData.CreatedBy ?? string.Empty,
+ LastModifiedAt: systemData.LastModifiedOn?.ToString("o") ?? string.Empty,
+ LastModifiedBy: systemData.LastModifiedBy ?? string.Empty);
+
+ return new UsagePlanInfo(
+ Id: data.Id?.ToString() ?? string.Empty,
+ Name: data.Name ?? string.Empty,
+ ResourceType: data.ResourceType.ToString(),
+ Location: data.Location.Name ?? string.Empty,
+ Tags: data.Tags is null ? null : new Dictionary(data.Tags),
+ Properties: mappedProperties,
+ SystemData: mappedSystemData);
+ }
+
+ public async Task GetUsagePlanAsync(string resourceGroup, string usagePlan, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default)
+ {
+ var subscriptionId = _subscriptionService.IsSubscriptionId(subscription)
+ ? subscription
+ : (await _subscriptionService.GetSubscription(subscription, tenant, retryPolicy, cancellationToken)).Data.SubscriptionId;
+
+ ArmClient armClient = await CreateArmClientAsync(tenantIdOrName: tenant, cancellationToken: cancellationToken);
+
+ var resourceGroupId = new ResourceIdentifier($"/subscriptions/{subscriptionId}/resourceGroups/{resourceGroup}");
+ var resourceGroupResource = armClient.GetResourceGroupResource(resourceGroupId);
+ UsagePlanCollection usagePlans = resourceGroupResource.GetUsagePlans();
+ UsagePlanResource resource = await usagePlans.GetAsync(usagePlan, cancellationToken);
+
+ return MapUsagePlan(resource.Data);
+ }
+
+ public async Task> ListUsagePlanEnrollmentsAsync(string resourceGroup, string usagePlan, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default)
+ {
+ var subscriptionId = _subscriptionService.IsSubscriptionId(subscription)
+ ? subscription
+ : (await _subscriptionService.GetSubscription(subscription, tenant, retryPolicy, cancellationToken)).Data.SubscriptionId;
+
+ ArmClient armClient = await CreateArmClientAsync(tenantIdOrName: tenant, cancellationToken: cancellationToken);
+
+ var usagePlanId = new ResourceIdentifier($"/subscriptions/{subscriptionId}/resourceGroups/{resourceGroup}/providers/Microsoft.AzureResilienceManagement/usagePlans/{usagePlan}");
+ var usagePlanResource = armClient.GetUsagePlanResource(usagePlanId);
+ UsagePlanEnrollmentCollection enrollments = usagePlanResource.GetUsagePlanEnrollments();
+
+ var result = new List();
+ await foreach (var enrollment in enrollments.GetAllAsync(cancellationToken: cancellationToken))
+ {
+ result.Add(new ResourceSummary(
+ Id: enrollment.Data.Id?.ToString() ?? string.Empty,
+ Name: enrollment.Data.Name ?? string.Empty));
+ }
+
+ return result;
+ }
+
+ public async Task GetUsagePlanEnrollmentAsync(string resourceGroup, string usagePlan, string enrollment, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default)
+ {
+ var subscriptionId = _subscriptionService.IsSubscriptionId(subscription)
+ ? subscription
+ : (await _subscriptionService.GetSubscription(subscription, tenant, retryPolicy, cancellationToken)).Data.SubscriptionId;
+
+ ArmClient armClient = await CreateArmClientAsync(tenantIdOrName: tenant, cancellationToken: cancellationToken);
+
+ var usagePlanId = new ResourceIdentifier($"/subscriptions/{subscriptionId}/resourceGroups/{resourceGroup}/providers/Microsoft.AzureResilienceManagement/usagePlans/{usagePlan}");
+ var usagePlanResource = armClient.GetUsagePlanResource(usagePlanId);
+ UsagePlanEnrollmentCollection enrollments = usagePlanResource.GetUsagePlanEnrollments();
+ UsagePlanEnrollmentResource resource = await enrollments.GetAsync(enrollment, cancellationToken);
+
+ return MapUsagePlanEnrollment(resource.Data);
+ }
+
+ private static UsagePlanEnrollmentInfo MapUsagePlanEnrollment(UsagePlanEnrollmentData data)
+ {
+ var props = data.Properties;
+ var systemData = data.SystemData;
+
+ var mappedProperties = props is null
+ ? null
+ : new UsagePlanEnrollmentInfoProperties(
+ ServiceGroupId: props.ServiceGroupId?.ToString() ?? string.Empty,
+ ProvisioningState: props.ProvisioningState?.ToString() ?? string.Empty,
+ ErrorDetails: props.ErrorDetails is null
+ ? null
+ : new UsagePlanEnrollmentInfoErrorDetails(
+ Code: props.ErrorDetails.Code ?? string.Empty,
+ Message: props.ErrorDetails.Message ?? string.Empty));
+
+ var mappedSystemData = systemData is null
+ ? null
+ : new UsagePlanEnrollmentInfoSystemData(
+ CreatedAt: systemData.CreatedOn?.ToString("o") ?? string.Empty,
+ CreatedBy: systemData.CreatedBy ?? string.Empty,
+ CreatedByType: systemData.CreatedByType?.ToString() ?? string.Empty,
+ LastModifiedAt: systemData.LastModifiedOn?.ToString("o") ?? string.Empty,
+ LastModifiedBy: systemData.LastModifiedBy ?? string.Empty,
+ LastModifiedByType: systemData.LastModifiedByType?.ToString() ?? string.Empty);
+
+ return new UsagePlanEnrollmentInfo(
+ Id: data.Id?.ToString() ?? string.Empty,
+ Name: data.Name ?? string.Empty,
+ Properties: mappedProperties,
+ SystemData: mappedSystemData);
+ }
+
+ public async Task> ListGoalResourcesAsync(string serviceGroup, string goalAssignment, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, CancellationToken cancellationToken = default)
+ {
+ ArmClient armClient = await CreateArmClientAsync(tenantIdOrName: tenant, cancellationToken: cancellationToken);
+
+ var goalAssignmentId = GoalAssignmentResource.CreateResourceIdentifier(serviceGroup, goalAssignment);
+ GoalMembersCollection goalMembers = armClient.GetGoalAssignmentResource(goalAssignmentId).GetAllGoalMembers();
+
+ var result = new List();
+ await foreach (var goalMember in goalMembers.GetAllAsync(cancellationToken: cancellationToken))
+ {
+ result.Add(new ResourceSummary(
+ Id: goalMember.Data.Id?.ToString() ?? string.Empty,
+ Name: goalMember.Data.Name ?? string.Empty));
+ }
+
+ return result;
+ }
+
+ public async Task