Skip to content

Commit

Permalink
added: go_template input for get resource tool
Browse files Browse the repository at this point in the history
  • Loading branch information
strowk committed Jan 19, 2025
1 parent c0652ea commit 1670381
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 12 deletions.
2 changes: 1 addition & 1 deletion internal/content/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"github.com/strowk/foxy-contexts/pkg/mcp"
)

func NewJsonContent(v interface{}) (mcp.TextContent, error) {
func NewJsonContent(v any) (mcp.TextContent, error) {
contents, err := json.Marshal(v)
if err != nil {
return mcp.TextContent{}, err
Expand Down
54 changes: 48 additions & 6 deletions internal/k8s/apps/v1/deployment/get_deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package deployment

import (
"context"
"encoding/json"
"html/template"
"strings"

"github.com/strowk/foxy-contexts/pkg/mcp"
"github.com/strowk/mcp-k8s-go/internal/content"
Expand All @@ -11,20 +14,59 @@ import (
"k8s.io/client-go/kubernetes"
)

func GetDeployment(clientset kubernetes.Interface, namespace string, name string) *mcp.CallToolResult {
func GetDeployment(
clientset kubernetes.Interface,
namespace string,
name string,
templateStr string,
) *mcp.CallToolResult {
deployment, err := clientset.AppsV1().Deployments(namespace).Get(context.Background(), name, metav1.GetOptions{})
if err != nil {
return utils.ErrResponse(err)
}
utils.SanitizeObjectMeta(&deployment.ObjectMeta)

c, err := content.NewJsonContent(deployment)
if err != nil {
return utils.ErrResponse(err)
var cnt interface{}
if templateStr != "" {
tmpl, err := template.New("template").Parse(templateStr)
if err != nil {
return utils.ErrResponse(err)
}

// transforming deployment to JSON and back so that it has clear structure
parsedDeployment, err := json.Marshal(deployment)
if err != nil {
return utils.ErrResponse(err)
}

var parsedDeploymentMap map[string]interface{}
err = json.Unmarshal(parsedDeployment, &parsedDeploymentMap)
if err != nil {
return utils.ErrResponse(err)
}

buf := new(strings.Builder)

err = tmpl.Execute(buf, parsedDeploymentMap)
if err != nil {
return utils.ErrResponse(err)
}

cnt = mcp.TextContent{
Type: "text",
Text: buf.String(),
}
} else {
utils.SanitizeObjectMeta(&deployment.ObjectMeta)
c, err := content.NewJsonContent(deployment)
if err != nil {
return utils.ErrResponse(err)
}
cnt = c
}

return &mcp.CallToolResult{
Meta: map[string]interface{}{},
Content: []interface{}{c},
Content: []interface{}{cnt},
IsError: utils.Ptr(false),
}
}
31 changes: 31 additions & 0 deletions internal/k8s/apps/v1/deployment/get_deployment_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,34 @@ out:
"isError": false,
},
}

---
case: Get k8s deployment name
in:
{
"jsonrpc": "2.0",
"method": "tools/call",
"id": 2,
"params":
{
"name": "get-k8s-resource",
"arguments":
{
"context": "k3d-mcp-k8s-integration-test",
"namespace": "test-deployment",
"kind": "deployment",
"name": "nginx-deployment",
"go_template": "{{ .metadata.name }}",
},
},
}
out:
{
"jsonrpc": "2.0",
"id": 2,
"result":
{
"content": [{ "type": "text", "text": "nginx-deployment" }],
"isError": false,
},
}
28 changes: 28 additions & 0 deletions internal/k8s/core/v1/pod/get_pod_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,31 @@ out:
"isError": false,
},
}

---
case: Get k8s pod dnsPolicy
in:
{
"jsonrpc": "2.0",
"method": "tools/call",
"id": 2,
"params":
{
"name": "get-k8s-resource",
"arguments":
{
"context": "k3d-mcp-k8s-integration-test",
"namespace": "test",
"kind": "pod",
"name": "nginx",
"go_template": "{{ .spec.dnsPolicy }}",
},
},
}
out:
{
"jsonrpc": "2.0",
"id": 2,
"result":
{ "content": [{ "type": "text", "text": "ClusterFirst" }], "isError": false },
}
33 changes: 28 additions & 5 deletions internal/tools/get_resource_tool.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package tools
import (
"context"
"fmt"
"html/template"
"strings"

"github.com/strowk/foxy-contexts/pkg/fxctx"
Expand All @@ -26,6 +27,7 @@ func NewGetResourceTool(pool k8s.ClientPool) fxctx.Tool {
groupProperty := "group"
versionProperty := "version"
nameProperty := "name"
templateProperty := "go_template"

inputSchema := toolinput.NewToolInputSchema(
toolinput.WithString(contextProperty, "Name of the Kubernetes context to use, defaults to current context"),
Expand All @@ -34,6 +36,7 @@ func NewGetResourceTool(pool k8s.ClientPool) fxctx.Tool {
toolinput.WithString(versionProperty, "API Version of the resource to get"),
toolinput.WithRequiredString(kindProperty, "Kind of resource to get"),
toolinput.WithRequiredString(nameProperty, "Name of the resource to get"),
toolinput.WithString(templateProperty, "Go template to render the output, if not specified, the complete JSON object will be returned"),
)

return fxctx.NewTool(
Expand Down Expand Up @@ -72,8 +75,10 @@ func NewGetResourceTool(pool k8s.ClientPool) fxctx.Tool {
return utils.ErrResponse(err)
}

templateStr := input.StringOr(templateProperty, "")

if strings.ToLower(kind) == "deployment" && (group == "apps" || group == "") && (version == "v1" || version == "") {
return deployment.GetDeployment(clientset, namespace, name)
return deployment.GetDeployment(clientset, namespace, name, templateStr)
}

res, err := clientset.Discovery().ServerPreferredResources()
Expand Down Expand Up @@ -120,11 +125,29 @@ func NewGetResourceTool(pool k8s.ClientPool) fxctx.Tool {
}
}

cnt, err := content.NewJsonContent(unstructured.Object)
if err != nil {
return utils.ErrResponse(err)
var cnt any
if templateStr != "" {
tmpl, err := template.New("template").Parse(templateStr)
if err != nil {
return utils.ErrResponse(err)
}
buf := new(strings.Builder)
err = tmpl.Execute(buf, object)
if err != nil {
return utils.ErrResponse(err)
}
cnt = mcp.TextContent{
Type: "text",
Text: buf.String(),
}
} else {
c, err := content.NewJsonContent(object)
if err != nil {
return utils.ErrResponse(err)
}
cnt = c
}
var contents = []interface{}{cnt}
var contents = []any{cnt}

return &mcp.CallToolResult{
Meta: map[string]interface{}{},
Expand Down

0 comments on commit 1670381

Please sign in to comment.