Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions servers/Azure.Mcp.Server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1194,6 +1194,10 @@ Example prompts that generate Azure CLI commands:
* "List all resilience recovery plans in service group 'my-service-group'"
* "Get the recovery plan 'my-recovery-plan' in service group 'my-service-group'"
* "List the recovery jobs of recovery plan 'my-recovery-plan' in service group 'my-service-group'"
* "Create a resilience goal template 'my-template' in service group 'my-service-group' with a 15-minute recovery point objective and 30-minute recovery time objective"
* "Create a resilience usage plan 'my-plan' in resource group 'my-rg'"
* "Enroll service group 'my-service-group' into usage plan 'my-plan' in resource group 'my-rg'"
* "Assign goal template 'my-template' to service group 'my-service-group' as a resiliency goal"

### Azure Resource Manager

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
changes:
- section: "Features Added"
description: "Added the 'azmcp resilience goal template create' command to create or update a resilience goal template in a service group, including its goal type, high availability and disaster recovery requirements, and regional recovery point and time objectives."
- section: "Features Added"
description: "Added the 'azmcp resilience usageplan create' command to create a resilience usage plan in a resource group, including its plan type."
- section: "Features Added"
description: "Added the 'azmcp resilience usageplan enrollment create' command to create or update an enrollment under a resilience usage plan, associating it with a service group."
- section: "Features Added"
description: "Added the 'azmcp resilience goal assignment create' command to create or update a resilience goal assignment in a service group that assigns a goal template."
35 changes: 35 additions & 0 deletions servers/Azure.Mcp.Server/docs/azmcp-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -3629,12 +3629,32 @@ azmcp resilience goal template get --subscription <subscription> \
--service-group <service-group> \
[--name <name>]

# Create or update a resilience goal template in a service group
# ❌ Destructive | ✅ Idempotent | ❌ OpenWorld | ❌ ReadOnly | ❌ Secret | ❌ LocalRequired
azmcp resilience goal template create --subscription <subscription> \
--service-group <service-group> \
--goal-template <goal-template> \
--goal-type <goal-type> \
--require-high-availability <require-high-availability> \
--require-disaster-recovery <require-disaster-recovery> \
--regional-recovery-point-objective <regional-recovery-point-objective> \
--regional-recovery-time-objective <regional-recovery-time-objective>

# 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 <subscription> \
--service-group <service-group> \
[--name <name>]

# Create or update a resilience goal assignment in a service group that assigns a goal template
# ❌ Destructive | ✅ Idempotent | ❌ OpenWorld | ❌ ReadOnly | ❌ Secret | ❌ LocalRequired
azmcp resilience goal assignment create --subscription <subscription> \
--service-group <service-group> \
--goal-assignment <goal-assignment> \
--goal-template <goal-template> \
--goal-template-service-group <goal-template-service-group> \
--goal-assignment-type <goal-assignment-type>

# 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 <subscription> \
Expand All @@ -3648,13 +3668,28 @@ azmcp resilience usageplan get --subscription <subscription> \
[--resource-group <resource-group>] \
[--name <name>]

# Create a resilience usage plan in a resource group
# ❌ Destructive | ✅ Idempotent | ❌ OpenWorld | ❌ ReadOnly | ❌ Secret | ❌ LocalRequired
azmcp resilience usageplan create --subscription <subscription> \
--resource-group <resource-group> \
--usage-plan <usage-plan> \
--plan-type <plan-type>

# 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 <subscription> \
--resource-group <resource-group> \
--usage-plan <usage-plan> \
[--name <name>]

# Create or update an enrollment under a resilience usage plan, associating it with a service group
# ❌ Destructive | ✅ Idempotent | ❌ OpenWorld | ❌ ReadOnly | ❌ Secret | ❌ LocalRequired
azmcp resilience usageplan enrollment create --subscription <subscription> \
--resource-group <resource-group> \
--usage-plan <usage-plan> \
--enrollment <enrollment> \
--service-group <service-group>

# 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 <subscription> \
Expand Down
4 changes: 4 additions & 0 deletions servers/Azure.Mcp.Server/docs/e2eTestPrompts.md
Original file line number Diff line number Diff line change
Expand Up @@ -858,10 +858,12 @@ This file contains prompts used for end-to-end testing to ensure each tool is in

| Tool Name | Test Prompt |
|:----------|:----------|
| resilience_goal_assignment_create | Create a resilience goal assignment <goal_assignment_name> in service group <service_group> that assigns goal template <goal_template_name> from service group <goal_template_service_group> with assignment type Resiliency |
| resilience_goal_assignment_get | List all resilience goal assignments in service group <service_group> |
| resilience_goal_assignment_get | Get the details of goal assignment <goal_assignment_name> in service group <service_group> |
| resilience_goal_resource_get | List all resources (members) of goal assignment <goal_assignment_name> in service group <service_group> |
| resilience_goal_resource_get | Get the goal resource <resource_name> for goal assignment <goal_assignment_name> in service group <service_group> |
| resilience_goal_template_create | Create a resilience goal template <goal_template_name> in service group <service_group> with goal type Resiliency, high availability required, disaster recovery not required, a regional recovery point objective of PT15M and a regional recovery time objective of PT30M |
| resilience_goal_template_get | List all resilience goal templates in service group <service_group> |
| resilience_goal_template_get | Get the details of goal template <goal_template_name> in service group <service_group> |
| resilience_recovery_job_get | List all recovery jobs of recovery plan <recovery_plan_name> in service group <service_group> |
Expand All @@ -872,6 +874,8 @@ This file contains prompts used for end-to-end testing to ensure each tool is in
| resilience_recovery_plan_get | Get the details of recovery plan <recovery_plan_name> in service group <service_group> |
| resilience_recovery_plan_resource_get | List all resources (members) of recovery plan <recovery_plan_name> in service group <service_group> |
| resilience_recovery_plan_resource_get | Get the recovery resource <resource_name> for recovery plan <recovery_plan_name> in service group <service_group> |
| resilience_usageplan_create | Create a resilience usage plan <usage_plan_name> with plan type Basic in resource group <resource_group_name> |
| resilience_usageplan_enrollment_create | Create a usage plan enrollment <enrollment_name> for usage plan <usage_plan_name> associated with service group <service_group> in resource group <resource_group_name> |
| resilience_usageplan_enrollment_get | List all enrollments of usage plan <usage_plan_name> in resource group <resource_group_name> |
| resilience_usageplan_enrollment_get | Get the details of usage plan enrollment <enrollment_name> for usage plan <usage_plan_name> in resource group <resource_group_name> |
| resilience_usageplan_get | List all resilience usage plans in my subscription |
Expand Down
36 changes: 36 additions & 0 deletions servers/Azure.Mcp.Server/src/Resources/consolidated-tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,42 @@
"resilience_recovery_job_resource_get"
]
},
{
"name": "create_azure_resilience_management_resources",
"description": "Create or update Azure Resilience Management resources, including resilience goal templates and goal assignments, and usage plans and usage plan enrollments, 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": false,
"description": "This tool may modify its environment by creating, updating, or deleting 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_create",
"resilience_goal_assignment_create",
"resilience_usageplan_create",
"resilience_usageplan_enrollment_create"
]
},
{
"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.",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// 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 = "b8e4d1c6-3a07-4f29-9d85-2c6f0a7b1e94",
Name = "create",
Title = "Create or Update Resilience Goal Assignment",
Description = """
Creates or updates a resilience goal assignment in the specified service group that assigns the given
goal template, and returns the goal assignment information including id, name, goal assignment type,
goal template id, and provisioning state.
""",
Destructive = false,
Idempotent = true,
OpenWorld = false,
ReadOnly = false,
Secret = false,
LocalRequired = false)]
public sealed class GoalAssignmentCreateCommand(ILogger<GoalAssignmentCreateCommand> logger, IResilienceManagementService resilienceManagementService, ISubscriptionResolver subscriptionResolver)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This command extends from Subscription command, but it doesn't use subscription parameter, does it ?
If not, we should not extend from Subscription command.

: SubscriptionCommand<GoalAssignmentCreateOptions, GoalAssignmentCreateCommand.GoalAssignmentCreateCommandResult>(subscriptionResolver)
{
private readonly ILogger<GoalAssignmentCreateCommand> _logger = logger;
private readonly IResilienceManagementService _resilienceManagementService = resilienceManagementService;

public override async Task<CommandResponse> ExecuteAsync(CommandContext context, GoalAssignmentCreateOptions options, CancellationToken cancellationToken)
{
try
{
var goalAssignment = await _resilienceManagementService.CreateGoalAssignmentAsync(
options.ServiceGroup,
options.GoalAssignment,
options.GoalTemplate,
options.GoalTemplateServiceGroup,
options.GoalAssignmentType,
options.Subscription!,
options.Tenant,
options.RetryPolicy,
cancellationToken);

context.Response.Results = ResponseResult.Create(
new GoalAssignmentCreateCommandResult(goalAssignment),
ResilienceManagementJsonContext.Default.GoalAssignmentCreateCommandResult);
}
catch (Exception ex)
{
_logger.LogError(ex,
"Error creating goal assignment. ServiceGroup: {ServiceGroup}, GoalAssignment: {GoalAssignment}, GoalTemplate: {GoalTemplate}, Subscription: {Subscription}.",
options.ServiceGroup, options.GoalAssignment, options.GoalTemplate, options.Subscription);
HandleException(context, ex);
}

return context.Response;
}

protected override string GetErrorMessage(Exception ex) => ex switch
{
RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.Forbidden =>
$"Authorization failed creating the goal assignment. Details: {reqEx.Message}",
RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.NotFound =>
"Service group or goal template not found. Verify they exist and you have access.",
RequestFailedException reqEx => reqEx.Message,
_ => base.GetErrorMessage(ex)
};

public record GoalAssignmentCreateCommandResult(GoalAssignmentInfo GoalAssignment);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// 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 = "f1d6b3a8-7c25-4e90-9b14-6a2d8f0c5e37",
Name = "create",
Title = "Create or Update Resilience Goal Template",
Description = """
Creates or updates a resilience goal template in the specified service group with the given high
availability and disaster recovery requirements and regional recovery point and time objectives, and
returns the goal template information including id, name, goal type, provisioning state, recovery point
and time objectives, and high availability and disaster recovery requirements.
""",
Destructive = false,
Idempotent = true,
OpenWorld = false,
ReadOnly = false,
Secret = false,
LocalRequired = false)]
public sealed class GoalTemplateCreateCommand(ILogger<GoalTemplateCreateCommand> logger, IResilienceManagementService resilienceManagementService, ISubscriptionResolver subscriptionResolver)
: SubscriptionCommand<GoalTemplateCreateOptions, GoalTemplateCreateCommand.GoalTemplateCreateCommandResult>(subscriptionResolver)
{
private readonly ILogger<GoalTemplateCreateCommand> _logger = logger;
private readonly IResilienceManagementService _resilienceManagementService = resilienceManagementService;

public override async Task<CommandResponse> ExecuteAsync(CommandContext context, GoalTemplateCreateOptions options, CancellationToken cancellationToken)
{
try
{
var goalTemplate = await _resilienceManagementService.CreateGoalTemplateAsync(
options.ServiceGroup,
options.GoalTemplate,
options.GoalType,
options.RequireHighAvailability,
options.RequireDisasterRecovery,
options.RegionalRecoveryPointObjective,
options.RegionalRecoveryTimeObjective,
options.Subscription!,
options.Tenant,
options.RetryPolicy,
cancellationToken);

context.Response.Results = ResponseResult.Create(
new GoalTemplateCreateCommandResult(goalTemplate),
ResilienceManagementJsonContext.Default.GoalTemplateCreateCommandResult);
}
catch (Exception ex)
{
_logger.LogError(ex,
"Error creating goal template. ServiceGroup: {ServiceGroup}, GoalTemplate: {GoalTemplate}, Subscription: {Subscription}.",
options.ServiceGroup, options.GoalTemplate, options.Subscription);
HandleException(context, ex);
}

return context.Response;
}

protected override string GetErrorMessage(Exception ex) => ex switch
{
RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.Forbidden =>
$"Authorization failed creating the goal template. Details: {reqEx.Message}",
RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.NotFound =>
"Service group not found. Verify the service group exists and you have access.",
RequestFailedException reqEx => reqEx.Message,
_ => base.GetErrorMessage(ex)
};

public record GoalTemplateCreateCommandResult(GoalTemplateInfo GoalTemplate);
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
namespace Azure.Mcp.Tools.ResilienceManagement.Commands;

[JsonSerializable(typeof(GoalTemplateGetCommand.GoalTemplateGetCommandResult))]
[JsonSerializable(typeof(GoalTemplateCreateCommand.GoalTemplateCreateCommandResult))]
[JsonSerializable(typeof(GoalTemplateInfo))]
[JsonSerializable(typeof(GoalTemplateInfoProperties))]
[JsonSerializable(typeof(GoalTemplateInfoSystemData))]
[JsonSerializable(typeof(GoalAssignmentGetCommand.GoalAssignmentGetCommandResult))]
[JsonSerializable(typeof(GoalAssignmentCreateCommand.GoalAssignmentCreateCommandResult))]
[JsonSerializable(typeof(GoalAssignmentInfo))]
[JsonSerializable(typeof(GoalAssignmentInfoProperties))]
[JsonSerializable(typeof(GoalAssignmentInfoSystemData))]
Expand All @@ -30,10 +32,12 @@ namespace Azure.Mcp.Tools.ResilienceManagement.Commands;
[JsonSerializable(typeof(GoalResourceServiceGroupMembership))]
[JsonSerializable(typeof(GoalResourceInfoSystemData))]
[JsonSerializable(typeof(UsagePlanGetCommand.UsagePlanGetCommandResult))]
[JsonSerializable(typeof(UsagePlanCreateCommand.UsagePlanCreateCommandResult))]
[JsonSerializable(typeof(UsagePlanInfo))]
[JsonSerializable(typeof(UsagePlanInfoProperties))]
[JsonSerializable(typeof(UsagePlanInfoSystemData))]
[JsonSerializable(typeof(UsagePlanEnrollmentGetCommand.UsagePlanEnrollmentGetCommandResult))]
[JsonSerializable(typeof(UsagePlanEnrollmentCreateCommand.UsagePlanEnrollmentCreateCommandResult))]
[JsonSerializable(typeof(UsagePlanEnrollmentInfo))]
[JsonSerializable(typeof(UsagePlanEnrollmentInfoProperties))]
[JsonSerializable(typeof(UsagePlanEnrollmentInfoErrorDetails))]
Expand Down
Loading