diff --git a/core/Azure.Mcp.Core/src/Areas/Server/Commands/Runtime/McpRuntime.cs b/core/Azure.Mcp.Core/src/Areas/Server/Commands/Runtime/McpRuntime.cs index 7000cd146..419af83fd 100644 --- a/core/Azure.Mcp.Core/src/Areas/Server/Commands/Runtime/McpRuntime.cs +++ b/core/Azure.Mcp.Core/src/Areas/Server/Commands/Runtime/McpRuntime.cs @@ -98,6 +98,7 @@ public async ValueTask CallToolHandler(RequestContext CallToolHandler(RequestContext InvokeChildToolAsync( }; } - Activity.Current?.SetTag(TagName.IsServerCommandInvoked, true); IReadOnlyDictionary namespaceCommands; try { @@ -404,6 +402,7 @@ private async Task InvokeChildToolAsync( // this case, which will be executed. currentActivity?.SetTag(TagName.ToolName, command); + request.Items[TagName.IsServerCommandInvoked] = true; var commandResponse = await cmd.ExecuteAsync(commandContext, commandOptions); var jsonResponse = JsonSerializer.Serialize(commandResponse, ModelsJsonContext.Default.CommandResponse); var isError = commandResponse.Status < HttpStatusCode.OK || commandResponse.Status >= HttpStatusCode.Ambiguous; @@ -469,36 +468,53 @@ There was an error finding or calling tool and command. private async Task InvokeToolLearn(RequestContext request, string? intent, string namespaceName, CancellationToken cancellationToken) { - Activity.Current?.SetTag(TagName.IsServerCommandInvoked, false); - var toolsJson = GetChildToolListJson(request, namespaceName); + request.Items[TagName.IsServerCommandInvoked] = false; + var availableTools = GetChildToolList(request, namespaceName); - var learnResponse = new CallToolResult + if (SupportsSampling(request.Server) && !string.IsNullOrWhiteSpace(intent)) { - Content = - [ + (string? commandName, IReadOnlyDictionary parameters) = await GetCommandAndParametersFromIntentAsync(request, intent, namespaceName, availableTools, cancellationToken); + if (commandName != null) + { + var commandTool = availableTools.Where(tool => string.Equals(commandName, tool.Name)).FirstOrDefault(); + if (commandTool != null) + { + return new CallToolResult + { + Content = [ + new TextContentBlock { + Text = $""" + Here is the most suitable command and its parameters based on the intent '{intent}'. + If you do not find the command suitable, run again with the "learn=true" to get a list of available commands and their parameters. + Next, identify the command you want to execute and run again with the "command" and "parameters" arguments. + + {JsonSerializer.Serialize(commandTool, ServerJsonContext.Default.Tool)} + """ + } + ], + IsError = false + }; + } + } + } + + // Wasn't able to infer a specific tool command, either intent was missing, sampling wasn't support, or sampling failed. + // Return the list of available tools for the namespace. + return new CallToolResult + { + Content = [ new TextContentBlock { Text = $""" - Here are the available command and their parameters for '{namespaceName}' tool. + Here are the available commands and their parameters for '{namespaceName}' tool. If you do not find a suitable command, run again with the "learn=true" to get a list of available commands and their parameters. Next, identify the command you want to execute and run again with the "command" and "parameters" arguments. - {toolsJson} + {JsonSerializer.Serialize(availableTools, ServerJsonContext.Default.ListTool)} """ } ], IsError = false }; - var response = learnResponse; - if (SupportsSampling(request.Server) && !string.IsNullOrWhiteSpace(intent)) - { - var availableTools = GetChildToolList(request, namespaceName); - (string? commandName, IReadOnlyDictionary parameters) = await GetCommandAndParametersFromIntentAsync(request, intent, namespaceName, availableTools, cancellationToken); - if (commandName != null) - { - response = await InvokeChildToolAsync(request, intent, namespaceName, commandName, parameters, cancellationToken); - } - } - return response; } /// @@ -542,12 +558,6 @@ private List GetChildToolList(RequestContext reques return list; } - private string GetChildToolListJson(RequestContext request, string namespaceName) - { - var listTools = GetChildToolList(request, namespaceName); - return JsonSerializer.Serialize(listTools, ServerJsonContext.Default.ListTool); - } - private string GetChildToolJson(RequestContext request, string namespaceName, string commandName) { var tools = GetChildToolList(request, namespaceName); diff --git a/core/Azure.Mcp.Core/src/Areas/Server/Commands/ToolLoading/ServerToolLoader.cs b/core/Azure.Mcp.Core/src/Areas/Server/Commands/ToolLoading/ServerToolLoader.cs index db7f3c7b8..437516235 100644 --- a/core/Azure.Mcp.Core/src/Areas/Server/Commands/ToolLoading/ServerToolLoader.cs +++ b/core/Azure.Mcp.Core/src/Areas/Server/Commands/ToolLoading/ServerToolLoader.cs @@ -245,7 +245,7 @@ private async Task InvokeChildToolAsync(RequestContext InvokeToolLearn(RequestContext request, string? intent, string tool, CancellationToken cancellationToken) { - Activity.Current?.SetTag(TagName.IsServerCommandInvoked, false); + request.Items[TagName.IsServerCommandInvoked] = false; var toolsJson = await GetChildToolListJsonAsync(request, tool); var learnResponse = new CallToolResult diff --git a/core/Azure.Mcp.Core/src/Areas/Server/Commands/ToolLoading/SingleProxyToolLoader.cs b/core/Azure.Mcp.Core/src/Areas/Server/Commands/ToolLoading/SingleProxyToolLoader.cs index f0b9942df..dd9accec8 100644 --- a/core/Azure.Mcp.Core/src/Areas/Server/Commands/ToolLoading/SingleProxyToolLoader.cs +++ b/core/Azure.Mcp.Core/src/Areas/Server/Commands/ToolLoading/SingleProxyToolLoader.cs @@ -1,9 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using System.Diagnostics; using Azure.Mcp.Core.Areas.Server.Commands.Discovery; -using Azure.Mcp.Core.Services.Telemetry; using Microsoft.Extensions.Logging; using ModelContextProtocol; using ModelContextProtocol.Client; @@ -133,11 +131,11 @@ public override async ValueTask CallToolHandler(RequestContext GetToolListJsonAsync(RequestContext RootLearnModeAsync(RequestContext request, string intent, CancellationToken cancellationToken) { - Activity.Current?.SetTag(TagName.IsServerCommandInvoked, false); + request.Items[TagName.IsServerCommandInvoked] = false; var toolsJson = await GetRootToolsJsonAsync(); var learnResponse = new CallToolResult { @@ -236,7 +234,7 @@ Here are the available list of tools. private async Task ToolLearnModeAsync(RequestContext request, string intent, string tool, CancellationToken cancellationToken) { - Activity.Current?.SetTag(TagName.IsServerCommandInvoked, false); + request.Items[TagName.IsServerCommandInvoked] = false; var toolsJson = await GetToolListJsonAsync(request, tool); if (string.IsNullOrEmpty(toolsJson)) { @@ -273,7 +271,7 @@ private async Task ToolLearnModeAsync(RequestContext CommandModeAsync(RequestContext request, string intent, string tool, string command, Dictionary parameters, CancellationToken cancellationToken) { - Activity.Current?.SetTag(TagName.IsServerCommandInvoked, true); + request.Items[TagName.IsServerCommandInvoked] = true; McpClient? client; try diff --git a/core/Azure.Mcp.Core/src/Commands/CommandFactory.cs b/core/Azure.Mcp.Core/src/Commands/CommandFactory.cs index f4c02b92a..5e1125701 100644 --- a/core/Azure.Mcp.Core/src/Commands/CommandFactory.cs +++ b/core/Azure.Mcp.Core/src/Commands/CommandFactory.cs @@ -201,7 +201,7 @@ private void ConfigureCommandHandler(Command command, IBaseCommand implementatio if (response.Status == HttpStatusCode.OK && response.Results == null) { - response.Results = ResponseResult.Create(new List(), JsonSourceGenerationContext.Default.ListString); + response.Results = ResponseResult.Create([], JsonSourceGenerationContext.Default.ListString); } var isServiceStartCommand = implementation is Areas.Server.Commands.ServiceStartCommand;