Skip to content

Commit e3759ec

Browse files
authored
mcp: adds tool and resource for config volumes (knative#2925)
Signed-off-by: kapil <[email protected]>
1 parent d9389fb commit e3759ec

File tree

1 file changed

+119
-7
lines changed

1 file changed

+119
-7
lines changed

pkg/mcp/mcp.go

Lines changed: 119 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,29 @@ func NewServer() *MCPServer {
156156
handleDeleteTool,
157157
)
158158

159+
mcpServer.AddTool(
160+
mcp.NewTool("config_volumes",
161+
mcp.WithDescription("Lists and manages configured volumes for a function"),
162+
mcp.WithString("action",
163+
mcp.Required(),
164+
mcp.Description("The action to perform: 'add' to add a volume, 'remove' to remove a volume, 'list' to list volumes"),
165+
),
166+
mcp.WithString("path",
167+
mcp.Required(),
168+
mcp.Description("Path to the function. Default is current directory ($FUNC_PATH)"),
169+
),
170+
171+
// Optional flags
172+
mcp.WithString("type", mcp.Description("Volume type: configmap, secret, pvc, or emptydir")),
173+
mcp.WithString("mount_path", mcp.Description("Mount path for the volume in the function container")),
174+
mcp.WithString("source", mcp.Description("Name of the ConfigMap, Secret, or PVC to mount (not used for emptydir)")),
175+
mcp.WithString("medium", mcp.Description("Storage medium for EmptyDir volume: 'Memory' or '' (default)")),
176+
mcp.WithString("size", mcp.Description("Maximum size limit for EmptyDir volume (e.g., 1Gi)")),
177+
mcp.WithBoolean("read_only", mcp.Description("Mount volume as read-only (only for PVC)")),
178+
mcp.WithBoolean("verbose", mcp.Description("Print verbose logs ($FUNC_VERBOSE)")),
179+
),
180+
handleConfigVolumesTool,
181+
)
159182
mcpServer.AddResource(mcp.NewResource(
160183
"func://docs",
161184
"Root Help Command",
@@ -170,7 +193,7 @@ func NewServer() *MCPServer {
170193
mcp.WithResourceDescription("--help output of the 'create' command"),
171194
mcp.WithMIMEType("text/plain"),
172195
), func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
173-
return runHelpCommand("create", "func://create/docs")
196+
return runHelpCommand([]string{"create"}, "func://create/docs")
174197
})
175198

176199
mcpServer.AddResource(mcp.NewResource(
@@ -179,7 +202,7 @@ func NewServer() *MCPServer {
179202
mcp.WithResourceDescription("--help output of the 'build' command"),
180203
mcp.WithMIMEType("text/plain"),
181204
), func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
182-
return runHelpCommand("build", "func://build/docs")
205+
return runHelpCommand([]string{"build"}, "func://build/docs")
183206
})
184207

185208
mcpServer.AddResource(mcp.NewResource(
@@ -188,7 +211,7 @@ func NewServer() *MCPServer {
188211
mcp.WithResourceDescription("--help output of the 'deploy' command"),
189212
mcp.WithMIMEType("text/plain"),
190213
), func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
191-
return runHelpCommand("deploy", "func://deploy/docs")
214+
return runHelpCommand([]string{"deploy"}, "func://deploy/docs")
192215
})
193216

194217
mcpServer.AddResource(mcp.NewResource(
@@ -197,7 +220,7 @@ func NewServer() *MCPServer {
197220
mcp.WithResourceDescription("--help output of the 'list' command"),
198221
mcp.WithMIMEType("text/plain"),
199222
), func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
200-
return runHelpCommand("list", "func://list/docs")
223+
return runHelpCommand([]string{"list"}, "func://list/docs")
201224
})
202225

203226
mcpServer.AddResource(mcp.NewResource(
@@ -206,7 +229,25 @@ func NewServer() *MCPServer {
206229
mcp.WithResourceDescription("--help output of the 'delete' command"),
207230
mcp.WithMIMEType("text/plain"),
208231
), func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
209-
return runHelpCommand("delete", "func://delete/docs")
232+
return runHelpCommand([]string{"delete"}, "func://delete/docs")
233+
})
234+
235+
mcpServer.AddResource(mcp.NewResource(
236+
"func://config/volumes/add/docs",
237+
"Config Volumes Add Command Help",
238+
mcp.WithResourceDescription("--help output of the 'config volumes add' command"),
239+
mcp.WithMIMEType("text/plain"),
240+
), func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
241+
return runHelpCommand([]string{"config", "volumes", "add"}, "func://config/volumes/add/docs")
242+
})
243+
244+
mcpServer.AddResource(mcp.NewResource(
245+
"func://config/volumes/remove/docs",
246+
"Config Volumes Remove Command Help",
247+
mcp.WithResourceDescription("--help output of the 'config volumes remove' command"),
248+
mcp.WithMIMEType("text/plain"),
249+
), func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
250+
return runHelpCommand([]string{"config", "volumes", "remove"}, "func://config/volumes/add/docs")
210251
})
211252

212253
mcpServer.AddPrompt(mcp.NewPrompt("help",
@@ -245,8 +286,9 @@ func handleRootHelpResource(ctx context.Context, request mcp.ReadResourceRequest
245286
}, nil
246287
}
247288

248-
func runHelpCommand(cmd string, uri string) ([]mcp.ResourceContents, error) {
249-
content, err := exec.Command("func", cmd, "--help").Output()
289+
func runHelpCommand(args []string, uri string) ([]mcp.ResourceContents, error) {
290+
args = append(args, "--help")
291+
content, err := exec.Command("func", args...).Output()
250292
if err != nil {
251293
return nil, err
252294
}
@@ -573,3 +615,73 @@ func handleDeleteTool(
573615
body := []byte(fmt.Sprintf(`{"result": "%s"}`, out))
574616
return mcp.NewToolResultText(string(body)), nil
575617
}
618+
619+
func handleConfigVolumesTool(
620+
ctx context.Context,
621+
request mcp.CallToolRequest,
622+
) (*mcp.CallToolResult, error) {
623+
action, err := request.RequireString("action")
624+
if err != nil {
625+
return mcp.NewToolResultError(err.Error()), nil
626+
}
627+
path, err := request.RequireString("path")
628+
if err != nil {
629+
return mcp.NewToolResultError(err.Error()), nil
630+
}
631+
if action == "list" {
632+
// For 'list' action, we don't need other parameters, only --path
633+
args := []string{"config", "volumes", "--path", path}
634+
if request.GetBool("verbose", false) {
635+
args = append(args, "--verbose")
636+
}
637+
638+
cmd := exec.Command("func", args...)
639+
out, err := cmd.CombinedOutput()
640+
if err != nil {
641+
return mcp.NewToolResultError(fmt.Sprintf("func config volumes list failed: %s", out)), nil
642+
}
643+
body := []byte(fmt.Sprintf(`{"result": "%s"}`, out))
644+
return mcp.NewToolResultText(string(body)), nil
645+
}
646+
647+
args := []string{"config", "volumes", action}
648+
649+
if action == "add" {
650+
volumeType, err := request.RequireString("type")
651+
if err != nil {
652+
return mcp.NewToolResultError(err.Error()), nil
653+
}
654+
args = append(args, "--type", volumeType)
655+
}
656+
mountPath, err := request.RequireString("mount_path")
657+
if err != nil {
658+
return mcp.NewToolResultError(err.Error()), nil
659+
}
660+
args = append(args, "--mount-path", mountPath, "--path", path)
661+
662+
// Optional flags
663+
if v := request.GetString("source", ""); v != "" {
664+
args = append(args, "--source", v)
665+
}
666+
if v := request.GetString("medium", ""); v != "" {
667+
args = append(args, "--medium", v)
668+
}
669+
if v := request.GetString("size", ""); v != "" {
670+
args = append(args, "--size", v)
671+
}
672+
if request.GetBool("read_only", false) {
673+
args = append(args, "--read-only")
674+
}
675+
if request.GetBool("verbose", false) {
676+
args = append(args, "--verbose")
677+
}
678+
679+
cmd := exec.Command("func", args...)
680+
out, err := cmd.CombinedOutput()
681+
if err != nil {
682+
return mcp.NewToolResultError(fmt.Sprintf("func config volumes failed: %s", out)), nil
683+
}
684+
685+
body := []byte(fmt.Sprintf(`{"result": "%s"}`, out))
686+
return mcp.NewToolResultText(string(body)), nil
687+
}

0 commit comments

Comments
 (0)