Tools and Toolboxes (azd ai)
How to attach tools (web search, Azure AI Search, MCP, A2A) to a hosted agent using azd ai toolbox and azd ai agent connection.
A toolbox is a curated bundle of connection-backed tools that Foundry exposes as a single MCP-compatible endpoint. The agent connects to one URL and discovers every tool inside. azd deploy does NOT auto-create toolboxes -- you drive the lifecycle explicitly.
🚦 Toolbox creation gate: before creating a toolbox/connection, you MUST read the boundary rules in create-hosted.md → Toolbox creation boundary and follow them, then continue with the rest of this file.
Install the extension once
azd extension install azure.ai.toolboxesThe flow (every recipe)
- Create the connection (
azd ai agent connection create ...). - Create or update the toolbox (
azd ai toolbox create/connection add). - Read the endpoint (
azd ai toolbox show <name> --output json). azd env set TOOLBOX_<NAME>_MCP_ENDPOINT "<endpoint>".- Reference it in
<service-dir>/agent.yamlenvironment_variables[]. azd deploy.
Env var naming convention
Uppercase the toolbox name, collapse non-alphanumeric to _, prefix TOOLBOX_, suffix _MCP_ENDPOINT. Examples: agent-tools -> TOOLBOX_AGENT_TOOLS_MCP_ENDPOINT, agent.tools.v2 -> TOOLBOX_AGENT_TOOLS_V2_MCP_ENDPOINT.
Endpoint URL shapes
{project}/toolboxes/{name}/versions/{version}/mcp?api-version=v1-- version-pinned. Whatazd ai toolbox showreturns.{project}/toolboxes/{name}/mcp?api-version=v1-- default version (consumer). Always servesdefault_version.
To auto-pick up new default versions without redeploying, drop the /versions/<ver> segment and store the consumer URL.
CLI surface
| Command | What it does |
|---|---|
azd ai toolbox create <name> --from-file <path> | Create toolbox + publish v1. File must list at least one connection. |
azd ai toolbox connection add <toolbox> <connection> [--index ...] [--instance-name ...] | Attach one; new default version. |
azd ai toolbox connection add <toolbox> --from-file <path> | Attach many in one call; ONE new version. |
azd ai toolbox connection remove <toolbox> <connection> | Detach; new default version. Refuses to leave zero tools. |
azd ai toolbox show <name> [--version <ver>] | Show toolbox + MCP endpoint URL. |
azd ai toolbox list | List toolboxes. |
azd ai toolbox version list <toolbox> | List versions. |
azd ai toolbox update <name> --default-version <ver> | Re-point default (rollback). |
azd ai toolbox delete <name> [--version <ver>] [--force] | Delete toolbox or one version. |
Every mutation publishes a new immutable version and promotes it to default.
--from-file shape
description: research toolbox # only on `create`
connections:
- name: my-mcp # RemoteTool
- name: my-search # CognitiveSearch -- needs index
index: products
- name: my-bing # GroundingWithCustomSearch -- needs instance_name
instance_name: docs-config
- name: my-a2a # RemoteA2ARecipe: GitHub MCP
# 1. Connection
azd ai agent connection create github-mcp-conn \
--kind remote-tool \
--target https://api.githubcopilot.com/mcp \
--auth-type custom-keys \
--custom-key Authorization="Bearer ghp_xxx..."
# 2. Toolbox (initial create needs a file; otherwise use `connection add`)
cat > tools.json <<EOF
{ "description": "GitHub MCP", "connections": [{ "name": "github-mcp-conn" }] }
EOF
azd ai toolbox create agent-tools --from-file tools.json
# 3. Wire the env var
ENDPOINT=$(azd ai toolbox show agent-tools --output json | jq -r .endpoint)
azd env set TOOLBOX_AGENT_TOOLS_MCP_ENDPOINT "$ENDPOINT"Add the env var to <service-dir>/agent.yaml:
environment_variables:
- name: TOOLBOX_AGENT_TOOLS_MCP_ENDPOINT
value: ${TOOLBOX_AGENT_TOOLS_MCP_ENDPOINT}Then azd deploy.
Recipe: Azure AI Search RAG
azd ai agent connection create my-search-conn \
--kind cognitive-search \
--target https://my-search.search.windows.net/ \
--auth-type api-key --key "<search-admin-key>"
azd ai toolbox connection add agent-tools my-search-conn --index contoso-outdoorsFor multiple indexes, add multiple entries with different index values.
Recipe: A2A peer agent
azd ai agent connection create peer-agent-conn \
--kind remote-a2a \
--target https://other-agent.foundry-account.westus2.azure.com/ \
--auth-type none
azd ai toolbox connection add agent-tools peer-agent-connFor authenticated peers, use --auth-type project-managed-identity --audience https://ai.azure.com/.default.
Recipe: multi-tool toolbox in one call
# tools.yaml
description: "GitHub MCP + AI Search + A2A peer."
connections:
- name: github-mcp-conn
- name: my-search-conn
index: contoso-outdoors
- name: peer-agent-connazd ai toolbox create agent-tools --from-file tools.yaml
# OR (existing toolbox): azd ai toolbox connection add agent-tools --from-file tools.yamlOne new default version regardless of how many connections you attach in one call.
Tools the CLI does NOT manage today
azd ai toolbox only handles connection-backed tools (RemoteTool, CognitiveSearch, RemoteA2A, GroundingWithCustomSearch). These built-ins have no connection and are NOT addable via this CLI: web_search, code_interpreter, file_search, function, toolbox_search_preview.
To include any built-in in a toolbox today, use the Python / .NET / JS SDK or call the REST API directly.
Required header (agent code)
Every MCP request to the toolbox endpoint must include:
Foundry-Features: Toolboxes=V1PreviewToken scope: https://ai.azure.com/.default. RBAC: the calling identity (developer + agent identity at runtime) needs Foundry User on the Foundry project.
Agent code (Python, Microsoft Agent Framework)
import os, httpx
from azure.identity import DefaultAzureCredential
from agent_framework.tools.mcp import MCPStreamableHTTPTool
_credential = DefaultAzureCredential()
def _inject_auth(request: httpx.Request) -> None:
# Per-request token refresh -- static tokens expire in ~1 hour.
token = _credential.get_token("https://ai.azure.com/.default").token
request.headers["Authorization"] = f"Bearer {token}"
request.headers["Foundry-Features"] = "Toolboxes=V1Preview"
tool = MCPStreamableHTTPTool(
name="github", # becomes server_label prefix
url=os.environ["TOOLBOX_AGENT_TOOLS_MCP_ENDPOINT"],
httpx_client=httpx.AsyncClient(event_hooks={"request": [_inject_auth]}),
load_prompts=False, # Foundry doesn't implement prompts/list
approval_mode="never_require", # for require_approval:always tools
)Install: pip install httpx azure-identity agent-framework.
MCP client gotchas
- Always stream. Non-streaming is not supported.
- Don't call
prompts/list. Returns500. Passload_prompts=False. - Don't
send_ping()with generic clients (returns500). Agent Framework handles this. - Tool names are prefixed with
server_label.name="myserver"-> tools appear asmyserver.<tool>. require_approvalis the client's responsibility -- the toolbox proxy does NOT enforce it. Passapproval_mode="never_require"or wire an approval handler.
Verify the wire end-to-end
azd ai toolbox list --output json
azd ai toolbox show agent-tools --output json
azd deploy
azd ai agent invoke "list the tools you have access to"Troubleshooting
| Symptom | Likely cause |
|---|---|
TOOLBOX_<NAME>_MCP_ENDPOINT not set | Run azd ai toolbox show + azd env set. |
| Env var missing in deployed agent | Add to agent.yaml environment_variables[], azd deploy. |
400 mentioning Toolboxes | Missing Foundry-Features: Toolboxes=V1Preview header. |
401 on MCP calls | Expired / wrong-scope token. Use https://ai.azure.com/.default; refresh per request. |
403 Forbidden | Caller missing Foundry User role. |
500 on prompts/list / ping | Disable in MCP client (load_prompts=False). |
| Empty response, tool never called | require_approval: always with no handler. Pass approval_mode="never_require". |
tools/list returns zero | Bad credentials, or toolbox version still provisioning. |
| Tool names don't match | Use {server_label}.{tool_name}. |