Use a Toolbox from Your Agent Code
A toolbox is a single MCP-compatible endpoint that exposes all the tools you've configured; your agent connects to that one URL and discovers every tool inside. For the concept, object model, and API/schema, see toolbox.md.
There are two ways to consume it from agent code:
- Default SDK — Microsoft Agent Framework (MAF). The
FoundryToolboxwrapper does all the plumbing (endpoint resolution, auth, per-request call-id, connect/close). This is the happy path below. - Other — LangGraph, generic/BYO raw MCP client, or C#. You wire the MCP client yourself. See Bring Your Own (BYO) — raw MCP client.
🚦 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.
💡 This skill covers consuming an existing toolbox from agent code. To add a tool (
web_search,file_search,azure_ai_search,code_interpreter,openapi,mcp,a2a_preview, …), don't wire it to the agent — put it in a toolbox first, via theazd aiCLI (toolbox.md → Create & use a toolbox), Foundry Toolkit (VS Code), or Foundry Portal. The agent only talks to the toolbox's MCP endpoint; add/remove/reconfigure tools there, not in agent code. For supportedtypevalues and adjacent capabilities (Agent Memory, Routines), see toolbox.md.
Choose your integration
Pick the path that matches your framework, then start from its sample:
| Path | Framework | Sample | When to use |
|---|---|---|---|
| Default | Agent Framework (MAF) | agent-framework/responses/04-foundry-toolbox/ |
Most agents — the FoundryToolbox wrapper handles the wiring. Follow the happy path below. |
| Other | LangGraph (BYO) | bring-your-own/responses/langgraph-toolbox/ |
LangGraph ReAct agent with a toolbox. See BYO. |
| Other | Generic MCP (BYO), Responses | bring-your-own/responses/bring-your-own-toolbox/ |
Raw httpx MCP client — works with any framework. See BYO. |
| Other | Generic MCP (BYO), Invocations | bring-your-own/invocations/toolbox/ |
Toolbox via the Invocations protocol. See BYO. |
| Other | C# (.NET), Agent Framework | csharp/hosted-agents/agent-framework/foundry-toolbox-server-side/ |
Agent Framework agent with toolbox MCP (Responses). |
Happy path (default SDK — MAF)
1. Set TOOLBOX_ENDPOINT
Hosted agents read the MCP endpoint from one env var, conventionally TOOLBOX_ENDPOINT (not enforced, but prefer it). For the URL format, see toolbox.md § MCP endpoint URL format.
Set it in .env locally, or azd env set TOOLBOX_ENDPOINT "<url>" when deployed; get the URL via azd ai toolbox show (see toolbox-azd.md § CLI surface).
⚠️ Avoid
FOUNDRY_-prefixed names — the platform reserves them and may overwrite them at runtime.FOUNDRY_TOOLBOX_ENDPOINTin older samples is deprecated.
2. Start from the sample
Don't hand-write the MCP client wiring. Start from the MAF Default Sample and adapt its main.py + requirements.txt — refer to the repo for the latest code sample and dependencies.
3. Run and invoke
Run the agent locally with azd ai agent run, then invoke it (azd ai agent invoke --local "..."). See the sample's README for the exact commands.
Verify the deployed wire end-to-end — after azd deploy, confirm the toolbox exists and the deployed agent can enumerate its tools:
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
| Error | Cause | Resolution |
|---|---|---|
CONSENT_REQUIRED (nested string code inside an outer -32006 error) |
OAuth MCP connection needs user consent | Parse the consent URL from the nested error message, open it in a browser, complete OAuth, retry |
| 401 on MCP calls | Expired token or wrong scope | Use scope https://ai.azure.com/.default (not cognitiveservices) and refresh token on every request |
| OAuth/ARA errors when calling MCP directly from agent | Direct MCP wiring without toolbox token passthrough | Wire the MCP server into a toolbox and call the toolbox endpoint instead — Foundry handles consent + refresh |
Tool not found on tools/call |
Missing server_label___ prefix for MCP-sourced tools |
Call as {server_label}___{tool_name} (three underscores) |
500 on prompts/list |
Not supported by toolbox endpoint | Pass load_prompts=False if your MCP client library calls it automatically |
500 on send_ping() (MAF MCPStreamableHTTPTool._ensure_connected) |
Toolbox MCP server doesn't implement ping |
Disable the ping check or override with a no-op |
400 missing api-version |
Query string dropped | Append ?api-version=v1 to every toolbox URL |
| Environment variable silently overwritten at runtime | Foundry reserves FOUNDRY_-prefixed env vars |
Rename to a non-FOUNDRY_ name (e.g. TOOLBOX_ENDPOINT) |
For toolbox-composition / provisioning errors (Multiple tools without identifiers, tools/list returns zero, 403 on toolbox/connection writes), see mcp-protocol.md § Troubleshooting (create / provision).
Bring Your Own (BYO) — raw MCP client
Everything below is only needed when you hand-write the MCP client (generic frameworks, or the BYO samples) instead of using the Microsoft Agent Framework, which handles all of it for you.
For the MCP protocol methods and tool-naming rules, see mcp-protocol.md § MCP protocol and § Tool naming.
Authentication
- Agent → Toolbox: Azure AD bearer token, scope
https://ai.azure.com/.default(NOTcognitiveservices— the endpoint rejects it with 401), refreshed on every request. - Toolbox → external services: platform-managed via project connections (API keys, OAuth, managed identity).
Handling require_approval
The toolbox proxy does not enforce require_approval — that's the client's responsibility. Pass approval_mode="never_require" to skip it, or wire your own approval handler.
Handling CONSENT_REQUIRED
When a toolbox includes an OAuth-based MCP connection (e.g. GitHub OAuth), the first call from a new user surfaces a consent requirement — on tools/list, initialize, or tools/call, depending on when the server discovers the missing grant. It's wrapped in a JSON-RPC error with outer code -32006; the failing source's nested error carries string code "CONSENT_REQUIRED" and its message is the consent URL. This is a one-time flow per user per OAuth connection — don't silently swallow it.
Your code must:
On a
-32006error, slice the embedded JSON off the human-readable prefix (don't parse the wholemessage):msg = err["message"] payload = json.loads(msg[msg.index("{"):]) # slice off the prefix firstRead
"code":"CONSENT_REQUIRED"inpayload["errors"][i]["error"]and take the consent URL from that nestedmessage.Surface the URL to the user (stdout or the agent response).
After the user completes OAuth in a browser, retry — subsequent calls succeed without re-prompting.
Example error shape (note the prefix text before the JSON):
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32006,
"message": "tools/list failed for 1 tool source(s), succeeded for 0 tool source(s) {\"errors\":[{\"name\":\"GitHub\",\"type\":\"mcp\",\"error\":{\"code\":\"CONSENT_REQUIRED\",\"message\":\"https://logic-apis-<region>.consent.azure-apim.net/login?data=...\"}}]}"
}
}Azure AI Search Citation Pattern
When calling an azure_ai_search tool through the toolbox MCP endpoint, citation metadata is returned under result.structuredContent.documents[] — not in a separate citations array. Treat each document as one citation:
| Field | Meaning |
|---|---|
title |
Citation display text |
url |
Source link |
id |
Source identifier |
score |
Retrieval relevance score |
For the authoritative field list and the File Search / Web Search citation patterns (under result.content[].resource._meta and ..._meta.annotations[] respectively), see the public Toolbox docs.
Verification checklist:
tools/listreturns the tool nameazure_ai_search.tools/callsucceeds with aqueryargument.result.structuredContent.documentsis present and non-empty.- At least one document has both
titleandurl.