-
Notifications
You must be signed in to change notification settings - Fork 434
Switch from Environment.GetEnvironmentVariable to IConfiguration #1704
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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; | |
| /// <param name="serverInfo">Configuration information for the server.</param> | ||
| /// <param name="httpClientFactory">Factory for creating HTTP clients.</param> | ||
| /// <param name="tokenCredentialProvider">The token credential provider for OAuth authentication.</param> | ||
| 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; | ||
|
|
||
| /// <summary> | ||
| /// Creates metadata that describes this registry-based server. | ||
|
|
@@ -126,10 +128,10 @@ private async Task<McpClient> 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<System.Collections.DictionaryEntry>() | ||
| .ToDictionary(e => (string)e.Key, e => (string?)e.Value); | ||
| // Merge current configuration values (includes environment variables) with serverInfo.Env (serverInfo.Env overrides) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IConfiguration comprises of a lot more than just environment variables. Also includes things like appsettings.json, other configuration providers. Is this what you want?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the intent here is for serverInfo.Env to take precedence over everything else. So, yes, this should still work as expected.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would also argue that it may not be appropriate for azmcp's json config to appear as transitive config at the environment variable level for another server we start. If environment variables have higher priority than json config. We'd be elevating azmcp's json config over the other server's json config |
||
| var env = _configuration.AsEnumerable() | ||
| .Where(kvp => kvp.Value is not null) | ||
| .ToDictionary(kvp => kvp.Key, kvp => (string?)kvp.Value); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure if this would round trip correctly. While IConfig and environment variables are both string/string maps, their key serialization scheme is different. When IConfiguration is built from environment variables, it expects a hierarchy delimiter of To round trip, you'd have to convert all
|
||
|
|
||
| if (_serverInfo.Env != null) | ||
| { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm 100% behind replacing our environment variable pulls with DI, but passing IConfiguration into the business layer feels like an antipattern. It's hiding the real dependency and letting some deep logic decide that it now cares about a new json or environment variable config without "informing" the startup.
I'd much prefer we use the options pattern over raw IConfiguration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Program.cs and ServiceCollection/Provider would be responsible for converting the state of the world at program start into strongly typed options classes. Everything below program.cs would deal with strongly typed POCOs.
We would just need to decide how coupled our option classes would be. We could have:
RegistryServerProviderdepend onIOptions<RegistryServerProviderOptions>Or we could have a more aggregate options class that serves any of our internal classes that needed config:
RegistryServerProviderdepends onIOptions<AzureMcpServerOptions>There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or we could punt on IOptions and just replace the non-mockable
Environment.GetEnvironmentVariablewithIEnvironmentVariables.Get