04 — Foundry Toolbox
Connect your hosted agent to a Foundry Toolbox — a managed collection of tools (Code Interpreter, File Search, and more) exposed via an MCP (Model Context Protocol) endpoint. Your agent gains powerful capabilities without you having to build or host them.
What you'll learn
- What a Foundry Toolbox is and how it works.
- Create a Toolbox with Code Interpreter and File Search in the Foundry portal.
- Connect to the Toolbox MCP endpoint using
MCPStreamableHTTPTool. - Authenticate with
get_bearer_token_providerand a customhttpx.Authclass. - Mix local tools and Toolbox tools in the same agent.
What is a Foundry Toolbox?
A Toolbox is a managed resource in your Foundry project that bundles one or more server-side tools behind an MCP-compliant endpoint. You create a Toolbox in the portal, add tools (like Code Interpreter or Web Search), and your agent connects to it over HTTP.
flowchart LR
Agent["Hosted Agent"] -->|MCP / Streamable HTTP| Toolbox["Foundry Toolbox"]
Toolbox --> CI["Code Interpreter"]
Toolbox --> FS["File Search (RAG)"]
Toolbox --> Custom["Custom tools (future)"]
Key properties:
| Feature | Detail |
|---|---|
| Protocol | MCP (Streamable HTTP transport) |
| Authentication | Azure AD bearer token (https://ai.azure.com/.default) |
| Required header | Foundry-Features: Toolboxes=V1Preview |
| Built-in tools | Code Interpreter, Web Search (Bing), File Search |
| Scope | Per Foundry project |
| Endpoint format | {project_endpoint}/toolboxes/{toolbox_name}/mcp?api-version=v1 |
Set up the vector store
File Search requires a vector store with at least one uploaded document. This lesson includes a sample clinical guidelines document in data/clinical-guidelines.md.
Upload via the Foundry portal
- Open your Foundry project → Data + indexes → Vector stores.
- Click + Create vector store → name it (e.g.,
workshop-guidelines). - Upload
data/clinical-guidelines.md. - Wait for processing to complete (a few seconds for this small file).
- Copy the vector store ID (starts with
vs_...) — you'll need it when adding File Search to your Toolbox.
Or use the REST API
# Create vector store
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
"$PROJECT_ENDPOINT/vector_stores?api-version=2025-11-15-preview" \
-d '{"name":"workshop-guidelines"}'
# Upload file
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-F "file=@data/clinical-guidelines.md" \
-F "purpose=assistants" \
"$PROJECT_ENDPOINT/files?api-version=2025-11-15-preview"
# Attach file to vector store
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
"$PROJECT_ENDPOINT/vector_stores/<VS_ID>/files?api-version=2025-11-15-preview" \
-d '{"file_id":"<FILE_ID>"}'
Create a Toolbox
Before deploying this lesson's agent, create a Toolbox in the Foundry portal:
- Open your Foundry project in the Foundry portal.
- Navigate to Build → Toolboxes.
- Click + Create toolbox.
- Give it a name (e.g.,
workshop-toolbox). - Add tools:
- Code Interpreter — executes Python code in a sandboxed environment.
- File Search — searches through uploaded documents using vector embeddings (requires a vector store with at least one uploaded file).
- Click Publish.
File Search requires a vector store
Before adding File Search to your Toolbox, create a vector store in your Foundry project and upload at least one document. The Toolbox will use this vector store for semantic search over your documents.
Toolbox name
Note the toolbox name — you'll need it for the TOOLBOX_NAME environment variable.
Update your .env
Add the toolbox name to your .env file:
Project structure
examples/04-toolbox/
├── main.py ← agent with Toolbox MCP integration
├── agent.yaml ← includes TOOLBOX_NAME env var
├── azure.yaml ← azd project manifest
├── Dockerfile
├── requirements.txt
└── data/
└── clinical-guidelines.md ← sample doc for File Search
The code
"""Lesson 04 — Foundry Toolbox."""
import os
from typing import Annotated
import httpx
from azure.identity import DefaultAzureCredential, get_bearer_token_provider
from dotenv import load_dotenv
from pydantic import Field
from agent_framework import Agent, MCPStreamableHTTPTool, tool
from agent_framework.foundry import FoundryChatClient
from agent_framework_foundry_hosting import ResponsesHostServer
load_dotenv()
credential = DefaultAzureCredential()
client = FoundryChatClient(
project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"],
model=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
credential=credential,
)
_TOOLBOX_FEATURES = "Toolboxes=V1Preview"
class _ToolboxAuth(httpx.Auth):
"""httpx Auth that injects a fresh bearer token on every request."""
def __init__(self, token_provider) -> None:
self._get_token = token_provider
def auth_flow(self, request: httpx.Request):
request.headers["Authorization"] = f"Bearer {self._get_token()}"
yield request
def resolve_toolbox_endpoint() -> str:
project_endpoint = os.environ["AZURE_AI_PROJECT_ENDPOINT"].rstrip("/")
toolbox_name = os.environ["TOOLBOX_NAME"]
return f"{project_endpoint}/toolboxes/{toolbox_name}/mcp?api-version=v1"
token_provider = get_bearer_token_provider(credential, "https://ai.azure.com/.default")
http_client = httpx.AsyncClient(
auth=_ToolboxAuth(token_provider),
headers={"Foundry-Features": _TOOLBOX_FEATURES},
timeout=120.0,
)
toolbox = MCPStreamableHTTPTool(
name="toolbox",
url=resolve_toolbox_endpoint(),
http_client=http_client,
load_prompts=False,
)
@tool(approval_mode="never_require")
def summarize_findings(
findings: Annotated[str, Field(description="The findings text to summarize")],
) -> str:
"""Summarize a set of findings into a concise bullet list."""
return f"Summary of findings:\n{findings}"
async def main() -> None:
agent = Agent(
client=client,
instructions=(
"You are a healthcare research assistant with access to a Foundry Toolbox. "
"Use the File Search tool to look up clinical guidelines and evidence-based recommendations. "
"Use the Code Interpreter tool to run Python code for data analysis and calculations. "
"Use the summarize_findings tool to compile your results. "
"Always cite sources and remind the user your answers are informational only."
),
tools=[summarize_findings, toolbox],
default_options={"store": False},
)
server = ResponsesHostServer(agent)
async with agent:
await server.run_async()
if __name__ == "__main__":
import asyncio
asyncio.run(main())
Step-by-step walkthrough
1. Toolbox authentication
_TOOLBOX_FEATURES = "Toolboxes=V1Preview"
class _ToolboxAuth(httpx.Auth):
def __init__(self, token_provider):
self._get_token = token_provider
def auth_flow(self, request):
request.headers["Authorization"] = f"Bearer {self._get_token()}"
yield request
token_provider = get_bearer_token_provider(credential, "https://ai.azure.com/.default")
http_client = httpx.AsyncClient(
auth=_ToolboxAuth(token_provider),
headers={"Foundry-Features": _TOOLBOX_FEATURES},
timeout=120.0,
)
The Toolbox MCP endpoint requires:
- An Azure AD bearer token scoped to
https://ai.azure.com/.default. - The feature header
Foundry-Features: Toolboxes=V1Previewon every request.
get_bearer_token_provider handles token caching and refresh automatically. The custom httpx.Auth class injects the token into each outbound request.
2. Build the Toolbox endpoint URL
def resolve_toolbox_endpoint() -> str:
project_endpoint = os.environ["AZURE_AI_PROJECT_ENDPOINT"].rstrip("/")
toolbox_name = os.environ["TOOLBOX_NAME"]
return f"{project_endpoint}/toolboxes/{toolbox_name}/mcp?api-version=v1"
The Toolbox MCP endpoint follows a predictable URL pattern. The ?api-version=v1 query parameter is required — omitting it returns a 400 error.
3. Create the MCP tool
toolbox = MCPStreamableHTTPTool(
name="toolbox",
url=resolve_toolbox_endpoint(),
http_client=http_client,
load_prompts=False,
)
MCPStreamableHTTPTool is MAF's built-in MCP client. It connects to the Toolbox and automatically discovers all available tools (Code Interpreter, Web Search, etc.).
load_prompts=False— required; the Toolbox MCP server does not implementprompts/list.- The
http_clientcarries both the authentication and the feature header.
4. Mix local and Toolbox tools
You can combine local @tool functions and MCP tools in the same tools list. The agent sees all of them as callable tools.
5. Async context manager
MCP tools require async initialization (to discover available tools from the server). The async with agent context manager connects to the Toolbox, discovers tools, then starts the server. On exit it cleanly disconnects.
6. agent.yaml with TOOLBOX_NAME
environment_variables:
- name: AZURE_AI_MODEL_DEPLOYMENT_NAME
value: ${AZURE_AI_MODEL_DEPLOYMENT_NAME}
- name: AZURE_AI_PROJECT_ENDPOINT
value: ${AZURE_AI_PROJECT_ENDPOINT}
- name: TOOLBOX_NAME
value: ${TOOLBOX_NAME}
The TOOLBOX_NAME environment variable is mapped from your Foundry project environment, just like the model deployment name.
Try it
Initialize the agent
The wizard will ask you to:
- Use the code in the current directory
- Allow
agent.yamloverwrite - Choose Container Image (Docker)
- Select your subscription and Foundry project
- Enter your ACR login server (e.g.
foundrywsadvaullah.azurecr.io) - Select your existing model deployment
Fix agent.yaml after init
azd ai agent init overwrites agent.yaml and removes custom environment variables.
After running init, ensure your agent.yaml includes all three env vars:
environment_variables:
- name: AZURE_AI_MODEL_DEPLOYMENT_NAME
value: ${AZURE_AI_MODEL_DEPLOYMENT_NAME}
- name: AZURE_AI_PROJECT_ENDPOINT
value: ${AZURE_AI_PROJECT_ENDPOINT}
- name: TOOLBOX_NAME
value: ${TOOLBOX_NAME}
Without AZURE_AI_PROJECT_ENDPOINT, the Toolbox endpoint cannot be resolved.
Without TOOLBOX_NAME, the agent won't know which Toolbox to connect to.
Set the Toolbox name in your environment
Make sure the Toolbox exists in your Foundry project and the name matches:
This registers the variable in your azd environment so it gets injected into the agent at deploy time. For local testing, also add it to your .env file:
Run locally
Toolbox tools require cloud connectivity
Unlike lessons 01–03, the Toolbox MCP endpoint is a remote service. Even when running locally, your agent makes outbound calls to the Toolbox endpoint. Ensure you are authenticated (az login) and the Toolbox exists in your project.
Invoke (in a separate terminal)
cd examples/04-toolbox
azd ai agent invoke --local "Use Code Interpreter to calculate the average BMI from this data: weights = [72, 85, 68, 95, 78], heights = [1.75, 1.82, 1.60, 1.90, 1.68]"
Expected: the agent writes and executes Python code, returns the computed averages.
File Search:
azd ai agent invoke --local "What are the LDL-C targets for a very high risk patient with established cardiovascular disease?"
Expected: the agent searches the clinical guidelines document and returns the target (< 1.4 mmol/L and ≥ 50% reduction).
Combining both tools:
azd ai agent invoke --local "Look up the CHA2DS2-VASc scoring criteria, then use code interpreter to calculate the score for a 70-year-old woman with hypertension and diabetes."
Expected: the agent retrieves the scoring table via File Search, then uses Code Interpreter to compute the score.
Deploy to the cloud
This builds the container remotely, pushes to ACR, and deploys the agent to Foundry.
After the first deploy, assign the Foundry User role to the agent's managed identity:
AGENT_NAME=toolbox-agent
PROJECT_NAME=${BASE_NAME}-project
AGENT_IDENTITY=$(az ad sp list \
--display-name "${BASE_NAME}-${PROJECT_NAME}-${AGENT_NAME}-AgentIdentity" \
--query "[0].id" -o tsv)
az role assignment create \
--assignee-object-id "$AGENT_IDENTITY" \
--assignee-principal-type ServicePrincipal \
--role "53ca6127-db72-4b80-b1b0-d745d6d5456d" \
--scope "$ACCOUNT_ID"
Stale conversation after RBAC errors
If you invoke the agent before the role assignment propagates, azd caches a
conversation ID that was never persisted server-side. Subsequent calls will fail with
404 Conversation not found. Fix it by forcing a new conversation:
Then invoke remotely:
azd ai agent invoke "What are the first-line medications for hypertension according to the guidelines? Use Code Interpreter to create a comparison table."
Key takeaways
- A Toolbox bundles managed tools (Code Interpreter, File Search, Web Search) behind an MCP endpoint.
MCPStreamableHTTPTooldiscovers and connects to Toolbox tools automatically.- Authentication uses
get_bearer_token_providerwith scopehttps://ai.azure.com/.default. - The
Foundry-Features: Toolboxes=V1Previewheader is required on all requests. - The endpoint URL must include
?api-version=v1. load_prompts=Falseis mandatory (Toolbox doesn't implementprompts/list).- File Search requires a vector store with uploaded documents.
- Local
@toolfunctions and Toolbox MCP tools can be mixed in the same agent.