diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 7fb297a45d..e4eecd0ce2 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -94,6 +94,12 @@
# ServiceLabel: %tools-Authorization
# ServiceOwners: @vurhanau @xiangyan99
+# PRLabel: %tools-AzureBackup
+/tools/Azure.Mcp.Tools.AzureBackup/ @shrja @microsoft/azure-mcp
+
+# ServiceLabel: %tools-AzureBackup
+# ServiceOwners: @shrja
+
# ServiceLabel: %tools-AzCLI
# ServiceOwners: @JasonYeMSFT @microsoft/azure-mcp
diff --git a/Directory.Packages.props b/Directory.Packages.props
index c03c789275..5f78705641 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -37,6 +37,9 @@
+
+
+
diff --git a/Microsoft.Mcp.slnx b/Microsoft.Mcp.slnx
index 2dca2e152d..fa228ba102 100644
--- a/Microsoft.Mcp.slnx
+++ b/Microsoft.Mcp.slnx
@@ -126,6 +126,14 @@
+
+
+
+
+
+
+
+
diff --git a/servers/Azure.Mcp.Server/Azure.Mcp.Server.slnx b/servers/Azure.Mcp.Server/Azure.Mcp.Server.slnx
index cce1b34d12..56ca00f4fd 100644
--- a/servers/Azure.Mcp.Server/Azure.Mcp.Server.slnx
+++ b/servers/Azure.Mcp.Server/Azure.Mcp.Server.slnx
@@ -87,6 +87,14 @@
+
+
+
+
+
+
+
+
diff --git a/servers/Azure.Mcp.Server/README.md b/servers/Azure.Mcp.Server/README.md
index eefb9427b4..7aedf53bda 100644
--- a/servers/Azure.Mcp.Server/README.md
+++ b/servers/Azure.Mcp.Server/README.md
@@ -922,6 +922,18 @@ For full configuration options, see the [Sovereign Clouds documentation](https:/
* "List the deployments for web app 'my-webapp' in 'my-resource-group'"
* "Get the deployment 'deployment-id' for web app 'my-webapp' in 'my-resource-group'"
+### π‘οΈ Azure Backup
+
+* "Create a Recovery Services vault named 'myvault' in resource group 'myRG' in eastus"
+* "Get details of backup vault 'myvault' in resource group 'myRG'"
+* "Create a backup policy for Azure VMs in vault 'myvault'"
+* "List protectable items in my backup vault"
+* "Check backup status for my Azure resource"
+* "Get recovery points for a protected item"
+* "Find unprotected resources in my subscription"
+* "Check soft delete and immutability settings on my vault"
+* "Enable cross-region restore on my vault"
+
### π₯οΈ Azure CLI Generate
* Generate Azure CLI commands based on user intent
@@ -1119,6 +1131,7 @@ The Azure MCP Server provides tools for interacting with **43+ Azure service are
- π€ **Azure AI Services Speech** - Speech-to-text recognition and text-to-speech synthesis
- βοΈ **Azure App Configuration** - Configuration management
- πΈοΈ **Azure App Service** - Web app hosting
+- π‘οΈ **Azure Backup** - Recovery Services vault management, backup policies, protection, jobs, recovery points, governance, and disaster recovery
- π‘οΈ **Azure Best Practices** - Secure, production-grade guidance
- π₯οΈ **Azure CLI Generate** - Generate Azure CLI commands from natural language
- π **Azure Communication Services** - SMS messaging and communication
diff --git a/servers/Azure.Mcp.Server/changelog-entries/shrja-add-azure-backup-toolset.yaml b/servers/Azure.Mcp.Server/changelog-entries/shrja-add-azure-backup-toolset.yaml
new file mode 100644
index 0000000000..bc6eb098f2
--- /dev/null
+++ b/servers/Azure.Mcp.Server/changelog-entries/shrja-add-azure-backup-toolset.yaml
@@ -0,0 +1,3 @@
+changes:
+ - section: "Features Added"
+ description: "Add Azure Backup toolset with 15 commands for vault management, backup policies, protection, jobs, recovery points, governance, and disaster recovery"
diff --git a/servers/Azure.Mcp.Server/docs/azmcp-commands.md b/servers/Azure.Mcp.Server/docs/azmcp-commands.md
index 3b11c359ae..5e45b67b23 100644
--- a/servers/Azure.Mcp.Server/docs/azmcp-commands.md
+++ b/servers/Azure.Mcp.Server/docs/azmcp-commands.md
@@ -580,6 +580,180 @@ azmcp appservice database add --subscription "my-subscription" \
- `--connection-string`: Custom connection string (optional - auto-generated if not provided)
- `--tenant`: Azure tenant ID for authentication (optional)
+### Azure Backup Operations
+
+#### Vault
+
+```bash
+# Creates a new backup vault. Specify --vault-type as 'rsv' for a Recovery Services vault or 'dpp' for a Backup vault (Data Protection). Returns the created vault details.
+# β
Destructive | β Idempotent | β OpenWorld | β ReadOnly | β Secret | β LocalRequired
+azmcp azurebackup vault create --subscription \
+ --resource-group \
+ --vault \
+ --location \
+ [--vault-type ] \
+ [--sku ] \
+ [--storage-type ]
+
+# Retrieves backup vault information. When --vault and --resource-group are specified, returns detailed information about a single vault including type, location, SKU, and storage redundancy. When omitted, lists all backup vaults (RSV and Backup vaults) in the subscription, optionally filtered by --vault-type ('rsv' or 'dpp').
+# β Destructive | β
Idempotent | β OpenWorld | β
ReadOnly | β Secret | β LocalRequired
+azmcp azurebackup vault get --subscription \
+ [--resource-group ] \
+ [--vault ] \
+ [--vault-type ]
+
+# Updates vault-level settings including storage redundancy, soft delete, immutability, and managed identity.
+# β
Destructive | β
Idempotent | β OpenWorld | β ReadOnly | β Secret | β LocalRequired
+azmcp azurebackup vault update --subscription \
+ --resource-group \
+ --vault \
+ [--vault-type ] \
+ [--redundancy ] \
+ [--soft-delete ] \
+ [--soft-delete-retention-days ] \
+ [--immutability-state ] \
+ [--identity-type ] \
+ [--tags ]
+```
+
+#### Policy
+
+```bash
+# Creates a backup policy for a specified workload type with schedule and retention rules.
+# β
Destructive | β Idempotent | β OpenWorld | β ReadOnly | β Secret | β LocalRequired
+azmcp azurebackup policy create --subscription \
+ --resource-group \
+ --vault \
+ --policy \
+ [--vault-type ] \
+ [--workload-type ] \
+ [--schedule-frequency ] \
+ [--schedule-time ] \
+ [--daily-retention-days ] \
+ [--weekly-retention-weeks ] \
+ [--monthly-retention-months ] \
+ [--yearly-retention-years ]
+
+# Retrieves backup policy information. When --policy is specified, returns detailed information about a single policy including datasource types and protected items count. When omitted, lists all backup policies configured in the vault.
+# β Destructive | β
Idempotent | β OpenWorld | β
ReadOnly | β Secret | β LocalRequired
+azmcp azurebackup policy get --subscription \
+ --resource-group \
+ --vault \
+ [--vault-type ] \
+ [--policy ]
+```
+
+#### Protected Item
+
+```bash
+# Retrieves protected item information. When --protected-item is specified, returns detailed information about a single backup instance including protection status, datasource details, policy assignment, and last backup time. When --protected-item is omitted, lists all protected items in the vault.
+# β Destructive | β
Idempotent | β OpenWorld | β
ReadOnly | β Secret | β LocalRequired
+azmcp azurebackup protecteditem get --subscription \
+ --resource-group \
+ --vault \
+ [--vault-type ] \
+ [--protected-item ] \
+ [--container ]
+
+# Enables backup protection for a resource by creating a protected item or backup instance.
+# β
Destructive | β Idempotent | β OpenWorld | β ReadOnly | β Secret | β LocalRequired
+azmcp azurebackup protecteditem protect --subscription \
+ --resource-group \
+ --vault \
+ --datasource-id \
+ --policy \
+ [--vault-type ] \
+ [--container ] \
+ [--datasource-type ]
+```
+
+#### Protectable Item
+
+```bash
+# Lists protectable items (SQL databases, SAP HANA databases) discovered in the Recovery Services vault.
+# β Destructive | β
Idempotent | β OpenWorld | β
ReadOnly | β Secret | β LocalRequired
+azmcp azurebackup protectableitem list --subscription \
+ --resource-group \
+ --vault \
+ [--vault-type ] \
+ [--workload-type ] \
+ [--container ]
+```
+
+#### Backup
+
+```bash
+# Checks whether a datasource is protected and returns vault and policy details.
+# β Destructive | β
Idempotent | β OpenWorld | β
ReadOnly | β Secret | β LocalRequired
+azmcp azurebackup backup status --subscription \
+ --datasource-id \
+ --location
+```
+
+#### Job
+
+```bash
+# Retrieves backup job information. When --job is specified, returns detailed information about a single job. When omitted, lists all backup jobs in the vault.
+# β Destructive | β
Idempotent | β OpenWorld | β
ReadOnly | β Secret | β LocalRequired
+azmcp azurebackup job get --subscription \
+ --resource-group \
+ --vault \
+ [--vault-type ] \
+ [--job ]
+```
+
+#### Recovery Point
+
+```bash
+# Retrieves recovery point information for a protected item. When --recovery-point is specified, returns a single recovery point. When omitted, lists all available recovery points.
+# β Destructive | β
Idempotent | β OpenWorld | β
ReadOnly | β Secret | β LocalRequired
+azmcp azurebackup recoverypoint get --subscription \
+ --resource-group \
+ --vault \
+ --protected-item \
+ [--vault-type ] \
+ [--container ] \
+ [--recovery-point ]
+```
+
+#### Governance
+
+```bash
+# Scans the subscription to find Azure resources that are not currently protected by any backup policy.
+# β Destructive | β
Idempotent | β OpenWorld | β
ReadOnly | β Secret | β LocalRequired
+azmcp azurebackup governance find-unprotected --subscription \
+ [--resource-type-filter ] \
+ [--resource-group-filter ] \
+ [--tag-filter ]
+
+# Configures the immutability state for a backup vault.
+# β
Destructive | β
Idempotent | β OpenWorld | β ReadOnly | β Secret | β LocalRequired
+azmcp azurebackup governance immutability --subscription \
+ --resource-group \
+ --vault \
+ [--vault-type ] \
+ [--immutability-state ]
+
+# Configures the soft delete settings for a backup vault.
+# β
Destructive | β
Idempotent | β OpenWorld | β ReadOnly | β Secret | β LocalRequired
+azmcp azurebackup governance soft-delete --subscription \
+ --resource-group \
+ --vault \
+ [--vault-type ] \
+ [--soft-delete ] \
+ [--soft-delete-retention-days ]
+```
+
+#### DR
+
+```bash
+# Enables Cross-Region Restore on a GRS-enabled vault.
+# β
Destructive | β
Idempotent | β OpenWorld | β ReadOnly | β Secret | β LocalRequired
+azmcp azurebackup dr enablecrr --subscription \
+ --resource-group \
+ --vault \
+ [--vault-type ]
+
#### Web Apps
```bash
diff --git a/servers/Azure.Mcp.Server/docs/e2eTestPrompts.md b/servers/Azure.Mcp.Server/docs/e2eTestPrompts.md
index 8e7458c779..315bc6c377 100644
--- a/servers/Azure.Mcp.Server/docs/e2eTestPrompts.md
+++ b/servers/Azure.Mcp.Server/docs/e2eTestPrompts.md
@@ -119,6 +119,41 @@ This file contains prompts used for end-to-end testing to ensure each tool is in
| appservice_webapp_settings_update-appsettings | Set application setting with to web app in |
| appservice_webapp_settings_update-appsettings | Delete application setting from web app in |
+## Azure Backup
+
+| Tool Name | Test Prompt |
+|:----------|:----------|
+| azurebackup_vault_create | Create a Recovery Services vault named in resource group in region |
+| azurebackup_vault_create | Set up a new backup vault called in under resource group |
+| azurebackup_vault_get | Get details of Recovery Services vault in resource group |
+| azurebackup_vault_get | Show me information about vault in resource group |
+| azurebackup_vault_update | Update vault in resource group to use GeoRedundant storage |
+| azurebackup_vault_update | Change the redundancy of vault in resource group to LocallyRedundant |
+| azurebackup_policy_create | Create a backup policy named for AzureIaasVM in vault in resource group |
+| azurebackup_policy_create | Set up a new backup policy called for AzureStorage workload in vault under resource group |
+| azurebackup_policy_get | Get backup policy from vault in resource group |
+| azurebackup_policy_get | Show me the details of backup policy in vault under resource group |
+| azurebackup_protecteditem_get | Get protected item details for in vault and resource group |
+| azurebackup_protecteditem_get | Show backup status of protected item in vault under resource group |
+| azurebackup_protecteditem_protect | Enable backup protection for using policy in vault and resource group |
+| azurebackup_protecteditem_protect | Protect item with backup policy in vault under resource group |
+| azurebackup_protectableitem_list | List protectable items in vault in resource group |
+| azurebackup_protectableitem_list | Show me all items that can be backed up in vault under resource group |
+| azurebackup_backup_status | Check backup status for resource |
+| azurebackup_backup_status | What is the backup status of in my subscription? |
+| azurebackup_job_get | Get backup job from vault in resource group |
+| azurebackup_job_get | Show me the status of backup job in vault under resource group |
+| azurebackup_recoverypoint_get | Get recovery points for protected item in vault and resource group |
+| azurebackup_recoverypoint_get | List available recovery points for in vault under resource group |
+| azurebackup_governance_find-unprotected | Find unprotected resources of type in my subscription |
+| azurebackup_governance_find-unprotected | Show me Azure resources that are not backed up for datasource type |
+| azurebackup_governance_immutability | Check immutability status of vault in resource group |
+| azurebackup_governance_immutability | Is immutability enabled on vault in resource group ? |
+| azurebackup_governance_soft-delete | Check soft delete configuration for vault in resource group |
+| azurebackup_governance_soft-delete | Is soft delete enabled on vault in resource group ? |
+| azurebackup_dr_enablecrr | Enable cross-region restore on vault in resource group |
+| azurebackup_dr_enablecrr | Turn on cross-region restore for vault under resource group |
+
## Azure Application Insights
| Tool Name | Test Prompt |
diff --git a/servers/Azure.Mcp.Server/src/Program.cs b/servers/Azure.Mcp.Server/src/Program.cs
index f75961ef4e..956581ae10 100644
--- a/servers/Azure.Mcp.Server/src/Program.cs
+++ b/servers/Azure.Mcp.Server/src/Program.cs
@@ -102,6 +102,7 @@ private static IAreaSetup[] RegisterAreas()
new Azure.Mcp.Tools.AppLens.AppLensSetup(),
new Azure.Mcp.Tools.AppService.AppServiceSetup(),
new Azure.Mcp.Tools.Authorization.AuthorizationSetup(),
+ new Azure.Mcp.Tools.AzureBackup.AzureBackupSetup(),
new Azure.Mcp.Tools.AzureIsv.AzureIsvSetup(),
new Azure.Mcp.Tools.ManagedLustre.ManagedLustreSetup(),
new Azure.Mcp.Tools.AzureMigrate.AzureMigrateSetup(),
diff --git a/servers/Azure.Mcp.Server/src/Resources/consolidated-tools.json b/servers/Azure.Mcp.Server/src/Resources/consolidated-tools.json
index 40fc2f5705..61912260d8 100644
--- a/servers/Azure.Mcp.Server/src/Resources/consolidated-tools.json
+++ b/servers/Azure.Mcp.Server/src/Resources/consolidated-tools.json
@@ -3562,6 +3562,213 @@
"mappedToolList": [
"deviceregistry_namespace_list"
]
+ },
+ {
+ "name": "get_azure_backup_vault_details",
+ "description": "Get information about Azure Recovery Services vaults including configuration, redundancy settings, and properties.",
+ "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": [
+ "azurebackup_vault_get"
+ ]
+ },
+ {
+ "name": "manage_azure_backup_vaults",
+ "description": "Create and update Azure Recovery Services vaults for backup and disaster recovery.",
+ "toolMetadata": {
+ "destructive": {
+ "value": true,
+ "description": "This tool performs write operations by creating or updating Azure Recovery Services vault resources and can modify existing state."
+ },
+ "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": [
+ "azurebackup_vault_create",
+ "azurebackup_vault_update"
+ ]
+ },
+ {
+ "name": "manage_azure_backup_policies",
+ "description": "Create and retrieve Azure Backup policies for configuring backup schedules and retention.",
+ "toolMetadata": {
+ "destructive": {
+ "value": true,
+ "description": "This tool can create or modify Azure Backup policies, changing the configuration of backup schedules and retention."
+ },
+ "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": [
+ "azurebackup_policy_create",
+ "azurebackup_policy_get"
+ ]
+ },
+ {
+ "name": "manage_azure_backup_protection",
+ "description": "Manage backup protection for Azure resources including enabling protection, checking status, listing protectable items, and monitoring protected items.",
+ "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": [
+ "azurebackup_protecteditem_get",
+ "azurebackup_protecteditem_protect",
+ "azurebackup_protectableitem_list",
+ "azurebackup_backup_status"
+ ]
+ },
+ {
+ "name": "get_azure_backup_jobs_and_recovery_points",
+ "description": "Get Azure Backup job status and recovery point details for protected items.",
+ "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": [
+ "azurebackup_job_get",
+ "azurebackup_recoverypoint_get"
+ ]
+ },
+ {
+ "name": "manage_azure_backup_governance_and_dr",
+ "description": "Manage Azure Backup governance settings including soft delete, immutability, cross-region restore, and find unprotected resources.",
+ "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": [
+ "azurebackup_governance_find-unprotected",
+ "azurebackup_governance_immutability",
+ "azurebackup_governance_soft-delete",
+ "azurebackup_dr_enablecrr"
+ ]
}
]
}
diff --git a/tools/Azure.Mcp.Tools.AzureBackup/src/AssemblyInfo.cs b/tools/Azure.Mcp.Tools.AzureBackup/src/AssemblyInfo.cs
new file mode 100644
index 0000000000..384ecb29c2
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.AzureBackup/src/AssemblyInfo.cs
@@ -0,0 +1,7 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("Azure.Mcp.Tools.AzureBackup.UnitTests")]
+[assembly: InternalsVisibleTo("Azure.Mcp.Tools.AzureBackup.LiveTests")]
diff --git a/tools/Azure.Mcp.Tools.AzureBackup/src/Azure.Mcp.Tools.AzureBackup.csproj b/tools/Azure.Mcp.Tools.AzureBackup/src/Azure.Mcp.Tools.AzureBackup.csproj
new file mode 100644
index 0000000000..9372dbb7da
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.AzureBackup/src/Azure.Mcp.Tools.AzureBackup.csproj
@@ -0,0 +1,19 @@
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tools/Azure.Mcp.Tools.AzureBackup/src/AzureBackupSetup.cs b/tools/Azure.Mcp.Tools.AzureBackup/src/AzureBackupSetup.cs
new file mode 100644
index 0000000000..bba204c080
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.AzureBackup/src/AzureBackupSetup.cs
@@ -0,0 +1,118 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Azure.Mcp.Tools.AzureBackup.Commands.Backup;
+using Azure.Mcp.Tools.AzureBackup.Commands.Dr;
+using Azure.Mcp.Tools.AzureBackup.Commands.Governance;
+using Azure.Mcp.Tools.AzureBackup.Commands.Job;
+using Azure.Mcp.Tools.AzureBackup.Commands.Policy;
+using Azure.Mcp.Tools.AzureBackup.Commands.ProtectableItem;
+using Azure.Mcp.Tools.AzureBackup.Commands.ProtectedItem;
+using Azure.Mcp.Tools.AzureBackup.Commands.RecoveryPoint;
+using Azure.Mcp.Tools.AzureBackup.Commands.Vault;
+using Azure.Mcp.Tools.AzureBackup.Services;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Mcp.Core.Areas;
+using Microsoft.Mcp.Core.Commands;
+
+namespace Azure.Mcp.Tools.AzureBackup;
+
+public class AzureBackupSetup : IAreaSetup
+{
+ public string Name => "azurebackup";
+
+ public string Title => "Manage Azure Backup";
+
+ 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();
+
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+
+ services.AddSingleton();
+ }
+
+ public CommandGroup RegisterCommands(IServiceProvider serviceProvider)
+ {
+ var azureBackup = new CommandGroup(Name,
+ """
+ Azure Backup operations β Unified commands to manage backup across Recovery Services vaults (RSV)
+ and Backup vaults (DPP/Data Protection). Supports vault management, protected item operations,
+ policy management, job monitoring, recovery point browsing, governance, and disaster recovery.
+ Use --vault-type to specify vault type or let the system auto-detect.
+ """,
+ Title);
+
+ var vault = new CommandGroup("vault", "Backup vault operations β Get vault details or list all vaults, create, and update vaults.");
+ azureBackup.AddSubGroup(vault);
+ RegisterCommand(serviceProvider, vault);
+ RegisterCommand(serviceProvider, vault);
+ RegisterCommand(serviceProvider, vault);
+
+ var policy = new CommandGroup("policy", "Backup policy operations β Get policy details or list all policies, and create policies.");
+ azureBackup.AddSubGroup(policy);
+ RegisterCommand(serviceProvider, policy);
+ RegisterCommand(serviceProvider, policy);
+
+ var protectedItem = new CommandGroup("protecteditem", "Protected item operations β Get protected item details or list all, and enable backup protection.");
+ azureBackup.AddSubGroup(protectedItem);
+ RegisterCommand(serviceProvider, protectedItem);
+ RegisterCommand(serviceProvider, protectedItem);
+
+ var protectableItem = new CommandGroup("protectableitem", "Protectable item operations β List discovered databases available for protection.");
+ azureBackup.AddSubGroup(protectableItem);
+ RegisterCommand(serviceProvider, protectableItem);
+
+ var backup = new CommandGroup("backup", "Backup operations β Check backup status for a datasource.");
+ azureBackup.AddSubGroup(backup);
+ RegisterCommand(serviceProvider, backup);
+
+ var job = new CommandGroup("job", "Backup job operations β Get job details or list all jobs in a vault.");
+ azureBackup.AddSubGroup(job);
+ RegisterCommand(serviceProvider, job);
+
+ var recoveryPoint = new CommandGroup("recoverypoint", "Recovery point operations β Get recovery point details or list all for a protected item.");
+ azureBackup.AddSubGroup(recoveryPoint);
+ RegisterCommand(serviceProvider, recoveryPoint);
+
+ var governance = new CommandGroup("governance", "Governance operations β Find unprotected resources, configure immutability and soft delete.");
+ azureBackup.AddSubGroup(governance);
+ RegisterCommand(serviceProvider, governance);
+ RegisterCommand(serviceProvider, governance);
+ RegisterCommand(serviceProvider, governance);
+
+ var dr = new CommandGroup("dr", "Disaster recovery operations β Enable Cross-Region Restore on a GRS vault.");
+ azureBackup.AddSubGroup(dr);
+ RegisterCommand(serviceProvider, dr);
+
+ return azureBackup;
+ }
+
+ private static void RegisterCommand(IServiceProvider serviceProvider, CommandGroup group) where T : IBaseCommand
+ {
+ var cmd = serviceProvider.GetRequiredService();
+ group.AddCommand(cmd.Name, cmd);
+ }
+}
diff --git a/tools/Azure.Mcp.Tools.AzureBackup/src/Commands/AzureBackupJsonContext.cs b/tools/Azure.Mcp.Tools.AzureBackup/src/Commands/AzureBackupJsonContext.cs
new file mode 100644
index 0000000000..c3953d943f
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.AzureBackup/src/Commands/AzureBackupJsonContext.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.AzureBackup.Commands.Backup;
+using Azure.Mcp.Tools.AzureBackup.Commands.Dr;
+using Azure.Mcp.Tools.AzureBackup.Commands.Governance;
+using Azure.Mcp.Tools.AzureBackup.Commands.Job;
+using Azure.Mcp.Tools.AzureBackup.Commands.Policy;
+using Azure.Mcp.Tools.AzureBackup.Commands.ProtectableItem;
+using Azure.Mcp.Tools.AzureBackup.Commands.ProtectedItem;
+using Azure.Mcp.Tools.AzureBackup.Commands.RecoveryPoint;
+using Azure.Mcp.Tools.AzureBackup.Commands.Vault;
+using Azure.Mcp.Tools.AzureBackup.Models;
+
+namespace Azure.Mcp.Tools.AzureBackup.Commands;
+
+[JsonSerializable(typeof(VaultGetCommand.VaultGetCommandResult))]
+[JsonSerializable(typeof(VaultCreateCommand.VaultCreateCommandResult))]
+[JsonSerializable(typeof(VaultUpdateCommand.VaultUpdateCommandResult))]
+[JsonSerializable(typeof(PolicyGetCommand.PolicyGetCommandResult))]
+[JsonSerializable(typeof(PolicyCreateCommand.PolicyCreateCommandResult))]
+[JsonSerializable(typeof(ProtectedItemGetCommand.ProtectedItemGetCommandResult))]
+[JsonSerializable(typeof(ProtectedItemProtectCommand.ProtectedItemProtectCommandResult))]
+[JsonSerializable(typeof(ProtectableItemListCommand.ProtectableItemListCommandResult))]
+[JsonSerializable(typeof(BackupStatusCommand.BackupStatusCommandResult))]
+[JsonSerializable(typeof(JobGetCommand.JobGetCommandResult))]
+[JsonSerializable(typeof(RecoveryPointGetCommand.RecoveryPointGetCommandResult))]
+[JsonSerializable(typeof(GovernanceFindUnprotectedCommand.GovernanceFindUnprotectedCommandResult))]
+[JsonSerializable(typeof(GovernanceImmutabilityCommand.GovernanceImmutabilityCommandResult))]
+[JsonSerializable(typeof(GovernanceSoftDeleteCommand.GovernanceSoftDeleteCommandResult))]
+[JsonSerializable(typeof(DrEnableCrrCommand.DrEnableCrrCommandResult))]
+[JsonSerializable(typeof(BackupVaultInfo))]
+[JsonSerializable(typeof(ProtectedItemInfo))]
+[JsonSerializable(typeof(BackupPolicyInfo))]
+[JsonSerializable(typeof(BackupJobInfo))]
+[JsonSerializable(typeof(RecoveryPointInfo))]
+[JsonSerializable(typeof(ProtectableItemInfo))]
+[JsonSerializable(typeof(ContainerInfo))]
+[JsonSerializable(typeof(VaultCreateResult))]
+[JsonSerializable(typeof(ProtectResult))]
+[JsonSerializable(typeof(BackupTriggerResult))]
+[JsonSerializable(typeof(RestoreTriggerResult))]
+[JsonSerializable(typeof(OperationResult))]
+[JsonSerializable(typeof(BackupStatusResult))]
+[JsonSerializable(typeof(CostEstimateResult))]
+[JsonSerializable(typeof(HealthCheckResult))]
+[JsonSerializable(typeof(HealthCheckItemDetail))]
+[JsonSerializable(typeof(UnprotectedResourceInfo))]
+[JsonSerializable(typeof(DrValidationResult))]
+[JsonSerializable(typeof(WorkflowResult))]
+[JsonSerializable(typeof(WorkflowStep))]
+[JsonSerializable(typeof(JsonElement))]
+[JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault)]
+internal sealed partial class AzureBackupJsonContext : JsonSerializerContext
+{
+}
diff --git a/tools/Azure.Mcp.Tools.AzureBackup/src/Commands/Backup/BackupStatusCommand.cs b/tools/Azure.Mcp.Tools.AzureBackup/src/Commands/Backup/BackupStatusCommand.cs
new file mode 100644
index 0000000000..c11e96f9de
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.AzureBackup/src/Commands/Backup/BackupStatusCommand.cs
@@ -0,0 +1,60 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Text.Json.Serialization;
+using Azure.Mcp.Core.Commands.Subscription;
+using Azure.Mcp.Core.Extensions;
+using Azure.Mcp.Core.Models.Option;
+using Azure.Mcp.Tools.AzureBackup.Models;
+using Azure.Mcp.Tools.AzureBackup.Options;
+using Azure.Mcp.Tools.AzureBackup.Options.Backup;
+using Azure.Mcp.Tools.AzureBackup.Services;
+using Microsoft.Extensions.Logging;
+using Microsoft.Mcp.Core.Commands;
+using Microsoft.Mcp.Core.Models.Command;
+using Microsoft.Mcp.Core.Models.Option;
+
+namespace Azure.Mcp.Tools.AzureBackup.Commands.Backup;
+
+public sealed class BackupStatusCommand(ILogger logger) : SubscriptionCommand()
+{
+ private const string CommandTitle = "Check Backup Status";
+ private readonly ILogger _logger = logger;
+
+ public override string Id => "b1a2c3d4-e5f6-7890-abcd-ef12345678b5";
+ public override string Name => "status";
+ public override string Description => "Checks whether a datasource is protected and returns vault and policy details.";
+ public override string Title => CommandTitle;
+ public override ToolMetadata Metadata => new() { Destructive = false, Idempotent = true, OpenWorld = false, ReadOnly = true, LocalRequired = false, Secret = false };
+
+ protected override void RegisterOptions(Command command)
+ {
+ base.RegisterOptions(command);
+ command.Options.Add(AzureBackupOptionDefinitions.DatasourceId);
+ command.Options.Add(AzureBackupOptionDefinitions.Location);
+ }
+
+ protected override BackupStatusOptions BindOptions(ParseResult parseResult)
+ {
+ var options = base.BindOptions(parseResult);
+ options.DatasourceId = parseResult.GetValueOrDefault(AzureBackupOptionDefinitions.DatasourceId.Name);
+ options.Location = parseResult.GetValueOrDefault(AzureBackupOptionDefinitions.Location.Name);
+ return options;
+ }
+
+ public override async Task ExecuteAsync(CommandContext context, ParseResult parseResult, CancellationToken cancellationToken)
+ {
+ if (!Validate(parseResult.CommandResult, context.Response).IsValid) return context.Response;
+ var options = BindOptions(parseResult);
+ try
+ {
+ var service = context.GetService();
+ var result = await service.GetBackupStatusAsync(options.DatasourceId!, options.Subscription!, options.Location!, options.Tenant, options.RetryPolicy, cancellationToken);
+ context.Response.Results = ResponseResult.Create(new BackupStatusCommandResult(result), AzureBackupJsonContext.Default.BackupStatusCommandResult);
+ }
+ catch (Exception ex) { _logger.LogError(ex, "Error checking backup status"); HandleException(context, ex); }
+ return context.Response;
+ }
+
+ internal record BackupStatusCommandResult([property: JsonPropertyName("status")] BackupStatusResult Status);
+}
diff --git a/tools/Azure.Mcp.Tools.AzureBackup/src/Commands/BaseAzureBackupCommand.cs b/tools/Azure.Mcp.Tools.AzureBackup/src/Commands/BaseAzureBackupCommand.cs
new file mode 100644
index 0000000000..0e723aff65
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.AzureBackup/src/Commands/BaseAzureBackupCommand.cs
@@ -0,0 +1,35 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Diagnostics.CodeAnalysis;
+using Azure.Mcp.Core.Commands;
+using Azure.Mcp.Core.Commands.Subscription;
+using Azure.Mcp.Core.Extensions;
+using Azure.Mcp.Tools.AzureBackup.Options;
+using Azure.Mcp.Core.Models.Option;
+using Microsoft.Mcp.Core.Models.Option;
+
+namespace Azure.Mcp.Tools.AzureBackup.Commands;
+
+public abstract class BaseAzureBackupCommand<
+ [DynamicallyAccessedMembers(TrimAnnotations.CommandAnnotations)] T>
+ : SubscriptionCommand
+ where T : BaseAzureBackupOptions, new()
+{
+ protected override void RegisterOptions(Command command)
+ {
+ base.RegisterOptions(command);
+ command.Options.Add(OptionDefinitions.Common.ResourceGroup.AsRequired());
+ command.Options.Add(AzureBackupOptionDefinitions.Vault);
+ command.Options.Add(AzureBackupOptionDefinitions.VaultType);
+ }
+
+ protected override T BindOptions(ParseResult parseResult)
+ {
+ var options = base.BindOptions(parseResult);
+ options.ResourceGroup ??= parseResult.GetValueOrDefault(OptionDefinitions.Common.ResourceGroup.Name);
+ options.Vault = parseResult.GetValueOrDefault(AzureBackupOptionDefinitions.Vault.Name);
+ options.VaultType = parseResult.GetValueOrDefault(AzureBackupOptionDefinitions.VaultType.Name);
+ return options;
+ }
+}
diff --git a/tools/Azure.Mcp.Tools.AzureBackup/src/Commands/BaseProtectedItemCommand.cs b/tools/Azure.Mcp.Tools.AzureBackup/src/Commands/BaseProtectedItemCommand.cs
new file mode 100644
index 0000000000..cbe6e3bab1
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.AzureBackup/src/Commands/BaseProtectedItemCommand.cs
@@ -0,0 +1,30 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Diagnostics.CodeAnalysis;
+using Azure.Mcp.Core.Commands;
+using Azure.Mcp.Core.Extensions;
+using Azure.Mcp.Tools.AzureBackup.Options;
+
+namespace Azure.Mcp.Tools.AzureBackup.Commands;
+
+public abstract class BaseProtectedItemCommand<
+ [DynamicallyAccessedMembers(TrimAnnotations.CommandAnnotations)] T>
+ : BaseAzureBackupCommand
+ where T : BaseProtectedItemOptions, new()
+{
+ protected override void RegisterOptions(Command command)
+ {
+ base.RegisterOptions(command);
+ command.Options.Add(AzureBackupOptionDefinitions.ProtectedItem);
+ command.Options.Add(AzureBackupOptionDefinitions.Container);
+ }
+
+ protected override T BindOptions(ParseResult parseResult)
+ {
+ var options = base.BindOptions(parseResult);
+ options.ProtectedItem = parseResult.GetValueOrDefault(AzureBackupOptionDefinitions.ProtectedItem.Name);
+ options.Container = parseResult.GetValueOrDefault(AzureBackupOptionDefinitions.Container.Name);
+ return options;
+ }
+}
diff --git a/tools/Azure.Mcp.Tools.AzureBackup/src/Commands/Dr/DrEnableCrrCommand.cs b/tools/Azure.Mcp.Tools.AzureBackup/src/Commands/Dr/DrEnableCrrCommand.cs
new file mode 100644
index 0000000000..a89af16625
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.AzureBackup/src/Commands/Dr/DrEnableCrrCommand.cs
@@ -0,0 +1,42 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Text.Json.Serialization;
+using Azure.Mcp.Core.Extensions;
+using Azure.Mcp.Tools.AzureBackup.Models;
+using Azure.Mcp.Tools.AzureBackup.Options.Dr;
+using Azure.Mcp.Tools.AzureBackup.Services;
+using Microsoft.Extensions.Logging;
+using Microsoft.Mcp.Core.Commands;
+using Microsoft.Mcp.Core.Models.Command;
+using Microsoft.Mcp.Core.Models.Option;
+
+namespace Azure.Mcp.Tools.AzureBackup.Commands.Dr;
+
+public sealed class DrEnableCrrCommand(ILogger logger) : BaseAzureBackupCommand()
+{
+ private const string CommandTitle = "Enable Cross-Region Restore";
+ private readonly ILogger _logger = logger;
+
+ public override string Id => "b1a2c3d4-e5f6-7890-abcd-ef12345678d4";
+ public override string Name => "enablecrr";
+ public override string Description => "Enables Cross-Region Restore on a GRS-enabled vault.";
+ public override string Title => CommandTitle;
+ public override ToolMetadata Metadata => new() { Destructive = true, Idempotent = true, OpenWorld = false, ReadOnly = false, LocalRequired = false, Secret = false };
+
+ public override async Task ExecuteAsync(CommandContext context, ParseResult parseResult, CancellationToken cancellationToken)
+ {
+ if (!Validate(parseResult.CommandResult, context.Response).IsValid) return context.Response;
+ var options = BindOptions(parseResult);
+ try
+ {
+ var service = context.GetService();
+ var result = await service.ConfigureCrossRegionRestoreAsync(options.Vault!, options.ResourceGroup!, options.Subscription!, options.VaultType, options.Tenant, options.RetryPolicy, cancellationToken);
+ context.Response.Results = ResponseResult.Create(new DrEnableCrrCommandResult(result), AzureBackupJsonContext.Default.DrEnableCrrCommandResult);
+ }
+ catch (Exception ex) { _logger.LogError(ex, "Error enabling CRR"); HandleException(context, ex); }
+ return context.Response;
+ }
+
+ internal record DrEnableCrrCommandResult([property: JsonPropertyName("result")] OperationResult Result);
+}
diff --git a/tools/Azure.Mcp.Tools.AzureBackup/src/Commands/Governance/GovernanceFindUnprotectedCommand.cs b/tools/Azure.Mcp.Tools.AzureBackup/src/Commands/Governance/GovernanceFindUnprotectedCommand.cs
new file mode 100644
index 0000000000..1f7678616c
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.AzureBackup/src/Commands/Governance/GovernanceFindUnprotectedCommand.cs
@@ -0,0 +1,89 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Text.Json.Serialization;
+using Azure.Mcp.Core.Commands.Subscription;
+using Azure.Mcp.Core.Extensions;
+using Azure.Mcp.Tools.AzureBackup.Models;
+using Azure.Mcp.Tools.AzureBackup.Options;
+using Azure.Mcp.Tools.AzureBackup.Options.Governance;
+using Azure.Mcp.Tools.AzureBackup.Services;
+using Microsoft.Extensions.Logging;
+using Microsoft.Mcp.Core.Commands;
+using Microsoft.Mcp.Core.Models.Command;
+using Microsoft.Mcp.Core.Models.Option;
+
+namespace Azure.Mcp.Tools.AzureBackup.Commands.Governance;
+
+public sealed class GovernanceFindUnprotectedCommand(ILogger logger) : SubscriptionCommand()
+{
+ private const string CommandTitle = "Find Unprotected Resources";
+ private readonly ILogger _logger = logger;
+
+ public override string Id => "b1a2c3d4-e5f6-7890-abcd-ef12345678c8";
+ public override string Name => "find-unprotected";
+ public override string Description =>
+ """
+ Scans the subscription to find Azure resources that are not currently protected by any
+ backup policy. Optionally filter by resource type, resource group, or tags.
+ """;
+ public override string Title => CommandTitle;
+ public override ToolMetadata Metadata => new()
+ {
+ Destructive = false, Idempotent = true, OpenWorld = false,
+ ReadOnly = true, LocalRequired = false, Secret = false
+ };
+
+ protected override void RegisterOptions(Command command)
+ {
+ base.RegisterOptions(command);
+ command.Options.Add(AzureBackupOptionDefinitions.ResourceTypeFilter);
+ command.Options.Add(AzureBackupOptionDefinitions.ResourceGroupFilter);
+ command.Options.Add(AzureBackupOptionDefinitions.TagFilter);
+ }
+
+ protected override GovernanceFindUnprotectedOptions BindOptions(ParseResult parseResult)
+ {
+ var options = base.BindOptions(parseResult);
+ options.ResourceTypeFilter = parseResult.GetValueOrDefault(AzureBackupOptionDefinitions.ResourceTypeFilter.Name);
+ options.ResourceGroupFilter = parseResult.GetValueOrDefault(AzureBackupOptionDefinitions.ResourceGroupFilter.Name);
+ options.TagFilter = parseResult.GetValueOrDefault(AzureBackupOptionDefinitions.TagFilter.Name);
+ return options;
+ }
+
+ public override async Task ExecuteAsync(CommandContext context, ParseResult parseResult, CancellationToken cancellationToken)
+ {
+ if (!Validate(parseResult.CommandResult, context.Response).IsValid)
+ {
+ return context.Response;
+ }
+
+ var options = BindOptions(parseResult);
+
+ try
+ {
+ var service = context.GetService();
+ var resources = await service.FindUnprotectedResourcesAsync(
+ options.Subscription!,
+ options.ResourceTypeFilter,
+ options.ResourceGroupFilter,
+ options.TagFilter,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+
+ context.Response.Results = ResponseResult.Create(
+ new GovernanceFindUnprotectedCommandResult(resources),
+ AzureBackupJsonContext.Default.GovernanceFindUnprotectedCommandResult);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error finding unprotected resources. Subscription: {Subscription}", options.Subscription);
+ HandleException(context, ex);
+ }
+
+ return context.Response;
+ }
+
+ internal record GovernanceFindUnprotectedCommandResult([property: JsonPropertyName("resources")] List Resources);
+}
diff --git a/tools/Azure.Mcp.Tools.AzureBackup/src/Commands/Governance/GovernanceImmutabilityCommand.cs b/tools/Azure.Mcp.Tools.AzureBackup/src/Commands/Governance/GovernanceImmutabilityCommand.cs
new file mode 100644
index 0000000000..daac27981d
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.AzureBackup/src/Commands/Governance/GovernanceImmutabilityCommand.cs
@@ -0,0 +1,97 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Net;
+using System.Text.Json.Serialization;
+using Azure.Mcp.Core.Extensions;
+using Azure.Mcp.Tools.AzureBackup.Models;
+using Azure.Mcp.Tools.AzureBackup.Options;
+using Azure.Mcp.Tools.AzureBackup.Options.Governance;
+using Azure.Mcp.Tools.AzureBackup.Services;
+using Microsoft.Extensions.Logging;
+using Microsoft.Mcp.Core.Commands;
+using Microsoft.Mcp.Core.Models.Command;
+
+namespace Azure.Mcp.Tools.AzureBackup.Commands.Governance;
+
+public sealed class GovernanceImmutabilityCommand(ILogger logger) : BaseAzureBackupCommand()
+{
+ private const string CommandTitle = "Configure Vault Immutability";
+ private readonly ILogger _logger = logger;
+
+ public override string Id => "b1a2c3d4-e5f6-7890-abcd-ef12345678ca";
+ public override string Name => "immutability";
+ public override string Description =>
+ """
+ Configures the immutability state for a backup vault. States include 'Disabled', 'Enabled',
+ or 'Locked'. Warning: 'Locked' state is irreversible.
+ """;
+ public override string Title => CommandTitle;
+ public override ToolMetadata Metadata => new()
+ {
+ Destructive = true, Idempotent = true, OpenWorld = false,
+ ReadOnly = false, LocalRequired = false, Secret = false
+ };
+
+ protected override void RegisterOptions(Command command)
+ {
+ base.RegisterOptions(command);
+ command.Options.Add(AzureBackupOptionDefinitions.ImmutabilityState);
+ }
+
+ protected override GovernanceImmutabilityOptions BindOptions(ParseResult parseResult)
+ {
+ var options = base.BindOptions(parseResult);
+ options.ImmutabilityState = parseResult.GetValueOrDefault(AzureBackupOptionDefinitions.ImmutabilityState.Name);
+ return options;
+ }
+
+ public override async Task ExecuteAsync(CommandContext context, ParseResult parseResult, CancellationToken cancellationToken)
+ {
+ if (!Validate(parseResult.CommandResult, context.Response).IsValid)
+ {
+ return context.Response;
+ }
+
+ var options = BindOptions(parseResult);
+
+ try
+ {
+ var service = context.GetService();
+ var result = await service.ConfigureImmutabilityAsync(
+ options.Vault!,
+ options.ResourceGroup!,
+ options.Subscription!,
+ options.ImmutabilityState!,
+ options.VaultType,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+
+ context.Response.Results = ResponseResult.Create(
+ new GovernanceImmutabilityCommandResult(result),
+ AzureBackupJsonContext.Default.GovernanceImmutabilityCommandResult);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error configuring immutability. Vault: {Vault}, State: {ImmutabilityState}",
+ options.Vault, options.ImmutabilityState);
+ HandleException(context, ex);
+ }
+
+ return context.Response;
+ }
+
+ protected override string GetErrorMessage(Exception ex) => ex switch
+ {
+ ArgumentException argEx => argEx.Message,
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.NotFound =>
+ "Vault not found. Verify the vault name and resource group.",
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.Conflict =>
+ "Immutability state cannot be changed. It may already be locked.",
+ RequestFailedException reqEx => reqEx.Message,
+ _ => base.GetErrorMessage(ex)
+ };
+
+ internal record GovernanceImmutabilityCommandResult([property: JsonPropertyName("result")] OperationResult Result);
+}
diff --git a/tools/Azure.Mcp.Tools.AzureBackup/src/Commands/Governance/GovernanceSoftDeleteCommand.cs b/tools/Azure.Mcp.Tools.AzureBackup/src/Commands/Governance/GovernanceSoftDeleteCommand.cs
new file mode 100644
index 0000000000..2181eb3ba9
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.AzureBackup/src/Commands/Governance/GovernanceSoftDeleteCommand.cs
@@ -0,0 +1,98 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Net;
+using System.Text.Json.Serialization;
+using Azure.Mcp.Core.Extensions;
+using Azure.Mcp.Tools.AzureBackup.Models;
+using Azure.Mcp.Tools.AzureBackup.Options;
+using Azure.Mcp.Tools.AzureBackup.Options.Governance;
+using Azure.Mcp.Tools.AzureBackup.Services;
+using Microsoft.Extensions.Logging;
+using Microsoft.Mcp.Core.Commands;
+using Microsoft.Mcp.Core.Models.Command;
+
+namespace Azure.Mcp.Tools.AzureBackup.Commands.Governance;
+
+public sealed class GovernanceSoftDeleteCommand(ILogger logger) : BaseAzureBackupCommand()
+{
+ private const string CommandTitle = "Configure Soft Delete";
+ private readonly ILogger _logger = logger;
+
+ public override string Id => "b1a2c3d4-e5f6-7890-abcd-ef12345678cb";
+ public override string Name => "soft-delete";
+ public override string Description =>
+ """
+ Configures the soft delete settings for a backup vault. Set the state to 'AlwaysOn', 'On',
+ or 'Off', and optionally specify the retention period in days (14-180).
+ """;
+ public override string Title => CommandTitle;
+ public override ToolMetadata Metadata => new()
+ {
+ Destructive = true, Idempotent = true, OpenWorld = false,
+ ReadOnly = false, LocalRequired = false, Secret = false
+ };
+
+ protected override void RegisterOptions(Command command)
+ {
+ base.RegisterOptions(command);
+ command.Options.Add(AzureBackupOptionDefinitions.SoftDelete);
+ command.Options.Add(AzureBackupOptionDefinitions.SoftDeleteRetentionDays);
+ }
+
+ protected override GovernanceSoftDeleteOptions BindOptions(ParseResult parseResult)
+ {
+ var options = base.BindOptions(parseResult);
+ options.SoftDeleteState = parseResult.GetValueOrDefault(AzureBackupOptionDefinitions.SoftDelete.Name);
+ options.SoftDeleteRetentionDays = parseResult.GetValueOrDefault(AzureBackupOptionDefinitions.SoftDeleteRetentionDays.Name);
+ return options;
+ }
+
+ public override async Task ExecuteAsync(CommandContext context, ParseResult parseResult, CancellationToken cancellationToken)
+ {
+ if (!Validate(parseResult.CommandResult, context.Response).IsValid)
+ {
+ return context.Response;
+ }
+
+ var options = BindOptions(parseResult);
+
+ try
+ {
+ var service = context.GetService();
+ var result = await service.ConfigureSoftDeleteAsync(
+ options.Vault!,
+ options.ResourceGroup!,
+ options.Subscription!,
+ options.SoftDeleteState!,
+ options.SoftDeleteRetentionDays,
+ options.VaultType,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+
+ context.Response.Results = ResponseResult.Create(
+ new GovernanceSoftDeleteCommandResult(result),
+ AzureBackupJsonContext.Default.GovernanceSoftDeleteCommandResult);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error configuring soft delete. Vault: {Vault}, State: {SoftDeleteState}",
+ options.Vault, options.SoftDeleteState);
+ HandleException(context, ex);
+ }
+
+ return context.Response;
+ }
+
+ protected override string GetErrorMessage(Exception ex) => ex switch
+ {
+ ArgumentException argEx => argEx.Message,
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.NotFound =>
+ "Vault not found. Verify the vault name and resource group.",
+ RequestFailedException reqEx => reqEx.Message,
+ _ => base.GetErrorMessage(ex)
+ };
+
+ internal record GovernanceSoftDeleteCommandResult([property: JsonPropertyName("result")] OperationResult Result);
+}
diff --git a/tools/Azure.Mcp.Tools.AzureBackup/src/Commands/Job/JobGetCommand.cs b/tools/Azure.Mcp.Tools.AzureBackup/src/Commands/Job/JobGetCommand.cs
new file mode 100644
index 0000000000..dfee1fcb4d
--- /dev/null
+++ b/tools/Azure.Mcp.Tools.AzureBackup/src/Commands/Job/JobGetCommand.cs
@@ -0,0 +1,118 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Net;
+using System.Text.Json.Serialization;
+using Azure.Mcp.Core.Extensions;
+using Azure.Mcp.Tools.AzureBackup.Models;
+using Azure.Mcp.Tools.AzureBackup.Options;
+using Azure.Mcp.Tools.AzureBackup.Options.Job;
+using Azure.Mcp.Tools.AzureBackup.Services;
+using Microsoft.Extensions.Logging;
+using Microsoft.Mcp.Core.Commands;
+using Microsoft.Mcp.Core.Models.Command;
+using Microsoft.Mcp.Core.Models.Option;
+
+namespace Azure.Mcp.Tools.AzureBackup.Commands.Job;
+
+///
+/// Consolidated job command: when --job is supplied returns a single job's details;
+/// otherwise lists all jobs in the vault.
+///
+public sealed class JobGetCommand(ILogger logger) : BaseAzureBackupCommand()
+{
+ private const string CommandTitle = "Get Backup Job";
+ private readonly ILogger _logger = logger;
+
+ public override string Id => "b1a2c3d4-e5f6-7890-abcd-ef1234567896";
+ public override string Name => "get";
+ public override string Description =>
+ """
+ Retrieves backup job information. When --job is specified, returns detailed information
+ about a single job including operation type, status, start/end times, error codes, and
+ datasource details. When omitted, lists all backup jobs in the vault.
+ """;
+ public override string Title => CommandTitle;
+ public override ToolMetadata Metadata => new()
+ {
+ Destructive = false, Idempotent = true, OpenWorld = false,
+ ReadOnly = true, LocalRequired = false, Secret = false
+ };
+
+ protected override void RegisterOptions(Command command)
+ {
+ base.RegisterOptions(command);
+ command.Options.Add(AzureBackupOptionDefinitions.Job.AsOptional());
+ }
+
+ protected override JobGetOptions BindOptions(ParseResult parseResult)
+ {
+ var options = base.BindOptions(parseResult);
+ options.Job = parseResult.GetValueOrDefault(AzureBackupOptionDefinitions.Job.Name);
+ return options;
+ }
+
+ public override async Task ExecuteAsync(CommandContext context, ParseResult parseResult, CancellationToken cancellationToken)
+ {
+ if (!Validate(parseResult.CommandResult, context.Response).IsValid)
+ {
+ return context.Response;
+ }
+
+ var options = BindOptions(parseResult);
+
+ try
+ {
+ var service = context.GetService();
+
+ if (!string.IsNullOrEmpty(options.Job))
+ {
+ var job = await service.GetJobAsync(
+ options.Vault!,
+ options.ResourceGroup!,
+ options.Subscription!,
+ options.Job,
+ options.VaultType,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+
+ context.Response.Results = ResponseResult.Create(
+ new JobGetCommandResult([job]),
+ AzureBackupJsonContext.Default.JobGetCommandResult);
+ }
+ else
+ {
+ var jobs = await service.ListJobsAsync(
+ options.Vault!,
+ options.ResourceGroup!,
+ options.Subscription!,
+ options.VaultType,
+ options.Tenant,
+ options.RetryPolicy,
+ cancellationToken);
+
+ context.Response.Results = ResponseResult.Create(
+ new JobGetCommandResult(jobs),
+ AzureBackupJsonContext.Default.JobGetCommandResult);
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error getting job(s). Job: {Job}, Vault: {Vault}", options.Job, options.Vault);
+ HandleException(context, ex);
+ }
+
+ return context.Response;
+ }
+
+ protected override string GetErrorMessage(Exception ex) => ex switch
+ {
+ RequestFailedException reqEx when reqEx.Status == (int)HttpStatusCode.NotFound =>
+ "Job not found. Verify the job ID and vault.",
+ RequestFailedException reqEx => reqEx.Message,
+ _ => base.GetErrorMessage(ex)
+ };
+
+ internal record JobGetCommandResult([property: JsonPropertyName("jobs")] List