From 0b8870c90c965879153302afb8a9d5931763237d Mon Sep 17 00:00:00 2001
From: westey <164392973+westey-m@users.noreply.github.com>
Date: Mon, 20 Oct 2025 09:56:53 +0100
Subject: [PATCH 1/6] Adding sample demonstrating hosted MCP with Responses
---
dotnet/agent-framework-dotnet.slnx | 1 +
.../ModelContextProtocol/README.md | 1 +
.../ResponseAgent_Hosted_MCP/Program.cs | 95 +++++++++++++++++++
.../ResponseAgent_Hosted_MCP/README.md | 17 ++++
.../ResponseAgent_Hosted_MCP.csproj | 20 ++++
5 files changed, 134 insertions(+)
create mode 100644 dotnet/samples/GettingStarted/ModelContextProtocol/ResponseAgent_Hosted_MCP/Program.cs
create mode 100644 dotnet/samples/GettingStarted/ModelContextProtocol/ResponseAgent_Hosted_MCP/README.md
create mode 100644 dotnet/samples/GettingStarted/ModelContextProtocol/ResponseAgent_Hosted_MCP/ResponseAgent_Hosted_MCP.csproj
diff --git a/dotnet/agent-framework-dotnet.slnx b/dotnet/agent-framework-dotnet.slnx
index 9d3b86535c..90ca88c257 100644
--- a/dotnet/agent-framework-dotnet.slnx
+++ b/dotnet/agent-framework-dotnet.slnx
@@ -67,6 +67,7 @@
+
diff --git a/dotnet/samples/GettingStarted/ModelContextProtocol/README.md b/dotnet/samples/GettingStarted/ModelContextProtocol/README.md
index be84bff51f..874afa28b8 100644
--- a/dotnet/samples/GettingStarted/ModelContextProtocol/README.md
+++ b/dotnet/samples/GettingStarted/ModelContextProtocol/README.md
@@ -21,6 +21,7 @@ Before you begin, ensure you have the following prerequisites:
|---|---|
|[Agent with MCP server tools](./Agent_MCP_Server/)|This sample demonstrates how to use MCP server tools with a simple agent|
|[Agent with MCP server tools and authorization](./Agent_MCP_Server_Auth/)|This sample demonstrates how to use MCP Server tools from a protected MCP server with a simple agent|
+|[Responses Agent with Hosted MCP tool](./ResponseAgent_Hosted_MCP/)|This sample demonstrates how to use the Hosted MCP tool with the Responses Service, where the service invokes any MCP tools directly|
## Running the samples from the console
diff --git a/dotnet/samples/GettingStarted/ModelContextProtocol/ResponseAgent_Hosted_MCP/Program.cs b/dotnet/samples/GettingStarted/ModelContextProtocol/ResponseAgent_Hosted_MCP/Program.cs
new file mode 100644
index 0000000000..9a7165fdaa
--- /dev/null
+++ b/dotnet/samples/GettingStarted/ModelContextProtocol/ResponseAgent_Hosted_MCP/Program.cs
@@ -0,0 +1,95 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+// This sample shows how to create and use a simple AI agent with OpenAI Responses as the backend, that uses a Hosted MCP Tool.
+// In this case the OpenAI responses service will invoke any MCP tools as required. MCP tools are not invoked by the Agent Framework.
+// The sample first shows how to use MCP tools with auto approval, and then how to set up a tool that requires approval before it can be invoked and how to approve such a tool.
+
+using Azure.AI.OpenAI;
+using Azure.Identity;
+using Microsoft.Agents.AI;
+using Microsoft.Extensions.AI;
+using OpenAI;
+
+var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
+var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
+
+// **** MCP Tool with Auto Approval ****
+// *************************************
+
+// Create an MCP tool definition that the agent can use.
+// In this case we allow the tool to always be called without approval.
+var mcpTool = new HostedMcpServerTool(
+ serverName: "microsoft_learn",
+ url: "https://learn.microsoft.com/api/mcp")
+{
+ AllowedTools = ["microsoft_docs_search"],
+ ApprovalMode = HostedMcpServerToolApprovalMode.NeverRequire
+};
+
+// Create an agent based on Azure OpenAI Responses as the backend.
+AIAgent agent = new AzureOpenAIClient(
+ new Uri(endpoint),
+ new AzureCliCredential())
+ .GetOpenAIResponseClient(deploymentName)
+ .CreateAIAgent(
+ instructions: "You answer questions by searching the Microsoft Learn content only.",
+ name: "MicrosoftLearnAgent",
+ tools: [mcpTool]);
+
+// You can then invoke the agent like any other AIAgent.
+AgentThread thread = agent.GetNewThread();
+Console.WriteLine(await agent.RunAsync("Please summarize the Azure AI Agent documentation related to MCP Tool calling?", thread));
+
+// **** MCP Tool with Approval Required ****
+// *****************************************
+
+// Create an MCP tool definition that the agent can use.
+// In this case we require approval before the tool can be called.
+var mcpToolWithApproval = new HostedMcpServerTool(
+ serverName: "microsoft_learn",
+ url: "https://learn.microsoft.com/api/mcp")
+{
+ AllowedTools = ["microsoft_docs_search"],
+ ApprovalMode = HostedMcpServerToolApprovalMode.AlwaysRequire
+};
+
+// Create an agent based on Azure OpenAI Responses as the backend.
+AIAgent agentWithRequiredApproval = new AzureOpenAIClient(
+ new Uri(endpoint),
+ new AzureCliCredential())
+ .GetOpenAIResponseClient(deploymentName)
+ .CreateAIAgent(
+ instructions: "You answer questions by searching the Microsoft Learn content only.",
+ name: "MicrosoftLearnAgentWithApproval",
+ tools: [mcpToolWithApproval]);
+
+// You can then invoke the agent like any other AIAgent.
+var threadWithRequiredApproval = agentWithRequiredApproval.GetNewThread();
+var response = await agentWithRequiredApproval.RunAsync("Please summarize the Azure AI Agent documentation related to MCP Tool calling?", threadWithRequiredApproval);
+var userInputRequests = response.UserInputRequests.ToList();
+
+while (userInputRequests.Count > 0)
+{
+ // Ask the user to approve each MCP call request.
+ // For simplicity, we are assuming here that only MCP approval requests are being made.
+ var userInputResponses = userInputRequests
+ .OfType()
+ .Select(approvalRequest =>
+ {
+ Console.WriteLine($"""
+ The agent would like to invoke the following MCP Tool, please reply Y to approve.
+ ServerName: {approvalRequest.ToolCall.ServerName}
+ Name: {approvalRequest.ToolCall.ToolName}
+ Arguments: {string.Join(", ", approvalRequest.ToolCall.Arguments?.Select(x => $"{x.Key}: {x.Value}") ?? [])}
+ """);
+ return new ChatMessage(ChatRole.User, [approvalRequest.CreateResponse(Console.ReadLine()?.Equals("Y", StringComparison.OrdinalIgnoreCase) ?? false)]);
+ })
+ .ToList();
+
+ // Pass the user input responses back to the agent for further processing.
+ response = await agentWithRequiredApproval.RunAsync(userInputResponses, threadWithRequiredApproval);
+
+ userInputRequests = response.UserInputRequests.ToList();
+}
+
+Console.WriteLine($"\nAgent: {response}");
diff --git a/dotnet/samples/GettingStarted/ModelContextProtocol/ResponseAgent_Hosted_MCP/README.md b/dotnet/samples/GettingStarted/ModelContextProtocol/ResponseAgent_Hosted_MCP/README.md
new file mode 100644
index 0000000000..74e41dbbc1
--- /dev/null
+++ b/dotnet/samples/GettingStarted/ModelContextProtocol/ResponseAgent_Hosted_MCP/README.md
@@ -0,0 +1,17 @@
+# Prerequisites
+
+Before you begin, ensure you have the following prerequisites:
+
+- .NET 8.0 SDK or later
+- Azure OpenAI service endpoint and deployment configured
+- Azure CLI installed and authenticated (for Azure credential authentication)
+- User has the `Cognitive Services OpenAI Contributor` role for the Azure OpenAI resource.
+
+**Note**: This demo uses Azure CLI credentials for authentication. Make sure you're logged in with `az login` and have access to the Azure Foundry resource. For more information, see the [Azure CLI documentation](https://learn.microsoft.com/cli/azure/authenticate-azure-cli-interactively).
+
+Set the following environment variables:
+
+```powershell
+$env:AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com/" # Replace with your Azure OpenAI resource endpoint
+$env:AZURE_OPENAI_DEPLOYMENT_NAME="gpt-4.1-mini" # Optional, defaults to gpt-4.1-mini
+```
diff --git a/dotnet/samples/GettingStarted/ModelContextProtocol/ResponseAgent_Hosted_MCP/ResponseAgent_Hosted_MCP.csproj b/dotnet/samples/GettingStarted/ModelContextProtocol/ResponseAgent_Hosted_MCP/ResponseAgent_Hosted_MCP.csproj
new file mode 100644
index 0000000000..0eacdab258
--- /dev/null
+++ b/dotnet/samples/GettingStarted/ModelContextProtocol/ResponseAgent_Hosted_MCP/ResponseAgent_Hosted_MCP.csproj
@@ -0,0 +1,20 @@
+
+
+
+ Exe
+ net9.0
+
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
From b6902a79125c1f4bb6ed0c9236730964bc24f4bd Mon Sep 17 00:00:00 2001
From: westey <164392973+westey-m@users.noreply.github.com>
Date: Mon, 20 Oct 2025 09:57:23 +0100
Subject: [PATCH 2/6] Add mcp readme.md to slnx
---
dotnet/agent-framework-dotnet.slnx | 1 +
1 file changed, 1 insertion(+)
diff --git a/dotnet/agent-framework-dotnet.slnx b/dotnet/agent-framework-dotnet.slnx
index 90ca88c257..b576417472 100644
--- a/dotnet/agent-framework-dotnet.slnx
+++ b/dotnet/agent-framework-dotnet.slnx
@@ -64,6 +64,7 @@
+
From 34ff19ac2219fdd2fb78c97176598c5088a477ff Mon Sep 17 00:00:00 2001
From: westey <164392973+westey-m@users.noreply.github.com>
Date: Mon, 20 Oct 2025 18:12:18 +0100
Subject: [PATCH 3/6] Update FoundryAgent sample to use MCP types from
abstraction and to show how to do approval
---
.../FoundryAgent_Hosted_MCP/Program.cs | 110 +++++++++++++-----
1 file changed, 82 insertions(+), 28 deletions(-)
diff --git a/dotnet/samples/GettingStarted/ModelContextProtocol/FoundryAgent_Hosted_MCP/Program.cs b/dotnet/samples/GettingStarted/ModelContextProtocol/FoundryAgent_Hosted_MCP/Program.cs
index 32017af194..0a2f5acdfa 100644
--- a/dotnet/samples/GettingStarted/ModelContextProtocol/FoundryAgent_Hosted_MCP/Program.cs
+++ b/dotnet/samples/GettingStarted/ModelContextProtocol/FoundryAgent_Hosted_MCP/Program.cs
@@ -1,10 +1,13 @@
// Copyright (c) Microsoft. All rights reserved.
-// This sample shows how to create and use a simple AI agent with Azure Foundry Agents as the backend.
+// This sample shows how to create and use a simple AI agent with Azure Foundry Agents as the backend, that uses a Hosted MCP Tool.
+// In this case the Azure Foundry Agents service will invoke any MCP tools as required. MCP tools are not invoked by the Agent Framework.
+// The sample first shows how to use MCP tools with auto approval, and then how to set up a tool that requires approval before it can be invoked and how to approve such a tool.
using Azure.AI.Agents.Persistent;
using Azure.Identity;
using Microsoft.Agents.AI;
+using Microsoft.Extensions.AI;
var endpoint = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set.");
var model = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_MODEL_ID") ?? "gpt-4.1-mini";
@@ -12,41 +15,92 @@
// Get a client to create/retrieve server side agents with.
var persistentAgentsClient = new PersistentAgentsClient(endpoint, new AzureCliCredential());
+// **** MCP Tool with Auto Approval ****
+// *************************************
+
// Create an MCP tool definition that the agent can use.
-var mcpTool = new MCPToolDefinition(
- serverLabel: "microsoft_learn",
- serverUrl: "https://learn.microsoft.com/api/mcp");
-mcpTool.AllowedTools.Add("microsoft_docs_search");
+// In this case we allow the tool to always be called without approval.
+var mcpTool = new HostedMcpServerTool(
+ serverName: "microsoft_learn",
+ url: "https://learn.microsoft.com/api/mcp")
+{
+ AllowedTools = ["microsoft_docs_search"],
+ ApprovalMode = HostedMcpServerToolApprovalMode.NeverRequire
+};
-// Create a server side persistent agent with the Azure.AI.Agents.Persistent SDK.
-var agentMetadata = await persistentAgentsClient.Administration.CreateAgentAsync(
+// Create a server side persistent agent with the mcp tool, and expose it as an AIAgent.
+AIAgent agent = await persistentAgentsClient.CreateAIAgentAsync(
model: model,
- name: "MicrosoftLearnAgent",
- instructions: "You answer questions by searching the Microsoft Learn content only.",
- tools: [mcpTool]);
-
-// Retrieve an already created server side persistent agent as an AIAgent.
-AIAgent agent = await persistentAgentsClient.GetAIAgentAsync(agentMetadata.Value.Id);
-
-// Create run options to configure the agent invocation.
-var runOptions = new ChatClientAgentRunOptions()
-{
- ChatOptions = new()
+ options: new()
{
- RawRepresentationFactory = (_) => new ThreadAndRunOptions()
+ Name = "MicrosoftLearnAgent",
+ Instructions = "You answer questions by searching the Microsoft Learn content only.",
+ ChatOptions = new()
{
- ToolResources = new MCPToolResource(serverLabel: "microsoft_learn")
- {
- RequireApproval = new MCPApproval("never"),
- }.ToToolResources()
- }
- }
-};
+ Tools = [mcpTool]
+ },
+ });
// You can then invoke the agent like any other AIAgent.
AgentThread thread = agent.GetNewThread();
-var response = await agent.RunAsync("Please summarize the Azure AI Agent documentation related to MCP Tool calling?", thread, runOptions);
-Console.WriteLine(response);
+Console.WriteLine(await agent.RunAsync("Please summarize the Azure AI Agent documentation related to MCP Tool calling?", thread));
// Cleanup for sample purposes.
await persistentAgentsClient.Administration.DeleteAgentAsync(agent.Id);
+
+// **** MCP Tool with Approval Required ****
+// *****************************************
+
+// Create an MCP tool definition that the agent can use.
+// In this case we require approval before the tool can be called.
+var mcpToolWithApproval = new HostedMcpServerTool(
+ serverName: "microsoft_learn",
+ url: "https://learn.microsoft.com/api/mcp")
+{
+ AllowedTools = ["microsoft_docs_search"],
+ ApprovalMode = HostedMcpServerToolApprovalMode.AlwaysRequire
+};
+
+// Create an agent based on Azure OpenAI Responses as the backend.
+AIAgent agentWithRequiredApproval = await persistentAgentsClient.CreateAIAgentAsync(
+ model: model,
+ options: new()
+ {
+ Name = "MicrosoftLearnAgentWithApproval",
+ Instructions = "You answer questions by searching the Microsoft Learn content only.",
+ ChatOptions = new()
+ {
+ Tools = [mcpToolWithApproval]
+ },
+ });
+
+// You can then invoke the agent like any other AIAgent.
+var threadWithRequiredApproval = agentWithRequiredApproval.GetNewThread();
+var response = await agentWithRequiredApproval.RunAsync("Please summarize the Azure AI Agent documentation related to MCP Tool calling?", threadWithRequiredApproval);
+var userInputRequests = response.UserInputRequests.ToList();
+
+while (userInputRequests.Count > 0)
+{
+ // Ask the user to approve each MCP call request.
+ // For simplicity, we are assuming here that only MCP approval requests are being made.
+ var userInputResponses = userInputRequests
+ .OfType()
+ .Select(approvalRequest =>
+ {
+ Console.WriteLine($"""
+ The agent would like to invoke the following MCP Tool, please reply Y to approve.
+ ServerName: {approvalRequest.ToolCall.ServerName}
+ Name: {approvalRequest.ToolCall.ToolName}
+ Arguments: {string.Join(", ", approvalRequest.ToolCall.Arguments?.Select(x => $"{x.Key}: {x.Value}") ?? [])}
+ """);
+ return new ChatMessage(ChatRole.User, [approvalRequest.CreateResponse(Console.ReadLine()?.Equals("Y", StringComparison.OrdinalIgnoreCase) ?? false)]);
+ })
+ .ToList();
+
+ // Pass the user input responses back to the agent for further processing.
+ response = await agentWithRequiredApproval.RunAsync(userInputResponses, threadWithRequiredApproval);
+
+ userInputRequests = response.UserInputRequests.ToList();
+}
+
+Console.WriteLine($"\nAgent: {response}");
From c8f0c324e6aeffae3af156b997e950cc83b1fddf Mon Sep 17 00:00:00 2001
From: westey <164392973+westey-m@users.noreply.github.com>
Date: Tue, 28 Oct 2025 12:35:24 +0000
Subject: [PATCH 4/6] Fix param name after package update.
---
.../ModelContextProtocol/FoundryAgent_Hosted_MCP/Program.cs | 4 ++--
.../ModelContextProtocol/ResponseAgent_Hosted_MCP/Program.cs | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/dotnet/samples/GettingStarted/ModelContextProtocol/FoundryAgent_Hosted_MCP/Program.cs b/dotnet/samples/GettingStarted/ModelContextProtocol/FoundryAgent_Hosted_MCP/Program.cs
index 0a2f5acdfa..f4a6038387 100644
--- a/dotnet/samples/GettingStarted/ModelContextProtocol/FoundryAgent_Hosted_MCP/Program.cs
+++ b/dotnet/samples/GettingStarted/ModelContextProtocol/FoundryAgent_Hosted_MCP/Program.cs
@@ -22,7 +22,7 @@
// In this case we allow the tool to always be called without approval.
var mcpTool = new HostedMcpServerTool(
serverName: "microsoft_learn",
- url: "https://learn.microsoft.com/api/mcp")
+ serverAddress: "https://learn.microsoft.com/api/mcp")
{
AllowedTools = ["microsoft_docs_search"],
ApprovalMode = HostedMcpServerToolApprovalMode.NeverRequire
@@ -55,7 +55,7 @@
// In this case we require approval before the tool can be called.
var mcpToolWithApproval = new HostedMcpServerTool(
serverName: "microsoft_learn",
- url: "https://learn.microsoft.com/api/mcp")
+ serverAddress: "https://learn.microsoft.com/api/mcp")
{
AllowedTools = ["microsoft_docs_search"],
ApprovalMode = HostedMcpServerToolApprovalMode.AlwaysRequire
diff --git a/dotnet/samples/GettingStarted/ModelContextProtocol/ResponseAgent_Hosted_MCP/Program.cs b/dotnet/samples/GettingStarted/ModelContextProtocol/ResponseAgent_Hosted_MCP/Program.cs
index 9a7165fdaa..19793e64df 100644
--- a/dotnet/samples/GettingStarted/ModelContextProtocol/ResponseAgent_Hosted_MCP/Program.cs
+++ b/dotnet/samples/GettingStarted/ModelContextProtocol/ResponseAgent_Hosted_MCP/Program.cs
@@ -20,7 +20,7 @@
// In this case we allow the tool to always be called without approval.
var mcpTool = new HostedMcpServerTool(
serverName: "microsoft_learn",
- url: "https://learn.microsoft.com/api/mcp")
+ serverAddress: "https://learn.microsoft.com/api/mcp")
{
AllowedTools = ["microsoft_docs_search"],
ApprovalMode = HostedMcpServerToolApprovalMode.NeverRequire
@@ -47,7 +47,7 @@
// In this case we require approval before the tool can be called.
var mcpToolWithApproval = new HostedMcpServerTool(
serverName: "microsoft_learn",
- url: "https://learn.microsoft.com/api/mcp")
+ serverAddress: "https://learn.microsoft.com/api/mcp")
{
AllowedTools = ["microsoft_docs_search"],
ApprovalMode = HostedMcpServerToolApprovalMode.AlwaysRequire
From b79470aee9b098dd6cf40b5b102b810599ef3c66 Mon Sep 17 00:00:00 2001
From: westey <164392973+westey-m@users.noreply.github.com>
Date: Mon, 3 Nov 2025 11:19:03 +0000
Subject: [PATCH 5/6] Fix environment variable name for consistency
---
.../ModelContextProtocol/FoundryAgent_Hosted_MCP/Program.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dotnet/samples/GettingStarted/ModelContextProtocol/FoundryAgent_Hosted_MCP/Program.cs b/dotnet/samples/GettingStarted/ModelContextProtocol/FoundryAgent_Hosted_MCP/Program.cs
index f4a6038387..f824f09991 100644
--- a/dotnet/samples/GettingStarted/ModelContextProtocol/FoundryAgent_Hosted_MCP/Program.cs
+++ b/dotnet/samples/GettingStarted/ModelContextProtocol/FoundryAgent_Hosted_MCP/Program.cs
@@ -10,7 +10,7 @@
using Microsoft.Extensions.AI;
var endpoint = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set.");
-var model = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_MODEL_ID") ?? "gpt-4.1-mini";
+var model = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_DEPLOYMENT_NAME") ?? "gpt-4.1-mini";
// Get a client to create/retrieve server side agents with.
var persistentAgentsClient = new PersistentAgentsClient(endpoint, new AzureCliCredential());
From e0bf1dbd90cc1cd53d0b34119b16106e2e8df7e7 Mon Sep 17 00:00:00 2001
From: westey <164392973+westey-m@users.noreply.github.com>
Date: Mon, 3 Nov 2025 11:56:27 +0000
Subject: [PATCH 6/6] Apply suggestion from @Copilot
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
.../ModelContextProtocol/ResponseAgent_Hosted_MCP/README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dotnet/samples/GettingStarted/ModelContextProtocol/ResponseAgent_Hosted_MCP/README.md b/dotnet/samples/GettingStarted/ModelContextProtocol/ResponseAgent_Hosted_MCP/README.md
index 74e41dbbc1..f84bd8f1b4 100644
--- a/dotnet/samples/GettingStarted/ModelContextProtocol/ResponseAgent_Hosted_MCP/README.md
+++ b/dotnet/samples/GettingStarted/ModelContextProtocol/ResponseAgent_Hosted_MCP/README.md
@@ -7,7 +7,7 @@ Before you begin, ensure you have the following prerequisites:
- Azure CLI installed and authenticated (for Azure credential authentication)
- User has the `Cognitive Services OpenAI Contributor` role for the Azure OpenAI resource.
-**Note**: This demo uses Azure CLI credentials for authentication. Make sure you're logged in with `az login` and have access to the Azure Foundry resource. For more information, see the [Azure CLI documentation](https://learn.microsoft.com/cli/azure/authenticate-azure-cli-interactively).
+**Note**: This demo uses Azure CLI credentials for authentication. Make sure you're logged in with `az login` and have access to the Azure OpenAI resource. For more information, see the [Azure CLI documentation](https://learn.microsoft.com/cli/azure/authenticate-azure-cli-interactively).
Set the following environment variables: