mcp: extends flags support for existing tools (#2889)

Signed-off-by: kapil <kapilsareen584@gmail.com>
This commit is contained in:
Kapil Sareen 2025-06-27 09:07:06 +05:30 committed by GitHub
parent 9a71fa4725
commit a90f07fdfb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 237 additions and 42 deletions

View File

@ -29,19 +29,25 @@ func NewServer() *MCPServer {
mcpServer.AddTool( mcpServer.AddTool(
mcp.NewTool("create", mcp.NewTool("create",
mcp.WithDescription("Creates a knative function in the current directory"), mcp.WithDescription("Creates a Knative function project in the current or specified directory"),
mcp.WithString("name",
mcp.Required(),
mcp.Description("Name of the function to be created"),
),
mcp.WithString("language",
mcp.Required(),
mcp.Description("Language/Runtime of the function to be created"),
),
mcp.WithString("cwd", mcp.WithString("cwd",
mcp.Required(), mcp.Required(),
mcp.Description("Current working directory of the MCP client"), mcp.Description("Current working directory of the MCP client"),
), ),
mcp.WithString("name",
mcp.Required(),
mcp.Description("Name of the function to be created (used as subdirectory)"),
),
mcp.WithString("language",
mcp.Required(),
mcp.Description("Language runtime to use (e.g., node, go, python)"),
),
// Optional flags
mcp.WithString("template", mcp.Description("Function template (e.g., http, cloudevents)")),
mcp.WithString("repository", mcp.Description("URI to Git repo containing the template")),
mcp.WithBoolean("confirm", mcp.Description("Prompt to confirm options interactively")),
mcp.WithBoolean("verbose", mcp.Description("Print verbose logs")),
), ),
handleCreateTool, handleCreateTool,
) )
@ -51,7 +57,7 @@ func NewServer() *MCPServer {
mcp.WithDescription("Deploys the function to the cluster"), mcp.WithDescription("Deploys the function to the cluster"),
mcp.WithString("registry", mcp.WithString("registry",
mcp.Required(), mcp.Required(),
mcp.Description("Name of the registry to be used to push the function image"), mcp.Description("Registry to be used to push the function image"),
), ),
mcp.WithString("cwd", mcp.WithString("cwd",
mcp.Required(), mcp.Required(),
@ -61,17 +67,41 @@ func NewServer() *MCPServer {
mcp.Required(), mcp.Required(),
mcp.Description("Builder to be used to build the function image"), mcp.Description("Builder to be used to build the function image"),
), ),
mcp.WithBoolean("remote",
mcp.DefaultBool(false), // Optional flags
mcp.Description("If true, the function will be deployed remotely"), mcp.WithString("image", mcp.Description("Full image name (overrides registry)")),
), mcp.WithString("namespace", mcp.Description("Namespace to deploy the function into")),
mcp.WithString("git-url", mcp.Description("Git URL containing the function source")),
mcp.WithString("git-branch", mcp.Description("Git branch for remote deployment")),
mcp.WithString("git-dir", mcp.Description("Directory inside the Git repository")),
mcp.WithString("builder-image", mcp.Description("Custom builder image")),
mcp.WithString("domain", mcp.Description("Domain for the function route")),
mcp.WithString("platform", mcp.Description("Target platform to build for (e.g., linux/amd64)")),
mcp.WithString("path", mcp.Description("Path to the function directory")),
mcp.WithString("build", mcp.Description(`Build control: "true", "false", or "auto"`)),
mcp.WithString("pvc-size", mcp.Description("Custom volume size for remote builds")),
mcp.WithString("service-account", mcp.Description("Kubernetes ServiceAccount to use")),
mcp.WithString("remote-storage-class", mcp.Description("Storage class for remote volume")),
mcp.WithBoolean("confirm", mcp.Description("Prompt for confirmation before deploying")),
mcp.WithBoolean("push", mcp.Description("Push image to registry before deployment")),
mcp.WithBoolean("verbose", mcp.Description("Print verbose logs")),
mcp.WithBoolean("registry-insecure", mcp.Description("Skip TLS verification for registry")),
mcp.WithBoolean("build-timestamp", mcp.Description("Use actual time in image metadata")),
mcp.WithBoolean("remote", mcp.Description("Trigger remote deployment")),
), ),
handleDeployTool, handleDeployTool,
) )
mcpServer.AddTool( mcpServer.AddTool(
mcp.NewTool("list", mcp.NewTool("list",
mcp.WithDescription("Lists all the functions deployed in the cluster"), mcp.WithDescription("Lists all deployed functions in the current or specified namespace"),
// Optional flags
mcp.WithBoolean("all-namespaces", mcp.Description("List functions in all namespaces (overrides --namespace)")),
mcp.WithString("namespace", mcp.Description("The namespace to list functions in (default is current/active)")),
mcp.WithString("output", mcp.Description("Output format: human, plain, json, xml, yaml")),
mcp.WithBoolean("verbose", mcp.Description("Enable verbose output")),
), ),
handleListTool, handleListTool,
) )
@ -85,12 +115,24 @@ func NewServer() *MCPServer {
), ),
mcp.WithString("builder", mcp.WithString("builder",
mcp.Required(), mcp.Required(),
mcp.Description("Builder to be used to build the function image"), mcp.Description("Builder to be used to build the function image (pack, s2i, host)"),
), ),
mcp.WithString("registry", mcp.WithString("registry",
mcp.Required(), mcp.Required(),
mcp.Description("Name of the registry to be used to push the function image"), mcp.Description("Registry to be used to push the function image (e.g. ghcr.io/user)"),
), ),
// Optional flags
mcp.WithString("builder-image", mcp.Description("Custom builder image to use with buildpacks")),
mcp.WithString("image", mcp.Description("Full image name (overrides registry + function name)")),
mcp.WithString("path", mcp.Description("Path to the function directory (default is current dir)")),
mcp.WithString("platform", mcp.Description("Target platform, e.g. linux/amd64 (for s2i builds)")),
mcp.WithBoolean("confirm", mcp.Description("Prompt for confirmation before proceeding")),
mcp.WithBoolean("push", mcp.Description("Push image to registry after building")),
mcp.WithBoolean("verbose", mcp.Description("Enable verbose logging output")),
mcp.WithBoolean("registry-insecure", mcp.Description("Skip TLS verification for insecure registries")),
mcp.WithBoolean("build-timestamp", mcp.Description("Use actual time for image timestamp (buildpacks only)")),
), ),
handleBuildTool, handleBuildTool,
) )
@ -102,6 +144,14 @@ func NewServer() *MCPServer {
mcp.Required(), mcp.Required(),
mcp.Description("Name of the function to be deleted"), mcp.Description("Name of the function to be deleted"),
), ),
// Optional flags
mcp.WithString("namespace", mcp.Description("Namespace to delete from (default: current or active)")),
mcp.WithString("path", mcp.Description("Path to the function project (default is current directory)")),
mcp.WithString("all", mcp.Description(`Delete all related resources like Pipelines, Secrets ("true"/"false")`)),
mcp.WithBoolean("confirm", mcp.Description("Prompt to confirm before deletion")),
mcp.WithBoolean("verbose", mcp.Description("Enable verbose output")),
), ),
handleDeleteTool, handleDeleteTool,
) )
@ -185,12 +235,33 @@ func handleCreateTool(
return mcp.NewToolResultError(err.Error()), nil return mcp.NewToolResultError(err.Error()), nil
} }
cmd := exec.Command("func", "create", "-l", language, name) args := []string{"create", "-l", language}
cmd.Dir = cwd
out, err := cmd.Output() // Optional flags
if err != nil { if v := request.GetString("template", ""); v != "" {
return mcp.NewToolResultError(err.Error()), nil args = append(args, "--template", v)
} }
if v := request.GetString("repository", ""); v != "" {
args = append(args, "--repository", v)
}
if request.GetBool("confirm", false) {
args = append(args, "--confirm")
}
if request.GetBool("verbose", false) {
args = append(args, "--verbose")
}
// `name` is passed as a positional argument (directory to create in)
args = append(args, name)
cmd := exec.Command("func", args...)
cmd.Dir = cwd
out, err := cmd.CombinedOutput()
if err != nil {
return mcp.NewToolResultError(fmt.Sprintf("func create failed: %s", out)), nil
}
body := []byte(fmt.Sprintf(`{"result": "%s"}`, out)) body := []byte(fmt.Sprintf(`{"result": "%s"}`, out))
return mcp.NewToolResultText(string(body)), nil return mcp.NewToolResultText(string(body)), nil
} }
@ -211,20 +282,74 @@ func handleDeployTool(
if err != nil { if err != nil {
return mcp.NewToolResultError(err.Error()), nil return mcp.NewToolResultError(err.Error()), nil
} }
remote, err := request.RequireBool("remote")
if err != nil { args := []string{"deploy", "--builder", builder, "--registry", registry}
return mcp.NewToolResultError(err.Error()), nil
// Optional flags
if v := request.GetString("image", ""); v != "" {
args = append(args, "--image", v)
} }
var cmd *exec.Cmd if v := request.GetString("namespace", ""); v != "" {
if remote { args = append(args, "--namespace", v)
cmd = exec.Command("func", "deploy", "--registry", registry, "--builder", builder, "--remote")
} else {
cmd = exec.Command("func", "deploy", "--registry", registry, "--builder", builder)
} }
if v := request.GetString("git-url", ""); v != "" {
args = append(args, "--git-url", v)
}
if v := request.GetString("git-branch", ""); v != "" {
args = append(args, "--git-branch", v)
}
if v := request.GetString("git-dir", ""); v != "" {
args = append(args, "--git-dir", v)
}
if v := request.GetString("builder-image", ""); v != "" {
args = append(args, "--builder-image", v)
}
if v := request.GetString("domain", ""); v != "" {
args = append(args, "--domain", v)
}
if v := request.GetString("platform", ""); v != "" {
args = append(args, "--platform", v)
}
if v := request.GetString("path", ""); v != "" {
args = append(args, "--path", v)
}
if v := request.GetString("build", ""); v != "" {
args = append(args, "--build", v)
}
if v := request.GetString("pvc-size", ""); v != "" {
args = append(args, "--pvc-size", v)
}
if v := request.GetString("service-account", ""); v != "" {
args = append(args, "--service-account", v)
}
if v := request.GetString("remote-storage-class", ""); v != "" {
args = append(args, "--remote-storage-class", v)
}
if request.GetBool("confirm", false) {
args = append(args, "--confirm")
}
if request.GetBool("push", false) {
args = append(args, "--push")
}
if request.GetBool("verbose", false) {
args = append(args, "--verbose")
}
if request.GetBool("registry-insecure", false) {
args = append(args, "--registry-insecure")
}
if request.GetBool("build-timestamp", false) {
args = append(args, "--build-timestamp")
}
if request.GetBool("remote", false) {
args = append(args, "--remote")
}
cmd := exec.Command("func", args...)
cmd.Dir = cwd cmd.Dir = cwd
out, err := cmd.Output() out, err := cmd.CombinedOutput()
if err != nil { if err != nil {
return mcp.NewToolResultError(err.Error()), nil return mcp.NewToolResultError(fmt.Sprintf("func deploy failed: %s", out)), nil
} }
body := []byte(fmt.Sprintf(`{"result": "%s"}`, out)) body := []byte(fmt.Sprintf(`{"result": "%s"}`, out))
return mcp.NewToolResultText(string(body)), nil return mcp.NewToolResultText(string(body)), nil
@ -234,10 +359,26 @@ func handleListTool(
ctx context.Context, ctx context.Context,
request mcp.CallToolRequest, request mcp.CallToolRequest,
) (*mcp.CallToolResult, error) { ) (*mcp.CallToolResult, error) {
cmd := exec.Command("func", "list") args := []string{"list"}
out, err := cmd.Output()
// Optional flags
if request.GetBool("all-namespaces", false) {
args = append(args, "--all-namespaces")
}
if v := request.GetString("namespace", ""); v != "" {
args = append(args, "--namespace", v)
}
if v := request.GetString("output", ""); v != "" {
args = append(args, "--output", v)
}
if request.GetBool("verbose", false) {
args = append(args, "--verbose")
}
cmd := exec.Command("func", args...)
out, err := cmd.CombinedOutput()
if err != nil { if err != nil {
return mcp.NewToolResultError(err.Error()), nil return mcp.NewToolResultError(fmt.Sprintf("func list failed: %s", out)), nil
} }
body := []byte(fmt.Sprintf(`{"result": "%s"}`, out)) body := []byte(fmt.Sprintf(`{"result": "%s"}`, out))
return mcp.NewToolResultText(string(body)), nil return mcp.NewToolResultText(string(body)), nil
@ -260,11 +401,43 @@ func handleBuildTool(
return mcp.NewToolResultError(err.Error()), nil return mcp.NewToolResultError(err.Error()), nil
} }
cmd := exec.Command("func", "build", "--builder", builder, "--registry", registry) args := []string{"build", "--builder", builder, "--registry", registry}
// Optional flags
if v := request.GetString("builder-image", ""); v != "" {
args = append(args, "--builder-image", v)
}
if v := request.GetString("image", ""); v != "" {
args = append(args, "--image", v)
}
if v := request.GetString("path", ""); v != "" {
args = append(args, "--path", v)
}
if v := request.GetString("platform", ""); v != "" {
args = append(args, "--platform", v)
}
if v := request.GetBool("confirm", false); v {
args = append(args, "--confirm")
}
if v := request.GetBool("push", false); v {
args = append(args, "--push")
}
if v := request.GetBool("verbose", false); v {
args = append(args, "--verbose")
}
if v := request.GetBool("registry-insecure", false); v {
args = append(args, "--registry-insecure")
}
if v := request.GetBool("build-timestamp", false); v {
args = append(args, "--build-timestamp")
}
cmd := exec.Command("func", args...)
cmd.Dir = cwd cmd.Dir = cwd
out, err := cmd.Output() out, err := cmd.CombinedOutput()
if err != nil { if err != nil {
return mcp.NewToolResultError(err.Error()), nil return mcp.NewToolResultError(fmt.Sprintf("func build failed: %s", out)), nil
} }
body := []byte(fmt.Sprintf(`{"result": "%s"}`, out)) body := []byte(fmt.Sprintf(`{"result": "%s"}`, out))
return mcp.NewToolResultText(string(body)), nil return mcp.NewToolResultText(string(body)), nil
@ -278,11 +451,33 @@ func handleDeleteTool(
if err != nil { if err != nil {
return mcp.NewToolResultError(err.Error()), nil return mcp.NewToolResultError(err.Error()), nil
} }
cmd := exec.Command("func", "delete", name)
out, err := cmd.Output() args := []string{"delete", name}
if err != nil {
return mcp.NewToolResultError(err.Error()), nil // Optional flags
if v := request.GetString("namespace", ""); v != "" {
args = append(args, "--namespace", v)
} }
if v := request.GetString("path", ""); v != "" {
args = append(args, "--path", v)
}
if v := request.GetString("all", ""); v != "" {
args = append(args, "--all", v)
}
if request.GetBool("confirm", false) {
args = append(args, "--confirm")
}
if request.GetBool("verbose", false) {
args = append(args, "--verbose")
}
cmd := exec.Command("func", args...)
out, err := cmd.CombinedOutput()
if err != nil {
return mcp.NewToolResultError(fmt.Sprintf("func delete failed: %s", out)), nil
}
body := []byte(fmt.Sprintf(`{"result": "%s"}`, out)) body := []byte(fmt.Sprintf(`{"result": "%s"}`, out))
return mcp.NewToolResultText(string(body)), nil return mcp.NewToolResultText(string(body)), nil
} }