-
Notifications
You must be signed in to change notification settings - Fork 15
feat: consolidate tools and reduce total number of tools #96
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
93388b4
to
151502e
Compare
173aea7
to
29a3ba8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR consolidates the AKS MCP tools from 47 to 18 tools while maintaining all functionality. The consolidation moves from individual command-specific tools to unified operation-based tools, introducing a new executor pattern for handling multiple related operations through single tools.
- Consolidates AKS operations into a single
az_aks_operations
tool with operation-based routing - Unifies monitoring operations into an
az_monitoring
tool supporting metrics, resource health, app insights, diagnostics, and logs - Consolidates network resource tools into a single
az_network_resources
tool with resource-type-based routing
Reviewed Changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.
Show a summary per file
File | Description |
---|---|
internal/server/server.go |
Streamlines tool registration by replacing multiple command-specific registrations with unified tools |
internal/k8s/adapter.go |
Minor comment cleanup removing redundant text |
internal/components/network/registry_test.go |
Removes individual tool registration tests, keeping handler tests |
internal/components/network/registry.go |
Replaces multiple network tool registrations with unified az_network_resources tool |
internal/components/network/handlers.go |
Adds unified handler for network resources with operation routing |
internal/components/monitor/registry_test.go |
Updates tests to match new consolidated monitoring tool structure |
internal/components/monitor/registry.go |
Consolidates monitoring commands into unified az_monitoring tool |
internal/components/monitor/handlers_test.go |
Removes obsolete tool registration test |
internal/components/monitor/handlers.go |
Adds unified monitoring handler with operation-based routing |
internal/components/azaks/registry_test.go |
Updates tests for new consolidated AKS operations approach |
internal/components/azaks/registry.go |
Replaces command lists with operation-based tool registration and access validation |
internal/components/azaks/executor.go |
New executor implementing operation-to-command mapping with access control |
internal/components/advisor/aks_recommendations.go |
Removes commented code for cleaner implementation |
Comments suppressed due to low confidence (1)
internal/components/azaks/registry.go:99
- [nitpick] The tool name 'az_aks_operations' is inconsistent with the naming convention used for other tools like 'az_monitoring' and 'az_network_resources'. Consider using 'az_aks' for consistency.
return mcp.NewTool("az_aks_operations",
result := make(map[string]interface{}) | ||
|
||
// Get VNet info | ||
if vnetResult, err := handleVNetResource(client, subID, rg, clusterName); err == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error handling pattern using assignment in if condition could mask errors. If handleVNetResource
returns a non-nil error, it's assigned to err
but then the error is only stored in the result map as a string. This could make debugging difficult as the original error context is lost.
Copilot uses AI. Check for mistakes.
} | ||
|
||
// If the command is not an az command, return an error | ||
if binaryName != "az" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The security check only validates that the command starts with 'az', but doesn't prevent command injection through the arguments. An attacker could potentially inject malicious commands through semicolons, pipes, or other shell operators in the args parameter.
Copilot uses AI. Check for mistakes.
"github.com/Azure/aks-mcp/internal/config" | ||
"github.com/Azure/aks-mcp/internal/tools" | ||
) | ||
|
||
// mergeMonitoringParams merges top-level parameters with nested "parameters" JSON string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The mergeMonitoringParams
function lacks documentation explaining its purpose, parameters, and return values. This is a key function that handles parameter merging logic and should be properly documented.
// mergeMonitoringParams merges top-level parameters with nested "parameters" JSON string | |
// mergeMonitoringParams merges top-level parameters with nested "parameters" JSON string. | |
// | |
// Parameters: | |
// - params: A map[string]interface{} containing the top-level parameters. If a key "parameters" | |
// exists and its value is a JSON string, the function will attempt to parse and merge it. | |
// | |
// Returns: | |
// - A map[string]interface{} containing the merged parameters. Top-level parameters take precedence | |
// over nested parameters in case of key conflicts. | |
// - An error if the "parameters" key contains an invalid JSON string. |
Copilot uses AI. Check for mistakes.
// Extract resource_type parameter | ||
resourceType, ok := params["resource_type"].(string) | ||
if !ok { | ||
return "", fmt.Errorf("missing or invalid 'resource_type' parameter") | ||
} | ||
|
||
// Validate resource type | ||
if !ValidateNetworkResourceType(resourceType) { | ||
supportedTypes := GetSupportedNetworkResourceTypes() | ||
return "", fmt.Errorf("unsupported resource type: %s. Supported types: %v", resourceType, supportedTypes) | ||
} | ||
|
||
// Extract common AKS parameters | ||
subID, rg, clusterName, err := common.ExtractAKSParameters(params) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
// Handle different resource types | ||
switch resourceType { | ||
case string(ResourceTypeAll): | ||
return handleAllNetworkResources(client, subID, rg, clusterName) | ||
case string(ResourceTypeVNet): | ||
return handleVNetResource(client, subID, rg, clusterName) | ||
case string(ResourceTypeNSG): | ||
return handleNSGResource(client, subID, rg, clusterName) | ||
case string(ResourceTypeRouteTable): | ||
return handleRouteTableResource(client, subID, rg, clusterName) | ||
case string(ResourceTypeSubnet): | ||
return handleSubnetResource(client, subID, rg, clusterName) | ||
case string(ResourceTypeLoadBalancer): | ||
return handleLoadBalancerResource(client, subID, rg, clusterName) | ||
case string(ResourceTypePrivateEndpoint): | ||
return handlePrivateEndpointResource(client, subID, rg, clusterName) | ||
default: | ||
return "", fmt.Errorf("resource type '%s' not implemented", resourceType) | ||
} | ||
}) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The GetAzNetworkResourcesHandler
function is quite large (over 160 lines) and handles multiple concerns. Consider breaking it down into smaller, more focused functions for better maintainability and testability.
// Extract resource_type parameter | |
resourceType, ok := params["resource_type"].(string) | |
if !ok { | |
return "", fmt.Errorf("missing or invalid 'resource_type' parameter") | |
} | |
// Validate resource type | |
if !ValidateNetworkResourceType(resourceType) { | |
supportedTypes := GetSupportedNetworkResourceTypes() | |
return "", fmt.Errorf("unsupported resource type: %s. Supported types: %v", resourceType, supportedTypes) | |
} | |
// Extract common AKS parameters | |
subID, rg, clusterName, err := common.ExtractAKSParameters(params) | |
if err != nil { | |
return "", err | |
} | |
// Handle different resource types | |
switch resourceType { | |
case string(ResourceTypeAll): | |
return handleAllNetworkResources(client, subID, rg, clusterName) | |
case string(ResourceTypeVNet): | |
return handleVNetResource(client, subID, rg, clusterName) | |
case string(ResourceTypeNSG): | |
return handleNSGResource(client, subID, rg, clusterName) | |
case string(ResourceTypeRouteTable): | |
return handleRouteTableResource(client, subID, rg, clusterName) | |
case string(ResourceTypeSubnet): | |
return handleSubnetResource(client, subID, rg, clusterName) | |
case string(ResourceTypeLoadBalancer): | |
return handleLoadBalancerResource(client, subID, rg, clusterName) | |
case string(ResourceTypePrivateEndpoint): | |
return handlePrivateEndpointResource(client, subID, rg, clusterName) | |
default: | |
return "", fmt.Errorf("resource type '%s' not implemented", resourceType) | |
} | |
}) | |
} | |
// Extract and validate parameters | |
resourceType, subID, rg, clusterName, err := extractAndValidateParams(params) | |
if err != nil { | |
return "", err | |
} | |
// Handle resource type | |
return handleResourceType(client, resourceType, subID, rg, clusterName) | |
}) | |
} | |
func extractAndValidateParams(params map[string]interface{}) (string, string, string, string, error) { | |
// Extract resource_type parameter | |
resourceType, ok := params["resource_type"].(string) | |
if !ok { | |
return "", "", "", "", fmt.Errorf("missing or invalid 'resource_type' parameter") | |
} | |
// Validate resource type | |
if !ValidateNetworkResourceType(resourceType) { | |
supportedTypes := GetSupportedNetworkResourceTypes() | |
return "", "", "", "", fmt.Errorf("unsupported resource type: %s. Supported types: %v", resourceType, supportedTypes) | |
} | |
// Extract common AKS parameters | |
subID, rg, clusterName, err := common.ExtractAKSParameters(params) | |
if err != nil { | |
return "", "", "", "", err | |
} | |
return resourceType, subID, rg, clusterName, nil | |
} | |
func handleResourceType(client *azureclient.AzureClient, resourceType, subID, rg, clusterName string) (string, error) { | |
switch resourceType { | |
case string(ResourceTypeAll): | |
return handleAllNetworkResources(client, subID, rg, clusterName) | |
case string(ResourceTypeVNet): | |
return handleVNetResource(client, subID, rg, clusterName) | |
case string(ResourceTypeNSG): | |
return handleNSGResource(client, subID, rg, clusterName) | |
case string(ResourceTypeRouteTable): | |
return handleRouteTableResource(client, subID, rg, clusterName) | |
case string(ResourceTypeSubnet): | |
return handleSubnetResource(client, subID, rg, clusterName) | |
case string(ResourceTypeLoadBalancer): | |
return handleLoadBalancerResource(client, subID, rg, clusterName) | |
case string(ResourceTypePrivateEndpoint): | |
return handlePrivateEndpointResource(client, subID, rg, clusterName) | |
default: | |
return "", fmt.Errorf("resource type '%s' not implemented", resourceType) | |
} | |
} |
Copilot uses AI. Check for mistakes.
return []MonitorCommand{} | ||
} | ||
Examples: | ||
- List metrics: operation="metrics", query_type="list", parameters="{\"resource\":\"<aks-cluster-id>\"}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
my test on getting aks/lb metrics passed. but failed on getting vm metrics sometimes, it would be better if we can provide different examples for different resource, I guess.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, I think so. What common scenarios do you suggest to add here?
This PR consolidates the AKS MCP tools to reduce the total number of registered tools while maintaining the same functionality. The consolidation moves from individual command-specific tools to unified operation-based tools that handle multiple related commands.
Tools reduced from 47-> 18.
Key Changes:
nodepool, and account operations
validation
operation-based registration
Technical Details:
Benefits: