diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.UnitTests/Areas/Server/CommandFactoryHelpers.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.UnitTests/Areas/Server/CommandFactoryHelpers.cs index 929cf089eb..96d4c4d37e 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.UnitTests/Areas/Server/CommandFactoryHelpers.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.UnitTests/Areas/Server/CommandFactoryHelpers.cs @@ -41,6 +41,7 @@ using Azure.Mcp.Tools.Storage; using Azure.Mcp.Tools.VirtualDesktop; using Azure.Mcp.Tools.Workbooks; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Mcp.Core.Areas; @@ -160,6 +161,7 @@ public static IServiceCollection SetupCommonServices() var builder = new ServiceCollection() .AddLogging() + .AddSingleton(new ConfigurationBuilder().AddEnvironmentVariables().Build()) .AddSingleton(); foreach (var area in areaSetups) diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.UnitTests/Areas/Server/Commands/Discovery/RegistryServerProviderTests.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.UnitTests/Areas/Server/Commands/Discovery/RegistryServerProviderTests.cs index 27b68ee830..b3bfb0015d 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.UnitTests/Areas/Server/Commands/Discovery/RegistryServerProviderTests.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.UnitTests/Areas/Server/Commands/Discovery/RegistryServerProviderTests.cs @@ -5,6 +5,7 @@ using System.Net.Sockets; using Azure.Mcp.Core.Areas.Server.Commands.Discovery; using Azure.Mcp.Core.Areas.Server.Models; +using Microsoft.Extensions.Configuration; using ModelContextProtocol.Client; using NSubstitute; using Xunit; @@ -18,7 +19,8 @@ private static RegistryServerProvider CreateServerProvider(string id, RegistrySe var httpClientFactory = Substitute.For(); httpClientFactory.CreateClient(Arg.Any()) .Returns(Substitute.For()); - return new RegistryServerProvider(id, serverInfo, httpClientFactory); + var configuration = new ConfigurationBuilder().AddEnvironmentVariables().Build(); + return new RegistryServerProvider(id, serverInfo, httpClientFactory, configuration); } [Fact] public void Constructor_InitializesCorrectly() diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.UnitTests/Areas/Server/Commands/ToolLoading/SingleProxyToolLoaderTests.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.UnitTests/Areas/Server/Commands/ToolLoading/SingleProxyToolLoaderTests.cs index f5281320f6..261e7844ad 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.UnitTests/Areas/Server/Commands/ToolLoading/SingleProxyToolLoaderTests.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.UnitTests/Areas/Server/Commands/ToolLoading/SingleProxyToolLoaderTests.cs @@ -6,6 +6,7 @@ using Azure.Mcp.Core.Areas.Server.Commands.ToolLoading; using Azure.Mcp.Core.Areas.Server.Options; using Azure.Mcp.Core.Helpers; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using ModelContextProtocol.Protocol; @@ -21,7 +22,8 @@ private static RegistryDiscoveryStrategy CreateStrategy(ServiceStartOptions opti var serviceOptions = Microsoft.Extensions.Options.Options.Create(options ?? new ServiceStartOptions()); var httpClientFactory = Substitute.For(); var registryRoot = RegistryServerHelper.GetRegistryRoot(); - return new RegistryDiscoveryStrategy(serviceOptions, logger, httpClientFactory, registryRoot!); + var configuration = new ConfigurationBuilder().AddEnvironmentVariables().Build(); + return new RegistryDiscoveryStrategy(serviceOptions, logger, httpClientFactory, registryRoot!, configuration); } private static (SingleProxyToolLoader toolLoader, IMcpDiscoveryStrategy discoveryStrategy) CreateToolLoader(bool useRealDiscovery = true) diff --git a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.UnitTests/RegistryDiscoveryStrategyHelper.cs b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.UnitTests/RegistryDiscoveryStrategyHelper.cs index 28a91ff843..e6d3e4a805 100644 --- a/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.UnitTests/RegistryDiscoveryStrategyHelper.cs +++ b/core/Azure.Mcp.Core/tests/Azure.Mcp.Core.UnitTests/RegistryDiscoveryStrategyHelper.cs @@ -4,6 +4,7 @@ using Azure.Mcp.Core.Areas.Server.Commands.Discovery; using Azure.Mcp.Core.Areas.Server.Options; using Azure.Mcp.Core.Helpers; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; namespace Azure.Mcp.Core.UnitTests; @@ -16,6 +17,7 @@ public static RegistryDiscoveryStrategy CreateStrategy(ServiceStartOptions? opti logger = logger ?? NSubstitute.Substitute.For>(); var httpClientFactory = NSubstitute.Substitute.For(); var registryRoot = RegistryServerHelper.GetRegistryRoot(); - return new RegistryDiscoveryStrategy(serviceOptions, logger, httpClientFactory, registryRoot!); + var configuration = new ConfigurationBuilder().AddEnvironmentVariables().Build(); + return new RegistryDiscoveryStrategy(serviceOptions, logger, httpClientFactory, registryRoot!, configuration); } } diff --git a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/RegistryDiscoveryStrategy.cs b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/RegistryDiscoveryStrategy.cs index 926193e93e..324bc2a255 100644 --- a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/RegistryDiscoveryStrategy.cs +++ b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/RegistryDiscoveryStrategy.cs @@ -3,6 +3,7 @@ using Azure.Mcp.Core.Areas.Server.Models; using Azure.Mcp.Core.Areas.Server.Options; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -16,10 +17,11 @@ namespace Azure.Mcp.Core.Areas.Server.Commands.Discovery; /// Logger instance for this discovery strategy. /// Factory that can create HttpClient objects. /// Manifest of all the MCP server registries. -public sealed class RegistryDiscoveryStrategy(IOptions options, ILogger logger, IHttpClientFactory httpClientFactory, IRegistryRoot registryRoot) : BaseDiscoveryStrategy(logger) +public sealed class RegistryDiscoveryStrategy(IOptions options, ILogger logger, IHttpClientFactory httpClientFactory, IRegistryRoot registryRoot, IConfiguration configuration) : BaseDiscoveryStrategy(logger) { private readonly IOptions _options = options; private readonly IHttpClientFactory _httpClientFactory = httpClientFactory; + private readonly IConfiguration _configuration = configuration; /// public override async Task> DiscoverServersAsync(CancellationToken cancellationToken) @@ -34,7 +36,7 @@ public override async Task> DiscoverServersAsync .Where(s => _options.Value.Namespace == null || _options.Value.Namespace.Length == 0 || _options.Value.Namespace.Contains(s.Key, StringComparer.OrdinalIgnoreCase)) - .Select(s => new RegistryServerProvider(s.Key, s.Value, _httpClientFactory)) + .Select(s => new RegistryServerProvider(s.Key, s.Value, _httpClientFactory, _configuration)) .Cast(); } } diff --git a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/RegistryServerProvider.cs b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/RegistryServerProvider.cs index 4047c34c28..fbd1d58d29 100644 --- a/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/RegistryServerProvider.cs +++ b/core/Microsoft.Mcp.Core/src/Areas/Server/Commands/Discovery/RegistryServerProvider.cs @@ -3,6 +3,7 @@ using Azure.Mcp.Core.Areas.Server.Models; using Azure.Mcp.Core.Helpers; +using Microsoft.Extensions.Configuration; using ModelContextProtocol.Client; namespace Azure.Mcp.Core.Areas.Server.Commands.Discovery; @@ -15,11 +16,12 @@ namespace Azure.Mcp.Core.Areas.Server.Commands.Discovery; /// Configuration information for the server. /// Factory for creating HTTP clients. /// The token credential provider for OAuth authentication. -public sealed class RegistryServerProvider(string id, RegistryServerInfo serverInfo, IHttpClientFactory httpClientFactory) : IMcpServerProvider +public sealed class RegistryServerProvider(string id, RegistryServerInfo serverInfo, IHttpClientFactory httpClientFactory, IConfiguration configuration) : IMcpServerProvider { private readonly string _id = id; private readonly RegistryServerInfo _serverInfo = serverInfo; private readonly IHttpClientFactory _httpClientFactory = httpClientFactory; + private readonly IConfiguration _configuration = configuration; /// /// Creates metadata that describes this registry-based server. @@ -126,10 +128,10 @@ private async Task CreateStdioClientAsync(McpClientOptions clientOpti throw new InvalidOperationException($"Registry server '{_id}' does not have a valid command for stdio transport."); } - // Merge current system environment variables with serverInfo.Env (serverInfo.Env overrides system) - var env = Environment.GetEnvironmentVariables() - .Cast() - .ToDictionary(e => (string)e.Key, e => (string?)e.Value); + // Merge current configuration values (includes environment variables) with serverInfo.Env (serverInfo.Env overrides) + var env = _configuration.AsEnumerable() + .Where(kvp => kvp.Value is not null) + .ToDictionary(kvp => kvp.Key, kvp => (string?)kvp.Value); if (_serverInfo.Env != null) { diff --git a/tools/Azure.Mcp.Tools.Extension/src/Commands/AzCommand.cs b/tools/Azure.Mcp.Tools.Extension/src/Commands/AzCommand.cs index 38eb191735..0808e22c15 100644 --- a/tools/Azure.Mcp.Tools.Extension/src/Commands/AzCommand.cs +++ b/tools/Azure.Mcp.Tools.Extension/src/Commands/AzCommand.cs @@ -8,16 +8,18 @@ using Azure.Mcp.Core.Services.Azure.Authentication; using Azure.Mcp.Core.Services.ProcessExecution; using Azure.Mcp.Tools.Extension.Options; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Microsoft.Mcp.Core.Commands; using Microsoft.Mcp.Core.Models.Command; namespace Azure.Mcp.Tools.Extension.Commands; -public sealed class AzCommand(ILogger logger, int processTimeoutSeconds = 300) : GlobalCommand() +public sealed class AzCommand(ILogger logger, IConfiguration configuration, int processTimeoutSeconds = 300) : GlobalCommand() { private const string CommandTitle = "Azure CLI Command"; private readonly ILogger _logger = logger; + private readonly IConfiguration _configuration = configuration; private readonly int _processTimeoutSeconds = processTimeoutSeconds; private static string? _cachedAzPath; private volatile bool _isAuthenticated = false; @@ -65,7 +67,7 @@ protected override AzOptions BindOptions(ParseResult parseResult) return options; } - internal static string? FindAzCliPath() + internal string? FindAzCliPath() { string executableName = "az"; @@ -75,7 +77,7 @@ protected override AzOptions BindOptions(ParseResult parseResult) return _cachedAzPath; } - var pathEnv = Environment.GetEnvironmentVariable("PATH"); + var pathEnv = _configuration["PATH"]; if (string.IsNullOrEmpty(pathEnv)) return null;