Skip to content

Conversation

@JasonYeMSFT
Copy link
Member

@JasonYeMSFT JasonYeMSFT commented Jan 15, 2026

What does this PR do?

[Provide a clear, concise description of the changes]

This PR extends the RegistryServerProvider to support adding registry servers protected by OAuth for all its MCP accesses.

[Any additional context, screenshots, or information that helps reviewers]

registry.json now let's MCP servers with http transport to optionally declare an oauthScopes parameter. When this property is defined, the RegistryServerProvider will instantiate the corresponding McpClient object with a custom HttpClient. This custom HttpClient object has a delegate handler that fetches an access token and sets it in the Authorization header in each request.

Text scenarios

  • local stdio + environment credential
  • local stdio + user credential
  • remote + environment credential
  • remote + user credential obo

The server may apply additional restrictions that limit access, such as the tenant restriction.

GitHub issue number?

Pre-merge Checklist

  • Required for All PRs
    • Read contribution guidelines
    • PR title clearly describes the change
    • Commit history is clean with descriptive messages (cleanup guide)
    • Added comprehensive tests for new/modified functionality
    • Updated servers/Azure.Mcp.Server/CHANGELOG.md and/or servers/Fabric.Mcp.Server/CHANGELOG.md for product changes (features, bug fixes, UI/UX, updated dependencies)
  • For MCP tool changes:
    • One tool per PR: This PR adds or modifies only one MCP tool for faster review cycles
    • Updated servers/Azure.Mcp.Server/README.md and/or servers/Fabric.Mcp.Server/README.md documentation
    • Validate README.md changes using script at eng/scripts/Process-PackageReadMe.ps1. See Package README
    • Updated command list in /servers/Azure.Mcp.Server/docs/azmcp-commands.md and/or /docs/fabric-commands.md
    • Run .\eng\scripts\Update-AzCommandsMetadata.ps1 to update tool metadata in azmcp-commands.md (required for CI)
    • For new or modified tool descriptions, ran ToolDescriptionEvaluator and obtained a score of 0.4 or more and a top 3 ranking for all related test prompts
    • For tools with new names, including new tools or renamed tools, update consolidated-tools.json
    • For new tools associated with Azure services or publicly available tools/APIs/products, add URL to documentation in the PR description
  • Extra steps for Azure MCP Server tool changes:
    • Updated test prompts in /servers/Azure.Mcp.Server/docs/e2eTestPrompts.md
    • 👉 For Community (non-Microsoft team member) PRs:
      • Security review: Reviewed code for security vulnerabilities, malicious code, or suspicious activities before running tests (crypto mining, spam, data exfiltration, etc.)
      • Manual tests run: added comment /azp run mcp - pullrequest - live to run Live Test Pipeline

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the RegistryServerProvider to support OAuth-protected registry servers by adding authentication capabilities for MCP servers with HTTP transport. The implementation allows registry servers to specify OAuth scopes in registry.json, which triggers the creation of custom HttpClient instances with access token handlers that automatically fetch and attach bearer tokens to outgoing requests.

Changes:

  • Added OAuth scope configuration support to RegistryServerInfo model
  • Implemented CreateClientWithAccessToken method in HttpClientService with an AccessTokenHandler delegating handler
  • Updated RegistryServerProvider and RegistryDiscoveryStrategy to inject and use authentication services
  • Modified unit tests to accommodate new constructor dependencies with proper mocking

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
core/Azure.Mcp.Core/src/Services/Http/IHttpClientService.cs Added interface method for creating HttpClient with access token provider
core/Azure.Mcp.Core/src/Services/Http/HttpClientService.cs Implemented access token-enabled HttpClient creation with custom delegating handler
core/Azure.Mcp.Core/src/Areas/Server/Models/RegistryServerInfo.cs Added OAuthScopes property to registry server configuration model
core/Azure.Mcp.Core/src/Areas/Server/Commands/Discovery/RegistryServerProvider.cs Integrated OAuth support into client creation logic for HTTP transport
core/Azure.Mcp.Core/src/Areas/Server/Commands/Discovery/RegistryDiscoveryStrategy.cs Added dependency injection for authentication services
core/Azure.Mcp.Core/src/Areas/Server/Resources/registry.json Added example "arm" server configuration with OAuth scopes
core/Azure.Mcp.Core/tests/Azure.Mcp.Core.UnitTests/Areas/Server/Commands/Discovery/RegistryServerProviderTests.cs Updated tests to mock new dependencies
core/Azure.Mcp.Core/tests/Azure.Mcp.Core.UnitTests/Areas/Server/Commands/Discovery/RegistryDiscoveryStrategyTests.cs Updated tests to mock new dependencies
core/Azure.Mcp.Core/tests/Azure.Mcp.Core.UnitTests/Areas/Server/Commands/ServiceCollectionExtensionsTests.cs Added token credential provider registration to test setup
core/Azure.Mcp.Core/tests/Azure.Mcp.Core.UnitTests/Areas/Server/Commands/ToolLoading/SingleProxyToolLoaderTests.cs Refactored to use helper method for creating RegistryDiscoveryStrategy with dependencies
core/Azure.Mcp.Core/tests/Azure.Mcp.Core.UnitTests/Areas/Server/Commands/ToolLoading/ServerToolLoaderTests.cs Refactored to use helper method for creating RegistryDiscoveryStrategy with dependencies

Copy link
Member

@vukelich vukelich left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chatted offline. Jason was already mid-change for switching to IHttpClientFactory. Will return for review when that's complete.

@github-project-automation github-project-automation bot moved this from Untriaged to In Progress in Azure MCP Server Jan 22, 2026
/// <summary>
/// Add HttpClient for each registry server with OAuthScopes that knows how to fetch its access token.
/// </summary>
private static IServiceCollection AddHttpClientForMcpRegistry(this IServiceCollection services)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For clean code organization, please put this code somewhere close to adding the registry tool loader and discovery strategy into the DI container. This code is not relevant for the TenantService.

private static IServiceCollection AddHttpClientForMcpRegistry(this IServiceCollection services)
{
var assembly = Assembly.GetExecutingAssembly();
var resourceName = assembly
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd strongly recommend leaving a comment as a warning to other maintainers both here and in RegistryDiscoveryStrategy that we have two different files reading and acting on registry.json. As an example, if one of them changes the name of the file, then the other will break.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic for registring RegistryServer related DI depdendencies have been moved to RegistryServerServiceCollectionExtension.cs.

var resourceName = assembly
.GetManifestResourceNames()
.FirstOrDefault(n => n.EndsWith("registry.json", StringComparison.OrdinalIgnoreCase));
if (resourceName is null)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As an alternative to opening and parsing this file within this method and tossing out the results, we could load the results into an object and add it into the DI container such as adding RegistryRoot as a type into the DI for RegistryDiscoveryStrategy to be constructed with.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This allows the application to have a "read once" rather than multiple times in separate spots.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now azmcp loads the registry.json once and registers the parsed object as a DI singleton.

Copy link
Member

@vukelich vukelich left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple more comments.

services.AddHttpClient(RegistryServerHelper.GetRegistryServerHttpClientName(serverName))
.AddHttpMessageHandler((services) =>
{
var fetchAccessToken = async (CancellationToken cancellationToken) =>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than passing around function callbacks, can we please construct AccessTokenHandler with the OAuth scopes and a credential provider, and the internal logic of AccessTokenHandler has this logic?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is very TypeScript/JavaScript-esque rather than OOB

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's modified to constructor AccessTokenHandler with an IAzureTokenCredentialProvider and oauthScopes.

// Licensed under the MIT License.

using System.Net;
using System.Net.Http.Headers;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can remove this change.

Use DI to read server registry once and load at multiple places
Style and documentation fixes per PR feedback
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

3 participants