mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
904a5b843e
* Python: .NET Samples - Restructure and Improve Samples (Feature Branch) (#4091) * Moved by agent (#4094) * Fix readme links * .NET Samples - Create `04-hosting` learning path step (#4098) * Agent move * Agent reorderd * Remove A2A section from README Removed A2A section from the Getting Started README. * Agent fixed links * Fix broken sample links in durable-agents README (#4101) * Initial plan * Fix broken internal links in documentation Co-authored-by: crickman <66376200+crickman@users.noreply.github.com> * Revert template link changes; keep only durable-agents README fix Co-authored-by: crickman <66376200+crickman@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: crickman <66376200+crickman@users.noreply.github.com> * .NET Samples - Create `03-workflows` learning path step (#4102) * Fix solution project path * Python: Fix broken markdown links to repo resources (outside /docs) (#4105) * Initial plan * Fix broken markdown links to repo resources Co-authored-by: crickman <66376200+crickman@users.noreply.github.com> * Update README to rename .NET Workflows Samples section --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: crickman <66376200+crickman@users.noreply.github.com> * .NET Samples - Create `02-agents` learning path step (#4107) * .NET: Fix broken relative link in GroupChatToolApproval README (#4108) * Initial plan * Fix broken link in GroupChatToolApproval README Co-authored-by: crickman <66376200+crickman@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: crickman <66376200+crickman@users.noreply.github.com> * Update labeler configuration for workflow samples * .NET - Reorder Agents samples to start from Step01 instead of Step04 (#4110) * Fix solution * Resolve new sample paths * Move new AgentSkills and AgentWithMemory_Step04 samples * Fix link * Fix readme path * fix: update stale dotnet/samples/Durable path reference in AGENTS.md Co-authored-by: crickman <66376200+crickman@users.noreply.github.com> * Moved new sample * Update solution * Resolve merge (new sample) * Sync to new sample - FoundryAgents_Step21_BingCustomSearch * Updated README * .NET Samples - Configuration Naming Update (#4149) * .NET: Restore AzureFunctions index parity with ConsoleApps under DurableAgents samples (#4221) * Clean-up `05_host_your_agent` * Config setting consistency * Refine samples * AGENTS.md * Move new samples * Re-order samples * Move new project and fixup solution * Fixup model config * Fix up new UT project --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
142 lines
6.1 KiB
C#
142 lines
6.1 KiB
C#
// Copyright (c) Microsoft. All rights reserved.
|
|
|
|
// This sample demonstrates using the InvokeMcpTool action to call MCP (Model Context Protocol)
|
|
// server tools directly from a declarative workflow. MCP servers expose tools that can be
|
|
// invoked to perform specific tasks, like searching documentation or executing operations.
|
|
|
|
using Azure.AI.Projects;
|
|
using Azure.AI.Projects.OpenAI;
|
|
using Azure.Core;
|
|
using Azure.Identity;
|
|
using Microsoft.Agents.AI.Workflows.Declarative.Mcp;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Shared.Foundry;
|
|
using Shared.Workflows;
|
|
|
|
namespace Demo.Workflows.Declarative.InvokeMcpTool;
|
|
|
|
/// <summary>
|
|
/// Demonstrates a workflow that uses InvokeMcpTool to call MCP server tools
|
|
/// directly from the workflow.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// The InvokeMcpTool action allows workflows to invoke tools on MCP (Model Context Protocol)
|
|
/// servers. This enables:
|
|
/// </para>
|
|
/// <list type="bullet">
|
|
/// <item>Searching external data sources like documentation</item>
|
|
/// <item>Executing operations on remote servers</item>
|
|
/// <item>Integrating with MCP-compatible services</item>
|
|
/// </list>
|
|
/// <para>
|
|
/// This sample uses the Microsoft Learn MCP server to search Azure documentation and the Azure foundry MCP server to get AI model details.
|
|
/// When you run the sample, provide an AI model (e.g. gpt-4.1-mini) as input,
|
|
/// The workflow will use the MCP tools to find relevant information about the model from Microsoft Learn and foundry, then an agent will summarize the results.
|
|
/// </para>
|
|
/// <para>
|
|
/// See the README.md file in the parent folder (../README.md) for detailed
|
|
/// information about the configuration required to run this sample.
|
|
/// </para>
|
|
/// </remarks>
|
|
internal sealed class Program
|
|
{
|
|
public static async Task Main(string[] args)
|
|
{
|
|
// Initialize configuration
|
|
IConfiguration configuration = Application.InitializeConfig();
|
|
Uri foundryEndpoint = new(configuration.GetValue(Application.Settings.FoundryEndpoint));
|
|
|
|
// Ensure sample agent exists in Foundry
|
|
await CreateAgentAsync(foundryEndpoint, configuration);
|
|
|
|
// Get input from command line or console
|
|
string workflowInput = Application.GetInput(args);
|
|
|
|
// Create the MCP tool handler for invoking MCP server tools.
|
|
// The HttpClient callback allows configuring authentication per MCP server.
|
|
// Different MCP servers may require different authentication configurations.
|
|
// For Production scenarios, consider implementing a more robust HttpClient management strategy to reuse HttpClient instances and manage their lifetimes appropriately.
|
|
List<HttpClient> createdHttpClients = [];
|
|
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
|
|
DefaultAzureCredential credential = new();
|
|
DefaultMcpToolHandler mcpToolHandler = new(
|
|
httpClientProvider: async (serverUrl, cancellationToken) =>
|
|
{
|
|
if (serverUrl.StartsWith("https://mcp.ai.azure.com", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
// Acquire token for the Azure MCP server
|
|
AccessToken token = await credential.GetTokenAsync(
|
|
new TokenRequestContext(["https://mcp.ai.azure.com/.default"]),
|
|
cancellationToken);
|
|
|
|
// Create HttpClient with Authorization header
|
|
HttpClient httpClient = new();
|
|
httpClient.DefaultRequestHeaders.Authorization =
|
|
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token.Token);
|
|
createdHttpClients.Add(httpClient);
|
|
return httpClient;
|
|
}
|
|
|
|
if (serverUrl.StartsWith("https://learn.microsoft.com", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
// Microsoft Learn MCP server does not require authentication
|
|
HttpClient httpClient = new();
|
|
createdHttpClients.Add(httpClient);
|
|
return httpClient;
|
|
}
|
|
|
|
// Return null for unknown servers to use the default HttpClient without auth.
|
|
return null;
|
|
});
|
|
|
|
try
|
|
{
|
|
// Create the workflow factory with MCP tool provider
|
|
WorkflowFactory workflowFactory = new("InvokeMcpTool.yaml", foundryEndpoint)
|
|
{
|
|
McpToolHandler = mcpToolHandler
|
|
};
|
|
|
|
// Execute the workflow
|
|
WorkflowRunner runner = new() { UseJsonCheckpoints = true };
|
|
await runner.ExecuteAsync(workflowFactory.CreateWorkflow, workflowInput);
|
|
}
|
|
finally
|
|
{
|
|
// Clean up connections and dispose created HttpClients
|
|
await mcpToolHandler.DisposeAsync();
|
|
|
|
foreach (HttpClient httpClient in createdHttpClients)
|
|
{
|
|
httpClient.Dispose();
|
|
}
|
|
}
|
|
}
|
|
|
|
private static async Task CreateAgentAsync(Uri foundryEndpoint, IConfiguration configuration)
|
|
{
|
|
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
|
|
AIProjectClient aiProjectClient = new(foundryEndpoint, new DefaultAzureCredential());
|
|
|
|
await aiProjectClient.CreateAgentAsync(
|
|
agentName: "McpSearchAgent",
|
|
agentDefinition: DefineSearchAgent(configuration),
|
|
agentDescription: "Provides information based on search results");
|
|
}
|
|
|
|
private static PromptAgentDefinition DefineSearchAgent(IConfiguration configuration)
|
|
{
|
|
return new PromptAgentDefinition(configuration.GetValue(Application.Settings.FoundryModel))
|
|
{
|
|
Instructions =
|
|
"""
|
|
You are a helpful assistant that answers questions based on search results.
|
|
Use the information provided in the conversation history to answer questions.
|
|
If the information is already available in the conversation, use it directly.
|
|
Be concise and helpful in your responses.
|
|
"""
|
|
};
|
|
}
|
|
}
|