Microsoft Foundry 工具箱

Microsoft Foundry 工具箱是一個有名稱、有版本限制的伺服器端工具組合包,包含程式碼解譯器、檔案搜尋、影像產生、MCP 及網頁搜尋等。 工具箱讓你在 Foundry 裡管理工具設定,並在不同代理間重複使用。

代理框架涵蓋 Toolbox 的使用方式。 透過 Foundry 入口網站或 azure-ai-projects SDK 建立並更新 Toolbox 版本。

這很重要

FoundryToolbox 由測試 agent-framework-foundry-hosting 套件提供,且可在穩定版發行前進行變更。

對於服務受控 FoundryAgent,請將工具箱附加至 Foundry 中的代理程式定義。

對於使用 Microsoft Agent Framework 建置的託管代理,請使用來自 Microsoft.Agents.AI.Foundry.Hosting 的 AddFoundryToolboxes,如下列範例所示。

使用已啟用隱含使用、與Microsoft.Agents.AI.Foundry和Microsoft.Agents.AI.Foundry.Hosting以及DotNetEnv的版本相符的 .NET 10 Web 專案。 將 TOOLBOX_NAME 設為現有的工具箱,並將 FOUNDRY_MODEL 設為你的模型部署。 鑄造廠供應 FOUNDRY_PROJECT_ENDPOINT 給部署的主機。 若要存取本地模型,請設定FOUNDRY_PROJECT_ENDPOINT並登入 Azure CLI。 託管部署會改用 azd 管理的 AZURE_AI_MODEL_DEPLOYMENT_NAME。 主機整合會在 FOUNDRY_PROJECT_ENDPOINT 可用時載入工具箱中的工具。

using DotNetEnv;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Foundry.Hosting;

// Load .env file if present (for local development)
Env.TraversePath().Load();

string endpoint = System.Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT")
    ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = FirstNonBlank(
    System.Environment.GetEnvironmentVariable("FOUNDRY_MODEL"),
    System.Environment.GetEnvironmentVariable("AZURE_AI_MODEL_DEPLOYMENT_NAME"),
    "gpt-4o")!;
string toolboxName = FirstNonBlank(
    System.Environment.GetEnvironmentVariable("TOOLBOX_NAME"),
    "my-toolset")!;

// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
// Use a chained credential: try a temporary dev token first (for local Docker debugging),
// then fall back to DefaultAzureCredential (for local dev via dotnet run / managed identity in production).
    .AsAIAgent(
        model: deploymentName,
            Use the available tools to answer user questions.
            If a tool is not available for a request, let the user know clearly.
            """,
        name: System.Environment.GetEnvironmentVariable("AGENT_NAME") ?? "hosted-toolbox-agent",
        description: "Hosted agent backed by Foundry Toolbox MCP tools");

// ── Build the host ────────────────────────────────────────────────────────────

var builder = WebApplication.CreateBuilder(args);

// Register the agent and response handler
// Register Foundry Toolbox: connects to the MCP proxy at startup and makes tools available.
// The toolbox name must match a toolbox registered in your Foundry project.
// When FOUNDRY_PROJECT_ENDPOINT is absent (e.g., in local development without Foundry
// infrastructure), startup succeeds without error and no toolbox tools are loaded.
builder.Services.AddFoundryToolboxes(credential, toolboxName);

app.Run();

static string? FirstNonBlank(params string?[] candidates) =>
    Array.Find(candidates, candidate => !string.IsNullOrWhiteSpace(candidate));

// ── DevTemporaryTokenCredential ───────────────────────────────────────────────

同一託管註冊支援其工具箱連線中已設定為每位使用者 OAuth 同意的工具。 使用者仍需取得必要的權限與同意;不需要獨立的主機註冊區塊。

關於專案檔案與部署說明,請參閱 Hosted-Toolbox。 關於每位使用者同意的設定,請參見 Hosted-Toolbox-AuthPaths。

安裝套件

pip install agent-framework-foundry-hosting agent-framework-foundry --pre

FoundryToolbox 是從 agent_framework.foundry 匯入,並由 agent-framework-foundry-hosting 提供。

配置工具箱

設定明確的 Toolbox MCP 端點:

TOOLBOX_ENDPOINT="https://<account>.services.ai.azure.com/api/projects/<project>/toolboxes/<name>/mcp?api-version=v1"

或者讓 FoundryToolbox 建立端點:

FOUNDRY_PROJECT_ENDPOINT="https://<account>.services.ai.azure.com/api/projects/<project>"
TOOLBOX_NAME="<toolbox-name>"

託管 Agent 範例在本機執行時會優先使用 FOUNDRY_MODEL;在託管環境中執行時,則會回復使用由 azd 管理的 AZURE_AI_MODEL_DEPLOYMENT_NAME。

將 FoundryToolbox 與託管代理程式搭配使用

FoundryToolbox解決其端點,使用提供的 Azure 憑證驗證每個 MCP 請求,轉發 Foundry 的每個請求呼叫 ID,並參與代理的連線生命週期。 它會在每個操作邊界解析平台標頭,並在有效請求身份變更時重新連接 MCP 會話。 因此,長期使用的 Toolbox 不會保留先前來電者的呼叫 ID。

此範例會在要求範圍的 Agent Factory 內建立工具箱、用戶端與認證,以確保所有權與清理作業具有可預期性。 當相關資源是由請求所擁有時,請使用此工廠模式,但並非僅為了使 Toolbox 呼叫 ID 保持最新狀態。

import asyncio
import os
from contextlib import AsyncExitStack
from types import TracebackType

from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient, FoundryToolbox
from agent_framework_foundry_hosting import ResponsesHostServer
from azure.ai.agentserver.core import AgentConfig, get_request_context
from azure.identity.aio import AzureCliCredential, ManagedIdentityCredential
from dotenv import load_dotenv


def create_agent() -> Agent:
    """Create request-owned SDK resources and close them with the agent."""
    endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"]
    model = os.environ.get("FOUNDRY_MODEL") or os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"]
    credential = (
        ManagedIdentityCredential(client_id=os.environ.get("FOUNDRY_AGENT_INSTANCE_CLIENT_ID"))
        if AgentConfig.from_env().is_hosted
        else AzureCliCredential()
    )

    class RequestClient(FoundryChatClient):
        async def __aenter__(self) -> RequestClient:
            return self

        async def __aexit__(
            self, exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None
        ) -> None:
            async with AsyncExitStack() as cleanup:
                cleanup.push_async_callback(credential.close)
                cleanup.push_async_callback(self.project_client.close)
                cleanup.push_async_callback(self.client.close)

    toolbox = FoundryToolbox(credential)
    client = RequestClient(
        project_endpoint=endpoint,
        model=model,
        credential=credential,
        default_headers=get_request_context().platform_headers(),
    )
    return Agent(
        client=client,
        instructions="You are a friendly assistant. Keep your answers brief.",
        tools=toolbox,
    )


async def main() -> None:
    load_dotenv()
    server = ResponsesHostServer(agent=create_agent, history_source="agent_server")
    await server.run_async()

當 Toolbox Code Interpreter 產生檔案,且助理回應提及該檔案名稱時,託管的 Responses 適配器會發出包含容器與檔案 ID 的原生 container_file_citation 註解。 回應用戶端可以使用這些 ID,透過容器檔案 API 探索並下載產生的檔案。

公開工具箱技能

工具箱可以透過 MCP 公開代理技能。 當只應讓技能對模型可見時,請設定 load_tools=False,然後將 Toolbox 新增為工具,使其 MCP 工作階段得以連線,並使用 as_skills_provider() 作為情境提供者。

import asyncio
import os
from contextlib import AsyncExitStack
from types import TracebackType

from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient, FoundryToolbox
from agent_framework_foundry_hosting import ResponsesHostServer
from azure.ai.agentserver.core import AgentConfig, get_request_context
from azure.identity.aio import AzureCliCredential, ManagedIdentityCredential
from dotenv import load_dotenv


def create_agent() -> Agent:
    """Keep skill caches, credentials and the MCP lifecycle request-owned."""
    endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"]
    model = os.environ.get("FOUNDRY_MODEL") or os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"]
    credential = (
        ManagedIdentityCredential(client_id=os.environ.get("FOUNDRY_AGENT_INSTANCE_CLIENT_ID"))
        if AgentConfig.from_env().is_hosted
        else AzureCliCredential()
    )

    class RequestClient(FoundryChatClient):
        async def __aenter__(self) -> RequestClient:
            return self

        async def __aexit__(
            self, exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None
        ) -> None:
            async with AsyncExitStack() as cleanup:
                cleanup.push_async_callback(credential.close)
                cleanup.push_async_callback(self.project_client.close)
                cleanup.push_async_callback(self.client.close)

    # tools= connects the MCP session; context_providers= reads skills from that same session.
    toolbox = FoundryToolbox(credential, load_tools=False)
    skills_provider = toolbox.as_skills_provider(disable_load_skill_approval=True)
    client = RequestClient(
        project_endpoint=endpoint,
        model=model,
        credential=credential,
        default_headers=get_request_context().platform_headers(),
    )
    return Agent(
        client=client,
        name=os.environ.get("AGENT_NAME", "hosted-toolbox-mcp-skills"),
        instructions="You are a helpful assistant.",
        tools=toolbox,
        context_providers=[skills_provider],
    )


async def main() -> None:
    load_dotenv()
    server = ResponsesHostServer(agent=create_agent, history_source="agent_server")
    await server.run_async()

技能操作的核准預設仍為啟用狀態。 僅針對受信任的無人參與情境停用個別核准。 把工具箱和技能提供者放在一起,讓兩者共用同一個 MCP 會話。 若為長時間執行的工具箱,當有效的平台標頭識別變更時,技能探索快取會被取代。 與技能相關的自訂 header_provider 必須從環境狀態(如閉包或 ContextVar)解析,因為技能與資源讀取不會接收函式執行時參數。

將工具箱與 FoundryAgent 搭配使用

將工具箱附加到 Foundry 中的提示或託管代理程式定義中。 FoundryAgent 會使用該已儲存的工具組態;從用戶端傳入 Toolbox 並不會將其新增至受管理代理程式。

透過 MCP 與 FoundryToolbox 連線

使用 FoundryToolbox with ResponsesHostServer 將託管代理連接到 Toolbox MCP 端點。 包裝程式會驗證 MCP 要求,並轉發目前託管要求的呼叫端上下文,以進行每位使用者的身分識別直通傳遞。 當用戶端、憑證與工具箱需要單一清理邊界時,請求範圍 agent 工廠仍是最簡單的選擇。 同時也支援一個長壽命的 Toolbox,當平台標頭身份變更時,會在操作前重新連接。

import asyncio
import os
from contextlib import AsyncExitStack
from types import TracebackType

from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient, FoundryToolbox
from agent_framework_foundry_hosting import ResponsesHostServer
from azure.ai.agentserver.core import AgentConfig, get_request_context
from azure.identity.aio import AzureCliCredential, ManagedIdentityCredential
from dotenv import load_dotenv


def create_agent() -> Agent:
    """Create request-owned SDK resources and close them with the agent."""
    endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"]
    model = os.environ.get("FOUNDRY_MODEL") or os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"]
    credential = (
        ManagedIdentityCredential(client_id=os.environ.get("FOUNDRY_AGENT_INSTANCE_CLIENT_ID"))
        if AgentConfig.from_env().is_hosted
        else AzureCliCredential()
    )

    class RequestClient(FoundryChatClient):
        async def __aenter__(self) -> RequestClient:
            return self

        async def __aexit__(
            self, exc_type: type[BaseException] | None, exc_value: BaseException | None, traceback: TracebackType | None
        ) -> None:
            async with AsyncExitStack() as cleanup:
                cleanup.push_async_callback(credential.close)
                cleanup.push_async_callback(self.project_client.close)
                cleanup.push_async_callback(self.client.close)

    toolbox = FoundryToolbox(credential)
    client = RequestClient(
        project_endpoint=endpoint,
        model=model,
        credential=credential,
        default_headers=get_request_context().platform_headers(),
    )
    return Agent(
        client=client,
        instructions="You are a friendly assistant. Keep your answers brief.",
        tools=toolbox,
    )


async def main() -> None:
    load_dotenv()
    server = ResponsesHostServer(agent=create_agent, history_source="agent_server")
    await server.run_async()

設定 TOOLBOX_ENDPOINT,或同時設定 FOUNDRY_PROJECT_ENDPOINT 和 TOOLBOX_NAME,如 設定工具箱中所述。 設定 FOUNDRY_MODEL 為本地執行;託管部署則改為使用由 azd 管理的 AZURE_AI_MODEL_DEPLOYMENT_NAME。

當 Toolbox 或 MCP 操作需要 OAuth 同意時,串流與非串流 FoundryAgent 和 FoundryChatClient 呼叫會以同意連結回傳 Content(type="oauth_consent_request"),而非空的助理訊息。 將這些內容視為使用者輸入請求,並向使用者呈現其 consent_link。

用戶端只會顯示具有 HTTPS 方案且主機有效的連結。 缺少或無效的連結會被省略並登錄。

限制

  • 工具箱內的 MCP 工具透過 Foundry project_connection_id進行伺服器端認證;Agent Framework 用戶端不持有上游 MCP 承載憑證。
  • 將 Toolbox 作為 MCP 伺服器來使用時,需要對 Toolbox 端點進行用戶端 Entra ID 驗證。
  • 同意流程回應(如 ) CONSENT_REQUIRED 是在代理執行時處理,而非在 Toolbox 連線建立時處理。

Samples

Sample 說明
foundry_toolbox/main.py FoundryToolbox 搭配託管 Responses
foundry_toolbox_mcp_skills/main.py 工具箱支援的代理程式技能
foundry_chat_client_with_toolbox.py 搭配 MCPStreamableHTTPTool 的工具箱 MCP 取用
foundry_chat_client_with_toolbox_skills.py 以工具箱為基礎的技能配置
invoke_foundry_toolbox_mcp 工作流程端的 MCP 消耗

Go 目前尚未提供 Foundry Toolbox 輔助函式。 透過 Foundry 配置工具箱,並使用支援的本地或託管工具宣告給 Go 代理使用。