# Foundry Toolbox

> >

- **Type:** Skill
- **Install:** `agentstack add skill-aiappsgbb-awesome-gbb-foundry-toolbox`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [aiappsgbb](https://agentstack.voostack.com/s/aiappsgbb)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [aiappsgbb](https://github.com/aiappsgbb)
- **Source:** https://github.com/aiappsgbb/awesome-gbb/tree/main/skills/foundry-toolbox

## Install

```sh
agentstack add skill-aiappsgbb-awesome-gbb-foundry-toolbox
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Microsoft Foundry Toolbox — Reference Guide

The **Foundry Toolbox** is a managed Foundry resource that bundles multiple
tools (MCP servers, web search, AI Search indexes, code interpreter, file
search, OpenAPI specs, agent-to-agent calls) behind a **single MCP
endpoint** — agents connect to one URL, and the platform handles credential
injection, token refresh, policy enforcement, and version pinning.

Use this skill when an agent needs more than one tool, when you want to
swap or reconfigure tools without redeploying the agent, or when you need
the platform's centralized credential vault for OAuth/Entra/key auth.
Wire-up patterns are documented for **MAF**, **LangGraph**, the **GitHub
Copilot SDK**, and **`azd ai agent init`** declarative deployment.

```
┌───────────────────────────────────────────────────────────────┐
│           Foundry Project (managed namespace)                 │
│                                                                │
│  ┌──────────────────────────────────────────────────┐         │
│  │  Toolbox: my-toolbox                             │         │
│  │   ├─ default_version → v3                        │         │
│  │   ├─ v1, v2, v3 (immutable ToolboxVersionObject) │         │
│  │   └─ tools[]:                                    │         │
│  │      ├─ web_search                               │         │
│  │      ├─ azure_ai_search (INDEX, not KB)          │         │
│  │      ├─ mcp (server_label, project_connection_id)│         │
│  │      ├─ code_interpreter                         │         │
│  │      ├─ file_search (vector_store_ids)           │         │
│  │      ├─ openapi (spec + auth)                    │         │
│  │      └─ a2a_preview (base_url + connection)      │         │
│  └────────────────────┬─────────────────────────────┘         │
│                       │                                        │
│         exposed via:  │                                        │
│   {project}/toolboxes/my-toolbox/mcp?api-version=v1            │
│         (consumer endpoint — always serves default_version)    │
│                       │                                        │
│   {project}/toolboxes/my-toolbox/versions/v3/mcp?...           │
│         (developer endpoint — pin a specific version)          │
└───────────────────────┼────────────────────────────────────────┘
                        │
                        ▼  every request MUST carry:
                  Authorization: Bearer 
                  Foundry-Features: Toolboxes=V1Preview
                        │
        ┌───────────────┼───────────────┐
        ▼               ▼               ▼
   MAF Agent      LangGraph Agent   Copilot SDK Agent
  (MCPStreamable  (AzureAIProject   (MCP bridge with
   HTTPTool +      Toolbox          dots→underscores
   httpx.Auth)     one-liner)       in tool names)
```

---

## ⚠️ Toolbox is for code-based agents only (no Prompt / Declarative wiring)

> **Verified end-to-end against a live Foundry project (May 2026):**
> Toolboxes are consumed by an **MCP client running inside the agent's
> code** — MAF (`MCPStreamableHTTPTool`), LangGraph (`AzureAIProjectToolbox`),
> Copilot SDK (custom `McpBridge`), or any framework that speaks
> Streamable-HTTP MCP. **There is no declarative `tools=[{type: "toolbox",
> toolbox_name: ...}]` shape on a Foundry Prompt agent.** The Foundry agent
> runtime accepts only this fixed list of `tools[].type` values:
> `code_interpreter`, `function`, `namespace`, `tool_search`, `file_search`,
> `web_search_preview`, `web_search_preview_2025_03_11`, `image_generation`,
> `mcp`, `custom`, `computer`, `computer_use_preview`, `shell`, `apply_patch`.
> No `toolbox` type.

Why this matters: a Prompt agent can wire *individual* tools (code_interpreter,
mcp pointing at a server, etc.) directly via its `tools` array, but it
**cannot** delegate the bundle-of-tools fan-out to a toolbox endpoint at
the runtime layer. The bundling lives one layer up — in the agent's code.

What about wiring `tools=[{type: "mcp", server_url: }]`?
**Don't.** It passes shape validation at create time, but at invoke time
the agent runtime calls the toolbox MCP endpoint **without** any `Authorization`
header (no project-managed-identity injection), so it gets `401
PermissionDenied` from the toolbox endpoint regardless of what RBAC you
grant the agent's `instance_identity`. Toolboxes need an MCP client that
mints its own bearer token per request — exactly what
`MCPStreamableHTTPTool` + `httpx.Auth` does in Pattern A below.

Other dead ends ruled out by direct testing (May 2026):

- `type: "namespace"` — exists, but `tools[]` inside a namespace only
  accepts `function` and `custom` types. It's a way to group developer
  functions, not a wrapper for toolboxes.
- `type: "tool_search"` — newer OpenAI feature unsupported on
  `gpt-4.1-mini` and has no `toolbox_name` / `namespaces` / `sources` /
  `toolboxes` fields. It's not the toolbox consumer.
- `type: "mcp"` + `project_connection_id` — the runtime DOES resolve the
  connection (proven via a deliberate "not found" error path), but
  toolbox endpoints require a fresh AAD bearer per request. Foundry
  connections that hold static API keys can't authenticate to a toolbox
  endpoint, so this path is blocked at the auth layer.

If you want a Prompt-only agent (no code container) and you need just one
or two tools, wire those tools directly into the Prompt agent's `tools`
array — skip the toolbox abstraction entirely.

---

## When to use Toolbox vs alternatives

| Need | Use | Why |
|---|---|---|
| **Multiple managed tools behind one endpoint** | **Toolbox** | Centralized creds, swap tools without agent redeploy, versioning |
| **Single hosted MCP with static API key** | `client.get_mcp_tool()` (`foundry-hosted-agents` § MCP) | Simpler — no toolbox abstraction layer |
| **MCP with short-lived AAD bearer (KB MCP, Storage behind PMI)** | `MCPStreamableHTTPTool` + `header_provider` (`foundry-hosted-agents`) | Toolbox MCP endpoint can wrap it, but direct `header_provider` is one less hop |
| **KB-only RAG with agentic retrieval / multi-hop / citations** | `foundry-iq` (Knowledge Base, NOT Toolbox `azure_ai_search`) | Toolbox `azure_ai_search` wraps an INDEX, not a KB — no query planning or answer synthesis |
| **Custom MCP server you build + deploy** | `foundry-mcp-aca` to build the server, **then wire it INTO a Toolbox** | These compose: build with one skill, manage centrally with this one |
| **Cross-resource model invocation** | `foundry-cross-resource` | Toolbox is for *tools*, not models |
| **Vision / DocIntel / Speech tools** | `foundry-doc-vision-speech` patterns wrapped via Toolbox `openapi` or `mcp` | Toolbox is the consumption layer |

---

## Tool type reference

7 tool types. Each can appear at most **once without a `name` field** per
toolbox; for multiple instances of the same type, set a unique `name` on
each. Always add a `description` so the model picks the right tool.

| Type | Required fields | Auth | VNet | Quirks |
|---|---|---|---|---|
| `mcp` | `server_label`, `server_url` | None / Key / OAuth-managed / OAuth-custom / AgenticIdentity (Entra) / UserEntraToken (1P OBO) — via `project_connection_id` | ✅ via VNet subnet | Tool names prefixed `{server_label}.{tool_name}` from the MCP server side; **when wrapped via MAF `MCPStreamableHTTPTool` with `tool_name_prefix=X`, the agent-visible name FLATTENS to `X_{tool_name}` and `server_label` is dropped** (validated MAF 1.3.0 + Toolbox v1, May 2026). `UserEntraToken` requires `audience` field or `tools/list` returns 0 |
| `web_search` | (none) | Bing Grounding (no project conn) or `web_search.custom_search_configuration.project_connection_id` | ✅ public endpoint | Uses Grounding with Bing — first-party, billed separately, **no DPA**. Citations in `content[].resource._meta.annotations[]` |
| `azure_ai_search` | `index_name`, `project_connection_id` | API key or MI via connection | ✅ private endpoint | **Wraps an INDEX, not a Knowledge Base** — no agentic query planning. For KB → use `mcp` tool type pointing at `/knowledgebases//mcp` (see `foundry-iq`). Defaults `top_k=5`, `query_type=vector_semantic_hybrid` |
| `code_interpreter` | (none); optional `container.file_ids[]` | (none) | ✅ Microsoft backbone | **User isolation NOT supported in hosted agents** — all users share the same container context |
| `file_search` | `vector_store_ids[]` | (none) | ❌ **Not supported in VNet** | **User isolation NOT supported in hosted agents**. Vector stores created via `{project}/openai/v1/vector_stores` |
| `openapi` | `spec`, `auth.type` | `anonymous` / `connection` / `managed_identity` (Foundry project MI) | ✅ depends on target | MI auth requires RBAC on target. Spec must be OpenAPI 3.0 / 3.1 with `paths` + `operationId` |
| `a2a_preview` | `base_url`, `project_connection_id` | Connection-driven (e.g. `RemoteA2A`) | ✅ private endpoint | Calls another agent as a tool |

### Per-tool anti-patterns

- **`azure_ai_search` tool:** DO NOT use when you need vector + keyword hybrid search in a VNet-injected agent (file_search VNet support is broken as of May 2026). DO use a custom MCP-wrapped AI Search in those cases, wired via the `mcp` tool type.
- **`file_search` tool:** DO NOT use in VNet-isolated Foundry projects (the file_search backend doesn't yet support PMI in VNet). DO use Cosmos MCP or custom AI Search MCP via `foundry-mcp-aca` or wire directly with `mcp` tool type.
- **`code_interpreter` tool:** DO NOT use for long-running computations (>5 min wall-clock) — the container will timeout and fail silently. DO use ACA Jobs via `azd-patterns` for batch work.
- **`web_search` tool:** DO NOT enable in regulated-data contexts without explicit allow-listing of source domains. DO use the `allowed_domains` parameter when you need to scope results to a restricted set of trusted sources.

---

## The mandatory `Foundry-Features` header

> **🛑 EVERY request to the toolbox MCP endpoint MUST include the header
> `Foundry-Features: Toolboxes=V1Preview`. Calls that omit this header
> fail.** Include it in HTTP clients, MCP transports, and any SDK wrapper
> that calls the toolbox endpoint.

| Element | Value |
|---|---|
| **HTTP header** | `Foundry-Features: Toolboxes=V1Preview` |
| **AAD token scope** | `https://ai.azure.com/.default` |
| **Bearer header** | `Authorization: Bearer ` |
| **API version query** | `?api-version=v1` |

If you forget the `Foundry-Features` header you get a generic 400 / 404
with no useful signal — debug the symptom by curling the endpoint with
`-v` and inspecting your headers FIRST.

---

## Two endpoint shapes

| Role | Endpoint | When |
|---|---|---|
| **Toolbox developer** | `{project}/toolboxes/{name}/versions/{version}/mcp?api-version=v1` | Test or validate a specific version before promoting it |
| **Toolbox consumer** | `{project}/toolboxes/{name}/mcp?api-version=v1` | Production agents — always serves `default_version` |

The first version of a new toolbox is auto-promoted to `default_version`
(`v1`). Subsequent versions stay un-promoted until you explicitly update
the toolbox's `default_version`.

---

## Auth & RBAC

Grant **Azure AI User** on the Foundry project to each identity that
applies:

| Identity | Required for | Why |
|---|---|---|
| **Developer** | Always | Create / update / promote / delete toolbox versions |
| **Agent identity (UAMI / agent MI)** | Hosted agents calling tools | Agent calls `tools/call` at runtime |
| **End user** | OAuth-based MCP or `UserEntraToken` connections | OBO flow proxies the user's Entra token |

> **Hosted MAF / GHCP agent identity:** the calling identity at runtime
> is `instance_identity.principal_id`, not the project / account MIs. See
> `foundry-iq` § Hosted-agent runtime identity for the full breakdown
> (same identity model applies to Toolbox tool calls).

---

## The 4 silent traps (CRITICAL — read before wiring)

These are documented in the Microsoft Learn troubleshooting table, but
they're buried at the bottom and they all surface as opaque `500` /
`server_error` responses with no useful log signal.

### Trap 1 — `500` on `send_ping()`

The Foundry Toolbox MCP server **does not implement the optional MCP
`ping` method**. MAF's `MCPStreamableHTTPTool._ensure_connected()` calls
`send_ping()` automatically during agent registration. When it fires, the
agent fails to register and **every invoke returns `server_error` from
the responses endpoint**.

**Fix:** override `_ensure_connected` with a no-op subclass:

```python
from agent_framework import MCPStreamableHTTPTool

class ToolboxMCPTool(MCPStreamableHTTPTool):
    """MCPStreamableHTTPTool that skips the ping-on-connect probe.
    Foundry Toolbox endpoint returns HTTP 500 on `ping`."""
    async def _ensure_connected(self) -> None:  # noqa: D401
        # Skip the ping; assume the transport is healthy.
        if self._client is None:
            await self.connect()
```

This is the **same trap** documented in `foundry-hosted-agents` SKILL §
"MCP `ping` trap on Foundry-hosted MCP servers" — the cross-link is
deliberate: the hosted-agents skill treats it generically (any
Foundry-hosted MCP), this skill treats it specifically (every Toolbox
endpoint by design).

### Trap 2 — `500` on `prompts/list`

The Foundry MCP server does not implement `prompts/list`. Many MCP
clients (including MAF's) call it on init by default.

**Fix:** pass `load_prompts=False` (or framework equivalent):

```python
mcp_tool = ToolboxMCPTool(
    name="toolbox",
    url=TOOLBOX_ENDPOINT,
    http_client=http_client,
    load_prompts=False,           # 🔑 do not call prompts/list
)
```

### Trap 3 — `500` on non-streaming `tools/call`

Non-streaming mode (`stream=False`) is **not supported** for Toolbox MCP
endpoints. Most MCP client SDKs default to streaming — but if you've
explicitly disabled it for debugging, every call will fail.

**Fix:** keep `stream=True` (the default for `streamablehttp_client` and
`MCPStreamableHTTPTool`).

### Trap 4 — `FOUNDRY_*` env-var overwrite

The platform **reserves all environment variables prefixed with
`FOUNDRY_`** and may silently overwrite user-defined values at runtime.
If you name your custom env var `FOUNDRY_TOOLBOX_ENDPOINT`, the runtime
will overwrite it with whatever it injects, and your code will read the
wrong URL with no warning.

**Fix:** rename custom env vars to avoid the `FOUNDRY_` prefix. The
catalog convention is `TOOLBOX_*` (e.g. `TOOLBOX_MCP_ENDPOINT`,
`TOOLBOX_NAME`).

Platform-injected variables you can safely depend on:

| Variable | Set by | Value |
|---|---|---|
| `FOUNDRY_PROJECT_ENDPOINT` | Platform | `{project}` base URL |
| `FOUNDRY_AGENT_TOOLBOX_ENDPOINT` | Platform | Toolbox base URL (without `/{toolbox}/mcp` suffix) |
| `TOOLBOX_{NAME}_MCP_ENDPOINT` | Platform | Full per-toolbox endpoint — for toolbox `agent-tools` → `TOOLBOX_AGENT_TOOLS_MCP_ENDPOINT` |

Read these in `main.py` / `container.py` instead of hard-coding URLs.

---

## Tool-authoring failure modes

When integrating tools into a toolbox or wiring them to an agent, watch for these common authoring mistakes. This table documents how they manifest, root causes, and defensive patterns.

| Symptom | Root cause | DO NOT do | DO instead |
|---|---|---|---|
| Tool not invoked when expected | Tool description too vague or contradicts agent instructions | Write generic tool descriptions like "search for things" | Write specific descriptions naming inputs/outputs/preconditions — e.g. "Search product catalog by name or SKU; returns title + price + stock" |
| Tool invoked too aggressively | Tool description too tempting OR no scoping in agent system prompt | Rely solely on description to control invocation | Add explicit tool-use scope rules in the agent's `instructions=` parameter; e.g. "Only call product_search after confirming the user requested a search" |
| Malformed JSON returned by tool | Tool returns Python object via plain `print()` or `return` | Return

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [aiappsgbb](https://github.com/aiappsgbb)
- **Source:** [aiappsgbb/awesome-gbb](https://github.com/aiappsgbb/awesome-gbb)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-aiappsgbb-awesome-gbb-foundry-toolbox
- Seller: https://agentstack.voostack.com/s/aiappsgbb
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
