Give an agent five tools and it picks the right one almost every time. Give it two hundred and three things go wrong together. Every turn costs more tokens, the context fills with tool definitions the task never needs, and the model starts choosing the wrong tool. Microsoft Foundry has a built-in answer to this: tool search in Toolboxes.

What a toolbox is

A toolbox is a named, versioned bundle of tools that your agents reach through one endpoint. The tools can be remote MCP servers or built-in Foundry tools. You curate the toolbox once, publish a version, and any agent that needs those capabilities can use it. As of Microsoft's September 2026 update, toolboxes are generally available for hosted agents and in public preview for prompt agents.

How tool search works

You turn tool search on by adding one entry, {"type": "toolbox_search"}, to the toolbox version. After that, the toolbox no longer lists its tools to the model. The model sees two meta-tools instead:

Foundry ranks the toolbox's tools against the query using BM25, a standard text-ranking method that scores each tool's name, description, and parameter information. It returns the best matches, five by default and ten at most. Tools that come back stay callable for the rest of the turn, and the model can search again if a later step needs something else.

Microsoft reports that in an internal evaluation on a public benchmark of more than 44,000 tools, tool search cut input tokens by more than 60% for a 50-tool toolbox and by over 97% for a 1,000-tool toolbox. Those numbers compare against a prompt-cached baseline that loads the whole catalog up front. They are Microsoft's results, so measure your own agent before you quote them.

Create a toolbox with tool search

You need a Foundry project, the Foundry User role on that project, and a project connection for any MCP server that requires credentials. Here is the Python version:

import os
from azure.identity import DefaultAzureCredential
from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import MCPToolboxTool, ToolSearchToolboxTool

project = AIProjectClient(
    endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
    credential=DefaultAzureCredential(),
)

github_tools = MCPToolboxTool(
    server_label="github",
    server_url="https://api.githubcopilot.com/mcp",
    require_approval="never",  # use "always" for tools that change data
    project_connection_id="your-connection-id",
)

version = project.toolboxes.create_version(
    name="my-toolbox",
    description="Large toolbox with tool search enabled",
    tools=[github_tools, ToolSearchToolboxTool()],
)
print(f"Created toolbox {version.name}, version {version.version}")

The same thing in C#:

using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Identity;

var endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT");
AIProjectClient projectClient = new(endpoint: new Uri(endpoint), tokenProvider: new DefaultAzureCredential());
AgentToolboxes toolboxClient = projectClient.AgentAdministrationClient.GetAgentToolboxes();

MCPToolboxTool githubTools = new(serverLabel: "github")
{
    ServerUri = new Uri("https://api.githubcopilot.com/mcp"),
    ToolCallApprovalPolicy = new McpToolCallApprovalPolicy(
        GlobalMcpToolCallApprovalPolicy.NeverRequireApproval),
};
ToolSearchToolboxTool searchTool = new()
{
    Name = "ToolBoxSearch",
    Description = "Search for tools by capability"
};

ToolboxVersion version = toolboxClient.CreateVersion(
    name: "my-toolbox",
    tools: [githubTools, searchTool],
    description: "Large toolbox with tool search enabled");
Console.WriteLine($"Created toolbox {version.Name}, version {version.Version}");

Publishing creates the first version, and it becomes the default automatically. These APIs are still in preview, so pin your package version and check the docs if a type has moved.

Check that it is working

Every toolbox version has its own MCP endpoint, so you can inspect it with any MCP client before you promote the version. If tool search is on, the tool list should contain tool_search and call_tool and nothing else, apart from tools you pinned.

import asyncio
from azure.identity import DefaultAzureCredential
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

url = ("https://<account>.services.ai.azure.com/api/projects/<project>"
       "/toolboxes/my-toolbox/versions/<version>/mcp?api-version=v1")
token = DefaultAzureCredential().get_token("https://ai.azure.com/.default").token

async def main():
    async with streamablehttp_client(url, headers={"Authorization": f"Bearer {token}"}) as (read, write, _):
        async with ClientSession(read, write) as session:
            await session.initialize()
            tools = await session.list_tools()
            print([t.name for t in tools.tools])

asyncio.run(main())

Tune what the model finds

Search works without extra settings, but two options help when you know your usage. pin keeps a tool permanently visible, so the model can call it without a search round trip. additional_search_text adds keywords to a tool's search entry when the server's own description uses different words than your users do. The extra text is used only for ranking and is never shown to the model.

{
    "type": "mcp",
    "server_label": "analytics",
    "server_url": "https://db-mcp.internal/sse",
    "tool_configs": {
        "execute_query": {
            "pin": True,
            "additional_search_text": "SQL database analytics reporting dashboard queries",
        },
        "list_tables": {
            "additional_search_text": "schema columns metadata table structure discover",
        },
    },
}

Foundry also tracks which tools each user calls most and surfaces them automatically after a short warmup, so the most-used tools skip the search step without any configuration.

Practical tips

Resources