Skip to content

Commit 458c171

Browse files
authored
Reduce AppLens failures (#2018)
* Reduce AppLens failures The "diagnose" tool uses an AppLens endpoint to identify problems in Azure resources and provide solutions. It currently has a high failure rate. I suspect this is due in part to the way we present the parameters to the LM and how we handle them internally. The subscription, resource group, and resource type are presented as optional parameters, when in fact we need them all to construct the resource ID to pass to the AppLens API. It is likely that the LMs first attempt at diagnosing an issue will thus result in a failure, with a message telling it what it needs to provide. At that point it _may_ be able to find the necessary information, but it might also hallucinate it (leading to further failures) or just give up on the tool entirely. Instead, we should treat only the resource name as required, and then use an Azure Resource Graph query to find all of the potentially relevant resources. The subscription, group, and type can then be used to disambiguate when more than one possibility is found. This should increase the likelihood of finding the expected resource on the first try. * Add a changelog entry * Add trailing newline * Remove unnecessary filter The `AppLensService` currently uses ARG to find all resources of a given name, and then filters those results by subscription, resource group, and resource type, if they have been provided. Since the ARG query results are broad we have the opportunity to do some error correction; e.g., if resource group is given _but_ the resource is actually in a different group we will still find it and can return a message asking the LM if that's actually the one it meant. However, if we have a subscription we pass it in to the ARG query and results will necessarily be limited to that subscription; there is no value in further filtering. Here we remove the unncessary code.
1 parent d2c3c4f commit 458c171

File tree

7 files changed

+417
-78
lines changed

7 files changed

+417
-78
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
pr: 2018
2+
changes:
3+
- section: "Bugs Fixed"
4+
description: "Improved AppLens diagnose tool to use ARG-based resource discovery with optional subscription, resource group, and resource type parameters"

tools/Azure.Mcp.Tools.AppLens/src/Commands/Resource/ResourceDiagnoseCommand.cs

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33

4-
using Azure.Mcp.Core.Commands.Subscription;
5-
using Azure.Mcp.Core.Models.Option;
4+
using Azure.Mcp.Core.Commands;
65
using Azure.Mcp.Tools.AppLens.Models;
76
using Azure.Mcp.Tools.AppLens.Options;
87
using Azure.Mcp.Tools.AppLens.Options.Resource;
98
using Azure.Mcp.Tools.AppLens.Services;
109
using Microsoft.Extensions.Logging;
1110
using Microsoft.Mcp.Core.Commands;
1211
using Microsoft.Mcp.Core.Models.Command;
13-
using Microsoft.Mcp.Core.Models.Option;
1412

1513
namespace Azure.Mcp.Tools.AppLens.Commands.Resource;
1614

1715
/// <summary>
1816
/// Command to diagnose Azure resources using AppLens conversational diagnostics.
17+
/// Subscription, resource group, and resource type are optional - the service uses
18+
/// Azure Resource Graph to discover the resource by name when they are not provided.
1919
/// </summary>
2020
public sealed class ResourceDiagnoseCommand(ILogger<ResourceDiagnoseCommand> logger, IAppLensService appLensService)
21-
: SubscriptionCommand<ResourceDiagnoseOptions>
21+
: GlobalCommand<ResourceDiagnoseOptions>
2222
{
2323
private const string CommandTitle = "Diagnose Azure Resource Issues";
2424
private readonly ILogger<ResourceDiagnoseCommand> _logger = logger;
@@ -29,9 +29,10 @@ public sealed class ResourceDiagnoseCommand(ILogger<ResourceDiagnoseCommand> log
2929
public override string Name => "diagnose";
3030

3131
public override string Description =>
32-
"Get diagnostic help from App Lens for Azure application and service issues to identify what’s wrong with a service. Ask questions about performance, slowness, failures, errors, application state, availability to receive expert analysis and solutions which can help when performing diagnostics and to address issues about performance and failures. " +
33-
"Returns insights, recommended solutions, and analysis. " +
34-
"Always use this tool before manually checking metrics or logs when users report performance or functionality issues. Use Azure CLI to find the subscription, resourceGroup, and resourceType if not provided. If given a resourceId, parse it to extract subscription, resourceGroup, and resourceType (format: /subscriptions/{subscription}/resourceGroups/{resourceGroup}/providers/{resourceType}/{resource}). This tool can be used to ask questions about application state, diagnose performance problems, and address service failures.";
32+
"Get diagnostic help from App Lens for Azure application and service issues to identify what's wrong with a service. Ask questions about performance, slowness, failures, errors, application state, availability to receive expert analysis and solutions which can help when performing diagnostics and to address issues about performance and failures. " +
33+
"Returns analysis, insights, and recommended solutions. " +
34+
"Always use this tool before manually checking metrics or logs when users report performance or functionality issues. " +
35+
"Only the resource name and question are required - subscription, resource group, and resource type are optional and used to narrow down results when multiple resources share the same name.";
3536
public override string Title => CommandTitle;
3637

3738
public override ToolMetadata Metadata => new()
@@ -47,19 +48,21 @@ public sealed class ResourceDiagnoseCommand(ILogger<ResourceDiagnoseCommand> log
4748
protected override void RegisterOptions(Command command)
4849
{
4950
base.RegisterOptions(command);
50-
command.Options.Add(OptionDefinitions.Common.ResourceGroup.AsRequired());
51-
command.Options.Add(AppLensOptionDefinitions.Question);
52-
command.Options.Add(AppLensOptionDefinitions.Resource);
51+
command.Options.Add(AppLensOptionDefinitions.Subscription);
52+
command.Options.Add(AppLensOptionDefinitions.ResourceGroup);
5353
command.Options.Add(AppLensOptionDefinitions.ResourceType);
54+
command.Options.Add(AppLensOptionDefinitions.Resource);
55+
command.Options.Add(AppLensOptionDefinitions.Question);
5456
}
5557

5658
protected override ResourceDiagnoseOptions BindOptions(ParseResult parseResult)
5759
{
5860
var options = base.BindOptions(parseResult);
59-
options.ResourceGroup ??= parseResult.GetValueOrDefault<string>(OptionDefinitions.Common.ResourceGroup.Name);
61+
options.Subscription = parseResult.GetValueOrDefault<string>(AppLensOptionDefinitions.Subscription.Name);
62+
options.ResourceGroup = parseResult.GetValueOrDefault<string>(AppLensOptionDefinitions.ResourceGroup.Name);
6063
options.Question = parseResult.GetValueOrDefault<string>(AppLensOptionDefinitions.Question.Name) ?? string.Empty;
6164
options.Resource = parseResult.GetValueOrDefault<string>(AppLensOptionDefinitions.Resource.Name) ?? string.Empty;
62-
options.ResourceType ??= parseResult.GetValueOrDefault<string>(AppLensOptionDefinitions.ResourceType.Name);
65+
options.ResourceType = parseResult.GetValueOrDefault<string>(AppLensOptionDefinitions.ResourceType.Name);
6366
return options;
6467
}
6568

@@ -80,7 +83,7 @@ public override async Task<CommandResponse> ExecuteAsync(CommandContext context,
8083
var result = await _appLensService.DiagnoseResourceAsync(
8184
options.Question,
8285
options.Resource,
83-
options.Subscription!,
86+
options.Subscription,
8487
options.ResourceGroup,
8588
options.ResourceType,
8689
options.Tenant,

tools/Azure.Mcp.Tools.AppLens/src/Options/AppLensOptionDefinitions.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ public static class AppLensOptionDefinitions
88
public const string QuestionName = "question";
99
public const string ResourceName = "resource";
1010
public const string ResourceTypeName = "resource-type";
11+
public const string ResourceGroupName = "resource-group";
12+
public const string SubscriptionName = "subscription";
1113

1214
public static readonly Option<string> Question = new(
1315
$"--{QuestionName}")
@@ -23,10 +25,24 @@ public static class AppLensOptionDefinitions
2325
Required = true
2426
};
2527

28+
public static readonly Option<string?> Subscription = new(
29+
$"--{SubscriptionName}")
30+
{
31+
Description = "Azure subscription ID or name. Provide this when disambiguating between multiple resources of the same name.",
32+
Required = false
33+
};
34+
35+
public static readonly Option<string?> ResourceGroup = new(
36+
$"--{ResourceGroupName}")
37+
{
38+
Description = "Azure resource group name. Provide this when disambiguating between multiple resources of the same name.",
39+
Required = false
40+
};
41+
2642
public static readonly Option<string?> ResourceType = new(
2743
$"--{ResourceTypeName}")
2844
{
29-
Description = "Resource type. Try to get this information using the Azure CLI tool before asking the user.",
30-
Required = true
45+
Description = "Resource type. Provide this when disambiguating between multiple resources of the same name.",
46+
Required = false
3147
};
3248
}

tools/Azure.Mcp.Tools.AppLens/src/Options/Resource/ResourceDiagnoseOptions.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace Azure.Mcp.Tools.AppLens.Options.Resource;
88
/// <summary>
99
/// Options for the AppLens resource diagnose command.
1010
/// </summary>
11-
public class ResourceDiagnoseOptions : SubscriptionOptions
11+
public class ResourceDiagnoseOptions : GlobalOptions
1212
{
1313
/// <summary>
1414
/// The user's question for diagnosis.
@@ -21,7 +21,12 @@ public class ResourceDiagnoseOptions : SubscriptionOptions
2121
public string Resource { get; set; } = string.Empty;
2222

2323
/// <summary>
24-
/// The Resource Type of the resource to diagnose
24+
/// The Resource Type of the resource to diagnose. This is optional and used to disambiguate between multiple resources with the same name.
2525
/// </summary>
2626
public string? ResourceType { get; set; }
27+
28+
/// <summary>
29+
/// The subscription of the resource to diagnose. This is optional and used to disambiguate between multiple resources with the same name.
30+
/// </summary>
31+
public string? Subscription { get; set; }
2732
}

0 commit comments

Comments
 (0)