Initial commit: Gitea MCP Server

This commit is contained in:
2026-04-10 21:57:19 -07:00
commit 1f27844dce
119 changed files with 25001 additions and 0 deletions
+256
View File
@@ -0,0 +1,256 @@
package mirror
import (
"context"
"fmt"
"gitea.com/gitea/gitea-mcp/pkg/gitea"
"gitea.com/gitea/gitea-mcp/pkg/log"
"gitea.com/gitea/gitea-mcp/pkg/params"
"gitea.com/gitea/gitea-mcp/pkg/to"
"gitea.com/gitea/gitea-mcp/pkg/tool"
gitea_sdk "code.gitea.io/sdk/gitea"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
)
const (
ListPushMirrorsToolName = "list_push_mirrors"
GetPushMirrorToolName = "get_push_mirror"
CreatePushMirrorToolName = "create_push_mirror"
DeletePushMirrorToolName = "delete_push_mirror"
SyncMirrorToolName = "sync_mirror"
)
var Tool = tool.New()
var (
ListPushMirrorsTool = mcp.NewTool(
ListPushMirrorsToolName,
mcp.WithDescription("List push mirrors for a repository"),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
)
GetPushMirrorTool = mcp.NewTool(
GetPushMirrorToolName,
mcp.WithDescription("Get a specific push mirror by remote name"),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
mcp.WithString("remote_name", mcp.Required(), mcp.Description("Remote name")),
)
CreatePushMirrorTool = mcp.NewTool(
CreatePushMirrorToolName,
mcp.WithDescription("Create a push mirror for a repository"),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
mcp.WithString("remote_name", mcp.Required(), mcp.Description("Remote name")),
mcp.WithString("remote_addr", mcp.Required(), mcp.Description("Remote address (git URL)")),
mcp.WithString("sync_interval", mcp.Description("Sync interval (e.g. 8h30m0s)")),
mcp.WithBoolean("sync_on_commit", mcp.Description("Sync on commit"), mcp.DefaultBool(false)),
)
DeletePushMirrorTool = mcp.NewTool(
DeletePushMirrorToolName,
mcp.WithDescription("Delete a push mirror"),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
mcp.WithString("remote_name", mcp.Required(), mcp.Description("Remote name")),
)
SyncMirrorTool = mcp.NewTool(
SyncMirrorToolName,
mcp.WithDescription("Trigger immediate sync for a mirror repository"),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
)
)
func init() {
Tool.RegisterRead(server.ServerTool{
Tool: ListPushMirrorsTool,
Handler: listPushMirrorsFn,
})
Tool.RegisterRead(server.ServerTool{
Tool: GetPushMirrorTool,
Handler: getPushMirrorFn,
})
Tool.RegisterWrite(server.ServerTool{
Tool: CreatePushMirrorTool,
Handler: createPushMirrorFn,
})
Tool.RegisterWrite(server.ServerTool{
Tool: DeletePushMirrorTool,
Handler: deletePushMirrorFn,
})
Tool.RegisterWrite(server.ServerTool{
Tool: SyncMirrorTool,
Handler: syncMirrorFn,
})
}
func listPushMirrorsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("[Mirror] Called listPushMirrorsFn")
args := req.GetArguments()
owner, err := params.GetString(args, "owner")
if err != nil {
return to.ErrorResult(err)
}
repo, err := params.GetString(args, "repo")
if err != nil {
return to.ErrorResult(err)
}
client, err := gitea.ClientFromContext(ctx)
if err != nil {
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
}
mirrors, _, err := client.ListPushMirrors(owner, repo, gitea_sdk.ListOptions{})
if err != nil {
return to.ErrorResult(fmt.Errorf("list push mirrors err: %v", err))
}
return to.TextResult(slimMirrors(mirrors))
}
func getPushMirrorFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("[Mirror] Called getPushMirrorFn")
args := req.GetArguments()
owner, err := params.GetString(args, "owner")
if err != nil {
return to.ErrorResult(err)
}
repo, err := params.GetString(args, "repo")
if err != nil {
return to.ErrorResult(err)
}
remoteName, err := params.GetString(args, "remote_name")
if err != nil {
return to.ErrorResult(err)
}
client, err := gitea.ClientFromContext(ctx)
if err != nil {
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
}
mirror, _, err := client.GetPushMirrorByRemoteName(owner, repo, remoteName)
if err != nil {
return to.ErrorResult(fmt.Errorf("get push mirror err: %v", err))
}
return to.TextResult(slimMirror(mirror))
}
func createPushMirrorFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("[Mirror] Called createPushMirrorFn")
args := req.GetArguments()
owner, err := params.GetString(args, "owner")
if err != nil {
return to.ErrorResult(err)
}
repo, err := params.GetString(args, "repo")
if err != nil {
return to.ErrorResult(err)
}
remoteAddr, err := params.GetString(args, "remote_addr")
if err != nil {
return to.ErrorResult(err)
}
syncInterval, _ := args["sync_interval"].(string)
syncOnCommit, _ := args["sync_on_commit"].(bool)
client, err := gitea.ClientFromContext(ctx)
if err != nil {
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
}
opt := gitea_sdk.CreatePushMirrorOption{
RemoteAddress: remoteAddr,
Interval: syncInterval,
SyncONCommit: syncOnCommit,
}
mirror, _, err := client.PushMirrors(owner, repo, opt)
if err != nil {
return to.ErrorResult(fmt.Errorf("create push mirror err: %v", err))
}
return to.TextResult(slimMirror(mirror))
}
func deletePushMirrorFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("[Mirror] Called deletePushMirrorFn")
args := req.GetArguments()
owner, err := params.GetString(args, "owner")
if err != nil {
return to.ErrorResult(err)
}
repo, err := params.GetString(args, "repo")
if err != nil {
return to.ErrorResult(err)
}
remoteName, err := params.GetString(args, "remote_name")
if err != nil {
return to.ErrorResult(err)
}
client, err := gitea.ClientFromContext(ctx)
if err != nil {
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
}
_, err = client.DeletePushMirror(owner, repo, remoteName)
if err != nil {
return to.ErrorResult(fmt.Errorf("delete push mirror err: %v", err))
}
return to.TextResult("Push mirror deleted successfully")
}
func syncMirrorFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("[Mirror] Called syncMirrorFn")
args := req.GetArguments()
owner, err := params.GetString(args, "owner")
if err != nil {
return to.ErrorResult(err)
}
repo, err := params.GetString(args, "repo")
if err != nil {
return to.ErrorResult(err)
}
client, err := gitea.ClientFromContext(ctx)
if err != nil {
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
}
_, err = client.MirrorSync(owner, repo)
if err != nil {
return to.ErrorResult(fmt.Errorf("sync mirror err: %v", err))
}
return to.TextResult("Mirror sync triggered successfully")
}
func slimMirrors(mirrors []*gitea_sdk.PushMirrorResponse) []map[string]interface{} {
result := make([]map[string]interface{}, len(mirrors))
for i, m := range mirrors {
result[i] = slimMirror(m)
}
return result
}
func slimMirror(m *gitea_sdk.PushMirrorResponse) map[string]interface{} {
return map[string]interface{}{
"remote_name": m.RemoteName,
"remote_addr": m.RemoteAddress,
"interval": m.Interval,
"sync_on_commit": m.SyncONCommit,
"last_update": m.LastUpdate,
"last_error": m.LastError,
}
}