1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-10-30 23:58:09 +02:00

refactor: use official mcp library (#6175)

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>
This commit is contained in:
Carlos Alexandro Becker
2025-10-17 08:49:42 -03:00
committed by GitHub
parent 10ecdb0f0e
commit f9f04f30c8
3 changed files with 74 additions and 59 deletions

View File

@@ -12,8 +12,7 @@ import (
goversion "github.com/caarlos0/go-version"
"github.com/goreleaser/goreleaser/v2/internal/pipe/defaults"
"github.com/goreleaser/goreleaser/v2/pkg/context"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
"github.com/modelcontextprotocol/go-sdk/mcp"
"github.com/spf13/cobra"
)
@@ -31,54 +30,39 @@ func newMcpCmd(version goversion.Info) *mcpCmd {
SilenceErrors: true,
Args: cobra.NoArgs,
ValidArgsFunction: cobra.NoFileCompletions,
RunE: func(*cobra.Command, []string) error {
RunE: func(cmd *cobra.Command, _ []string) error {
bin, err := os.Executable()
if err != nil {
return err
}
root.bin = bin
s := server.NewMCPServer("goreleaser", version.GitVersion)
s.AddTool(
mcp.NewTool(
"check",
mcp.WithDescription("Checks a GoReleaser configuration for errors or deprecations"),
mcp.WithString("configuration",
mcp.Title("GoReleaser config file"),
mcp.Description("Path to the goreleaser YAML configuration file. If empty will use the default."),
),
mcp.WithReadOnlyHintAnnotation(true),
),
root.check,
)
server := mcp.NewServer(&mcp.Implementation{
Name: "goreleaser",
Version: version.GitVersion,
}, nil)
s.AddTool(
mcp.NewTool(
"healthcheck",
mcp.WithDescription("Checks if GoReleaser has all the dependencies installed"),
),
root.healthcheck,
)
mcp.AddTool(server, &mcp.Tool{
Name: "check",
Description: "Checks a GoReleaser configuration for errors or deprecations",
}, root.check)
s.AddTool(
mcp.NewTool(
"build",
mcp.WithDescription("Builds the current project for the current platform"),
mcp.WithDestructiveHintAnnotation(true),
),
root.build,
)
mcp.AddTool(server, &mcp.Tool{
Name: "healthcheck",
Description: "Checks if GoReleaser has all the dependencies installed",
}, root.healthcheck)
s.AddTool(
mcp.NewTool(
"init",
mcp.WithDescription("Initializes GoReleaser in the current directory"),
mcp.WithDestructiveHintAnnotation(true),
),
root.init,
)
mcp.AddTool(server, &mcp.Tool{
Name: "build",
Description: "Builds the current project for the current platform",
}, root.build)
return server.ServeStdio(s)
mcp.AddTool(server, &mcp.Tool{
Name: "init",
Description: "Initializes GoReleaser in the current directory",
}, root.init)
return server.Run(cmd.Context(), &mcp.StdioTransport{})
},
}
@@ -86,19 +70,40 @@ func newMcpCmd(version goversion.Info) *mcpCmd {
return root
}
func (c *mcpCmd) init(ctx stdctx.Context, _ mcp.CallToolRequest) (*mcp.CallToolResult, error) {
type (
initArgs struct{}
initOutput struct {
Output string `json:"output"`
}
)
func (c *mcpCmd) init(ctx stdctx.Context, _ *mcp.CallToolRequest, _ initArgs) (*mcp.CallToolResult, initOutput, error) {
out, _ := exec.CommandContext(ctx, c.bin, "init").CombinedOutput()
return mcp.NewToolResultText(string(out)), nil
return nil, initOutput{Output: string(out)}, nil
}
func (c *mcpCmd) healthcheck(ctx stdctx.Context, _ mcp.CallToolRequest) (*mcp.CallToolResult, error) {
type (
healthcheckArgs struct{}
healthcheckOutput struct {
Output string `json:"output"`
}
)
func (c *mcpCmd) healthcheck(ctx stdctx.Context, _ *mcp.CallToolRequest, _ healthcheckArgs) (*mcp.CallToolResult, healthcheckOutput, error) {
out, _ := exec.CommandContext(ctx, c.bin, "healthcheck").CombinedOutput()
return mcp.NewToolResultText(string(out)), nil
return nil, healthcheckOutput{Output: string(out)}, nil
}
func (c *mcpCmd) build(ctx stdctx.Context, _ mcp.CallToolRequest) (*mcp.CallToolResult, error) {
type (
buildArgs struct{}
buildOutput struct {
Output string `json:"output"`
}
)
func (c *mcpCmd) build(ctx stdctx.Context, _ *mcp.CallToolRequest, _ buildArgs) (*mcp.CallToolResult, buildOutput, error) {
out, _ := exec.CommandContext(ctx, c.bin, "build", "--snapshot", "--clean", "--single-target", "-o", ".").CombinedOutput()
return mcp.NewToolResultText(string(out)), nil
return nil, buildOutput{Output: string(out)}, nil
}
var instructions = map[string]string{
@@ -116,16 +121,24 @@ var instructions = map[string]string{
"snapshot.name_template": "rename `name_template` to `version_template`",
}
func (*mcpCmd) check(ctx stdctx.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
input := request.GetString("configuration", "")
cfg, path, err := loadConfigCheck(input)
type (
checkArgs struct {
Configuration string `json:"configuration" jsonschema:"Path to the goreleaser YAML configuration file. If empty will use the default."`
}
checkOutput struct {
Message string `json:"message"`
}
)
func (*mcpCmd) check(ctx stdctx.Context, _ *mcp.CallToolRequest, args checkArgs) (*mcp.CallToolResult, checkOutput, error) {
cfg, path, err := loadConfigCheck(args.Configuration)
if err != nil {
return mcp.NewToolResultErrorFromErr("Configuration is invalid", err), nil
return nil, checkOutput{}, fmt.Errorf("configuration is invalid: %w", err)
}
gctx := context.Wrap(ctx, cfg)
if err := (defaults.Pipe{}).Run(gctx); err != nil {
return mcp.NewToolResultErrorFromErr("Configuration is invalid", err), nil
return nil, checkOutput{}, fmt.Errorf("configuration is invalid: %w", err)
}
if gctx.Deprecated {
@@ -134,11 +147,10 @@ func (*mcpCmd) check(ctx stdctx.Context, request mcp.CallToolRequest) (*mcp.Call
for _, key := range slices.Collect(maps.Keys(gctx.NotifiedDeprecations)) {
sb.WriteString(fmt.Sprintf("## %s\n\nInstructions: %s\n\n", key, instructions[key]))
}
return mcp.NewToolResultText(sb.String()), nil
return nil, checkOutput{Message: sb.String()}, nil
}
return mcp.NewToolResultText(fmt.Sprintf(
"Configuration at %q is valid!",
path,
)), nil
return nil, checkOutput{
Message: fmt.Sprintf("Configuration at %q is valid!", path),
}, nil
}

3
go.mod
View File

@@ -35,9 +35,9 @@ require (
github.com/invopop/jsonschema v0.13.0
github.com/jarcoal/httpmock v1.4.1
github.com/klauspost/pgzip v1.2.6
github.com/mark3labs/mcp-go v0.41.1
github.com/mattn/go-mastodon v0.0.10
github.com/mitchellh/go-homedir v1.1.0
github.com/modelcontextprotocol/go-sdk v1.0.0
github.com/muesli/mango-cobra v1.3.0
github.com/muesli/roff v0.1.0
github.com/ory/dockertest/v3 v3.12.0
@@ -84,6 +84,7 @@ require (
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
github.com/go-chi/chi/v5 v5.2.2 // indirect
github.com/google/certificate-transparency-go v1.3.1 // indirect
github.com/google/jsonschema-go v0.3.0 // indirect
github.com/in-toto/attestation v1.1.1 // indirect
github.com/in-toto/in-toto-golang v0.9.0 // indirect
github.com/mattn/go-localereader v0.0.2-0.20220822084749-2491eb6c1c75 // indirect

6
go.sum
View File

@@ -492,6 +492,8 @@ github.com/google/go-replayers/httpreplay v1.2.0/go.mod h1:WahEFFZZ7a1P4VM1qEeHy
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/jsonschema-go v0.3.0 h1:6AH2TxVNtk3IlvkkhjrtbUc4S8AvO0Xii0DxIygDg+Q=
github.com/google/jsonschema-go v0.3.0/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
github.com/google/ko v0.18.0 h1:jkF5Fkvm+SMtqTt/SMzsCJO+6hz7FSDE6GRldGn0VVI=
github.com/google/ko v0.18.0/go.mod h1:iR0zT5aR4pINW9tk2Ujj99dBJ7cVy4to9ZirAkGKb9g=
github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc=
@@ -672,8 +674,6 @@ github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQ
github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
github.com/mark3labs/mcp-go v0.41.1 h1:w78eWfiQam2i8ICL7AL0WFiq7KHNJQ6UB53ZVtH4KGA=
github.com/mark3labs/mcp-go v0.41.1/go.mod h1:T7tUa2jO6MavG+3P25Oy/jR7iCeJPHImCZHRymCn39g=
github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ=
github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
@@ -712,6 +712,8 @@ github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo=
github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
github.com/modelcontextprotocol/go-sdk v1.0.0 h1:Z4MSjLi38bTgLrd/LjSmofqRqyBiVKRyQSJgw8q8V74=
github.com/modelcontextprotocol/go-sdk v1.0.0/go.mod h1:nYtYQroQ2KQiM0/SbyEPUWQ6xs4B95gJjEalc9AQyOs=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=