From e260200a7b4c902178a5c013a744970462e69cb5 Mon Sep 17 00:00:00 2001
From: Roger Barreto <19890735+RogerBarreto@users.noreply.github.com>
Date: Thu, 10 Sep 2026 12:09:27 +0100
Subject: [PATCH 1/4] .NET: Add Foundry hosted session client samples
---
dotnet/agent-framework-dotnet.slnx | 2 +
.../Agent_Step25_FoundryToolboxMcp/Program.cs | 30 +---
.../Program.cs | 4 -
.../FoundrySkills.cs | 4 -
.../ClawAgent/FoundrySkills.cs | 4 -
.../InvokeFoundryToolboxMcp.yaml | 6 -
.../InvokeFoundryToolboxMcp/Program.cs | 24 +--
.../responses/Hosted-AgentSkills/Program.cs | 28 +---
.../responses/Hosted-AgentSkills/README.md | 6 +-
.../Hosted-ToolboxMcpSkills/Program.cs | 4 -
.../FoundryHostedSession/.env.example | 2 +
.../FoundryHostedSession.csproj | 24 +++
.../FoundryHostedSession/Program.cs | 119 +++++++++++++++
.../FoundryHostedSession/README.md | 86 +++++++++++
.../responses/Using-Samples/README.md | 2 +
.../UserIsolationAgent/.env.example | 2 +
.../UserIsolationAgent/Program.cs | 141 ++++++++++++++++++
.../UserIsolationAgent/README.md | 122 +++++++++++++++
.../UserIsolationAgent.csproj | 24 +++
19 files changed, 530 insertions(+), 104 deletions(-)
create mode 100644 dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/FoundryHostedSession/.env.example
create mode 100644 dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/FoundryHostedSession/FoundryHostedSession.csproj
create mode 100644 dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/FoundryHostedSession/Program.cs
create mode 100644 dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/FoundryHostedSession/README.md
create mode 100644 dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/UserIsolationAgent/.env.example
create mode 100644 dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/UserIsolationAgent/Program.cs
create mode 100644 dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/UserIsolationAgent/README.md
create mode 100644 dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/UserIsolationAgent/UserIsolationAgent.csproj
diff --git a/dotnet/agent-framework-dotnet.slnx b/dotnet/agent-framework-dotnet.slnx
index 6f5fa9d46a6..638d6096225 100644
--- a/dotnet/agent-framework-dotnet.slnx
+++ b/dotnet/agent-framework-dotnet.slnx
@@ -388,9 +388,11 @@
+
+
diff --git a/dotnet/samples/02-agents/AgentProviders/foundry/Agent_Step25_FoundryToolboxMcp/Program.cs b/dotnet/samples/02-agents/AgentProviders/foundry/Agent_Step25_FoundryToolboxMcp/Program.cs
index 8dd3f55a8a1..dce06cf7cb9 100644
--- a/dotnet/samples/02-agents/AgentProviders/foundry/Agent_Step25_FoundryToolboxMcp/Program.cs
+++ b/dotnet/samples/02-agents/AgentProviders/foundry/Agent_Step25_FoundryToolboxMcp/Program.cs
@@ -6,7 +6,6 @@
// discovers the toolbox's tools at runtime and invokes them locally.
using System.ClientModel;
-using System.ClientModel.Primitives;
using System.Net.Http.Headers;
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
@@ -48,10 +47,6 @@
Endpoint = new Uri(toolboxEndpoint),
Name = "foundry_toolbox",
TransportMode = HttpTransportMode.StreamableHttp,
- AdditionalHeaders = new Dictionary
- {
- ["Foundry-Features"] = "Toolboxes=V1Preview",
- },
},
httpClient));
@@ -81,10 +76,7 @@ static async Task CreateSampleToolboxAsync(string name, string endpoint,
// script, not the application itself. This helper exists so the sample can
// be run end-to-end without first setting a toolbox up by hand.
- // The Foundry-Features header is currently required for toolbox CRUD operations.
- var options = new AgentAdministrationClientOptions();
- options.AddPolicy(new FoundryFeaturesPolicy("Toolboxes=V1Preview"), PipelinePosition.PerCall);
- var adminClient = new AgentAdministrationClient(new Uri(endpoint), credential, options);
+ var adminClient = new AgentAdministrationClient(new Uri(endpoint), credential);
var toolboxClient = adminClient.GetAgentToolboxes();
// Delete existing toolbox if present (ignore 404).
@@ -114,26 +106,6 @@ static async Task CreateSampleToolboxAsync(string name, string endpoint,
return $"{endpoint}/toolboxes/{created.Name}/mcp?api-version=v{created.Version}";
}
-// ---------------------------------------------------------------------------
-// Pipeline policy: adds the Foundry-Features header for toolbox CRUD calls
-// ---------------------------------------------------------------------------
-internal sealed class FoundryFeaturesPolicy(string feature) : PipelinePolicy
-{
- private const string FeatureHeader = "Foundry-Features";
-
- public override void Process(PipelineMessage message, IReadOnlyList pipeline, int currentIndex)
- {
- message.Request.Headers.Add(FeatureHeader, feature);
- ProcessNext(message, pipeline, currentIndex);
- }
-
- public override ValueTask ProcessAsync(PipelineMessage message, IReadOnlyList pipeline, int currentIndex)
- {
- message.Request.Headers.Add(FeatureHeader, feature);
- return ProcessNextAsync(message, pipeline, currentIndex);
- }
-}
-
// ---------------------------------------------------------------------------
// DelegatingHandler: attaches a fresh Azure AI bearer token to every request
// ---------------------------------------------------------------------------
diff --git a/dotnet/samples/02-agents/AgentProviders/foundry/Agent_Step26_FoundryToolboxMcpSkills/Program.cs b/dotnet/samples/02-agents/AgentProviders/foundry/Agent_Step26_FoundryToolboxMcpSkills/Program.cs
index d8fff025c56..8205e0565a8 100644
--- a/dotnet/samples/02-agents/AgentProviders/foundry/Agent_Step26_FoundryToolboxMcpSkills/Program.cs
+++ b/dotnet/samples/02-agents/AgentProviders/foundry/Agent_Step26_FoundryToolboxMcpSkills/Program.cs
@@ -38,10 +38,6 @@
Endpoint = new Uri(toolboxMcpServerUrl),
Name = "foundry_toolbox",
TransportMode = HttpTransportMode.StreamableHttp,
- AdditionalHeaders = new Dictionary
- {
- ["Foundry-Features"] = "Toolboxes=V1Preview",
- },
},
httpClient));
diff --git a/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/FoundrySkills.cs b/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/FoundrySkills.cs
index aea7da4088f..f5ae6aa183d 100644
--- a/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/FoundrySkills.cs
+++ b/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/FoundrySkills.cs
@@ -38,10 +38,6 @@ internal static class FoundrySkills
Endpoint = new Uri(toolboxMcpServerUrl),
Name = "foundry_toolbox",
TransportMode = HttpTransportMode.StreamableHttp,
- AdditionalHeaders = new Dictionary
- {
- ["Foundry-Features"] = "Toolboxes=V1Preview",
- },
},
httpClient));
diff --git a/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step04_ProductionReady/ClawAgent/FoundrySkills.cs b/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step04_ProductionReady/ClawAgent/FoundrySkills.cs
index b1748c10a39..07e7366fe01 100644
--- a/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step04_ProductionReady/ClawAgent/FoundrySkills.cs
+++ b/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step04_ProductionReady/ClawAgent/FoundrySkills.cs
@@ -34,10 +34,6 @@ internal static class FoundrySkills
Endpoint = new Uri(toolboxMcpServerUrl),
Name = "foundry_toolbox",
TransportMode = HttpTransportMode.StreamableHttp,
- AdditionalHeaders = new Dictionary
- {
- ["Foundry-Features"] = "Toolboxes=V1Preview",
- },
},
httpClient),
cancellationToken: cancellationToken).ConfigureAwait(false);
diff --git a/dotnet/samples/03-workflows/Declarative/InvokeFoundryToolboxMcp/InvokeFoundryToolboxMcp.yaml b/dotnet/samples/03-workflows/Declarative/InvokeFoundryToolboxMcp/InvokeFoundryToolboxMcp.yaml
index b5f6f39316e..8d8b8b9dc2a 100644
--- a/dotnet/samples/03-workflows/Declarative/InvokeFoundryToolboxMcp/InvokeFoundryToolboxMcp.yaml
+++ b/dotnet/samples/03-workflows/Declarative/InvokeFoundryToolboxMcp/InvokeFoundryToolboxMcp.yaml
@@ -36,8 +36,6 @@ trigger:
serverLabel: foundry_toolbox
toolName: tools/list
conversationId: =System.ConversationId
- headers:
- Foundry-Features: Toolboxes=V1Preview
output:
autoSend: true
result: Local.ToolboxTools
@@ -49,8 +47,6 @@ trigger:
serverLabel: foundry_toolbox
toolName: =Env.FOUNDRY_TOOLBOX_DOCS_SERVER_LABEL & "___microsoft_docs_search"
conversationId: =System.ConversationId
- headers:
- Foundry-Features: Toolboxes=V1Preview
arguments:
query: =Local.SearchQuery
output:
@@ -66,8 +62,6 @@ trigger:
serverLabel: foundry_toolbox
toolName: =Env.FOUNDRY_TOOLBOX_WEB_SEARCH_TOOL_NAME
conversationId: =System.ConversationId
- headers:
- Foundry-Features: Toolboxes=V1Preview
arguments:
search_query: =Local.SearchQuery
output:
diff --git a/dotnet/samples/03-workflows/Declarative/InvokeFoundryToolboxMcp/Program.cs b/dotnet/samples/03-workflows/Declarative/InvokeFoundryToolboxMcp/Program.cs
index 812d13cf7a2..7c3ecbc7e96 100644
--- a/dotnet/samples/03-workflows/Declarative/InvokeFoundryToolboxMcp/Program.cs
+++ b/dotnet/samples/03-workflows/Declarative/InvokeFoundryToolboxMcp/Program.cs
@@ -5,7 +5,6 @@
// through the reserved tools/list operation, then calls microsoft_docs_search from the workflow.
using System.ClientModel;
-using System.ClientModel.Primitives;
using System.Collections.Concurrent;
using System.Net.Http.Headers;
using Azure.AI.Projects;
@@ -19,8 +18,6 @@
using Shared.Workflows;
#pragma warning disable OPENAI001 // Experimental API
-#pragma warning disable AAIP001 // AgentToolboxes is experimental
-
namespace Demo.Workflows.Declarative.InvokeFoundryToolboxMcp;
///
@@ -148,9 +145,7 @@ Be concise.
private static async Task CreateSampleToolboxAsync(string name, string serverLabel, Uri foundryEndpoint, TokenCredential credential)
{
- AgentAdministrationClientOptions options = new();
- options.AddPolicy(new FoundryFeaturesPolicy("Toolboxes=V1Preview"), PipelinePosition.PerCall);
- AgentAdministrationClient adminClient = new(foundryEndpoint, credential, options);
+ AgentAdministrationClient adminClient = new(foundryEndpoint, credential);
AgentToolboxes toolboxClient = adminClient.GetAgentToolboxes();
try
@@ -199,21 +194,4 @@ protected override async Task SendAsync(
return await base.SendAsync(request, cancellationToken);
}
}
-
- private sealed class FoundryFeaturesPolicy(string feature) : PipelinePolicy
- {
- private const string FeatureHeader = "Foundry-Features";
-
- public override void Process(PipelineMessage message, IReadOnlyList pipeline, int currentIndex)
- {
- message.Request.Headers.Add(FeatureHeader, feature);
- ProcessNext(message, pipeline, currentIndex);
- }
-
- public override ValueTask ProcessAsync(PipelineMessage message, IReadOnlyList pipeline, int currentIndex)
- {
- message.Request.Headers.Add(FeatureHeader, feature);
- return ProcessNextAsync(message, pipeline, currentIndex);
- }
- }
}
diff --git a/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-AgentSkills/Program.cs b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-AgentSkills/Program.cs
index 30ac2904a5f..9af0e7b81f0 100644
--- a/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-AgentSkills/Program.cs
+++ b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-AgentSkills/Program.cs
@@ -20,7 +20,6 @@
#pragma warning disable AAIP001 // ProjectAgentSkills is experimental
using System.ClientModel;
-using System.ClientModel.Primitives;
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.Identity;
@@ -65,10 +64,7 @@
var credential = new DefaultAzureCredential();
AIProjectClient projectClient = new(new Uri(endpoint), credential);
-var adminOptions = new AgentAdministrationClientOptions();
-adminOptions.AddPolicy(new FoundryFeaturesPolicy("Skills=V1Preview"), PipelinePosition.PerCall);
-var adminClient = new AgentAdministrationClient(new Uri(endpoint), credential, adminOptions);
-ProjectAgentSkills skillsClient = adminClient.GetAgentSkills();
+ProjectAgentSkills skillsClient = projectClient.AgentAdministrationClient.GetAgentSkills();
// ── Provision skills (sample convenience only — NOT a production pattern) ─────
// In production, skills are provisioned externally (e.g., via CI/CD or a management script).
@@ -153,7 +149,6 @@ static async Task DownloadSkillsAsync(ProjectAgentSkills skillsClient, string[]
$"Downloaded skill '{name}' did not contain a SKILL.md at the root.");
}
}
-
}
// Ensures each requested skill is provisioned in Foundry. For each skill name, checks whether
@@ -183,24 +178,3 @@ static async Task EnsureSkillsProvisionedAsync(ProjectAgentSkills skillsClient,
}
}
}
-
-// Skills is a preview data-plane surface and requires an explicit feature opt-in on every call.
-internal sealed class FoundryFeaturesPolicy(string feature) : PipelinePolicy
-{
- private const string FeatureHeader = "Foundry-Features";
-
- public override void Process(PipelineMessage message, IReadOnlyList pipeline, int currentIndex)
- {
- message.Request.Headers.Add(FeatureHeader, feature);
- ProcessNext(message, pipeline, currentIndex);
- }
-
- public override ValueTask ProcessAsync(
- PipelineMessage message,
- IReadOnlyList pipeline,
- int currentIndex)
- {
- message.Request.Headers.Add(FeatureHeader, feature);
- return ProcessNextAsync(message, pipeline, currentIndex);
- }
-}
diff --git a/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-AgentSkills/README.md b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-AgentSkills/README.md
index a658e4f5a8f..40536036de6 100644
--- a/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-AgentSkills/README.md
+++ b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-AgentSkills/README.md
@@ -165,9 +165,9 @@ Do not substitute `Azure AI Developer`; Microsoft documents that role as insuffi
hosted agents. Recreate the role assignment when the agent is deleted and created again, because
the new agent receives a new identity.
-The Skills API is a preview surface. `Program.cs` adds the required
-`Foundry-Features: Skills=V1Preview` header and downloads skills into the writable temporary
-directory. The source-deploy application directory (`/app`) is read-only.
+The Skills API is a preview surface. `Azure.AI.Projects` applies its required feature opt-in
+internally. `Program.cs` downloads skills into the writable temporary directory. The source-deploy
+application directory (`/app`) is read-only.
### Step 4: clean up
diff --git a/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-ToolboxMcpSkills/Program.cs b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-ToolboxMcpSkills/Program.cs
index 00dc5330122..81b7fc54638 100644
--- a/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-ToolboxMcpSkills/Program.cs
+++ b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-ToolboxMcpSkills/Program.cs
@@ -63,10 +63,6 @@
Endpoint = new Uri(toolboxMcpServerUrl),
Name = toolboxName,
TransportMode = HttpTransportMode.StreamableHttp,
- AdditionalHeaders = new Dictionary
- {
- ["Foundry-Features"] = "Toolboxes=V1Preview",
- },
},
httpClient));
diff --git a/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/FoundryHostedSession/.env.example b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/FoundryHostedSession/.env.example
new file mode 100644
index 00000000000..45ba6ac976f
--- /dev/null
+++ b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/FoundryHostedSession/.env.example
@@ -0,0 +1,2 @@
+FOUNDRY_PROJECT_ENDPOINT=https://.services.ai.azure.com/api/projects/
+AZURE_AI_AGENT_NAME=
diff --git a/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/FoundryHostedSession/FoundryHostedSession.csproj b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/FoundryHostedSession/FoundryHostedSession.csproj
new file mode 100644
index 00000000000..0c68e461ed4
--- /dev/null
+++ b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/FoundryHostedSession/FoundryHostedSession.csproj
@@ -0,0 +1,24 @@
+
+
+
+ Exe
+ net10.0
+ enable
+ enable
+ false
+ FoundryHostedSessionClient
+ foundry-hosted-session-client
+ $(NoWarn);MEAI001;NU1605;OPENAI001
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/FoundryHostedSession/Program.cs b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/FoundryHostedSession/Program.cs
new file mode 100644
index 00000000000..141ad64f9d4
--- /dev/null
+++ b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/FoundryHostedSession/Program.cs
@@ -0,0 +1,119 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+#pragma warning disable MEAI001 // Foundry hosted session helpers are experimental.
+
+using Azure.AI.Projects;
+using Azure.AI.Projects.Agents;
+using Azure.Identity;
+using DotNetEnv;
+using Microsoft.Agents.AI;
+using Microsoft.Agents.AI.Foundry;
+
+Env.TraversePath().Load();
+
+Uri projectEndpoint = new(Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT")
+ ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set."));
+string agentName = Environment.GetEnvironmentVariable("AZURE_AI_AGENT_NAME")
+ ?? throw new InvalidOperationException("AZURE_AI_AGENT_NAME is not set.");
+Uri agentEndpoint = new($"{projectEndpoint.ToString().TrimEnd('/')}/agents/{agentName}/endpoint/protocols/openai");
+
+var credential = new AzureCliCredential();
+var projectClient = new AIProjectClient(projectEndpoint, credential);
+FoundryAgent agent = projectClient.AsAIAgent(agentEndpoint);
+AgentAdministrationClient adminClient = projectClient.AgentAdministrationClient;
+
+Console.WriteLine("Creating a Foundry hosted session...");
+ProjectsAgentRecord agentRecord = await adminClient.GetAgentAsync(agentName);
+string agentVersion = agentRecord.GetLatestVersion().Version;
+ProjectAgentSession hostedSession = await adminClient.CreateSessionAsync(
+ agentName,
+ new VersionRefIndicator(agentVersion));
+string hostedSessionId = hostedSession.AgentSessionId;
+
+try
+{
+ await WaitForSessionActiveAsync(adminClient, agentName, hostedSessionId);
+
+ ChatClientAgentSession session = await agent.CreateFoundryHostedAgentSessionAsync(
+ hostedSessionId: hostedSessionId);
+
+ Console.ForegroundColor = ConsoleColor.Cyan;
+ Console.WriteLine($"""
+ ============================================================
+ Foundry Hosted Session Sample
+ Agent: {agentName}
+ Hosted session: {session.FoundryHostedAgentSessionId}
+
+ Every turn uses the same Foundry sandbox. Conversation history
+ remains a separate concern and is carried by this AgentSession.
+ Type a message or 'quit' to exit.
+ ============================================================
+ """);
+ Console.ResetColor();
+
+ while (true)
+ {
+ Console.ForegroundColor = ConsoleColor.Green;
+ Console.Write("You> ");
+ Console.ResetColor();
+
+ string? input = Console.ReadLine();
+ if (string.IsNullOrWhiteSpace(input))
+ {
+ continue;
+ }
+
+ if (input.Equals("quit", StringComparison.OrdinalIgnoreCase))
+ {
+ break;
+ }
+
+ Console.ForegroundColor = ConsoleColor.Yellow;
+ Console.Write("Agent> ");
+ Console.ResetColor();
+
+ await foreach (AgentResponseUpdate update in agent.RunStreamingAsync(input, session))
+ {
+ Console.Write(update);
+ }
+
+ Console.WriteLine();
+ Console.WriteLine();
+ }
+}
+finally
+{
+ Console.WriteLine($"Deleting hosted session {hostedSessionId}...");
+ await adminClient.DeleteSessionAsync(agentName, hostedSessionId);
+}
+
+static async Task WaitForSessionActiveAsync(
+ AgentAdministrationClient adminClient,
+ string agentName,
+ string sessionId,
+ CancellationToken cancellationToken = default)
+{
+ TimeSpan timeout = TimeSpan.FromMinutes(3);
+ DateTimeOffset deadline = DateTimeOffset.UtcNow + timeout;
+ ProjectAgentSession session = await adminClient.GetSessionAsync(agentName, sessionId, cancellationToken);
+
+ while (session.Status != AgentSessionStatus.Active)
+ {
+ if (session.Status == AgentSessionStatus.Failed
+ || session.Status == AgentSessionStatus.Deleted
+ || session.Status == AgentSessionStatus.Expired)
+ {
+ throw new InvalidOperationException(
+ $"Hosted session '{sessionId}' entered terminal status '{session.Status}'.");
+ }
+
+ if (DateTimeOffset.UtcNow >= deadline)
+ {
+ throw new TimeoutException(
+ $"Hosted session '{sessionId}' did not become active within {timeout.TotalSeconds:F0} seconds. Last status: {session.Status}.");
+ }
+
+ await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
+ session = await adminClient.GetSessionAsync(agentName, sessionId, cancellationToken);
+ }
+}
diff --git a/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/FoundryHostedSession/README.md b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/FoundryHostedSession/README.md
new file mode 100644
index 00000000000..86a9a417fe6
--- /dev/null
+++ b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/FoundryHostedSession/README.md
@@ -0,0 +1,86 @@
+# Foundry Hosted Session
+
+This client creates a Foundry hosted session explicitly, attaches its identifier to an Agent Framework
+`AgentSession`, and sends every turn to the same hosted sandbox. It deletes the hosted session when the
+client exits.
+
+Use this pattern when the application must know the hosted session identifier before the first agent
+invocation. Common reasons include uploading files before the first turn and assigning several logical
+users to a caller managed session pool.
+
+## Sessions and conversations
+
+A hosted session and a conversation solve different problems.
+
+| Value | Purpose |
+| --- | --- |
+| Foundry `agent_session_id` | Selects the hosted sandbox, its compute, persisted `$HOME`, and session files. |
+| Agent Framework `AgentSession` | Keeps the hosted session identifier and conversation continuation state together for the client. |
+| Conversation or previous response identifier | Preserves model conversation history. Reusing only `agent_session_id` does not restore message history. |
+
+The sample creates the platform session with `AgentAdministrationClient.CreateSessionAsync`. It then
+calls `CreateFoundryHostedAgentSessionAsync(hostedSessionId: ...)`. Agent Framework stores the identifier
+on the returned `AgentSession` and sends `agent_session_id` on every subsequent Responses request.
+
+## Session lifetime
+
+The platform owns the hosted session lifecycle. When the idle timeout is reached, Foundry can remove
+the active compute while preserving the session filesystem. Referencing the session again causes Foundry
+to provision compute and restore the saved state. A hosted session identifies a logical sandbox. It does
+not reserve one physical virtual machine for its complete lifetime.
+
+This sample deletes the session in a `finally` block. A production service can retain session identifiers
+when it needs a longer lived pool, but it must eventually delete unused sessions or let the configured
+expiration reclaim them.
+
+## Session pools
+
+Applications that serve many users usually should not create one hosted session for every registered user.
+Instead, a middle tier can maintain a bounded pool:
+
+1. Create a small number of hosted sessions.
+2. Assign each user to one session.
+3. Keep that assignment stable while the user is active.
+4. Send the selected `agent_session_id` on every call.
+5. Grow the pool according to observed concurrent work rather than total user count.
+
+Sharing a hosted session does not automatically partition files or application data written by the
+container. When users share a sandbox, container owned data must be stored under a per user partition.
+The sibling [`UserIsolationAgent`](../UserIsolationAgent/) sample shows how to identify each user while
+sharing one hosted session.
+
+## Prerequisites
+
+* [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0)
+* A hosted agent deployed to Foundry
+* Azure CLI authenticated with `az login`
+* Permission to invoke the agent and create, read, and delete its hosted sessions
+
+This sample targets a deployed agent because the Foundry session administration API is not available
+from a local `dotnet run` agent server.
+
+## Configuration
+
+Copy `.env.example` to `.env` and set:
+
+```env
+FOUNDRY_PROJECT_ENDPOINT=https://.services.ai.azure.com/api/projects/
+AZURE_AI_AGENT_NAME=
+```
+
+## Run
+
+```powershell
+cd dotnet\samples\04-hosting\FoundryHostedAgents\responses\Using-Samples\FoundryHostedSession
+dotnet run
+```
+
+The startup output prints the explicit hosted session identifier. All REPL turns reuse that identifier.
+Entering `quit` or encountering an exception causes the `finally` block to request session deletion.
+An abrupt process termination can prevent cleanup, so production systems should also reclaim abandoned
+sessions outside the request process.
+
+## Related documentation
+
+* [Manage hosted agent sessions](https://learn.microsoft.com/azure/foundry/agents/how-to/manage-hosted-sessions)
+* [Multiplex multiple users in one hosted agent session](https://learn.microsoft.com/azure/foundry/agents/how-to/multiplex-session-users)
diff --git a/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/README.md b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/README.md
index 78d518670bb..7de3f5e4639 100644
--- a/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/README.md
+++ b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/README.md
@@ -47,6 +47,8 @@ never hits the TLS check.
| [`SimpleAgent/`](./SimpleAgent/) | Any hosted agent | Generic, agent-agnostic REPL. Point it at any `Hosted-*` server via `AZURE_AI_AGENT_NAME`. Used by `Hosted-Toolbox`, `Hosted-Toolbox-AuthPaths`, and `Hosted-McpTools`. |
| [`Hosted-Toolbox-AuthPaths-Client/`](./Hosted-Toolbox-AuthPaths-Client/) | Hosted toolbox agents | Handles OAuth consent, function-tool approvals, and native MCP approvals. Use it with `Hosted-Toolbox-AuthPaths` or `Hosted-ToolboxMcpSkills`. |
| [`SessionFilesClient/`](./SessionFilesClient/) | [`Hosted-Files`](../Hosted-Files/) | Same shape as `SimpleAgent`, framed around the bundled-files demo. |
+| [`FoundryHostedSession/`](./FoundryHostedSession/) | Any deployed hosted agent | Creates a hosted session explicitly, pins an `AgentSession` to it, explains session pools, and deletes the session on exit. |
+| [`UserIsolationAgent/`](./UserIsolationAgent/) | Any deployed hosted agent | Shares one hosted session across several application users while keeping an independent conversation and delegated identity for each user. |
For a self-contained demonstration that covers both crash and shutdown recovery, see
[`Using-E2E-Resilience`](../Using-E2E-Resilience/).
diff --git a/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/UserIsolationAgent/.env.example b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/UserIsolationAgent/.env.example
new file mode 100644
index 00000000000..45ba6ac976f
--- /dev/null
+++ b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/UserIsolationAgent/.env.example
@@ -0,0 +1,2 @@
+FOUNDRY_PROJECT_ENDPOINT=https://.services.ai.azure.com/api/projects/
+AZURE_AI_AGENT_NAME=
diff --git a/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/UserIsolationAgent/Program.cs b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/UserIsolationAgent/Program.cs
new file mode 100644
index 00000000000..bccadd60cd5
--- /dev/null
+++ b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/UserIsolationAgent/Program.cs
@@ -0,0 +1,141 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+#pragma warning disable MEAI001 // Foundry hosted session and user identity helpers are experimental.
+
+using Azure.AI.Projects;
+using Azure.AI.Projects.Agents;
+using Azure.Identity;
+using DotNetEnv;
+using Microsoft.Agents.AI;
+using Microsoft.Agents.AI.Foundry;
+using Microsoft.Extensions.AI;
+
+Env.TraversePath().Load();
+
+Uri projectEndpoint = new(Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT")
+ ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set."));
+string agentName = Environment.GetEnvironmentVariable("AZURE_AI_AGENT_NAME")
+ ?? throw new InvalidOperationException("AZURE_AI_AGENT_NAME is not set.");
+Uri agentEndpoint = new($"{projectEndpoint.ToString().TrimEnd('/')}/agents/{agentName}/endpoint/protocols/openai");
+
+var credential = new AzureCliCredential();
+var projectClient = new AIProjectClient(projectEndpoint, credential);
+FoundryAgent agent = projectClient.AsAIAgent(agentEndpoint);
+AgentAdministrationClient adminClient = projectClient.AgentAdministrationClient;
+
+Console.WriteLine("Creating one shared Foundry hosted session...");
+ProjectsAgentRecord agentRecord = await adminClient.GetAgentAsync(agentName);
+string agentVersion = agentRecord.GetLatestVersion().Version;
+ProjectAgentSession hostedSession = await adminClient.CreateSessionAsync(
+ agentName,
+ new VersionRefIndicator(agentVersion));
+string hostedSessionId = hostedSession.AgentSessionId;
+
+var userSessions = new Dictionary(StringComparer.Ordinal);
+
+try
+{
+ await WaitForSessionActiveAsync(adminClient, agentName, hostedSessionId);
+
+ Console.ForegroundColor = ConsoleColor.Cyan;
+ Console.WriteLine($"""
+ ============================================================
+ User Isolation Agent Sample
+ Agent: {agentName}
+ Shared hosted session: {hostedSessionId}
+
+ Enter a stable application user id for each message.
+ Each user gets an independent AgentSession and conversation,
+ while every user shares the same Foundry hosted sandbox.
+ Enter 'quit' as the user id to exit.
+ ============================================================
+ """);
+ Console.ResetColor();
+
+ while (true)
+ {
+ Console.ForegroundColor = ConsoleColor.Green;
+ Console.Write("User id> ");
+ Console.ResetColor();
+
+ string? userId = Console.ReadLine()?.Trim();
+ if (string.IsNullOrWhiteSpace(userId))
+ {
+ continue;
+ }
+
+ if (userId.Equals("quit", StringComparison.OrdinalIgnoreCase))
+ {
+ break;
+ }
+
+ Console.Write("Message> ");
+ string? input = Console.ReadLine();
+ if (string.IsNullOrWhiteSpace(input))
+ {
+ continue;
+ }
+
+ if (!userSessions.TryGetValue(userId, out ChatClientAgentSession? userSession))
+ {
+ userSession = await agent.CreateFoundryHostedAgentSessionAsync(
+ hostedSessionId: hostedSessionId);
+ userSessions.Add(userId, userSession);
+ Console.WriteLine($"Created an independent conversation for '{userId}'.");
+ }
+
+ var runOptions = new ChatClientAgentRunOptions(
+ new ChatOptions().WithFoundryHostedAgentUserIdentity(userId));
+
+ Console.ForegroundColor = ConsoleColor.Yellow;
+ Console.Write($"Agent for {userId}> ");
+ Console.ResetColor();
+
+ await foreach (AgentResponseUpdate update in agent.RunStreamingAsync(
+ input,
+ userSession,
+ runOptions))
+ {
+ Console.Write(update);
+ }
+
+ Console.WriteLine();
+ Console.WriteLine();
+ }
+}
+finally
+{
+ Console.WriteLine($"Deleting shared hosted session {hostedSessionId}...");
+ await adminClient.DeleteSessionAsync(agentName, hostedSessionId);
+}
+
+static async Task WaitForSessionActiveAsync(
+ AgentAdministrationClient adminClient,
+ string agentName,
+ string sessionId,
+ CancellationToken cancellationToken = default)
+{
+ TimeSpan timeout = TimeSpan.FromMinutes(3);
+ DateTimeOffset deadline = DateTimeOffset.UtcNow + timeout;
+ ProjectAgentSession session = await adminClient.GetSessionAsync(agentName, sessionId, cancellationToken);
+
+ while (session.Status != AgentSessionStatus.Active)
+ {
+ if (session.Status == AgentSessionStatus.Failed
+ || session.Status == AgentSessionStatus.Deleted
+ || session.Status == AgentSessionStatus.Expired)
+ {
+ throw new InvalidOperationException(
+ $"Hosted session '{sessionId}' entered terminal status '{session.Status}'.");
+ }
+
+ if (DateTimeOffset.UtcNow >= deadline)
+ {
+ throw new TimeoutException(
+ $"Hosted session '{sessionId}' did not become active within {timeout.TotalSeconds:F0} seconds. Last status: {session.Status}.");
+ }
+
+ await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
+ session = await adminClient.GetSessionAsync(agentName, sessionId, cancellationToken);
+ }
+}
diff --git a/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/UserIsolationAgent/README.md b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/UserIsolationAgent/README.md
new file mode 100644
index 00000000000..8788c3ce7db
--- /dev/null
+++ b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/UserIsolationAgent/README.md
@@ -0,0 +1,122 @@
+# User Isolation Agent
+
+This client demonstrates delegated user identity for a middle tier that serves several application
+users through one Foundry hosted session.
+
+The sample creates one shared hosted session. Each user receives a separate Agent Framework
+`AgentSession`, and every invocation sends that user's stable identifier through
+`ChatOptions.WithFoundryHostedAgentUserIdentity`. Agent Framework places the value in the
+`x-ms-user-identity` request header.
+
+## What Foundry isolates
+
+The middle tier authenticates Alice and Bob before calling Foundry. It then sends a stable application
+identifier for the authenticated user:
+
+```text
+Alice AgentSession + shared agent_session_id + x-ms-user-identity: alice
+Bob AgentSession + shared agent_session_id + x-ms-user-identity: bob
+```
+
+Foundry resolves that delegated identity and isolates platform managed conversation history. Bob cannot
+continue Alice's response chain, even though both users share the same hosted sandbox.
+
+The sample deliberately creates one `AgentSession` per user. Reusing one `AgentSession` for different
+users would also reuse its conversation continuation identifier. Foundry rejects that cross user
+continuation rather than exposing the first user's history.
+
+## What the application must isolate
+
+Foundry isolates the conversation history it manages. It does not automatically partition arbitrary
+files, database rows, or cache entries written by the container. If the hosted agent stores its own
+user data, partition that data by both the hosted session identifier and the resolved user identifier:
+
+```text
+(agent_session_id, user_id)
+```
+
+Do not trust a user identifier copied directly from an untrusted client request. The middle tier must
+authenticate the user, authorize the requested action, and choose the stable identifier that it sends
+to Foundry.
+
+## Configure the calling principal
+
+The identity represented by `AzureCliCredential` in this sample is acting as the trusted middle tier.
+In production this is normally a managed identity or service principal. That principal needs both:
+
+1. Permission to invoke the agent endpoint. `Foundry Agent Consumer` is the least privilege built in role.
+2. Permission to send `x-ms-user-identity`. This permission is not included in a built in role and must
+ be granted through a custom role.
+
+Create `custom-impersonation-role.json`:
+
+```json
+{
+ "Name": "Foundry Agent User Identity Impersonation",
+ "IsCustom": true,
+ "Description": "Lets a trusted middle-tier service delegate an end-user identity to a hosted agent.",
+ "Actions": [],
+ "NotActions": [],
+ "DataActions": [
+ "Microsoft.CognitiveServices/accounts/AIServices/agents/endpoints/UserIdentityImpersonation/action"
+ ],
+ "NotDataActions": [],
+ "AssignableScopes": [
+ "/subscriptions//resourceGroups//providers/Microsoft.CognitiveServices/accounts/"
+ ]
+}
+```
+
+Create and assign the role:
+
+```powershell
+az role definition create --role-definition custom-impersonation-role.json
+
+az role assignment create `
+ --assignee `
+ --role "Foundry Agent User Identity Impersonation" `
+ --scope "/subscriptions//resourceGroups//providers/Microsoft.CognitiveServices/accounts/"
+```
+
+The role can be assigned at the Foundry project or specific agent scope when your deployment model
+supports that narrower scope. A caller that sends `x-ms-user-identity` without this data action receives
+HTTP 403.
+
+The delegated identifier is not an access token and this flow is not OAuth on behalf of token exchange.
+The middle tier authenticates the user itself, then Foundry accepts the identifier only because the
+calling principal has the explicit impersonation data action.
+
+## Prerequisites
+
+* [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0)
+* A hosted agent deployed with Responses protocol version 2.0.0
+* Azure CLI authenticated with `az login`
+* Session administration permission for the sample's create and delete operations
+* The invocation and impersonation permissions described above
+
+User isolation is a platform behavior. It is not enforced by a local `dotnet run` agent server, so this
+sample targets a deployed Foundry agent.
+
+## Configuration
+
+Copy `.env.example` to `.env` and set:
+
+```env
+FOUNDRY_PROJECT_ENDPOINT=https://.services.ai.azure.com/api/projects/
+AZURE_AI_AGENT_NAME=
+```
+
+## Run
+
+```powershell
+cd dotnet\samples\04-hosting\FoundryHostedAgents\responses\Using-Samples\UserIsolationAgent
+dotnet run
+```
+
+Enter `alice`, send several messages, then enter `bob`. Returning to `alice` reuses Alice's own
+`AgentSession`. Both users remain attached to the one hosted session printed at startup.
+
+## Related documentation
+
+* [Multiplex multiple users in one hosted agent session](https://learn.microsoft.com/azure/foundry/agents/how-to/multiplex-session-users)
+* [Hosted agent permissions reference](https://learn.microsoft.com/azure/foundry/agents/concepts/hosted-agent-permissions#delegate-the-end-user-identity)
diff --git a/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/UserIsolationAgent/UserIsolationAgent.csproj b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/UserIsolationAgent/UserIsolationAgent.csproj
new file mode 100644
index 00000000000..aa7f03ca1c1
--- /dev/null
+++ b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/UserIsolationAgent/UserIsolationAgent.csproj
@@ -0,0 +1,24 @@
+
+
+
+ Exe
+ net10.0
+ enable
+ enable
+ false
+ UserIsolationAgentClient
+ user-isolation-agent-client
+ $(NoWarn);MEAI001;NU1605;OPENAI001
+
+
+
+
+
+
+
+
+
+
+
+
+
From 5ec86885b23cfa10728d34103ea1063f3e151db8 Mon Sep 17 00:00:00 2001
From: Roger Barreto <19890735+RogerBarreto@users.noreply.github.com>
Date: Thu, 10 Sep 2026 12:54:52 +0100
Subject: [PATCH 2/4] .NET: Handle closed input in hosted clients
---
.../FoundryHostedSession/Program.cs | 8 ++++++++
.../Using-Samples/UserIsolationAgent/Program.cs | 16 +++++++++++++++-
2 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/FoundryHostedSession/Program.cs b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/FoundryHostedSession/Program.cs
index 141ad64f9d4..31291c53878 100644
--- a/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/FoundryHostedSession/Program.cs
+++ b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/FoundryHostedSession/Program.cs
@@ -1,5 +1,8 @@
// Copyright (c) Microsoft. All rights reserved.
+// Creates a Foundry hosted session explicitly, pins an Agent Framework session to it,
+// reuses the hosted sandbox across turns, and deletes the hosted session on exit.
+
#pragma warning disable MEAI001 // Foundry hosted session helpers are experimental.
using Azure.AI.Projects;
@@ -58,6 +61,11 @@ Type a message or 'quit' to exit.
Console.ResetColor();
string? input = Console.ReadLine();
+ if (input is null)
+ {
+ break;
+ }
+
if (string.IsNullOrWhiteSpace(input))
{
continue;
diff --git a/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/UserIsolationAgent/Program.cs b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/UserIsolationAgent/Program.cs
index bccadd60cd5..a528648fb26 100644
--- a/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/UserIsolationAgent/Program.cs
+++ b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/UserIsolationAgent/Program.cs
@@ -1,5 +1,8 @@
// Copyright (c) Microsoft. All rights reserved.
+// Shares one Foundry hosted session across application users while preserving an
+// independent Agent Framework session and delegated identity for each user.
+
#pragma warning disable MEAI001 // Foundry hosted session and user identity helpers are experimental.
using Azure.AI.Projects;
@@ -58,7 +61,13 @@ User Isolation Agent Sample
Console.Write("User id> ");
Console.ResetColor();
- string? userId = Console.ReadLine()?.Trim();
+ string? userId = Console.ReadLine();
+ if (userId is null)
+ {
+ break;
+ }
+
+ userId = userId.Trim();
if (string.IsNullOrWhiteSpace(userId))
{
continue;
@@ -71,6 +80,11 @@ User Isolation Agent Sample
Console.Write("Message> ");
string? input = Console.ReadLine();
+ if (input is null)
+ {
+ break;
+ }
+
if (string.IsNullOrWhiteSpace(input))
{
continue;
From 98e7151223371f5ad27f3fac7af633525f37638a Mon Sep 17 00:00:00 2001
From: Roger Barreto <19890735+RogerBarreto@users.noreply.github.com>
Date: Fri, 11 Sep 2026 11:24:22 +0100
Subject: [PATCH 3/4] .NET: Clarify user isolation sample trust boundary
---
.../responses/Using-Samples/UserIsolationAgent/Program.cs | 3 +++
1 file changed, 3 insertions(+)
diff --git a/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/UserIsolationAgent/Program.cs b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/UserIsolationAgent/Program.cs
index a528648fb26..b26b02f01dd 100644
--- a/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/UserIsolationAgent/Program.cs
+++ b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/UserIsolationAgent/Program.cs
@@ -34,6 +34,9 @@
new VersionRefIndicator(agentVersion));
string hostedSessionId = hostedSession.AgentSessionId;
+// Demonstration only: this console accepts arbitrary user IDs to make isolation visible.
+// Production code must derive the user ID from authenticated request context, authorize the
+// operation, and use a managed session pool instead of trusting caller-provided identity text.
var userSessions = new Dictionary(StringComparer.Ordinal);
try
From 56fc228bbbbf2a3a49faeb044583ae69a529c5bc Mon Sep 17 00:00:00 2001
From: Roger Barreto <19890735+RogerBarreto@users.noreply.github.com>
Date: Fri, 11 Sep 2026 11:42:06 +0100
Subject: [PATCH 4/4] .NET: Keep preview flag on direct Toolbox MCP calls
---
.../foundry/Agent_Step25_FoundryToolboxMcp/Program.cs | 4 ++++
.../foundry/Agent_Step26_FoundryToolboxMcpSkills/Program.cs | 4 ++++
.../Claw_Step03_ScalingCapabilities/FoundrySkills.cs | 4 ++++
.../Claw_Step04_ProductionReady/ClawAgent/FoundrySkills.cs | 4 ++++
.../InvokeFoundryToolboxMcp/InvokeFoundryToolboxMcp.yaml | 6 ++++++
.../responses/Hosted-ToolboxMcpSkills/Program.cs | 4 ++++
6 files changed, 26 insertions(+)
diff --git a/dotnet/samples/02-agents/AgentProviders/foundry/Agent_Step25_FoundryToolboxMcp/Program.cs b/dotnet/samples/02-agents/AgentProviders/foundry/Agent_Step25_FoundryToolboxMcp/Program.cs
index dce06cf7cb9..5a04a8c7048 100644
--- a/dotnet/samples/02-agents/AgentProviders/foundry/Agent_Step25_FoundryToolboxMcp/Program.cs
+++ b/dotnet/samples/02-agents/AgentProviders/foundry/Agent_Step25_FoundryToolboxMcp/Program.cs
@@ -47,6 +47,10 @@
Endpoint = new Uri(toolboxEndpoint),
Name = "foundry_toolbox",
TransportMode = HttpTransportMode.StreamableHttp,
+ AdditionalHeaders = new Dictionary
+ {
+ ["Foundry-Features"] = "Toolboxes=V1Preview",
+ },
},
httpClient));
diff --git a/dotnet/samples/02-agents/AgentProviders/foundry/Agent_Step26_FoundryToolboxMcpSkills/Program.cs b/dotnet/samples/02-agents/AgentProviders/foundry/Agent_Step26_FoundryToolboxMcpSkills/Program.cs
index 8205e0565a8..d8fff025c56 100644
--- a/dotnet/samples/02-agents/AgentProviders/foundry/Agent_Step26_FoundryToolboxMcpSkills/Program.cs
+++ b/dotnet/samples/02-agents/AgentProviders/foundry/Agent_Step26_FoundryToolboxMcpSkills/Program.cs
@@ -38,6 +38,10 @@
Endpoint = new Uri(toolboxMcpServerUrl),
Name = "foundry_toolbox",
TransportMode = HttpTransportMode.StreamableHttp,
+ AdditionalHeaders = new Dictionary
+ {
+ ["Foundry-Features"] = "Toolboxes=V1Preview",
+ },
},
httpClient));
diff --git a/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/FoundrySkills.cs b/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/FoundrySkills.cs
index f5ae6aa183d..aea7da4088f 100644
--- a/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/FoundrySkills.cs
+++ b/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step03_ScalingCapabilities/FoundrySkills.cs
@@ -38,6 +38,10 @@ internal static class FoundrySkills
Endpoint = new Uri(toolboxMcpServerUrl),
Name = "foundry_toolbox",
TransportMode = HttpTransportMode.StreamableHttp,
+ AdditionalHeaders = new Dictionary
+ {
+ ["Foundry-Features"] = "Toolboxes=V1Preview",
+ },
},
httpClient));
diff --git a/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step04_ProductionReady/ClawAgent/FoundrySkills.cs b/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step04_ProductionReady/ClawAgent/FoundrySkills.cs
index 07e7366fe01..b1748c10a39 100644
--- a/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step04_ProductionReady/ClawAgent/FoundrySkills.cs
+++ b/dotnet/samples/02-agents/Harness/BuildYourOwnClaw/Claw_Step04_ProductionReady/ClawAgent/FoundrySkills.cs
@@ -34,6 +34,10 @@ internal static class FoundrySkills
Endpoint = new Uri(toolboxMcpServerUrl),
Name = "foundry_toolbox",
TransportMode = HttpTransportMode.StreamableHttp,
+ AdditionalHeaders = new Dictionary
+ {
+ ["Foundry-Features"] = "Toolboxes=V1Preview",
+ },
},
httpClient),
cancellationToken: cancellationToken).ConfigureAwait(false);
diff --git a/dotnet/samples/03-workflows/Declarative/InvokeFoundryToolboxMcp/InvokeFoundryToolboxMcp.yaml b/dotnet/samples/03-workflows/Declarative/InvokeFoundryToolboxMcp/InvokeFoundryToolboxMcp.yaml
index 8d8b8b9dc2a..b5f6f39316e 100644
--- a/dotnet/samples/03-workflows/Declarative/InvokeFoundryToolboxMcp/InvokeFoundryToolboxMcp.yaml
+++ b/dotnet/samples/03-workflows/Declarative/InvokeFoundryToolboxMcp/InvokeFoundryToolboxMcp.yaml
@@ -36,6 +36,8 @@ trigger:
serverLabel: foundry_toolbox
toolName: tools/list
conversationId: =System.ConversationId
+ headers:
+ Foundry-Features: Toolboxes=V1Preview
output:
autoSend: true
result: Local.ToolboxTools
@@ -47,6 +49,8 @@ trigger:
serverLabel: foundry_toolbox
toolName: =Env.FOUNDRY_TOOLBOX_DOCS_SERVER_LABEL & "___microsoft_docs_search"
conversationId: =System.ConversationId
+ headers:
+ Foundry-Features: Toolboxes=V1Preview
arguments:
query: =Local.SearchQuery
output:
@@ -62,6 +66,8 @@ trigger:
serverLabel: foundry_toolbox
toolName: =Env.FOUNDRY_TOOLBOX_WEB_SEARCH_TOOL_NAME
conversationId: =System.ConversationId
+ headers:
+ Foundry-Features: Toolboxes=V1Preview
arguments:
search_query: =Local.SearchQuery
output:
diff --git a/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-ToolboxMcpSkills/Program.cs b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-ToolboxMcpSkills/Program.cs
index 81b7fc54638..00dc5330122 100644
--- a/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-ToolboxMcpSkills/Program.cs
+++ b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-ToolboxMcpSkills/Program.cs
@@ -63,6 +63,10 @@
Endpoint = new Uri(toolboxMcpServerUrl),
Name = toolboxName,
TransportMode = HttpTransportMode.StreamableHttp,
+ AdditionalHeaders = new Dictionary
+ {
+ ["Foundry-Features"] = "Toolboxes=V1Preview",
+ },
},
httpClient));