diff --git a/dotnet/agent-framework/sample-agent/Agent/MyAgent.cs b/dotnet/agent-framework/sample-agent/Agent/MyAgent.cs index d147c768..eed9f0c6 100644 --- a/dotnet/agent-framework/sample-agent/Agent/MyAgent.cs +++ b/dotnet/agent-framework/sample-agent/Agent/MyAgent.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. using Agent365AgentFrameworkSampleAgent.telemetry; @@ -44,8 +44,10 @@ Otherwise you should use the tools available to you to help answer the user's qu private readonly ILogger? _logger = null; private readonly IMcpToolRegistrationService? _toolService = null; // Setup reusable auto sign-in handlers - private readonly string AgenticIdAuthHanlder = "agentic"; - private readonly string MyAuthHanlder = "me"; + // Setup reusable auto sign-in handler for agentic requests + private readonly string AgenticIdAuthHandler = "agentic"; + // Setup reusable auto sign-in handler for OBO (On-Behalf-Of) authentication + private readonly string MyAuthHandler = "me"; // Temp private static readonly ConcurrentDictionary> _agentToolCache = new(); @@ -68,8 +70,10 @@ public MyAgent(AgentApplicationOptions options, // Handle A365 Notification Messages. // Listen for ANY message to be received. MUST BE AFTER ANY OTHER MESSAGE HANDLERS - OnActivity(ActivityTypes.Message, OnMessageAsync, isAgenticOnly: true, autoSignInHandlers: new[] { AgenticIdAuthHanlder }); - OnActivity(ActivityTypes.Message, OnMessageAsync, isAgenticOnly: false , autoSignInHandlers: new[] { MyAuthHanlder }); + // Agentic requests require the "agentic" handler for user authorization + OnActivity(ActivityTypes.Message, OnMessageAsync, isAgenticOnly: true, autoSignInHandlers: new[] { AgenticIdAuthHandler }); + // Non-agentic requests use OBO authentication via the "me" handler + OnActivity(ActivityTypes.Message, OnMessageAsync, isAgenticOnly: false, autoSignInHandlers: new[] { MyAuthHandler }); } protected async Task WelcomeMessageAsync(ITurnContext turnContext, ITurnState turnState, CancellationToken cancellationToken) @@ -98,12 +102,13 @@ await AgentMetrics.InvokeObservedAgentOperation( /// protected async Task OnMessageAsync(ITurnContext turnContext, ITurnState turnState, CancellationToken cancellationToken) { + // Select the appropriate auth handler based on request type string ObservabilityAuthHandlerName = ""; string ToolAuthHandlerName = ""; if (turnContext.IsAgenticRequest()) - ObservabilityAuthHandlerName = ToolAuthHandlerName = AgenticIdAuthHanlder; + ObservabilityAuthHandlerName = ToolAuthHandlerName = AgenticIdAuthHandler; else - ObservabilityAuthHandlerName = ToolAuthHandlerName = MyAuthHanlder; + ObservabilityAuthHandlerName = ToolAuthHandlerName = MyAuthHandler; await A365OtelWrapper.InvokeObservedAgentOperation( @@ -180,30 +185,39 @@ await A365OtelWrapper.InvokeObservedAgentOperation( if (toolService != null) { - string toolCacheKey = GetToolCacheKey(turnState); - if (_agentToolCache.ContainsKey(toolCacheKey)) + try { - var cachedTools = _agentToolCache[toolCacheKey]; - if (cachedTools != null && cachedTools.Count > 0) + string toolCacheKey = GetToolCacheKey(turnState); + if (_agentToolCache.ContainsKey(toolCacheKey)) { - toolList.AddRange(cachedTools); + var cachedTools = _agentToolCache[toolCacheKey]; + if (cachedTools != null && cachedTools.Count > 0) + { + toolList.AddRange(cachedTools); + } } - } - else - { - // Notify the user we are loading tools - await context.StreamingResponse.QueueInformativeUpdateAsync("Loading tools..."); + else + { + // Notify the user we are loading tools + await context.StreamingResponse.QueueInformativeUpdateAsync("Loading tools..."); - string agentId = Utility.ResolveAgentIdentity(context, await UserAuthorization.GetTurnTokenAsync(context, authHandlerName)); - var a365Tools = await toolService.GetMcpToolsAsync(agentId, UserAuthorization, authHandlerName, context).ConfigureAwait(false); + string agentId = Utility.ResolveAgentIdentity(context, await UserAuthorization.GetTurnTokenAsync(context, authHandlerName)); + var a365Tools = await toolService.GetMcpToolsAsync(agentId, UserAuthorization, authHandlerName, context).ConfigureAwait(false); - // Add the A365 tools to the tool options - if (a365Tools != null && a365Tools.Count > 0) - { - toolList.AddRange(a365Tools); - _agentToolCache.TryAdd(toolCacheKey, [.. a365Tools]); + // Add the A365 tools to the tool options + if (a365Tools != null && a365Tools.Count > 0) + { + toolList.AddRange(a365Tools); + _agentToolCache.TryAdd(toolCacheKey, [.. a365Tools]); + } } } + catch (Exception ex) + { + // Log error and rethrow - MCP tool registration is required + _logger?.LogError(ex, "Failed to register MCP tool servers. Ensure MCP servers are configured correctly or use mock MCP servers for local testing."); + throw; + } } // Create Chat Options with tools: @@ -266,4 +280,4 @@ private string GetToolCacheKey(ITurnState turnState) return userToolCacheKey; } } -} \ No newline at end of file +} diff --git a/dotnet/agent-framework/sample-agent/appsettings.json b/dotnet/agent-framework/sample-agent/appsettings.json index 9e346c48..7afd0ef1 100644 --- a/dotnet/agent-framework/sample-agent/appsettings.json +++ b/dotnet/agent-framework/sample-agent/appsettings.json @@ -13,6 +13,16 @@ "https://graph.microsoft.com/.default" ] } + }, + "me": { + "Type": "MsalUserAuthorization", + "Settings": { + "ClientId": "{{ClientId}}", + "TenantId": "{{TenantId}}", + "Scopes": [ + "https://graph.microsoft.com/.default" + ] + } } } }