Skip to content

Commit

Permalink
added: list-k8s-namespaces prompt
Browse files Browse the repository at this point in the history
  • Loading branch information
strowk committed Dec 14, 2024
1 parent 35db694 commit db46388
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 2 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ Currently available:
- tool: list-k8s-events in a given context and namespace
- tool: list-k8s-services in a given context and namespace
- tool: get-k8s-pod-logs in a given context and namespace
- prompt: list k8s pods in current context and with given namespace
- prompt: list-k8s-namespaces in a given context
- prompt: list-k8s-pods in current context and with given namespace

## Example usage with Inspector

Expand Down
100 changes: 100 additions & 0 deletions internal/prompts/namespaces.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package prompts

import (
"context"
"fmt"
"sort"

"github.com/strowk/foxy-contexts/pkg/fxctx"
"github.com/strowk/foxy-contexts/pkg/mcp"
"github.com/strowk/mcp-k8s-go/internal/content"
"github.com/strowk/mcp-k8s-go/internal/k8s"
"github.com/strowk/mcp-k8s-go/internal/utils"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func NewListNamespacesPrompt(pool k8s.ClientPool) fxctx.Prompt {
return fxctx.NewPrompt(
mcp.Prompt{
Name: "list-k8s-namespaces",
Description: utils.Ptr(
"List Kubernetes Namespaces in the specified context",
),
Arguments: []mcp.PromptArgument{
{
Name: "context",
Description: utils.Ptr(
"Context to list namespaces in, defaults to current context",
),
Required: utils.Ptr(false),
},
},
},
func(req *mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
k8sContext := req.Params.Arguments["context"]
clientset, err := pool.GetClientset(k8sContext)
if err != nil {
return nil, fmt.Errorf("failed to get k8s client: %w", err)
}

namespaces, err := clientset.
CoreV1().
Namespaces().
List(context.Background(), metav1.ListOptions{})
if err != nil {
return nil, fmt.Errorf("failed to list namespaces: %w", err)
}

sort.Slice(namespaces.Items, func(i, j int) bool {
return namespaces.Items[i].Name < namespaces.Items[j].Name
})

ofContextMsg := ""
currentContext, err := k8s.GetCurrentContext()
if err == nil && currentContext != "" {
ofContextMsg = fmt.Sprintf(", context '%s'", currentContext)
}

var messages []mcp.PromptMessage = make(
[]mcp.PromptMessage,
len(namespaces.Items)+1,
)
messages[0] = mcp.PromptMessage{
Content: mcp.TextContent{
Type: "text",
Text: fmt.Sprintf(
"There are %d namespaces%s:",
len(namespaces.Items),
ofContextMsg,
),
},
Role: mcp.RoleUser,
}

type NamespaceInList struct {
Name string `json:"name"`
}

for i, namespace := range namespaces.Items {
content, err := content.NewJsonContent(NamespaceInList{
Name: namespace.Name,
})
if err != nil {
return nil, fmt.Errorf("failed to create content: %w", err)
}
messages[i+1] = mcp.PromptMessage{
Content: content,
Role: mcp.RoleUser,
}
}

return &mcp.GetPromptResult{
Description: utils.Ptr(
fmt.Sprintf("Namespaces%s", ofContextMsg),
),
Messages: messages,
}, nil
},
)
}
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ func main() {
WithTool(tools.NewListPodsTool).
WithTool(tools.NewListServicesTool).
WithPrompt(prompts.NewListPodsPrompt).
WithPrompt(prompts.NewListNamespacesPrompt).
WithResourceProvider(resources.NewContextsResourceProvider).
WithServerCapabilities(getCapabilities()).
// setting up server
Expand Down
3 changes: 2 additions & 1 deletion packages/npm-mcp-k8s/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ Currently available:
- tool: list-k8s-events in a given context and namespace
- tool: list-k8s-services in a given context and namespace
- tool: get-k8s-pod-logs in a given context and namespace
- prompt: list k8s pods in current context and with given namespace
- prompt: list-k8s-namespaces in a given context
- prompt: list-k8s-pods in current context and with given namespace

## Example usage with Claude Desktop

Expand Down
11 changes: 11 additions & 0 deletions testdata/list_prompts_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ out:
"result":
{
"prompts": [
{
"name": "list-k8s-namespaces",
"description": "List Kubernetes Namespaces in the specified context",
"arguments": [
{
"description": "Context to list namespaces in, defaults to current context",
"name": "context",
"required": false,
},
]
},
{
"name": "list-k8s-pods",
"description": "List Kubernetes Pods with name and namespace in the current context",
Expand Down
67 changes: 67 additions & 0 deletions testdata/with_k3d/list_k8s_namespaces_test.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
case: List k8s namespaces using tool

in:
{
"jsonrpc": "2.0",
Expand Down Expand Up @@ -42,3 +44,68 @@ out:
"isError": false,
},
}

---

case: List k8s namespaces using prompt

in: {
"jsonrpc": "2.0",
"method": "prompts/get",
"id": 3,
"params": {
"name": "list-k8s-namespaces"
}
}

out: {
"jsonrpc": "2.0",
"id": 3,
"result": {
"description": "Namespaces, context 'k3d-mcp-k8s-integration-test'",
"messages": [
{
"content": {
"type": "text",
"text": "There are 5 namespaces, context 'k3d-mcp-k8s-integration-test':"
},
"role": "user"
},
{
"content": {
"type": "text",
"text": "{\"name\":\"default\"}"
},
"role": "user"
},
{
"content": {
"type": "text",
"text": "{\"name\":\"kube-node-lease\"}"
},
"role": "user"
},
{
"content": {
"type": "text",
"text": "{\"name\":\"kube-public\"}"
},
"role": "user"
},
{
"content": {
"type": "text",
"text": "{\"name\":\"kube-system\"}"
},
"role": "user"
},
{
"content": {
"type": "text",
"text": "{\"name\":\"test\"}"
},
"role": "user"
}
]
}
}

0 comments on commit db46388

Please sign in to comment.