Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
3900ebc
Migrate remaining functions
xiang17 Mar 18, 2026
f51666e
Fix unit tests
xiang17 Mar 18, 2026
220dd1a
Update missing changes
xiang17 Mar 18, 2026
416223e
Sync code changes
xiang17 Mar 18, 2026
9367502
Merge pull request #1 from rajkumar-rangaraj/xiang17/MonitorInstrumen…
xiang17 Mar 19, 2026
0959f55
Update according to instructions in new-command.md
xiang17 Mar 19, 2026
282f59c
Fix "error WHITESPACE: Fix whitespace formatting." with `dotnet forma…
xiang17 Mar 19, 2026
1c57565
Remove "related:" sections
xiang17 Mar 19, 2026
9729268
Convert internal markdown links
xiang17 Mar 19, 2026
202b20a
fix 404 link
xiang17 Mar 19, 2026
296dda8
Update changelog and remove unused line
xiang17 Mar 19, 2026
46f4db3
ToolMetadata update
xiang17 Mar 19, 2026
48dcce6
address Copilot feedbacks
xiang17 Mar 19, 2026
0457e29
merge with rest of Azure Monitor operations in e2eTstPrompts.md
xiang17 Mar 19, 2026
1cc0aff
Merge branch 'main' into xiang17/MonitorInstrumentation_remaining
xiang17 Mar 19, 2026
f90058d
Fixed OpenWorld ToolMetadata attributes and updated consolidated-tool…
xiang17 Mar 20, 2026
fb9e4c2
Sync missing logic from standalone instrumentation MCP server
rajkumar-rangaraj Mar 20, 2026
0131cc1
Fix nuget-vs to match standalone and add missing natural language sen…
rajkumar-rangaraj Mar 20, 2026
7e225eb
Merge pull request #3 from rajkumar-rangaraj/rajrang/sync-standalone-…
rajkumar-rangaraj Mar 20, 2026
4ce1c12
update changelog to include the full list of supported languages and …
xiang17 Mar 20, 2026
69c3965
reword changelog
xiang17 Mar 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pr: 2115
changes:
- section: "Features Added"
description: "Azure Monitor Instrumentation in the tool now supports guided onboarding for .NET, Node.js, and Python with framework-aware recommendations and code/package actions. Automated guidance currently includes .NET (ASP.NET Core, ASP.NET classic including MVC/WebForms, Worker Service, plus console/library migration paths), Node.js (Express, Fastify, NestJS, Next.js, LangChain.js, Postgres, MongoDB, Redis, MySQL, Winston, Bunyan, and console apps), and Python (Django, Flask, FastAPI, Falcon, Starlette, GenAI, and generic console/script apps). .NET also supports brownfield migration guidance for Application Insights SDK to 3.x and enhancement flows for projects already on Application Insights 3.x or Azure Monitor Distro."
5 changes: 5 additions & 0 deletions servers/Azure.Mcp.Server/docs/azmcp-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -2509,11 +2509,16 @@ azmcp monitor instrumentation orchestrator_next --session-id <session-id> \
# Send brownfield analysis findings JSON to continue migration flow
azmcp monitor instrumentation send_brownfield_analysis --session-id <session-id> \
--findings-json <json>

# Submit enhancement selection when orchestrator_start returns enhancement_available
azmcp monitor instrumentation send_enhanced_selection --session-id <session-id> \
--enhancement-keys <comma-separated-keys>
```

**Notes:**
- `orchestrator_start` and `orchestrator_next` mirror the orchestration flow used by Azure Monitor onboarding.
- `send_brownfield_analysis` expects a JSON payload matching the `analysisTemplate` returned by `orchestrator_start` when status is `analysis_needed`.
- `send_enhanced_selection` expects one or more enhancement keys from `enhancementOptions` returned by `orchestrator_start` when status is `enhancement_available`.

### Azure Managed Lustre Operations

Expand Down
33 changes: 18 additions & 15 deletions servers/Azure.Mcp.Server/docs/e2eTestPrompts.md
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,24 @@ This file contains prompts used for end-to-end testing to ensure each tool is in
|:----------|:----------|
| monitor_activitylog_list | List the activity logs of the last month for <resource_name> |
| monitor_healthmodels_entity_get | Show me the health status of entity <entity_id> using the health model <health_model_name> |
| monitor_instrumentation_get_learning_resource | Get the onboarding learning resource at path <resource_path> |
| monitor_instrumentation_get_learning_resource | Show me the content of the Azure Monitor onboarding learning resource at path <resource_path> |
| monitor_instrumentation_get_learning_resource | Get the content of the Azure Monitor learning resource file at path <resource_path> |
| monitor_instrumentation_get_learning_resource | List all available Azure Monitor onboarding learning resources |
| monitor_instrumentation_get_learning_resource | Show me all learning resource paths for Azure Monitor instrumentation |
| monitor_instrumentation_get_learning_resource | What learning resources are available for Azure Monitor instrumentation onboarding? |
| monitor_instrumentation_orchestrator_next | After completing the previous Azure Monitor instrumentation step, get the next action for session <session_id> with completion note <completion_note> |
| monitor_instrumentation_orchestrator_next | Get the next onboarding action using session <session_id> after I completed <completion_note> |
| monitor_instrumentation_orchestrator_next | I finished the previous instrumentation step; return the next step for session <session_id> with note <completion_note> |
| monitor_instrumentation_orchestrator_start | Start Azure Monitor instrumentation orchestration for workspace <workspace_path> |
| monitor_instrumentation_orchestrator_start | Analyze workspace <workspace_path> and return the first Azure Monitor instrumentation step |
| monitor_instrumentation_orchestrator_start | Begin guided Azure Monitor onboarding for project at <workspace_path> and give me step one |
| monitor_instrumentation_send_brownfield_analysis | Send brownfield code analysis findings JSON <findings_json> to Azure Monitor instrumentation session <session_id> after analysis was requested |
| monitor_instrumentation_send_brownfield_analysis | Continue migration orchestration by submitting analysis payload <findings_json> to session <session_id> |
| monitor_instrumentation_send_brownfield_analysis | Send completed brownfield telemetry analysis <findings_json> for onboarding session <session_id> |
| monitor_instrumentation_send_enhanced_selection | Submit enhancement selection keys <enhancement_keys> for Azure Monitor instrumentation session <session_id> after enhancement options are presented |
| monitor_instrumentation_send_enhanced_selection | Continue instrumentation enhancement flow by sending selected keys <enhancement_keys> to session <session_id> |
| monitor_instrumentation_send_enhanced_selection | Send chosen enhancement option key list <enhancement_keys> for onboarding session <session_id> |
| monitor_metrics_definitions | Get metric definitions for <resource_type> <resource_name> from the namespace |
| monitor_metrics_definitions | Show me all available metrics and their definitions for storage account <account_name> |
| monitor_metrics_definitions | What metric definitions are available for the Application Insights resource <resource_name> |
Expand All @@ -683,21 +701,6 @@ This file contains prompts used for end-to-end testing to ensure each tool is in
| monitor_workspace_list | Show me my Log Analytics workspaces |
| monitor_workspace_list | Show me the Log Analytics workspaces in my subscription |
| monitor_workspace_log_query | Show me the logs for the past hour in the Log Analytics workspace <workspace_name> |
| monitor_instrumentation_get_learning_resource | Get the onboarding learning resource at path <resource_path> |
| monitor_instrumentation_get_learning_resource | Show me the content of the Azure Monitor onboarding learning resource at path <resource_path> |
| monitor_instrumentation_get_learning_resource | Get the content of the Azure Monitor learning resource file at path <resource_path> |
| monitor_instrumentation_get_learning_resource | List all available Azure Monitor onboarding learning resources |
| monitor_instrumentation_get_learning_resource | Show me all learning resource paths for Azure Monitor instrumentation |
| monitor_instrumentation_get_learning_resource | What learning resources are available for Azure Monitor instrumentation onboarding? |
| monitor_instrumentation_orchestrator_next | After completing the previous Azure Monitor instrumentation step, get the next action for session <session_id> with completion note <completion_note> |
| monitor_instrumentation_orchestrator_next | Get the next onboarding action using session <session_id> after I completed <completion_note> |
| monitor_instrumentation_orchestrator_next | I finished the previous instrumentation step; return the next step for session <session_id> with note <completion_note> |
| monitor_instrumentation_orchestrator_start | Start Azure Monitor instrumentation orchestration for workspace <workspace_path> |
| monitor_instrumentation_orchestrator_start | Analyze workspace <workspace_path> and return the first Azure Monitor instrumentation step |
| monitor_instrumentation_orchestrator_start | Begin guided Azure Monitor onboarding for project at <workspace_path> and give me step one |
| monitor_instrumentation_send_brownfield_analysis | Send brownfield code analysis findings JSON <findings_json> to Azure Monitor instrumentation session <session_id> after analysis was requested |
| monitor_instrumentation_send_brownfield_analysis | Continue migration orchestration by submitting analysis payload <findings_json> to session <session_id> |
| monitor_instrumentation_send_brownfield_analysis | Send completed brownfield telemetry analysis <findings_json> for onboarding session <session_id> |

## Azure Native ISV

Expand Down
11 changes: 6 additions & 5 deletions servers/Azure.Mcp.Server/src/Resources/consolidated-tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -3538,12 +3538,12 @@
"description": "Running this operation multiple times with the same arguments may have additional effects or produce different results."
},
"openWorld": {
"value": true,
"description": "This tool may interact with an unpredictable or dynamic set of external entities."
"value": false,
"description": "This tool's domain of interaction is closed and well-defined, limited to a specific set of entities."
},
"readOnly": {
"value": true,
"description": "This tool only performs read operations without modifying any state or data."
"value": false,
"description": "This tool may modify its environment by creating, updating, or deleting data."
},
"secret": {
"value": false,
Expand All @@ -3557,7 +3557,8 @@
"mappedToolList": [
"monitor_instrumentation_orchestrator_start",
"monitor_instrumentation_orchestrator_next",
"monitor_instrumentation_send_brownfield_analysis"
"monitor_instrumentation_send_brownfield_analysis",
"monitor_instrumentation_send_enhanced_selection"
]
}
,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ 3. Now call this tool to get the next action
{
Destructive = false,
Idempotent = false,
OpenWorld = true,
ReadOnly = true,
OpenWorld = false,
ReadOnly = false,
LocalRequired = true,
Secret = false
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ public sealed class OrchestratorStartCommand(ILogger<OrchestratorStartCommand> l
{
Destructive = false,
Idempotent = false,
OpenWorld = true,
ReadOnly = true,
OpenWorld = false,
ReadOnly = false,
LocalRequired = true,
Secret = false
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ You must have scanned the workspace source files and filled in the analysis temp
{
Destructive = false,
Idempotent = false,
OpenWorld = true,
ReadOnly = true,
OpenWorld = false,
ReadOnly = false,
LocalRequired = true,
Secret = false
};
Expand Down Expand Up @@ -81,7 +81,8 @@ public override Task<CommandResponse> ExecuteAsync(CommandContext context, Parse
findings.Processors,
findings.ClientUsage,
findings.Sampling,
findings.TelemetryPipeline);
findings.TelemetryPipeline,
findings.Logging);

context.Response.Status = HttpStatusCode.OK;
context.Response.Results = ResponseResult.Create(result, MonitorInstrumentationJsonContext.Default.String);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.Net;
using Azure.Mcp.Tools.Monitor.Options;
using Azure.Mcp.Tools.Monitor.Tools;
using Microsoft.Extensions.Logging;
using Microsoft.Mcp.Core.Commands;
using Microsoft.Mcp.Core.Extensions;
using Microsoft.Mcp.Core.Models.Command;
using Microsoft.Mcp.Core.Models.Option;

namespace Azure.Mcp.Tools.Monitor.Commands;

public sealed class SendEnhancedSelectionCommand(ILogger<SendEnhancedSelectionCommand> logger)
: BaseCommand<SendEnhancedSelectionOptions>
{
private readonly ILogger<SendEnhancedSelectionCommand> _logger = logger;

public override string Id => "8fd4eb5f-14d1-450f-982c-82d761f0f7d6";

public override string Name => "send_enhanced_selection";

public override string Description => @"Submit the user's enhancement selection after orchestrator_start returned status 'enhancement_available'.
Present the enhancement options to the user first, then call this tool with their chosen option key(s).
Multiple enhancements can be selected by passing a comma-separated list (e.g. 'redis,processors').
After this call succeeds, continue with orchestrator_next as usual.";

public override string Title => "Send Enhancement Selection";

public override ToolMetadata Metadata => new()
{
Destructive = false,
Idempotent = false,
OpenWorld = false,
ReadOnly = false,
LocalRequired = true,
Secret = false
};

protected override void RegisterOptions(Command command)
{
command.Options.Add(MonitorInstrumentationOptionDefinitions.SessionId);
command.Options.Add(MonitorInstrumentationOptionDefinitions.EnhancementKeys);
}

protected override SendEnhancedSelectionOptions BindOptions(ParseResult parseResult)
{
return new SendEnhancedSelectionOptions
{
SessionId = parseResult.CommandResult.GetValueOrDefault(MonitorInstrumentationOptionDefinitions.SessionId),
EnhancementKeys = parseResult.CommandResult.GetValueOrDefault(MonitorInstrumentationOptionDefinitions.EnhancementKeys)
};
}

public override Task<CommandResponse> ExecuteAsync(CommandContext context, ParseResult parseResult, CancellationToken cancellationToken)
{
if (!Validate(parseResult.CommandResult, context.Response).IsValid)
{
return Task.FromResult(context.Response);
}

var options = BindOptions(parseResult);

try
{
var tool = context.GetService<SendEnhancedSelectionTool>();
var result = tool.Send(options.SessionId!, options.EnhancementKeys!);

context.Response.Status = HttpStatusCode.OK;
context.Response.Results = ResponseResult.Create(result, MonitorInstrumentationJsonContext.Default.String);
context.Response.Message = string.Empty;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in {Operation}. SessionId: {SessionId}", Name, options.SessionId);
HandleException(context, ex);
}

return Task.FromResult(context.Response);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ public InstrumentationResult Detect(string workspacePath)
var configEvidence = CheckConfigFiles(workspacePath);
evidence.AddRange(configEvidence);

// Check packages.config for classic .NET Framework projects
var packagesConfigEvidence = CheckPackagesConfig(workspacePath);
evidence.AddRange(packagesConfigEvidence);

if (evidence.Count == 0)
{
return new InstrumentationResult(InstrumentationState.Greenfield, null);
Expand All @@ -31,18 +35,56 @@ public InstrumentationResult Detect(string workspacePath)
// Determine instrumentation type from evidence
var instrumentationType = DetermineInstrumentationType(evidence);
var version = ExtractVersion(evidence);
var isTargetVersion = IsAlreadyOnTargetVersion(instrumentationType, version);

return new InstrumentationResult(
InstrumentationState.Brownfield,
new ExistingInstrumentation
{
Type = instrumentationType,
Version = version,
IsTargetVersion = isTargetVersion,
Evidence = evidence
}
);
}

private List<Evidence> CheckPackagesConfig(string workspacePath)
{
var evidence = new List<Evidence>();
var packagesConfigs = Directory.GetFiles(workspacePath, "packages.config", SearchOption.AllDirectories);

foreach (var configFile in packagesConfigs)
{
try
{
var doc = XDocument.Load(configFile);
var packages = doc.Descendants("package");

foreach (var pkg in packages)
{
var id = pkg.Attribute("id")?.Value ?? string.Empty;
var version = pkg.Attribute("version")?.Value ?? "unknown";

if (PackageDetection.AiSdkPackages.Any(p => id.Equals(p, StringComparison.OrdinalIgnoreCase)))
{
evidence.Add(new Evidence
{
File = configFile,
Indicator = $"PackageReference: {id} {version}"
});
}
}
}
catch
{
// Skip files we can't parse
}
}

return evidence;
}

private List<Evidence> AnalyzeProjectReferences(string csprojPath)
{
var evidence = new List<Evidence>();
Expand Down Expand Up @@ -174,4 +216,41 @@ private InstrumentationType DetermineInstrumentationType(List<Evidence> evidence
}
return null;
}

/// <summary>
/// Determines if the detected SDK is already on the target version:
/// - ApplicationInsightsSdk: 3.x is target (2.x needs migration)
/// - AzureMonitorDistro: any version is target (already on the recommended path)
/// </summary>
private static bool IsAlreadyOnTargetVersion(InstrumentationType type, string? version)
{
if (type == InstrumentationType.AzureMonitorDistro)
{
return true;
}

if (type != InstrumentationType.ApplicationInsightsSdk || string.IsNullOrWhiteSpace(version))
{
return false;
}

// Handle wildcard versions like "3.*"
if (version.StartsWith("3.", StringComparison.Ordinal) || version.StartsWith("3-", StringComparison.Ordinal))
{
return true;
}

// Try to parse as a real version
// Strip leading 'v' if present, handle pre-release suffix
var versionToParse = version.TrimStart('v');
var dashIndex = versionToParse.IndexOf('-');
var versionCore = dashIndex > 0 ? versionToParse[..dashIndex] : versionToParse;

if (Version.TryParse(versionCore, out var parsed))
{
return parsed.Major >= 3;
}

return false;
}
}
Loading