diff --git a/README.md b/README.md index b94d6d2..840aaaf 100644 --- a/README.md +++ b/README.md @@ -199,6 +199,7 @@ The Gitea MCP Server supports the following tools: | get_pull_request_by_index | Pull Request | Get a pull request by its index | | list_repo_pull_requests | Pull Request | List all pull requests in a repository | | create_pull_request | Pull Request | Create a new pull request | +| create_pull_request_reviewer | Pull Request | Add reviewers to a pull request | | search_users | User | Search for users | | search_org_teams | Organization | Search for teams in an organization | | list_org_labels | Organization | List labels defined at organization level | diff --git a/README.zh-cn.md b/README.zh-cn.md index 4de210f..de63d83 100644 --- a/README.zh-cn.md +++ b/README.zh-cn.md @@ -199,6 +199,7 @@ Gitea MCP 服务器支持以下工具: | get_pull_request_by_index | 拉取请求 | 按索引获取拉取请求 | | list_repo_pull_requests | 拉取请求 | 列出所有拉取请求 | | create_pull_request | 拉取请求 | 创建新拉取请求 | +| create_pull_request_reviewer | 拉取请求 | 为拉取请求添加审查者 | | search_users | 用户 | 搜索用户 | | search_org_teams | 组织 | 搜索组织团队 | | list_org_labels | 组织 | 列出组织标签 | diff --git a/README.zh-tw.md b/README.zh-tw.md index 23708a0..7da44ca 100644 --- a/README.zh-tw.md +++ b/README.zh-tw.md @@ -199,6 +199,7 @@ Gitea MCP 伺服器支援以下工具: | get_pull_request_by_index | 拉取請求 | 依索引取得拉取請求 | | list_repo_pull_requests | 拉取請求 | 列出所有拉取請求 | | create_pull_request | 拉取請求 | 創建新拉取請求 | +| create_pull_request_reviewer | 拉取請求 | 為拉取請求添加審查者 | | search_users | 用戶 | 搜尋用戶 | | search_org_teams | 組織 | 搜尋組織團隊 | | list_org_labels | 組織 | 列出組織標籤 | diff --git a/operation/pull/pull.go b/operation/pull/pull.go index 85f151b..f6ddf03 100644 --- a/operation/pull/pull.go +++ b/operation/pull/pull.go @@ -17,9 +17,10 @@ import ( var Tool = tool.New() const ( - GetPullRequestByIndexToolName = "get_pull_request_by_index" - ListRepoPullRequestsToolName = "list_repo_pull_requests" - CreatePullRequestToolName = "create_pull_request" + GetPullRequestByIndexToolName = "get_pull_request_by_index" + ListRepoPullRequestsToolName = "list_repo_pull_requests" + CreatePullRequestToolName = "create_pull_request" + CreatePullRequestReviewerToolName = "create_pull_request_reviewer" ) var ( @@ -53,6 +54,16 @@ var ( mcp.WithString("head", mcp.Required(), mcp.Description("pull request head")), mcp.WithString("base", mcp.Required(), mcp.Description("pull request base")), ) + + CreatePullRequestReviewerTool = mcp.NewTool( + CreatePullRequestReviewerToolName, + mcp.WithDescription("create pull request reviewer"), + mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")), + mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")), + mcp.WithNumber("index", mcp.Required(), mcp.Description("pull request index")), + mcp.WithArray("reviewers", mcp.Description("list of reviewer usernames"), mcp.Items(map[string]interface{}{"type": "string"})), + mcp.WithArray("team_reviewers", mcp.Description("list of team reviewer names"), mcp.Items(map[string]interface{}{"type": "string"})), + ) ) func init() { @@ -68,6 +79,10 @@ func init() { Tool: CreatePullRequestTool, Handler: CreatePullRequestFn, }) + Tool.RegisterWrite(server.ServerTool{ + Tool: CreatePullRequestReviewerTool, + Handler: CreatePullRequestReviewerFn, + }) } func GetPullRequestByIndexFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { @@ -183,3 +198,65 @@ func CreatePullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Cal return to.TextResult(pr) } + +func CreatePullRequestReviewerFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { + log.Debugf("Called CreatePullRequestReviewerFn") + owner, ok := req.GetArguments()["owner"].(string) + if !ok { + return to.ErrorResult(fmt.Errorf("owner is required")) + } + repo, ok := req.GetArguments()["repo"].(string) + if !ok { + return to.ErrorResult(fmt.Errorf("repo is required")) + } + index, ok := req.GetArguments()["index"].(float64) + if !ok { + return to.ErrorResult(fmt.Errorf("index is required")) + } + + var reviewers []string + if reviewersArg, exists := req.GetArguments()["reviewers"]; exists { + if reviewersSlice, ok := reviewersArg.([]interface{}); ok { + for _, reviewer := range reviewersSlice { + if reviewerStr, ok := reviewer.(string); ok { + reviewers = append(reviewers, reviewerStr) + } + } + } + } + + var teamReviewers []string + if teamReviewersArg, exists := req.GetArguments()["team_reviewers"]; exists { + if teamReviewersSlice, ok := teamReviewersArg.([]interface{}); ok { + for _, teamReviewer := range teamReviewersSlice { + if teamReviewerStr, ok := teamReviewer.(string); ok { + teamReviewers = append(teamReviewers, teamReviewerStr) + } + } + } + } + + client, err := gitea.ClientFromContext(ctx) + if err != nil { + return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err)) + } + + _, err = client.CreateReviewRequests(owner, repo, int64(index), gitea_sdk.PullReviewRequestOptions{ + Reviewers: reviewers, + TeamReviewers: teamReviewers, + }) + if err != nil { + return to.ErrorResult(fmt.Errorf("create review requests for %v/%v/pr/%v err: %v", owner, repo, int64(index), err)) + } + + // Return a success message instead of the Response object which contains non-serializable functions + successMsg := map[string]interface{}{ + "message": "Successfully created review requests", + "reviewers": reviewers, + "team_reviewers": teamReviewers, + "pr_index": int64(index), + "repository": fmt.Sprintf("%s/%s", owner, repo), + } + + return to.TextResult(successMsg) +}