Files
gitea-mcp-extended/operation/repo/transfer.go
Andrew Miller 60f05e5f1e
Some checks failed
release-nightly / publish-nightly (push) Failing after 44s
release / goreleaser (push) Failing after 37s
release / publish-packages (push) Has been skipped
feat: rename to gitea-mcp-extended and add package publishing workflows
Rename the fork from gitea-mcp to gitea-mcp-extended to reflect the
significantly expanded tool coverage (299 vs upstream's 93 tools).

- Rename Go module path and all import references
- Rename binary to gitea-mcp-extended in Makefile, Dockerfile, .gitignore
- Point .goreleaser.yaml gitea_urls to git.lethalbits.com
- Replace release-tag workflow with goreleaser + Generic Package Registry publishing
- Replace release-nightly workflow with cross-platform build + nightly package publishing
- Update CLAUDE.md project description and tool count
2026-03-05 13:04:02 -05:00

168 lines
6.4 KiB
Go

package repo
import (
"context"
"errors"
"fmt"
"git.lethalbits.com/lethalbits/gitea-mcp-extended/pkg/gitea"
"git.lethalbits.com/lethalbits/gitea-mcp-extended/pkg/log"
"git.lethalbits.com/lethalbits/gitea-mcp-extended/pkg/to"
gitea_sdk "code.gitea.io/sdk/gitea"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
)
const (
TransferRepoToolName = "transfer_repo"
AcceptRepoTransferToolName = "accept_repo_transfer"
RejectRepoTransferToolName = "reject_repo_transfer"
CreateFromTemplateToolName = "create_repo_from_template"
)
var (
TransferRepoTool = mcp.NewTool(
TransferRepoToolName,
mcp.WithDescription("Transfer a repository to a new owner"),
mcp.WithString("owner", mcp.Required(), mcp.Description("current repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
mcp.WithString("new_owner", mcp.Required(), mcp.Description("new owner username or org")),
)
AcceptRepoTransferTool = mcp.NewTool(
AcceptRepoTransferToolName,
mcp.WithDescription("Accept a pending repository transfer"),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
)
RejectRepoTransferTool = mcp.NewTool(
RejectRepoTransferToolName,
mcp.WithDescription("Reject a pending repository transfer"),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
)
CreateFromTemplateTool = mcp.NewTool(
CreateFromTemplateToolName,
mcp.WithDescription("Create a repository from a template"),
mcp.WithString("template_owner", mcp.Required(), mcp.Description("template repository owner")),
mcp.WithString("template_repo", mcp.Required(), mcp.Description("template repository name")),
mcp.WithString("name", mcp.Required(), mcp.Description("name for the new repository")),
mcp.WithString("owner", mcp.Required(), mcp.Description("owner of the new repository (user or org)")),
mcp.WithString("description", mcp.Description("description for the new repository")),
mcp.WithBoolean("private", mcp.Description("whether the new repository is private")),
mcp.WithBoolean("git_content", mcp.Description("copy git content from template (default: true)")),
mcp.WithBoolean("topics", mcp.Description("copy topics from template")),
mcp.WithBoolean("labels", mcp.Description("copy labels from template")),
mcp.WithBoolean("webhooks", mcp.Description("copy webhooks from template")),
)
)
func init() {
Tool.RegisterWrite(server.ServerTool{Tool: TransferRepoTool, Handler: TransferRepoFn})
Tool.RegisterWrite(server.ServerTool{Tool: AcceptRepoTransferTool, Handler: AcceptRepoTransferFn})
Tool.RegisterWrite(server.ServerTool{Tool: RejectRepoTransferTool, Handler: RejectRepoTransferFn})
Tool.RegisterWrite(server.ServerTool{Tool: CreateFromTemplateTool, Handler: CreateFromTemplateFn})
}
func TransferRepoFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called TransferRepoFn")
owner, _ := req.GetArguments()["owner"].(string)
repo, _ := req.GetArguments()["repo"].(string)
newOwner, _ := req.GetArguments()["new_owner"].(string)
if owner == "" || repo == "" || newOwner == "" {
return to.ErrorResult(errors.New("owner, repo, and new_owner are required"))
}
client, err := gitea.ClientFromContext(ctx)
if err != nil {
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
}
repository, _, err := client.TransferRepo(owner, repo, gitea_sdk.TransferRepoOption{
NewOwner: newOwner,
})
if err != nil {
return to.ErrorResult(fmt.Errorf("transfer repo err: %v", err))
}
return to.TextResult(repository)
}
func AcceptRepoTransferFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called AcceptRepoTransferFn")
owner, _ := req.GetArguments()["owner"].(string)
repo, _ := req.GetArguments()["repo"].(string)
if owner == "" || repo == "" {
return to.ErrorResult(errors.New("owner and repo are required"))
}
client, err := gitea.ClientFromContext(ctx)
if err != nil {
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
}
repository, _, err := client.AcceptRepoTransfer(owner, repo)
if err != nil {
return to.ErrorResult(fmt.Errorf("accept repo transfer err: %v", err))
}
return to.TextResult(repository)
}
func RejectRepoTransferFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called RejectRepoTransferFn")
owner, _ := req.GetArguments()["owner"].(string)
repo, _ := req.GetArguments()["repo"].(string)
if owner == "" || repo == "" {
return to.ErrorResult(errors.New("owner and repo are required"))
}
client, err := gitea.ClientFromContext(ctx)
if err != nil {
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
}
repository, _, err := client.RejectRepoTransfer(owner, repo)
if err != nil {
return to.ErrorResult(fmt.Errorf("reject repo transfer err: %v", err))
}
return to.TextResult(repository)
}
func CreateFromTemplateFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called CreateFromTemplateFn")
templateOwner, _ := req.GetArguments()["template_owner"].(string)
templateRepo, _ := req.GetArguments()["template_repo"].(string)
name, _ := req.GetArguments()["name"].(string)
owner, _ := req.GetArguments()["owner"].(string)
if templateOwner == "" || templateRepo == "" || name == "" || owner == "" {
return to.ErrorResult(errors.New("template_owner, template_repo, name, and owner are required"))
}
opt := gitea_sdk.CreateRepoFromTemplateOption{
Name: name,
Owner: owner,
}
if v, ok := req.GetArguments()["description"].(string); ok {
opt.Description = v
}
if v, ok := req.GetArguments()["private"].(bool); ok {
opt.Private = v
}
if v, ok := req.GetArguments()["git_content"].(bool); ok {
opt.GitContent = v
}
if v, ok := req.GetArguments()["topics"].(bool); ok {
opt.Topics = v
}
if v, ok := req.GetArguments()["labels"].(bool); ok {
opt.Labels = v
}
if v, ok := req.GetArguments()["webhooks"].(bool); ok {
opt.Webhooks = v
}
client, err := gitea.ClientFromContext(ctx)
if err != nil {
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
}
repository, _, err := client.CreateRepoFromTemplate(templateOwner, templateRepo, opt)
if err != nil {
return to.ErrorResult(fmt.Errorf("create from template err: %v", err))
}
return to.TextResult(repository)
}