Skip to content
This repository was archived by the owner on Sep 4, 2025. It is now read-only.

Commit 70d61f3

Browse files
authored
Using ARG query to support Sql resource read operations (#938)
* Using ARG query to list & get Sql data * update * update * update doc * update * update * update * update * update * update * update * update * update * revert vscode/README.md * udpate * update * update changelog * update changelog * update checklist * Update the identify unused properteis check * update * fix typo * update changelog
1 parent cded84b commit 70d61f3

28 files changed

+1176
-218
lines changed

.vscode/cspell.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
"Groq",
7070
"HKCU",
7171
"HKEY_CURRENT_USER",
72+
"Hyperscale",
7273
"Intune",
7374
"LASTEXITCODE",
7475
"LPUTF8Str",
@@ -110,6 +111,7 @@
110111
"contentfiles",
111112
"credscan",
112113
"cslschema",
114+
"cutover",
113115
"datatable",
114116
"datistemplate",
115117
"datname",

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,22 @@ The Azure MCP Server updates automatically by default whenever a new release com
66

77
### Features Added
88

9+
- Introduced `BaseAzureResourceService` class to perform Azure Resource read operations using Azure Resource Graph queries. [[#938](https://github.com/Azure/azure-mcp/pull/938)]
10+
911
### Breaking Changes
1012

1113
### Bugs Fixed
1214

15+
- Fixed SQL service test assertions to use case-insensitive string comparisons for resource type validation. [[#938](https://github.com/Azure/azure-mcp/pull/938)]
16+
- Fixed HttpClient service test assertions to properly validate NoProxy collection handling instead of expecting a single string value. [[#938](https://github.com/Azure/azure-mcp/pull/938)]
17+
1318
### Other Changes
1419

20+
- Refactored SQL service implementation to use Azure Resource Graph queries instead of direct ARM API calls. [[#938](https://github.com/Azure/azure-mcp/pull/938)]
21+
- Removed dependency on `Azure.ResourceManager.Sql` package by migrating to Azure Resource Graph queries, reducing package size and improving startup performance.
22+
- Enhanced `BaseAzureService` with `EscapeKqlString` method for safe KQL query construction across all Azure services. [[#938](https://github.com/Azure/azure-mcp/pull/938)]
23+
- Fixed KQL string escaping in Workbooks service queries.
24+
1525
## 0.5.7 (2025-08-19)
1626

1727
### Features Added

Directory.Packages.props

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
<PackageVersion Include="Azure.ResourceManager.RedisEnterprise" Version="1.2.1" />
3737
<PackageVersion Include="Azure.ResourceManager.ResourceHealth" Version="1.0.0" />
3838
<PackageVersion Include="Azure.ResourceManager.LoadTesting" Version="1.1.2" />
39-
<PackageVersion Include="Azure.ResourceManager.Sql" Version="1.4.0-beta.3" />
4039
<PackageVersion Include="Azure.ResourceManager.Network" Version="1.11.2" />
4140
<PackageVersion Include="Azure.ResourceManager.MachineLearning" Version="1.2.3" />
4241
<PackageVersion Include="Azure.Security.KeyVault.Keys" Version="4.7.0" />

areas/sql/src/AzureMcp.Sql/AzureMcp.Sql.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
<ItemGroup />
1313
<ItemGroup>
1414
<PackageReference Include="Azure.ResourceManager" />
15-
<PackageReference Include="Azure.ResourceManager.Sql" />
1615
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
1716
<PackageReference Include="ModelContextProtocol" />
1817
<PackageReference Include="System.CommandLine" />

areas/sql/src/AzureMcp.Sql/Commands/Database/DatabaseShowCommand.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,6 @@ public override async Task<CommandResponse> ExecuteAsync(CommandContext context,
5353
options.Subscription!,
5454
options.RetryPolicy);
5555

56-
if (database == null)
57-
{
58-
context.Response.Status = 404;
59-
context.Response.Message = $"Database '{options.Database}' not found on server '{options.Server}' in resource group '{options.ResourceGroup}'.";
60-
return context.Response;
61-
}
62-
6356
context.Response.Results = ResponseResult.Create(
6457
new DatabaseShowResult(database),
6558
SqlJsonContext.Default.DatabaseShowResult);
@@ -77,6 +70,7 @@ public override async Task<CommandResponse> ExecuteAsync(CommandContext context,
7770

7871
protected override string GetErrorMessage(Exception ex) => ex switch
7972
{
73+
KeyNotFoundException => $"SQL database not found. Verify the database name, server name, resource group, and that you have access.",
8074
Azure.RequestFailedException reqEx when reqEx.Status == 404 =>
8175
"Database or server not found. Verify the database name, server name, resource group, and that you have access.",
8276
Azure.RequestFailedException reqEx when reqEx.Status == 403 =>
@@ -87,6 +81,7 @@ public override async Task<CommandResponse> ExecuteAsync(CommandContext context,
8781

8882
protected override int GetStatusCode(Exception ex) => ex switch
8983
{
84+
KeyNotFoundException => 404,
9085
Azure.RequestFailedException reqEx => reqEx.Status,
9186
_ => base.GetStatusCode(ex)
9287
};

areas/sql/src/AzureMcp.Sql/Commands/SqlJsonContext.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using AzureMcp.Sql.Commands.EntraAdmin;
88
using AzureMcp.Sql.Commands.FirewallRule;
99
using AzureMcp.Sql.Models;
10+
using AzureMcp.Sql.Services.Models;
1011

1112
namespace AzureMcp.Sql.Commands;
1213

@@ -22,6 +23,13 @@ namespace AzureMcp.Sql.Commands;
2223
[JsonSerializable(typeof(DatabaseSku))]
2324
[JsonSerializable(typeof(ElasticPoolSku))]
2425
[JsonSerializable(typeof(ElasticPoolPerDatabaseSettings))]
26+
[JsonSerializable(typeof(SqlDatabaseData))]
27+
[JsonSerializable(typeof(SqlDatabaseProperties))]
28+
[JsonSerializable(typeof(SqlServerAadAdministratorData))]
29+
[JsonSerializable(typeof(SqlElasticPoolData))]
30+
[JsonSerializable(typeof(SqlElasticPoolProperties))]
31+
[JsonSerializable(typeof(SqlElasticPoolPerDatabaseSettings))]
32+
[JsonSerializable(typeof(SqlFirewallRuleData))]
2533
[JsonSourceGenerationOptions(
2634
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
2735
WriteIndented = true,

areas/sql/src/AzureMcp.Sql/Services/ISqlService.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ public interface ISqlService
1717
/// <param name="subscription">The subscription ID or name</param>
1818
/// <param name="retryPolicy">Optional retry policy options</param>
1919
/// <param name="cancellationToken">Cancellation token</param>
20-
/// <returns>The SQL database information, or null if not found</returns>
21-
Task<SqlDatabase?> GetDatabaseAsync(
20+
/// <returns>The SQL database information</returns>
21+
/// <exception cref="KeyNotFoundException">Thrown when the database is not found</exception>
22+
Task<SqlDatabase> GetDatabaseAsync(
2223
string serverName,
2324
string databaseName,
2425
string resourceGroup,
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System.Text.Json;
5+
using System.Text.Json.Serialization;
6+
using AzureMcp.Sql.Commands;
7+
8+
namespace AzureMcp.Sql.Services.Models
9+
{
10+
/// <summary>
11+
/// A class representing the SqlDatabase data model.
12+
/// A database resource.
13+
/// </summary>
14+
internal sealed class SqlDatabaseData
15+
{
16+
/// <summary> The resource ID for the resource. </summary>
17+
[JsonPropertyName("id")]
18+
public string? ResourceId { get; set; }
19+
/// <summary> The type of the resource. </summary>
20+
[JsonPropertyName("type")]
21+
public string? ResourceType { get; set; }
22+
/// <summary> The name of the resource. </summary>
23+
[JsonPropertyName("name")]
24+
public string? ResourceName { get; set; }
25+
/// <summary> The location of the resource. </summary>
26+
public string? Location { get; set; }
27+
/// <summary> The database SKU. </summary>
28+
public SqlSku? Sku { get; set; }
29+
/// <summary> Properties of the Sql database. </summary>
30+
public SqlDatabaseProperties? Properties { get; set; }
31+
32+
// Read the JSON response content and create a model instance from it.
33+
public static SqlDatabaseData? FromJson(JsonElement source)
34+
{
35+
return JsonSerializer.Deserialize<SqlDatabaseData>(source, SqlJsonContext.Default.SqlDatabaseData);
36+
}
37+
}
38+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
using System.Text.Json.Serialization;
4+
5+
namespace AzureMcp.Sql.Services.Models
6+
{
7+
/// <summary>
8+
/// A class representing the SqlDatabase properties model.
9+
/// A database resource properties.
10+
/// </summary>
11+
internal sealed class SqlDatabaseProperties
12+
{
13+
/// <summary> The collation of the database. </summary>
14+
public string? Collation { get; set; }
15+
/// <summary> The max size of the database expressed in bytes. </summary>
16+
public long? MaxSizeBytes { get; set; }
17+
/// <summary> The resource identifier of the elastic pool containing this database. </summary>
18+
public string? ElasticPoolId { get; set; }
19+
/// <summary> The status of the database. </summary>
20+
public string? Status { get; set; }
21+
/// <summary> The creation date of the database (ISO8601 format). </summary>
22+
[JsonPropertyName("creationDate")]
23+
public DateTimeOffset? CreatedOn { get; set; }
24+
/// <summary> The current service level objective name of the database. </summary>
25+
public string? CurrentServiceObjectiveName { get; set; }
26+
/// <summary> The license type to apply for this database. `LicenseIncluded` if you need a license, or `BasePrice` if you have a license and are eligible for the Azure Hybrid Benefit. </summary>
27+
public string? LicenseType { get; set; }
28+
/// <summary> This records the earliest start date and time that restore is available for this database (ISO8601 format). </summary>
29+
[JsonPropertyName("earliestRestoreDate")]
30+
public DateTimeOffset? EarliestRestoreOn { get; set; }
31+
/// <summary> The state of read-only routing. If enabled, connections that have application intent set to readonly in their connection string may be routed to a readonly secondary replica in the same region. Not applicable to a Hyperscale database within an elastic pool. </summary>
32+
public string? ReadScale { get; set; }
33+
/// <summary> Whether or not this database is zone redundant, which means the replicas of this database will be spread across multiple availability zones. </summary>
34+
public bool? IsZoneRedundant { get; set; }
35+
/// <summary> The name and tier of the SKU. </summary>
36+
public SqlSku? CurrentSku { get; set; }
37+
}
38+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System.Text.Json;
5+
using System.Text.Json.Serialization;
6+
using AzureMcp.Sql.Commands;
7+
8+
namespace AzureMcp.Sql.Services.Models
9+
{
10+
/// <summary>
11+
/// A class representing the ElasticPool data model.
12+
/// An elastic pool.
13+
/// </summary>
14+
internal sealed class SqlElasticPoolData
15+
{
16+
/// <summary> The resource ID for the resource. </summary>
17+
[JsonPropertyName("id")]
18+
public string? ResourceId { get; set; }
19+
/// <summary> The type of the resource. </summary>
20+
[JsonPropertyName("type")]
21+
public string? ResourceType { get; set; }
22+
/// <summary> The name of the resource. </summary>
23+
[JsonPropertyName("name")]
24+
public string? ResourceName { get; set; }
25+
/// <summary> The location of the resource. </summary>
26+
public string? Location { get; set; }
27+
/// <summary> The database SKU. </summary>
28+
public SqlSku? Sku { get; set; }
29+
/// <summary> The properties of elastic pool. </summary>
30+
public SqlElasticPoolProperties? Properties { get; set; }
31+
32+
// Read the JSON response content and create a model instance from it.
33+
public static SqlElasticPoolData? FromJson(JsonElement source)
34+
{
35+
return JsonSerializer.Deserialize<SqlElasticPoolData>(source, SqlJsonContext.Default.SqlElasticPoolData);
36+
}
37+
}
38+
}

0 commit comments

Comments
 (0)