> ## Documentation Index
> Fetch the complete documentation index at: https://hobbyist-e43fa225.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Use a toolbox with a hosted agent in Microsoft Foundry

> Connect a hosted agent to a Microsoft Foundry toolbox over MCP by using Agent Framework, LangGraph, the Foundry Toolkit, or the Azure Developer CLI.

export const ZonePivot = ({group, options = [], defaultValue, label = "Choose an experience"}) => {
  const values = options.map(option => option.id);
  const optionKey = options.map(option => `${option.id}:${option.title}`).join("|");
  const [activePivot, setActivePivot] = useState(defaultValue || values[0]);
  const slugify = value => value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
  const resolvePivot = () => {
    if (typeof window === "undefined") return defaultValue || values[0];
    const params = new URLSearchParams(window.location.search);
    const requested = params.get("pivots");
    if (requested) {
      const requestedIds = requested.split(",").map(value => value.trim()).filter(Boolean);
      const match = requestedIds.find(id => values.includes(id));
      if (match) return match;
    }
    const hash = window.location.hash.replace(/^#/, "");
    if (hash) {
      const match = options.find(option => option.id === hash || slugify(option.title) === hash);
      if (match) return match.id;
    }
    try {
      const stored = window.localStorage.getItem(`foundry-zone-pivot:${group}`);
      if (values.includes(stored)) return stored;
    } catch {
      return defaultValue || values[0];
    }
    return defaultValue || values[0];
  };
  const publishPivotChange = value => {
    if (typeof window === "undefined") return;
    window.dispatchEvent(new CustomEvent("foundry-zone-pivot-change", {
      detail: {
        group,
        value
      }
    }));
  };
  const syncTableOfContents = () => {
    if (typeof window === "undefined") return;
    window.requestAnimationFrame(() => {
      const toc = document.getElementById("table-of-contents-content");
      if (!toc) return;
      const links = Array.from(toc.querySelectorAll('a[href^="#"]'));
      for (const link of links) {
        const item = link.closest("li");
        const rawId = link.getAttribute("href")?.slice(1);
        if (!item || !rawId) continue;
        let id = rawId;
        try {
          id = decodeURIComponent(rawId);
        } catch {}
        item.style.display = document.getElementById(id) ? "" : "none";
      }
    });
  };
  useEffect(() => {
    const resolvedPivot = resolvePivot();
    setActivePivot(resolvedPivot);
    publishPivotChange(resolvedPivot);
    window.setTimeout(syncTableOfContents, 0);
  }, [group, defaultValue, values.join("|"), optionKey]);
  const selectPivot = value => {
    setActivePivot(value);
    if (typeof window !== "undefined") {
      try {
        window.localStorage.setItem(`foundry-zone-pivot:${group}`, value);
      } catch {}
      const url = new URL(window.location.href);
      const current = url.searchParams.get("pivots");
      const preserved = current ? current.split(",").map(id => id.trim()).filter(id => id && !values.includes(id)) : [];
      url.searchParams.set("pivots", [...preserved, value].join(","));
      window.history.replaceState(null, "", `${url.pathname}${url.search}${url.hash}`);
    }
    publishPivotChange(value);
    window.setTimeout(syncTableOfContents, 0);
  };
  if (options.length < 2) return null;
  return <div className="not-prose my-6 border-b border-slate-200 pb-3 dark:border-slate-800">
      <div className="mb-2 text-xs font-semibold uppercase tracking-wide text-slate-500 dark:text-slate-400">
        {label}
      </div>
      <div className="flex flex-wrap gap-2" role="tablist" aria-label={label}>
        {options.map(option => {
    const selected = option.id === activePivot;
    return <button key={option.id} type="button" role="tab" aria-selected={selected} onClick={() => selectPivot(option.id)} className={`rounded-md border px-3 py-1.5 text-sm font-medium transition ${selected ? "border-slate-900 bg-slate-900 text-white shadow-sm dark:border-slate-100 dark:bg-slate-100 dark:text-slate-950" : "border-slate-200 bg-white text-slate-700 hover:border-slate-400 hover:text-slate-950 dark:border-slate-700 dark:bg-slate-950 dark:text-slate-200 dark:hover:border-slate-500"}`}>
              {option.title}
            </button>;
  })}
      </div>
    </div>;
};

export const ZoneContent = ({group, value, options = [], values = [], defaultValue, children}) => {
  const optionKey = options.map(option => `${option.id}:${option.title}`).join("|");
  const [activePivot, setActivePivot] = useState(defaultValue || values[0]);
  const slugify = value => value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
  const resolvePivot = () => {
    if (typeof window === "undefined") return defaultValue || values[0];
    const params = new URLSearchParams(window.location.search);
    const requested = params.get("pivots");
    if (requested) {
      const requestedIds = requested.split(",").map(value => value.trim()).filter(Boolean);
      const match = requestedIds.find(id => values.includes(id));
      if (match) return match;
    }
    const hash = window.location.hash.replace(/^#/, "");
    if (hash) {
      const match = options.find(option => option.id === hash || slugify(option.title) === hash);
      if (match) return match.id;
    }
    try {
      const stored = window.localStorage.getItem(`foundry-zone-pivot:${group}`);
      if (values.includes(stored)) return stored;
    } catch {
      return defaultValue || values[0];
    }
    return defaultValue || values[0];
  };
  useEffect(() => {
    setActivePivot(resolvePivot());
  }, [group, defaultValue, values.join("|"), optionKey]);
  useEffect(() => {
    const onPivotChange = event => {
      if (event.detail?.group === group && values.includes(event.detail.value)) {
        setActivePivot(event.detail.value);
      }
    };
    window.addEventListener("foundry-zone-pivot-change", onPivotChange);
    return () => window.removeEventListener("foundry-zone-pivot-change", onPivotChange);
  }, [group, values.join("|")]);
  if (activePivot !== value) return null;
  return <>{children}</>;
};

A [hosted agent](/agents/hosted-agents) runs your code in Foundry Agent Service. In this article, you connect that code to a [toolbox](/get-started/toolbox-overview) so the agent discovers and calls the toolbox tools through one Model Context Protocol (MCP) endpoint.

If you use a coding agent like GitHub Copilot, the [Microsoft Foundry Skill](/get-started/use-microsoft-foundry-skill) can help connect the hosted agent to a toolbox endpoint and adapt the sample to your own tools.

## Prerequisites

* A [toolbox](/toolboxes/toolbox) with at least one tool and a default version.
* A Microsoft Foundry project with a deployed model.
* A hosted-agent project. To create the agent and toolbox together, complete the [toolbox quickstart](/agents/quickstart-toolbox-agent).
* A development identity that can access the Foundry project. Sign in locally with `az login` or `azd auth login` before you run a sample.
* Any permissions required by the services behind the toolbox tools. For tools that use OAuth or Microsoft Entra identity passthrough, review [Toolbox authentication](/toolboxes/tool-authentication) before you deploy the agent.

## Choose the toolbox endpoint

Use the toolbox consumer endpoint for an agent that should follow the toolbox's `default_version`:

```http theme={null}
https://<account>.services.ai.azure.com/api/projects/<project>/toolboxes/<toolbox-name>/mcp?api-version=v1
```

When you promote another toolbox version to default, an agent that uses this endpoint gets the new version without an endpoint change or redeployment.

Use a version-specific developer endpoint only when you need to test an immutable version before promotion:

```http theme={null}
https://<account>.services.ai.azure.com/api/projects/<project>/toolboxes/<toolbox-name>/versions/<version>/mcp?api-version=v1
```

## Authenticate the agent to the toolbox

The agent authenticates to the toolbox endpoint with its Microsoft Entra identity and the `https://ai.azure.com/.default` scope. The connection for each toolbox tool determines which identity or credential reaches the downstream service.

Don't put downstream API keys or OAuth tokens in the agent code. Configure those credentials on the project connection that the toolbox tool references. For details about supported authentication types, consent, and role requirements, see [Toolbox authentication](/toolboxes/tool-authentication).

## Connect the hosted agent

<ZonePivot group="azd__dotnet__javascript__python__rest-api__vscode" options={[{"id": "python", "title": "Python"}, {"id": "dotnet", "title": ".NET"}, {"id": "rest-api", "title": "REST API"}, {"id": "javascript", "title": "JavaScript"}, {"id": "vscode", "title": "VS Code"}, {"id": "azd", "title": "Azure Developer CLI"}]} defaultValue="python" />

<ZoneContent group="azd__dotnet__javascript__python__rest-api__vscode" value="python" options={[{"id": "python", "title": "Python"}, {"id": "dotnet", "title": ".NET"}, {"id": "rest-api", "title": "REST API"}, {"id": "javascript", "title": "JavaScript"}, {"id": "vscode", "title": "VS Code"}, {"id": "azd", "title": "Azure Developer CLI"}]} values={["python", "dotnet", "rest-api", "javascript", "vscode", "azd"]} defaultValue="python">
  ### Use Microsoft Agent Framework

  The maintained Python sample uses `FoundryToolbox` from the Agent Framework hosting package. The class resolves the toolbox from `TOOLBOX_ENDPOINT`, or from `FOUNDRY_PROJECT_ENDPOINT` and `TOOLBOX_NAME`. It also authenticates MCP requests and forwards the hosted runtime's per-request call ID.

  Install Python 3.12 or later, Azure Developer CLI (`azd`) 1.25 or later, and the `microsoft.foundry` extension before you initialize the sample.

  1. Initialize a project from the [hosted-agent toolbox sample](https://github.com/microsoft-foundry/foundry-samples/tree/main/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox):

     ```bash theme={null}
     mkdir my-toolbox-agent && cd my-toolbox-agent
     azd ai agent init -m https://github.com/microsoft-foundry/foundry-samples/blob/main/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/azure.yaml
     ```

  2. Set the toolbox name. The sample constructs the consumer endpoint from the project endpoint and this name:

     ```bash theme={null}
     azd env set TOOLBOX_NAME <toolbox-name>
     ```

  3. Run the agent locally:

     ```bash theme={null}
     azd ai agent run
     ```

  4. In another terminal, verify that the agent discovers the toolbox tools:

     ```bash theme={null}
     azd ai agent invoke --local "List the tools you can use and briefly describe each one."
     ```

  The response lists the tools that the toolbox returns from MCP `tools/list`. If the response contains no toolbox tools, see [Troubleshoot the connection](#troubleshoot-the-connection).

  ### Use LangGraph

  Use `AzureAIProjectToolbox` when your hosted-agent code is built with LangGraph. The integration loads the toolbox tools as LangChain tools and handles authentication to the consumer endpoint.

  1. Install the LangChain Azure integration and its hosting dependencies:

     ```bash theme={null}
     pip install "langchain-azure-ai[hosting]>=1.2.8"
     ```

  2. Set `FOUNDRY_PROJECT_ENDPOINT` in the hosted-agent environment. The runtime supplies this value after deployment. Set it yourself for local development.

  3. Load the tools by toolbox name:

  ```python theme={null}
  import asyncio

  from langchain_azure_ai.tools import AzureAIProjectToolbox

  async def load_tools():
     toolbox = AzureAIProjectToolbox(toolbox_name="<toolbox-name>")
     tools = await toolbox.get_tools()
     print("\n".join(tool.name for tool in tools))

  asyncio.run(load_tools())
  ```

  The output contains the names that the toolbox returns from MCP `tools/list`:

  ```output theme={null}
  <tool-name>
  <tool-name>
  ```

  **Reference:** [AzureAIProjectToolbox](https://pypi.org/project/langchain-azure-ai/)

  1. Pass the loaded tools to your LangGraph agent and run a prompt that requires one of the toolbox tools. For a complete implementation, see the [LangGraph toolbox sample](https://aka.ms/foundry-toolbox-langgraph).
</ZoneContent>

<ZoneContent group="azd__dotnet__javascript__python__rest-api__vscode" value="dotnet" options={[{"id": "python", "title": "Python"}, {"id": "dotnet", "title": ".NET"}, {"id": "rest-api", "title": "REST API"}, {"id": "javascript", "title": "JavaScript"}, {"id": "vscode", "title": "VS Code"}, {"id": "azd", "title": "Azure Developer CLI"}]} values={["python", "dotnet", "rest-api", "javascript", "vscode", "azd"]} defaultValue="python">
  Use the Agent Framework Foundry hosting integration to register a toolbox by name. `AddFoundryToolboxes` constructs the consumer endpoint from `FOUNDRY_PROJECT_ENDPOINT`, calls MCP `tools/list` during startup, and adds the discovered tools to each agent request.

  Install the .NET 10 SDK and Azure CLI before you run the maintained sample.

  1. Start from the public [hosted toolbox sample](https://github.com/microsoft/agent-framework/tree/main/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-Toolbox), or add the Foundry hosting package to an existing Agent Framework host.

  2. Set these environment variables for local development:

     ```text theme={null}
     AZURE_AI_PROJECT_ENDPOINT=https://<account>.services.ai.azure.com/api/projects/<project>
     AZURE_AI_MODEL_DEPLOYMENT_NAME=<model-deployment-name>
     TOOLBOX_NAME=<toolbox-name>
     ```

     Foundry supplies `FOUNDRY_PROJECT_ENDPOINT` to the deployed container. Keep the toolbox name in `TOOLBOX_NAME`; other `FOUNDRY_*` variable names are reserved by the hosted runtime.

  3. In `Program.cs`, register the agent with `AddFoundryResponses`, and then register the toolbox with `AddFoundryToolboxes(credential, toolboxName)`. After you build the web application, call `MapFoundryResponses` before `Run`. The public sample includes the required imports, packages, agent construction, and credential setup.

  4. Start the host, and then invoke it with a prompt that requires a toolbox tool. The `/readiness` endpoint returns an unhealthy status when the host can't enumerate the toolbox tools.
</ZoneContent>

<ZoneContent group="azd__dotnet__javascript__python__rest-api__vscode" value="rest-api" options={[{"id": "python", "title": "Python"}, {"id": "dotnet", "title": ".NET"}, {"id": "rest-api", "title": "REST API"}, {"id": "javascript", "title": "JavaScript"}, {"id": "vscode", "title": "VS Code"}, {"id": "azd", "title": "Azure Developer CLI"}]} values={["python", "dotnet", "rest-api", "javascript", "vscode", "azd"]} defaultValue="python">
  The hosted-agent toolbox integrations in this article are available for Python and .NET. To call the MCP endpoint from another runtime, use an MCP Streamable HTTP client, authenticate with a token for `https://ai.azure.com/.default`, and implement the hosted-agent runtime contract.
</ZoneContent>

<ZoneContent group="azd__dotnet__javascript__python__rest-api__vscode" value="javascript" options={[{"id": "python", "title": "Python"}, {"id": "dotnet", "title": ".NET"}, {"id": "rest-api", "title": "REST API"}, {"id": "javascript", "title": "JavaScript"}, {"id": "vscode", "title": "VS Code"}, {"id": "azd", "title": "Azure Developer CLI"}]} values={["python", "dotnet", "rest-api", "javascript", "vscode", "azd"]} defaultValue="python">
  The hosted-agent toolbox integrations in this article are available for Python and .NET. To call the MCP endpoint from another runtime, use an MCP Streamable HTTP client, authenticate with a token for `https://ai.azure.com/.default`, and implement the hosted-agent runtime contract.
</ZoneContent>

<ZoneContent group="azd__dotnet__javascript__python__rest-api__vscode" value="vscode" options={[{"id": "python", "title": "Python"}, {"id": "dotnet", "title": ".NET"}, {"id": "rest-api", "title": "REST API"}, {"id": "javascript", "title": "JavaScript"}, {"id": "vscode", "title": "VS Code"}, {"id": "azd", "title": "Azure Developer CLI"}]} values={["python", "dotnet", "rest-api", "javascript", "vscode", "azd"]} defaultValue="python">
  Use the Microsoft Foundry Toolkit for Visual Studio Code to scaffold a hosted-agent sample that's connected to a toolbox.

  Install Visual Studio Code, the Microsoft Foundry Toolkit extension, and the extension pack for your programming language before you scaffold the project.

  1. In the Activity Bar, select **Foundry Toolkit**.
  2. Under **My Resources**, expand your project, and then expand **Tools**.
  3. On the **Toolboxes** tab, find the toolbox, and then select **Scaffold code template**.
  4. In the Command Palette, select a project folder.
  5. Open the generated `README.md`, and then complete its local run and deployment steps.
  6. Run a prompt that requires a toolbox tool and confirm that the agent calls the expected tool.
</ZoneContent>

<ZoneContent group="azd__dotnet__javascript__python__rest-api__vscode" value="azd" options={[{"id": "python", "title": "Python"}, {"id": "dotnet", "title": ".NET"}, {"id": "rest-api", "title": "REST API"}, {"id": "javascript", "title": "JavaScript"}, {"id": "vscode", "title": "VS Code"}, {"id": "azd", "title": "Azure Developer CLI"}]} values={["python", "dotnet", "rest-api", "javascript", "vscode", "azd"]} defaultValue="python">
  Pass the toolbox name to a hosted-agent sample that constructs the consumer endpoint from `FOUNDRY_PROJECT_ENDPOINT`:

  Install Azure Developer CLI (`azd`) 1.25 or later and the `microsoft.foundry` extension before you run these commands.

  1. Inspect the toolbox and its current default version:

     ```bash theme={null}
     azd ai toolbox show <toolbox-name> --output json
     ```

     The output uses the `endpoint` property. The endpoint returned by this command identifies the selected version and is useful for testing that version.

  2. Store the toolbox name in the `azd` environment:

     ```bash theme={null}
     azd env set TOOLBOX_NAME <toolbox-name>
     ```

  3. To run the hosted agent locally, use:

     ```bash theme={null}
     azd ai agent run
     ```

     To deploy the hosted agent instead, use:

     ```bash theme={null}
     azd deploy
     ```

  If your application accepts only a complete URL, set `TOOLBOX_ENDPOINT` to the unversioned consumer endpoint from [Choose the toolbox endpoint](#choose-the-toolbox-endpoint).
</ZoneContent>

## Enforce tool approval

Each entry returned by MCP `tools/list` can contain a `_meta.tool_configuration.require_approval` value:

| Value    | Required runtime behavior                                                                                                                                          |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `always` | Show the proposed tool name and arguments to the user, wait for an explicit approval, and invoke the tool only after approval. Repeat this process for every call. |
| `never`  | Invoke the tool without an approval prompt.                                                                                                                        |

The toolbox MCP endpoint doesn't block `tools/call` when `require_approval` is `always`. Your agent runtime must enforce the setting before every invocation. A system-prompt instruction alone doesn't enforce approval.

Use `require_approval: never` unless your runtime can pause the pending tool call, collect the user's decision, and resume or reject that exact call. To configure the value on a toolbox tool, see [Configure tool approval](/toolboxes/toolbox#configure-require_approval-on-a-tool).

## Troubleshoot the connection

| Symptom                             | Cause and resolution                                                                                                                                                                                                  |
| ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| The agent returns no toolbox tools. | Confirm that the toolbox has a default version, the toolbox name matches, and the agent identity can access the Foundry project.                                                                                      |
| Startup or readiness fails.         | A toolbox enumerates all its tool sources together. Check agent logs for a failing connection, unavailable MCP server, or invalid allowed-tool name. Fix or remove that source, create a new version, and promote it. |
| A tool returns `401` or `403`.      | Verify the agent-to-toolbox identity and the downstream authentication configured on the tool's project connection. These are separate authorization boundaries.                                                      |
| A tool requests consent.            | Return the consent request to the signed-in user and resume the call after consent. Review the tenant and role requirements in [Toolbox authentication](/toolboxes/tool-authentication).                              |
| A version change doesn't appear.    | Confirm that the agent uses the unversioned consumer endpoint and that you promoted the intended version to `default_version`.                                                                                        |

## Related content

* [Create and manage a toolbox](/toolboxes/toolbox)
* [Toolbox authentication](/toolboxes/tool-authentication)
* [Quickstart: Build a toolbox and use it with a hosted agent](/agents/quickstart-toolbox-agent)
