Summary
PR #5346 ships Foundry toolbox support on the Python FoundryChatClient surface (experimental). The learn-site docs do not yet describe toolboxes, the new public API, or the two consumption patterns. This issue tracks the required learn-site additions so users can discover and adopt the feature without reading the package README or source.
Scope is Python only. The .NET package does not include this feature yet — within every .NET code pivot on the affected learn-site pages, include a short placeholder noting "Foundry Toolbox .NET docs are coming soon." so .NET readers are not left with an empty tab.
Concepts to introduce on the learn site
- What a Foundry toolbox is — a named, versioned server-side bundle of hosted tool configurations (code interpreter, file search, image generation, MCP, web search) configured in a Microsoft Foundry project. Toolboxes let you manage tool configuration once and reuse it across agents.
- Authoring vs consumption — authoring (create / update versions) is done in the Foundry portal or via the raw
azure-ai-projects SDK; Agent Framework only covers consumption.
- SDK version matrix — toolbox authoring APIs (
ToolboxVersionObject, project_client.beta.toolboxes.*) require azure-ai-projects>=2.1.0; earlier versions can only consume existing toolboxes.
- Two consumption patterns — native (hosted-tool configs executed by the Foundry runtime) vs MCP (
MCPStreamableHTTPTool against the toolbox's MCP endpoint). The doc must make the distinction and execution-model difference explicit.
- FoundryAgent vs FoundryChatClient behavior — for hosted
FoundryAgent, toolbox attachment happens server-side and there is no client-side wiring; for FoundryChatClient, the user fetches the toolbox and passes it as tools=.
- Experimental feature stage — these APIs ship behind
@experimental(feature_id=ExperimentalFeature.TOOLBOXES). Call out the experimental banner and what it implies for stability.
New public API surface to document
All live under agent_framework.foundry:
| Symbol |
Kind |
Notes |
FoundryChatClient.get_toolbox(name, *, version=None) -> ToolboxVersionObject |
async instance method |
Two-request default-version path when version is omitted; single request when pinned. Raises azure.core.exceptions.ResourceNotFoundError. |
select_toolbox_tools(tools, *, include_names, exclude_names, include_types, exclude_types, predicate) |
helper |
Post-fetch local filtering; accepts a ToolboxVersionObject or a raw tool sequence. |
get_toolbox_tool_name(tool) -> str | None |
helper |
Selection-name precedence: MCP server_label → name → type. |
get_toolbox_tool_type(tool) -> str | None |
helper |
Returns the raw tool type. |
FoundryHostedToolType |
TypeAlias |
Literal["code_interpreter", "file_search", "image_generation", "mcp", "web_search"] | str — used for IDE-guided completion on include_types/exclude_types. |
Also document the implicit flattening behavior that makes the ergonomic calls work:
tools=toolbox
tools=[toolbox]
tools=[local_tool, toolbox]
tools=[toolbox_a, toolbox_b]
This is delivered via core normalize_tools recognizing ToolboxVersionObject; users should not need to write toolbox.tools themselves.
Code samples to include (or link to)
Ordered from simplest to most advanced:
- Basic fetch + pass —
client.get_toolbox("research_toolbox") → Agent(..., tools=toolbox).
- Version pinning —
get_toolbox(name, version="v3") and why pinning matters in production.
- Combining toolboxes —
tools=[toolbox_a, toolbox_b].
- Combining toolbox tools with local function tools —
tools=[get_internal_metrics, toolbox].
- Filtering with
select_toolbox_tools — one example for include_names, one for include_types, one with predicate.
- MCP consumption path —
MCPStreamableHTTPTool(name=..., url=<toolbox MCP endpoint>). Call out that this works with any chat client, not just FoundryChatClient.
- (Optional, advanced) Dynamic per-turn tool selection via
ContextProvider — link to the new context-provider sample; do not inline.
Each code sample on the learn site should link to the corresponding runnable sample in the repo:
python/samples/02-agents/providers/foundry/foundry_chat_client_with_toolbox.py
python/samples/02-agents/providers/foundry/foundry_chat_client_with_toolbox_mcp.py
python/samples/02-agents/context_providers/foundry_toolbox_context_provider.py
.NET code pivots: for each Python sample above, the sibling .NET tab should contain only a short placeholder — "Foundry Toolbox .NET docs are coming soon." — so the pivot renders cleanly until .NET parity lands.
Gotchas / behaviors to call out
- Default-version resolution makes two requests. Pinning
version= avoids the extra round trip.
- Caching is caller-owned. Each
get_toolbox() call hits the network; no framework-side cache, because default versions can change server-side.
- MCP auth is server-side. For MCP tools inside a toolbox, authentication is handled via
project_connection_id on the MCP tool entry (OAuth connection configured in the Foundry project). The client never holds bearer tokens.
- Consent-flow handling is a runtime concern. If a toolbox MCP tool triggers
CONSENT_REQUIRED during agent.run(), that is handled at run time, not during toolbox fetch. The docs should note this exists; runtime handling is a future doc/feature.
- External
project_clients are not mutated. If the caller supplies their own AIProjectClient, Agent Framework does not inject the MAF user-agent; backend request-log attribution will reflect the caller's client configuration.
- Hosted-tool payload sanitization is internal. The framework strips extra fields (
name, description) from non-function hosted tool payloads before calling the Responses API. Users should not need to know about this, but the docs should mention it exists so unexpected-field bug reports have a breadcrumb.
Pages to add or update
New or expanded:
- Foundry provider overview — add a "Toolboxes" section with the concept introduction and decision tree (FoundryAgent vs FoundryChatClient; native vs MCP).
FoundryChatClient reference page — document get_toolbox and the flattening behavior; link to the toolbox section.
- Hosted tools page — cross-link to toolboxes as a grouping mechanism.
- Context providers page — link the new
foundry_toolbox_context_provider.py sample under "dynamic tool selection" patterns.
- Samples index — link to the three new samples above.
Every one of the above pages that uses language pivots must include the "Foundry Toolbox .NET docs are coming soon." placeholder in its .NET tab.
Explicit non-goals for the docs
Do not document the following on the learn site; they are intentionally out of framework scope today. Users who need them should be pointed at the raw azure-ai-projects SDK:
- Toolbox CRUD from framework code (
create_version, update, delete).
- Server-side agent authoring from a toolbox (
PromptAgentDefinition(tools=toolbox.tools, ...)).
- Discovery / listing (
list_toolboxes, list_toolbox_versions).
- Runtime OAuth consent-flow handling (separate future design).
- Caching / refresh APIs.
- Server-side toolbox telemetry attribution — only client-side provenance / user-agent-based attribution exists today; no structured server-side mechanism yet.
References
Summary
PR #5346 ships Foundry toolbox support on the Python
FoundryChatClientsurface (experimental). The learn-site docs do not yet describe toolboxes, the new public API, or the two consumption patterns. This issue tracks the required learn-site additions so users can discover and adopt the feature without reading the package README or source.Scope is Python only. The .NET package does not include this feature yet — within every .NET code pivot on the affected learn-site pages, include a short placeholder noting "Foundry Toolbox .NET docs are coming soon." so .NET readers are not left with an empty tab.
Concepts to introduce on the learn site
azure-ai-projectsSDK; Agent Framework only covers consumption.ToolboxVersionObject,project_client.beta.toolboxes.*) requireazure-ai-projects>=2.1.0; earlier versions can only consume existing toolboxes.MCPStreamableHTTPToolagainst the toolbox's MCP endpoint). The doc must make the distinction and execution-model difference explicit.FoundryAgent, toolbox attachment happens server-side and there is no client-side wiring; forFoundryChatClient, the user fetches the toolbox and passes it astools=.@experimental(feature_id=ExperimentalFeature.TOOLBOXES). Call out the experimental banner and what it implies for stability.New public API surface to document
All live under
agent_framework.foundry:FoundryChatClient.get_toolbox(name, *, version=None) -> ToolboxVersionObjectversionis omitted; single request when pinned. Raisesazure.core.exceptions.ResourceNotFoundError.select_toolbox_tools(tools, *, include_names, exclude_names, include_types, exclude_types, predicate)ToolboxVersionObjector a raw tool sequence.get_toolbox_tool_name(tool) -> str | Noneserver_label→name→type.get_toolbox_tool_type(tool) -> str | Nonetype.FoundryHostedToolTypeTypeAliasLiteral["code_interpreter", "file_search", "image_generation", "mcp", "web_search"] | str— used for IDE-guided completion oninclude_types/exclude_types.Also document the implicit flattening behavior that makes the ergonomic calls work:
tools=toolboxtools=[toolbox]tools=[local_tool, toolbox]tools=[toolbox_a, toolbox_b]This is delivered via core
normalize_toolsrecognizingToolboxVersionObject; users should not need to writetoolbox.toolsthemselves.Code samples to include (or link to)
Ordered from simplest to most advanced:
client.get_toolbox("research_toolbox")→Agent(..., tools=toolbox).get_toolbox(name, version="v3")and why pinning matters in production.tools=[toolbox_a, toolbox_b].tools=[get_internal_metrics, toolbox].select_toolbox_tools— one example forinclude_names, one forinclude_types, one withpredicate.MCPStreamableHTTPTool(name=..., url=<toolbox MCP endpoint>). Call out that this works with any chat client, not justFoundryChatClient.ContextProvider— link to the new context-provider sample; do not inline.Each code sample on the learn site should link to the corresponding runnable sample in the repo:
python/samples/02-agents/providers/foundry/foundry_chat_client_with_toolbox.pypython/samples/02-agents/providers/foundry/foundry_chat_client_with_toolbox_mcp.pypython/samples/02-agents/context_providers/foundry_toolbox_context_provider.pyGotchas / behaviors to call out
version=avoids the extra round trip.get_toolbox()call hits the network; no framework-side cache, because default versions can change server-side.project_connection_idon the MCP tool entry (OAuth connection configured in the Foundry project). The client never holds bearer tokens.CONSENT_REQUIREDduringagent.run(), that is handled at run time, not during toolbox fetch. The docs should note this exists; runtime handling is a future doc/feature.project_clients are not mutated. If the caller supplies their ownAIProjectClient, Agent Framework does not inject the MAF user-agent; backend request-log attribution will reflect the caller's client configuration.name,description) from non-function hosted tool payloads before calling the Responses API. Users should not need to know about this, but the docs should mention it exists so unexpected-field bug reports have a breadcrumb.Pages to add or update
New or expanded:
FoundryChatClientreference page — documentget_toolboxand the flattening behavior; link to the toolbox section.foundry_toolbox_context_provider.pysample under "dynamic tool selection" patterns.Every one of the above pages that uses language pivots must include the "Foundry Toolbox .NET docs are coming soon." placeholder in its .NET tab.
Explicit non-goals for the docs
Do not document the following on the learn site; they are intentionally out of framework scope today. Users who need them should be pointed at the raw
azure-ai-projectsSDK:create_version,update,delete).PromptAgentDefinition(tools=toolbox.tools, ...)).list_toolboxes,list_toolbox_versions).References
docs/decisions/0025-foundry-toolbox-support.mdpython/packages/foundry/README.md