Integrate Config based env retrieval#1978
Conversation
…ls with IConfiguration All direct Environment.GetEnvironmentVariable calls in the Remote Azure MCP Server auth and startup paths are replaced with IConfiguration-based retrieval, since the configuration system already handles environment variables and other sources (appsettings.json, etc.). Changes: - CustomChainedCredential: add static Configuration property (mirrors the existing CloudConfiguration pattern) and GetConfigValue helper that prefers IConfiguration when set and falls back to env vars for backward compatibility. All env var reads in CreateCredential, CreateBrowserCredential, CreateDefaultCredential, AddManagedIdentityCredential, and ShouldUseOnlyBrokerCredential now use GetConfigValue. - AuthenticationServiceCollectionExtensions: wire the IConfiguration singleton (if registered) into CustomChainedCredential.Configuration when building the single-identity token credential provider. - ServiceStartCommand (HTTP paths): use builder/app IConfiguration instead of Environment.GetEnvironmentVariable for ASPNETCORE_URLS, ALLOW_INSECURE_EXTERNAL_BINDING, AZURE_MCP_DANGEROUSLY_ENABLE_FORWARDED_HEADERS, AZURE_MCP_DANGEROUSLY_DISABLE_HTTPS_REDIRECTION, AZURE_MCP_COLLECT_TELEMETRY, and APPLICATIONINSIGHTS_CONNECTION_STRING. AddIncomingAndOutgoingHttpSpans now receives an IConfiguration instance built from env vars before the host is constructed.
There was a problem hiding this comment.
Pull request overview
Integrates IConfiguration-based settings retrieval into authentication credential selection and server startup, reducing direct Environment.GetEnvironmentVariable usage and centralizing settings access through configuration.
Changes:
- Add
IConfigurationsupport toCustomChainedCredentialand prefer configuration values when available. - Wire
IConfigurationintoCustomChainedCredentialduring DI registration. - Switch several server startup settings (telemetry, URLs, forwarded headers, HTTPS redirect opt-out) from direct env-var reads to
IConfiguration.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
| core/Microsoft.Mcp.Core/src/Services/Azure/Authentication/CustomChainedCredential.cs | Adds configuration-backed value lookup for credential chain behavior. |
| core/Microsoft.Mcp.Core/src/Services/Azure/Authentication/AuthenticationServiceCollectionExtensions.cs | Passes IConfiguration from DI into CustomChainedCredential static state. |
| core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ServiceStartCommand.cs | Uses IConfiguration for multiple server startup toggles and telemetry settings. |
core/Microsoft.Mcp.Core/src/Services/Azure/Authentication/CustomChainedCredential.cs
Outdated
Show resolved
Hide resolved
core/Microsoft.Mcp.Core/src/Services/Azure/Authentication/CustomChainedCredential.cs
Outdated
Show resolved
Hide resolved
core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ServiceStartCommand.cs
Outdated
Show resolved
Hide resolved
core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ServiceStartCommand.cs
Outdated
Show resolved
Hide resolved
core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ServiceStartCommand.cs
Outdated
Show resolved
Hide resolved
core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ServiceStartCommand.cs
Outdated
Show resolved
Hide resolved
core/Microsoft.Mcp.Core/src/Areas/Server/Commands/ServiceStartCommand.cs
Outdated
Show resolved
Hide resolved
anuchandy
left a comment
There was a problem hiding this comment.
Thanks Vinay! @g2vinay, these changes route env var reads through IConfiguration, but most of the values here are env var conventions by design - so wondering if this routing is necessary. Since it shifts expectations around how these are configured, it might be worth holding off on including this in GA.
| /// When set, configuration-based retrieval is preferred over direct environment variable access, | ||
| /// allowing values to come from non-environment sources (e.g. appsettings.json) in addition to environment variables. | ||
| /// </summary> | ||
| internal static IConfiguration? Configuration { get; set; } |
There was a problem hiding this comment.
I wonder if IConfiguration indirection layer we've here earn its keep? -
- "AZURE_CLIENT_ID" is a standard Azure Identity convention. The
EnvironmentCredentialin the same chain reads it directly from env viaEnvironmentCredentialOptions- routing our read throughIConfigurationwhile the azure-identity's own read bypasses it creates inconsistency within the same credential chain. - "VSCODE_PID" is process introspection set by VS Code it will never appear in
appsettings.json.
These values are lazily initialized and cached, so env reads happen once per instance - IConfiguration indirection doesn't improve caching or correctness.
My two cents, I'd lean toward keeping Environment.GetEnvironmentVariable as-is. If there's a specific scenario where appsettings.json sourcing is needed for certain values later, we could scope the change to just that variable rather than adding a blanket IConfiguration layer.
There was a problem hiding this comment.
I assume, @srnagar's direction was to make it similar to how we support Configuration in Azure Core in Java Azure SDKs.
Read from both code level config, properties, env var etc.
If that's still the goal, then the code level can override the env var, which is fine, as it won't regress users.
There was a problem hiding this comment.
We can add this selectively too, by design we can exclude certain areas where we want to restrict to env var only.
Will bring downside of incosnsitency, but if its justified by design, its fine, for Credential purposes, I don't see strong reason to restrict it, its fine to support config there too.
There was a problem hiding this comment.
Yeah, I was trying to understand the general pattern libs use.
Taking the telemetry SDK as an example: APPLICATIONINSIGHTS_CONNECTION_STRING (ALL_CAPS) is a flat "env var" read directly via Environment.GetEnvironmentVariable, not through IConfiguration.
The appsettings.json equivalent is the hierarchical ApplicationInsights:ConnectionString section, which maps to ApplicationInsights__ConnectionString (double underscore) "env-var" for IConfiguration resolution.
So my main point was that reading ALL_CAPS "env vars" through IConfiguration is uncommon - users understand IConfiguration work with the double-underscore "env var" form of a hierarchical section. That said, I don't see a concrete issue with us supporting ALL_CAPS via appsettings.json - yet.
There was a problem hiding this comment.
I see, then perhaps we can also honor the double-underscore format as best practice.
| out bool parsedEnvVar) | ||
| && parsedEnvVar; | ||
| // Default to false; the configuration value must parse to "true" to enable. | ||
| string? forwardedHeadersSetting = builder.Configuration["AZURE_MCP_DANGEROUSLY_ENABLE_FORWARDED_HEADERS"]; |
There was a problem hiding this comment.
So we're now reading ALLOW_INSECURE_EXTERNAL_BINDING, AZURE_MCP_DANGEROUSLY_DISABLE_HTTPS_REDIRECTION, and AZURE_MCP_DANGEROUSLY_ENABLE_FORWARDED_HEADERS via WebApplicationBuilder - meaning they can now be set via "appsettings.json". These are security-sensitive opt-ins, so this is worth scrutinizing: a checked-in config file could accidentally enable insecure settings, whereas env vars require explicit runtime intent. Would be good to get a read from the security folks before we settle on this.
Tagging Xiang, Srikanta - \cc @xiangyan99 , @srnagar
There was a problem hiding this comment.
We can opt to selectively restrict it to env here by design.
| } | ||
|
|
||
| string? connectionString = Environment.GetEnvironmentVariable("APPLICATIONINSIGHTS_CONNECTION_STRING"); | ||
| string? connectionString = configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"]; |
There was a problem hiding this comment.
Routing through IConfiguration appears to unlock setting APPLICATIONINSIGHTS_CONNECTION_STRING via appsettings.json, but this flat key is an env var convention.
| private static string? GetConfigValue(string key) => | ||
| Configuration?[key] ?? Environment.GetEnvironmentVariable(key); |
There was a problem hiding this comment.
I'd make this check a bit more verbose as there's a different between Configuration is null and fallback to Environment.GetEnvironmentVariable and Configuration returned null from the lookup, as Configuration will fallback to looking at Environment.GetEnvironmentVariable.
| private static string? GetConfigValue(string key) => | |
| Configuration?[key] ?? Environment.GetEnvironmentVariable(key); | |
| private static string? GetConfigValue(string key) => | |
| (Configuration == null) | |
| ? Environment.GetEnvironmentVariable(key) | |
| : Configuration[key]; |
No description provided.