Skip to content

Commit 0157893

Browse files
authored
mcp: adds labels and envs config tools and resources (knative#2931)
Signed-off-by: kapil <[email protected]>
1 parent 860e063 commit 0157893

File tree

3 files changed

+189
-3
lines changed

3 files changed

+189
-3
lines changed

pkg/mcp/help.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66
"os/exec"
7+
"strings"
78

89
"github.com/mark3labs/mcp-go/mcp"
910
)
@@ -44,6 +45,11 @@ func handleCmdHelpPrompt(ctx context.Context, request mcp.GetPromptRequest) (*mc
4445
return nil, fmt.Errorf("cmd is required")
4546
}
4647

48+
parts := strings.Fields(cmd)
49+
if len(parts) == 0 {
50+
return nil, fmt.Errorf("invalid cmd: %s", cmd)
51+
}
52+
4753
return mcp.NewGetPromptResult(
4854
"Cmd Help Prompt",
4955
[]mcp.PromptMessage{
@@ -54,7 +60,7 @@ func handleCmdHelpPrompt(ctx context.Context, request mcp.GetPromptRequest) (*mc
5460
mcp.NewPromptMessage(
5561
mcp.RoleAssistant,
5662
mcp.NewEmbeddedResource(mcp.TextResourceContents{
57-
URI: fmt.Sprintf("func://%s/docs", cmd),
63+
URI: fmt.Sprintf("func://%s/docs", strings.Join(parts, "/")),
5864
MIMEType: "text/plain",
5965
}),
6066
),

pkg/mcp/mcp.go

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,47 @@ func NewServer() *MCPServer {
177177
),
178178
handleConfigVolumesTool,
179179
)
180+
181+
mcpServer.AddTool(
182+
mcp.NewTool("config_labels",
183+
mcp.WithDescription("Lists and manages labels for a function"),
184+
mcp.WithString("action",
185+
mcp.Required(),
186+
mcp.Description("The action to perform: 'add' to add a label, 'remove' to remove a label, 'list' to list labels"),
187+
),
188+
mcp.WithString("path",
189+
mcp.Required(),
190+
mcp.Description("Path to the function. Default is current directory ($FUNC_PATH)"),
191+
),
192+
193+
// Optional flags
194+
mcp.WithString("name", mcp.Description("Name of the label.")),
195+
mcp.WithString("value", mcp.Description("Value of the label.")),
196+
mcp.WithBoolean("verbose", mcp.Description("Print verbose logs ($FUNC_VERBOSE)")),
197+
),
198+
handleConfigLabelsTool,
199+
)
200+
201+
mcpServer.AddTool(
202+
mcp.NewTool("config_envs",
203+
mcp.WithDescription("Lists and manages environment variables for a function"),
204+
mcp.WithString("action",
205+
mcp.Required(),
206+
mcp.Description("The action to perform: 'add' to add an env var, 'remove' to remove, 'list' to list env vars"),
207+
),
208+
mcp.WithString("path",
209+
mcp.Required(),
210+
mcp.Description("Path to the function. Default is current directory ($FUNC_PATH)"),
211+
),
212+
213+
// Optional flags
214+
mcp.WithString("name", mcp.Description("Name of the environment variable.")),
215+
mcp.WithString("value", mcp.Description("Value of the environment variable.")),
216+
mcp.WithBoolean("verbose", mcp.Description("Print verbose logs ($FUNC_VERBOSE)")),
217+
),
218+
handleConfigEnvsTool,
219+
)
220+
180221
mcpServer.AddResource(mcp.NewResource(
181222
"func://docs",
182223
"Root Help Command",
@@ -245,7 +286,43 @@ func NewServer() *MCPServer {
245286
mcp.WithResourceDescription("--help output of the 'config volumes remove' command"),
246287
mcp.WithMIMEType("text/plain"),
247288
), func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
248-
return runHelpCommand([]string{"config", "volumes", "remove"}, "func://config/volumes/add/docs")
289+
return runHelpCommand([]string{"config", "volumes", "remove"}, "func://config/volumes/remove/docs")
290+
})
291+
292+
mcpServer.AddResource(mcp.NewResource(
293+
"func://config/labels/add/docs",
294+
"Config Labels Add Command Help",
295+
mcp.WithResourceDescription("--help output of the 'config labels add' command"),
296+
mcp.WithMIMEType("text/plain"),
297+
), func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
298+
return runHelpCommand([]string{"config", "labels", "add"}, "func://config/labels/add/docs")
299+
})
300+
301+
mcpServer.AddResource(mcp.NewResource(
302+
"func://config/labels/remove/docs",
303+
"Config Labels Remove Command Help",
304+
mcp.WithResourceDescription("--help output of the 'config labels remove' command"),
305+
mcp.WithMIMEType("text/plain"),
306+
), func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
307+
return runHelpCommand([]string{"config", "labels", "remove"}, "func://config/labels/remove/docs")
308+
})
309+
310+
mcpServer.AddResource(mcp.NewResource(
311+
"func://config/envs/add/docs",
312+
"Config Envs Add Command Help",
313+
mcp.WithResourceDescription("--help output of the 'config envs add' command"),
314+
mcp.WithMIMEType("text/plain"),
315+
), func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
316+
return runHelpCommand([]string{"config", "envs", "add"}, "func://config/envs/add/docs")
317+
})
318+
319+
mcpServer.AddResource(mcp.NewResource(
320+
"func://config/envs/remove/docs",
321+
"Config Envs Remove Command Help",
322+
mcp.WithResourceDescription("--help output of the 'config envs remove' command"),
323+
mcp.WithMIMEType("text/plain"),
324+
), func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
325+
return runHelpCommand([]string{"config", "envs", "remove"}, "func://config/envs/remove/docs")
249326
})
250327

251328
mcpServer.AddPrompt(mcp.NewPrompt("help",

pkg/mcp/tools.go

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,6 @@ func handleConfigVolumesTool(
293293
return mcp.NewToolResultError(err.Error()), nil
294294
}
295295
if action == "list" {
296-
// For 'list' action, we don't need other parameters, only --path
297296
args := []string{"config", "volumes", "--path", path}
298297
if request.GetBool("verbose", false) {
299298
args = append(args, "--verbose")
@@ -349,3 +348,107 @@ func handleConfigVolumesTool(
349348
body := []byte(fmt.Sprintf(`{"result": "%s"}`, out))
350349
return mcp.NewToolResultText(string(body)), nil
351350
}
351+
352+
func handleConfigLabelsTool(
353+
ctx context.Context,
354+
request mcp.CallToolRequest,
355+
) (*mcp.CallToolResult, error) {
356+
action, err := request.RequireString("action")
357+
if err != nil {
358+
return mcp.NewToolResultError(err.Error()), nil
359+
}
360+
path, err := request.RequireString("path")
361+
if err != nil {
362+
return mcp.NewToolResultError(err.Error()), nil
363+
}
364+
365+
if action == "list" {
366+
args := []string{"config", "labels", "--path", path}
367+
if request.GetBool("verbose", false) {
368+
args = append(args, "--verbose")
369+
}
370+
371+
cmd := exec.Command("func", args...)
372+
out, err := cmd.CombinedOutput()
373+
if err != nil {
374+
return mcp.NewToolResultError(fmt.Sprintf("func config labels list failed: %s", out)), nil
375+
}
376+
body := []byte(fmt.Sprintf(`{"result": "%s"}`, out))
377+
return mcp.NewToolResultText(string(body)), nil
378+
}
379+
380+
args := []string{"config", "labels", action, "--path", path}
381+
382+
// Optional flags
383+
if name := request.GetString("name", ""); name != "" {
384+
args = append(args, "--name", name)
385+
}
386+
if value := request.GetString("value", ""); value != "" {
387+
args = append(args, "--value", value)
388+
}
389+
if request.GetBool("verbose", false) {
390+
args = append(args, "--verbose")
391+
}
392+
393+
cmd := exec.Command("func", args...)
394+
out, err := cmd.CombinedOutput()
395+
if err != nil {
396+
return mcp.NewToolResultError(fmt.Sprintf("func config labels %s failed: %s", action, out)), nil
397+
}
398+
399+
body := []byte(fmt.Sprintf(`{"result": "%s"}`, out))
400+
return mcp.NewToolResultText(string(body)), nil
401+
}
402+
403+
func handleConfigEnvsTool(
404+
ctx context.Context,
405+
request mcp.CallToolRequest,
406+
) (*mcp.CallToolResult, error) {
407+
action, err := request.RequireString("action")
408+
if err != nil {
409+
return mcp.NewToolResultError(err.Error()), nil
410+
}
411+
path, err := request.RequireString("path")
412+
if err != nil {
413+
return mcp.NewToolResultError(err.Error()), nil
414+
}
415+
416+
// Handle 'list' action separately
417+
if action == "list" {
418+
args := []string{"config", "envs", "--path", path}
419+
if request.GetBool("verbose", false) {
420+
args = append(args, "--verbose")
421+
}
422+
423+
cmd := exec.Command("func", args...)
424+
out, err := cmd.CombinedOutput()
425+
if err != nil {
426+
return mcp.NewToolResultError(fmt.Sprintf("func config envs list failed: %s", out)), nil
427+
}
428+
body := []byte(fmt.Sprintf(`{"result": "%s"}`, out))
429+
return mcp.NewToolResultText(string(body)), nil
430+
}
431+
432+
// Handle 'add' and 'remove' actions
433+
args := []string{"config", "envs", action, "--path", path}
434+
435+
// Optional flags
436+
if name := request.GetString("name", ""); name != "" {
437+
args = append(args, "--name", name)
438+
}
439+
if value := request.GetString("value", ""); value != "" {
440+
args = append(args, "--value", value)
441+
}
442+
if request.GetBool("verbose", false) {
443+
args = append(args, "--verbose")
444+
}
445+
446+
cmd := exec.Command("func", args...)
447+
out, err := cmd.CombinedOutput()
448+
if err != nil {
449+
return mcp.NewToolResultError(fmt.Sprintf("func config envs %s failed: %s", action, out)), nil
450+
}
451+
452+
body := []byte(fmt.Sprintf(`{"result": "%s"}`, out))
453+
return mcp.NewToolResultText(string(body)), nil
454+
}

0 commit comments

Comments
 (0)