From cf786efdd0bf552a2dd28b72a3d64895531af918 Mon Sep 17 00:00:00 2001 From: Tao Chen <12570346+TaoChenOSU@users.noreply.github.com> Date: Tue, 30 Jun 2026 18:50:13 -0700 Subject: [PATCH 1/2] MAF samples: upgrade to protocol 2.0.0 (#575) --- .../hosted-agents/agent-framework/README.md | 5 + .../invocations/01-basic/agent.manifest.yaml | 2 +- .../invocations/01-basic/agent.yaml | 2 +- .../invocations/01-basic/requirements.txt | 4 +- .../responses/01-basic/agent.manifest.yaml | 2 +- .../responses/01-basic/agent.yaml | 2 +- .../responses/01-basic/requirements.txt | 6 +- .../responses/02-tools/agent.manifest.yaml | 2 +- .../responses/02-tools/agent.yaml | 2 +- .../responses/02-tools/requirements.txt | 6 +- .../responses/03-mcp/agent.manifest.yaml | 2 +- .../responses/03-mcp/agent.yaml | 2 +- .../responses/03-mcp/requirements.txt | 6 +- .../responses/04-foundry-toolbox/README.md | 129 ++++++++++++++++-- .../04-foundry-toolbox/agent.manifest.yaml | 12 +- .../responses/04-foundry-toolbox/agent.yaml | 2 +- .../responses/04-foundry-toolbox/main.py | 101 ++++---------- .../04-foundry-toolbox/requirements.txt | 6 +- .../scripts/list-foundry-connectors.ps1 | 105 ++++++++++++++ .../scripts/list-foundry-connectors.sh | 106 ++++++++++++++ .../responses/04-foundry-toolbox/toolbox.yaml | 32 ++++- .../05-workflows/agent.manifest.yaml | 2 +- .../responses/05-workflows/agent.yaml | 2 +- .../responses/05-workflows/requirements.txt | 6 +- .../responses/06-files/agent.manifest.yaml | 2 +- .../responses/06-files/agent.yaml | 2 +- .../responses/06-files/main.py | 1 - .../responses/06-files/requirements.txt | 6 +- .../responses/07-skills/agent.manifest.yaml | 2 +- .../responses/07-skills/agent.yaml | 2 +- .../responses/07-skills/requirements.txt | 6 +- .../07-teams-activity/agent.manifest.yaml | 2 +- .../responses/07-teams-activity/agent.yaml | 2 +- .../responses/07-teams-activity/main.py | 1 - .../07-teams-activity/requirements.txt | 6 +- .../08-observability/agent.manifest.yaml | 2 +- .../responses/08-observability/agent.yaml | 2 +- .../08-observability/requirements.txt | 6 +- .../agent.manifest.yaml | 2 +- .../agent.yaml | 2 +- .../requirements.txt | 8 +- .../11-azure-search-rag/agent.manifest.yaml | 2 +- .../responses/11-azure-search-rag/agent.yaml | 2 +- .../11-azure-search-rag/requirements.txt | 6 +- .../12-foundry-skills/agent.manifest.yaml | 2 +- .../responses/12-foundry-skills/agent.yaml | 2 +- .../12-foundry-skills/requirements.txt | 4 +- .../13-foundry-memory/agent.manifest.yaml | 2 +- .../responses/13-foundry-memory/agent.yaml | 2 +- .../13-foundry-memory/requirements.txt | 10 +- .../agent.manifest.yaml | 2 +- .../14-browser-automation-agent/agent.yaml | 2 +- .../requirements.txt | 8 +- .../utils/agent_factory.py | 45 ++++-- .../utils/tools.py | 1 - .../agent.manifest.yaml | 2 +- .../agent.yaml | 2 +- .../requirements.txt | 4 +- .../agent.manifest.yaml | 2 +- .../16-content-safety-guardrail/agent.yaml | 2 +- .../requirements.txt | 6 +- .../responses/17-foundry-iq-toolbox/README.md | 4 +- .../17-foundry-iq-toolbox/agent.manifest.yaml | 2 +- .../17-foundry-iq-toolbox/agent.yaml | 2 +- .../responses/17-foundry-iq-toolbox/main.py | 104 +++++--------- .../17-foundry-iq-toolbox/requirements.txt | 16 +-- 66 files changed, 535 insertions(+), 301 deletions(-) create mode 100644 samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/scripts/list-foundry-connectors.ps1 create mode 100644 samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/scripts/list-foundry-connectors.sh diff --git a/samples/python/hosted-agents/agent-framework/README.md b/samples/python/hosted-agents/agent-framework/README.md index 8513d9dcd..aa6bbdc55 100644 --- a/samples/python/hosted-agents/agent-framework/README.md +++ b/samples/python/hosted-agents/agent-framework/README.md @@ -2,6 +2,11 @@ This directory contains samples that demonstrate how to use the [Agent Framework](https://github.com/microsoft/agent-framework) to host agents with different capabilities and configurations. Each sample includes a README with instructions on how to set up, run, and interact with the agent. +> [!IMPORTANT] +> **Migrating from Protocol version 1.0.0 to 2.0.0:** The Foundry Hosted Agents service has been updated to use Protocol version 2.0.0. If your application is using Protocol version 1.0.0, upgrade to Protocol version 2.0.0 in your `agent.manifest.yaml` or `agent.yaml` and upgrade to the latest `agent-framework-foundry-hosting` package. `agent-framework-foundry-hosting==1.0.0a260625` is the last version that supports Protocol version 1.0.0. +> +> The `agent-framework-foundry-hosting` Python API surface is intended to remain stable, but protocol 1.0.0 and 2.0.0 are incompatible. + ## Samples ### Responses API diff --git a/samples/python/hosted-agents/agent-framework/invocations/01-basic/agent.manifest.yaml b/samples/python/hosted-agents/agent-framework/invocations/01-basic/agent.manifest.yaml index 838f3944d..351a49bf9 100644 --- a/samples/python/hosted-agents/agent-framework/invocations/01-basic/agent.manifest.yaml +++ b/samples/python/hosted-agents/agent-framework/invocations/01-basic/agent.manifest.yaml @@ -13,7 +13,7 @@ template: kind: hosted protocols: - protocol: invocations - version: 1.0.0 + version: 2.0.0 environment_variables: - name: AZURE_AI_MODEL_DEPLOYMENT_NAME value: "{{AZURE_AI_MODEL_DEPLOYMENT_NAME}}" diff --git a/samples/python/hosted-agents/agent-framework/invocations/01-basic/agent.yaml b/samples/python/hosted-agents/agent-framework/invocations/01-basic/agent.yaml index 68a73d34a..3f9118c11 100644 --- a/samples/python/hosted-agents/agent-framework/invocations/01-basic/agent.yaml +++ b/samples/python/hosted-agents/agent-framework/invocations/01-basic/agent.yaml @@ -3,7 +3,7 @@ kind: hosted name: agent-framework-agent-basic-invocations protocols: - protocol: invocations - version: 1.0.0 + version: 2.0.0 resources: cpu: '0.25' memory: '0.5Gi' diff --git a/samples/python/hosted-agents/agent-framework/invocations/01-basic/requirements.txt b/samples/python/hosted-agents/agent-framework/invocations/01-basic/requirements.txt index 03962b4c6..6969202b1 100644 --- a/samples/python/hosted-agents/agent-framework/invocations/01-basic/requirements.txt +++ b/samples/python/hosted-agents/agent-framework/invocations/01-basic/requirements.txt @@ -1,5 +1,5 @@ agent-framework-foundry -agent-framework-foundry-hosting +agent-framework-foundry-hosting>=1.0.0a260630 # debugpy enables local debugging of this agent with the Foundry Toolkit VS Code extension. -debugpy +debugpy \ No newline at end of file diff --git a/samples/python/hosted-agents/agent-framework/responses/01-basic/agent.manifest.yaml b/samples/python/hosted-agents/agent-framework/responses/01-basic/agent.manifest.yaml index 567fd03e1..90ea1922c 100644 --- a/samples/python/hosted-agents/agent-framework/responses/01-basic/agent.manifest.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/01-basic/agent.manifest.yaml @@ -13,7 +13,7 @@ template: kind: hosted protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 environment_variables: - name: AZURE_AI_MODEL_DEPLOYMENT_NAME value: "{{AZURE_AI_MODEL_DEPLOYMENT_NAME}}" diff --git a/samples/python/hosted-agents/agent-framework/responses/01-basic/agent.yaml b/samples/python/hosted-agents/agent-framework/responses/01-basic/agent.yaml index bf652ba1f..832d67e71 100644 --- a/samples/python/hosted-agents/agent-framework/responses/01-basic/agent.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/01-basic/agent.yaml @@ -3,7 +3,7 @@ kind: hosted name: agent-framework-agent-basic-responses protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 resources: cpu: '0.25' memory: '0.5Gi' diff --git a/samples/python/hosted-agents/agent-framework/responses/01-basic/requirements.txt b/samples/python/hosted-agents/agent-framework/responses/01-basic/requirements.txt index 01f3e7bc9..6969202b1 100644 --- a/samples/python/hosted-agents/agent-framework/responses/01-basic/requirements.txt +++ b/samples/python/hosted-agents/agent-framework/responses/01-basic/requirements.txt @@ -1,7 +1,5 @@ -# Use the narrow Foundry subpackages to keep dependencies light. agent-framework-foundry -agent-framework-foundry-hosting -mcp<2,>=1.24.0 +agent-framework-foundry-hosting>=1.0.0a260630 # debugpy enables local debugging of this agent with the Foundry Toolkit VS Code extension. -debugpy +debugpy \ No newline at end of file diff --git a/samples/python/hosted-agents/agent-framework/responses/02-tools/agent.manifest.yaml b/samples/python/hosted-agents/agent-framework/responses/02-tools/agent.manifest.yaml index 22971a8cf..19b754f7c 100644 --- a/samples/python/hosted-agents/agent-framework/responses/02-tools/agent.manifest.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/02-tools/agent.manifest.yaml @@ -13,7 +13,7 @@ template: kind: hosted protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 environment_variables: - name: AZURE_AI_MODEL_DEPLOYMENT_NAME value: "{{AZURE_AI_MODEL_DEPLOYMENT_NAME}}" diff --git a/samples/python/hosted-agents/agent-framework/responses/02-tools/agent.yaml b/samples/python/hosted-agents/agent-framework/responses/02-tools/agent.yaml index 597ad3b98..2a27cd4f0 100644 --- a/samples/python/hosted-agents/agent-framework/responses/02-tools/agent.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/02-tools/agent.yaml @@ -2,7 +2,7 @@ kind: hosted name: agent-framework-agent-with-local-tools-responses protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 resources: cpu: "0.25" memory: 0.5Gi diff --git a/samples/python/hosted-agents/agent-framework/responses/02-tools/requirements.txt b/samples/python/hosted-agents/agent-framework/responses/02-tools/requirements.txt index 01f3e7bc9..6969202b1 100644 --- a/samples/python/hosted-agents/agent-framework/responses/02-tools/requirements.txt +++ b/samples/python/hosted-agents/agent-framework/responses/02-tools/requirements.txt @@ -1,7 +1,5 @@ -# Use the narrow Foundry subpackages to keep dependencies light. agent-framework-foundry -agent-framework-foundry-hosting -mcp<2,>=1.24.0 +agent-framework-foundry-hosting>=1.0.0a260630 # debugpy enables local debugging of this agent with the Foundry Toolkit VS Code extension. -debugpy +debugpy \ No newline at end of file diff --git a/samples/python/hosted-agents/agent-framework/responses/03-mcp/agent.manifest.yaml b/samples/python/hosted-agents/agent-framework/responses/03-mcp/agent.manifest.yaml index 9f9a7f9e7..81ce21f74 100644 --- a/samples/python/hosted-agents/agent-framework/responses/03-mcp/agent.manifest.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/03-mcp/agent.manifest.yaml @@ -13,7 +13,7 @@ template: kind: hosted protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 environment_variables: - name: AZURE_AI_MODEL_DEPLOYMENT_NAME value: "{{AZURE_AI_MODEL_DEPLOYMENT_NAME}}" diff --git a/samples/python/hosted-agents/agent-framework/responses/03-mcp/agent.yaml b/samples/python/hosted-agents/agent-framework/responses/03-mcp/agent.yaml index e222b6f5f..442d8e59a 100644 --- a/samples/python/hosted-agents/agent-framework/responses/03-mcp/agent.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/03-mcp/agent.yaml @@ -2,7 +2,7 @@ kind: hosted name: agent-framework-agent-with-remote-mcp-tools-responses protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 resources: cpu: "0.25" memory: 0.5Gi diff --git a/samples/python/hosted-agents/agent-framework/responses/03-mcp/requirements.txt b/samples/python/hosted-agents/agent-framework/responses/03-mcp/requirements.txt index 01f3e7bc9..6969202b1 100644 --- a/samples/python/hosted-agents/agent-framework/responses/03-mcp/requirements.txt +++ b/samples/python/hosted-agents/agent-framework/responses/03-mcp/requirements.txt @@ -1,7 +1,5 @@ -# Use the narrow Foundry subpackages to keep dependencies light. agent-framework-foundry -agent-framework-foundry-hosting -mcp<2,>=1.24.0 +agent-framework-foundry-hosting>=1.0.0a260630 # debugpy enables local debugging of this agent with the Foundry Toolkit VS Code extension. -debugpy +debugpy \ No newline at end of file diff --git a/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/README.md b/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/README.md index 01156ad2e..9703edfb9 100644 --- a/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/README.md +++ b/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/README.md @@ -8,21 +8,90 @@ You can create a Foundry Toolbox by code. Refer to this sample for an example: [ You can also create a Foundry Toolbox in the Foundry portal. Read more about it [in the Foundry toolbox documentation](https://learn.microsoft.com/en-us/azure/foundry/agents/how-to/tools/toolbox). -This sample consumes a toolbox over its MCP endpoint. It bundles a [`toolbox.yaml`](toolbox.yaml) that defines two connectionless tools behind one endpoint: +This sample consumes a toolbox over its MCP endpoint. It bundles a [`toolbox.yaml`](toolbox.yaml) that defines 6 tools behind one endpoint: - **Web search**, which grounds responses in real-time public web results. -- The **Microsoft Learn MCP server** (`https://learn.microsoft.com/api/mcp`), a public endpoint that grounds responses in official Microsoft documentation and requires no authentication. +- **Code interpreter**, which executes Python code in a secure sandbox and returns the output. +- **Azure Specs MCP**, which demonstrates connecting to an MCP server that doesn't require authentication. +- **GitHub MCP**, which demonstrates connecting to the GitHub MCP server using either a Personal Access Token (PAT) or OAuth2 (switch by changing the `project_connection_id` in `toolbox.yaml`). +- **Azure Language MCP with agent identity**, which demonstrates connecting to the Azure Language MCP server using agent identity for authentication. +- **Microsoft Foundry MCP with Entra pass-through**, which demonstrates connecting to the Microsoft Foundry MCP server using Entra pass-through for authentication. + +### Authentication Methods + +You can connect to MCP servers in Foundry Toolbox that use different authentication methods. This sample demonstrates the following authentication methods: + +- [**No authentication**](https://github.com/microsoft-foundry/foundry-samples/blob/main/samples/python/hosted-agents/SUPPORTED_TOOLBOX_SCENARIOS.md#5-mcp-no-auth): The tool does not require any authentication. The agent can invoke the tool without providing any credentials. Sample MCP server: `https://gitmcp.io/Azure/azure-rest-api-specs` +- [**Key-based authentication**](https://github.com/microsoft-foundry/foundry-samples/blob/main/samples/python/hosted-agents/SUPPORTED_TOOLBOX_SCENARIOS.md#4-mcp-key-auth-github): The tool requires a key to authenticate. Sample MCP server: `https://api.githubcopilot.com/mcp` (GitHub MCP server) with a Personal Access Token (PAT) for authentication. +- [**OAuth2 authentication (managed)**](https://github.com/microsoft-foundry/foundry-samples/blob/main/samples/python/hosted-agents/SUPPORTED_TOOLBOX_SCENARIOS.md#6-mcp-oauth-managed-connector): The tool requires OAuth2 to authenticate. Sample MCP server: `https://api.githubcopilot.com/mcp` (GitHub MCP server) with OAuth2 for authentication. +- [**Agent identity authentication**](https://github.com/microsoft-foundry/foundry-samples/blob/main/samples/python/hosted-agents/SUPPORTED_TOOLBOX_SCENARIOS.md#8-mcp-agent-identity): The tool requires an agent identity token to authenticate. Sample MCP server: `https://{foundry-resource-name}.cognitiveservices.azure.com/language/mcp?api-version=2025-11-15-preview` ([Azure Language MCP server](https://learn.microsoft.com/en-us/azure/ai-services/language-service/concepts/foundry-tools-agents#azure-language-mcp-server-preview)) with agent identity for authentication. +- [**Entra Pass-through authentication**](https://github.com/microsoft-foundry/foundry-samples/blob/main/samples/python/hosted-agents/SUPPORTED_TOOLBOX_SCENARIOS.md#13-mcp-oauth-entra-passthrough): The tool requires an Entra pass-through token to authenticate; Foundry forwards the calling user's Entra token to the MCP server. Sample MCP server: the [Microsoft Foundry MCP server](https://learn.microsoft.com/en-us/azure/foundry/mcp/get-started?view=foundry&tabs=user), which exposes Foundry model-catalog, evaluation, agent, and session tools and requires only that the caller have access to the Foundry project (no extra license). + +There are also Non-MCP tools in the toolbox that support different authentication methods. Learn more at the [Foundry sample repository](https://github.com/microsoft-foundry/foundry-samples/blob/main/samples/python/hosted-agents/SUPPORTED_TOOLBOX_SCENARIOS.md). + +### Finding the Entra audience for an MCP server + +An Entra pass-through connection requires an **audience** — the Entra resource that the MCP server validates tokens against. For the Microsoft Foundry MCP server (`https://mcp.ai.azure.com`), read it from the server's OAuth protected-resource metadata: + +```bash +curl https://mcp.ai.azure.com/.well-known/oauth-protected-resource +``` + +```jsonc +{ + "resource": "https://mcp.ai.azure.com", + "authorization_servers": ["https://login.microsoftonline.com/common/v2.0"], + "scopes_supported": ["https://mcp.ai.azure.com/Foundry.Mcp.Tools"] +} +``` + +Use the `resource` value (`https://mcp.ai.azure.com`) as the audience. + +> For connector-backed MCP servers (for example Microsoft 365 / WorkIQ servers such as Outlook Mail), the audience is instead published in the Foundry Tools Catalog. Look it up with the helper scripts in [`scripts/`](scripts/): run `./scripts/list-foundry-connectors.ps1 -ConnectorName ` (or `./scripts/list-foundry-connectors.sh -n `) and read `AzureActiveDirectoryResourceId` (equivalently `resourceUri`) under `properties.x-ms-connection-parameters`. Run the script with no connector name to list every connector with its name, title, and auth type. + +### Creating Connections + +Before creating the toolbox, create project connections for any tools that require authentication. The connection defines the authentication details and credentials for the tool, and the toolbox references the connection to authenticate tool invocations at runtime. The following connections are needed for this sample (used in `toolbox.yaml`): + +For `ghmcppat`, run the following command to create a PAT-based connection to the GitHub MCP server: + +```powershell +azd ai connection create ghmcppat --kind remote-tool --target https://api.githubcopilot.com/mcp --auth-type custom-keys --custom-key "Authorization=Bearer " -p https://.services.ai.azure.com/api/projects/ +``` + +For `ghmcpoauth`, create an OAuth2-based connection to the GitHub MCP server: + +```powershell +azd ai connection create ghmcpoauth --kind remote-tool --target https://api.githubcopilot.com/mcp --auth-type oauth2 --connector-name foundrygithubmcp -p https://.services.ai.azure.com/api/projects/ +``` + +> This sample uses `ghmcppat` by default, but you can switch to `ghmcpoauth` in the `toolbox.yaml` file. + +For `langmcpconn`, create an agent-identity-based connection to the Azure Language MCP server: + +```powershell +azd ai connection create langmcpconn --kind remote-tool --target https://.cognitiveservices.azure.com/language/mcp?api-version=2025-11-15-preview --auth-type project-managed-identity --audience https://cognitiveservices.azure.com/ -p https://.services.ai.azure.com/api/projects/ +``` + +For `foundrymcpconn`, create an Entra pass-through connection to the Microsoft Foundry MCP server: + +```powershell +azd ai connection create foundrymcpconn --kind remote-tool --target https://mcp.ai.azure.com --auth-type user-entra-token --audience https://mcp.ai.azure.com -p https://.services.ai.azure.com/api/projects/ +``` + +### Creating the toolbox You create the toolbox once from `toolbox.yaml`, then copy the versioned MCP endpoint it prints into the `TOOLBOX_ENDPOINT` environment variable. The agent connects to that endpoint at runtime. -> [!NOTE] -> To attach tools that need credentials (MCP servers with API keys or OAuth, Azure AI Search, Bing Custom Search, and more), create a project connection first and reference it from `toolbox.yaml`. For connection-backed examples, see the [`langgraph-toolbox`](../../../bring-your-own/responses/langgraph-toolbox/README.md) and [`langgraph-toolbox-user-identity`](../../../bring-your-own/responses/langgraph-toolbox-user-identity/README.md) samples, and the [supported toolbox scenarios](https://github.com/microsoft-foundry/foundry-samples/blob/main/samples/python/hosted-agents/SUPPORTED_TOOLBOX_SCENARIOS.md). +```powershell +azd ai toolbox create agent-tools --from-file ./toolbox.yaml --project-endpoint https://.services.ai.azure.com/api/projects/ +``` ## How it works ### Model Integration -The agent uses `FoundryChatClient` from the Agent Framework to create an OpenAI-compatible Responses client. It connects to the toolbox's MCP endpoint via `MCPStreamableHTTPTool`, which discovers and invokes the toolbox's tools over MCP at runtime. The agent resolves the endpoint from the `TOOLBOX_ENDPOINT` environment variable. If that variable isn't set, it builds the latest-version endpoint from `FOUNDRY_PROJECT_ENDPOINT` and `TOOLBOX_NAME`. +The agent uses `FoundryChatClient` from the Agent Framework to create an OpenAI-compatible Responses client. It connects to the toolbox's MCP endpoint via `FoundryToolbox` — a thin convenience wrapper over `MCPStreamableHTTPTool` that authenticates every request with the credential and forwards the platform per-request call-id — which discovers and invokes the toolbox's tools over MCP at runtime. `FoundryToolbox` resolves the endpoint from the `TOOLBOX_ENDPOINT` environment variable. If that variable isn't set, it builds the endpoint from `FOUNDRY_PROJECT_ENDPOINT` and `TOOLBOX_NAME`. See [main.py](main.py) for the full implementation. @@ -68,17 +137,17 @@ Follow the prompts to configure your Foundry project and model deployment. If yo The agent reads the toolbox's MCP endpoint from `TOOLBOX_ENDPOINT`. Create the toolbox once from the bundled [`toolbox.yaml`](toolbox.yaml): ```bash -azd ai toolbox create my-toolbox --from-file ./toolbox.yaml +azd ai toolbox create agent-tools --from-file ./toolbox.yaml --project-endpoint https://.services.ai.azure.com/api/projects/ ``` -The first version becomes the default automatically. Use `azd ai toolbox list`, `azd ai toolbox show my-toolbox`, and `azd ai toolbox version list my-toolbox` to inspect, and `azd ai toolbox delete my-toolbox --force` to remove it. +The first version becomes the default automatically. Use `azd ai toolbox list`, `azd ai toolbox show agent-tools`, and `azd ai toolbox version list agent-tools` to inspect, and `azd ai toolbox delete agent-tools --force` to remove it. -To stage incremental changes safely, use `azd ai toolbox connection add/remove` and `azd ai toolbox skill add/list/remove` — each creates a new toolbox version that carries forward existing connections and skills but **doesn't** change the default. Promote a version with `azd ai toolbox publish my-toolbox ` when you're ready to make it active. +To stage incremental changes safely, use `azd ai toolbox connection add/remove` and `azd ai toolbox skill add/list/remove`; each creates a new toolbox version that carries forward existing connections and skills but **doesn't** change the default. Promote a version with `azd ai toolbox publish agent-tools ` when you're ready to make it active. `azd ai toolbox create` prints the toolbox's versioned MCP endpoint. Copy that endpoint and store it in your `azd` environment so the agent connects to it: ```bash -azd env set TOOLBOX_ENDPOINT "https://.services.ai.azure.com/api/projects//toolboxes/my-toolbox/versions/1/mcp?api-version=v1" +azd env set TOOLBOX_ENDPOINT "https://.services.ai.azure.com/api/projects//toolboxes/agent-tools/versions/1/mcp?api-version=v1" ``` #### Provision Azure resources (if needed) @@ -125,9 +194,9 @@ azd ai agent invoke "What tools do you have?" #### Prerequisites -1. **VS Code** with the **[Foundry Toolkit](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.azure-ai-foundry)** extension installed. +1. **VS Code** with the **[Foundry Toolkit](https://learn.microsoft.com/en-us/azure/foundry/how-to/develop/get-started-projects-vs-code)** extension installed. 2. Sign in to Azure in VS Code. -3. The `my-toolbox` toolbox must exist in your Foundry project. Create it from the bundled [`toolbox.yaml`](toolbox.yaml) (`azd ai toolbox create my-toolbox --from-file ./toolbox.yaml`) or in the Foundry portal before you run the agent. +3. The `agent-tools` toolbox must exist in your Foundry project. Create it from the bundled [`toolbox.yaml`](toolbox.yaml) (`azd ai toolbox create agent-tools --from-file ./toolbox.yaml`) or in the Foundry portal before you run the agent. #### Create the project @@ -158,6 +227,44 @@ You can create a Foundry Toolbox by code. Refer to this sample for an example: [ You can also create a Foundry Toolbox in the Foundry portal. Read more about it [in the Foundry toolbox documentation](https://learn.microsoft.com/en-us/azure/foundry/agents/how-to/tools/toolbox). +## Troubleshooting + +### A single failing MCP source can fail the whole agent + +A toolbox aggregates every tool source behind one MCP endpoint. If **any** referenced MCP server fails while the toolbox enumerates tools (`tools/list`), the toolbox fails the entire enumeration, so the agent can't load its tools and every request returns an error (HTTP 500) until that source recovers. + +For example, a flaky third-party MCP source can intermittently return `HTTP 502 (Bad Gateway)` during enumeration, which surfaces as: + +``` +tools/list failed for 1 tool source(s), succeeded for 5 tool source(s) +{"errors":[{"name":"","type":"mcp","error":{"code":"HTTP_502", ...}}]} +``` + +This is an upstream/service hiccup, not a problem with the agent code. Mitigations: + +- Retry the request — these failures are usually transient. +- If a source is persistently unavailable, temporarily remove its tool entry (and connection) from `toolbox.yaml`, recreate the toolbox, and update `TOOLBOX_ENDPOINT`. +- Inspect deployed agent logs with `azd ai agent monitor` to identify which source failed. + +### Entra pass-through forwards the caller's identity + +The Foundry MCP tool authenticates with **Entra pass-through** (`foundrymcpconn`): Foundry forwards the +calling user's Entra token to `https://mcp.ai.azure.com`. The token is forwarded both from the Foundry +portal **Agent Playground** (signed-in user) and by `azd ai agent invoke` (the developer's Entra token), +so the tools operate as that user and only act on resources the user can already access. The Foundry MCP +server requires no extra license — just access to the Foundry project. + +Because the tool acts as a specific user, running the agent **locally** (`python main.py`) or calling the +endpoint with a raw token uses whatever identity that token represents (`az login` user locally, the +agent's managed identity when hosted). If that identity has no access to the target resources, the tool +returns an authorization error even though it is discovered and called correctly. + +> Some other Entra pass-through MCP servers add their **own** entitlement checks on top of the token. For +> example, the Microsoft 365 / WorkIQ servers (Outlook Mail, Teams) require the caller to hold a +> **Microsoft 365 Copilot (Business Chat)** license; without it they fail with +> `WorkIQ license check failed. Required service plan(s): [M365_COPILOT_BUSINESS_CHAT]`. That is a +> property of those servers, not of Entra pass-through itself. + ## Next steps - [Quickstart: Create a hosted agent](https://learn.microsoft.com/en-us/azure/foundry/agents/quickstarts/quickstart-hosted-agent) — end-to-end walkthrough using `azd` diff --git a/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/agent.manifest.yaml b/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/agent.manifest.yaml index 1c615f4a3..770bb0100 100644 --- a/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/agent.manifest.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/agent.manifest.yaml @@ -13,16 +13,16 @@ template: kind: hosted protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 environment_variables: - name: AZURE_AI_MODEL_DEPLOYMENT_NAME value: "{{AZURE_AI_MODEL_DEPLOYMENT_NAME}}" - # Full MCP endpoint of the toolbox the agent consumes. Create the toolbox - # from the bundled toolbox.yaml, then copy the versioned endpoint it prints - # and store it in your azd environment before you run or deploy: - # azd ai toolbox create my-toolbox --from-file ./toolbox.yaml - # azd env set TOOLBOX_ENDPOINT "" - name: TOOLBOX_ENDPOINT + # Full MCP endpoint of the toolbox the agent consumes. Create the toolbox + # from the bundled toolbox.yaml, then copy the versioned endpoint it prints + # and store it in your azd environment before you run or deploy: + # azd ai toolbox create my-toolbox --from-file ./toolbox.yaml + # azd env set TOOLBOX_ENDPOINT "" value: "{{TOOLBOX_ENDPOINT}}" resources: - kind: model diff --git a/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/agent.yaml b/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/agent.yaml index 5e44793e1..a9927d399 100644 --- a/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/agent.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/agent.yaml @@ -2,7 +2,7 @@ kind: hosted name: agent-framework-agent-with-foundry-toolbox-responses protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 resources: cpu: "0.25" memory: 0.5Gi diff --git a/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/main.py b/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/main.py index 0045c2ccd..782ad1d86 100644 --- a/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/main.py +++ b/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/main.py @@ -2,89 +2,46 @@ import asyncio import os -from collections.abc import Callable -import httpx -from agent_framework import Agent, MCPStreamableHTTPTool +from agent_framework import Agent from agent_framework.foundry import FoundryChatClient -from agent_framework_foundry_hosting import ResponsesHostServer -from azure.identity import DefaultAzureCredential, get_bearer_token_provider +from agent_framework_foundry_hosting import FoundryToolbox, ResponsesHostServer +from azure.identity import DefaultAzureCredential from dotenv import load_dotenv # Load environment variables from .env file load_dotenv() -def resolve_toolbox_endpoint() -> str: - """Resolve the toolbox MCP endpoint URL. - - Prefers the explicit ``TOOLBOX_ENDPOINT`` env var; falls back to - constructing the URL from ``FOUNDRY_PROJECT_ENDPOINT`` and ``TOOLBOX_NAME`` - (the variables injected by the Foundry hosting scaffolding after ``azd provision``). - """ - if (endpoint := os.environ.get("TOOLBOX_ENDPOINT")) is not None: - if not endpoint: - raise ValueError("TOOLBOX_ENDPOINT is set but empty") - return endpoint - project_endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"].rstrip("/") - toolbox_name = os.environ["TOOLBOX_NAME"] - return f"{project_endpoint}/toolboxes/{toolbox_name}/mcp?api-version=v1" - - -class ToolboxAuth(httpx.Auth): - """Injects a fresh bearer token on every request.""" - - def __init__(self, token_provider: Callable[[], str]): - self._get_token = token_provider - - def auth_flow(self, request: httpx.Request): - request.headers["Authorization"] = f"Bearer {self._get_token()}" - yield request - - async def main(): credential = DefaultAzureCredential() - # Create the toolbox - token_provider = get_bearer_token_provider(credential, "https://ai.azure.com/.default") - - # Resolve the endpoint once and derive the tool name from the same source: when - # ``TOOLBOX_NAME`` isn't explicitly set, parse it out of the resolved URL so the - # tool's local name and the upstream toolbox always agree. - toolbox_endpoint = resolve_toolbox_endpoint() - toolbox_name = os.environ.get("TOOLBOX_NAME") or toolbox_endpoint.rsplit("/mcp", 1)[0].rsplit("/", 1)[-1] - - async with httpx.AsyncClient( - auth=ToolboxAuth(token_provider), - headers={"Foundry-Features": "Toolboxes=V1Preview"}, - timeout=120.0, - ) as http_client: - toolbox = MCPStreamableHTTPTool( - name=toolbox_name, - url=toolbox_endpoint, - http_client=http_client, - load_prompts=False, - ) - - # Create the chat client - client = FoundryChatClient( - project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"], - model=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"], - credential=credential, - ) - - agent = Agent( - client=client, - instructions="You are a friendly assistant. Keep your answers brief.", - tools=toolbox, - # History will be managed by the hosting infrastructure, thus there - # is no need to store history by the service. Learn more at: - # https://developers.openai.com/api/reference/resources/responses/methods/create - default_options={"store": False}, - ) - - server = ResponsesHostServer(agent) - await server.run_async() + # FoundryToolbox resolves the toolbox endpoint from the environment + # (TOOLBOX_ENDPOINT, or FOUNDRY_PROJECT_ENDPOINT + TOOLBOX_NAME), authenticates + # every request with the credential, and transparently forwards the platform + # per-request call-id to the toolbox. The hosting server enters the agent, which + # connects the toolbox on first use and closes it at shutdown. + toolbox = FoundryToolbox(credential) + + # Create the chat client + client = FoundryChatClient( + project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"], + model=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"], + credential=credential, + ) + + agent = Agent( + client=client, + instructions="You are a friendly assistant. Keep your answers brief.", + tools=toolbox, + # History will be managed by the hosting infrastructure, thus there + # is no need to store history by the service. Learn more at: + # https://developers.openai.com/api/reference/resources/responses/methods/create + default_options={"store": False}, + ) + + server = ResponsesHostServer(agent) + await server.run_async() if __name__ == "__main__": diff --git a/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/requirements.txt b/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/requirements.txt index 01f3e7bc9..6969202b1 100644 --- a/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/requirements.txt +++ b/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/requirements.txt @@ -1,7 +1,5 @@ -# Use the narrow Foundry subpackages to keep dependencies light. agent-framework-foundry -agent-framework-foundry-hosting -mcp<2,>=1.24.0 +agent-framework-foundry-hosting>=1.0.0a260630 # debugpy enables local debugging of this agent with the Foundry Toolkit VS Code extension. -debugpy +debugpy \ No newline at end of file diff --git a/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/scripts/list-foundry-connectors.ps1 b/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/scripts/list-foundry-connectors.ps1 new file mode 100644 index 000000000..b2af59b91 --- /dev/null +++ b/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/scripts/list-foundry-connectors.ps1 @@ -0,0 +1,105 @@ +#!/usr/bin/env pwsh +<# +.SYNOPSIS + List Foundry Tools Catalog connectors, or fetch full details for one connector. + +.DESCRIPTION + Queries the Azure AI Foundry Tools Catalog (asset-gallery) connectors registry. + - With no -ConnectorName: lists all connectors (name, title, detected auth type). + - With -ConnectorName: prints the full JSON details for that connector. + + A bearer token for https://ai.azure.com is required. It is read from the + -Token parameter, then the CATALOG_TOKEN environment variable, and finally + acquired automatically via 'az account get-access-token' (requires 'az login'). + +.EXAMPLE + ./list-foundry-connectors.ps1 + Lists all connectors. + +.EXAMPLE + ./list-foundry-connectors.ps1 -ConnectorName a365outlookmailmcp + Prints full details for the Work IQ Mail MCP connector. + +.EXAMPLE + ./list-foundry-connectors.ps1 -PageSize 2000 + Lists more connectors in a single page. +#> +[CmdletBinding()] +param( + # annotations/name of a connector to fetch full details for. Omit to list all. + [string]$ConnectorName, + # Azure ML region host prefix. + [string]$Region = "eastus", + # Number of results to request in one page. + [int]$PageSize = 100, + # Catalog bearer token (audience https://ai.azure.com). Defaults to $env:CATALOG_TOKEN, else acquired via az. + [string]$Token = $env:CATALOG_TOKEN +) + +$ErrorActionPreference = "Stop" + +if (-not $Token) { + Write-Verbose "No token supplied; acquiring via 'az account get-access-token'..." + $Token = az account get-access-token --resource https://ai.azure.com --query accessToken -o tsv +} +if (-not $Token) { + throw "Failed to acquire a catalog token. Run 'az login', or pass -Token / set `$env:CATALOG_TOKEN." +} + +$uri = "https://$Region.api.azureml.ms/asset-gallery/v1.0/tools" +$headers = @{ + "Authorization" = "Bearer $Token" + "Content-Type" = "application/json" + "x-ms-user-agent" = "AzureMachineLearningWorkspacePortal/12.0" +} + +$filters = [System.Collections.ArrayList]@( + @{ field = "entityContainerId"; operator = "eq"; values = @("connectors-registry-prod-bl") } + @{ field = "type"; operator = "eq"; values = @("tools") } + @{ field = "kind"; operator = "eq"; values = @("Versioned") } + @{ field = "labels"; operator = "eq"; values = @("latest") } +) +if ($ConnectorName) { + [void]$filters.Add(@{ field = "annotations/name"; operator = "eq"; values = @($ConnectorName) }) +} + +$body = @{ + freeTextSearch = "*" + filters = $filters + includeTotalResultCount = $true + pageSize = $PageSize + skip = 0 +} | ConvertTo-Json -Depth 10 + +# The response can be several MB and may contain a property with an empty-string +# name, so read the raw content and parse with -AsHashtable. +$content = (Invoke-WebRequest -Method Post -Uri $uri -Headers $headers -Body $body).Content +$resp = $content | ConvertFrom-Json -AsHashtable -Depth 100 + +if ($ConnectorName) { + if ($resp.totalCount -eq 0) { + Write-Warning "No connector found with annotations/name '$ConnectorName'." + return + } + $resp.value | ConvertTo-Json -Depth 100 +} +else { + Write-Host "Total connectors: $($resp.totalCount)" + $resp.value | ForEach-Object { + $params = $_.properties.'x-ms-connection-parameters' + $authType = if ($null -eq $params) { + "None" + } + else { + $types = $params.Values | ForEach-Object { $_.type } + if ($types -contains "oauthSetting") { "OAuth2" } + elseif ($types -contains "securestring") { "CustomKeys" } + else { "None" } + } + [pscustomobject]@{ + Name = $_.annotations.name + Title = $_.properties.title + Auth = $authType + } + } | Format-Table -AutoSize +} diff --git a/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/scripts/list-foundry-connectors.sh b/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/scripts/list-foundry-connectors.sh new file mode 100644 index 000000000..3792dff01 --- /dev/null +++ b/samples/python/hosted-agents/agent-framework/responses/04-foundry-toolbox/scripts/list-foundry-connectors.sh @@ -0,0 +1,106 @@ +#!/usr/bin/env bash +# +# List Foundry Tools Catalog connectors, or fetch full details for one connector. +# +# - With no -n: lists all connectors (name, title, detected auth type). +# - With -n NAME: prints the full JSON details for that connector. +# +# A bearer token for https://ai.azure.com is required. It is read from the +# -t option, then the CATALOG_TOKEN environment variable, and finally acquired +# automatically via 'az account get-access-token' (requires 'az login'). +# +# Requires: curl, jq (and optionally az). +# +# Examples: +# ./list-foundry-connectors.sh +# ./list-foundry-connectors.sh -n a365outlookmailmcp +# ./list-foundry-connectors.sh -p 2000 +# +set -euo pipefail + +CONNECTOR_NAME="" +REGION="eastus" +PAGE_SIZE=100 +TOKEN="${CATALOG_TOKEN:-}" + +usage() { + cat <&2; usage; exit 1 ;; + :) echo "Option -$OPTARG requires an argument." >&2; usage; exit 1 ;; + esac +done + +if [[ -z "$TOKEN" ]]; then + TOKEN=$(az account get-access-token --resource https://ai.azure.com --query accessToken -o tsv) +fi +if [[ -z "$TOKEN" ]]; then + echo "Failed to acquire a catalog token. Run 'az login', or pass -t / set CATALOG_TOKEN." >&2 + exit 1 +fi + +URI="https://${REGION}.api.azureml.ms/asset-gallery/v1.0/tools" + +# Base filters; optionally narrow to a single connector by annotations/name. +FILTERS=$(jq -nc --arg connector "$CONNECTOR_NAME" ' + [ + {"field":"entityContainerId","operator":"eq","values":["connectors-registry-prod-bl"]}, + {"field":"type", "operator":"eq","values":["tools"]}, + {"field":"kind", "operator":"eq","values":["Versioned"]}, + {"field":"labels", "operator":"eq","values":["latest"]} + ] + ( ($connector | length) > 0 + ? [{"field":"annotations/name","operator":"eq","values":[$connector]}] + : [] ) + ') + +BODY=$(cat <=1.24.0 +agent-framework-foundry-hosting>=1.0.0a260630 # debugpy enables local debugging of this agent with the Foundry Toolkit VS Code extension. -debugpy +debugpy \ No newline at end of file diff --git a/samples/python/hosted-agents/agent-framework/responses/06-files/agent.manifest.yaml b/samples/python/hosted-agents/agent-framework/responses/06-files/agent.manifest.yaml index 5d4a39fa2..1dfe49e6b 100644 --- a/samples/python/hosted-agents/agent-framework/responses/06-files/agent.manifest.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/06-files/agent.manifest.yaml @@ -13,7 +13,7 @@ template: kind: hosted protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 environment_variables: - name: AZURE_AI_MODEL_DEPLOYMENT_NAME value: "{{AZURE_AI_MODEL_DEPLOYMENT_NAME}}" diff --git a/samples/python/hosted-agents/agent-framework/responses/06-files/agent.yaml b/samples/python/hosted-agents/agent-framework/responses/06-files/agent.yaml index 5a62d90ff..6d815c8af 100644 --- a/samples/python/hosted-agents/agent-framework/responses/06-files/agent.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/06-files/agent.yaml @@ -3,7 +3,7 @@ kind: hosted name: agent-framework-agent-files-responses protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 resources: cpu: '0.25' memory: '0.5Gi' diff --git a/samples/python/hosted-agents/agent-framework/responses/06-files/main.py b/samples/python/hosted-agents/agent-framework/responses/06-files/main.py index 0913208b9..6bb8444bb 100644 --- a/samples/python/hosted-agents/agent-framework/responses/06-files/main.py +++ b/samples/python/hosted-agents/agent-framework/responses/06-files/main.py @@ -66,7 +66,6 @@ async def main(): http_client = httpx.AsyncClient( auth=ToolboxAuth(token_provider), - headers={"Foundry-Features": "Toolboxes=V1Preview"}, timeout=120.0, ) diff --git a/samples/python/hosted-agents/agent-framework/responses/06-files/requirements.txt b/samples/python/hosted-agents/agent-framework/responses/06-files/requirements.txt index 01f3e7bc9..6969202b1 100644 --- a/samples/python/hosted-agents/agent-framework/responses/06-files/requirements.txt +++ b/samples/python/hosted-agents/agent-framework/responses/06-files/requirements.txt @@ -1,7 +1,5 @@ -# Use the narrow Foundry subpackages to keep dependencies light. agent-framework-foundry -agent-framework-foundry-hosting -mcp<2,>=1.24.0 +agent-framework-foundry-hosting>=1.0.0a260630 # debugpy enables local debugging of this agent with the Foundry Toolkit VS Code extension. -debugpy +debugpy \ No newline at end of file diff --git a/samples/python/hosted-agents/agent-framework/responses/07-skills/agent.manifest.yaml b/samples/python/hosted-agents/agent-framework/responses/07-skills/agent.manifest.yaml index 1711f9a08..fff3688a2 100644 --- a/samples/python/hosted-agents/agent-framework/responses/07-skills/agent.manifest.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/07-skills/agent.manifest.yaml @@ -14,7 +14,7 @@ template: kind: hosted protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 environment_variables: - name: AZURE_AI_MODEL_DEPLOYMENT_NAME value: "{{AZURE_AI_MODEL_DEPLOYMENT_NAME}}" diff --git a/samples/python/hosted-agents/agent-framework/responses/07-skills/agent.yaml b/samples/python/hosted-agents/agent-framework/responses/07-skills/agent.yaml index 96879c772..b15e6fbc3 100644 --- a/samples/python/hosted-agents/agent-framework/responses/07-skills/agent.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/07-skills/agent.yaml @@ -3,7 +3,7 @@ kind: hosted name: agent-framework-agent-with-skills-responses protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 resources: cpu: '0.25' memory: '0.5Gi' diff --git a/samples/python/hosted-agents/agent-framework/responses/07-skills/requirements.txt b/samples/python/hosted-agents/agent-framework/responses/07-skills/requirements.txt index 01f3e7bc9..6969202b1 100644 --- a/samples/python/hosted-agents/agent-framework/responses/07-skills/requirements.txt +++ b/samples/python/hosted-agents/agent-framework/responses/07-skills/requirements.txt @@ -1,7 +1,5 @@ -# Use the narrow Foundry subpackages to keep dependencies light. agent-framework-foundry -agent-framework-foundry-hosting -mcp<2,>=1.24.0 +agent-framework-foundry-hosting>=1.0.0a260630 # debugpy enables local debugging of this agent with the Foundry Toolkit VS Code extension. -debugpy +debugpy \ No newline at end of file diff --git a/samples/python/hosted-agents/agent-framework/responses/07-teams-activity/agent.manifest.yaml b/samples/python/hosted-agents/agent-framework/responses/07-teams-activity/agent.manifest.yaml index 958cfa4b0..8fdbf9046 100644 --- a/samples/python/hosted-agents/agent-framework/responses/07-teams-activity/agent.manifest.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/07-teams-activity/agent.manifest.yaml @@ -14,7 +14,7 @@ template: kind: hosted protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 environment_variables: - name: AZURE_AI_MODEL_DEPLOYMENT_NAME value: "{{AZURE_AI_MODEL_DEPLOYMENT_NAME}}" diff --git a/samples/python/hosted-agents/agent-framework/responses/07-teams-activity/agent.yaml b/samples/python/hosted-agents/agent-framework/responses/07-teams-activity/agent.yaml index e958ef1a3..bdd2c06b5 100644 --- a/samples/python/hosted-agents/agent-framework/responses/07-teams-activity/agent.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/07-teams-activity/agent.yaml @@ -3,7 +3,7 @@ kind: hosted name: agent-framework-agent-teams-activity protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 resources: cpu: '0.25' memory: '0.5Gi' diff --git a/samples/python/hosted-agents/agent-framework/responses/07-teams-activity/main.py b/samples/python/hosted-agents/agent-framework/responses/07-teams-activity/main.py index 04faff869..239aa7922 100644 --- a/samples/python/hosted-agents/agent-framework/responses/07-teams-activity/main.py +++ b/samples/python/hosted-agents/agent-framework/responses/07-teams-activity/main.py @@ -89,7 +89,6 @@ def main(): http_client = httpx.AsyncClient( auth=ToolboxAuth(token_provider), - headers={"Foundry-Features": "Toolboxes=V1Preview"}, timeout=120.0, ) diff --git a/samples/python/hosted-agents/agent-framework/responses/07-teams-activity/requirements.txt b/samples/python/hosted-agents/agent-framework/responses/07-teams-activity/requirements.txt index 01f3e7bc9..6969202b1 100644 --- a/samples/python/hosted-agents/agent-framework/responses/07-teams-activity/requirements.txt +++ b/samples/python/hosted-agents/agent-framework/responses/07-teams-activity/requirements.txt @@ -1,7 +1,5 @@ -# Use the narrow Foundry subpackages to keep dependencies light. agent-framework-foundry -agent-framework-foundry-hosting -mcp<2,>=1.24.0 +agent-framework-foundry-hosting>=1.0.0a260630 # debugpy enables local debugging of this agent with the Foundry Toolkit VS Code extension. -debugpy +debugpy \ No newline at end of file diff --git a/samples/python/hosted-agents/agent-framework/responses/08-observability/agent.manifest.yaml b/samples/python/hosted-agents/agent-framework/responses/08-observability/agent.manifest.yaml index 8e79fdf0d..93a66e1c9 100644 --- a/samples/python/hosted-agents/agent-framework/responses/08-observability/agent.manifest.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/08-observability/agent.manifest.yaml @@ -13,7 +13,7 @@ template: kind: hosted protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 environment_variables: - name: AZURE_AI_MODEL_DEPLOYMENT_NAME value: "{{AZURE_AI_MODEL_DEPLOYMENT_NAME}}" diff --git a/samples/python/hosted-agents/agent-framework/responses/08-observability/agent.yaml b/samples/python/hosted-agents/agent-framework/responses/08-observability/agent.yaml index 216dd415d..dbd6f052e 100644 --- a/samples/python/hosted-agents/agent-framework/responses/08-observability/agent.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/08-observability/agent.yaml @@ -3,7 +3,7 @@ kind: hosted name: agent-framework-agent-observability-responses protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 resources: cpu: '0.25' memory: '0.5Gi' diff --git a/samples/python/hosted-agents/agent-framework/responses/08-observability/requirements.txt b/samples/python/hosted-agents/agent-framework/responses/08-observability/requirements.txt index 01f3e7bc9..6969202b1 100644 --- a/samples/python/hosted-agents/agent-framework/responses/08-observability/requirements.txt +++ b/samples/python/hosted-agents/agent-framework/responses/08-observability/requirements.txt @@ -1,7 +1,5 @@ -# Use the narrow Foundry subpackages to keep dependencies light. agent-framework-foundry -agent-framework-foundry-hosting -mcp<2,>=1.24.0 +agent-framework-foundry-hosting>=1.0.0a260630 # debugpy enables local debugging of this agent with the Foundry Toolkit VS Code extension. -debugpy +debugpy \ No newline at end of file diff --git a/samples/python/hosted-agents/agent-framework/responses/09-declarative-customer-support/agent.manifest.yaml b/samples/python/hosted-agents/agent-framework/responses/09-declarative-customer-support/agent.manifest.yaml index 2378fd74c..584120c87 100644 --- a/samples/python/hosted-agents/agent-framework/responses/09-declarative-customer-support/agent.manifest.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/09-declarative-customer-support/agent.manifest.yaml @@ -15,7 +15,7 @@ template: kind: hosted protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 environment_variables: - name: AZURE_AI_MODEL_DEPLOYMENT_NAME value: "{{AZURE_AI_MODEL_DEPLOYMENT_NAME}}" diff --git a/samples/python/hosted-agents/agent-framework/responses/09-declarative-customer-support/agent.yaml b/samples/python/hosted-agents/agent-framework/responses/09-declarative-customer-support/agent.yaml index 68834440d..44ad3ede5 100644 --- a/samples/python/hosted-agents/agent-framework/responses/09-declarative-customer-support/agent.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/09-declarative-customer-support/agent.yaml @@ -3,7 +3,7 @@ kind: hosted name: agent-framework-declarative-customer-support-responses protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 resources: cpu: '0.25' memory: '0.5Gi' diff --git a/samples/python/hosted-agents/agent-framework/responses/09-declarative-customer-support/requirements.txt b/samples/python/hosted-agents/agent-framework/responses/09-declarative-customer-support/requirements.txt index c44de55a7..a00f21738 100644 --- a/samples/python/hosted-agents/agent-framework/responses/09-declarative-customer-support/requirements.txt +++ b/samples/python/hosted-agents/agent-framework/responses/09-declarative-customer-support/requirements.txt @@ -1,8 +1,6 @@ -# Use the narrow Foundry subpackages to keep dependencies light. -agent-framework-foundry agent-framework-declarative -agent-framework-foundry-hosting -mcp<2,>=1.24.0 +agent-framework-foundry +agent-framework-foundry-hosting>=1.0.0a260630 # debugpy enables local debugging of this agent with the Foundry Toolkit VS Code extension. -debugpy +debugpy \ No newline at end of file diff --git a/samples/python/hosted-agents/agent-framework/responses/11-azure-search-rag/agent.manifest.yaml b/samples/python/hosted-agents/agent-framework/responses/11-azure-search-rag/agent.manifest.yaml index f67076452..c75c21bcf 100644 --- a/samples/python/hosted-agents/agent-framework/responses/11-azure-search-rag/agent.manifest.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/11-azure-search-rag/agent.manifest.yaml @@ -16,7 +16,7 @@ template: kind: hosted protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 environment_variables: - name: AZURE_AI_MODEL_DEPLOYMENT_NAME value: "{{AZURE_AI_MODEL_DEPLOYMENT_NAME}}" diff --git a/samples/python/hosted-agents/agent-framework/responses/11-azure-search-rag/agent.yaml b/samples/python/hosted-agents/agent-framework/responses/11-azure-search-rag/agent.yaml index c6d58b23d..7ffb60057 100644 --- a/samples/python/hosted-agents/agent-framework/responses/11-azure-search-rag/agent.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/11-azure-search-rag/agent.yaml @@ -3,7 +3,7 @@ kind: hosted name: agent-framework-agent-azure-search-rag-responses protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 resources: cpu: "0.25" memory: "0.5Gi" diff --git a/samples/python/hosted-agents/agent-framework/responses/11-azure-search-rag/requirements.txt b/samples/python/hosted-agents/agent-framework/responses/11-azure-search-rag/requirements.txt index 2eefb8749..846c6d98d 100644 --- a/samples/python/hosted-agents/agent-framework/responses/11-azure-search-rag/requirements.txt +++ b/samples/python/hosted-agents/agent-framework/responses/11-azure-search-rag/requirements.txt @@ -1,8 +1,6 @@ -# Use the narrow Foundry / Azure AI Search subpackages to keep dependencies light. agent-framework-foundry agent-framework-azure-ai-search -agent-framework-foundry-hosting -mcp<2,>=1.24.0 +agent-framework-foundry-hosting>=1.0.0a260630 # debugpy enables local debugging of this agent with the Foundry Toolkit VS Code extension. -debugpy +debugpy \ No newline at end of file diff --git a/samples/python/hosted-agents/agent-framework/responses/12-foundry-skills/agent.manifest.yaml b/samples/python/hosted-agents/agent-framework/responses/12-foundry-skills/agent.manifest.yaml index fee2d5e8a..818c65bcd 100644 --- a/samples/python/hosted-agents/agent-framework/responses/12-foundry-skills/agent.manifest.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/12-foundry-skills/agent.manifest.yaml @@ -15,7 +15,7 @@ template: kind: hosted protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 environment_variables: - name: AZURE_AI_MODEL_DEPLOYMENT_NAME value: "{{AZURE_AI_MODEL_DEPLOYMENT_NAME}}" diff --git a/samples/python/hosted-agents/agent-framework/responses/12-foundry-skills/agent.yaml b/samples/python/hosted-agents/agent-framework/responses/12-foundry-skills/agent.yaml index c56d14ac4..3a7a14d0b 100644 --- a/samples/python/hosted-agents/agent-framework/responses/12-foundry-skills/agent.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/12-foundry-skills/agent.yaml @@ -3,7 +3,7 @@ kind: hosted name: agent-framework-agent-foundry-skills-responses protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 resources: cpu: "0.25" memory: "0.5Gi" diff --git a/samples/python/hosted-agents/agent-framework/responses/12-foundry-skills/requirements.txt b/samples/python/hosted-agents/agent-framework/responses/12-foundry-skills/requirements.txt index 11e34099a..7cf0122c2 100644 --- a/samples/python/hosted-agents/agent-framework/responses/12-foundry-skills/requirements.txt +++ b/samples/python/hosted-agents/agent-framework/responses/12-foundry-skills/requirements.txt @@ -1,7 +1,5 @@ -# Use the narrow Foundry subpackages to keep dependencies light. agent-framework-foundry -agent-framework-foundry-hosting -mcp<2,>=1.24.0 +agent-framework-foundry-hosting>=1.0.0a260630 azure-ai-projects # debugpy enables local debugging of this agent with the Foundry Toolkit VS Code extension. diff --git a/samples/python/hosted-agents/agent-framework/responses/13-foundry-memory/agent.manifest.yaml b/samples/python/hosted-agents/agent-framework/responses/13-foundry-memory/agent.manifest.yaml index 5f3b86883..4fbaf6075 100644 --- a/samples/python/hosted-agents/agent-framework/responses/13-foundry-memory/agent.manifest.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/13-foundry-memory/agent.manifest.yaml @@ -16,7 +16,7 @@ template: kind: hosted protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 environment_variables: - name: AZURE_AI_MODEL_DEPLOYMENT_NAME value: "{{AZURE_AI_MODEL_DEPLOYMENT_NAME}}" diff --git a/samples/python/hosted-agents/agent-framework/responses/13-foundry-memory/agent.yaml b/samples/python/hosted-agents/agent-framework/responses/13-foundry-memory/agent.yaml index 502a4c790..53691375e 100644 --- a/samples/python/hosted-agents/agent-framework/responses/13-foundry-memory/agent.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/13-foundry-memory/agent.yaml @@ -3,7 +3,7 @@ kind: hosted name: agent-framework-agent-foundry-memory-responses protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 resources: cpu: "0.25" memory: "0.5Gi" diff --git a/samples/python/hosted-agents/agent-framework/responses/13-foundry-memory/requirements.txt b/samples/python/hosted-agents/agent-framework/responses/13-foundry-memory/requirements.txt index 8294eab63..bb566e7e1 100644 --- a/samples/python/hosted-agents/agent-framework/responses/13-foundry-memory/requirements.txt +++ b/samples/python/hosted-agents/agent-framework/responses/13-foundry-memory/requirements.txt @@ -1,12 +1,6 @@ -# Use the narrow Foundry subpackages to keep dependencies light. agent-framework-foundry -agent-framework-foundry-hosting -# mcp is a transitive dependency of agent-framework-core[all] that is needed -# at runtime but not declared as a required dependency of agent-framework-core. -# Pin below 2.0: agent-framework-foundry-hosting imports ``McpError`` from mcp, -# which the 2.0 line renamed to ``MCPError`` — installing mcp 2.x breaks startup. -mcp>=1.24.0,<2 +agent-framework-foundry-hosting>=1.0.0a260630 azure-ai-projects # debugpy enables local debugging of this agent with the Foundry Toolkit VS Code extension. -debugpy +debugpy \ No newline at end of file diff --git a/samples/python/hosted-agents/agent-framework/responses/14-browser-automation-agent/agent.manifest.yaml b/samples/python/hosted-agents/agent-framework/responses/14-browser-automation-agent/agent.manifest.yaml index 157df7f8f..501e823b7 100644 --- a/samples/python/hosted-agents/agent-framework/responses/14-browser-automation-agent/agent.manifest.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/14-browser-automation-agent/agent.manifest.yaml @@ -14,7 +14,7 @@ template: kind: hosted protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 environment_variables: - name: AZURE_AI_MODEL_DEPLOYMENT_NAME value: "{{AZURE_AI_MODEL_DEPLOYMENT_NAME}}" diff --git a/samples/python/hosted-agents/agent-framework/responses/14-browser-automation-agent/agent.yaml b/samples/python/hosted-agents/agent-framework/responses/14-browser-automation-agent/agent.yaml index ddfd2efe1..3c5fa2cb8 100644 --- a/samples/python/hosted-agents/agent-framework/responses/14-browser-automation-agent/agent.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/14-browser-automation-agent/agent.yaml @@ -13,7 +13,7 @@ metadata: - Browser Automation protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 resources: cpu: "0.25" memory: "0.5Gi" diff --git a/samples/python/hosted-agents/agent-framework/responses/14-browser-automation-agent/requirements.txt b/samples/python/hosted-agents/agent-framework/responses/14-browser-automation-agent/requirements.txt index a3f2907cc..8b56656df 100644 --- a/samples/python/hosted-agents/agent-framework/responses/14-browser-automation-agent/requirements.txt +++ b/samples/python/hosted-agents/agent-framework/responses/14-browser-automation-agent/requirements.txt @@ -1,9 +1,7 @@ -agent-framework-core==1.2.2 -agent-framework-foundry>=1.2.2,<1.3 -agent-framework-foundry-hosting>=1.0.0a260429,<1.1 +agent-framework-core +agent-framework-foundry +agent-framework-foundry-hosting>=1.0.0a260630 azure-identity>=1.19.0 -httpx>=0.28.0 -mcp<2,>=1.24.0 pydantic>=2.0.0 python-dotenv>=1.0.0 websockets>=14.0 diff --git a/samples/python/hosted-agents/agent-framework/responses/14-browser-automation-agent/utils/agent_factory.py b/samples/python/hosted-agents/agent-framework/responses/14-browser-automation-agent/utils/agent_factory.py index b16855cf2..ae3d4f358 100644 --- a/samples/python/hosted-agents/agent-framework/responses/14-browser-automation-agent/utils/agent_factory.py +++ b/samples/python/hosted-agents/agent-framework/responses/14-browser-automation-agent/utils/agent_factory.py @@ -9,7 +9,12 @@ from agent_framework._mcp import MCPStreamableHTTPTool from agent_framework._middleware import chat_middleware, function_middleware from agent_framework._skills import SkillsProvider -from agent_framework._types import ChatResponse, ChatResponseUpdate, Content, ResponseStream +from agent_framework._types import ( + ChatResponse, + ChatResponseUpdate, + Content, + ResponseStream, +) from agent_framework.foundry import FoundryChatClient from azure.identity import DefaultAzureCredential @@ -66,7 +71,7 @@ async def live_view_url_inject_middleware(context: Any, call_next: Any) -> None: return global _last_prepended_url - should_prepend = (_last_prepended_url != _live_view_url) + should_prepend = _last_prepended_url != _live_view_url # Streaming path if context.stream and isinstance(context.result, ResponseStream): @@ -77,7 +82,11 @@ async def _inject_url_stream() -> AsyncIterable[ChatResponseUpdate]: # Prepend only the first time for this URL if should_prepend: yield ChatResponseUpdate( - contents=[Content.from_text(text=f"🔴Created Browser Session: [Live View]({_live_view_url}) \n\n")], + contents=[ + Content.from_text( + text=f"🔴Created Browser Session: [Live View]({_live_view_url}) \n\n" + ) + ], role="assistant", ) _last_prepended_url = _live_view_url @@ -95,21 +104,32 @@ async def _inject_url_stream() -> AsyncIterable[ChatResponseUpdate]: # Append URL at end of text responses if has_text: yield ChatResponseUpdate( - contents=[Content.from_text(text=f"\n\n🔴 [Browser Live View]({_live_view_url})\n")], + contents=[ + Content.from_text( + text=f"\n\n🔴 [Browser Live View]({_live_view_url})\n" + ) + ], role="assistant", finish_reason="stop", ) - context.result = ResponseStream(_inject_url_stream(), finalizer=ChatResponse.from_updates) + context.result = ResponseStream( + _inject_url_stream(), finalizer=ChatResponse.from_updates + ) logger.info("[chat-middleware] Wrapped stream for live_view_url injection") # Non-streaming path — only inject once per URL (same as streaming prepend guard) elif isinstance(context.result, ChatResponse) and should_prepend: from agent_framework._types import Message - url_message = Message("assistant", [f"\n\n🔴 [Browser Live View]({_live_view_url})"]) + + url_message = Message( + "assistant", [f"\n\n🔴 [Browser Live View]({_live_view_url})"] + ) context.result.messages.append(url_message) _last_prepended_url = _live_view_url - logger.info("[chat-middleware] Injected live_view_url into non-streaming response") + logger.info( + "[chat-middleware] Injected live_view_url into non-streaming response" + ) def build_agent(settings: AgentSettings) -> tuple[Agent, MCPStreamableHTTPTool]: @@ -124,7 +144,7 @@ def build_agent(settings: AgentSettings) -> tuple[Agent, MCPStreamableHTTPTool]: credential=credential, ) - skills_provider = SkillsProvider(skill_paths=skill_paths()) + skills_provider = SkillsProvider.from_paths(skill_paths()) toolbox_mcp_tool = make_toolbox_mcp_tool(settings, default_credential) run_playwright_cli = make_run_playwright_cli(settings) close_browser_session = make_close_browser_session(settings) @@ -135,9 +155,14 @@ def build_agent(settings: AgentSettings) -> tuple[Agent, MCPStreamableHTTPTool]: client=client, name="browser-automation-agent-sample-foundry", instructions=instructions, - tools=[run_playwright_cli, close_browser_session, get_live_view_url, toolbox_mcp_tool], + tools=[ + run_playwright_cli, + close_browser_session, + get_live_view_url, + toolbox_mcp_tool, + ], context_providers=[skills_provider], middleware=[tool_logging_middleware, live_view_url_inject_middleware], default_options={"store": False}, ) - return agent, toolbox_mcp_tool \ No newline at end of file + return agent, toolbox_mcp_tool diff --git a/samples/python/hosted-agents/agent-framework/responses/14-browser-automation-agent/utils/tools.py b/samples/python/hosted-agents/agent-framework/responses/14-browser-automation-agent/utils/tools.py index e8105993e..fdc3ae9a3 100644 --- a/samples/python/hosted-agents/agent-framework/responses/14-browser-automation-agent/utils/tools.py +++ b/samples/python/hosted-agents/agent-framework/responses/14-browser-automation-agent/utils/tools.py @@ -254,7 +254,6 @@ def make_toolbox_mcp_tool( token_provider = get_bearer_token_provider(credential, settings.azure_scope) http_client = httpx.AsyncClient( auth=ToolboxAuth(token_provider), - headers={"Foundry-Features": "Toolboxes=V1Preview"}, timeout=settings.mcp_timeout_seconds, ) diff --git a/samples/python/hosted-agents/agent-framework/responses/15-optimization-travel-approver/agent.manifest.yaml b/samples/python/hosted-agents/agent-framework/responses/15-optimization-travel-approver/agent.manifest.yaml index 59c0be5a6..dc7e4959f 100644 --- a/samples/python/hosted-agents/agent-framework/responses/15-optimization-travel-approver/agent.manifest.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/15-optimization-travel-approver/agent.manifest.yaml @@ -18,7 +18,7 @@ template: kind: hosted protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 environment_variables: - name: AZURE_AI_MODEL_DEPLOYMENT_NAME value: "{{AZURE_AI_MODEL_DEPLOYMENT_NAME}}" diff --git a/samples/python/hosted-agents/agent-framework/responses/15-optimization-travel-approver/agent.yaml b/samples/python/hosted-agents/agent-framework/responses/15-optimization-travel-approver/agent.yaml index b1dd9089b..9092eb98d 100644 --- a/samples/python/hosted-agents/agent-framework/responses/15-optimization-travel-approver/agent.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/15-optimization-travel-approver/agent.yaml @@ -3,7 +3,7 @@ kind: hosted name: optimization-travel-approver-python-responses protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 resources: cpu: "1" memory: 2Gi diff --git a/samples/python/hosted-agents/agent-framework/responses/15-optimization-travel-approver/requirements.txt b/samples/python/hosted-agents/agent-framework/responses/15-optimization-travel-approver/requirements.txt index 7c9c9b254..46cf1a47e 100644 --- a/samples/python/hosted-agents/agent-framework/responses/15-optimization-travel-approver/requirements.txt +++ b/samples/python/hosted-agents/agent-framework/responses/15-optimization-travel-approver/requirements.txt @@ -1,7 +1,5 @@ -# Use the narrow Foundry subpackages to keep dependencies light. agent-framework-foundry -agent-framework-foundry-hosting -mcp<2,>=1.24.0 +agent-framework-foundry-hosting>=1.0.0a260630 azure-identity>=1.15.0 azure-ai-agentserver-optimization>=1.0.0b1 diff --git a/samples/python/hosted-agents/agent-framework/responses/16-content-safety-guardrail/agent.manifest.yaml b/samples/python/hosted-agents/agent-framework/responses/16-content-safety-guardrail/agent.manifest.yaml index c971ae7f8..51efe4b95 100644 --- a/samples/python/hosted-agents/agent-framework/responses/16-content-safety-guardrail/agent.manifest.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/16-content-safety-guardrail/agent.manifest.yaml @@ -17,7 +17,7 @@ template: kind: hosted protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 # Content safety guardrail. Replace rai_policy_name with the full ARM resource # ID of an RAI policy on your Foundry resource. See README.md for how to create # one. Omit the policies block entirely to deploy the agent without a guardrail. diff --git a/samples/python/hosted-agents/agent-framework/responses/16-content-safety-guardrail/agent.yaml b/samples/python/hosted-agents/agent-framework/responses/16-content-safety-guardrail/agent.yaml index ff8d804b9..f2c036c10 100644 --- a/samples/python/hosted-agents/agent-framework/responses/16-content-safety-guardrail/agent.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/16-content-safety-guardrail/agent.yaml @@ -3,7 +3,7 @@ kind: hosted name: agent-framework-content-safety-guardrail protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 # Content safety guardrail. Replace rai_policy_name with the full ARM resource # ID of an RAI policy on your Foundry resource. See README.md for how to create # one. Omit the policies block entirely to deploy the agent without a guardrail. diff --git a/samples/python/hosted-agents/agent-framework/responses/16-content-safety-guardrail/requirements.txt b/samples/python/hosted-agents/agent-framework/responses/16-content-safety-guardrail/requirements.txt index 01f3e7bc9..6969202b1 100644 --- a/samples/python/hosted-agents/agent-framework/responses/16-content-safety-guardrail/requirements.txt +++ b/samples/python/hosted-agents/agent-framework/responses/16-content-safety-guardrail/requirements.txt @@ -1,7 +1,5 @@ -# Use the narrow Foundry subpackages to keep dependencies light. agent-framework-foundry -agent-framework-foundry-hosting -mcp<2,>=1.24.0 +agent-framework-foundry-hosting>=1.0.0a260630 # debugpy enables local debugging of this agent with the Foundry Toolkit VS Code extension. -debugpy +debugpy \ No newline at end of file diff --git a/samples/python/hosted-agents/agent-framework/responses/17-foundry-iq-toolbox/README.md b/samples/python/hosted-agents/agent-framework/responses/17-foundry-iq-toolbox/README.md index 1d88a8892..701ab1a39 100644 --- a/samples/python/hosted-agents/agent-framework/responses/17-foundry-iq-toolbox/README.md +++ b/samples/python/hosted-agents/agent-framework/responses/17-foundry-iq-toolbox/README.md @@ -15,11 +15,11 @@ flowchart LR 1. **Knowledge base (data plane).** [`provision_kb.py`](provision_kb.py) creates an Azure AI Search index, seeds it with the "Earth at night" documents, and builds a **knowledge source** and a **knowledge base**. The knowledge base synthesizes answers with an Azure OpenAI model and exposes an MCP endpoint (`{search}/knowledgebases/{kb}/mcp`) whose only tool is `knowledge_base_retrieve`. 2. **Toolbox connection.** A `RemoteTool` **connection** (`knowledge-base-mcp`) authenticates to the knowledge base's MCP endpoint with **Agentic Identity** — the agent's managed identity, keyless. A **toolbox** (defined in [`toolbox.yaml`](toolbox.yaml)) exposes that endpoint as an MCP tool: its `server_url` points at the knowledge base's MCP endpoint and `project_connection_id` supplies the connection's auth. Both are created for you by the `azd provision` `postprovision` hook (see [Provision and run the agent](#provision-and-run-the-agent)). -3. **Agent.** [`main.py`](main.py) uses `FoundryChatClient` and connects to the toolbox's MCP endpoint with `MCPStreamableHTTPTool`. The agent discovers `knowledge_base_retrieve` at runtime and grounds its answers in the retrieved sources. +3. **Agent.** [`main.py`](main.py) uses `FoundryChatClient` and connects to the toolbox's MCP endpoint with `FoundryToolbox`. The agent discovers `knowledge_base_retrieve` at runtime and grounds its answers in the retrieved sources. ### Model Integration -The agent uses `FoundryChatClient` from the Agent Framework to create an OpenAI-compatible Responses client, and connects to the toolbox over MCP via `MCPStreamableHTTPTool`. It reads the toolbox's MCP endpoint from the `TOOLBOX_ENDPOINT` environment variable. See [main.py](main.py) for the full implementation. +The agent uses `FoundryChatClient` from the Agent Framework to create an OpenAI-compatible Responses client, and connects to the toolbox over MCP via `FoundryToolbox`. It reads the toolbox's MCP endpoint from the `TOOLBOX_ENDPOINT` environment variable. See [main.py](main.py) for the full implementation. ## Prerequisites diff --git a/samples/python/hosted-agents/agent-framework/responses/17-foundry-iq-toolbox/agent.manifest.yaml b/samples/python/hosted-agents/agent-framework/responses/17-foundry-iq-toolbox/agent.manifest.yaml index 4ed182cf8..763c44f9c 100644 --- a/samples/python/hosted-agents/agent-framework/responses/17-foundry-iq-toolbox/agent.manifest.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/17-foundry-iq-toolbox/agent.manifest.yaml @@ -21,7 +21,7 @@ template: kind: hosted protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 environment_variables: - name: AZURE_AI_MODEL_DEPLOYMENT_NAME value: "{{AZURE_AI_MODEL_DEPLOYMENT_NAME}}" diff --git a/samples/python/hosted-agents/agent-framework/responses/17-foundry-iq-toolbox/agent.yaml b/samples/python/hosted-agents/agent-framework/responses/17-foundry-iq-toolbox/agent.yaml index a1f447ea2..5de913407 100644 --- a/samples/python/hosted-agents/agent-framework/responses/17-foundry-iq-toolbox/agent.yaml +++ b/samples/python/hosted-agents/agent-framework/responses/17-foundry-iq-toolbox/agent.yaml @@ -3,7 +3,7 @@ kind: hosted name: agent-framework-foundry-iq-knowledge-base-responses protocols: - protocol: responses - version: 1.0.0 + version: 2.0.0 resources: cpu: "0.25" memory: "0.5Gi" diff --git a/samples/python/hosted-agents/agent-framework/responses/17-foundry-iq-toolbox/main.py b/samples/python/hosted-agents/agent-framework/responses/17-foundry-iq-toolbox/main.py index 38ef0ed00..2f1261419 100644 --- a/samples/python/hosted-agents/agent-framework/responses/17-foundry-iq-toolbox/main.py +++ b/samples/python/hosted-agents/agent-framework/responses/17-foundry-iq-toolbox/main.py @@ -2,87 +2,51 @@ import asyncio import os -from collections.abc import Callable -import httpx -from agent_framework import Agent, MCPStreamableHTTPTool +from agent_framework import Agent from agent_framework.foundry import FoundryChatClient -from agent_framework_foundry_hosting import ResponsesHostServer -from azure.identity import DefaultAzureCredential, get_bearer_token_provider +from agent_framework_foundry_hosting import FoundryToolbox, ResponsesHostServer +from azure.identity import DefaultAzureCredential from dotenv import load_dotenv # Load environment variables from .env file load_dotenv() -def resolve_toolbox_endpoint() -> str: - """Resolve the toolbox MCP endpoint URL from the ``TOOLBOX_ENDPOINT`` env var. - - Set it to the versioned endpoint printed by ``azd ai toolbox create`` (see - README.md / toolbox.yaml). - """ - endpoint = os.environ.get("TOOLBOX_ENDPOINT") - if not endpoint: - raise ValueError("TOOLBOX_ENDPOINT is not set") - return endpoint - - -class ToolboxAuth(httpx.Auth): - """Injects a fresh bearer token on every request.""" - - def __init__(self, token_provider: Callable[[], str]): - self._get_token = token_provider - - def auth_flow(self, request: httpx.Request): - request.headers["Authorization"] = f"Bearer {self._get_token()}" - yield request - - async def main(): credential = DefaultAzureCredential() - # Token for the Foundry toolbox MCP endpoint. The toolbox proxies the call to - # the Azure AI Search knowledge base using the agent's managed identity, which - # is configured on the `knowledge-base-mcp` connection in agent.manifest.yaml. - token_provider = get_bearer_token_provider(credential, "https://ai.azure.com/.default") - - toolbox_endpoint = resolve_toolbox_endpoint() - - async with httpx.AsyncClient( - auth=ToolboxAuth(token_provider), - headers={"Foundry-Features": "Toolboxes=V1Preview"}, - timeout=120.0, - ) as http_client: - toolbox = MCPStreamableHTTPTool( - name="knowledge_base", - url=toolbox_endpoint, - http_client=http_client, - load_prompts=False, - ) - - client = FoundryChatClient( - project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"], - model=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"], - credential=credential, - ) - - agent = Agent( - client=client, - instructions=( - "You are a helpful assistant. Use the knowledge base tool to answer " - "user questions. If the knowledge base doesn't contain the answer, " - "respond with 'I don't know'. When you use information from the " - "knowledge base, include citations to the retrieved sources." - ), - tools=toolbox, - # History will be managed by the hosting infrastructure, thus there - # is no need to store history by the service. Learn more at: - # https://developers.openai.com/api/reference/resources/responses/methods/create - default_options={"store": False}, - ) - - server = ResponsesHostServer(agent) - await server.run_async() + # FoundryToolbox resolves the toolbox endpoint from the environment + # (TOOLBOX_ENDPOINT, or FOUNDRY_PROJECT_ENDPOINT + TOOLBOX_NAME) and authenticates + # every request with the credential. The toolbox proxies the call to the Azure AI + # Search knowledge base using the agent's managed identity, which is configured on + # the `knowledge-base-mcp` connection in agent.manifest.yaml. The hosting server + # enters the agent, which connects the toolbox on first use and closes it at shutdown. + toolbox = FoundryToolbox(credential, name="knowledge_base") + + client = FoundryChatClient( + project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"], + model=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"], + credential=credential, + ) + + agent = Agent( + client=client, + instructions=( + "You are a helpful assistant. Use the knowledge base tool to answer " + "user questions. If the knowledge base doesn't contain the answer, " + "respond with 'I don't know'. When you use information from the " + "knowledge base, include citations to the retrieved sources." + ), + tools=toolbox, + # History will be managed by the hosting infrastructure, thus there + # is no need to store history by the service. Learn more at: + # https://developers.openai.com/api/reference/resources/responses/methods/create + default_options={"store": False}, + ) + + server = ResponsesHostServer(agent) + await server.run_async() if __name__ == "__main__": diff --git a/samples/python/hosted-agents/agent-framework/responses/17-foundry-iq-toolbox/requirements.txt b/samples/python/hosted-agents/agent-framework/responses/17-foundry-iq-toolbox/requirements.txt index e9d0f0f2a..d852f8743 100644 --- a/samples/python/hosted-agents/agent-framework/responses/17-foundry-iq-toolbox/requirements.txt +++ b/samples/python/hosted-agents/agent-framework/responses/17-foundry-iq-toolbox/requirements.txt @@ -1,16 +1,2 @@ -# Install the narrow Foundry subpackages directly required by this sample -# (Agent, MCPStreamableHTTPTool, FoundryChatClient, ResponsesHostServer) instead -# of the bare ``agent-framework`` meta-package. The meta-package pulls in -# ``agent-framework-orchestrations``, whose latest release requires -# ``agent-framework-core>=1.9.0`` while ``agent-framework`` pins -# ``agent-framework-core==1.2.2`` — an unsatisfiable combination that fails the -# remote build with ``ResolutionImpossible``. The narrow ``agent-framework-foundry`` -# subpackage still provides ``agent_framework`` and ``agent_framework.foundry``. agent-framework-foundry -agent-framework-foundry-hosting -# mcp backs MCPStreamableHTTPTool's runtime client and is imported by -# agent-framework-foundry-hosting (``from mcp import McpError``); it is needed at -# runtime but not declared as a required dependency of agent-framework-core. Pin -# below 2.0: the 2.0 line renamed ``McpError`` to ``MCPError`` and breaks startup. -mcp>=1.24.0,<2 -httpx +agent-framework-foundry-hosting>=1.0.0a260630 From d37b031f02134a3bee7185ea94d0b05f62edcd7f Mon Sep 17 00:00:00 2001 From: Linda Li <139801625+lindazqli@users.noreply.github.com> Date: Tue, 30 Jun 2026 18:55:05 -0700 Subject: [PATCH 2/2] Remove Foundry-Features: Toolboxes=V1Preview opt-in header from toolbox samples (#599) * Remove Foundry-Features: Toolboxes=V1Preview opt-in header from toolbox samples * Keep Foundry-Features: Toolboxes=V1Preview header for agent-framework toolbox samples The header is still required on the python agent-framework/responses toolbox path. Removing it makes 04-foundry-toolbox, 06-files, 07-teams-activity, and 17-foundry-iq-toolbox return HTTP 500 server_error on the live toolbox invoke (proven by main-vs-PR A/B: these pass on main with the header and fail on this branch without it). Restore the header only on these samples. * Keep Foundry-Features: Toolboxes=V1Preview header for bring-your-own-toolbox sample Removing the header (and the call_id platform-header forwarding) makes the live toolbox invoke E2E fail with "Agent returned an error response". Proven by main-vs-PR A/B: bring-your-own-toolbox-code-interpreter-container is success on main with the header and fails on this branch without it. Restore the file to main. * Keep Foundry-Features: Toolboxes=V1Preview header for langgraph-toolbox (bring-your-own/responses) sample Removing the header + call_id forwarding makes the Foundry-Ext smoke invoke return 500 server_error. Same proven regression as bring-your-own-toolbox / agent-framework toolbox samples. Restore the file to main. --- .../foundry-toolbox-mcp-skills/Program.cs | 6 ------ .../browser-automation/utils/ToolboxClient.cs | 3 --- .../invocations/toolbox/main.py | 15 -------------- .../browser-automation/utils/toolbox.py | 4 ---- .../langgraph-toolbox-user-identity/README.md | 1 - .../langgraph-toolbox-user-identity/main.py | 20 ------------------- .../responses/langgraph-toolbox/README.md | 1 - .../langgraph/a2a/a2a-caller/README.md | 1 - .../langgraph/a2a/a2a-caller/main.py | 1 - .../responses/02-langgraph-toolbox/README.md | 2 +- 10 files changed, 1 insertion(+), 53 deletions(-) diff --git a/samples/csharp/hosted-agents/agent-framework/foundry-toolbox-mcp-skills/Program.cs b/samples/csharp/hosted-agents/agent-framework/foundry-toolbox-mcp-skills/Program.cs index 98ff25495..a20b908b2 100644 --- a/samples/csharp/hosted-agents/agent-framework/foundry-toolbox-mcp-skills/Program.cs +++ b/samples/csharp/hosted-agents/agent-framework/foundry-toolbox-mcp-skills/Program.cs @@ -62,8 +62,6 @@ Console.WriteLine($"Connecting to Foundry Toolbox '{toolboxName}' MCP server..."); // Connect to the Foundry Toolbox MCP endpoint. -// The Foundry-Features: Toolboxes=V1Preview opt-in header is required while the -// toolbox MCP surface is in preview. await using var mcpClient = await McpClient.CreateAsync( new HttpClientTransport( new HttpClientTransportOptions @@ -71,10 +69,6 @@ Endpoint = new Uri(toolboxMcpServerUrl), Name = toolboxName, TransportMode = HttpTransportMode.StreamableHttp, - AdditionalHeaders = new Dictionary - { - ["Foundry-Features"] = "Toolboxes=V1Preview", - }, }, httpClient)); diff --git a/samples/csharp/hosted-agents/bring-your-own/responses/browser-automation/utils/ToolboxClient.cs b/samples/csharp/hosted-agents/bring-your-own/responses/browser-automation/utils/ToolboxClient.cs index d6cabd4ec..daae80d5a 100644 --- a/samples/csharp/hosted-agents/bring-your-own/responses/browser-automation/utils/ToolboxClient.cs +++ b/samples/csharp/hosted-agents/bring-your-own/responses/browser-automation/utils/ToolboxClient.cs @@ -11,8 +11,6 @@ namespace BrowserAutomation; /// public class ToolboxClient { - private const string ToolboxFeatures = "Toolboxes=V1Preview"; - private readonly string _endpoint; private readonly Func _getToken; private readonly ILogger _logger; @@ -152,7 +150,6 @@ private async Task PostAsync(HttpClient client, object body Content = new StringContent(json, System.Text.Encoding.UTF8, "application/json"), }; request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _getToken()); - request.Headers.TryAddWithoutValidation("Foundry-Features", ToolboxFeatures); if (_sessionId != null) request.Headers.TryAddWithoutValidation("mcp-session-id", _sessionId); diff --git a/samples/python/hosted-agents/bring-your-own/invocations/toolbox/main.py b/samples/python/hosted-agents/bring-your-own/invocations/toolbox/main.py index f8c73ca62..30ab689f7 100644 --- a/samples/python/hosted-agents/bring-your-own/invocations/toolbox/main.py +++ b/samples/python/hosted-agents/bring-your-own/invocations/toolbox/main.py @@ -121,16 +121,6 @@ sep = "&" if "?" in TOOLBOX_ENDPOINT else "?" TOOLBOX_ENDPOINT += f"{sep}api-version=v1" -# Feature-flag header value (e.g. "Toolboxes=V1Preview"). -_TOOLBOX_FEATURES = os.getenv( - "FOUNDRY_AGENT_TOOLBOX_FEATURES", "Toolboxes=V1Preview") - -# Platform-injected per-request call identifier (container protocol v2.0.0). -# Extracted from the inbound invocation context and forwarded verbatim on every -# egress call to the Foundry toolbox MCP proxy so the platform can correlate the -# downstream tool calls with the originating invocation. The header name is owned -# by the SDK; use ``platform_headers()`` instead of hardcoding it. - _credential = DefaultAzureCredential() _project_client = AIProjectClient(endpoint=_endpoint, credential=_credential) _responses_client = _project_client.get_openai_client().responses @@ -160,11 +150,6 @@ def _headers(self, call_id: str | None = None) -> dict: "Content-Type": "application/json", "Authorization": f"Bearer {self._get_token()}", } - if _TOOLBOX_FEATURES: - h["Foundry-Features"] = _TOOLBOX_FEATURES - # Forward the per-request call ID extracted from the inbound invocation. - if call_id: - h.update(FoundryAgentRequestContext(call_id=call_id).platform_headers()) if self._session_id: h["mcp-session-id"] = self._session_id return h diff --git a/samples/python/hosted-agents/bring-your-own/responses/browser-automation/utils/toolbox.py b/samples/python/hosted-agents/bring-your-own/responses/browser-automation/utils/toolbox.py index 2ef194bec..4812adcf4 100644 --- a/samples/python/hosted-agents/bring-your-own/responses/browser-automation/utils/toolbox.py +++ b/samples/python/hosted-agents/bring-your-own/responses/browser-automation/utils/toolbox.py @@ -11,8 +11,6 @@ logger = logging.getLogger(__name__) -_TOOLBOX_FEATURES = "Toolboxes=V1Preview" - class ToolboxClient: """Lightweight MCP client for Foundry Toolbox browser session management.""" @@ -30,8 +28,6 @@ def _headers(self) -> dict: "Content-Type": "application/json", "Authorization": f"Bearer {self._get_token()}", } - if _TOOLBOX_FEATURES: - h["Foundry-Features"] = _TOOLBOX_FEATURES if self._session_id: h["mcp-session-id"] = self._session_id return h diff --git a/samples/python/hosted-agents/bring-your-own/responses/langgraph-toolbox-user-identity/README.md b/samples/python/hosted-agents/bring-your-own/responses/langgraph-toolbox-user-identity/README.md index 03e192ddf..8871f6204 100644 --- a/samples/python/hosted-agents/bring-your-own/responses/langgraph-toolbox-user-identity/README.md +++ b/samples/python/hosted-agents/bring-your-own/responses/langgraph-toolbox-user-identity/README.md @@ -309,7 +309,6 @@ my-project/ | `FOUNDRY_PROJECT_ENDPOINT` | **Yes** | Project endpoint URL — platform-injected at runtime | | `MODEL_DEPLOYMENT_NAME` | **Yes** | Model deployment name (e.g. `gpt-4.1`) | | `TOOLBOX_ENDPOINT` | **Yes** | Full toolbox MCP endpoint URL including toolbox name and api-version | -| `FOUNDRY_AGENT_TOOLBOX_FEATURES` | No | Feature-flag header value — platform-injected (default: `Toolboxes=V1Preview`) | `TOOLBOX_ENDPOINT` is the full pre-constructed MCP URL. Two forms are supported: ``` diff --git a/samples/python/hosted-agents/bring-your-own/responses/langgraph-toolbox-user-identity/main.py b/samples/python/hosted-agents/bring-your-own/responses/langgraph-toolbox-user-identity/main.py index ace8c0a52..85290e00a 100644 --- a/samples/python/hosted-agents/bring-your-own/responses/langgraph-toolbox-user-identity/main.py +++ b/samples/python/hosted-agents/bring-your-own/responses/langgraph-toolbox-user-identity/main.py @@ -8,7 +8,6 @@ The Foundry platform injects these at runtime: - `FOUNDRY_PROJECT_ENDPOINT` — project endpoint - `FOUNDRY_AGENT_TOOLBOX_ENDPOINT` — base URL for toolbox MCP proxy -- `FOUNDRY_AGENT_TOOLBOX_FEATURES` — feature-flag headers for toolbox requests ## User-Defined Variables @@ -129,15 +128,6 @@ def auth_flow(self, request): else: TOOLBOX_ENDPOINT = "" -# Feature-flag header value (e.g. "Toolboxes=V1Preview"). -_TOOLBOX_FEATURES = os.getenv("FOUNDRY_AGENT_TOOLBOX_FEATURES", "Toolboxes=V1Preview") - -# Platform-injected per-request call identifier (container protocol v2.0.0). -# Extracted from the inbound responses request via ``get_request_context()`` and -# forwarded on the egress toolbox MCP calls so the platform can correlate the -# downstream tool calls with the originating request. The header name is owned -# by the SDK; use ``platform_headers()`` instead of hardcoding it. - def _toolbox_name_from_endpoint(endpoint: str) -> str | None: """Extract toolbox name from endpoint URL path.""" @@ -182,20 +172,10 @@ async def quickstart(call_id: str | None = None): ) logger.info(f"Connecting to toolbox: {TOOLBOX_ENDPOINT}") - extra_headers = {"Foundry-Features": _TOOLBOX_FEATURES} if _TOOLBOX_FEATURES else {} - # Forward the inbound per-request call ID on toolbox egress calls. Note: - # AzureAIProjectToolbox only accepts static extra_headers at construction and - # the agent/toolbox is cached (see _get_agent), so the call ID captured on the - # first request is reused for the lifetime of the cached toolbox. - if call_id: - extra_headers.update( - FoundryAgentRequestContext(call_id=call_id).platform_headers() - ) toolbox = AzureAIProjectToolbox( project_endpoint=PROJECT_ENDPOINT, toolbox_name=toolbox_name, credential=DefaultAzureCredential(), - extra_headers=extra_headers, ) tools = await toolbox.get_tools() diff --git a/samples/python/hosted-agents/bring-your-own/responses/langgraph-toolbox/README.md b/samples/python/hosted-agents/bring-your-own/responses/langgraph-toolbox/README.md index 1e1531b95..02e938223 100644 --- a/samples/python/hosted-agents/bring-your-own/responses/langgraph-toolbox/README.md +++ b/samples/python/hosted-agents/bring-your-own/responses/langgraph-toolbox/README.md @@ -236,7 +236,6 @@ my-project/ | `AZURE_AI_MODEL_DEPLOYMENT_NAME` | **Yes** | Model deployment name (e.g. `gpt-4.1`) | | `TOOLBOX_ENDPOINT` | **Yes** | Full toolbox MCP endpoint URL. Copy the versioned endpoint from the `azd ai toolbox create` output. | | `TOOLBOX_NAME` | No | Toolbox name. If `TOOLBOX_ENDPOINT` isn't set, the agent builds the latest-version endpoint from this and `FOUNDRY_PROJECT_ENDPOINT`. | -| `FOUNDRY_AGENT_TOOLBOX_FEATURES` | No | Feature-flag header value — platform-injected (default: `Toolboxes=V1Preview`) | Set `TOOLBOX_ENDPOINT` to the full MCP URL. Two forms are supported: ``` diff --git a/samples/python/hosted-agents/langgraph/a2a/a2a-caller/README.md b/samples/python/hosted-agents/langgraph/a2a/a2a-caller/README.md index 42b080cc5..b0a14d656 100644 --- a/samples/python/hosted-agents/langgraph/a2a/a2a-caller/README.md +++ b/samples/python/hosted-agents/langgraph/a2a/a2a-caller/README.md @@ -26,7 +26,6 @@ client = MultiServerMCPClient({ "a2a-delegation": { "transport": "streamable_http", "url": f"{project_endpoint}/toolboxes/{toolbox_name}/mcp?api-version=v1", - "headers": {"Foundry-Features": "Toolboxes=V1Preview"}, "auth": _ToolboxAuth(token_provider), # fresh Entra token per request } }) diff --git a/samples/python/hosted-agents/langgraph/a2a/a2a-caller/main.py b/samples/python/hosted-agents/langgraph/a2a/a2a-caller/main.py index 7414f8d2e..c63ca9b76 100644 --- a/samples/python/hosted-agents/langgraph/a2a/a2a-caller/main.py +++ b/samples/python/hosted-agents/langgraph/a2a/a2a-caller/main.py @@ -78,7 +78,6 @@ async def _load_toolbox_tools() -> list[BaseTool]: "a2a-delegation": { "transport": "streamable_http", "url": _toolbox_mcp_url(), - "headers": {"Foundry-Features": "Toolboxes=V1Preview"}, "auth": _ToolboxAuth(token_provider), } } diff --git a/samples/python/hosted-agents/langgraph/responses/02-langgraph-toolbox/README.md b/samples/python/hosted-agents/langgraph/responses/02-langgraph-toolbox/README.md index c19df1f4b..650488597 100644 --- a/samples/python/hosted-agents/langgraph/responses/02-langgraph-toolbox/README.md +++ b/samples/python/hosted-agents/langgraph/responses/02-langgraph-toolbox/README.md @@ -29,7 +29,7 @@ You can also create a Foundry Toolbox in the Foundry portal. Read more about it ### Toolbox tool loading -[`langchain_azure_ai.tools.AzureAIProjectToolbox`](https://github.com/langchain-ai/langchain-azure/blob/main/libs/azure-ai/langchain_azure_ai/tools/_toolbox.py) opens an MCP session against the toolbox endpoint, authenticates with `DefaultAzureCredential`, injects the required `Foundry-Features` header, sanitizes tool schemas, and returns standard LangChain `BaseTool` instances. Tools are loaded **lazily** (once, on the first request) and reused for all subsequent turns; each tool invocation opens its own short-lived MCP session. +[`langchain_azure_ai.tools.AzureAIProjectToolbox`](https://github.com/langchain-ai/langchain-azure/blob/main/libs/azure-ai/langchain_azure_ai/tools/_toolbox.py) opens an MCP session against the toolbox endpoint, authenticates with `DefaultAzureCredential`, sanitizes tool schemas, and returns standard LangChain `BaseTool` instances. Tools are loaded **lazily** (once, on the first request) and reused for all subsequent turns; each tool invocation opens its own short-lived MCP session. ### LangGraph Agent