feat: add missing administration tools

Add 20+ new MCP tools for repository administration:

- Repository: get_repo, repo_write (edit/delete/transfer), list_forks
- Branch Protection: read (list/get) and write (create/edit/delete)
- Webhooks: read (list/get) and write (create/edit/delete/test)
- Collaborators: read (list) and write (add/delete)
- Deploy Keys: read (list/get) and write (create/delete)
- Topics: read (list) and write (add/delete/set)
- Compare: get_compare for branch/tag/commit comparison
- Organization: org_read (get/list_teams/get_team/list_team_members/list_team_repos)
  and org_write (create_team/delete_team/add_team_member/remove_team_member/add_team_repo/remove_team_repo)
- PR enhancements: list_files and is_merged methods added to pull_request_read

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-04 08:41:36 +00:00
parent 08128b9471
commit 4b4b5ee247
13 changed files with 2120 additions and 2 deletions
+168
View File
@@ -0,0 +1,168 @@
package repo
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_sdk "code.gitea.io/sdk/gitea"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
)
const (
CollaboratorReadToolName = "collaborator_read"
CollaboratorWriteToolName = "collaborator_write"
)
var (
CollaboratorReadTool = mcp.NewTool(
CollaboratorReadToolName,
mcp.WithDescription("List repository collaborators."),
mcp.WithString("method", mcp.Required(), mcp.Description("operation to perform"), mcp.Enum("list")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
mcp.WithNumber("page", mcp.Description("page number"), mcp.DefaultNumber(1)),
mcp.WithNumber("perPage", mcp.Description("results per page"), mcp.DefaultNumber(30)),
)
CollaboratorWriteTool = mcp.NewTool(
CollaboratorWriteToolName,
mcp.WithDescription("Add or remove repository collaborators. Use method 'add' to grant access, 'delete' to revoke."),
mcp.WithString("method", mcp.Required(), mcp.Description("operation to perform"), mcp.Enum("add", "delete")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
mcp.WithString("username", mcp.Required(), mcp.Description("collaborator username")),
mcp.WithString("permission", mcp.Description("permission level (for 'add')"), mcp.Enum("read", "write", "admin")),
)
)
func init() {
Tool.RegisterRead(server.ServerTool{
Tool: CollaboratorReadTool,
Handler: collaboratorReadFn,
})
Tool.RegisterWrite(server.ServerTool{
Tool: CollaboratorWriteTool,
Handler: collaboratorWriteFn,
})
}
func collaboratorReadFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
args := req.GetArguments()
method, err := params.GetString(args, "method")
if err != nil {
return to.ErrorResult(err)
}
switch method {
case "list":
return listCollaboratorsFn(ctx, req)
default:
return to.ErrorResult(fmt.Errorf("unknown method: %s", method))
}
}
func listCollaboratorsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called listCollaboratorsFn")
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)
}
page, pageSize := params.GetPagination(args, 30)
client, err := gitea.ClientFromContext(ctx)
if err != nil {
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
}
users, _, err := client.ListCollaborators(owner, repo, gitea_sdk.ListCollaboratorsOptions{
ListOptions: gitea_sdk.ListOptions{
Page: page,
PageSize: pageSize,
},
})
if err != nil {
return to.ErrorResult(fmt.Errorf("list collaborators %v/%v err: %v", owner, repo, err))
}
return to.TextResult(slimUsers(users))
}
func collaboratorWriteFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
args := req.GetArguments()
method, err := params.GetString(args, "method")
if err != nil {
return to.ErrorResult(err)
}
switch method {
case "add":
return addCollaboratorFn(ctx, req)
case "delete":
return deleteCollaboratorFn(ctx, req)
default:
return to.ErrorResult(fmt.Errorf("unknown method: %s", method))
}
}
func addCollaboratorFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called addCollaboratorFn")
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)
}
username, err := params.GetString(args, "username")
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))
}
opt := gitea_sdk.AddCollaboratorOption{}
if perm, ok := args["permission"].(string); ok {
am := gitea_sdk.AccessMode(perm)
opt.Permission = &am
}
_, err = client.AddCollaborator(owner, repo, username, opt)
if err != nil {
return to.ErrorResult(fmt.Errorf("add collaborator %v to %v/%v err: %v", username, owner, repo, err))
}
return mcp.NewToolResultText(fmt.Sprintf("Collaborator %s added to %s/%s", username, owner, repo)), nil
}
func deleteCollaboratorFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called deleteCollaboratorFn")
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)
}
username, err := params.GetString(args, "username")
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.DeleteCollaborator(owner, repo, username)
if err != nil {
return to.ErrorResult(fmt.Errorf("delete collaborator %v from %v/%v err: %v", username, owner, repo, err))
}
return mcp.NewToolResultText(fmt.Sprintf("Collaborator %s removed from %s/%s", username, owner, repo)), nil
}