Skip to content
This repository was archived by the owner on Sep 4, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
7bed346
Initial plan
Copilot Aug 6, 2025
c33d546
Fix AppConfig service subscription parameter handling
Copilot Aug 6, 2025
69cb5f0
Fix Redis and start Storage service subscription parameter handling
Copilot Aug 6, 2025
47c8263
Complete Storage service subscription parameter handling
Copilot Aug 6, 2025
f99ff05
Complete Cosmos and Workbooks services subscription parameter handling
Copilot Aug 6, 2025
7a00a59
Complete final services subscription parameter handling - Grafana, Ku…
Copilot Aug 6, 2025
6ed4ff5
Update documentation for subscription parameter handling pattern
Copilot Aug 6, 2025
f793114
Add initial devcontainer configuration for Azure MCP Codespace
jongio Aug 6, 2025
bbe1160
Refactor test method parameters for consistency and clarity in Access…
jongio Aug 6, 2025
f5f760c
Add "Codespace" and "devcontainers" to cspell dictionary
jongio Aug 6, 2025
2731d73
Fix formatting issues: whitespace in StorageService and NSubstitute a…
Copilot Aug 6, 2025
e52e932
Fix test parameter specificity: restore original concrete values in A…
Copilot Aug 6, 2025
1baf74f
Fix dotnet format whitespace issue: remove trailing space in AccessPo…
Copilot Aug 6, 2025
78850af
Merge branch 'copilot/fix-877' of https://github.com/Azure/azure-mcp …
jongio Aug 6, 2025
d32fffc
Merge
jongio Aug 6, 2025
f04734d
Merge branch 'main' into copilot/fix-877
jongio Aug 7, 2025
1dcaa26
Update cspell configuration: add exclusions for .devcontainer and new…
jongio Aug 7, 2025
32418c4
Remove obsolete files related to Container Apps service and documenta…
jongio Aug 7, 2025
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ The Azure MCP Server updates automatically by default whenever a new release com

### Bugs Fixed

- Fixed subscription parameter handling across all Azure MCP service methods to consistently use `subscription` instead of `subscriptionId`, enabling proper support for both subscription IDs and subscription names. [[#877](https://github.com/Azure/azure-mcp/issues/877)]

### Other Changes

## 0.5.3 (2025-08-05)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ public class AppConfigService(ISubscriptionService subscriptionService, ITenantS
{
private readonly ISubscriptionService _subscriptionService = subscriptionService ?? throw new ArgumentNullException(nameof(subscriptionService));

public async Task<List<AppConfigurationAccount>> GetAppConfigAccounts(string subscriptionId, string? tenant = null, RetryPolicyOptions? retryPolicy = null)
public async Task<List<AppConfigurationAccount>> GetAppConfigAccounts(string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null)
{
ValidateRequiredParameters(subscriptionId);
ValidateRequiredParameters(subscription);

var subscription = await _subscriptionService.GetSubscription(subscriptionId, tenant, retryPolicy);
var subscriptionResource = await _subscriptionService.GetSubscription(subscription, tenant, retryPolicy);
var accounts = new List<AppConfigurationAccount>();

await foreach (var account in subscription.GetAppConfigurationStoresAsync())
await foreach (var account in subscriptionResource.GetAppConfigurationStoresAsync())
{
ResourceIdentifier resourceId = account.Id;
if (resourceId.ToString().Length == 0)
Expand Down Expand Up @@ -81,15 +81,15 @@ public async Task<List<AppConfigurationAccount>> GetAppConfigAccounts(string sub

public async Task<List<KeyValueSetting>> ListKeyValues(
string accountName,
string subscriptionId,
string subscription,
string? key = null,
string? label = null,
string? tenant = null,
RetryPolicyOptions? retryPolicy = null)
{
ValidateRequiredParameters(accountName, subscriptionId);
ValidateRequiredParameters(accountName, subscription);

var client = await GetConfigurationClient(accountName, subscriptionId, tenant, retryPolicy);
var client = await GetConfigurationClient(accountName, subscription, tenant, retryPolicy);
var settings = new List<KeyValueSetting>();

var selector = new SettingSelector
Expand All @@ -115,10 +115,10 @@ public async Task<List<KeyValueSetting>> ListKeyValues(
return settings;
}

public async Task<KeyValueSetting> GetKeyValue(string accountName, string key, string subscriptionId, string? tenant = null, RetryPolicyOptions? retryPolicy = null, string? label = null, string? contentType = null)
public async Task<KeyValueSetting> GetKeyValue(string accountName, string key, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, string? label = null, string? contentType = null)
{
ValidateRequiredParameters(accountName, key, subscriptionId);
var client = await GetConfigurationClient(accountName, subscriptionId, tenant, retryPolicy);
ValidateRequiredParameters(accountName, key, subscription);
var client = await GetConfigurationClient(accountName, subscription, tenant, retryPolicy);
var response = await client.GetConfigurationSettingAsync(key, label, cancellationToken: default);
var setting = response.Value;

Expand All @@ -134,20 +134,20 @@ public async Task<KeyValueSetting> GetKeyValue(string accountName, string key, s
};
}

public async Task LockKeyValue(string accountName, string key, string subscriptionId, string? tenant = null, RetryPolicyOptions? retryPolicy = null, string? label = null)
public async Task LockKeyValue(string accountName, string key, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, string? label = null)
{
await SetKeyValueReadOnlyState(accountName, key, subscriptionId, tenant, retryPolicy, label, true);
await SetKeyValueReadOnlyState(accountName, key, subscription, tenant, retryPolicy, label, true);
}

public async Task UnlockKeyValue(string accountName, string key, string subscriptionId, string? tenant = null, RetryPolicyOptions? retryPolicy = null, string? label = null)
public async Task UnlockKeyValue(string accountName, string key, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, string? label = null)
{
await SetKeyValueReadOnlyState(accountName, key, subscriptionId, tenant, retryPolicy, label, false);
await SetKeyValueReadOnlyState(accountName, key, subscription, tenant, retryPolicy, label, false);
}

public async Task SetKeyValue(string accountName, string key, string value, string subscriptionId, string? tenant = null, RetryPolicyOptions? retryPolicy = null, string? label = null, string? contentType = null, string[]? tags = null)
public async Task SetKeyValue(string accountName, string key, string value, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, string? label = null, string? contentType = null, string[]? tags = null)
{
ValidateRequiredParameters(accountName, key, value, subscriptionId);
var client = await GetConfigurationClient(accountName, subscriptionId, tenant, retryPolicy);
ValidateRequiredParameters(accountName, key, value, subscription);
var client = await GetConfigurationClient(accountName, subscription, tenant, retryPolicy);

// Create a ConfigurationSetting object to include contentType if provided
var setting = new ConfigurationSetting(key, value, label)
Expand Down Expand Up @@ -179,32 +179,32 @@ public async Task SetKeyValue(string accountName, string key, string value, stri

await client.SetConfigurationSettingAsync(setting, cancellationToken: default);
}
public async Task DeleteKeyValue(string accountName, string key, string subscriptionId, string? tenant = null, RetryPolicyOptions? retryPolicy = null, string? label = null)
public async Task DeleteKeyValue(string accountName, string key, string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null, string? label = null)
{
ValidateRequiredParameters(accountName, key, subscriptionId);
var client = await GetConfigurationClient(accountName, subscriptionId, tenant, retryPolicy);
ValidateRequiredParameters(accountName, key, subscription);
var client = await GetConfigurationClient(accountName, subscription, tenant, retryPolicy);
await client.DeleteConfigurationSettingAsync(key, label, cancellationToken: default);
}

private async Task SetKeyValueReadOnlyState(string accountName, string key, string subscriptionId, string? tenant, RetryPolicyOptions? retryPolicy, string? label, bool isReadOnly)
private async Task SetKeyValueReadOnlyState(string accountName, string key, string subscription, string? tenant, RetryPolicyOptions? retryPolicy, string? label, bool isReadOnly)
{
ValidateRequiredParameters(accountName, key, subscriptionId);
var client = await GetConfigurationClient(accountName, subscriptionId, tenant, retryPolicy);
ValidateRequiredParameters(accountName, key, subscription);
var client = await GetConfigurationClient(accountName, subscription, tenant, retryPolicy);
await client.SetReadOnlyAsync(key, label, isReadOnly, cancellationToken: default);
}

private async Task<ConfigurationClient> GetConfigurationClient(string accountName, string subscriptionId, string? tenant, RetryPolicyOptions? retryPolicy)
private async Task<ConfigurationClient> GetConfigurationClient(string accountName, string subscription, string? tenant, RetryPolicyOptions? retryPolicy)
{
var subscription = await _subscriptionService.GetSubscription(subscriptionId, tenant, retryPolicy);
var configStore = await FindAppConfigStore(subscription, accountName, subscriptionId);
var subscriptionResource = await _subscriptionService.GetSubscription(subscription, tenant, retryPolicy);
var configStore = await FindAppConfigStore(subscriptionResource, accountName, subscription);
var endpoint = configStore.Data.Endpoint;
var credential = await GetCredential(tenant);
AddDefaultPolicies(new ConfigurationClientOptions());

return new ConfigurationClient(new Uri(endpoint), credential);
}

private static async Task<AppConfigurationStoreResource> FindAppConfigStore(SubscriptionResource subscription, string accountName, string subscriptionId)
private static async Task<AppConfigurationStoreResource> FindAppConfigStore(SubscriptionResource subscription, string accountName, string subscriptionIdentifier)
{
AppConfigurationStoreResource? configStore = null;
await foreach (var store in subscription.GetAppConfigurationStoresAsync())
Expand All @@ -217,7 +217,7 @@ private static async Task<AppConfigurationStoreResource> FindAppConfigStore(Subs
}

if (configStore == null)
throw new Exception($"App Configuration store '{accountName}' not found in subscription '{subscriptionId}'");
throw new Exception($"App Configuration store '{accountName}' not found in subscription '{subscriptionIdentifier}'");

return configStore;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,42 +9,42 @@ namespace AzureMcp.AppConfig.Services;
public interface IAppConfigService
{
Task<List<AppConfigurationAccount>> GetAppConfigAccounts(
string subscriptionId,
string subscription,
string? tenant = null,
RetryPolicyOptions? retryPolicy = null);
Task<List<KeyValueSetting>> ListKeyValues(
string accountName,
string subscriptionId,
string subscription,
string? key = null, string? label = null,
string? tenant = null,
RetryPolicyOptions? retryPolicy = null);
Task<KeyValueSetting> GetKeyValue(
string accountName,
string key,
string subscriptionId,
string subscription,
string? tenant = null,
RetryPolicyOptions? retryPolicy = null,
string? label = null,
string? contentType = null);
Task LockKeyValue(
string accountName,
string key,
string subscriptionId,
string subscription,
string? tenant = null,
RetryPolicyOptions? retryPolicy = null,
string? label = null);
Task UnlockKeyValue(
string accountName,
string key,
string subscriptionId,
string subscription,
string? tenant = null,
RetryPolicyOptions? retryPolicy = null,
string? label = null);
Task SetKeyValue(
string accountName,
string key,
string value,
string subscriptionId,
string subscription,
string? tenant = null,
RetryPolicyOptions? retryPolicy = null,
string? label = null,
Expand All @@ -53,7 +53,7 @@ Task SetKeyValue(
Task DeleteKeyValue(
string accountName,
string key,
string subscriptionId,
string subscription,
string? tenant = null,
RetryPolicyOptions? retryPolicy = null,
string? label = null);
Expand Down
48 changes: 24 additions & 24 deletions areas/cosmos/src/AzureMcp.Cosmos/Services/CosmosService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,28 +25,28 @@ public class CosmosService(ISubscriptionService subscriptionService, ITenantServ
private bool _disposed;

private async Task<CosmosDBAccountResource> GetCosmosAccountAsync(
string subscriptionId,
string subscription,
string accountName,
string? tenant = null,
RetryPolicyOptions? retryPolicy = null)
{
ValidateRequiredParameters(subscriptionId, accountName);
ValidateRequiredParameters(subscription, accountName);

var subscription = await _subscriptionService.GetSubscription(subscriptionId, tenant, retryPolicy);
var subscriptionResource = await _subscriptionService.GetSubscription(subscription, tenant, retryPolicy);

await foreach (var account in subscription.GetCosmosDBAccountsAsync())
await foreach (var account in subscriptionResource.GetCosmosDBAccountsAsync())
{
if (account.Data.Name == accountName)
{
return account;
}
}
throw new Exception($"Cosmos DB account '{accountName}' not found in subscription '{subscriptionId}'");
throw new Exception($"Cosmos DB account '{accountName}' not found in subscription '{subscription}'");
}

private async Task<CosmosClient> CreateCosmosClientWithAuth(
string accountName,
string subscriptionId,
string subscription,
AuthMethod authMethod,
string? tenant = null,
RetryPolicyOptions? retryPolicy = null)
Expand All @@ -65,7 +65,7 @@ private async Task<CosmosClient> CreateCosmosClientWithAuth(
switch (authMethod)
{
case AuthMethod.Key:
var cosmosAccount = await GetCosmosAccountAsync(subscriptionId, accountName, tenant);
var cosmosAccount = await GetCosmosAccountAsync(subscription, accountName, tenant);
var keys = await cosmosAccount.GetKeysAsync();
cosmosClient = new CosmosClient(
string.Format(CosmosBaseUri, accountName),
Expand Down Expand Up @@ -107,12 +107,12 @@ private async Task ValidateCosmosClientAsync(CosmosClient client)

private async Task<CosmosClient> GetCosmosClientAsync(
string accountName,
string subscriptionId,
string subscription,
AuthMethod authMethod = AuthMethod.Credential,
string? tenant = null,
RetryPolicyOptions? retryPolicy = null)
{
ValidateRequiredParameters(accountName, subscriptionId);
ValidateRequiredParameters(accountName, subscription);

var key = CosmosClientsCacheKeyPrefix + accountName;
var cosmosClient = await _cacheService.GetAsync<CosmosClient>(CacheGroup, key, s_cacheDurationResources);
Expand All @@ -124,7 +124,7 @@ private async Task<CosmosClient> GetCosmosClientAsync(
// First attempt with requested auth method
cosmosClient = await CreateCosmosClientWithAuth(
accountName,
subscriptionId,
subscription,
authMethod,
tenant,
retryPolicy);
Expand All @@ -139,7 +139,7 @@ private async Task<CosmosClient> GetCosmosClientAsync(
// If credential auth fails with 401/403, try key auth
cosmosClient = await CreateCosmosClientWithAuth(
accountName,
subscriptionId,
subscription,
AuthMethod.Key,
tenant,
retryPolicy);
Expand All @@ -151,15 +151,15 @@ private async Task<CosmosClient> GetCosmosClientAsync(
throw new Exception($"Failed to create Cosmos client for account '{accountName}' with any authentication method");
}

public async Task<List<string>> GetCosmosAccounts(string subscriptionId, string? tenant = null, RetryPolicyOptions? retryPolicy = null)
public async Task<List<string>> GetCosmosAccounts(string subscription, string? tenant = null, RetryPolicyOptions? retryPolicy = null)
{
ValidateRequiredParameters(subscriptionId);
ValidateRequiredParameters(subscription);

var subscription = await _subscriptionService.GetSubscription(subscriptionId, tenant, retryPolicy);
var subscriptionResource = await _subscriptionService.GetSubscription(subscription, tenant, retryPolicy);
var accounts = new List<string>();
try
{
await foreach (var account in subscription.GetCosmosDBAccountsAsync())
await foreach (var account in subscriptionResource.GetCosmosDBAccountsAsync())
{
if (account?.Data?.Name != null)
{
Expand All @@ -177,12 +177,12 @@ public async Task<List<string>> GetCosmosAccounts(string subscriptionId, string?

public async Task<List<string>> ListDatabases(
string accountName,
string subscriptionId,
string subscription,
AuthMethod authMethod = AuthMethod.Credential,
string? tenant = null,
RetryPolicyOptions? retryPolicy = null)
{
ValidateRequiredParameters(accountName, subscriptionId);
ValidateRequiredParameters(accountName, subscription);

var cacheKey = CosmosDatabasesCacheKeyPrefix + accountName;

Expand All @@ -192,7 +192,7 @@ public async Task<List<string>> ListDatabases(
return cachedDatabases;
}

var client = await GetCosmosClientAsync(accountName, subscriptionId, authMethod, tenant, retryPolicy);
var client = await GetCosmosClientAsync(accountName, subscription, authMethod, tenant, retryPolicy);
var databases = new List<string>();

try
Expand All @@ -216,12 +216,12 @@ public async Task<List<string>> ListDatabases(
public async Task<List<string>> ListContainers(
string accountName,
string databaseName,
string subscriptionId,
string subscription,
AuthMethod authMethod = AuthMethod.Credential,
string? tenant = null,
RetryPolicyOptions? retryPolicy = null)
{
ValidateRequiredParameters(accountName, databaseName, subscriptionId);
ValidateRequiredParameters(accountName, databaseName, subscription);

var cacheKey = CosmosContainersCacheKeyPrefix + accountName + "_" + databaseName;

Expand All @@ -231,7 +231,7 @@ public async Task<List<string>> ListContainers(
return cachedContainers;
}

var client = await GetCosmosClientAsync(accountName, subscriptionId, authMethod, tenant, retryPolicy);
var client = await GetCosmosClientAsync(accountName, subscription, authMethod, tenant, retryPolicy);
var containers = new List<string>();

try
Expand All @@ -258,14 +258,14 @@ public async Task<List<JsonElement>> QueryItems(
string databaseName,
string containerName,
string? query,
string subscriptionId,
string subscription,
AuthMethod authMethod = AuthMethod.Credential,
string? tenant = null,
RetryPolicyOptions? retryPolicy = null)
{
ValidateRequiredParameters(accountName, databaseName, containerName, subscriptionId);
ValidateRequiredParameters(accountName, databaseName, containerName, subscription);

var client = await GetCosmosClientAsync(accountName, subscriptionId, authMethod, tenant, retryPolicy);
var client = await GetCosmosClientAsync(accountName, subscription, authMethod, tenant, retryPolicy);

try
{
Expand Down
8 changes: 4 additions & 4 deletions areas/cosmos/src/AzureMcp.Cosmos/Services/ICosmosService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,21 @@ namespace AzureMcp.Cosmos.Services;
public interface ICosmosService : IDisposable
{
Task<List<string>> GetCosmosAccounts(
string subscriptionId,
string subscription,
string? tenant = null,
RetryPolicyOptions? retryPolicy = null);

Task<List<string>> ListDatabases(
string accountName,
string subscriptionId,
string subscription,
AuthMethod authMethod = AuthMethod.Credential,
string? tenant = null,
RetryPolicyOptions? retryPolicy = null);

Task<List<string>> ListContainers(
string accountName,
string databaseName,
string subscriptionId,
string subscription,
AuthMethod authMethod = AuthMethod.Credential,
string? tenant = null,
RetryPolicyOptions? retryPolicy = null);
Expand All @@ -34,7 +34,7 @@ Task<List<JsonElement>> QueryItems(
string databaseName,
string containerName,
string? query,
string subscriptionId,
string subscription,
AuthMethod authMethod = AuthMethod.Credential,
string? tenant = null,
RetryPolicyOptions? retryPolicy = null);
Expand Down
Loading
Loading