Files
agent-framework/dotnet/tests/Microsoft.Agents.AI.Foundry.UnitTests/Hosting/FoundryToolboxServiceTests.cs
Roger Barreto 215a0ad473 Add HostedMcpToolboxAITool for client-selectable Foundry toolboxes
Introduces HostedMcpToolboxAITool, a marker tool subclassing HostedMcpServerTool that rides the OpenAI Responses 'mcp' wire format to let clients request a specific Foundry toolbox per request.

- New FoundryAITool.CreateHostedMcpToolbox(name, version?) factory.

- FoundryToolboxOptions.StrictMode (default true) rejects unregistered toolboxes; set to false to allow lazy-open on first use.

- FoundryToolboxService.GetToolboxToolsAsync(name, version?) resolves cached or lazy-opened MCP tools.

- AgentFrameworkResponseHandler parses request.Tools for foundry-toolbox://name[?version=v] markers and injects resolved tools per request, merging with pre-registered ones.

- Unit tests for marker parsing and strict-mode resolution.
2026-04-17 23:21:57 +01:00

70 lines
2.5 KiB
C#

// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Threading;
using System.Threading.Tasks;
using Azure.Core;
using Microsoft.Agents.AI.Foundry.Hosting;
using Microsoft.Extensions.Options;
using Moq;
namespace Microsoft.Agents.AI.Foundry.UnitTests.Hosting;
public class FoundryToolboxServiceTests
{
[Fact]
public async Task GetToolboxToolsAsync_StrictMode_ThrowsForUnknownToolboxAsync()
{
var options = new FoundryToolboxOptions { StrictMode = true };
var service = new FoundryToolboxService(
Options.Create(options),
Mock.Of<TokenCredential>());
// Act + Assert: no StartAsync so Tools is empty; unknown name in strict mode throws.
var ex = await Assert.ThrowsAsync<InvalidOperationException>(
async () => await service.GetToolboxToolsAsync("missing", version: null, CancellationToken.None));
Assert.Contains("missing", ex.Message, StringComparison.Ordinal);
Assert.Contains("StrictMode", ex.Message, StringComparison.Ordinal);
}
[Fact]
public async Task GetToolboxToolsAsync_NonStrictMode_RequiresEndpointAsync()
{
var options = new FoundryToolboxOptions { StrictMode = false };
var service = new FoundryToolboxService(
Options.Create(options),
Mock.Of<TokenCredential>());
// Without calling StartAsync, endpoint is not resolved so lazy-open fails clearly.
var ex = await Assert.ThrowsAsync<InvalidOperationException>(
async () => await service.GetToolboxToolsAsync("missing", version: null, CancellationToken.None));
Assert.Contains("FOUNDRY_AGENT_TOOLSET_ENDPOINT", ex.Message, StringComparison.Ordinal);
}
[Fact]
public async Task StartAsync_WithoutEndpoint_LeavesToolsEmptyAsync()
{
// Ensure env var is not set (tests may run in any CI environment)
var saved = Environment.GetEnvironmentVariable("FOUNDRY_AGENT_TOOLSET_ENDPOINT");
Environment.SetEnvironmentVariable("FOUNDRY_AGENT_TOOLSET_ENDPOINT", null);
try
{
var options = new FoundryToolboxOptions();
options.ToolboxNames.Add("any");
var service = new FoundryToolboxService(
Options.Create(options),
Mock.Of<TokenCredential>());
await service.StartAsync(CancellationToken.None);
Assert.Empty(service.Tools);
}
finally
{
Environment.SetEnvironmentVariable("FOUNDRY_AGENT_TOOLSET_ENDPOINT", saved);
}
}
}