Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
07949c1a63 | ||
|
|
3e093c10b9 | ||
|
|
10f5a345d8 | ||
|
|
554b7490e2 | ||
|
|
026f40bc15 | ||
|
|
4f7a191b67 |
@@ -160,8 +160,8 @@ Once configured, try `list all my repositories` in the chat box.
|
||||
| package_write | packages | Write | Delete a package version (irreversible) |
|
||||
| list_issues | issue | Read | List repository issues |
|
||||
| attachment_read | issue | Read | Read issue/comment attachments: list metadata, get metadata, or download content |
|
||||
| issue_read | issue | Read | Read issue: details, comments, or labels |
|
||||
| issue_write | issue | Write | Write issues: create, update, manage comments and labels |
|
||||
| issue_read | issue | Read | Read issue: details, comments, labels, or dependency/blocking links |
|
||||
| issue_write | issue | Write | Write issues: create, update, manage comments, labels, and dependency/blocking links |
|
||||
| list_pull_requests | pull_request | Read | List repository pull requests |
|
||||
| pull_request_read | pull_request | Read | Read pull request: details, diff, files, status, reviews, review comments |
|
||||
| pull_request_write | pull_request | Write | Write pull requests: create, update, close, reopen, merge, update branch, manage reviewers |
|
||||
|
||||
+2
-2
@@ -160,8 +160,8 @@ Cursor 等客户端可使用 stdio 命令:
|
||||
| package_write | packages | 写入 | 删除软件包版本(不可恢复) |
|
||||
| list_issues | issue | 读取 | 列出仓库问题 |
|
||||
| attachment_read | issue | 读取 | 读取问题/评论附件:列出元数据、获取元数据或下载内容 |
|
||||
| issue_read | issue | 读取 | 读取问题:详情、评论或标签 |
|
||||
| issue_write | issue | 写入 | 写入问题:创建、更新、管理评论和标签 |
|
||||
| issue_read | issue | 读取 | 读取问题:详情、评论、标签或阻塞关系 |
|
||||
| issue_write | issue | 写入 | 写入问题:创建、更新、管理评论、标签和阻塞关系 |
|
||||
| list_pull_requests | pull_request | 读取 | 列出仓库拉取请求 |
|
||||
| pull_request_read | pull_request | 读取 | 读取拉取请求:详情、差异、变更文件、头部提交状态、审查、审查评论 |
|
||||
| pull_request_write | pull_request | 写入 | 写入拉取请求:创建、更新、关闭、重新打开、合并、更新分支、管理审查者 |
|
||||
|
||||
+2
-2
@@ -160,8 +160,8 @@ Cursor 等客戶端可使用 stdio 命令:
|
||||
| package_write | packages | 寫入 | 刪除軟體套件版本(不可復原) |
|
||||
| list_issues | issue | 讀取 | 列出倉庫問題 |
|
||||
| attachment_read | issue | 讀取 | 讀取問題/評論附件:列出中繼資料、取得中繼資料或下載內容 |
|
||||
| issue_read | issue | 讀取 | 讀取問題:詳情、評論或標籤 |
|
||||
| issue_write | issue | 寫入 | 寫入問題:創建、更新、管理評論和標籤 |
|
||||
| issue_read | issue | 讀取 | 讀取問題:詳情、評論、標籤或阻塞關係 |
|
||||
| issue_write | issue | 寫入 | 寫入問題:創建、更新、管理評論、標籤和阻塞關係 |
|
||||
| list_pull_requests | pull_request | 讀取 | 列出倉庫拉取請求 |
|
||||
| pull_request_read | pull_request | 讀取 | 讀取拉取請求:詳情、差異、變更檔案、頭部提交狀態、審查、審查評論 |
|
||||
| pull_request_write | pull_request | 寫入 | 寫入拉取請求:創建、更新、關閉、重新開啟、合併、更新分支、管理審查者 |
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
package issue
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"gitea.com/gitea/gitea-mcp/pkg/gitea"
|
||||
"gitea.com/gitea/gitea-mcp/pkg/params"
|
||||
"gitea.com/gitea/gitea-mcp/pkg/to"
|
||||
|
||||
gitea_sdk "gitea.dev/sdk"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
)
|
||||
|
||||
// issueMeta carries owner/repo in the body; the SDK's IssueMeta only has Index
|
||||
// and Gitea resolves the body repo from those fields.
|
||||
type issueMeta struct {
|
||||
Index int64 `json:"index"`
|
||||
Owner string `json:"owner"`
|
||||
Repo string `json:"repo"`
|
||||
}
|
||||
|
||||
func listIssueBlocksFn(ctx context.Context, args map[string]any) (*mcp.CallToolResult, error) {
|
||||
owner, repo, index, err := issueRef(args)
|
||||
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))
|
||||
}
|
||||
listOpt := gitea_sdk.ListOptions{Page: page, PageSize: pageSize}
|
||||
issues, _, err := client.Issues.ListIssueBlocks(ctx, owner, repo, index, gitea_sdk.ListIssueBlocksOptions{
|
||||
ListOptions: listOpt,
|
||||
})
|
||||
if err != nil {
|
||||
return to.ErrorResult(fmt.Errorf("list %v/%v/issue/%v/blocks err: %v", owner, repo, index, err))
|
||||
}
|
||||
return to.TextResult(slimIssues(issues))
|
||||
}
|
||||
|
||||
func blockIssueFn(ctx context.Context, args map[string]any) (*mcp.CallToolResult, error) {
|
||||
return setIssueBlockingFn(ctx, args, true)
|
||||
}
|
||||
|
||||
func unblockIssueFn(ctx context.Context, args map[string]any) (*mcp.CallToolResult, error) {
|
||||
return setIssueBlockingFn(ctx, args, false)
|
||||
}
|
||||
|
||||
func setIssueBlockingFn(ctx context.Context, args map[string]any, block bool) (*mcp.CallToolResult, error) {
|
||||
owner, repo, index, err := issueRef(args)
|
||||
if err != nil {
|
||||
return to.ErrorResult(err)
|
||||
}
|
||||
blocked, err := params.GetIndex(args, "blocked_issue")
|
||||
if err != nil {
|
||||
return to.ErrorResult(err)
|
||||
}
|
||||
blockedOwner, blockedRepo := relatedIssueRepo(args, "blocked_owner", "blocked_repo", owner, repo)
|
||||
method := http.MethodPost
|
||||
if !block {
|
||||
method = http.MethodDelete
|
||||
}
|
||||
var issue gitea_sdk.Issue
|
||||
path := fmt.Sprintf("repos/%s/%s/issues/%d/blocks", url.PathEscape(owner), url.PathEscape(repo), index)
|
||||
if _, err := gitea.DoJSON(ctx, method, path, nil, issueMeta{Index: blocked, Owner: blockedOwner, Repo: blockedRepo}, &issue); err != nil {
|
||||
return to.ErrorResult(fmt.Errorf("update %v/%v/issue/%v/blocks err: %v", owner, repo, index, err))
|
||||
}
|
||||
return to.TextResult(slimIssue(&issue))
|
||||
}
|
||||
|
||||
func listIssueDependenciesFn(ctx context.Context, args map[string]any) (*mcp.CallToolResult, error) {
|
||||
owner, repo, index, err := issueRef(args)
|
||||
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))
|
||||
}
|
||||
listOpt := gitea_sdk.ListOptions{Page: page, PageSize: pageSize}
|
||||
issues, _, err := client.Issues.ListIssueDependencies(ctx, owner, repo, index, gitea_sdk.ListIssueDependenciesOptions{
|
||||
ListOptions: listOpt,
|
||||
})
|
||||
if err != nil {
|
||||
return to.ErrorResult(fmt.Errorf("list %v/%v/issue/%v/dependencies err: %v", owner, repo, index, err))
|
||||
}
|
||||
return to.TextResult(slimIssues(issues))
|
||||
}
|
||||
|
||||
func addIssueDependencyFn(ctx context.Context, args map[string]any) (*mcp.CallToolResult, error) {
|
||||
return setIssueDependencyFn(ctx, args, true)
|
||||
}
|
||||
|
||||
func removeIssueDependencyFn(ctx context.Context, args map[string]any) (*mcp.CallToolResult, error) {
|
||||
return setIssueDependencyFn(ctx, args, false)
|
||||
}
|
||||
|
||||
func setIssueDependencyFn(ctx context.Context, args map[string]any, add bool) (*mcp.CallToolResult, error) {
|
||||
owner, repo, index, err := issueRef(args)
|
||||
if err != nil {
|
||||
return to.ErrorResult(err)
|
||||
}
|
||||
blocking, err := params.GetIndex(args, "blocking_issue")
|
||||
if err != nil {
|
||||
return to.ErrorResult(err)
|
||||
}
|
||||
blockingOwner, blockingRepo := relatedIssueRepo(args, "blocking_owner", "blocking_repo", owner, repo)
|
||||
method := http.MethodPost
|
||||
if !add {
|
||||
method = http.MethodDelete
|
||||
}
|
||||
var issue gitea_sdk.Issue
|
||||
path := fmt.Sprintf("repos/%s/%s/issues/%d/dependencies", url.PathEscape(owner), url.PathEscape(repo), index)
|
||||
if _, err := gitea.DoJSON(ctx, method, path, nil, issueMeta{Index: blocking, Owner: blockingOwner, Repo: blockingRepo}, &issue); err != nil {
|
||||
return to.ErrorResult(fmt.Errorf("update %v/%v/issue/%v/dependencies err: %v", owner, repo, index, err))
|
||||
}
|
||||
return to.TextResult(slimIssue(&issue))
|
||||
}
|
||||
|
||||
func checkIssueBlockedFn(ctx context.Context, args map[string]any) (*mcp.CallToolResult, error) {
|
||||
owner, repo, index, err := issueRef(args)
|
||||
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))
|
||||
}
|
||||
listOpt := gitea_sdk.ListOptions{Page: page, PageSize: pageSize}
|
||||
issues, _, err := client.Issues.ListIssueDependencies(ctx, owner, repo, index, gitea_sdk.ListIssueDependenciesOptions{
|
||||
ListOptions: listOpt,
|
||||
})
|
||||
if err != nil {
|
||||
return to.ErrorResult(fmt.Errorf("list %v/%v/issue/%v/dependencies err: %v", owner, repo, index, err))
|
||||
}
|
||||
openBlockers := make([]map[string]any, 0)
|
||||
for _, issue := range issues {
|
||||
if issue == nil {
|
||||
continue
|
||||
}
|
||||
if issue.State == gitea_sdk.StateOpen || issue.State == "" {
|
||||
openBlockers = append(openBlockers, slimIssue(issue))
|
||||
}
|
||||
}
|
||||
return to.TextResult(map[string]any{
|
||||
"blocked": len(openBlockers) > 0,
|
||||
"total_dependencies": len(issues),
|
||||
"open_blockers": len(openBlockers),
|
||||
"blockers": slimIssues(issues),
|
||||
"open": openBlockers,
|
||||
})
|
||||
}
|
||||
|
||||
func relatedIssueRepo(args map[string]any, ownerKey, repoKey, owner, repo string) (string, string) {
|
||||
if o := params.GetOptionalString(args, ownerKey, ""); o != "" {
|
||||
owner = o
|
||||
}
|
||||
if r := params.GetOptionalString(args, repoKey, ""); r != "" {
|
||||
repo = r
|
||||
}
|
||||
return owner, repo
|
||||
}
|
||||
|
||||
func issueRef(args map[string]any) (owner, repo string, index int64, err error) {
|
||||
if owner, err = params.GetString(args, "owner"); err != nil {
|
||||
return "", "", 0, err
|
||||
}
|
||||
if repo, err = params.GetString(args, "repo"); err != nil {
|
||||
return "", "", 0, err
|
||||
}
|
||||
if index, err = params.GetIndex(args, "issue_number"); err != nil {
|
||||
return "", "", 0, err
|
||||
}
|
||||
return owner, repo, index, nil
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
package issue
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"maps"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gitea.com/gitea/gitea-mcp/pkg/flag"
|
||||
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
)
|
||||
|
||||
func Test_issueBlocking(t *testing.T) {
|
||||
const (
|
||||
owner = "octo"
|
||||
repo = "demo"
|
||||
)
|
||||
blocksPath := fmt.Sprintf("/api/v1/repos/%s/%s/issues/42/blocks", owner, repo)
|
||||
depsPath := fmt.Sprintf("/api/v1/repos/%s/%s/issues/42/dependencies", owner, repo)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
fn func(context.Context, map[string]any) (*mcp.CallToolResult, error)
|
||||
args map[string]any
|
||||
wantPath string
|
||||
wantMethod string
|
||||
wantQuery string
|
||||
wantIndex float64
|
||||
wantOwner string
|
||||
wantRepo string
|
||||
wantBody string
|
||||
}{
|
||||
{
|
||||
name: "list blocks paginates",
|
||||
fn: listIssueBlocksFn,
|
||||
args: map[string]any{"page": float64(2), "per_page": float64(10)},
|
||||
wantPath: blocksPath,
|
||||
wantMethod: http.MethodGet,
|
||||
wantQuery: "limit=10&page=2",
|
||||
},
|
||||
{
|
||||
name: "block issue posts index",
|
||||
fn: blockIssueFn,
|
||||
args: map[string]any{"blocked_issue": float64(7)},
|
||||
wantPath: blocksPath,
|
||||
wantMethod: http.MethodPost,
|
||||
wantIndex: 7,
|
||||
wantOwner: owner,
|
||||
wantRepo: repo,
|
||||
},
|
||||
{
|
||||
name: "block issue posts cross-repo target",
|
||||
fn: blockIssueFn,
|
||||
args: map[string]any{
|
||||
"blocked_issue": float64(7),
|
||||
"blocked_owner": "other",
|
||||
"blocked_repo": "elsewhere",
|
||||
},
|
||||
wantPath: blocksPath,
|
||||
wantMethod: http.MethodPost,
|
||||
wantIndex: 7,
|
||||
wantOwner: "other",
|
||||
wantRepo: "elsewhere",
|
||||
},
|
||||
{
|
||||
name: "unblock issue deletes with index",
|
||||
fn: unblockIssueFn,
|
||||
args: map[string]any{"blocked_issue": float64(7)},
|
||||
wantPath: blocksPath,
|
||||
wantMethod: http.MethodDelete,
|
||||
wantIndex: 7,
|
||||
wantOwner: owner,
|
||||
wantRepo: repo,
|
||||
},
|
||||
{
|
||||
name: "list dependencies paginates",
|
||||
fn: listIssueDependenciesFn,
|
||||
args: map[string]any{"page": float64(3), "per_page": float64(5)},
|
||||
wantPath: depsPath,
|
||||
wantMethod: http.MethodGet,
|
||||
wantQuery: "limit=5&page=3",
|
||||
},
|
||||
{
|
||||
name: "add dependency posts index",
|
||||
fn: addIssueDependencyFn,
|
||||
args: map[string]any{"blocking_issue": float64(9)},
|
||||
wantPath: depsPath,
|
||||
wantMethod: http.MethodPost,
|
||||
wantIndex: 9,
|
||||
wantOwner: owner,
|
||||
wantRepo: repo,
|
||||
},
|
||||
{
|
||||
name: "add dependency posts cross-repo target",
|
||||
fn: addIssueDependencyFn,
|
||||
args: map[string]any{
|
||||
"blocking_issue": float64(9),
|
||||
"blocking_owner": "other",
|
||||
"blocking_repo": "elsewhere",
|
||||
},
|
||||
wantPath: depsPath,
|
||||
wantMethod: http.MethodPost,
|
||||
wantIndex: 9,
|
||||
wantOwner: "other",
|
||||
wantRepo: "elsewhere",
|
||||
},
|
||||
{
|
||||
name: "remove dependency deletes with index",
|
||||
fn: removeIssueDependencyFn,
|
||||
args: map[string]any{"blocking_issue": float64(9)},
|
||||
wantPath: depsPath,
|
||||
wantMethod: http.MethodDelete,
|
||||
wantIndex: 9,
|
||||
wantOwner: owner,
|
||||
wantRepo: repo,
|
||||
},
|
||||
{
|
||||
name: "check blocked summarizes open dependencies",
|
||||
fn: checkIssueBlockedFn,
|
||||
args: map[string]any{"page": float64(1), "per_page": float64(30)},
|
||||
wantPath: depsPath,
|
||||
wantMethod: http.MethodGet,
|
||||
wantQuery: "limit=30&page=1",
|
||||
wantBody: `"blocked":true`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var (
|
||||
gotMethod string
|
||||
gotPath string
|
||||
gotQuery string
|
||||
gotBody map[string]any
|
||||
)
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
case "/api/v1/version":
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(`{"version":"1.27.2"}`))
|
||||
case blocksPath, depsPath:
|
||||
gotMethod = r.Method
|
||||
gotPath = r.URL.Path
|
||||
gotQuery = r.URL.RawQuery
|
||||
_ = json.NewDecoder(r.Body).Decode(&gotBody)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if r.Method == http.MethodGet {
|
||||
_, _ = w.Write([]byte(`[{"number":7,"title":"blocked","state":"open"}]`))
|
||||
} else {
|
||||
_, _ = w.Write([]byte(`{"number":7,"title":"blocked","state":"open"}`))
|
||||
}
|
||||
default:
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
})
|
||||
server := httptest.NewServer(handler)
|
||||
defer server.Close()
|
||||
|
||||
origHost, origToken, origVersion := flag.Host, flag.Token, flag.Version
|
||||
flag.Host, flag.Token, flag.Version = server.URL, "", "test"
|
||||
defer func() { flag.Host, flag.Token, flag.Version = origHost, origToken, origVersion }()
|
||||
|
||||
args := map[string]any{"owner": owner, "repo": repo, "issue_number": float64(42)}
|
||||
maps.Copy(args, tt.args)
|
||||
res, err := tt.fn(context.Background(), args)
|
||||
if err != nil {
|
||||
t.Fatalf("handler error = %v", err)
|
||||
}
|
||||
if res.IsError {
|
||||
t.Fatalf("unexpected error result: %v", res.Content)
|
||||
}
|
||||
if gotMethod != tt.wantMethod {
|
||||
t.Fatalf("method = %s, want %s", gotMethod, tt.wantMethod)
|
||||
}
|
||||
if gotPath != tt.wantPath {
|
||||
t.Fatalf("path = %s, want %s", gotPath, tt.wantPath)
|
||||
}
|
||||
if tt.wantQuery != "" && gotQuery != tt.wantQuery {
|
||||
t.Fatalf("query = %s, want %s", gotQuery, tt.wantQuery)
|
||||
}
|
||||
if tt.wantIndex != 0 {
|
||||
if gotBody["index"] != tt.wantIndex {
|
||||
t.Fatalf("body index = %v, want %v", gotBody["index"], tt.wantIndex)
|
||||
}
|
||||
if gotBody["owner"] != tt.wantOwner {
|
||||
t.Fatalf("body owner = %v, want %s", gotBody["owner"], tt.wantOwner)
|
||||
}
|
||||
if gotBody["repo"] != tt.wantRepo {
|
||||
t.Fatalf("body repo = %v, want %s", gotBody["repo"], tt.wantRepo)
|
||||
}
|
||||
}
|
||||
body := res.Content[0].(*mcp.TextContent).Text
|
||||
if tt.wantBody != "" {
|
||||
if !strings.Contains(body, tt.wantBody) {
|
||||
t.Fatalf("expected %s in output, got: %s", tt.wantBody, body)
|
||||
}
|
||||
} else if !strings.Contains(body, `"number":7`) && !strings.Contains(body, `"number": 7`) {
|
||||
t.Fatalf("expected slim issue in output, got: %s", body)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -55,19 +55,21 @@ var (
|
||||
|
||||
IssueReadTool = tool.NewDefinition(
|
||||
IssueReadToolName,
|
||||
"Read issue: details, comments, or labels.",
|
||||
"Read issue: details, comments, labels, or dependency/blocking links. list_dependencies is issues that block this one (blocked-by); list_blocks is issues this one blocks. check_blocked summarizes whether any of those dependencies are still open. These methods 404 if the repo has issue dependencies disabled.",
|
||||
annotation.ReadOnly("Read issue details"),
|
||||
tool.String("method", tool.Required(), tool.Enum("get", "get_comments", "get_labels")),
|
||||
tool.String("method", tool.Required(), tool.Enum("get", "get_comments", "get_labels", "list_blocks", "list_dependencies", "check_blocked")),
|
||||
tool.String("owner", tool.Required(), tool.Description(params.OwnerDesc)),
|
||||
tool.String("repo", tool.Required(), tool.Description(params.RepoDesc)),
|
||||
tool.Number("issue_number", tool.Required()),
|
||||
tool.Number("page", tool.Description(params.PageDesc), tool.Default(1)),
|
||||
tool.Number("per_page", tool.Description(params.PaginationDesc), tool.Default(30)),
|
||||
)
|
||||
|
||||
IssueWriteTool = tool.NewDefinition(
|
||||
IssueWriteToolName,
|
||||
"Write issues: create, update, manage comments and labels.",
|
||||
"Write issues: create, update, manage comments, labels, and dependency/blocking links. block_issue makes issue_number block blocked_issue; add_dependency makes issue_number depend on blocking_issue. Cross-repo links use blocked_owner/blocked_repo or blocking_owner/blocking_repo (instance must allow cross-repository dependencies). Repo must have issue dependencies enabled or Gitea returns 404.",
|
||||
annotation.Write("Create or update issues, comments, and labels"),
|
||||
tool.String("method", tool.Required(), tool.Enum("create", "update", "add_comment", "edit_comment", "add_labels", "remove_label", "replace_labels", "clear_labels")),
|
||||
tool.String("method", tool.Required(), tool.Enum("create", "update", "add_comment", "edit_comment", "add_labels", "remove_label", "replace_labels", "clear_labels", "block_issue", "unblock_issue", "add_dependency", "remove_dependency")),
|
||||
tool.String("owner", tool.Required(), tool.Description(params.OwnerDesc)),
|
||||
tool.String("repo", tool.Required(), tool.Description(params.RepoDesc)),
|
||||
tool.Number("issue_number", tool.Description("required except for 'create'")),
|
||||
@@ -82,6 +84,12 @@ var (
|
||||
tool.String("ref", tool.Description("branch to associate")),
|
||||
tool.String("deadline", tool.Description("ISO 8601")),
|
||||
tool.Boolean("remove_deadline"),
|
||||
tool.Number("blocked_issue", tool.Description("issue number that issue_number blocks (required for 'block_issue'/'unblock_issue')")),
|
||||
tool.String("blocked_owner", tool.Description("owner of blocked_issue; defaults to owner")),
|
||||
tool.String("blocked_repo", tool.Description("repo of blocked_issue; defaults to repo")),
|
||||
tool.Number("blocking_issue", tool.Description("issue number that blocks issue_number (required for 'add_dependency'/'remove_dependency')")),
|
||||
tool.String("blocking_owner", tool.Description("owner of blocking_issue; defaults to owner")),
|
||||
tool.String("blocking_repo", tool.Description("repo of blocking_issue; defaults to repo")),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -112,6 +120,12 @@ func issueReadFn(ctx context.Context, args map[string]any) (*mcp.CallToolResult,
|
||||
return getIssueCommentsByIndexFn(ctx, args)
|
||||
case "get_labels":
|
||||
return getIssueLabelsFn(ctx, args)
|
||||
case "list_blocks":
|
||||
return listIssueBlocksFn(ctx, args)
|
||||
case "list_dependencies":
|
||||
return listIssueDependenciesFn(ctx, args)
|
||||
case "check_blocked":
|
||||
return checkIssueBlockedFn(ctx, args)
|
||||
default:
|
||||
return to.ErrorResult(fmt.Errorf("unknown method: %s", method))
|
||||
}
|
||||
@@ -139,6 +153,14 @@ func issueWriteFn(ctx context.Context, args map[string]any) (*mcp.CallToolResult
|
||||
return replaceIssueLabelsFn(ctx, args)
|
||||
case "clear_labels":
|
||||
return clearIssueLabelsFn(ctx, args)
|
||||
case "block_issue":
|
||||
return blockIssueFn(ctx, args)
|
||||
case "unblock_issue":
|
||||
return unblockIssueFn(ctx, args)
|
||||
case "add_dependency":
|
||||
return addIssueDependencyFn(ctx, args)
|
||||
case "remove_dependency":
|
||||
return removeIssueDependencyFn(ctx, args)
|
||||
default:
|
||||
return to.ErrorResult(fmt.Errorf("unknown method: %s", method))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user