Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
58a7c9d
Migrate Foundry to external MCP server
g2vinay Feb 19, 2026
4688c8a
Merge remote-tracking branch 'upstream/main' into add-foundry-mcp-server
g2vinay Feb 19, 2026
b1d8abc
auth update add browser fallback
g2vinay Feb 24, 2026
9b7c48b
Add forceBrowserFallback and normalizeScopes for registry server OAuth
g2vinay Feb 25, 2026
07e8650
Merge remote-tracking branch 'upstream/main' into add-foundry-mcp-server
g2vinay Feb 25, 2026
5c0e396
Add changelog entry for Foundry external MCP server migration
g2vinay Feb 25, 2026
687c98c
Add foundry extensions
g2vinay Mar 3, 2026
b49f342
Merge remote-tracking branch 'upstream/main' into add-foundry-mcp-server
g2vinay Mar 3, 2026
25987d9
Fix failing tests after foundry registry and CustomChainedCredential …
g2vinay Mar 3, 2026
2914674
Address feedback
g2vinay Mar 3, 2026
3ff53f9
Fix whitespace formatting and improve VisualStudioToolNameTests robus…
g2vinay Mar 3, 2026
3d9c1ec
Add changelog entry for FoundryExtensions namespace move and new exte…
g2vinay Mar 3, 2026
4fe31f5
Rename changelog entry to timestamp-based filename
g2vinay Mar 3, 2026
27c0318
Consolidate changelog entries into single file
g2vinay Mar 3, 2026
6d3019b
add changelog
g2vinay Mar 3, 2026
16c94ce
Add CODEOWNERS entry for FoundryExtensions toolset
g2vinay Mar 3, 2026
0cb02ae
Fix: restrict FoundryExtensions tests to --namespace foundryextension…
g2vinay Mar 3, 2026
6202ec1
Fix: skip external registry servers when running under TEST_PROXY_URL…
g2vinay Mar 3, 2026
6af8f9a
Add FoundryExtensionsSetup to CommandFactoryHelpers
g2vinay Mar 3, 2026
cbe68ba
update docs + fix unit tests
g2vinay Mar 3, 2026
89f0a31
update docs + fix unit tests
g2vinay Mar 3, 2026
ba2c4a0
Register FoundryExtensionsSetup in Program.cs and add solution structure
g2vinay Mar 3, 2026
8a67e0c
Fix: Remove stale foundry_agents_create from consolidated-tools.json
g2vinay Mar 3, 2026
731ca0e
fix consolidated mode + code cleanup
g2vinay Mar 4, 2026
74b9616
Sync with upstream, update solution file, and re-record FoundryExtens…
g2vinay Mar 4, 2026
f1b2cc9
Merge remote-tracking branch 'upstream/main' into add-foundry-mcp-server
g2vinay Mar 4, 2026
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
6 changes: 0 additions & 6 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -186,12 +186,6 @@
# ServiceLabel: %tools-FileShares
# ServiceOwners: @ankushbindlish2 @kszobi

# PRLabel: %tools-Foundry
/tools/Azure.Mcp.Tools.Foundry/ @jayzzh @xiangyan99 @microsoft/azure-mcp

# ServiceLabel: %tools-Foundry
# ServiceOwners: @jayzzh @xiangyan99

# PRLabel: %tools-FunctionApp
/tools/Azure.Mcp.Tools.FunctionApp/ @jongio @microsoft/azure-mcp

Expand Down
9 changes: 1 addition & 8 deletions Microsoft.Mcp.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -237,14 +237,7 @@
<Project Path="tools/Azure.Mcp.Tools.FileShares/tests/Azure.Mcp.Tools.FileShares.LiveTests/Azure.Mcp.Tools.FileShares.LiveTests.csproj" />
<Project Path="tools/Azure.Mcp.Tools.FileShares/tests/Azure.Mcp.Tools.FileShares.UnitTests/Azure.Mcp.Tools.FileShares.UnitTests.csproj" />
</Folder>
<Folder Name="/tools/Azure.Mcp.Tools.Foundry/" />
<Folder Name="/tools/Azure.Mcp.Tools.Foundry/src/">
<Project Path="tools/Azure.Mcp.Tools.Foundry/src/Azure.Mcp.Tools.Foundry.csproj" />
</Folder>
<Folder Name="/tools/Azure.Mcp.Tools.Foundry/tests/">
<Project Path="tools/Azure.Mcp.Tools.Foundry/tests/Azure.Mcp.Tools.Foundry.LiveTests/Azure.Mcp.Tools.Foundry.LiveTests.csproj" />
<Project Path="tools/Azure.Mcp.Tools.Foundry/tests/Azure.Mcp.Tools.Foundry.UnitTests/Azure.Mcp.Tools.Foundry.UnitTests.csproj" />
</Folder>

<Folder Name="/tools/Azure.Mcp.Tools.FunctionApp/" />
<Folder Name="/tools/Azure.Mcp.Tools.FunctionApp/src/">
<Project Path="tools/Azure.Mcp.Tools.FunctionApp/src/Azure.Mcp.Tools.FunctionApp.csproj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
using Azure.Mcp.Tools.Deploy;
using Azure.Mcp.Tools.EventGrid;
using Azure.Mcp.Tools.Extension;
using Azure.Mcp.Tools.Foundry;
using Azure.Mcp.Tools.FunctionApp;
using Azure.Mcp.Tools.Grafana;
using Azure.Mcp.Tools.KeyVault;
Expand Down Expand Up @@ -73,7 +72,6 @@ public static ICommandFactory CreateCommandFactory(IServiceProvider? serviceProv
new DeploySetup(),
new EventGridSetup(),
new ExtensionSetup(),
new FoundrySetup(),
new FunctionAppSetup(),
new GrafanaSetup(),
new KeyVaultSetup(),
Expand Down Expand Up @@ -137,7 +135,6 @@ public static IServiceCollection SetupCommonServices()
new DeploySetup(),
new EventGridSetup(),
new ExtensionSetup(),
new FoundrySetup(),
new FunctionAppSetup(),
new GrafanaSetup(),
new KeyVaultSetup(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -430,4 +430,71 @@ public async Task DiscoverServersAsync_NamespaceFilteringIsCaseInsensitive()
var serverIds = providers.Select(p => p.CreateMetadata().Id).ToList();
Assert.Contains("documentation", serverIds);
}

[Fact]
public async Task DiscoverServersAsync_FoundryServerIsDiscovered()
{
// Arrange
var strategy = RegistryDiscoveryStrategyHelper.CreateStrategy();

// Act
var result = await strategy.DiscoverServersAsync(TestContext.Current.CancellationToken);
var foundryProvider = result.FirstOrDefault(p => p.CreateMetadata().Name == "foundry");

// Assert
Assert.NotNull(foundryProvider);

var metadata = foundryProvider.CreateMetadata();
Assert.Equal("foundry", metadata.Id);
Assert.Equal("foundry", metadata.Name);
Assert.NotEmpty(metadata.Description);

// Verify description contains key terms
var description = metadata.Description.ToLowerInvariant();
Assert.Contains("foundry", description);
Assert.Contains("mcp", description);
}

[Fact]
public async Task DiscoverServersAsync_FoundryServerHasExpectedProperties()
{
// Arrange
var strategy = RegistryDiscoveryStrategyHelper.CreateStrategy();

// Act
var result = await strategy.DiscoverServersAsync(TestContext.Current.CancellationToken);
var foundryProvider = result.FirstOrDefault(p => p.CreateMetadata().Name == "foundry");

// Assert
Assert.NotNull(foundryProvider);

var metadata = foundryProvider.CreateMetadata();
Assert.Equal("foundry", metadata.Id);
Assert.Equal("foundry", metadata.Name);

// Description should mention models, agents, and evaluation workflows
var description = metadata.Description.ToLowerInvariant();
Assert.Contains("models", description);
Assert.Contains("agents", description);
}

[Fact]
public async Task DiscoverServersAsync_AllExpectedServersArePresent()
{
// Arrange
var strategy = RegistryDiscoveryStrategyHelper.CreateStrategy();

// Act
var result = await strategy.DiscoverServersAsync(TestContext.Current.CancellationToken);
var serverIds = result.Select(p => p.CreateMetadata().Id).ToList();

// Assert
// Verify all expected registry servers are discovered
Assert.Contains("documentation", serverIds);
Assert.Contains("azd", serverIds);
Assert.Contains("foundry", serverIds);

// Should have exactly 3 servers in registry
Assert.Equal(3, serverIds.Count);
}
}
12 changes: 10 additions & 2 deletions core/Microsoft.Mcp.Core/src/AccessTokenHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ namespace Azure.Mcp.Core;
/// </summary>
public sealed class AccessTokenHandler : DelegatingHandler
{
private readonly IAzureTokenCredentialProvider _tokenCredentialProvider;
private readonly IAzureTokenCredentialProvider? _tokenCredentialProvider;
private readonly TokenCredential? _credential;
private readonly string[] _oauthScopes;

public AccessTokenHandler(IAzureTokenCredentialProvider tokenCredentialProvider, string[] oauthScopes)
Expand All @@ -21,6 +22,12 @@ public AccessTokenHandler(IAzureTokenCredentialProvider tokenCredentialProvider,
_oauthScopes = oauthScopes;
}

public AccessTokenHandler(TokenCredential credential, string[] oauthScopes)
{
_credential = credential;
_oauthScopes = oauthScopes;
}

/// <summary>
/// Sends an HTTP request with a Bearer access token fetched using the embedded <see cref="IAzureTokenCredentialProvider"/>.
/// This method will overwrite the Authorization header if it already exist on the request.
Expand All @@ -29,7 +36,8 @@ public AccessTokenHandler(IAzureTokenCredentialProvider tokenCredentialProvider,
/// <param name="cancellationToken"></param>
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var credential = await _tokenCredentialProvider.GetTokenCredentialAsync(tenantId: null, cancellationToken);
TokenCredential credential = _credential
?? await _tokenCredentialProvider!.GetTokenCredentialAsync(tenantId: null, cancellationToken);
var tokenContext = new TokenRequestContext(_oauthScopes);
var token = await credential.GetTokenAsync(tokenContext, cancellationToken);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.Token);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,20 @@ public static IServiceCollection AddRegistryRoot(this IServiceCollection service
}

services.AddHttpClient(RegistryServerHelper.GetRegistryServerHttpClientName(serverName))
.AddHttpMessageHandler((services) =>
.AddHttpMessageHandler((sp) =>
{
var tokenCredentialProvider = services.GetRequiredService<IAzureTokenCredentialProvider>();
return new AccessTokenHandler(tokenCredentialProvider, oauthScopes);
var provider = sp.GetRequiredService<IAzureTokenCredentialProvider>();
// Only force browser fallback for SingleIdentityTokenCredentialProvider
// (stdio mode and UseHostingEnvironmentIdentity HTTP mode). In those scenarios
// the user's own identity drives auth, so an interactive browser prompt is a
// reasonable last resort when silent credentials (AzCLI, WAM, etc.) fail.
// For UseOnBehalfOf (HttpOnBehalfOfTokenCredentialProvider) the OBO flow owns
// the token exchange — delegate back to the provider as usual.
if (provider is SingleIdentityTokenCredentialProvider)
{
return new AccessTokenHandler(new CustomChainedCredential(forceBrowserFallback: true), oauthScopes);
}
return new AccessTokenHandler(provider, oauthScopes);
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -403,39 +403,6 @@
"deploy_plan_get"
]
},
{
"name": "deploy_azure_ai_models",
"description": "Deploy AI models to Microsoft Foundry for machine learning inference and production use.",
"toolMetadata": {
"destructive": {
"value": true,
"description": "This tool may delete or modify existing resources in its environment."
},
"idempotent": {
"value": false,
"description": "Running this operation multiple times with the same arguments may have additional effects or produce different results."
},
"openWorld": {
"value": false,
"description": "This tool's domain of interaction is closed and well-defined, limited to a specific set of entities."
},
"readOnly": {
"value": false,
"description": "This tool may modify its environment by creating, updating, or deleting data."
},
"secret": {
"value": false,
"description": "This tool does not handle sensitive or secret information."
},
"localRequired": {
"value": false,
"description": "This tool is available in both local and remote server modes."
}
},
"mappedToolList": [
"foundry_models_deploy"
]
},
{
"name": "get_azure_app_config_settings",
"description": "Get details about Azure App Configuration settings",
Expand Down Expand Up @@ -1039,7 +1006,7 @@
},
{
"name": "get_azure_best_practices",
"description": "Retrieve Azure best practices and infrastructure schema for code generation, deployment, and operations. Covers general Azure practices, Azure Functions best practices, AI app development best practices, Terraform configurations, Bicep template schemas, deployment best practices and Microsoft Foundry sdk code samples.",
"description": "Retrieve Azure best practices and infrastructure schema for code generation, deployment, and operations. Covers general Azure practices, Azure Functions best practices, AI app development best practices, Terraform configurations, Bicep template schemas, and deployment best practices.",
"toolMetadata": {
"destructive": {
"value": false,
Expand Down Expand Up @@ -1070,8 +1037,7 @@
"azureterraformbestpractices_get",
"bicepschema_get",
"get_azure_bestpractices_ai_app",
"get_azure_bestpractices_get",
"foundry_agents_get-sdk-sample"
"get_azure_bestpractices_get"
]
},
{
Expand Down Expand Up @@ -1180,7 +1146,7 @@
},
{
"name": "get_azure_ai_resources_details",
"description": "Get details about Azure AI resources including listing and querying AI Search services, listing models available to be deployed and models deployed already, knowledge index schema by Microsoft Foundry, knowledge base and source information, and listing Microsoft Foundry , threads, messages and resources.",
"description": "Get details about Azure AI resources including listing and querying AI Search services, knowledge base and source information.",
"toolMetadata": {
"destructive": {
"value": false,
Expand Down Expand Up @@ -1212,16 +1178,7 @@
"search_index_get",
"search_index_query",
"search_knowledge_source_get",
"search_knowledge_base_get",
"foundry_models_deployments_list",
"foundry_models_list",
"foundry_knowledge_index_list",
"foundry_knowledge_index_schema",
"foundry_openai_models-list",
"foundry_agents_list",
"foundry_resource_get",
"foundry_threads_list",
"foundry_threads_get-messages"
"search_knowledge_base_get"
]
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@
"title": "Azure Developer CLI",
"description": "Azure Developer CLI (azd) includes a suite of tools to help build, modernize, and manage applications on Azure. It simplifies the process of developing cloud applications by providing commands for project initialization, resource provisioning, deployment, and monitoring. Use this tool to streamline your Azure development workflow and manage your cloud resources efficiently.",
"installInstructions": "The Azure Developer CLI (azd) is either not installed or requires an update. The minimum required version that works with MCP tools is 1.20.0.\n\nTo install or upgrade, follow the instructions at https://aka.ms/azd/install\n\nAfter installation you may need to restart the Azure MCP server and your IDE."
},
"foundry": {
"url": "https://mcp.ai.azure.com",
"title": "Microsoft Foundry MCP",
"description": "MCP server with tools to read, create, modify resources such as Models, Agents and Evaluation workflows in Microsoft Foundry platform.",
"oauthScopes": ["https://mcp.ai.azure.com/Foundry.Mcp.Tools"]
}
}
}
Loading
Loading