Skip to content

Commit b92bb8b

Browse files
committed
feat: Add configurable annotation filtering to list_resources
- Add include_annotations parameter to control annotation inclusion (default: true) - Add exclude_annotation_keys parameter with wildcard support (e.g., nvidia.com/*) - Add include_annotation_keys parameter for exclusive annotation inclusion - Implement filterAnnotations function with pattern matching - Default excludes kubectl.kubernetes.io/last-applied-configuration - Add comprehensive unit tests for all filtering scenarios - Update README.md with detailed documentation and examples Resolves issue with metadata output truncation in large clusters, particularly those with GPU nodes containing extensive NVIDIA annotations. Fixes #89
1 parent 28c0716 commit b92bb8b

File tree

5 files changed

+420
-5
lines changed

5 files changed

+420
-5
lines changed

README.md

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,16 @@ Parameters:
199199
- `version` (required): API version (e.g., v1, v1beta1)
200200
- `resource` (required): Resource name (e.g., deployments, services)
201201
- `namespace`: Namespace (required for namespaced resources)
202+
- `label_selector`: Kubernetes label selector for filtering resources (optional)
203+
- `include_annotations`: Whether to include annotations in the output (default: true)
204+
- `exclude_annotation_keys`: List of annotation keys to exclude from output (supports wildcards with *)
205+
- `include_annotation_keys`: List of annotation keys to include in output (if specified, only these are included)
202206

203-
Example:
207+
##### Annotation Filtering
208+
209+
The `list_resources` tool provides powerful annotation filtering capabilities to control metadata output size and prevent truncation issues with large annotations (such as GPU node annotations).
210+
211+
**Basic Usage:**
204212

205213
```json
206214
{
@@ -215,6 +223,64 @@ Example:
215223
}
216224
```
217225

226+
**Exclude specific annotations (useful for GPU nodes):**
227+
228+
```json
229+
{
230+
"name": "list_resources",
231+
"arguments": {
232+
"resource_type": "clustered",
233+
"group": "",
234+
"version": "v1",
235+
"resource": "nodes",
236+
"exclude_annotation_keys": [
237+
"nvidia.com/*",
238+
"kubectl.kubernetes.io/last-applied-configuration"
239+
]
240+
}
241+
}
242+
```
243+
244+
**Include only specific annotations:**
245+
246+
```json
247+
{
248+
"name": "list_resources",
249+
"arguments": {
250+
"resource_type": "namespaced",
251+
"group": "",
252+
"version": "v1",
253+
"resource": "pods",
254+
"namespace": "default",
255+
"include_annotation_keys": ["app", "version", "prometheus.io/scrape"]
256+
}
257+
}
258+
```
259+
260+
**Disable annotations completely for maximum performance:**
261+
262+
```json
263+
{
264+
"name": "list_resources",
265+
"arguments": {
266+
"resource_type": "namespaced",
267+
"group": "",
268+
"version": "v1",
269+
"resource": "pods",
270+
"namespace": "default",
271+
"include_annotations": false
272+
}
273+
}
274+
```
275+
276+
**Annotation Filtering Rules:**
277+
278+
- By default, `kubectl.kubernetes.io/last-applied-configuration` is excluded to prevent large configuration data
279+
- `exclude_annotation_keys` supports wildcard patterns using `*` (e.g., `nvidia.com/*` excludes all NVIDIA annotations)
280+
- When `include_annotation_keys` is specified, it takes precedence and only those annotations are included
281+
- Setting `include_annotations: false` completely removes all annotations from the output
282+
- Wildcard patterns only support `*` at the end of the key (e.g., `nvidia.com/*`)
283+
218284
#### apply_resource
219285

220286
Applies (creates or updates) a Kubernetes resource.

pkg/mcp/helpers.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,60 @@
11
package mcp
22

3+
import (
4+
"strings"
5+
)
6+
37
// BoolPtr returns a pointer to the given bool value
48
func BoolPtr(b bool) *bool {
59
return &b
610
}
11+
12+
// filterAnnotations filters annotations based on include/exclude lists
13+
func filterAnnotations(annotations map[string]string, includeKeys, excludeKeys []string) map[string]string {
14+
if annotations == nil {
15+
return nil
16+
}
17+
18+
result := make(map[string]string)
19+
20+
// If includeKeys is specified, only include those keys
21+
if len(includeKeys) > 0 {
22+
for _, key := range includeKeys {
23+
if value, exists := annotations[key]; exists {
24+
result[key] = value
25+
}
26+
}
27+
return result
28+
}
29+
30+
// Otherwise, include all except excluded keys
31+
for key, value := range annotations {
32+
excluded := false
33+
for _, excludeKey := range excludeKeys {
34+
if matchesPattern(key, excludeKey) {
35+
excluded = true
36+
break
37+
}
38+
}
39+
if !excluded {
40+
result[key] = value
41+
}
42+
}
43+
44+
return result
45+
}
46+
47+
// matchesPattern checks if a key matches a pattern (supports wildcards with *)
48+
func matchesPattern(key, pattern string) bool {
49+
if pattern == key {
50+
return true
51+
}
52+
53+
// Simple wildcard matching - only supports * at the end
54+
if strings.HasSuffix(pattern, "*") {
55+
prefix := strings.TrimSuffix(pattern, "*")
56+
return strings.HasPrefix(key, prefix)
57+
}
58+
59+
return false
60+
}

pkg/mcp/list_resources.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ func (m *Implementation) HandleListResources(ctx context.Context, request mcp.Ca
3232
resource := mcp.ParseString(request, "resource", "")
3333
namespace := mcp.ParseString(request, "namespace", "")
3434
labelSelector := mcp.ParseString(request, "label_selector", "")
35+
36+
// Parse new annotation filtering parameters
37+
includeAnnotations := request.GetBool("include_annotations", true)
38+
excludeAnnotationKeys := request.GetStringSlice("exclude_annotation_keys", []string{"kubectl.kubernetes.io/last-applied-configuration"})
39+
includeAnnotationKeys := request.GetStringSlice("include_annotation_keys", []string{})
3540

3641
// Validate parameters
3742
if resourceType == "" {
@@ -90,10 +95,13 @@ func (m *Implementation) HandleListResources(ctx context.Context, request mcp.Ca
9095

9196
// Extract metadata from each resource
9297
for _, item := range list.Items {
93-
// Get annotations and filter out the last-applied-configuration annotation
94-
annotations := item.GetAnnotations()
95-
if annotations != nil {
96-
delete(annotations, "kubectl.kubernetes.io/last-applied-configuration")
98+
// Process annotations based on parameters
99+
var annotations map[string]string
100+
if includeAnnotations {
101+
rawAnnotations := item.GetAnnotations()
102+
if rawAnnotations != nil {
103+
annotations = filterAnnotations(rawAnnotations, includeAnnotationKeys, excludeAnnotationKeys)
104+
}
97105
}
98106

99107
metadata := metav1.PartialObjectMetadata{

0 commit comments

Comments
 (0)