Suppose you build five different AI agents for your company: an HR agent, an IT helpdesk agent, a sales assistant, an onboarding buddy, and an incident responder. All five of them need to search your internal company wiki, look up live web pages, and create tickets in your issue tracker.
If you wire those three tools directly into each agent's code:
- You have to manage API keys and connection strings in five different places.
- When the ticketing API changes its schema, you have to redeploy all five agents.
- If you attach 30 or 40 tools to a single agent, every single tool schema gets stuffed into the model's prompt on every turn. That burns thousands of tokens and confuses the model into picking the wrong tool.
Microsoft Foundry solves all three headaches with Foundry Toolboxes (GA), Model Context Protocol (MCP), and Tool Search.
How Foundry Toolboxes Work
A Toolbox is a versioned, reusable collection of tools that lives inside your Foundry project. You configure your tools and credentials once inside the Toolbox, and Foundry exposes that Toolbox as a single managed MCP (Model Context Protocol) endpoint:
https://<account>.services.ai.azure.com/api/projects/<project>/toolboxes/<name>/versions/<version>/mcp?api-version=v1
Any agent (whether it is a declarative Prompt Agent or a custom Hosted Agent written with the Microsoft Agent Framework) can connect to that single URL and immediately use every tool inside the box.
[ Agent A: IT Helpdesk ] \
+---> [ Managed Toolbox MCP Endpoint ]
[ Agent B: Sales Bot ] / |
+---> Tool Search (Picks relevant tools dynamically)
+---> Web Search Tool
+---> Custom MCP Server (Jira / ServiceNow)
+---> Playwright Browser Automation
+---> Code Interpreter
What Is "Tool Search" and Why Does It Matter?
When your Toolbox grows past five or six tools, you add ToolSearchToolboxTool to the Toolbox. Instead of dumping 50 tool definitions into the LLM's context window on every user message, Tool Search lets the agent search the toolbox catalog on the fly and load only the one or two tool schemas relevant to the user's current question. This cuts prompt token costs dramatically and prevents tool-selection mistakes.
Building and Consuming a Versioned Toolbox
Let's create a Toolbox containing Web Search, an external MCP server connection, and Tool Search, and then attach that Toolbox to a Hosted Agent using the Microsoft Agent Framework.
C# (.NET) Example: Creating a Toolbox Version
using System;
using System.Threading.Tasks;
using Azure.Identity;
using Azure.AI.Projects;
var projectEndpoint = "https://your-resource.services.ai.azure.com/api/projects/your-project";
AIProjectClient projectClient = new(new Uri(projectEndpoint), new DefaultAzureCredential());
AgentToolboxes toolboxClient = projectClient.AgentAdministrationClient.GetAgentToolboxes();
// 1. Define the tools to bundle inside the Toolbox
WebSearchToolboxTool webTool = new();
MCPToolboxTool mcpTool = new(serverLabel: "ticketing_server")
{
ServerUri = new Uri("https://mcp.internal.contoso.com/sse"),
ToolCallApprovalPolicy = new McpToolCallApprovalPolicy(
GlobalMcpToolCallApprovalPolicy.NeverRequireApproval),
};
ToolSearchToolboxTool searchTool = new() { Name = "ToolBoxSearch" };
// 2. Publish a new immutable version of the Toolbox
ToolboxVersion toolboxVersion = await toolboxClient.CreateVersionAsync(
name: "enterprise-ops-toolbox",
tools: [webTool, mcpTool, searchTool],
description: "Shared operational tools with dynamic tool search"
);
Console.WriteLine($"Published Toolbox: {toolboxVersion.Name}, Version: {toolboxVersion.Version}");
Python Example: Creating a Toolbox & Attaching It to an Agent
Install the Microsoft Agent Framework alongside the Foundry Projects SDK:
pip install agent-framework-foundry "azure-ai-projects>=2.3.0" azure-identity
Create the Toolbox and connect an agent to its managed MCP URL:
import asyncio
from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient, FoundryToolbox
from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import (
MCPToolboxTool,
ToolSearchToolboxTool,
WebSearchToolboxTool,
)
from azure.identity import DefaultAzureCredential
PROJECT_ENDPOINT = "https://your-resource.services.ai.azure.com/api/projects/your-project"
async def main() -> None:
credential = DefaultAzureCredential()
project = AIProjectClient(endpoint=PROJECT_ENDPOINT, credential=credential)
# 1. Create a reusable Toolbox version in Foundry
toolbox = project.toolboxes.create_version(
name="enterprise-ops-toolbox",
description="Shared operational tools with dynamic tool search",
tools=[
WebSearchToolboxTool(),
MCPToolboxTool(
server_label="ticketing_server",
server_url="https://mcp.internal.contoso.com/sse",
require_approval="never",
project_connection_id="ticketing-key-connection",
),
ToolSearchToolboxTool(),
],
)
# 2. Build the managed MCP endpoint URL for this toolbox version
toolbox_mcp_url = (
f"{PROJECT_ENDPOINT}/toolboxes/{toolbox.name}"
f"/versions/{toolbox.version}/mcp?api-version=v1"
)
# 3. Attach the Toolbox to a Microsoft Agent Framework agent
toolbox_tool = FoundryToolbox(credential, url=toolbox_mcp_url)
agent = Agent(
client=FoundryChatClient(credential=credential),
instructions="You are an operations assistant. Use your toolbox to research issues and log tickets.",
tools=[toolbox_tool],
)
result = await agent.run("Check current Azure status announcements and open a low-priority test ticket.")
print(result.text)
if __name__ == "__main__":
asyncio.run(main())
Important Production Rules for Toolboxes
When deploying Toolboxes in a corporate environment, keep these three architectural rules in mind:
- Unique Names for Duplicate Tool Types: A Toolbox allows at most one unnamed instance of built-in tools like Web Search, File Search, Code Interpreter, or Azure AI Search. If you want to put two different Azure AI Search indexes into the same Toolbox, you must set a unique
name property on each tool instance, or the API will return an invalid_payload error.
- Human-in-the-Loop Approval (
require_approval): For read-only tools (like looking up documentation), setting require_approval="never" lets the agent run unattended. For destructive tools (like deleting a database row or transferring money), set require_approval="always" so the Responses API pauses and returns an approval request to your UI before executing the tool call.
- Automating Scheduled Runs with Routines: If you need an agent and its Toolbox to run automatically every morning at 8:00 AM (for example, summarizing overnight server alerts), use Foundry Routines inside your project instead of spinning up external cron jobs or Azure Functions.
Join the conversation! Your thoughts help the community grow.